From f15e026101a99487fd1debb87e6c879eb9b215c1 Mon Sep 17 00:00:00 2001 From: Raghul Nanth A <61490162+NanthR@users.noreply.github.com> Date: Mon, 12 Jun 2023 01:18:24 +0530 Subject: [PATCH 001/324] ci(metrics): Run measurement functions in parallel feat(xtask): Split metrics function --- .github/workflows/metrics.yaml | 234 +++++++++++++++++++++++++++++++-- xtask/src/flags.rs | 29 +++- xtask/src/metrics.rs | 76 ++++++----- 3 files changed, 292 insertions(+), 47 deletions(-) diff --git a/.github/workflows/metrics.yaml b/.github/workflows/metrics.yaml index 3fe2fc917a39..233af42f42c3 100644 --- a/.github/workflows/metrics.yaml +++ b/.github/workflows/metrics.yaml @@ -11,20 +11,234 @@ env: RUSTUP_MAX_RETRIES: 10 jobs: - metrics: - if: github.repository == 'rust-lang/rust-analyzer' + setup_cargo: runs-on: ubuntu-latest + steps: + - name: Install Rust toolchain + run: | + rustup update --no-self-update stable + rustup component add rustfmt rust-src + - name: Cache cargo + uses: actions/cache@v3 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + key: ${{ runner.os }}-cargo-${{ github.sha }} + + build_metrics: + runs-on: ubuntu-latest + needs: setup_cargo steps: - name: Checkout repository uses: actions/checkout@v3 - - name: Install Rust toolchain - run: | - rustup update --no-self-update stable - rustup component add rustfmt rust-src + - name: Restore cargo cache + uses: actions/cache@v3 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + key: ${{ runner.os }}-cargo-${{ github.sha }} - - name: Collect metrics - run: cargo xtask metrics - env: - METRICS_TOKEN: ${{ secrets.METRICS_TOKEN }} + + - name: Collect build metrics + run: cargo xtask metrics build + + - name: Cache target + uses: actions/cache@v3 + with: + path: target/ + key: ${{ runner.os }}-target-${{ github.sha }} + + - name: Upload build metrics + uses: actions/upload-artifact@v3 + with: + name: build-${{ github.sha }} + path: target/build.json + if-no-files-found: error + + self_metrics: + runs-on: ubuntu-latest + needs: [setup_cargo, build_metrics] + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Restore cargo cache + uses: actions/cache@v3 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + key: ${{ runner.os }}-cargo-${{ github.sha }} + + - name: Restore target cache + uses: actions/cache@v3 + with: + path: target/ + key: ${{ runner.os }}-target-${{ github.sha }} + + - name: Collect build metrics + run: cargo xtask metrics self + + - name: Upload build metrics + uses: actions/upload-artifact@v3 + with: + name: self-${{ github.sha }} + path: target/self.json + if-no-files-found: error + + ripgrep_metrics: + runs-on: ubuntu-latest + needs: [setup_cargo, build_metrics] + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Restore cargo cache + uses: actions/cache@v3 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + key: ${{ runner.os }}-cargo-${{ github.sha }} + + - name: Restore target cache + uses: actions/cache@v3 + with: + path: target/ + key: ${{ runner.os }}-target-${{ github.sha }} + + - name: Collect build metrics + run: cargo xtask metrics ripgrep + + - name: Upload ripgrep metrics + uses: actions/upload-artifact@v3 + with: + name: ripgrep-${{ github.sha }} + path: target/ripgrep.json + if-no-files-found: error + + webrender_metrics: + runs-on: ubuntu-latest + needs: [setup_cargo, build_metrics] + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Restore cargo cache + uses: actions/cache@v3 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + key: ${{ runner.os }}-cargo-${{ github.sha }} + + - name: Restore target cache + uses: actions/cache@v3 + with: + path: target/ + key: ${{ runner.os }}-target-${{ github.sha }} + + - name: Collect webrender metrics + run: cargo xtask metrics webrender + + - name: Upload webrender metrics + uses: actions/upload-artifact@v3 + with: + name: webrender-${{ github.sha }} + path: target/webrender.json + if-no-files-found: error + + diesel_metrics: + runs-on: ubuntu-latest + needs: [setup_cargo, build_metrics] + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Restore cargo cache + uses: actions/cache@v3 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + key: ${{ runner.os }}-cargo-${{ github.sha }} + + - name: Restore target cache + uses: actions/cache@v3 + with: + path: target/ + key: ${{ runner.os }}-target-${{ github.sha }} + + - name: Collect build metrics + run: cargo xtask metrics diesel + + - name: Upload build metrics + uses: actions/upload-artifact@v3 + with: + name: diesel-${{ github.sha }} + path: target/diesel.json + if-no-files-found: error + + + + generate_final_metrics: + runs-on: ubuntu-latest + needs: [build_metrics, self_metrics, ripgrep_metrics, webrender_metrics, diesel_metrics] + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Download build metrics + uses: actions/download-artifact@v3 + with: + name: build-${{ github.sha }} + + - name: Download self metrics + uses: actions/download-artifact@v3 + with: + name: self-${{ github.sha }} + + - name: Download ripgrep metrics + uses: actions/download-artifact@v3 + with: + name: ripgrep-${{ github.sha }} + + - name: Download webrender metrics + uses: actions/download-artifact@v3 + with: + name: webrender-${{ github.sha }} + + - name: Download diesel metrics + uses: actions/download-artifact@v3 + with: + name: diesel-${{ github.sha }} + + - name: Combine json + run: | + git clone --depth 1 https://$METRICS_TOKEN@github.com/nanthR/metrics.git + jq -s ".[0] * .[1] * .[2] * .[3] * .[4]" build.json self.json ripgrep.json webrender.json diesel.json -c >> metrics/metrics.json + git -C metrics add . + git -C metrics -c user.name=Bot -c user.email=dummy@example.com commit --message 📈 + git -C metrics push origin master + env: + METRICS_TOKEN: ${{ secrets.METRICS_TOKEN }} diff --git a/xtask/src/flags.rs b/xtask/src/flags.rs index 21004797014e..47d0ea254bba 100644 --- a/xtask/src/flags.rs +++ b/xtask/src/flags.rs @@ -1,5 +1,7 @@ #![allow(unreachable_pub)] +use std::str::FromStr; + use crate::install::{ClientOpt, Malloc, ServerOpt}; xflags::xflags! { @@ -42,7 +44,7 @@ xflags::xflags! { required changelog: String } cmd metrics { - optional --dry-run + optional measurement_type: MeasurementType } /// Builds a benchmark version of rust-analyzer and puts it into `./target`. cmd bb { @@ -105,9 +107,32 @@ pub struct PublishReleaseNotes { pub dry_run: bool, } +#[derive(Debug)] +pub enum MeasurementType { + Build, + AnalyseSelf, + AnalyseRipgrep, + AnalyseWebRender, + AnalyseDiesel, +} + +impl FromStr for MeasurementType { + type Err = String; + fn from_str(s: &str) -> Result { + match s { + "build" => Ok(Self::Build), + "self" => Ok(Self::AnalyseSelf), + "ripgrep" => Ok(Self::AnalyseRipgrep), + "webrender" => Ok(Self::AnalyseWebRender), + "diesel" => Ok(Self::AnalyseDiesel), + _ => Err("Invalid option".to_string()), + } + } +} + #[derive(Debug)] pub struct Metrics { - pub dry_run: bool, + pub measurement_type: Option, } #[derive(Debug)] diff --git a/xtask/src/metrics.rs b/xtask/src/metrics.rs index b6f730dbf126..d51dfb183f81 100644 --- a/xtask/src/metrics.rs +++ b/xtask/src/metrics.rs @@ -1,6 +1,6 @@ use std::{ collections::BTreeMap, - env, fs, + fs, io::Write as _, path::Path, time::{Instant, SystemTime, UNIX_EPOCH}, @@ -9,16 +9,13 @@ use std::{ use anyhow::{bail, format_err}; use xshell::{cmd, Shell}; -use crate::flags; +use crate::flags::{self, MeasurementType}; type Unit = String; impl flags::Metrics { pub(crate) fn run(self, sh: &Shell) -> anyhow::Result<()> { let mut metrics = Metrics::new(sh)?; - if !self.dry_run { - sh.remove_path("./target/release")?; - } if !Path::new("./target/rustc-perf").exists() { sh.create_dir("./target/rustc-perf")?; cmd!(sh, "git clone https://github.com/rust-lang/rustc-perf.git ./target/rustc-perf") @@ -32,38 +29,47 @@ impl flags::Metrics { let _env = sh.push_env("RA_METRICS", "1"); - { - // https://github.com/rust-lang/rust-analyzer/issues/9997 - let _d = sh.push_dir("target/rustc-perf/collector/benchmarks/webrender"); - cmd!(sh, "cargo update -p url --precise 1.6.1").run()?; - } - metrics.measure_build(sh)?; - metrics.measure_analysis_stats_self(sh)?; - metrics.measure_analysis_stats(sh, "ripgrep")?; - metrics.measure_analysis_stats(sh, "webrender")?; - metrics.measure_analysis_stats(sh, "diesel/diesel")?; - - if !self.dry_run { - let _d = sh.push_dir("target"); - let metrics_token = env::var("METRICS_TOKEN").unwrap(); - cmd!( - sh, - "git clone --depth 1 https://{metrics_token}@github.com/rust-analyzer/metrics.git" - ) - .run()?; - - { - let mut file = - fs::File::options().append(true).open("target/metrics/metrics.json")?; - writeln!(file, "{}", metrics.json())?; + let filename = match self.measurement_type { + Some(ms) => match ms { + MeasurementType::Build => { + metrics.measure_build(sh)?; + "build.json" + } + MeasurementType::AnalyseSelf => { + metrics.measure_analysis_stats_self(sh)?; + "self.json" + } + MeasurementType::AnalyseRipgrep => { + metrics.measure_analysis_stats(sh, "ripgrep")?; + "ripgrep.json" + } + MeasurementType::AnalyseWebRender => { + { + // https://github.com/rust-lang/rust-analyzer/issues/9997 + let _d = sh.push_dir("target/rustc-perf/collector/benchmarks/webrender"); + cmd!(sh, "cargo update -p url --precise 1.6.1").run()?; + } + metrics.measure_analysis_stats(sh, "webrender")?; + "webrender.json" + } + MeasurementType::AnalyseDiesel => { + metrics.measure_analysis_stats(sh, "diesel/diesel")?; + "diesel.json" + } + }, + None => { + metrics.measure_build(sh)?; + metrics.measure_analysis_stats_self(sh)?; + metrics.measure_analysis_stats(sh, "ripgrep")?; + metrics.measure_analysis_stats(sh, "webrender")?; + metrics.measure_analysis_stats(sh, "diesel/diesel")?; + "all.json" } + }; - let _d = sh.push_dir("metrics"); - cmd!(sh, "git add .").run()?; - cmd!(sh, "git -c user.name=Bot -c user.email=dummy@example.com commit --message 📈") - .run()?; - cmd!(sh, "git push origin master").run()?; - } + let mut file = + fs::File::options().write(true).create(true).open(format!("target/{}", filename))?; + writeln!(file, "{}", metrics.json())?; eprintln!("{metrics:#?}"); Ok(()) } From 5d77839b25963ce9bb06d8e1de760106477e6fe1 Mon Sep 17 00:00:00 2001 From: Raghul Nanth A <61490162+NanthR@users.noreply.github.com> Date: Mon, 12 Jun 2023 23:14:04 +0530 Subject: [PATCH 002/324] style(metrics): Change spelling --- xtask/src/flags.rs | 16 ++++++++-------- xtask/src/metrics.rs | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/xtask/src/flags.rs b/xtask/src/flags.rs index 47d0ea254bba..7720ad69fe09 100644 --- a/xtask/src/flags.rs +++ b/xtask/src/flags.rs @@ -110,10 +110,10 @@ pub struct PublishReleaseNotes { #[derive(Debug)] pub enum MeasurementType { Build, - AnalyseSelf, - AnalyseRipgrep, - AnalyseWebRender, - AnalyseDiesel, + AnalyzeSelf, + AnalyzeRipgrep, + AnalyzeWebRender, + AnalyzeDiesel, } impl FromStr for MeasurementType { @@ -121,10 +121,10 @@ impl FromStr for MeasurementType { fn from_str(s: &str) -> Result { match s { "build" => Ok(Self::Build), - "self" => Ok(Self::AnalyseSelf), - "ripgrep" => Ok(Self::AnalyseRipgrep), - "webrender" => Ok(Self::AnalyseWebRender), - "diesel" => Ok(Self::AnalyseDiesel), + "self" => Ok(Self::AnalyzeSelf), + "ripgrep" => Ok(Self::AnalyzeRipgrep), + "webrender" => Ok(Self::AnalyzeWebRender), + "diesel" => Ok(Self::AnalyzeDiesel), _ => Err("Invalid option".to_string()), } } diff --git a/xtask/src/metrics.rs b/xtask/src/metrics.rs index d51dfb183f81..68537423195e 100644 --- a/xtask/src/metrics.rs +++ b/xtask/src/metrics.rs @@ -35,15 +35,15 @@ impl flags::Metrics { metrics.measure_build(sh)?; "build.json" } - MeasurementType::AnalyseSelf => { + MeasurementType::AnalyzeSelf => { metrics.measure_analysis_stats_self(sh)?; "self.json" } - MeasurementType::AnalyseRipgrep => { + MeasurementType::AnalyzeRipgrep => { metrics.measure_analysis_stats(sh, "ripgrep")?; "ripgrep.json" } - MeasurementType::AnalyseWebRender => { + MeasurementType::AnalyzeWebRender => { { // https://github.com/rust-lang/rust-analyzer/issues/9997 let _d = sh.push_dir("target/rustc-perf/collector/benchmarks/webrender"); @@ -52,7 +52,7 @@ impl flags::Metrics { metrics.measure_analysis_stats(sh, "webrender")?; "webrender.json" } - MeasurementType::AnalyseDiesel => { + MeasurementType::AnalyzeDiesel => { metrics.measure_analysis_stats(sh, "diesel/diesel")?; "diesel.json" } From e55a1f1916192bbf613223651e6073460b6ca1ac Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Thu, 15 Jun 2023 01:47:22 +0330 Subject: [PATCH 003/324] Map our diagnostics to rustc and clippy's ones --- Cargo.lock | 1 + crates/hir-ty/src/diagnostics.rs | 2 +- crates/hir-ty/src/diagnostics/decl_check.rs | 6 +- crates/hir/src/diagnostics.rs | 2 +- crates/hir/src/lib.rs | 10 +- crates/ide-diagnostics/Cargo.toml | 1 + .../src/handlers/break_outside_of_loop.rs | 9 +- .../src/handlers/expected_function.rs | 9 +- .../src/handlers/field_shorthand.rs | 40 +-- .../src/handlers/inactive_code.rs | 7 +- .../src/handlers/incoherent_impl.rs | 10 +- .../src/handlers/incorrect_case.rs | 112 ++++++-- .../src/handlers/invalid_derive_target.rs | 5 +- .../src/handlers/json_is_not_rust.rs | 5 +- .../src/handlers/macro_error.rs | 16 +- .../src/handlers/malformed_derive.rs | 5 +- .../src/handlers/mismatched_arg_count.rs | 4 +- .../src/handlers/missing_fields.rs | 4 +- .../src/handlers/missing_match_arms.rs | 9 +- .../src/handlers/missing_unsafe.rs | 9 +- .../src/handlers/moved_out_of_ref.rs | 9 +- .../src/handlers/mutability_errors.rs | 125 +++++---- .../src/handlers/no_such_field.rs | 9 +- .../src/handlers/private_assoc_item.rs | 21 +- .../src/handlers/private_field.rs | 9 +- .../replace_filter_map_next_with_find_map.rs | 41 ++- .../src/handlers/type_mismatch.rs | 4 +- .../src/handlers/typed_hole.rs | 5 +- .../src/handlers/undeclared_label.rs | 9 +- .../handlers/unimplemented_builtin_macro.rs | 10 +- .../src/handlers/unlinked_file.rs | 5 +- .../src/handlers/unreachable_label.rs | 9 +- .../src/handlers/unresolved_extern_crate.rs | 9 +- .../src/handlers/unresolved_field.rs | 9 +- .../src/handlers/unresolved_import.rs | 9 +- .../src/handlers/unresolved_macro_call.rs | 4 +- .../src/handlers/unresolved_method.rs | 9 +- .../src/handlers/unresolved_module.rs | 29 +- .../src/handlers/unresolved_proc_macro.rs | 4 +- .../src/handlers/useless_braces.rs | 5 +- crates/ide-diagnostics/src/lib.rs | 257 ++++++++++++++++-- crates/ide-diagnostics/src/tests.rs | 13 +- crates/rust-analyzer/src/main_loop.rs | 6 +- crates/rust-analyzer/src/to_proto.rs | 3 + 44 files changed, 628 insertions(+), 251 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 322a67383b03..de7abe0f03c3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -748,6 +748,7 @@ dependencies = [ "hir", "ide-db", "itertools", + "once_cell", "profile", "serde_json", "sourcegen", diff --git a/crates/hir-ty/src/diagnostics.rs b/crates/hir-ty/src/diagnostics.rs index 4b147b99707c..ef43ed5c463f 100644 --- a/crates/hir-ty/src/diagnostics.rs +++ b/crates/hir-ty/src/diagnostics.rs @@ -5,7 +5,7 @@ mod unsafe_check; mod decl_check; pub use crate::diagnostics::{ - decl_check::{incorrect_case, IncorrectCase}, + decl_check::{incorrect_case, CaseType, IncorrectCase}, expr::{ record_literal_missing_fields, record_pattern_missing_fields, BodyValidationDiagnostic, }, diff --git a/crates/hir-ty/src/diagnostics/decl_check.rs b/crates/hir-ty/src/diagnostics/decl_check.rs index 1233469b947b..f4c6d6dd3ceb 100644 --- a/crates/hir-ty/src/diagnostics/decl_check.rs +++ b/crates/hir-ty/src/diagnostics/decl_check.rs @@ -57,11 +57,11 @@ pub fn incorrect_case( #[derive(Debug)] pub enum CaseType { - // `some_var` + /// `some_var` LowerSnakeCase, - // `SOME_CONST` + /// `SOME_CONST` UpperSnakeCase, - // `SomeStruct` + /// `SomeStruct` UpperCamelCase, } diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index b64d81490bb1..80c3bcdca8b7 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs @@ -3,7 +3,7 @@ //! //! This probably isn't the best way to do this -- ideally, diagnostics should //! be expressed in terms of hir types themselves. -pub use hir_ty::diagnostics::{IncoherentImpl, IncorrectCase}; +pub use hir_ty::diagnostics::{CaseType, IncoherentImpl, IncorrectCase}; use base_db::CrateId; use cfg::{CfgExpr, CfgOptions}; diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 9876503d0317..e9e9a202646f 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -89,11 +89,11 @@ use crate::db::{DefDatabase, HirDatabase}; pub use crate::{ attrs::{HasAttrs, Namespace}, diagnostics::{ - AnyDiagnostic, BreakOutsideOfLoop, ExpectedFunction, InactiveCode, IncoherentImpl, - IncorrectCase, InvalidDeriveTarget, MacroDefError, MacroError, MacroExpansionParseError, - MalformedDerive, MismatchedArgCount, MissingFields, MissingMatchArms, MissingUnsafe, - MovedOutOfRef, NeedMut, NoSuchField, PrivateAssocItem, PrivateField, - ReplaceFilterMapNextWithFindMap, TypeMismatch, TypedHole, UndeclaredLabel, + AnyDiagnostic, BreakOutsideOfLoop, CaseType, ExpectedFunction, InactiveCode, + IncoherentImpl, IncorrectCase, InvalidDeriveTarget, MacroDefError, MacroError, + MacroExpansionParseError, MalformedDerive, MismatchedArgCount, MissingFields, + MissingMatchArms, MissingUnsafe, MovedOutOfRef, NeedMut, NoSuchField, PrivateAssocItem, + PrivateField, ReplaceFilterMapNextWithFindMap, TypeMismatch, TypedHole, UndeclaredLabel, UnimplementedBuiltinMacro, UnreachableLabel, UnresolvedExternCrate, UnresolvedField, UnresolvedImport, UnresolvedMacroCall, UnresolvedMethodCall, UnresolvedModule, UnresolvedProcMacro, UnusedMut, diff --git a/crates/ide-diagnostics/Cargo.toml b/crates/ide-diagnostics/Cargo.toml index e18624fcc267..14aa3940199a 100644 --- a/crates/ide-diagnostics/Cargo.toml +++ b/crates/ide-diagnostics/Cargo.toml @@ -16,6 +16,7 @@ cov-mark = "2.0.0-pre.1" either = "1.7.0" itertools = "0.10.5" serde_json = "1.0.86" +once_cell = "1.17.0" # local deps profile.workspace = true diff --git a/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs b/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs index 30576c71fb7c..491005403882 100644 --- a/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs +++ b/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs @@ -1,4 +1,4 @@ -use crate::{Diagnostic, DiagnosticsContext}; +use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; // Diagnostic: break-outside-of-loop // @@ -13,10 +13,11 @@ pub(crate) fn break_outside_of_loop( let construct = if d.is_break { "break" } else { "continue" }; format!("{construct} outside of loop") }; - Diagnostic::new( - "break-outside-of-loop", + Diagnostic::new_with_syntax_node_ptr( + ctx, + DiagnosticCode::RustcHardError("E0268"), message, - ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range, + d.expr.clone().map(|it| it.into()), ) } diff --git a/crates/ide-diagnostics/src/handlers/expected_function.rs b/crates/ide-diagnostics/src/handlers/expected_function.rs index d2f27664d6f9..e1e5db91c54c 100644 --- a/crates/ide-diagnostics/src/handlers/expected_function.rs +++ b/crates/ide-diagnostics/src/handlers/expected_function.rs @@ -1,6 +1,6 @@ use hir::HirDisplay; -use crate::{Diagnostic, DiagnosticsContext}; +use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; // Diagnostic: expected-function // @@ -9,10 +9,11 @@ pub(crate) fn expected_function( ctx: &DiagnosticsContext<'_>, d: &hir::ExpectedFunction, ) -> Diagnostic { - Diagnostic::new( - "expected-function", + Diagnostic::new_with_syntax_node_ptr( + ctx, + DiagnosticCode::RustcHardError("E0618"), format!("expected function, found {}", d.found.display(ctx.sema.db)), - ctx.sema.diagnostics_display_range(d.call.clone().map(|it| it.into())).range, + d.call.clone().map(|it| it.into()), ) .experimental() } diff --git a/crates/ide-diagnostics/src/handlers/field_shorthand.rs b/crates/ide-diagnostics/src/handlers/field_shorthand.rs index 2b7105362503..3b69640af9b8 100644 --- a/crates/ide-diagnostics/src/handlers/field_shorthand.rs +++ b/crates/ide-diagnostics/src/handlers/field_shorthand.rs @@ -5,7 +5,7 @@ use ide_db::{base_db::FileId, source_change::SourceChange}; use syntax::{ast, match_ast, AstNode, SyntaxNode}; use text_edit::TextEdit; -use crate::{fix, Diagnostic, Severity}; +use crate::{fix, Diagnostic, DiagnosticCode}; pub(crate) fn field_shorthand(acc: &mut Vec, file_id: FileId, node: &SyntaxNode) { match_ast! { @@ -46,14 +46,17 @@ fn check_expr_field_shorthand( let field_range = record_field.syntax().text_range(); acc.push( - Diagnostic::new("use-field-shorthand", "Shorthand struct initialization", field_range) - .severity(Severity::WeakWarning) - .with_fixes(Some(vec![fix( - "use_expr_field_shorthand", - "Use struct shorthand initialization", - SourceChange::from_text_edit(file_id, edit), - field_range, - )])), + Diagnostic::new( + DiagnosticCode::Clippy("redundant_field_names"), + "Shorthand struct initialization", + field_range, + ) + .with_fixes(Some(vec![fix( + "use_expr_field_shorthand", + "Use struct shorthand initialization", + SourceChange::from_text_edit(file_id, edit), + field_range, + )])), ); } } @@ -87,14 +90,17 @@ fn check_pat_field_shorthand( let field_range = record_pat_field.syntax().text_range(); acc.push( - Diagnostic::new("use-field-shorthand", "Shorthand struct pattern", field_range) - .severity(Severity::WeakWarning) - .with_fixes(Some(vec![fix( - "use_pat_field_shorthand", - "Use struct field shorthand", - SourceChange::from_text_edit(file_id, edit), - field_range, - )])), + Diagnostic::new( + DiagnosticCode::Clippy("redundant_field_names"), + "Shorthand struct pattern", + field_range, + ) + .with_fixes(Some(vec![fix( + "use_pat_field_shorthand", + "Use struct field shorthand", + SourceChange::from_text_edit(file_id, edit), + field_range, + )])), ); } } diff --git a/crates/ide-diagnostics/src/handlers/inactive_code.rs b/crates/ide-diagnostics/src/handlers/inactive_code.rs index f558b7256a4c..9eb763d3e2c2 100644 --- a/crates/ide-diagnostics/src/handlers/inactive_code.rs +++ b/crates/ide-diagnostics/src/handlers/inactive_code.rs @@ -1,7 +1,7 @@ use cfg::DnfExpr; use stdx::format_to; -use crate::{Diagnostic, DiagnosticsContext, Severity}; +use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext, Severity}; // Diagnostic: inactive-code // @@ -27,13 +27,12 @@ pub(crate) fn inactive_code( format_to!(message, ": {}", inactive); } } - + // FIXME: This shouldn't be a diagnostic let res = Diagnostic::new( - "inactive-code", + DiagnosticCode::Ra("inactive-code", Severity::WeakWarning), message, ctx.sema.diagnostics_display_range(d.node.clone()).range, ) - .severity(Severity::WeakWarning) .with_unused(true); Some(res) } diff --git a/crates/ide-diagnostics/src/handlers/incoherent_impl.rs b/crates/ide-diagnostics/src/handlers/incoherent_impl.rs index 72af9ebfcbb6..4afb4db03bda 100644 --- a/crates/ide-diagnostics/src/handlers/incoherent_impl.rs +++ b/crates/ide-diagnostics/src/handlers/incoherent_impl.rs @@ -1,17 +1,17 @@ use hir::InFile; -use crate::{Diagnostic, DiagnosticsContext, Severity}; +use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; // Diagnostic: incoherent-impl // // This diagnostic is triggered if the targe type of an impl is from a foreign crate. pub(crate) fn incoherent_impl(ctx: &DiagnosticsContext<'_>, d: &hir::IncoherentImpl) -> Diagnostic { - Diagnostic::new( - "incoherent-impl", + Diagnostic::new_with_syntax_node_ptr( + ctx, + DiagnosticCode::RustcHardError("E0210"), format!("cannot define inherent `impl` for foreign type"), - ctx.sema.diagnostics_display_range(InFile::new(d.file_id, d.impl_.clone().into())).range, + InFile::new(d.file_id, d.impl_.clone().into()), ) - .severity(Severity::Error) } #[cfg(test)] diff --git a/crates/ide-diagnostics/src/handlers/incorrect_case.rs b/crates/ide-diagnostics/src/handlers/incorrect_case.rs index 90279e14536b..92fd4f71ca5d 100644 --- a/crates/ide-diagnostics/src/handlers/incorrect_case.rs +++ b/crates/ide-diagnostics/src/handlers/incorrect_case.rs @@ -1,4 +1,4 @@ -use hir::{db::ExpandDatabase, InFile}; +use hir::{db::ExpandDatabase, CaseType, InFile}; use ide_db::{assists::Assist, defs::NameClass}; use syntax::AstNode; @@ -6,23 +6,29 @@ use crate::{ // references::rename::rename_with_semantics, unresolved_fix, Diagnostic, + DiagnosticCode, DiagnosticsContext, - Severity, }; // Diagnostic: incorrect-ident-case // // This diagnostic is triggered if an item name doesn't follow https://doc.rust-lang.org/1.0.0/style/style/naming/README.html[Rust naming convention]. pub(crate) fn incorrect_case(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Diagnostic { - Diagnostic::new( - "incorrect-ident-case", + let code = match d.expected_case { + CaseType::LowerSnakeCase => DiagnosticCode::RustcLint("non_snake_case"), + CaseType::UpperSnakeCase => DiagnosticCode::RustcLint("non_upper_case_globals"), + // The name is lying. It also covers variants, traits, ... + CaseType::UpperCamelCase => DiagnosticCode::RustcLint("non_camel_case_types"), + }; + Diagnostic::new_with_syntax_node_ptr( + ctx, + code, format!( "{} `{}` should have {} name, e.g. `{}`", d.ident_type, d.ident_text, d.expected_case, d.suggested_text ), - ctx.sema.diagnostics_display_range(InFile::new(d.file, d.ident.clone().into())).range, + InFile::new(d.file, d.ident.clone().into()), ) - .severity(Severity::WeakWarning) .with_fixes(fixes(ctx, d)) } @@ -149,7 +155,7 @@ impl TestStruct { check_diagnostics( r#" fn FOO() {} -// ^^^ 💡 weak: Function `FOO` should have snake_case name, e.g. `foo` +// ^^^ 💡 warn: Function `FOO` should have snake_case name, e.g. `foo` "#, ); check_fix(r#"fn FOO$0() {}"#, r#"fn foo() {}"#); @@ -160,7 +166,7 @@ fn FOO() {} check_diagnostics( r#" fn NonSnakeCaseName() {} -// ^^^^^^^^^^^^^^^^ 💡 weak: Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name` +// ^^^^^^^^^^^^^^^^ 💡 warn: Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name` "#, ); } @@ -170,10 +176,10 @@ fn NonSnakeCaseName() {} check_diagnostics( r#" fn foo(SomeParam: u8) {} - // ^^^^^^^^^ 💡 weak: Parameter `SomeParam` should have snake_case name, e.g. `some_param` + // ^^^^^^^^^ 💡 warn: Parameter `SomeParam` should have snake_case name, e.g. `some_param` fn foo2(ok_param: &str, CAPS_PARAM: u8) {} - // ^^^^^^^^^^ 💡 weak: Parameter `CAPS_PARAM` should have snake_case name, e.g. `caps_param` + // ^^^^^^^^^^ 💡 warn: Parameter `CAPS_PARAM` should have snake_case name, e.g. `caps_param` "#, ); } @@ -184,9 +190,9 @@ fn foo2(ok_param: &str, CAPS_PARAM: u8) {} r#" fn foo() { let SOME_VALUE = 10; - // ^^^^^^^^^^ 💡 weak: Variable `SOME_VALUE` should have snake_case name, e.g. `some_value` + // ^^^^^^^^^^ 💡 warn: Variable `SOME_VALUE` should have snake_case name, e.g. `some_value` let AnotherValue = 20; - // ^^^^^^^^^^^^ 💡 weak: Variable `AnotherValue` should have snake_case name, e.g. `another_value` + // ^^^^^^^^^^^^ 💡 warn: Variable `AnotherValue` should have snake_case name, e.g. `another_value` } "#, ); @@ -197,10 +203,10 @@ fn foo() { check_diagnostics( r#" struct non_camel_case_name {} - // ^^^^^^^^^^^^^^^^^^^ 💡 weak: Structure `non_camel_case_name` should have CamelCase name, e.g. `NonCamelCaseName` + // ^^^^^^^^^^^^^^^^^^^ 💡 warn: Structure `non_camel_case_name` should have CamelCase name, e.g. `NonCamelCaseName` struct SCREAMING_CASE {} - // ^^^^^^^^^^^^^^ 💡 weak: Structure `SCREAMING_CASE` should have CamelCase name, e.g. `ScreamingCase` + // ^^^^^^^^^^^^^^ 💡 warn: Structure `SCREAMING_CASE` should have CamelCase name, e.g. `ScreamingCase` "#, ); } @@ -219,7 +225,7 @@ struct AABB {} check_diagnostics( r#" struct SomeStruct { SomeField: u8 } - // ^^^^^^^^^ 💡 weak: Field `SomeField` should have snake_case name, e.g. `some_field` + // ^^^^^^^^^ 💡 warn: Field `SomeField` should have snake_case name, e.g. `some_field` "#, ); } @@ -229,10 +235,10 @@ struct SomeStruct { SomeField: u8 } check_diagnostics( r#" enum some_enum { Val(u8) } - // ^^^^^^^^^ 💡 weak: Enum `some_enum` should have CamelCase name, e.g. `SomeEnum` + // ^^^^^^^^^ 💡 warn: Enum `some_enum` should have CamelCase name, e.g. `SomeEnum` enum SOME_ENUM {} - // ^^^^^^^^^ 💡 weak: Enum `SOME_ENUM` should have CamelCase name, e.g. `SomeEnum` + // ^^^^^^^^^ 💡 warn: Enum `SOME_ENUM` should have CamelCase name, e.g. `SomeEnum` "#, ); } @@ -251,7 +257,7 @@ enum AABB {} check_diagnostics( r#" enum SomeEnum { SOME_VARIANT(u8) } - // ^^^^^^^^^^^^ 💡 weak: Variant `SOME_VARIANT` should have CamelCase name, e.g. `SomeVariant` + // ^^^^^^^^^^^^ 💡 warn: Variant `SOME_VARIANT` should have CamelCase name, e.g. `SomeVariant` "#, ); } @@ -261,7 +267,7 @@ enum SomeEnum { SOME_VARIANT(u8) } check_diagnostics( r#" const some_weird_const: u8 = 10; - // ^^^^^^^^^^^^^^^^ 💡 weak: Constant `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST` + // ^^^^^^^^^^^^^^^^ 💡 warn: Constant `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST` "#, ); } @@ -271,7 +277,7 @@ const some_weird_const: u8 = 10; check_diagnostics( r#" static some_weird_const: u8 = 10; - // ^^^^^^^^^^^^^^^^ 💡 weak: Static variable `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST` + // ^^^^^^^^^^^^^^^^ 💡 warn: Static variable `some_weird_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_WEIRD_CONST` "#, ); } @@ -281,13 +287,13 @@ static some_weird_const: u8 = 10; check_diagnostics( r#" struct someStruct; - // ^^^^^^^^^^ 💡 weak: Structure `someStruct` should have CamelCase name, e.g. `SomeStruct` + // ^^^^^^^^^^ 💡 warn: Structure `someStruct` should have CamelCase name, e.g. `SomeStruct` impl someStruct { fn SomeFunc(&self) { - // ^^^^^^^^ 💡 weak: Function `SomeFunc` should have snake_case name, e.g. `some_func` + // ^^^^^^^^ 💡 warn: Function `SomeFunc` should have snake_case name, e.g. `some_func` let WHY_VAR_IS_CAPS = 10; - // ^^^^^^^^^^^^^^^ 💡 weak: Variable `WHY_VAR_IS_CAPS` should have snake_case name, e.g. `why_var_is_caps` + // ^^^^^^^^^^^^^^^ 💡 warn: Variable `WHY_VAR_IS_CAPS` should have snake_case name, e.g. `why_var_is_caps` } } "#, @@ -319,7 +325,7 @@ enum Option { Some, None } fn main() { match Option::None { SOME_VAR @ None => (), - // ^^^^^^^^ 💡 weak: Variable `SOME_VAR` should have snake_case name, e.g. `some_var` + // ^^^^^^^^ 💡 warn: Variable `SOME_VAR` should have snake_case name, e.g. `some_var` Some => (), } } @@ -461,7 +467,7 @@ mod CheckNonstandardStyle { #[allow(bad_style)] mod CheckBadStyle { - fn HiImABadFnName() {} + struct fooo; } mod F { @@ -483,4 +489,60 @@ pub static SomeStatic: u8 = 10; "#, ); } + + #[test] + fn deny_attributes() { + check_diagnostics( + r#" +#[deny(non_snake_case)] +fn NonSnakeCaseName(some_var: u8) -> u8 { + //^^^^^^^^^^^^^^^^ 💡 error: Function `NonSnakeCaseName` should have snake_case name, e.g. `non_snake_case_name` + // cov_flags generated output from elsewhere in this file + extern "C" { + #[no_mangle] + static lower_case: u8; + } + + let OtherVar = some_var + 1; + //^^^^^^^^ 💡 error: Variable `OtherVar` should have snake_case name, e.g. `other_var` + OtherVar +} + +#[deny(nonstandard_style)] +mod CheckNonstandardStyle { + fn HiImABadFnName() {} + //^^^^^^^^^^^^^^ 💡 error: Function `HiImABadFnName` should have snake_case name, e.g. `hi_im_abad_fn_name` +} + +#[deny(warnings)] +mod CheckBadStyle { + struct fooo; + //^^^^ 💡 error: Structure `fooo` should have CamelCase name, e.g. `Fooo` +} + +mod F { + #![deny(non_snake_case)] + fn CheckItWorksWithModAttr() {} + //^^^^^^^^^^^^^^^^^^^^^^^ 💡 error: Function `CheckItWorksWithModAttr` should have snake_case name, e.g. `check_it_works_with_mod_attr` +} + +#[deny(non_snake_case, non_camel_case_types)] +pub struct some_type { + //^^^^^^^^^ 💡 error: Structure `some_type` should have CamelCase name, e.g. `SomeType` + SOME_FIELD: u8, + //^^^^^^^^^^ 💡 error: Field `SOME_FIELD` should have snake_case name, e.g. `some_field` + SomeField: u16, + //^^^^^^^^^ 💡 error: Field `SomeField` should have snake_case name, e.g. `some_field` +} + +#[deny(non_upper_case_globals)] +pub const some_const: u8 = 10; + //^^^^^^^^^^ 💡 error: Constant `some_const` should have UPPER_SNAKE_CASE name, e.g. `SOME_CONST` + +#[deny(non_upper_case_globals)] +pub static SomeStatic: u8 = 10; + //^^^^^^^^^^ 💡 error: Static variable `SomeStatic` should have UPPER_SNAKE_CASE name, e.g. `SOME_STATIC` + "#, + ); + } } diff --git a/crates/ide-diagnostics/src/handlers/invalid_derive_target.rs b/crates/ide-diagnostics/src/handlers/invalid_derive_target.rs index c779266bc97b..1ec17952b238 100644 --- a/crates/ide-diagnostics/src/handlers/invalid_derive_target.rs +++ b/crates/ide-diagnostics/src/handlers/invalid_derive_target.rs @@ -1,4 +1,4 @@ -use crate::{Diagnostic, DiagnosticsContext, Severity}; +use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; // Diagnostic: invalid-derive-target // @@ -11,11 +11,10 @@ pub(crate) fn invalid_derive_target( let display_range = ctx.sema.diagnostics_display_range(d.node.clone()).range; Diagnostic::new( - "invalid-derive-target", + DiagnosticCode::RustcHardError("E0774"), "`derive` may only be applied to `struct`s, `enum`s and `union`s", display_range, ) - .severity(Severity::Error) } #[cfg(test)] diff --git a/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs b/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs index 04ce1e0feeed..a337e2660d6a 100644 --- a/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs +++ b/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs @@ -17,7 +17,7 @@ use syntax::{ }; use text_edit::TextEdit; -use crate::{fix, Diagnostic, DiagnosticsConfig, Severity}; +use crate::{fix, Diagnostic, DiagnosticCode, DiagnosticsConfig, Severity}; #[derive(Default)] struct State { @@ -117,11 +117,10 @@ pub(crate) fn json_in_items( edit.insert(range.start(), state.result); acc.push( Diagnostic::new( - "json-is-not-rust", + DiagnosticCode::Ra("json-is-not-rust", Severity::WeakWarning), "JSON syntax is not valid as a Rust item", range, ) - .severity(Severity::WeakWarning) .with_fixes(Some(vec![{ let mut scb = SourceChangeBuilder::new(file_id); let scope = match import_scope { diff --git a/crates/ide-diagnostics/src/handlers/macro_error.rs b/crates/ide-diagnostics/src/handlers/macro_error.rs index 7547779a95c7..937e2f96642e 100644 --- a/crates/ide-diagnostics/src/handlers/macro_error.rs +++ b/crates/ide-diagnostics/src/handlers/macro_error.rs @@ -1,4 +1,4 @@ -use crate::{Diagnostic, DiagnosticsContext}; +use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext, Severity}; // Diagnostic: macro-error // @@ -6,7 +6,12 @@ use crate::{Diagnostic, DiagnosticsContext}; pub(crate) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) -> Diagnostic { // Use more accurate position if available. let display_range = ctx.resolve_precise_location(&d.node, d.precise_location); - Diagnostic::new("macro-error", d.message.clone(), display_range).experimental() + Diagnostic::new( + DiagnosticCode::Ra("macro-error", Severity::Error), + d.message.clone(), + display_range, + ) + .experimental() } // Diagnostic: macro-error @@ -16,7 +21,12 @@ pub(crate) fn macro_def_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroDefErr // Use more accurate position if available. let display_range = ctx.resolve_precise_location(&d.node.clone().map(|it| it.syntax_node_ptr()), d.name); - Diagnostic::new("macro-def-error", d.message.clone(), display_range).experimental() + Diagnostic::new( + DiagnosticCode::Ra("macro-def-error", Severity::Error), + d.message.clone(), + display_range, + ) + .experimental() } #[cfg(test)] diff --git a/crates/ide-diagnostics/src/handlers/malformed_derive.rs b/crates/ide-diagnostics/src/handlers/malformed_derive.rs index cd48bdba07e5..fc57dde69f2a 100644 --- a/crates/ide-diagnostics/src/handlers/malformed_derive.rs +++ b/crates/ide-diagnostics/src/handlers/malformed_derive.rs @@ -1,4 +1,4 @@ -use crate::{Diagnostic, DiagnosticsContext, Severity}; +use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; // Diagnostic: malformed-derive // @@ -10,11 +10,10 @@ pub(crate) fn malformed_derive( let display_range = ctx.sema.diagnostics_display_range(d.node.clone()).range; Diagnostic::new( - "malformed-derive", + DiagnosticCode::RustcHardError("E0777"), "malformed derive input, derive attributes are of the form `#[derive(Derive1, Derive2, ...)]`", display_range, ) - .severity(Severity::Error) } #[cfg(test)] diff --git a/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs b/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs index c5db8c3741b8..6238c7e09e99 100644 --- a/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs +++ b/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs @@ -3,7 +3,7 @@ use syntax::{ AstNode, TextRange, }; -use crate::{adjusted_display_range, Diagnostic, DiagnosticsContext}; +use crate::{adjusted_display_range, Diagnostic, DiagnosticCode, DiagnosticsContext}; // Diagnostic: mismatched-arg-count // @@ -14,7 +14,7 @@ pub(crate) fn mismatched_arg_count( ) -> Diagnostic { let s = if d.expected == 1 { "" } else { "s" }; let message = format!("expected {} argument{s}, found {}", d.expected, d.found); - Diagnostic::new("mismatched-arg-count", message, invalid_args_range(ctx, d)) + Diagnostic::new(DiagnosticCode::RustcHardError("E0107"), message, invalid_args_range(ctx, d)) } fn invalid_args_range(ctx: &DiagnosticsContext<'_>, d: &hir::MismatchedArgCount) -> TextRange { diff --git a/crates/ide-diagnostics/src/handlers/missing_fields.rs b/crates/ide-diagnostics/src/handlers/missing_fields.rs index 60ccc41df01c..bb0e36ff3a1e 100644 --- a/crates/ide-diagnostics/src/handlers/missing_fields.rs +++ b/crates/ide-diagnostics/src/handlers/missing_fields.rs @@ -15,7 +15,7 @@ use syntax::{ }; use text_edit::TextEdit; -use crate::{fix, Diagnostic, DiagnosticsContext}; +use crate::{fix, Diagnostic, DiagnosticCode, DiagnosticsContext}; // Diagnostic: missing-fields // @@ -42,7 +42,7 @@ pub(crate) fn missing_fields(ctx: &DiagnosticsContext<'_>, d: &hir::MissingField .unwrap_or_else(|| d.field_list_parent.clone().either(|it| it.into(), |it| it.into())), ); - Diagnostic::new("missing-fields", message, ctx.sema.diagnostics_display_range(ptr).range) + Diagnostic::new_with_syntax_node_ptr(ctx, DiagnosticCode::RustcHardError("E0063"), message, ptr) .with_fixes(fixes(ctx, d)) } diff --git a/crates/ide-diagnostics/src/handlers/missing_match_arms.rs b/crates/ide-diagnostics/src/handlers/missing_match_arms.rs index 3f13b97a4473..82a9a3bd5595 100644 --- a/crates/ide-diagnostics/src/handlers/missing_match_arms.rs +++ b/crates/ide-diagnostics/src/handlers/missing_match_arms.rs @@ -1,4 +1,4 @@ -use crate::{Diagnostic, DiagnosticsContext}; +use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; // Diagnostic: missing-match-arm // @@ -7,10 +7,11 @@ pub(crate) fn missing_match_arms( ctx: &DiagnosticsContext<'_>, d: &hir::MissingMatchArms, ) -> Diagnostic { - Diagnostic::new( - "missing-match-arm", + Diagnostic::new_with_syntax_node_ptr( + ctx, + DiagnosticCode::RustcHardError("E0004"), format!("missing match arm: {}", d.uncovered_patterns), - ctx.sema.diagnostics_display_range(d.scrutinee_expr.clone().map(Into::into)).range, + d.scrutinee_expr.clone().map(Into::into), ) } diff --git a/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/crates/ide-diagnostics/src/handlers/missing_unsafe.rs index 2026b6fcef53..70b26009bae0 100644 --- a/crates/ide-diagnostics/src/handlers/missing_unsafe.rs +++ b/crates/ide-diagnostics/src/handlers/missing_unsafe.rs @@ -4,16 +4,17 @@ use syntax::{ast, SyntaxNode}; use syntax::{match_ast, AstNode}; use text_edit::TextEdit; -use crate::{fix, Diagnostic, DiagnosticsContext}; +use crate::{fix, Diagnostic, DiagnosticCode, DiagnosticsContext}; // Diagnostic: missing-unsafe // // This diagnostic is triggered if an operation marked as `unsafe` is used outside of an `unsafe` function or block. pub(crate) fn missing_unsafe(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsafe) -> Diagnostic { - Diagnostic::new( - "missing-unsafe", + Diagnostic::new_with_syntax_node_ptr( + ctx, + DiagnosticCode::RustcHardError("E0133"), "this operation is unsafe and requires an unsafe function or block", - ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range, + d.expr.clone().map(|it| it.into()), ) .with_fixes(fixes(ctx, d)) } diff --git a/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs b/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs index 32e321107e6f..3aa4aa97026a 100644 --- a/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs +++ b/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs @@ -1,14 +1,15 @@ -use crate::{Diagnostic, DiagnosticsContext}; +use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; use hir::HirDisplay; // Diagnostic: moved-out-of-ref // // This diagnostic is triggered on moving non copy things out of references. pub(crate) fn moved_out_of_ref(ctx: &DiagnosticsContext<'_>, d: &hir::MovedOutOfRef) -> Diagnostic { - Diagnostic::new( - "moved-out-of-ref", + Diagnostic::new_with_syntax_node_ptr( + ctx, + DiagnosticCode::RustcHardError("E0507"), format!("cannot move `{}` out of reference", d.ty.display(ctx.sema.db)), - ctx.sema.diagnostics_display_range(d.span.clone()).range, + d.span.clone(), ) .experimental() // spans are broken, and I'm not sure how precise we can detect copy types } diff --git a/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/crates/ide-diagnostics/src/handlers/mutability_errors.rs index f61460e317f7..a0a6513326d5 100644 --- a/crates/ide-diagnostics/src/handlers/mutability_errors.rs +++ b/crates/ide-diagnostics/src/handlers/mutability_errors.rs @@ -2,7 +2,7 @@ use ide_db::source_change::SourceChange; use syntax::{AstNode, SyntaxKind, SyntaxNode, SyntaxToken, T}; use text_edit::TextEdit; -use crate::{fix, Diagnostic, DiagnosticsContext, Severity}; +use crate::{fix, Diagnostic, DiagnosticCode, DiagnosticsContext}; // Diagnostic: need-mut // @@ -29,13 +29,15 @@ pub(crate) fn need_mut(ctx: &DiagnosticsContext<'_>, d: &hir::NeedMut) -> Diagno use_range, )]) })(); - Diagnostic::new( - "need-mut", + Diagnostic::new_with_syntax_node_ptr( + ctx, + // FIXME: `E0384` is not the only error that this diagnostic handles + DiagnosticCode::RustcHardError("E0384"), format!( "cannot mutate immutable variable `{}`", d.local.name(ctx.sema.db).display(ctx.sema.db) ), - ctx.sema.diagnostics_display_range(d.span.clone()).range, + d.span.clone(), ) .with_fixes(fixes) } @@ -68,12 +70,12 @@ pub(crate) fn unused_mut(ctx: &DiagnosticsContext<'_>, d: &hir::UnusedMut) -> Di )]) })(); let ast = d.local.primary_source(ctx.sema.db).syntax_ptr(); - Diagnostic::new( - "unused-mut", + Diagnostic::new_with_syntax_node_ptr( + ctx, + DiagnosticCode::RustcLint("unused_mut"), "variable does not need to be mutable", - ctx.sema.diagnostics_display_range(ast).range, + ast, ) - .severity(Severity::WeakWarning) .experimental() // Not supporting `#[allow(unused_mut)]` leads to false positive. .with_fixes(fixes) } @@ -93,7 +95,7 @@ mod tests { fn f(_: i32) {} fn main() { let mut x = 2; - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable f(x); } "#, @@ -268,7 +270,7 @@ fn main() { fn f(_: i32) {} fn main() { let mut x = (2, 7); - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable f(x.1); } "#, @@ -302,7 +304,7 @@ fn main() { r#" fn main() { let mut x = &mut 2; - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable *x = 5; } "#, @@ -346,7 +348,7 @@ fn main() { r#" //- minicore: copy, builtin_impls fn clone(mut i: &!) -> ! { - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable *i } "#, @@ -360,7 +362,7 @@ fn main() { //- minicore: option fn main() { let mut v = &mut Some(2); - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable let _ = || match v { Some(k) => { *k = 5; @@ -386,7 +388,7 @@ fn main() { fn main() { match (2, 3) { (x, mut y) => { - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable x = 7; //^^^^^ 💡 error: cannot mutate immutable variable `x` } @@ -407,7 +409,7 @@ fn main() { fn main() { return; let mut x = 2; - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable &mut x; } "#, @@ -417,7 +419,7 @@ fn main() { fn main() { loop {} let mut x = 2; - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable &mut x; } "#, @@ -438,7 +440,7 @@ fn main(b: bool) { g(); } let mut x = 2; - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable &mut x; } "#, @@ -452,7 +454,7 @@ fn main(b: bool) { return; } let mut x = 2; - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable &mut x; } "#, @@ -466,7 +468,7 @@ fn main(b: bool) { fn f(_: i32) {} fn main() { let mut x; - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable x = 5; f(x); } @@ -477,7 +479,7 @@ fn main() { fn f(_: i32) {} fn main(b: bool) { let mut x; - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable if b { x = 1; } else { @@ -552,15 +554,15 @@ fn f(_: i32) {} fn main() { loop { let mut x = 1; - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable f(x); if let mut y = 2 { - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable f(y); } match 3 { mut z => f(z), - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable } } } @@ -577,9 +579,9 @@ fn main() { loop { let c @ ( mut b, - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable mut d - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable ); a = 1; //^^^^^ 💡 error: cannot mutate immutable variable `a` @@ -597,7 +599,7 @@ fn main() { check_diagnostics( r#" fn f(mut x: i32) { - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable } "#, ); @@ -640,7 +642,7 @@ fn f() { //- minicore: iterators, copy fn f(x: [(i32, u8); 10]) { for (a, mut b) in x { - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable a = 2; //^^^^^ 💡 error: cannot mutate immutable variable `a` } @@ -657,9 +659,9 @@ fn f(x: [(i32, u8); 10]) { fn f(x: [(i32, u8); 10]) { let mut it = x.into_iter(); while let Some((a, mut b)) = it.next() { - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable while let Some((c, mut d)) = it.next() { - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable a = 2; //^^^^^ 💡 error: cannot mutate immutable variable `a` c = 2; @@ -683,7 +685,7 @@ fn f() { let x = &mut x; //^^^^^^ 💡 error: cannot mutate immutable variable `x` let mut x = x; - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable x[2] = 5; } "#, @@ -711,13 +713,13 @@ impl IndexMut for Foo { } fn f() { let mut x = Foo; - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable let y = &x[2]; let x = Foo; let y = &mut x[2]; //^💡 error: cannot mutate immutable variable `x` let mut x = &mut Foo; - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable let y: &mut (i32, u8) = &mut x[2]; let x = Foo; let ref mut y = x[7]; @@ -731,7 +733,7 @@ fn f() { } let mut x = Foo; let mut i = 5; - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable let y = &mut x[i]; } "#, @@ -759,7 +761,7 @@ impl DerefMut for Foo { } fn f() { let mut x = Foo; - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable let y = &*x; let x = Foo; let y = &mut *x; @@ -790,7 +792,7 @@ fn f() { fn f(_: i32) {} fn main() { let ((Some(mut x), None) | (_, Some(mut x))) = (None, Some(7)); - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable f(x); } "#, @@ -842,7 +844,7 @@ pub struct TreeLeaf { pub fn test() { let mut tree = Tree::Leaf( - //^^^^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^^^^ 💡 warn: variable does not need to be mutable TreeLeaf { depth: 0, data: 0 @@ -859,7 +861,7 @@ pub fn test() { r#" //- minicore: fn fn fn_ref(mut x: impl Fn(u8) -> u8) -> u8 { - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable x(2) } fn fn_mut(x: impl FnMut(u8) -> u8) -> u8 { @@ -867,11 +869,11 @@ fn fn_mut(x: impl FnMut(u8) -> u8) -> u8 { //^ 💡 error: cannot mutate immutable variable `x` } fn fn_borrow_mut(mut x: &mut impl FnMut(u8) -> u8) -> u8 { - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable x(2) } fn fn_once(mut x: impl FnOnce(u8) -> u8) -> u8 { - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable x(2) } "#, @@ -915,14 +917,14 @@ fn fn_once(mut x: impl FnOnce(u8) -> u8) -> u8 { //- minicore: copy, fn fn f() { let mut x = 5; - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable let mut y = 2; y = 7; let closure = || { let mut z = 8; z = 3; let mut k = z; - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable }; } "#, @@ -949,7 +951,7 @@ fn f() { fn f() { struct X; let mut x = X; - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable let c1 = || x; let mut x = X; let c2 = || { x = X; x }; @@ -965,12 +967,12 @@ fn f() { fn f() { let mut x = &mut 5; - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable let closure1 = || { *x = 2; }; let _ = closure1(); //^^^^^^^^ 💡 error: cannot mutate immutable variable `closure1` let mut x = &mut 5; - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable let closure1 = || { *x = 2; &x; }; let _ = closure1(); //^^^^^^^^ 💡 error: cannot mutate immutable variable `closure1` @@ -979,12 +981,12 @@ fn f() { let _ = closure1(); //^^^^^^^^ 💡 error: cannot mutate immutable variable `closure1` let mut x = &mut 5; - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable let closure1 = move || { *x = 2; }; let _ = closure1(); //^^^^^^^^ 💡 error: cannot mutate immutable variable `closure1` let mut x = &mut X(1, 2); - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable let closure1 = || { x.0 = 2; }; let _ = closure1(); //^^^^^^^^ 💡 error: cannot mutate immutable variable `closure1` @@ -1001,7 +1003,7 @@ fn f() { fn x(t: &[u8]) { match t { &[a, mut b] | &[a, _, mut b] => { - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable a = 2; //^^^^^ 💡 error: cannot mutate immutable variable `a` @@ -1055,7 +1057,7 @@ fn f() { *x = 7; //^^^^^^ 💡 error: cannot mutate immutable variable `x` let mut y = Box::new(5); - //^^^^^ 💡 weak: variable does not need to be mutable + //^^^^^ 💡 warn: variable does not need to be mutable *x = *y; //^^^^^^^ 💡 error: cannot mutate immutable variable `x` let x = Box::new(5); @@ -1080,18 +1082,39 @@ fn main() { } #[test] - fn respect_allow_unused_mut() { - // FIXME: respect + fn respect_lint_attributes_for_unused_mut() { check_diagnostics( r#" fn f(_: i32) {} fn main() { #[allow(unused_mut)] let mut x = 2; - //^^^^^ 💡 weak: variable does not need to be mutable + f(x); +} + +fn main2() { + #[deny(unused_mut)] + let mut x = 2; + //^^^^^ 💡 error: variable does not need to be mutable f(x); } "#, ); + check_diagnostics( + r#" +macro_rules! mac { + ($($x:expr),*$(,)*) => ({ + #[allow(unused_mut)] + let mut vec = 2; + vec + }); +} + +fn main2() { + let mut x = mac![]; + //^^^^^ 💡 warn: variable does not need to be mutable +} + "#, + ); } } diff --git a/crates/ide-diagnostics/src/handlers/no_such_field.rs b/crates/ide-diagnostics/src/handlers/no_such_field.rs index a39eceab2437..a34a5824f296 100644 --- a/crates/ide-diagnostics/src/handlers/no_such_field.rs +++ b/crates/ide-diagnostics/src/handlers/no_such_field.rs @@ -6,16 +6,17 @@ use syntax::{ }; use text_edit::TextEdit; -use crate::{fix, Assist, Diagnostic, DiagnosticsContext}; +use crate::{fix, Assist, Diagnostic, DiagnosticCode, DiagnosticsContext}; // Diagnostic: no-such-field // // This diagnostic is triggered if created structure does not have field provided in record. pub(crate) fn no_such_field(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField) -> Diagnostic { - Diagnostic::new( - "no-such-field", + Diagnostic::new_with_syntax_node_ptr( + ctx, + DiagnosticCode::RustcHardError("E0559"), "no such field", - ctx.sema.diagnostics_display_range(d.field.clone().map(|it| it.into())).range, + d.field.clone().map(|it| it.into()), ) .with_fixes(fixes(ctx, d)) } diff --git a/crates/ide-diagnostics/src/handlers/private_assoc_item.rs b/crates/ide-diagnostics/src/handlers/private_assoc_item.rs index 4cd85a479a06..c44d28e77f6d 100644 --- a/crates/ide-diagnostics/src/handlers/private_assoc_item.rs +++ b/crates/ide-diagnostics/src/handlers/private_assoc_item.rs @@ -1,6 +1,6 @@ use either::Either; -use crate::{Diagnostic, DiagnosticsContext}; +use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; // Diagnostic: private-assoc-item // @@ -16,8 +16,9 @@ pub(crate) fn private_assoc_item( .name(ctx.sema.db) .map(|name| format!("`{}` ", name.display(ctx.sema.db))) .unwrap_or_default(); - Diagnostic::new( - "private-assoc-item", + Diagnostic::new_with_syntax_node_ptr( + ctx, + DiagnosticCode::RustcHardError("E0624"), format!( "{} {}is private", match d.item { @@ -27,15 +28,13 @@ pub(crate) fn private_assoc_item( }, name, ), - ctx.sema - .diagnostics_display_range(d.expr_or_pat.clone().map(|it| match it { + d.expr_or_pat.clone().map(|it| match it { + Either::Left(it) => it.into(), + Either::Right(it) => match it { Either::Left(it) => it.into(), - Either::Right(it) => match it { - Either::Left(it) => it.into(), - Either::Right(it) => it.into(), - }, - })) - .range, + Either::Right(it) => it.into(), + }, + }), ) } diff --git a/crates/ide-diagnostics/src/handlers/private_field.rs b/crates/ide-diagnostics/src/handlers/private_field.rs index de7f51f693c4..553defcf9905 100644 --- a/crates/ide-diagnostics/src/handlers/private_field.rs +++ b/crates/ide-diagnostics/src/handlers/private_field.rs @@ -1,18 +1,19 @@ -use crate::{Diagnostic, DiagnosticsContext}; +use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; // Diagnostic: private-field // // This diagnostic is triggered if the accessed field is not visible from the current module. pub(crate) fn private_field(ctx: &DiagnosticsContext<'_>, d: &hir::PrivateField) -> Diagnostic { // FIXME: add quickfix - Diagnostic::new( - "private-field", + Diagnostic::new_with_syntax_node_ptr( + ctx, + DiagnosticCode::RustcHardError("E0616"), format!( "field `{}` of `{}` is private", d.field.name(ctx.sema.db).display(ctx.sema.db), d.field.parent_def(ctx.sema.db).name(ctx.sema.db).display(ctx.sema.db) ), - ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range, + d.expr.clone().map(|it| it.into()), ) } diff --git a/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs b/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs index d3eda3c5ebce..083ef3e8dc16 100644 --- a/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs +++ b/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs @@ -6,7 +6,7 @@ use syntax::{ }; use text_edit::TextEdit; -use crate::{fix, Assist, Diagnostic, DiagnosticsContext, Severity}; +use crate::{fix, Assist, Diagnostic, DiagnosticCode, DiagnosticsContext}; // Diagnostic: replace-filter-map-next-with-find-map // @@ -15,12 +15,12 @@ pub(crate) fn replace_filter_map_next_with_find_map( ctx: &DiagnosticsContext<'_>, d: &hir::ReplaceFilterMapNextWithFindMap, ) -> Diagnostic { - Diagnostic::new( - "replace-filter-map-next-with-find-map", + Diagnostic::new_with_syntax_node_ptr( + ctx, + DiagnosticCode::Clippy("filter_map_next"), "replace filter_map(..).next() with find_map(..)", - ctx.sema.diagnostics_display_range(InFile::new(d.file, d.next_expr.clone().into())).range, + InFile::new(d.file, d.next_expr.clone().into()), ) - .severity(Severity::WeakWarning) .with_fixes(fixes(ctx, d)) } @@ -64,7 +64,7 @@ mod tests { pub(crate) fn check_diagnostics(ra_fixture: &str) { let mut config = DiagnosticsConfig::test_sample(); config.disabled.insert("inactive-code".to_string()); - config.disabled.insert("unresolved-method".to_string()); + config.disabled.insert("E0599".to_string()); check_diagnostics_with_config(config, ra_fixture) } @@ -139,4 +139,33 @@ fn foo() { "#, ) } + + #[test] + fn respect_lint_attributes_for_clippy_equivalent() { + check_diagnostics( + r#" +//- minicore: iterators + +fn foo() { + #[allow(clippy::filter_map_next)] + let m = core::iter::repeat(()).filter_map(|()| Some(92)).next(); +} + +#[deny(clippy::filter_map_next)] +fn foo() { + let m = core::iter::repeat(()).filter_map(|()| Some(92)).next(); +} //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 error: replace filter_map(..).next() with find_map(..) + +fn foo() { + let m = core::iter::repeat(()).filter_map(|()| Some(92)).next(); +} //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 weak: replace filter_map(..).next() with find_map(..) + +#[warn(clippy::filter_map_next)] +fn foo() { + let m = core::iter::repeat(()).filter_map(|()| Some(92)).next(); +} //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 warn: replace filter_map(..).next() with find_map(..) + +"#, + ); + } } diff --git a/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/crates/ide-diagnostics/src/handlers/type_mismatch.rs index c28f98d8333e..15bd28c00dfd 100644 --- a/crates/ide-diagnostics/src/handlers/type_mismatch.rs +++ b/crates/ide-diagnostics/src/handlers/type_mismatch.rs @@ -7,7 +7,7 @@ use syntax::{ }; use text_edit::TextEdit; -use crate::{adjusted_display_range, fix, Assist, Diagnostic, DiagnosticsContext}; +use crate::{adjusted_display_range, fix, Assist, Diagnostic, DiagnosticCode, DiagnosticsContext}; // Diagnostic: type-mismatch // @@ -39,7 +39,7 @@ pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) } }; let mut diag = Diagnostic::new( - "type-mismatch", + DiagnosticCode::RustcHardError("E0308"), format!( "expected {}, found {}", d.expected.display(ctx.sema.db).with_closure_style(ClosureStyle::ClosureWithId), diff --git a/crates/ide-diagnostics/src/handlers/typed_hole.rs b/crates/ide-diagnostics/src/handlers/typed_hole.rs index e12bbcf68206..4af67227115d 100644 --- a/crates/ide-diagnostics/src/handlers/typed_hole.rs +++ b/crates/ide-diagnostics/src/handlers/typed_hole.rs @@ -7,7 +7,7 @@ use ide_db::{ use syntax::AstNode; use text_edit::TextEdit; -use crate::{Diagnostic, DiagnosticsContext}; +use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; // Diagnostic: typed-hole // @@ -26,7 +26,8 @@ pub(crate) fn typed_hole(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Di ) }; - Diagnostic::new("typed-hole", message, display_range.range).with_fixes(fixes) + Diagnostic::new(DiagnosticCode::RustcHardError("typed-hole"), message, display_range.range) + .with_fixes(fixes) } fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Option> { diff --git a/crates/ide-diagnostics/src/handlers/undeclared_label.rs b/crates/ide-diagnostics/src/handlers/undeclared_label.rs index 034e4fcfb85b..7de9a9a323ec 100644 --- a/crates/ide-diagnostics/src/handlers/undeclared_label.rs +++ b/crates/ide-diagnostics/src/handlers/undeclared_label.rs @@ -1,4 +1,4 @@ -use crate::{Diagnostic, DiagnosticsContext}; +use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; // Diagnostic: undeclared-label pub(crate) fn undeclared_label( @@ -6,10 +6,11 @@ pub(crate) fn undeclared_label( d: &hir::UndeclaredLabel, ) -> Diagnostic { let name = &d.name; - Diagnostic::new( - "undeclared-label", + Diagnostic::new_with_syntax_node_ptr( + ctx, + DiagnosticCode::RustcHardError("undeclared-label"), format!("use of undeclared label `{}`", name.display(ctx.sema.db)), - ctx.sema.diagnostics_display_range(d.node.clone().map(|it| it.into())).range, + d.node.clone().map(|it| it.into()), ) } diff --git a/crates/ide-diagnostics/src/handlers/unimplemented_builtin_macro.rs b/crates/ide-diagnostics/src/handlers/unimplemented_builtin_macro.rs index e879de75cd84..bcce72a7d010 100644 --- a/crates/ide-diagnostics/src/handlers/unimplemented_builtin_macro.rs +++ b/crates/ide-diagnostics/src/handlers/unimplemented_builtin_macro.rs @@ -1,4 +1,4 @@ -use crate::{Diagnostic, DiagnosticsContext, Severity}; +use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext, Severity}; // Diagnostic: unimplemented-builtin-macro // @@ -7,10 +7,10 @@ pub(crate) fn unimplemented_builtin_macro( ctx: &DiagnosticsContext<'_>, d: &hir::UnimplementedBuiltinMacro, ) -> Diagnostic { - Diagnostic::new( - "unimplemented-builtin-macro", + Diagnostic::new_with_syntax_node_ptr( + ctx, + DiagnosticCode::Ra("unimplemented-builtin-macro", Severity::WeakWarning), "unimplemented built-in macro".to_string(), - ctx.sema.diagnostics_display_range(d.node.clone()).range, + d.node.clone(), ) - .severity(Severity::WeakWarning) } diff --git a/crates/ide-diagnostics/src/handlers/unlinked_file.rs b/crates/ide-diagnostics/src/handlers/unlinked_file.rs index 271e7ce73bcd..afb899f4fc50 100644 --- a/crates/ide-diagnostics/src/handlers/unlinked_file.rs +++ b/crates/ide-diagnostics/src/handlers/unlinked_file.rs @@ -14,7 +14,7 @@ use syntax::{ }; use text_edit::TextEdit; -use crate::{fix, Assist, Diagnostic, DiagnosticsContext, Severity}; +use crate::{fix, Assist, Diagnostic, DiagnosticCode, DiagnosticsContext, Severity}; // Diagnostic: unlinked-file // @@ -46,8 +46,7 @@ pub(crate) fn unlinked_file( .unwrap_or(range); acc.push( - Diagnostic::new("unlinked-file", message, range) - .severity(Severity::WeakWarning) + Diagnostic::new(DiagnosticCode::Ra("unlinked-file", Severity::WeakWarning), message, range) .with_fixes(fixes), ); } diff --git a/crates/ide-diagnostics/src/handlers/unreachable_label.rs b/crates/ide-diagnostics/src/handlers/unreachable_label.rs index 9fedadeae035..1c5d6cd0909f 100644 --- a/crates/ide-diagnostics/src/handlers/unreachable_label.rs +++ b/crates/ide-diagnostics/src/handlers/unreachable_label.rs @@ -1,4 +1,4 @@ -use crate::{Diagnostic, DiagnosticsContext}; +use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; // Diagnostic: unreachable-label pub(crate) fn unreachable_label( @@ -6,10 +6,11 @@ pub(crate) fn unreachable_label( d: &hir::UnreachableLabel, ) -> Diagnostic { let name = &d.name; - Diagnostic::new( - "unreachable-label", + Diagnostic::new_with_syntax_node_ptr( + ctx, + DiagnosticCode::RustcHardError("E0767"), format!("use of unreachable label `{}`", name.display(ctx.sema.db)), - ctx.sema.diagnostics_display_range(d.node.clone().map(|it| it.into())).range, + d.node.clone().map(|it| it.into()), ) } diff --git a/crates/ide-diagnostics/src/handlers/unresolved_extern_crate.rs b/crates/ide-diagnostics/src/handlers/unresolved_extern_crate.rs index 74e4a69c64b7..f8265b63275f 100644 --- a/crates/ide-diagnostics/src/handlers/unresolved_extern_crate.rs +++ b/crates/ide-diagnostics/src/handlers/unresolved_extern_crate.rs @@ -1,4 +1,4 @@ -use crate::{Diagnostic, DiagnosticsContext}; +use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; // Diagnostic: unresolved-extern-crate // @@ -7,10 +7,11 @@ pub(crate) fn unresolved_extern_crate( ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedExternCrate, ) -> Diagnostic { - Diagnostic::new( - "unresolved-extern-crate", + Diagnostic::new_with_syntax_node_ptr( + ctx, + DiagnosticCode::RustcHardError("unresolved-extern-crate"), "unresolved extern crate", - ctx.sema.diagnostics_display_range(d.decl.clone().map(|it| it.into())).range, + d.decl.clone().map(|it| it.into()), ) } diff --git a/crates/ide-diagnostics/src/handlers/unresolved_field.rs b/crates/ide-diagnostics/src/handlers/unresolved_field.rs index 5e4efa41fd9c..94d49d4d48b2 100644 --- a/crates/ide-diagnostics/src/handlers/unresolved_field.rs +++ b/crates/ide-diagnostics/src/handlers/unresolved_field.rs @@ -8,7 +8,7 @@ use ide_db::{ use syntax::{ast, AstNode, AstPtr}; use text_edit::TextEdit; -use crate::{Diagnostic, DiagnosticsContext}; +use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; // Diagnostic: unresolved-field // @@ -22,14 +22,15 @@ pub(crate) fn unresolved_field( } else { "" }; - Diagnostic::new( - "unresolved-field", + Diagnostic::new_with_syntax_node_ptr( + ctx, + DiagnosticCode::RustcHardError("E0559"), format!( "no field `{}` on type `{}`{method_suffix}", d.name.display(ctx.sema.db), d.receiver.display(ctx.sema.db) ), - ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range, + d.expr.clone().map(|it| it.into()), ) .with_fixes(fixes(ctx, d)) .experimental() diff --git a/crates/ide-diagnostics/src/handlers/unresolved_import.rs b/crates/ide-diagnostics/src/handlers/unresolved_import.rs index e52a88459d55..6b8026c03419 100644 --- a/crates/ide-diagnostics/src/handlers/unresolved_import.rs +++ b/crates/ide-diagnostics/src/handlers/unresolved_import.rs @@ -1,4 +1,4 @@ -use crate::{Diagnostic, DiagnosticsContext}; +use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; // Diagnostic: unresolved-import // @@ -8,10 +8,11 @@ pub(crate) fn unresolved_import( ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedImport, ) -> Diagnostic { - Diagnostic::new( - "unresolved-import", + Diagnostic::new_with_syntax_node_ptr( + ctx, + DiagnosticCode::RustcHardError("E0432"), "unresolved import", - ctx.sema.diagnostics_display_range(d.decl.clone().map(|it| it.into())).range, + d.decl.clone().map(|it| it.into()), ) // This currently results in false positives in the following cases: // - `cfg_if!`-generated code in libstd (we don't load the sysroot correctly) diff --git a/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs b/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs index 3943b51ab422..33e7c2e37c3b 100644 --- a/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs +++ b/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs @@ -1,4 +1,4 @@ -use crate::{Diagnostic, DiagnosticsContext}; +use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; // Diagnostic: unresolved-macro-call // @@ -12,7 +12,7 @@ pub(crate) fn unresolved_macro_call( let display_range = ctx.resolve_precise_location(&d.macro_call, d.precise_location); let bang = if d.is_bang { "!" } else { "" }; Diagnostic::new( - "unresolved-macro-call", + DiagnosticCode::RustcHardError("unresolved-macro-call"), format!("unresolved macro `{}{bang}`", d.path.display(ctx.sema.db)), display_range, ) diff --git a/crates/ide-diagnostics/src/handlers/unresolved_method.rs b/crates/ide-diagnostics/src/handlers/unresolved_method.rs index 8bbb837e6709..ae9f6744c40f 100644 --- a/crates/ide-diagnostics/src/handlers/unresolved_method.rs +++ b/crates/ide-diagnostics/src/handlers/unresolved_method.rs @@ -8,7 +8,7 @@ use ide_db::{ use syntax::{ast, AstNode, TextRange}; use text_edit::TextEdit; -use crate::{Diagnostic, DiagnosticsContext}; +use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; // Diagnostic: unresolved-method // @@ -22,14 +22,15 @@ pub(crate) fn unresolved_method( } else { "" }; - Diagnostic::new( - "unresolved-method", + Diagnostic::new_with_syntax_node_ptr( + ctx, + DiagnosticCode::RustcHardError("E0599"), format!( "no method `{}` on type `{}`{field_suffix}", d.name.display(ctx.sema.db), d.receiver.display(ctx.sema.db) ), - ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range, + d.expr.clone().map(|it| it.into()), ) .with_fixes(fixes(ctx, d)) .experimental() diff --git a/crates/ide-diagnostics/src/handlers/unresolved_module.rs b/crates/ide-diagnostics/src/handlers/unresolved_module.rs index 6e3fd3b42b0c..be24e50c9871 100644 --- a/crates/ide-diagnostics/src/handlers/unresolved_module.rs +++ b/crates/ide-diagnostics/src/handlers/unresolved_module.rs @@ -3,7 +3,7 @@ use ide_db::{assists::Assist, base_db::AnchoredPathBuf, source_change::FileSyste use itertools::Itertools; use syntax::AstNode; -use crate::{fix, Diagnostic, DiagnosticsContext}; +use crate::{fix, Diagnostic, DiagnosticCode, DiagnosticsContext}; // Diagnostic: unresolved-module // @@ -12,8 +12,9 @@ pub(crate) fn unresolved_module( ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedModule, ) -> Diagnostic { - Diagnostic::new( - "unresolved-module", + Diagnostic::new_with_syntax_node_ptr( + ctx, + DiagnosticCode::RustcHardError("E0583"), match &*d.candidates { [] => "unresolved module".to_string(), [candidate] => format!("unresolved module, can't find module file: {candidate}"), @@ -25,7 +26,7 @@ pub(crate) fn unresolved_module( ) } }, - ctx.sema.diagnostics_display_range(d.decl.clone().map(|it| it.into())).range, + d.decl.clone().map(|it| it.into()), ) .with_fixes(fixes(ctx, d)) } @@ -82,8 +83,8 @@ mod baz {} expect![[r#" [ Diagnostic { - code: DiagnosticCode( - "unresolved-module", + code: RustcHardError( + "E0583", ), message: "unresolved module, can't find module file: foo.rs, or foo/mod.rs", range: 0..8, @@ -148,6 +149,22 @@ mod baz {} }, ], ), + main_node: Some( + InFile { + file_id: FileId( + FileId( + 0, + ), + ), + value: MODULE@0..8 + MOD_KW@0..3 "mod" + WHITESPACE@3..4 " " + NAME@4..7 + IDENT@4..7 "foo" + SEMICOLON@7..8 ";" + , + }, + ), }, ] "#]], diff --git a/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs b/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs index ae5cf135839f..015a3d6b2ce7 100644 --- a/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs +++ b/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs @@ -1,6 +1,6 @@ use hir::db::DefDatabase; -use crate::{Diagnostic, DiagnosticsContext, Severity}; +use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext, Severity}; // Diagnostic: unresolved-proc-macro // @@ -41,5 +41,5 @@ pub(crate) fn unresolved_proc_macro( }; let message = format!("{not_expanded_message}: {message}"); - Diagnostic::new("unresolved-proc-macro", message, display_range).severity(severity) + Diagnostic::new(DiagnosticCode::Ra("unresolved-proc-macro", severity), message, display_range) } diff --git a/crates/ide-diagnostics/src/handlers/useless_braces.rs b/crates/ide-diagnostics/src/handlers/useless_braces.rs index 289ed0458c67..11ce811efaa5 100644 --- a/crates/ide-diagnostics/src/handlers/useless_braces.rs +++ b/crates/ide-diagnostics/src/handlers/useless_braces.rs @@ -3,7 +3,7 @@ use itertools::Itertools; use syntax::{ast, AstNode, SyntaxNode, TextRange}; use text_edit::TextEdit; -use crate::{fix, Diagnostic, Severity}; +use crate::{fix, Diagnostic, DiagnosticCode}; // Diagnostic: unnecessary-braces // @@ -32,11 +32,10 @@ pub(crate) fn useless_braces( acc.push( Diagnostic::new( - "unnecessary-braces", + DiagnosticCode::RustcLint("unused_braces"), "Unnecessary braces in use statement".to_string(), use_range, ) - .severity(Severity::WeakWarning) .with_fixes(Some(vec![fix( "remove_braces", "Remove unnecessary braces", diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs index 55a4a482d3b2..e6b2eeeddf04 100644 --- a/crates/ide-diagnostics/src/lib.rs +++ b/crates/ide-diagnostics/src/lib.rs @@ -67,24 +67,61 @@ mod handlers { #[cfg(test)] mod tests; +use std::collections::HashMap; + use hir::{diagnostics::AnyDiagnostic, InFile, Semantics}; use ide_db::{ assists::{Assist, AssistId, AssistKind, AssistResolveStrategy}, base_db::{FileId, FileRange, SourceDatabase}, + generated::lints::{LintGroup, CLIPPY_LINT_GROUPS, DEFAULT_LINT_GROUPS}, imports::insert_use::InsertUseConfig, label::Label, source_change::SourceChange, - FxHashSet, RootDatabase, + syntax_helpers::node_ext::parse_tt_as_comma_sep_paths, + FxHashMap, FxHashSet, RootDatabase, +}; +use once_cell::sync::Lazy; +use stdx::never; +use syntax::{ + algo::find_node_at_range, + ast::{self, AstNode}, + SyntaxNode, SyntaxNodePtr, TextRange, }; -use syntax::{algo::find_node_at_range, ast::AstNode, SyntaxNodePtr, TextRange}; // FIXME: Make this an enum -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct DiagnosticCode(pub &'static str); +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum DiagnosticCode { + RustcHardError(&'static str), + RustcLint(&'static str), + Clippy(&'static str), + Ra(&'static str, Severity), +} impl DiagnosticCode { - pub fn as_str(&self) -> &str { - self.0 + pub fn url(&self) -> String { + match self { + DiagnosticCode::RustcHardError(e) => { + format!("https://doc.rust-lang.org/stable/error_codes/{e}.html") + } + DiagnosticCode::RustcLint(e) => { + format!("https://doc.rust-lang.org/rustc/?search={e}") + } + DiagnosticCode::Clippy(e) => { + format!("https://rust-lang.github.io/rust-clippy/master/#/{e}") + } + DiagnosticCode::Ra(e, _) => { + format!("https://rust-analyzer.github.io/manual.html#{e}") + } + } + } + + pub fn as_str(&self) -> &'static str { + match self { + DiagnosticCode::RustcHardError(r) + | DiagnosticCode::RustcLint(r) + | DiagnosticCode::Clippy(r) + | DiagnosticCode::Ra(r, _) => r, + } } } @@ -97,29 +134,51 @@ pub struct Diagnostic { pub unused: bool, pub experimental: bool, pub fixes: Option>, + // The node that will be affected by `#[allow]` and similar attributes. + pub main_node: Option>, } impl Diagnostic { - fn new(code: &'static str, message: impl Into, range: TextRange) -> Diagnostic { + fn new(code: DiagnosticCode, message: impl Into, range: TextRange) -> Diagnostic { let message = message.into(); Diagnostic { - code: DiagnosticCode(code), + code, message, range, - severity: Severity::Error, + severity: match code { + DiagnosticCode::RustcHardError(_) => Severity::Error, + // FIXME: Rustc lints are not always warning, but the ones that are currently implemented are all warnings. + DiagnosticCode::RustcLint(_) => Severity::Warning, + // FIXME: We can make this configurable, and if the user uses `cargo clippy` on flycheck, we can + // make it normal warning. + DiagnosticCode::Clippy(_) => Severity::WeakWarning, + DiagnosticCode::Ra(_, s) => s, + }, unused: false, experimental: false, fixes: None, + main_node: None, } } + fn new_with_syntax_node_ptr( + ctx: &DiagnosticsContext<'_>, + code: DiagnosticCode, + message: impl Into, + node: InFile, + ) -> Diagnostic { + let file_id = node.file_id; + Diagnostic::new(code, message, ctx.sema.diagnostics_display_range(node.clone()).range) + .with_main_node(node.map(|x| x.to_node(&ctx.sema.parse_or_expand(file_id)))) + } + fn experimental(mut self) -> Diagnostic { self.experimental = true; self } - fn severity(mut self, severity: Severity) -> Diagnostic { - self.severity = severity; + fn with_main_node(mut self, main_node: InFile) -> Diagnostic { + self.main_node = Some(main_node); self } @@ -134,12 +193,12 @@ impl Diagnostic { } } -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum Severity { Error, - // We don't actually emit this one yet, but we should at some point. - // Warning, + Warning, WeakWarning, + Allow, } #[derive(Clone, Debug, PartialEq, Eq)] @@ -228,11 +287,13 @@ pub fn diagnostics( let mut res = Vec::new(); // [#34344] Only take first 128 errors to prevent slowing down editor/ide, the number 128 is chosen arbitrarily. - res.extend( - parse.errors().iter().take(128).map(|err| { - Diagnostic::new("syntax-error", format!("Syntax Error: {err}"), err.range()) - }), - ); + res.extend(parse.errors().iter().take(128).map(|err| { + Diagnostic::new( + DiagnosticCode::RustcHardError("syntax-error"), + format!("Syntax Error: {err}"), + err.range(), + ) + })); let parse = sema.parse(file_id); @@ -271,7 +332,7 @@ pub fn diagnostics( res.extend(d.errors.iter().take(32).map(|err| { { Diagnostic::new( - "syntax-error", + DiagnosticCode::RustcHardError("syntax-error"), format!("Syntax Error in Expansion: {err}"), ctx.resolve_precise_location(&d.node.clone(), d.precise_location), ) @@ -309,14 +370,168 @@ pub fn diagnostics( res.push(d) } + let mut diagnostics_of_range = + res.iter_mut().filter_map(|x| Some((x.main_node.clone()?, x))).collect::>(); + + let mut rustc_stack: FxHashMap> = FxHashMap::default(); + let mut clippy_stack: FxHashMap> = FxHashMap::default(); + + handle_lint_attributes( + &ctx.sema, + parse.syntax(), + &mut rustc_stack, + &mut clippy_stack, + &mut diagnostics_of_range, + ); + res.retain(|d| { - !ctx.config.disabled.contains(d.code.as_str()) + d.severity != Severity::Allow + && !ctx.config.disabled.contains(d.code.as_str()) && !(ctx.config.disable_experimental && d.experimental) }); res } +// `__RA_EVERY_LINT` is a fake lint group to allow every lint in proc macros + +static RUSTC_LINT_GROUPS_DICT: Lazy>> = + Lazy::new(|| build_group_dict(DEFAULT_LINT_GROUPS, &["warnings", "__RA_EVERY_LINT"], "")); + +static CLIPPY_LINT_GROUPS_DICT: Lazy>> = + Lazy::new(|| build_group_dict(CLIPPY_LINT_GROUPS, &["__RA_EVERY_LINT"], "clippy::")); + +fn build_group_dict( + lint_group: &'static [LintGroup], + all_groups: &'static [&'static str], + prefix: &'static str, +) -> HashMap<&'static str, Vec<&'static str>> { + let mut r: HashMap<&str, Vec<&str>> = HashMap::new(); + for g in lint_group { + for child in g.children { + r.entry(child.strip_prefix(prefix).unwrap()) + .or_default() + .push(g.lint.label.strip_prefix(prefix).unwrap()); + } + } + for (lint, groups) in r.iter_mut() { + groups.push(lint); + groups.extend_from_slice(all_groups); + } + r +} + +fn handle_lint_attributes( + sema: &Semantics<'_, RootDatabase>, + root: &SyntaxNode, + rustc_stack: &mut FxHashMap>, + clippy_stack: &mut FxHashMap>, + diagnostics_of_range: &mut FxHashMap, &mut Diagnostic>, +) { + let file_id = sema.hir_file_for(root); + for ev in root.preorder() { + match ev { + syntax::WalkEvent::Enter(node) => { + for attr in node.children().filter_map(ast::Attr::cast) { + parse_lint_attribute(attr, rustc_stack, clippy_stack, |stack, severity| { + stack.push(severity); + }); + } + if let Some(x) = + diagnostics_of_range.get_mut(&InFile { file_id, value: node.clone() }) + { + const EMPTY_LINTS: &[&str] = &[]; + let (names, stack) = match x.code { + DiagnosticCode::RustcLint(name) => ( + RUSTC_LINT_GROUPS_DICT.get(name).map_or(EMPTY_LINTS, |x| &**x), + &mut *rustc_stack, + ), + DiagnosticCode::Clippy(name) => ( + CLIPPY_LINT_GROUPS_DICT.get(name).map_or(EMPTY_LINTS, |x| &**x), + &mut *clippy_stack, + ), + _ => continue, + }; + for &name in names { + if let Some(s) = stack.get(name).and_then(|x| x.last()) { + x.severity = *s; + } + } + } + if let Some(item) = ast::Item::cast(node.clone()) { + if let Some(me) = sema.expand_attr_macro(&item) { + for stack in [&mut *rustc_stack, &mut *clippy_stack] { + stack + .entry("__RA_EVERY_LINT".to_owned()) + .or_default() + .push(Severity::Allow); + } + handle_lint_attributes( + sema, + &me, + rustc_stack, + clippy_stack, + diagnostics_of_range, + ); + for stack in [&mut *rustc_stack, &mut *clippy_stack] { + stack.entry("__RA_EVERY_LINT".to_owned()).or_default().pop(); + } + } + } + if let Some(mc) = ast::MacroCall::cast(node) { + if let Some(me) = sema.expand(&mc) { + handle_lint_attributes( + sema, + &me, + rustc_stack, + clippy_stack, + diagnostics_of_range, + ); + } + } + } + syntax::WalkEvent::Leave(node) => { + for attr in node.children().filter_map(ast::Attr::cast) { + parse_lint_attribute(attr, rustc_stack, clippy_stack, |stack, severity| { + if stack.pop() != Some(severity) { + never!("Mismatched serevity in walking lint attributes"); + } + }); + } + } + } + } +} + +fn parse_lint_attribute( + attr: ast::Attr, + rustc_stack: &mut FxHashMap>, + clippy_stack: &mut FxHashMap>, + job: impl Fn(&mut Vec, Severity), +) { + let Some((tag, args_tt)) = attr.as_simple_call() else { + return; + }; + let serevity = match tag.as_str() { + "allow" => Severity::Allow, + "warn" => Severity::Warning, + "forbid" | "deny" => Severity::Error, + _ => return, + }; + for lint in parse_tt_as_comma_sep_paths(args_tt).into_iter().flatten() { + if let Some(lint) = lint.as_single_name_ref() { + job(rustc_stack.entry(lint.to_string()).or_default(), serevity); + } + if let Some(tool) = lint.qualifier().and_then(|x| x.as_single_name_ref()) { + if let Some(name_ref) = &lint.segment().and_then(|x| x.name_ref()) { + if tool.to_string() == "clippy" { + job(clippy_stack.entry(name_ref.to_string()).or_default(), serevity); + } + } + } + } +} + fn fix(id: &'static str, label: &str, source_change: SourceChange, target: TextRange) -> Assist { let mut res = unresolved_fix(id, label, target); res.source_change = Some(source_change); diff --git a/crates/ide-diagnostics/src/tests.rs b/crates/ide-diagnostics/src/tests.rs index b5cd4e0d6891..4ac9d0a9fb73 100644 --- a/crates/ide-diagnostics/src/tests.rs +++ b/crates/ide-diagnostics/src/tests.rs @@ -114,6 +114,8 @@ pub(crate) fn check_diagnostics_with_config(config: DiagnosticsConfig, ra_fixtur annotation.push_str(match d.severity { Severity::Error => "error", Severity::WeakWarning => "weak", + Severity::Warning => "warn", + Severity::Allow => "allow", }); annotation.push_str(": "); annotation.push_str(&d.message); @@ -130,14 +132,19 @@ pub(crate) fn check_diagnostics_with_config(config: DiagnosticsConfig, ra_fixtur ) } } - assert_eq!(expected, actual); + if expected != actual { + let fneg = expected.iter().filter(|x| !actual.contains(x)).collect::>(); + let fpos = actual.iter().filter(|x| !expected.contains(x)).collect::>(); + + panic!("Diagnostic test failed.\nFalse negatives: {fneg:?}\nFalse positives: {fpos:?}"); + } } } #[test] fn test_disabled_diagnostics() { let mut config = DiagnosticsConfig::test_sample(); - config.disabled.insert("unresolved-module".into()); + config.disabled.insert("E0583".into()); let (db, file_id) = RootDatabase::with_single_file(r#"mod foo;"#); @@ -159,7 +166,7 @@ fn minicore_smoke_test() { let source = minicore.source_code(); let mut config = DiagnosticsConfig::test_sample(); // This should be ignored since we conditionaly remove code which creates single item use with braces - config.disabled.insert("unnecessary-braces".to_string()); + config.disabled.insert("unused_braces".to_string()); check_diagnostics_with_config(config, &source); } diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index c70f60513b59..0a20472fe7be 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -831,11 +831,7 @@ impl GlobalState { d.code.as_str().to_string(), )), code_description: Some(lsp_types::CodeDescription { - href: lsp_types::Url::parse(&format!( - "https://rust-analyzer.github.io/manual.html#{}", - d.code.as_str() - )) - .unwrap(), + href: lsp_types::Url::parse(&d.code.url()).unwrap(), }), source: Some("rust-analyzer".to_string()), message: d.message, diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 648bc995ad5e..ba3421bf9e76 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -94,7 +94,10 @@ pub(crate) fn document_highlight_kind( pub(crate) fn diagnostic_severity(severity: Severity) -> lsp_types::DiagnosticSeverity { match severity { Severity::Error => lsp_types::DiagnosticSeverity::ERROR, + Severity::Warning => lsp_types::DiagnosticSeverity::WARNING, Severity::WeakWarning => lsp_types::DiagnosticSeverity::HINT, + // unreachable + Severity::Allow => lsp_types::DiagnosticSeverity::INFORMATION, } } From 58ac823864d55ba06f604a851c780c293e137e99 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 17 Jun 2023 10:58:52 +0200 Subject: [PATCH 004/324] Less eager parsing for module sources --- crates/hir-def/src/nameres.rs | 13 ++++++++++++- crates/hir/src/has_source.rs | 18 +++++++++++++++++- crates/ide-completion/src/completions/mod_.rs | 2 +- crates/ide-db/src/search.rs | 6 ++---- crates/ide/src/static_index.rs | 4 ++-- crates/rust-analyzer/src/cli/analysis_stats.rs | 2 +- crates/rust-analyzer/src/cli/diagnostics.rs | 4 ++-- 7 files changed, 37 insertions(+), 12 deletions(-) diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs index 0ab1bd8490c5..e7a4355d258a 100644 --- a/crates/hir-def/src/nameres.rs +++ b/crates/hir-def/src/nameres.rs @@ -60,7 +60,7 @@ mod tests; use std::{cmp::Ord, ops::Deref}; use base_db::{CrateId, Edition, FileId, ProcMacroKind}; -use hir_expand::{name::Name, InFile, MacroCallId, MacroDefId}; +use hir_expand::{name::Name, HirFileId, InFile, MacroCallId, MacroDefId}; use itertools::Itertools; use la_arena::Arena; use profile::Count; @@ -626,6 +626,17 @@ impl ModuleData { self.origin.definition_source(db) } + /// Same as [`definition_source`] but only returns the file id to prevent parsing the ASt. + pub fn definition_source_file_id(&self) -> HirFileId { + match self.origin { + ModuleOrigin::File { definition, .. } | ModuleOrigin::CrateRoot { definition } => { + definition.into() + } + ModuleOrigin::Inline { definition, .. } => definition.file_id, + ModuleOrigin::BlockExpr { block } => block.file_id, + } + } + /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`. /// `None` for the crate root or block. pub fn declaration_source(&self, db: &dyn DefDatabase) -> Option> { diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs index 9f6b5c0a9fcc..63d11155c6a5 100644 --- a/crates/hir/src/has_source.rs +++ b/crates/hir/src/has_source.rs @@ -1,12 +1,13 @@ //! Provides set of implementation for hir's objects that allows get back location in file. +use base_db::FileId; use either::Either; use hir_def::{ nameres::{ModuleOrigin, ModuleSource}, src::{HasChildSource, HasSource as _}, Lookup, MacroId, VariantId, }; -use hir_expand::InFile; +use hir_expand::{HirFileId, InFile}; use syntax::ast; use crate::{ @@ -32,6 +33,11 @@ impl Module { def_map[self.id.local_id].definition_source(db.upcast()) } + pub fn definition_source_file_id(self, db: &dyn HirDatabase) -> HirFileId { + let def_map = self.id.def_map(db.upcast()); + def_map[self.id.local_id].definition_source_file_id() + } + pub fn is_mod_rs(self, db: &dyn HirDatabase) -> bool { let def_map = self.id.def_map(db.upcast()); match def_map[self.id.local_id].origin { @@ -40,6 +46,16 @@ impl Module { } } + pub fn as_source_file_id(self, db: &dyn HirDatabase) -> Option { + let def_map = self.id.def_map(db.upcast()); + match def_map[self.id.local_id].origin { + ModuleOrigin::File { definition, .. } | ModuleOrigin::CrateRoot { definition, .. } => { + Some(definition) + } + _ => None, + } + } + pub fn is_inline(self, db: &dyn HirDatabase) -> bool { let def_map = self.id.def_map(db.upcast()); def_map[self.id.local_id].origin.is_inline() diff --git a/crates/ide-completion/src/completions/mod_.rs b/crates/ide-completion/src/completions/mod_.rs index d3e75c6da476..1e09894059d5 100644 --- a/crates/ide-completion/src/completions/mod_.rs +++ b/crates/ide-completion/src/completions/mod_.rs @@ -42,7 +42,7 @@ pub(crate) fn complete_mod( } let module_definition_file = - current_module.definition_source(ctx.db).file_id.original_file(ctx.db); + current_module.definition_source_file_id(ctx.db).original_file(ctx.db); let source_root = ctx.db.source_root(ctx.db.file_source_root(module_definition_file)); let directory_to_look_for_submodules = directory_to_look_for_submodules( current_module, diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs index e8ff107bd495..16f359818385 100644 --- a/crates/ide-db/src/search.rs +++ b/crates/ide-db/src/search.rs @@ -149,10 +149,8 @@ impl SearchScope { let mut to_visit: Vec<_> = module.children(db).collect(); while let Some(module) = to_visit.pop() { - if let InFile { file_id, value: ModuleSource::SourceFile(_) } = - module.definition_source(db) - { - entries.insert(file_id.original_file(db), None); + if let Some(file_id) = module.as_source_file_id(db) { + entries.insert(file_id, None); } to_visit.extend(module.children(db)); } diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs index 3e3d9f8f85c4..03c7ee478a61 100644 --- a/crates/ide/src/static_index.rs +++ b/crates/ide/src/static_index.rs @@ -187,7 +187,7 @@ impl StaticIndex<'_> { pub fn compute(analysis: &Analysis) -> StaticIndex<'_> { let db = &*analysis.db; let work = all_modules(db).into_iter().filter(|module| { - let file_id = module.definition_source(db).file_id.original_file(db); + let file_id = module.definition_source_file_id(db).original_file(db); let source_root = db.file_source_root(file_id); let source_root = db.source_root(source_root); !source_root.is_library @@ -201,7 +201,7 @@ impl StaticIndex<'_> { }; let mut visited_files = FxHashSet::default(); for module in work { - let file_id = module.definition_source(db).file_id.original_file(db); + let file_id = module.definition_source_file_id(db).original_file(db); if visited_files.contains(&file_id) { continue; } diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index 01bc0d77dd5b..9d6c633f4c3f 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -105,7 +105,7 @@ impl flags::AnalysisStats { } for krate in krates { let module = krate.root_module(db); - let file_id = module.definition_source(db).file_id; + let file_id = module.definition_source_file_id(db); let file_id = file_id.original_file(db); let source_root = db.file_source_root(file_id); let source_root = db.source_root(source_root); diff --git a/crates/rust-analyzer/src/cli/diagnostics.rs b/crates/rust-analyzer/src/cli/diagnostics.rs index 4306d721298d..0b46f35074e7 100644 --- a/crates/rust-analyzer/src/cli/diagnostics.rs +++ b/crates/rust-analyzer/src/cli/diagnostics.rs @@ -37,14 +37,14 @@ impl flags::Diagnostics { let mut visited_files = FxHashSet::default(); let work = all_modules(db).into_iter().filter(|module| { - let file_id = module.definition_source(db).file_id.original_file(db); + let file_id = module.definition_source_file_id(db).original_file(db); let source_root = db.file_source_root(file_id); let source_root = db.source_root(source_root); !source_root.is_library }); for module in work { - let file_id = module.definition_source(db).file_id.original_file(db); + let file_id = module.definition_source_file_id(db).original_file(db); if !visited_files.contains(&file_id) { let crate_name = module.krate().display_name(db).as_deref().unwrap_or("unknown").to_string(); From a824b734dd1dda4337b17ffae3b8c80eaad24cec Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 17 Jun 2023 11:20:21 +0200 Subject: [PATCH 005/324] Report metric timings for file item trees and crate def map creation --- .../rust-analyzer/src/cli/analysis_stats.rs | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index 9d6c633f4c3f..7c982fcc22a5 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -95,14 +95,38 @@ impl flags::AnalysisStats { eprintln!(")"); let mut analysis_sw = self.stop_watch(); - let mut num_crates = 0; - let mut visited_modules = FxHashSet::default(); - let mut visit_queue = Vec::new(); let mut krates = Crate::all(db); if self.randomize { shuffle(&mut rng, &mut krates); } + + let mut item_tree_sw = self.stop_watch(); + let mut num_item_trees = 0; + let source_roots = + krates.iter().cloned().map(|krate| db.file_source_root(krate.root_file(db))).unique(); + for source_root_id in source_roots { + let source_root = db.source_root(source_root_id); + if !source_root.is_library || self.with_deps { + for file_id in source_root.iter() { + if let Some(p) = source_root.path_for_file(&file_id) { + if let Some((_, Some("rs"))) = p.name_and_extension() { + db.file_item_tree(file_id.into()); + num_item_trees += 1; + } + } + } + } + } + eprintln!(" item trees: {num_item_trees}"); + let item_tree_time = item_tree_sw.elapsed(); + eprintln!("{:<20} {}", "Item Tree Collection:", item_tree_time); + report_metric("item tree time", item_tree_time.time.as_millis() as u64, "ms"); + + let mut crate_def_map_sw = self.stop_watch(); + let mut num_crates = 0; + let mut visited_modules = FxHashSet::default(); + let mut visit_queue = Vec::new(); for krate in krates { let module = krate.root_module(db); let file_id = module.definition_source_file_id(db); @@ -169,7 +193,9 @@ impl flags::AnalysisStats { visited_modules.len(), bodies.len() ); - eprintln!("{:<20} {}", "Item Collection:", analysis_sw.elapsed()); + let crate_def_map_time = crate_def_map_sw.elapsed(); + eprintln!("{:<20} {}", "Item Collection:", crate_def_map_time); + report_metric("crate def map time", crate_def_map_time.time.as_millis() as u64, "ms"); if self.randomize { shuffle(&mut rng, &mut bodies); From 8123a39c82f31d86cdfd1adf92cff44b8391d0b5 Mon Sep 17 00:00:00 2001 From: Ali Bektas Date: Fri, 2 Jun 2023 11:51:11 +0200 Subject: [PATCH 006/324] Generate delegate trait --- .../src/handlers/generate_delegate_trait.rs | 1064 +++++++++++++++++ crates/ide-assists/src/lib.rs | 2 + crates/ide-assists/src/tests/generated.rs | 63 + 3 files changed, 1129 insertions(+) create mode 100644 crates/ide-assists/src/handlers/generate_delegate_trait.rs diff --git a/crates/ide-assists/src/handlers/generate_delegate_trait.rs b/crates/ide-assists/src/handlers/generate_delegate_trait.rs new file mode 100644 index 000000000000..ce8f4256c085 --- /dev/null +++ b/crates/ide-assists/src/handlers/generate_delegate_trait.rs @@ -0,0 +1,1064 @@ +use std::ops::Not; + +use crate::{ + assist_context::{AssistContext, Assists}, + utils::convert_param_list_to_arg_list, +}; +use either::Either; +use hir::{db::HirDatabase, HasVisibility}; +use ide_db::{ + assists::{AssistId, GroupLabel}, + path_transform::PathTransform, +}; +use syntax::{ + ast::{ + self, + edit::{self, AstNodeEdit}, + make, AssocItem, HasGenericParams, HasName, HasVisibility as astHasVisibility, Path, + }, + ted::{self, Position}, + AstNode, NodeOrToken, SyntaxKind, +}; + +// Assist: generate_delegate_trait +// +// Generate delegate trait implementation for `StructField`s. +// +// ``` +// trait SomeTrait { +// type T; +// fn fn_(arg: u32) -> u32; +// fn method_(&mut self) -> bool; +// } +// struct A; +// impl SomeTrait for A { +// type T = u32; +// +// fn fn_(arg: u32) -> u32 { +// 42 +// } +// +// fn method_(&mut self) -> bool { +// false +// } +// } +// struct B { +// a$0: A, +// } +// ``` +// -> +// ``` +// trait SomeTrait { +// type T; +// fn fn_(arg: u32) -> u32; +// fn method_(&mut self) -> bool; +// } +// struct A; +// impl SomeTrait for A { +// type T = u32; +// +// fn fn_(arg: u32) -> u32 { +// 42 +// } +// +// fn method_(&mut self) -> bool { +// false +// } +// } +// struct B { +// a: A, +// } +// +// impl SomeTrait for B { +// type T = ::T; +// +// fn fn_(arg: u32) -> u32 { +// ::fn_(arg) +// } +// +// fn method_(&mut self) -> bool { +// ::method_( &mut self.a ) +// } +// } +// ``` +pub(crate) fn generate_delegate_trait(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + let strukt = Struct::new(ctx.find_node_at_offset::()?)?; + + let field: Field = match ctx.find_node_at_offset::() { + Some(field) => Field::new(&ctx, Either::Left(field))?, + None => { + let field = ctx.find_node_at_offset::()?; + let field_list = ctx.find_node_at_offset::()?; + Field::new(&ctx, either::Right((field, field_list)))? + } + }; + + strukt.delegate(field, acc, ctx); + Some(()) +} + +/// A utility object that represents a struct's field. +struct Field { + name: String, + ty: ast::Type, + range: syntax::TextRange, + impls: Vec, +} + +impl Field { + pub fn new( + ctx: &AssistContext<'_>, + f: Either, + ) -> Option { + let db = ctx.sema.db; + let name: String; + let range: syntax::TextRange; + let ty: ast::Type; + + let module = ctx.sema.to_module_def(ctx.file_id())?; + + match f { + Either::Left(f) => { + name = f.name()?.to_string(); + ty = f.ty()?; + range = f.syntax().text_range(); + } + Either::Right((f, l)) => { + name = l.fields().position(|it| it == f)?.to_string(); + ty = f.ty()?; + range = f.syntax().text_range(); + } + }; + + let hir_ty = ctx.sema.resolve_type(&ty)?; + let type_impls = hir::Impl::all_for_type(db, hir_ty.clone()); + let mut impls = Vec::with_capacity(type_impls.len()); + let type_param = hir_ty.as_type_param(db); + + if let Some(tp) = type_param { + for tb in tp.trait_bounds(db) { + impls.push(Delegee::Bound(BoundCase { 0: tb })); + } + }; + + for imp in type_impls { + match imp.trait_(db) { + Some(tr) => { + if tr.is_visible_from(db, module) { + impls.push(Delegee::Impls(ImplCase { 0: tr, 1: imp })) + } + } + None => { + continue; + } + } + } + + Some(Field { name, ty, range, impls }) + } +} + +/// A field that we want to delegate can offer the enclosing struct +/// trait to implement in two ways. The first way is when the field +/// actually implements the trait and the second way is when the field +/// has a bound type parameter. We handle these cases in different ways +/// hence the enum. +enum Delegee { + Bound(BoundCase), + Impls(ImplCase), +} + +struct BoundCase(hir::Trait); +struct ImplCase(hir::Trait, hir::Impl); + +/// When we list traits we can implement for the enclosing struct +/// we use the absolute path of a trait. This trait consists of a single +/// method that produces this path. +trait Signatured { + fn signature(&self, db: &dyn HirDatabase) -> String; +} + +impl Signatured for Delegee { + fn signature(&self, db: &dyn HirDatabase) -> String { + let mut s = String::new(); + let trait_: hir::Trait; + + match self { + Delegee::Bound(b) => trait_ = b.0, + Delegee::Impls(i) => trait_ = i.0, + }; + + for m in trait_.module(db).path_to_root(db).iter().rev() { + if let Some(name) = m.name(db) { + s.push_str(&format!("{}::", name.to_smol_str())); + } else { + continue; + } + } + + s.push_str(&trait_.name(db).to_smol_str()); + s + } +} + +/// A utility struct that is used for the enclosing struct. +struct Struct { + strukt: ast::Struct, + name: ast::Name, +} + +impl Struct { + pub fn new(s: ast::Struct) -> Option { + let name = s.name()?; + Some(Struct { name, strukt: s }) + } + + pub fn delegate(&self, field: Field, acc: &mut Assists, ctx: &AssistContext<'_>) { + let db = ctx.db(); + for delegee in &field.impls { + // FIXME : We can omit already implemented impl_traits + // But we don't know what the &[hir::Type] argument should look like. + + // let trait_ = match delegee { + // Delegee::Bound(b) => b.0, + // Delegee::Impls(i) => i.1, + // }; + + // if self.hir_ty.impls_trait(db, trait_, &[]) { + // continue; + // } + let signature = delegee.signature(db); + let delegate = generate_impl(ctx, self, &field.ty, &field.name, delegee); + + acc.add_group( + &GroupLabel("Generate delegate traits...".to_owned()), + AssistId("generate_delegate_trait", ide_db::assists::AssistKind::Generate), + format!("Generate delegate impl `{}` for `{}`", signature, field.name), + field.range, + |builder| { + builder.insert( + self.strukt.syntax().text_range().end(), + format!("\n\n{}", delegate.syntax()), + ); + }, + ); + } + } +} + +fn generate_impl( + ctx: &AssistContext<'_>, + strukt: &Struct, + field_ty: &ast::Type, + field_name: &String, + delegee: &Delegee, +) -> ast::Impl { + let delegate: ast::Impl; + let source: ast::Impl; + let genpar: Option; + let db = ctx.db(); + let base_path = make::path_from_text(&field_ty.to_string().as_str()); + let s_path = make::ext::ident_path(&strukt.name.to_string()); + + match delegee { + Delegee::Bound(delegee) => { + let in_file = ctx.sema.source(delegee.0.to_owned()).unwrap(); + let source: ast::Trait = in_file.value; + + delegate = make::impl_trait( + delegee.0.is_unsafe(db), + None, + None, + strukt.strukt.generic_param_list(), + None, + delegee.0.is_auto(db), + make::ty(&delegee.0.name(db).to_smol_str()), + make::ty_path(s_path), + source.where_clause(), + strukt.strukt.where_clause(), + None, + ) + .clone_for_update(); + + genpar = source.generic_param_list(); + let delegate_assoc_items = delegate.get_or_create_assoc_item_list(); + let gen_args: String = + genpar.map_or_else(String::new, |params| params.to_generic_args().to_string()); + + // Goto link : https://doc.rust-lang.org/reference/paths.html#qualified-paths + let qualified_path_type = make::path_from_text(&format!( + "<{} as {}{}>", + base_path.to_string(), + delegee.0.name(db).to_smol_str(), + gen_args.to_string() + )); + + match source.assoc_item_list() { + Some(ai) => { + ai.assoc_items() + .filter(|item| matches!(item, AssocItem::MacroCall(_)).not()) + .for_each(|item| { + let assoc = + process_assoc_item(item, qualified_path_type.clone(), &field_name); + if let Some(assoc) = assoc { + delegate_assoc_items.add_item(assoc); + } + }); + } + None => {} + }; + + let target = ctx.sema.scope(strukt.strukt.syntax()).unwrap(); + let source = ctx.sema.scope_for_def(delegee.0); + + let transform = + PathTransform::trait_impl(&target, &source, delegee.0, delegate.clone()); + transform.apply(&delegate.syntax()); + } + Delegee::Impls(delegee) => { + let in_file = ctx.sema.source(delegee.1.to_owned()).unwrap(); + source = in_file.value; + delegate = make::impl_trait( + delegee.0.is_unsafe(db), + source.generic_param_list(), + None, + None, + None, + delegee.0.is_auto(db), + make::ty(&delegee.0.name(db).to_smol_str()), + make::ty_path(s_path), + source.where_clause(), + strukt.strukt.where_clause(), + None, + ) + .clone_for_update(); + genpar = source.generic_param_list(); + let delegate_assoc_items = delegate.get_or_create_assoc_item_list(); + let gen_args: String = + genpar.map_or_else(String::new, |params| params.to_generic_args().to_string()); + + // Goto link : https://doc.rust-lang.org/reference/paths.html#qualified-paths + let qualified_path_type = make::path_from_text(&format!( + "<{} as {}{}>", + base_path.to_string().as_str(), + delegee.0.name(db).to_smol_str(), + gen_args.to_string().as_str() + )); + + source + .get_or_create_assoc_item_list() + .assoc_items() + .filter(|item| matches!(item, AssocItem::MacroCall(_)).not()) + .for_each(|item| { + let assoc = process_assoc_item(item, qualified_path_type.clone(), &field_name); + if let Some(assoc) = assoc { + delegate_assoc_items.add_item(assoc); + } + }); + + let target = ctx.sema.scope(strukt.strukt.syntax()).unwrap(); + let source = ctx.sema.scope_for_def(delegee.0); + + let transform = + PathTransform::trait_impl(&target, &source, delegee.0, delegate.clone()); + transform.apply(&delegate.syntax()); + } + } + + delegate +} + +fn process_assoc_item( + item: syntax::ast::AssocItem, + qual_path_ty: ast::Path, + base_name: &str, +) -> Option { + match item { + AssocItem::Const(c) => Some(const_assoc_item(c, qual_path_ty)), + AssocItem::Fn(f) => Some(func_assoc_item(f, qual_path_ty, base_name)), + AssocItem::MacroCall(_) => { + // FIXME : Handle MacroCall case. + // return Some(macro_assoc_item(mac, qual_path_ty)); + None + } + AssocItem::TypeAlias(ta) => Some(ty_assoc_item(ta, qual_path_ty)), + } +} + +fn const_assoc_item(item: syntax::ast::Const, qual_path_ty: ast::Path) -> AssocItem { + let path_expr_segment = make::path_from_text(item.name().unwrap().to_string().as_str()); + + // We want rhs of the const assignment to be a qualified path + // The general case for const assigment can be found [here](`https://doc.rust-lang.org/reference/items/constant-items.html`) + // The qualified will have the following generic syntax : + // >::ConstName; + // FIXME : We can't rely on `make::path_qualified` for now but it would be nice to replace the following with it. + // make::path_qualified(qual_path_ty, path_expr_segment.as_single_segment().unwrap()); + let qualpath = qualpath(qual_path_ty, path_expr_segment); + let inner = make::item_const( + item.visibility(), + item.name().unwrap(), + item.ty().unwrap(), + make::expr_path(qualpath), + ) + .clone_for_update(); + + AssocItem::Const(inner) +} + +fn func_assoc_item(item: syntax::ast::Fn, qual_path_ty: Path, base_name: &str) -> AssocItem { + let path_expr_segment = make::path_from_text(item.name().unwrap().to_string().as_str()); + let qualpath = qualpath(qual_path_ty, path_expr_segment); + + let call = match item.param_list() { + // Methods and funcs should be handled separately. + // We ask if the func has a `self` param. + Some(l) => match l.self_param() { + Some(slf) => { + let mut self_kw = make::expr_path(make::path_from_text("self")); + self_kw = make::expr_field(self_kw, base_name); + + let tail_expr_self = match slf.kind() { + ast::SelfParamKind::Owned => self_kw, + ast::SelfParamKind::Ref => make::expr_ref(self_kw, false), + ast::SelfParamKind::MutRef => make::expr_ref(self_kw, true), + }; + + let param_count = l.params().count(); + let args = convert_param_list_to_arg_list(l).clone_for_update(); + + if param_count > 0 { + // Add SelfParam and a TOKEN::COMMA + ted::insert_all( + Position::after(args.l_paren_token().unwrap()), + vec![ + NodeOrToken::Node(tail_expr_self.syntax().clone_for_update()), + NodeOrToken::Token(make::token(SyntaxKind::WHITESPACE)), + NodeOrToken::Token(make::token(SyntaxKind::COMMA)), + ], + ); + } else { + // Add SelfParam only + ted::insert( + Position::after(args.l_paren_token().unwrap()), + NodeOrToken::Node(tail_expr_self.syntax().clone_for_update()), + ); + } + + make::expr_call(make::expr_path(qualpath), args) + } + None => make::expr_call(make::expr_path(qualpath), convert_param_list_to_arg_list(l)), + }, + None => make::expr_call( + make::expr_path(qualpath), + convert_param_list_to_arg_list(make::param_list(None, Vec::new())), + ), + } + .clone_for_update(); + + let body = make::block_expr(vec![], Some(call)).clone_for_update(); + let func = make::fn_( + item.visibility(), + item.name().unwrap(), + item.generic_param_list(), + item.where_clause(), + item.param_list().unwrap(), + body, + item.ret_type(), + item.async_token().is_some(), + item.const_token().is_some(), + item.unsafe_token().is_some(), + ) + .clone_for_update(); + + AssocItem::Fn(func.indent(edit::IndentLevel(1)).clone_for_update()) +} + +fn ty_assoc_item(item: syntax::ast::TypeAlias, qual_path_ty: Path) -> AssocItem { + let path_expr_segment = make::path_from_text(item.name().unwrap().to_string().as_str()); + let qualpath = qualpath(qual_path_ty, path_expr_segment); + let ty = make::ty_path(qualpath); + let ident = item.name().unwrap().to_string(); + + let alias = make::ty_alias( + ident.as_str(), + item.generic_param_list(), + None, + item.where_clause(), + Some((ty, None)), + ) + .clone_for_update(); + + AssocItem::TypeAlias(alias) +} + +fn qualpath(qual_path_ty: ast::Path, path_expr_seg: ast::Path) -> ast::Path { + make::path_from_text(&format!("{}::{}", qual_path_ty.to_string(), path_expr_seg.to_string())) +} + +#[cfg(test)] +mod test { + + use super::*; + use crate::tests::{check_assist, check_assist_not_applicable}; + + #[test] + fn test_tuple_struct_basic() { + check_assist( + generate_delegate_trait, + r#" +struct Base; +struct S(B$0ase); +trait Trait {} +impl Trait for Base {} +"#, + r#" +struct Base; +struct S(Base); + +impl Trait for S {} +trait Trait {} +impl Trait for Base {} +"#, + ); + } + + #[test] + fn test_struct_struct_basic() { + check_assist( + generate_delegate_trait, + r#" +struct Base; +struct S { + ba$0se : Base +} +trait Trait {} +impl Trait for Base {} +"#, + r#" +struct Base; +struct S { + base : Base +} + +impl Trait for S {} +trait Trait {} +impl Trait for Base {} +"#, + ) + } + + // Structs need to be by def populated with fields + // However user can invoke this assist while still editing + // We therefore assert its non-applicability + #[test] + fn test_yet_empty_struct() { + check_assist_not_applicable( + generate_delegate_trait, + r#" +struct Base; +struct S { + $0 +} + +impl Trait for S {} +trait Trait {} +impl Trait for Base {} +"#, + ) + } + + #[test] + fn test_yet_unspecified_field_type() { + check_assist_not_applicable( + generate_delegate_trait, + r#" +struct Base; +struct S { + ab$0c +} + +impl Trait for S {} +trait Trait {} +impl Trait for Base {} +"#, + ); + } + + #[test] + fn test_unsafe_trait() { + check_assist( + generate_delegate_trait, + r#" +struct Base; +struct S { + ba$0se : Base +} +unsafe trait Trait {} +unsafe impl Trait for Base {} +"#, + r#" +struct Base; +struct S { + base : Base +} + +unsafe impl Trait for S {} +unsafe trait Trait {} +unsafe impl Trait for Base {} +"#, + ); + } + + #[test] + fn test_unsafe_trait_with_unsafe_fn() { + check_assist( + generate_delegate_trait, + r#" +struct Base; +struct S { + ba$0se: Base, +} + +unsafe trait Trait { + unsafe fn a_func(); + unsafe fn a_method(&self); +} +unsafe impl Trait for Base { + unsafe fn a_func() {} + unsafe fn a_method(&self) {} +} +"#, + r#" +struct Base; +struct S { + base: Base, +} + +unsafe impl Trait for S { + unsafe fn a_func() { + ::a_func() + } + + unsafe fn a_method(&self) { + ::a_method( &self.base ) + } +} + +unsafe trait Trait { + unsafe fn a_func(); + unsafe fn a_method(&self); +} +unsafe impl Trait for Base { + unsafe fn a_func() {} + unsafe fn a_method(&self) {} +} +"#, + ); + } + + #[test] + fn test_struct_with_where_clause() { + check_assist( + generate_delegate_trait, + r#" +trait AnotherTrait {} +struct S +where + T: AnotherTrait, +{ + b$0 : T, +}"#, + r#" +trait AnotherTrait {} +struct S +where + T: AnotherTrait, +{ + b : T, +} + +impl AnotherTrait for S +where + T: AnotherTrait, +{}"#, + ); + } + + #[test] + fn test_complex_without_where() { + check_assist( + generate_delegate_trait, + r#" +trait Trait<'a, T, const C: usize> { + type AssocType; + const AssocConst: usize; + fn assoc_fn(p: ()); + fn assoc_method(&self, p: ()); +} + +struct Base; +struct S { + field$0: Base +} + +impl<'a, T, const C: usize> Trait<'a, T, C> for Base { + type AssocType = (); + const AssocConst: usize = 0; + fn assoc_fn(p: ()) {} + fn assoc_method(&self, p: ()) {} +} +"#, + r#" +trait Trait<'a, T, const C: usize> { + type AssocType; + const AssocConst: usize; + fn assoc_fn(p: ()); + fn assoc_method(&self, p: ()); +} + +struct Base; +struct S { + field: Base +} + +impl<'a, T, const C: usize> Trait<'a, T, C> for S { + type AssocType = >::AssocType; + + const AssocConst: usize = >::AssocConst; + + fn assoc_fn(p: ()) { + >::assoc_fn(p) + } + + fn assoc_method(&self, p: ()) { + >::assoc_method( &self.field , p) + } +} + +impl<'a, T, const C: usize> Trait<'a, T, C> for Base { + type AssocType = (); + const AssocConst: usize = 0; + fn assoc_fn(p: ()) {} + fn assoc_method(&self, p: ()) {} +} +"#, + ); + } + + #[test] + fn test_complex_two() { + check_assist( + generate_delegate_trait, + r" +trait AnotherTrait {} + +trait Trait<'a, T, const C: usize> { + type AssocType; + const AssocConst: usize; + fn assoc_fn(p: ()); + fn assoc_method(&self, p: ()); +} + +struct Base; +struct S { + fi$0eld: Base, +} + +impl<'b, C, const D: usize> Trait<'b, C, D> for Base +where + C: AnotherTrait, +{ + type AssocType = (); + const AssocConst: usize = 0; + fn assoc_fn(p: ()) {} + fn assoc_method(&self, p: ()) {} +}", + r#" +trait AnotherTrait {} + +trait Trait<'a, T, const C: usize> { + type AssocType; + const AssocConst: usize; + fn assoc_fn(p: ()); + fn assoc_method(&self, p: ()); +} + +struct Base; +struct S { + field: Base, +} + +impl<'b, C, const D: usize> Trait<'b, C, D> for S +where + C: AnotherTrait, +{ + type AssocType = >::AssocType; + + const AssocConst: usize = >::AssocConst; + + fn assoc_fn(p: ()) { + >::assoc_fn(p) + } + + fn assoc_method(&self, p: ()) { + >::assoc_method( &self.field , p) + } +} + +impl<'b, C, const D: usize> Trait<'b, C, D> for Base +where + C: AnotherTrait, +{ + type AssocType = (); + const AssocConst: usize = 0; + fn assoc_fn(p: ()) {} + fn assoc_method(&self, p: ()) {} +}"#, + ) + } + + #[test] + fn test_complex_three() { + check_assist( + generate_delegate_trait, + r#" +trait AnotherTrait {} +trait YetAnotherTrait {} + +struct StructImplsAll(); +impl AnotherTrait for StructImplsAll {} +impl YetAnotherTrait for StructImplsAll {} + +trait Trait<'a, T, const C: usize> { + type A; + const ASSOC_CONST: usize = C; + fn assoc_fn(p: ()); + fn assoc_method(&self, p: ()); +} + +struct Base; +struct S { + fi$0eld: Base, +} + +impl<'b, A: AnotherTrait + YetAnotherTrait, const B: usize> Trait<'b, A, B> for Base +where + A: AnotherTrait, +{ + type A = i32; + + const ASSOC_CONST: usize = B; + + fn assoc_fn(p: ()) {} + + fn assoc_method(&self, p: ()) {} +} +"#, + r#" +trait AnotherTrait {} +trait YetAnotherTrait {} + +struct StructImplsAll(); +impl AnotherTrait for StructImplsAll {} +impl YetAnotherTrait for StructImplsAll {} + +trait Trait<'a, T, const C: usize> { + type A; + const ASSOC_CONST: usize = C; + fn assoc_fn(p: ()); + fn assoc_method(&self, p: ()); +} + +struct Base; +struct S { + field: Base, +} + +impl<'b, A: AnotherTrait + YetAnotherTrait, const B: usize> Trait<'b, A, B> for S +where + A: AnotherTrait, +{ + type A = >::A; + + const ASSOC_CONST: usize = >::ASSOC_CONST; + + fn assoc_fn(p: ()) { + >::assoc_fn(p) + } + + fn assoc_method(&self, p: ()) { + >::assoc_method( &self.field , p) + } +} + +impl<'b, A: AnotherTrait + YetAnotherTrait, const B: usize> Trait<'b, A, B> for Base +where + A: AnotherTrait, +{ + type A = i32; + + const ASSOC_CONST: usize = B; + + fn assoc_fn(p: ()) {} + + fn assoc_method(&self, p: ()) {} +} +"#, + ) + } + + #[test] + fn test_type_bound() { + check_assist( + generate_delegate_trait, + r#" +trait AnotherTrait {} +struct S +where + T: AnotherTrait, +{ + b$0: T, +}"#, + r#" +trait AnotherTrait {} +struct S +where + T: AnotherTrait, +{ + b: T, +} + +impl AnotherTrait for S +where + T: AnotherTrait, +{}"#, + ); + } + + #[test] + fn test_docstring_example() { + check_assist( + generate_delegate_trait, + r#" +trait SomeTrait { + type T; + fn fn_(arg: u32) -> u32; + fn method_(&mut self) -> bool; +} +struct A; +impl SomeTrait for A { + type T = u32; + fn fn_(arg: u32) -> u32 { + 42 + } + fn method_(&mut self) -> bool { + false + } +} +struct B { + a$0: A, +} +"#, + r#" +trait SomeTrait { + type T; + fn fn_(arg: u32) -> u32; + fn method_(&mut self) -> bool; +} +struct A; +impl SomeTrait for A { + type T = u32; + fn fn_(arg: u32) -> u32 { + 42 + } + fn method_(&mut self) -> bool { + false + } +} +struct B { + a: A, +} + +impl SomeTrait for B { + type T = ::T; + + fn fn_(arg: u32) -> u32 { + ::fn_(arg) + } + + fn method_(&mut self) -> bool { + ::method_( &mut self.a ) + } +} +"#, + ); + } + + #[test] + fn import_from_other_mod() { + check_assist( + generate_delegate_trait, + r#" +mod some_module { + pub trait SomeTrait { + type T; + fn fn_(arg: u32) -> u32; + fn method_(&mut self) -> bool; + } + pub struct A; + impl SomeTrait for A { + type T = u32; + + fn fn_(arg: u32) -> u32 { + 42 + } + + fn method_(&mut self) -> bool { + false + } + } +} + +struct B { + a$0: some_module::A, +}"#, + r#" +mod some_module { + pub trait SomeTrait { + type T; + fn fn_(arg: u32) -> u32; + fn method_(&mut self) -> bool; + } + pub struct A; + impl SomeTrait for A { + type T = u32; + + fn fn_(arg: u32) -> u32 { + 42 + } + + fn method_(&mut self) -> bool { + false + } + } +} + +struct B { + a: some_module::A, +} + +impl some_module::SomeTrait for B { + type T = ::T; + + fn fn_(arg: u32) -> u32 { + ::fn_(arg) + } + + fn method_(&mut self) -> bool { + ::method_( &mut self.a ) + } +}"#, + ) + } +} diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs index 111753bf3097..dc0a69971ef7 100644 --- a/crates/ide-assists/src/lib.rs +++ b/crates/ide-assists/src/lib.rs @@ -145,6 +145,7 @@ mod handlers { mod generate_constant; mod generate_default_from_enum_variant; mod generate_default_from_new; + mod generate_delegate_trait; mod generate_deref; mod generate_derive; mod generate_documentation_template; @@ -251,6 +252,7 @@ mod handlers { generate_constant::generate_constant, generate_default_from_enum_variant::generate_default_from_enum_variant, generate_default_from_new::generate_default_from_new, + generate_delegate_trait::generate_delegate_trait, generate_derive::generate_derive, generate_documentation_template::generate_documentation_template, generate_documentation_template::generate_doc_example, diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index c097e073980c..c6c70cc64a65 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -1015,6 +1015,69 @@ impl Person { ) } +#[test] +fn doctest_generate_delegate_trait() { + check_doc_test( + "generate_delegate_trait", + r#####" +trait SomeTrait { + type T; + fn fn_(arg: u32) -> u32; + fn method_(&mut self) -> bool; +} +struct A; +impl SomeTrait for A { + type T = u32; + + fn fn_(arg: u32) -> u32 { + 42 + } + + fn method_(&mut self) -> bool { + false + } +} +struct B { + a$0: A, +} +"#####, + r#####" +trait SomeTrait { + type T; + fn fn_(arg: u32) -> u32; + fn method_(&mut self) -> bool; +} +struct A; +impl SomeTrait for A { + type T = u32; + + fn fn_(arg: u32) -> u32 { + 42 + } + + fn method_(&mut self) -> bool { + false + } +} +struct B { + a: A, +} + +impl SomeTrait for B { + type T = ::T; + + fn fn_(arg: u32) -> u32 { + ::fn_(arg) + } + + fn method_(&mut self) -> bool { + ::method_( &mut self.a ) + } +} +"#####, + ) +} + #[test] fn doctest_generate_deref() { check_doc_test( From 59cc783a3be26dae2143066914d8600501229b1f Mon Sep 17 00:00:00 2001 From: Ali Bektas Date: Fri, 2 Jun 2023 12:41:05 +0200 Subject: [PATCH 007/324] Correct errors produced by CI --- crates/ide-assists/src/handlers/generate_delegate_trait.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_delegate_trait.rs b/crates/ide-assists/src/handlers/generate_delegate_trait.rs index ce8f4256c085..19fb9fa39007 100644 --- a/crates/ide-assists/src/handlers/generate_delegate_trait.rs +++ b/crates/ide-assists/src/handlers/generate_delegate_trait.rs @@ -106,7 +106,7 @@ struct Field { } impl Field { - pub fn new( + pub(crate) fn new( ctx: &AssistContext<'_>, f: Either, ) -> Option { @@ -208,12 +208,12 @@ struct Struct { } impl Struct { - pub fn new(s: ast::Struct) -> Option { + pub(crate) fn new(s: ast::Struct) -> Option { let name = s.name()?; Some(Struct { name, strukt: s }) } - pub fn delegate(&self, field: Field, acc: &mut Assists, ctx: &AssistContext<'_>) { + pub(crate) fn delegate(&self, field: Field, acc: &mut Assists, ctx: &AssistContext<'_>) { let db = ctx.db(); for delegee in &field.impls { // FIXME : We can omit already implemented impl_traits From 19a9de72f623c60370d0222326e4fba40ac3dc6b Mon Sep 17 00:00:00 2001 From: Ali Bektas Date: Sat, 17 Jun 2023 13:17:58 +0200 Subject: [PATCH 008/324] Version 2 --- .../src/handlers/generate_delegate_trait.rs | 31 +++++-------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_delegate_trait.rs b/crates/ide-assists/src/handlers/generate_delegate_trait.rs index 19fb9fa39007..4d05dbfcf5fa 100644 --- a/crates/ide-assists/src/handlers/generate_delegate_trait.rs +++ b/crates/ide-assists/src/handlers/generate_delegate_trait.rs @@ -137,7 +137,7 @@ impl Field { if let Some(tp) = type_param { for tb in tp.trait_bounds(db) { - impls.push(Delegee::Bound(BoundCase { 0: tb })); + impls.push(Delegee::Bound(BoundCase(tb))); } }; @@ -145,12 +145,10 @@ impl Field { match imp.trait_(db) { Some(tr) => { if tr.is_visible_from(db, module) { - impls.push(Delegee::Impls(ImplCase { 0: tr, 1: imp })) + impls.push(Delegee::Impls(ImplCase(tr, imp))) } } - None => { - continue; - } + None => (), } } @@ -171,32 +169,19 @@ enum Delegee { struct BoundCase(hir::Trait); struct ImplCase(hir::Trait, hir::Impl); -/// When we list traits we can implement for the enclosing struct -/// we use the absolute path of a trait. This trait consists of a single -/// method that produces this path. -trait Signatured { - fn signature(&self, db: &dyn HirDatabase) -> String; -} - -impl Signatured for Delegee { +impl Delegee { fn signature(&self, db: &dyn HirDatabase) -> String { let mut s = String::new(); - let trait_: hir::Trait; - match self { - Delegee::Bound(b) => trait_ = b.0, - Delegee::Impls(i) => trait_ = i.0, - }; + let (Delegee::Bound(BoundCase(it)) | Delegee::Impls(ImplCase(it, _))) = self; - for m in trait_.module(db).path_to_root(db).iter().rev() { + for m in it.module(db).path_to_root(db).iter().rev() { if let Some(name) = m.name(db) { s.push_str(&format!("{}::", name.to_smol_str())); - } else { - continue; } } - s.push_str(&trait_.name(db).to_smol_str()); + s.push_str(&it.name(db).to_smol_str()); s } } @@ -231,7 +216,7 @@ impl Struct { let delegate = generate_impl(ctx, self, &field.ty, &field.name, delegee); acc.add_group( - &GroupLabel("Generate delegate traits...".to_owned()), + &GroupLabel("Delegate trait impl for field...".to_owned()), AssistId("generate_delegate_trait", ide_db::assists::AssistKind::Generate), format!("Generate delegate impl `{}` for `{}`", signature, field.name), field.range, From d456d115442cfacde5358da20c579060e61d5ef6 Mon Sep 17 00:00:00 2001 From: Joe Chen Date: Sat, 17 Jun 2023 20:08:33 +0800 Subject: [PATCH 009/324] fix typo in `rustdoc/src/what-is-rustdoc.md` --- src/doc/rustdoc/src/what-is-rustdoc.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustdoc/src/what-is-rustdoc.md b/src/doc/rustdoc/src/what-is-rustdoc.md index 7a444d77c09d..7179ee0cf037 100644 --- a/src/doc/rustdoc/src/what-is-rustdoc.md +++ b/src/doc/rustdoc/src/what-is-rustdoc.md @@ -37,7 +37,7 @@ top, with no contents. ## Configuring rustdoc There are two problems with this: first, why does it -think that our package is named "lib"? Second, why does it not have any +think that our crate is named "lib"? Second, why does it not have any contents? The first problem is due to `rustdoc` trying to be helpful; like `rustc`, From 4ed119766282b2e758a88ac29daf488d718f730c Mon Sep 17 00:00:00 2001 From: Ali Bektas Date: Sat, 17 Jun 2023 21:27:52 +0200 Subject: [PATCH 010/324] Version 3 Remove scope_for_def calls as the definition have been removed entirely. As a result of this change the problem with false path resolutions has been solved. --- crates/ide-assists/src/handlers/generate_delegate_trait.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_delegate_trait.rs b/crates/ide-assists/src/handlers/generate_delegate_trait.rs index 4d05dbfcf5fa..185f47184d43 100644 --- a/crates/ide-assists/src/handlers/generate_delegate_trait.rs +++ b/crates/ide-assists/src/handlers/generate_delegate_trait.rs @@ -294,7 +294,7 @@ fn generate_impl( }; let target = ctx.sema.scope(strukt.strukt.syntax()).unwrap(); - let source = ctx.sema.scope_for_def(delegee.0); + let source = ctx.sema.scope(source.syntax()).unwrap(); let transform = PathTransform::trait_impl(&target, &source, delegee.0, delegate.clone()); @@ -342,7 +342,7 @@ fn generate_impl( }); let target = ctx.sema.scope(strukt.strukt.syntax()).unwrap(); - let source = ctx.sema.scope_for_def(delegee.0); + let source = ctx.sema.scope(source.syntax()).unwrap(); let transform = PathTransform::trait_impl(&target, &source, delegee.0, delegate.clone()); From 424ef7780914c2d9ce2fc610812e965ed2d33e83 Mon Sep 17 00:00:00 2001 From: Alex Kladov Date: Sat, 17 Jun 2023 22:23:25 +0100 Subject: [PATCH 011/324] internal: remove spurious regex dependency - replace tokio's env-filter with a smaller&simpler targets filter - reshuffle logging infra a bit to make sure there's only a single place where we read environmental variables - use anyhow::Result in rust-analyzer binary --- Cargo.lock | 37 ----- crates/hir-ty/Cargo.toml | 1 - crates/hir-ty/src/tests.rs | 5 +- crates/rust-analyzer/Cargo.toml | 1 - crates/rust-analyzer/src/bin/logger.rs | 88 +++++------- crates/rust-analyzer/src/bin/main.rs | 63 ++++----- crates/rust-analyzer/src/dispatch.rs | 26 ++-- crates/rust-analyzer/src/from_proto.rs | 27 ++-- crates/rust-analyzer/src/global_state.rs | 7 +- .../src/handlers/notification.rs | 26 ++-- crates/rust-analyzer/src/handlers/request.rs | 127 +++++++++--------- crates/rust-analyzer/src/lib.rs | 13 +- crates/rust-analyzer/src/main_loop.rs | 11 +- .../rust-analyzer/tests/slow-tests/support.rs | 5 +- 14 files changed, 196 insertions(+), 241 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 50c81ca279ee..1fe451c2f39e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -967,15 +967,6 @@ dependencies = [ "url", ] -[[package]] -name = "matchers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata", -] - [[package]] name = "mbe" version = "0.0.0" @@ -1438,30 +1429,6 @@ dependencies = [ "bitflags 1.3.2", ] -[[package]] -name = "regex" -version = "1.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" -dependencies = [ - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - [[package]] name = "rowan" version = "0.15.11" @@ -1953,12 +1920,8 @@ version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" dependencies = [ - "matchers", - "once_cell", - "regex", "sharded-slab", "thread_local", - "tracing", "tracing-core", "tracing-log", ] diff --git a/crates/hir-ty/Cargo.toml b/crates/hir-ty/Cargo.toml index c8bea34507c7..247e6466d8bb 100644 --- a/crates/hir-ty/Cargo.toml +++ b/crates/hir-ty/Cargo.toml @@ -47,7 +47,6 @@ limit.workspace = true expect-test = "1.4.0" tracing = "0.1.35" tracing-subscriber = { version = "0.3.16", default-features = false, features = [ - "env-filter", "registry", ] } tracing-tree = "0.2.1" diff --git a/crates/hir-ty/src/tests.rs b/crates/hir-ty/src/tests.rs index 857141280061..8e5514353d55 100644 --- a/crates/hir-ty/src/tests.rs +++ b/crates/hir-ty/src/tests.rs @@ -30,7 +30,7 @@ use syntax::{ ast::{self, AstNode, HasName}, SyntaxNode, }; -use tracing_subscriber::{layer::SubscriberExt, EnvFilter, Registry}; +use tracing_subscriber::{layer::SubscriberExt, Registry}; use tracing_tree::HierarchicalLayer; use triomphe::Arc; @@ -52,7 +52,8 @@ fn setup_tracing() -> Option { return None; } - let filter = EnvFilter::from_env("CHALK_DEBUG"); + let filter: tracing_subscriber::filter::Targets = + env::var("CHALK_DEBUG").ok().and_then(|it| it.parse().ok()).unwrap_or_default(); let layer = HierarchicalLayer::default() .with_indent_lines(true) .with_ansi(false) diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index 5b72d57560b2..dc8962064bf6 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml @@ -37,7 +37,6 @@ mimalloc = { version = "0.1.30", default-features = false, optional = true } lsp-server = { version = "0.7.0", path = "../../lib/lsp-server" } tracing = "0.1.35" tracing-subscriber = { version = "0.3.16", default-features = false, features = [ - "env-filter", "registry", "fmt", "tracing-log", diff --git a/crates/rust-analyzer/src/bin/logger.rs b/crates/rust-analyzer/src/bin/logger.rs index 8caadecd850b..867907dca396 100644 --- a/crates/rust-analyzer/src/bin/logger.rs +++ b/crates/rust-analyzer/src/bin/logger.rs @@ -8,10 +8,11 @@ use std::{ sync::Arc, }; -use rust_analyzer::Result; +use anyhow::Context; use tracing::{level_filters::LevelFilter, Event, Subscriber}; use tracing_log::NormalizeEvent; use tracing_subscriber::{ + filter::Targets, fmt::{ format::Writer, writer::BoxMakeWriter, FmtContext, FormatEvent, FormatFields, FormattedFields, MakeWriter, @@ -19,13 +20,14 @@ use tracing_subscriber::{ layer::SubscriberExt, registry::LookupSpan, util::SubscriberInitExt, - EnvFilter, Registry, + Registry, }; use tracing_tree::HierarchicalLayer; -pub(crate) struct Logger { - filter: EnvFilter, - file: Option, +pub(crate) struct LoggerConfig { + pub(crate) log_file: Option, + pub(crate) filter: String, + pub(crate) chalk_filter: Option, } struct MakeWriterStderr; @@ -38,62 +40,42 @@ impl<'a> MakeWriter<'a> for MakeWriterStderr { } } -impl Logger { - pub(crate) fn new(file: Option, filter: Option<&str>) -> Logger { - let filter = filter.map_or(EnvFilter::default(), EnvFilter::new); +impl LoggerConfig { + pub(crate) fn init(self) -> anyhow::Result<()> { + let mut filter: Targets = self + .filter + .parse() + .with_context(|| format!("invalid log filter: `{}`", self.filter))?; - Logger { filter, file } - } + let mut chalk_layer = None; + if let Some(chalk_filter) = self.chalk_filter { + let level: LevelFilter = + chalk_filter.parse().with_context(|| "invalid chalk log filter")?; + chalk_layer = Some( + HierarchicalLayer::default() + .with_indent_lines(true) + .with_ansi(false) + .with_indent_amount(2) + .with_writer(io::stderr), + ); + filter = filter + .with_target("chalk_solve", level) + .with_target("chalk_ir", level) + .with_target("chalk_recursive", level); + }; - pub(crate) fn install(self) -> Result<()> { - // The meaning of CHALK_DEBUG I suspected is to tell chalk crates - // (i.e. chalk-solve, chalk-ir, chalk-recursive) how to filter tracing - // logs. But now we can only have just one filter, which means we have to - // merge chalk filter to our main filter (from RA_LOG env). - // - // The acceptable syntax of CHALK_DEBUG is `target[span{field=value}]=level`. - // As the value should only affect chalk crates, we'd better manually - // specify the target. And for simplicity, CHALK_DEBUG only accept the value - // that specify level. - let chalk_level_dir = std::env::var("CHALK_DEBUG") - .map(|val| { - val.parse::().expect( - "invalid CHALK_DEBUG value, expect right log level (like debug or trace)", - ) - }) - .ok(); - - let chalk_layer = HierarchicalLayer::default() - .with_indent_lines(true) - .with_ansi(false) - .with_indent_amount(2) - .with_writer(io::stderr); - - let writer = match self.file { + let writer = match self.log_file { Some(file) => BoxMakeWriter::new(Arc::new(file)), None => BoxMakeWriter::new(io::stderr), }; let ra_fmt_layer = tracing_subscriber::fmt::layer().event_format(LoggerFormatter).with_writer(writer); - match chalk_level_dir { - Some(val) => { - Registry::default() - .with( - self.filter - .add_directive(format!("chalk_solve={val}").parse()?) - .add_directive(format!("chalk_ir={val}").parse()?) - .add_directive(format!("chalk_recursive={val}").parse()?), - ) - .with(ra_fmt_layer) - .with(chalk_layer) - .init(); - } - None => { - Registry::default().with(self.filter).with(ra_fmt_layer).init(); - } - }; - + let registry = Registry::default().with(filter).with(ra_fmt_layer); + match chalk_layer { + Some(chalk_layer) => registry.with(chalk_layer).init(), + None => registry.init(), + } Ok(()) } } diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs index 91911dd18096..118aad585ce3 100644 --- a/crates/rust-analyzer/src/bin/main.rs +++ b/crates/rust-analyzer/src/bin/main.rs @@ -7,14 +7,11 @@ mod logger; mod rustc_wrapper; -use std::{ - env, fs, - path::{Path, PathBuf}, - process, -}; +use std::{env, fs, path::PathBuf, process}; +use anyhow::Context; use lsp_server::Connection; -use rust_analyzer::{cli::flags, config::Config, from_json, Result}; +use rust_analyzer::{cli::flags, config::Config, from_json}; use vfs::AbsPathBuf; #[cfg(all(feature = "mimalloc"))] @@ -25,7 +22,7 @@ static ALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc; #[global_allocator] static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; -fn main() { +fn main() -> anyhow::Result<()> { if std::env::var("RA_RUSTC_WRAPPER").is_ok() { let mut args = std::env::args_os(); let _me = args.next().unwrap(); @@ -41,14 +38,7 @@ fn main() { } let flags = flags::RustAnalyzer::from_env_or_exit(); - if let Err(err) = try_main(flags) { - tracing::error!("Unexpected error: {}", err); - eprintln!("{err}"); - process::exit(101); - } -} -fn try_main(flags: flags::RustAnalyzer) -> Result<()> { #[cfg(debug_assertions)] if flags.wait_dbg || env::var("RA_WAIT_DBG").is_ok() { #[allow(unused_mut)] @@ -58,14 +48,8 @@ fn try_main(flags: flags::RustAnalyzer) -> Result<()> { } } - let mut log_file = flags.log_file.as_deref(); + setup_logging(flags.log_file.clone())?; - let env_log_file = env::var("RA_LOG_FILE").ok(); - if let Some(env_log_file) = env_log_file.as_deref() { - log_file = Some(Path::new(env_log_file)); - } - - setup_logging(log_file)?; let verbosity = flags.verbosity(); match flags.subcommand { @@ -102,7 +86,7 @@ fn try_main(flags: flags::RustAnalyzer) -> Result<()> { Ok(()) } -fn setup_logging(log_file: Option<&Path>) -> Result<()> { +fn setup_logging(log_file_flag: Option) -> anyhow::Result<()> { if cfg!(windows) { // This is required so that windows finds our pdb that is placed right beside the exe. // By default it doesn't look at the folder the exe resides in, only in the current working @@ -115,23 +99,42 @@ fn setup_logging(log_file: Option<&Path>) -> Result<()> { } } } + if env::var("RUST_BACKTRACE").is_err() { env::set_var("RUST_BACKTRACE", "short"); } + let log_file = env::var("RA_LOG_FILE").ok().map(PathBuf::from).or(log_file_flag); let log_file = match log_file { Some(path) => { if let Some(parent) = path.parent() { let _ = fs::create_dir_all(parent); } - Some(fs::File::create(path)?) + Some( + fs::File::create(&path) + .with_context(|| format!("can't create log file at {}", path.display()))?, + ) } None => None, }; - let filter = env::var("RA_LOG").ok(); - // deliberately enable all `error` logs if the user has not set RA_LOG, as there is usually useful - // information in there for debugging - logger::Logger::new(log_file, filter.as_deref().or(Some("error"))).install()?; + + logger::LoggerConfig { + log_file, + // Deliberately enable all `error` logs if the user has not set RA_LOG, as there is usually + // useful information in there for debugging. + filter: env::var("RA_LOG").ok().unwrap_or_else(|| "error".to_string()), + // The meaning of CHALK_DEBUG I suspected is to tell chalk crates + // (i.e. chalk-solve, chalk-ir, chalk-recursive) how to filter tracing + // logs. But now we can only have just one filter, which means we have to + // merge chalk filter to our main filter (from RA_LOG env). + // + // The acceptable syntax of CHALK_DEBUG is `target[span{field=value}]=level`. + // As the value should only affect chalk crates, we'd better manually + // specify the target. And for simplicity, CHALK_DEBUG only accept the value + // that specify level. + chalk_filter: env::var("CHALK_DEBUG").ok(), + } + .init()?; profile::init(); @@ -146,8 +149,8 @@ const STACK_SIZE: usize = 1024 * 1024 * 8; fn with_extra_thread( thread_name: impl Into, thread_intent: stdx::thread::ThreadIntent, - f: impl FnOnce() -> Result<()> + Send + 'static, -) -> Result<()> { + f: impl FnOnce() -> anyhow::Result<()> + Send + 'static, +) -> anyhow::Result<()> { let handle = stdx::thread::Builder::new(thread_intent) .name(thread_name.into()) .stack_size(STACK_SIZE) @@ -158,7 +161,7 @@ fn with_extra_thread( Ok(()) } -fn run_server() -> Result<()> { +fn run_server() -> anyhow::Result<()> { tracing::info!("server version {} will start", rust_analyzer::version()); let (connection, io_threads) = Connection::stdio(); diff --git a/crates/rust-analyzer/src/dispatch.rs b/crates/rust-analyzer/src/dispatch.rs index 4e57c6eb65a4..9a876f4b97fc 100644 --- a/crates/rust-analyzer/src/dispatch.rs +++ b/crates/rust-analyzer/src/dispatch.rs @@ -10,7 +10,7 @@ use crate::{ global_state::{GlobalState, GlobalStateSnapshot}, main_loop::Task, version::version, - LspError, Result, + LspError, }; /// A visitor for routing a raw JSON request to an appropriate handler function. @@ -38,7 +38,7 @@ impl<'a> RequestDispatcher<'a> { /// guarded by `catch_unwind`, so, please, don't make bugs :-) pub(crate) fn on_sync_mut( &mut self, - f: fn(&mut GlobalState, R::Params) -> Result, + f: fn(&mut GlobalState, R::Params) -> anyhow::Result, ) -> &mut Self where R: lsp_types::request::Request, @@ -63,7 +63,7 @@ impl<'a> RequestDispatcher<'a> { /// Dispatches the request onto the current thread. pub(crate) fn on_sync( &mut self, - f: fn(GlobalStateSnapshot, R::Params) -> Result, + f: fn(GlobalStateSnapshot, R::Params) -> anyhow::Result, ) -> &mut Self where R: lsp_types::request::Request, @@ -92,7 +92,7 @@ impl<'a> RequestDispatcher<'a> { /// without retrying it if it panics. pub(crate) fn on_no_retry( &mut self, - f: fn(GlobalStateSnapshot, R::Params) -> Result, + f: fn(GlobalStateSnapshot, R::Params) -> anyhow::Result, ) -> &mut Self where R: lsp_types::request::Request + 'static, @@ -128,7 +128,7 @@ impl<'a> RequestDispatcher<'a> { /// Dispatches a non-latency-sensitive request onto the thread pool. pub(crate) fn on( &mut self, - f: fn(GlobalStateSnapshot, R::Params) -> Result, + f: fn(GlobalStateSnapshot, R::Params) -> anyhow::Result, ) -> &mut Self where R: lsp_types::request::Request + 'static, @@ -141,7 +141,7 @@ impl<'a> RequestDispatcher<'a> { /// Dispatches a latency-sensitive request onto the thread pool. pub(crate) fn on_latency_sensitive( &mut self, - f: fn(GlobalStateSnapshot, R::Params) -> Result, + f: fn(GlobalStateSnapshot, R::Params) -> anyhow::Result, ) -> &mut Self where R: lsp_types::request::Request + 'static, @@ -156,7 +156,7 @@ impl<'a> RequestDispatcher<'a> { /// We can't run this on the main thread though as we invoke rustfmt which may take arbitrary time to complete! pub(crate) fn on_fmt_thread( &mut self, - f: fn(GlobalStateSnapshot, R::Params) -> Result, + f: fn(GlobalStateSnapshot, R::Params) -> anyhow::Result, ) -> &mut Self where R: lsp_types::request::Request + 'static, @@ -181,7 +181,7 @@ impl<'a> RequestDispatcher<'a> { fn on_with_thread_intent( &mut self, intent: ThreadIntent, - f: fn(GlobalStateSnapshot, R::Params) -> Result, + f: fn(GlobalStateSnapshot, R::Params) -> anyhow::Result, ) -> &mut Self where R: lsp_types::request::Request + 'static, @@ -245,7 +245,7 @@ impl<'a> RequestDispatcher<'a> { fn thread_result_to_response( id: lsp_server::RequestId, - result: thread::Result>, + result: thread::Result>, ) -> Result where R: lsp_types::request::Request, @@ -277,7 +277,7 @@ where fn result_to_response( id: lsp_server::RequestId, - result: Result, + result: anyhow::Result, ) -> Result where R: lsp_types::request::Request, @@ -289,7 +289,7 @@ where Err(e) => match e.downcast::() { Ok(lsp_error) => lsp_server::Response::new_err(id, lsp_error.code, lsp_error.message), Err(e) => match e.downcast::() { - Ok(cancelled) => return Err(*cancelled), + Ok(cancelled) => return Err(cancelled), Err(e) => lsp_server::Response::new_err( id, lsp_server::ErrorCode::InternalError as i32, @@ -309,8 +309,8 @@ pub(crate) struct NotificationDispatcher<'a> { impl<'a> NotificationDispatcher<'a> { pub(crate) fn on_sync_mut( &mut self, - f: fn(&mut GlobalState, N::Params) -> Result<()>, - ) -> Result<&mut Self> + f: fn(&mut GlobalState, N::Params) -> anyhow::Result<()>, + ) -> anyhow::Result<&mut Self> where N: lsp_types::notification::Notification, N::Params: DeserializeOwned + Send, diff --git a/crates/rust-analyzer/src/from_proto.rs b/crates/rust-analyzer/src/from_proto.rs index cd74a5500d0a..c247e1bb2297 100644 --- a/crates/rust-analyzer/src/from_proto.rs +++ b/crates/rust-analyzer/src/from_proto.rs @@ -14,19 +14,21 @@ use crate::{ line_index::{LineIndex, PositionEncoding}, lsp_ext, lsp_utils::invalid_params_error, - Result, }; -pub(crate) fn abs_path(url: &lsp_types::Url) -> Result { - let path = url.to_file_path().map_err(|()| "url is not a file")?; +pub(crate) fn abs_path(url: &lsp_types::Url) -> anyhow::Result { + let path = url.to_file_path().map_err(|()| anyhow::format_err!("url is not a file"))?; Ok(AbsPathBuf::try_from(path).unwrap()) } -pub(crate) fn vfs_path(url: &lsp_types::Url) -> Result { +pub(crate) fn vfs_path(url: &lsp_types::Url) -> anyhow::Result { abs_path(url).map(vfs::VfsPath::from) } -pub(crate) fn offset(line_index: &LineIndex, position: lsp_types::Position) -> Result { +pub(crate) fn offset( + line_index: &LineIndex, + position: lsp_types::Position, +) -> anyhow::Result { let line_col = match line_index.encoding { PositionEncoding::Utf8 => LineCol { line: position.line, col: position.character }, PositionEncoding::Wide(enc) => { @@ -42,7 +44,10 @@ pub(crate) fn offset(line_index: &LineIndex, position: lsp_types::Position) -> R Ok(text_size) } -pub(crate) fn text_range(line_index: &LineIndex, range: lsp_types::Range) -> Result { +pub(crate) fn text_range( + line_index: &LineIndex, + range: lsp_types::Range, +) -> anyhow::Result { let start = offset(line_index, range.start)?; let end = offset(line_index, range.end)?; match end < start { @@ -51,14 +56,14 @@ pub(crate) fn text_range(line_index: &LineIndex, range: lsp_types::Range) -> Res } } -pub(crate) fn file_id(snap: &GlobalStateSnapshot, url: &lsp_types::Url) -> Result { +pub(crate) fn file_id(snap: &GlobalStateSnapshot, url: &lsp_types::Url) -> anyhow::Result { snap.url_to_file_id(url) } pub(crate) fn file_position( snap: &GlobalStateSnapshot, tdpp: lsp_types::TextDocumentPositionParams, -) -> Result { +) -> anyhow::Result { let file_id = file_id(snap, &tdpp.text_document.uri)?; let line_index = snap.file_line_index(file_id)?; let offset = offset(&line_index, tdpp.position)?; @@ -69,7 +74,7 @@ pub(crate) fn file_range( snap: &GlobalStateSnapshot, text_document_identifier: lsp_types::TextDocumentIdentifier, range: lsp_types::Range, -) -> Result { +) -> anyhow::Result { file_range_uri(snap, &text_document_identifier.uri, range) } @@ -77,7 +82,7 @@ pub(crate) fn file_range_uri( snap: &GlobalStateSnapshot, document: &lsp_types::Url, range: lsp_types::Range, -) -> Result { +) -> anyhow::Result { let file_id = file_id(snap, document)?; let line_index = snap.file_line_index(file_id)?; let range = text_range(&line_index, range)?; @@ -101,7 +106,7 @@ pub(crate) fn assist_kind(kind: lsp_types::CodeActionKind) -> Option pub(crate) fn annotation( snap: &GlobalStateSnapshot, code_lens: lsp_types::CodeLens, -) -> Result> { +) -> anyhow::Result> { let data = code_lens.data.ok_or_else(|| invalid_params_error("code lens without data".to_string()))?; let resolve = from_json::("CodeLensResolveData", &data)?; diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index d5b0e3a57053..52512b21978b 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -30,7 +30,6 @@ use crate::{ reload::{self, SourceRootConfig}, task_pool::TaskPool, to_proto::url_from_abs_path, - Result, }; // Enforces drop order @@ -422,7 +421,7 @@ impl Drop for GlobalState { } impl GlobalStateSnapshot { - pub(crate) fn url_to_file_id(&self, url: &Url) -> Result { + pub(crate) fn url_to_file_id(&self, url: &Url) -> anyhow::Result { url_to_file_id(&self.vfs.read().0, url) } @@ -481,8 +480,8 @@ pub(crate) fn file_id_to_url(vfs: &vfs::Vfs, id: FileId) -> Url { url_from_abs_path(path) } -pub(crate) fn url_to_file_id(vfs: &vfs::Vfs, url: &Url) -> Result { +pub(crate) fn url_to_file_id(vfs: &vfs::Vfs, url: &Url) -> anyhow::Result { let path = from_proto::vfs_path(url)?; - let res = vfs.file_id(&path).ok_or_else(|| format!("file not found: {path}"))?; + let res = vfs.file_id(&path).ok_or_else(|| anyhow::format_err!("file not found: {path}"))?; Ok(res) } diff --git a/crates/rust-analyzer/src/handlers/notification.rs b/crates/rust-analyzer/src/handlers/notification.rs index ae1dc23153cd..3f94f2720c67 100644 --- a/crates/rust-analyzer/src/handlers/notification.rs +++ b/crates/rust-analyzer/src/handlers/notification.rs @@ -14,10 +14,10 @@ use vfs::{AbsPathBuf, ChangeKind, VfsPath}; use crate::{ config::Config, from_proto, global_state::GlobalState, lsp_ext::RunFlycheckParams, - lsp_utils::apply_document_changes, mem_docs::DocumentData, reload, Result, + lsp_utils::apply_document_changes, mem_docs::DocumentData, reload, }; -pub(crate) fn handle_cancel(state: &mut GlobalState, params: CancelParams) -> Result<()> { +pub(crate) fn handle_cancel(state: &mut GlobalState, params: CancelParams) -> anyhow::Result<()> { let id: lsp_server::RequestId = match params.id { lsp_types::NumberOrString::Number(id) => id.into(), lsp_types::NumberOrString::String(id) => id.into(), @@ -29,7 +29,7 @@ pub(crate) fn handle_cancel(state: &mut GlobalState, params: CancelParams) -> Re pub(crate) fn handle_work_done_progress_cancel( state: &mut GlobalState, params: WorkDoneProgressCancelParams, -) -> Result<()> { +) -> anyhow::Result<()> { if let lsp_types::NumberOrString::String(s) = ¶ms.token { if let Some(id) = s.strip_prefix("rust-analyzer/flycheck/") { if let Ok(id) = u32::from_str_radix(id, 10) { @@ -49,7 +49,7 @@ pub(crate) fn handle_work_done_progress_cancel( pub(crate) fn handle_did_open_text_document( state: &mut GlobalState, params: DidOpenTextDocumentParams, -) -> Result<()> { +) -> anyhow::Result<()> { let _p = profile::span("handle_did_open_text_document"); if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) { @@ -68,7 +68,7 @@ pub(crate) fn handle_did_open_text_document( pub(crate) fn handle_did_change_text_document( state: &mut GlobalState, params: DidChangeTextDocumentParams, -) -> Result<()> { +) -> anyhow::Result<()> { let _p = profile::span("handle_did_change_text_document"); if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) { @@ -100,7 +100,7 @@ pub(crate) fn handle_did_change_text_document( pub(crate) fn handle_did_close_text_document( state: &mut GlobalState, params: DidCloseTextDocumentParams, -) -> Result<()> { +) -> anyhow::Result<()> { let _p = profile::span("handle_did_close_text_document"); if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) { @@ -120,7 +120,7 @@ pub(crate) fn handle_did_close_text_document( pub(crate) fn handle_did_save_text_document( state: &mut GlobalState, params: DidSaveTextDocumentParams, -) -> Result<()> { +) -> anyhow::Result<()> { if let Ok(vfs_path) = from_proto::vfs_path(¶ms.text_document.uri) { // Re-fetch workspaces if a workspace related file has changed if let Some(abs_path) = vfs_path.as_path() { @@ -146,7 +146,7 @@ pub(crate) fn handle_did_save_text_document( pub(crate) fn handle_did_change_configuration( state: &mut GlobalState, _params: DidChangeConfigurationParams, -) -> Result<()> { +) -> anyhow::Result<()> { // As stated in https://github.com/microsoft/language-server-protocol/issues/676, // this notification's parameters should be ignored and the actual config queried separately. state.send_request::( @@ -186,7 +186,7 @@ pub(crate) fn handle_did_change_configuration( pub(crate) fn handle_did_change_workspace_folders( state: &mut GlobalState, params: DidChangeWorkspaceFoldersParams, -) -> Result<()> { +) -> anyhow::Result<()> { let config = Arc::make_mut(&mut state.config); for workspace in params.event.removed { @@ -214,7 +214,7 @@ pub(crate) fn handle_did_change_workspace_folders( pub(crate) fn handle_did_change_watched_files( state: &mut GlobalState, params: DidChangeWatchedFilesParams, -) -> Result<()> { +) -> anyhow::Result<()> { for change in params.changes { if let Ok(path) = from_proto::abs_path(&change.uri) { state.loader.handle.invalidate(path); @@ -302,13 +302,13 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool { } } -pub(crate) fn handle_cancel_flycheck(state: &mut GlobalState, _: ()) -> Result<()> { +pub(crate) fn handle_cancel_flycheck(state: &mut GlobalState, _: ()) -> anyhow::Result<()> { let _p = profile::span("handle_stop_flycheck"); state.flycheck.iter().for_each(|flycheck| flycheck.cancel()); Ok(()) } -pub(crate) fn handle_clear_flycheck(state: &mut GlobalState, _: ()) -> Result<()> { +pub(crate) fn handle_clear_flycheck(state: &mut GlobalState, _: ()) -> anyhow::Result<()> { let _p = profile::span("handle_clear_flycheck"); state.diagnostics.clear_check_all(); Ok(()) @@ -317,7 +317,7 @@ pub(crate) fn handle_clear_flycheck(state: &mut GlobalState, _: ()) -> Result<() pub(crate) fn handle_run_flycheck( state: &mut GlobalState, params: RunFlycheckParams, -) -> Result<()> { +) -> anyhow::Result<()> { let _p = profile::span("handle_run_flycheck"); if let Some(text_document) = params.text_document { if let Ok(vfs_path) = from_proto::vfs_path(&text_document.uri) { diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs index a6a72552d57c..afd82fc06137 100644 --- a/crates/rust-analyzer/src/handlers/request.rs +++ b/crates/rust-analyzer/src/handlers/request.rs @@ -43,10 +43,10 @@ use crate::{ FetchDependencyListResult, PositionOrRange, ViewCrateGraphParams, WorkspaceSymbolParams, }, lsp_utils::{all_edits_are_disjoint, invalid_params_error}, - to_proto, LspError, Result, + to_proto, LspError, }; -pub(crate) fn handle_workspace_reload(state: &mut GlobalState, _: ()) -> Result<()> { +pub(crate) fn handle_workspace_reload(state: &mut GlobalState, _: ()) -> anyhow::Result<()> { // FIXME: use `Arc::from_iter` when it becomes available state.proc_macro_clients = Arc::from(Vec::new()); state.proc_macro_changed = false; @@ -55,7 +55,7 @@ pub(crate) fn handle_workspace_reload(state: &mut GlobalState, _: ()) -> Result< Ok(()) } -pub(crate) fn handle_proc_macros_rebuild(state: &mut GlobalState, _: ()) -> Result<()> { +pub(crate) fn handle_proc_macros_rebuild(state: &mut GlobalState, _: ()) -> anyhow::Result<()> { // FIXME: use `Arc::from_iter` when it becomes available state.proc_macro_clients = Arc::from(Vec::new()); state.proc_macro_changed = false; @@ -67,7 +67,7 @@ pub(crate) fn handle_proc_macros_rebuild(state: &mut GlobalState, _: ()) -> Resu pub(crate) fn handle_analyzer_status( snap: GlobalStateSnapshot, params: lsp_ext::AnalyzerStatusParams, -) -> Result { +) -> anyhow::Result { let _p = profile::span("handle_analyzer_status"); let mut buf = String::new(); @@ -112,7 +112,7 @@ pub(crate) fn handle_analyzer_status( Ok(buf) } -pub(crate) fn handle_memory_usage(state: &mut GlobalState, _: ()) -> Result { +pub(crate) fn handle_memory_usage(state: &mut GlobalState, _: ()) -> anyhow::Result { let _p = profile::span("handle_memory_usage"); let mem = state.analysis_host.per_query_memory_usage(); @@ -125,7 +125,7 @@ pub(crate) fn handle_memory_usage(state: &mut GlobalState, _: ()) -> Result Result<()> { +pub(crate) fn handle_shuffle_crate_graph(state: &mut GlobalState, _: ()) -> anyhow::Result<()> { state.analysis_host.shuffle_crate_graph(); Ok(()) } @@ -133,7 +133,7 @@ pub(crate) fn handle_shuffle_crate_graph(state: &mut GlobalState, _: ()) -> Resu pub(crate) fn handle_syntax_tree( snap: GlobalStateSnapshot, params: lsp_ext::SyntaxTreeParams, -) -> Result { +) -> anyhow::Result { let _p = profile::span("handle_syntax_tree"); let id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let line_index = snap.file_line_index(id)?; @@ -145,7 +145,7 @@ pub(crate) fn handle_syntax_tree( pub(crate) fn handle_view_hir( snap: GlobalStateSnapshot, params: lsp_types::TextDocumentPositionParams, -) -> Result { +) -> anyhow::Result { let _p = profile::span("handle_view_hir"); let position = from_proto::file_position(&snap, params)?; let res = snap.analysis.view_hir(position)?; @@ -155,7 +155,7 @@ pub(crate) fn handle_view_hir( pub(crate) fn handle_view_mir( snap: GlobalStateSnapshot, params: lsp_types::TextDocumentPositionParams, -) -> Result { +) -> anyhow::Result { let _p = profile::span("handle_view_mir"); let position = from_proto::file_position(&snap, params)?; let res = snap.analysis.view_mir(position)?; @@ -165,7 +165,7 @@ pub(crate) fn handle_view_mir( pub(crate) fn handle_interpret_function( snap: GlobalStateSnapshot, params: lsp_types::TextDocumentPositionParams, -) -> Result { +) -> anyhow::Result { let _p = profile::span("handle_interpret_function"); let position = from_proto::file_position(&snap, params)?; let res = snap.analysis.interpret_function(position)?; @@ -175,7 +175,7 @@ pub(crate) fn handle_interpret_function( pub(crate) fn handle_view_file_text( snap: GlobalStateSnapshot, params: lsp_types::TextDocumentIdentifier, -) -> Result { +) -> anyhow::Result { let file_id = from_proto::file_id(&snap, ¶ms.uri)?; Ok(snap.analysis.file_text(file_id)?.to_string()) } @@ -183,7 +183,7 @@ pub(crate) fn handle_view_file_text( pub(crate) fn handle_view_item_tree( snap: GlobalStateSnapshot, params: lsp_ext::ViewItemTreeParams, -) -> Result { +) -> anyhow::Result { let _p = profile::span("handle_view_item_tree"); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let res = snap.analysis.view_item_tree(file_id)?; @@ -193,16 +193,16 @@ pub(crate) fn handle_view_item_tree( pub(crate) fn handle_view_crate_graph( snap: GlobalStateSnapshot, params: ViewCrateGraphParams, -) -> Result { +) -> anyhow::Result { let _p = profile::span("handle_view_crate_graph"); - let dot = snap.analysis.view_crate_graph(params.full)??; + let dot = snap.analysis.view_crate_graph(params.full)?.map_err(anyhow::Error::msg)?; Ok(dot) } pub(crate) fn handle_expand_macro( snap: GlobalStateSnapshot, params: lsp_ext::ExpandMacroParams, -) -> Result> { +) -> anyhow::Result> { let _p = profile::span("handle_expand_macro"); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let line_index = snap.file_line_index(file_id)?; @@ -215,11 +215,11 @@ pub(crate) fn handle_expand_macro( pub(crate) fn handle_selection_range( snap: GlobalStateSnapshot, params: lsp_types::SelectionRangeParams, -) -> Result>> { +) -> anyhow::Result>> { let _p = profile::span("handle_selection_range"); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let line_index = snap.file_line_index(file_id)?; - let res: Result> = params + let res: anyhow::Result> = params .positions .into_iter() .map(|position| { @@ -258,7 +258,7 @@ pub(crate) fn handle_selection_range( pub(crate) fn handle_matching_brace( snap: GlobalStateSnapshot, params: lsp_ext::MatchingBraceParams, -) -> Result> { +) -> anyhow::Result> { let _p = profile::span("handle_matching_brace"); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let line_index = snap.file_line_index(file_id)?; @@ -281,7 +281,7 @@ pub(crate) fn handle_matching_brace( pub(crate) fn handle_join_lines( snap: GlobalStateSnapshot, params: lsp_ext::JoinLinesParams, -) -> Result> { +) -> anyhow::Result> { let _p = profile::span("handle_join_lines"); let config = snap.config.join_lines(); @@ -306,7 +306,7 @@ pub(crate) fn handle_join_lines( pub(crate) fn handle_on_enter( snap: GlobalStateSnapshot, params: lsp_types::TextDocumentPositionParams, -) -> Result>> { +) -> anyhow::Result>> { let _p = profile::span("handle_on_enter"); let position = from_proto::file_position(&snap, params)?; let edit = match snap.analysis.on_enter(position)? { @@ -321,7 +321,7 @@ pub(crate) fn handle_on_enter( pub(crate) fn handle_on_type_formatting( snap: GlobalStateSnapshot, params: lsp_types::DocumentOnTypeFormattingParams, -) -> Result>> { +) -> anyhow::Result>> { let _p = profile::span("handle_on_type_formatting"); let mut position = from_proto::file_position(&snap, params.text_document_position)?; let line_index = snap.file_line_index(position.file_id)?; @@ -361,7 +361,7 @@ pub(crate) fn handle_on_type_formatting( pub(crate) fn handle_document_symbol( snap: GlobalStateSnapshot, params: lsp_types::DocumentSymbolParams, -) -> Result> { +) -> anyhow::Result> { let _p = profile::span("handle_document_symbol"); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let line_index = snap.file_line_index(file_id)?; @@ -450,7 +450,7 @@ pub(crate) fn handle_document_symbol( pub(crate) fn handle_workspace_symbol( snap: GlobalStateSnapshot, params: WorkspaceSymbolParams, -) -> Result>> { +) -> anyhow::Result>> { let _p = profile::span("handle_workspace_symbol"); let config = snap.config.workspace_symbol(); @@ -513,7 +513,10 @@ pub(crate) fn handle_workspace_symbol( (all_symbols, libs) } - fn exec_query(snap: &GlobalStateSnapshot, query: Query) -> Result> { + fn exec_query( + snap: &GlobalStateSnapshot, + query: Query, + ) -> anyhow::Result> { let mut res = Vec::new(); for nav in snap.analysis.symbol_search(query)? { let container_name = nav.container_name.as_ref().map(|v| v.to_string()); @@ -542,7 +545,7 @@ pub(crate) fn handle_workspace_symbol( pub(crate) fn handle_will_rename_files( snap: GlobalStateSnapshot, params: lsp_types::RenameFilesParams, -) -> Result> { +) -> anyhow::Result> { let _p = profile::span("handle_will_rename_files"); let source_changes: Vec = params @@ -604,7 +607,7 @@ pub(crate) fn handle_will_rename_files( pub(crate) fn handle_goto_definition( snap: GlobalStateSnapshot, params: lsp_types::GotoDefinitionParams, -) -> Result> { +) -> anyhow::Result> { let _p = profile::span("handle_goto_definition"); let position = from_proto::file_position(&snap, params.text_document_position_params)?; let nav_info = match snap.analysis.goto_definition(position)? { @@ -619,7 +622,7 @@ pub(crate) fn handle_goto_definition( pub(crate) fn handle_goto_declaration( snap: GlobalStateSnapshot, params: lsp_types::request::GotoDeclarationParams, -) -> Result> { +) -> anyhow::Result> { let _p = profile::span("handle_goto_declaration"); let position = from_proto::file_position(&snap, params.text_document_position_params.clone())?; let nav_info = match snap.analysis.goto_declaration(position)? { @@ -634,7 +637,7 @@ pub(crate) fn handle_goto_declaration( pub(crate) fn handle_goto_implementation( snap: GlobalStateSnapshot, params: lsp_types::request::GotoImplementationParams, -) -> Result> { +) -> anyhow::Result> { let _p = profile::span("handle_goto_implementation"); let position = from_proto::file_position(&snap, params.text_document_position_params)?; let nav_info = match snap.analysis.goto_implementation(position)? { @@ -649,7 +652,7 @@ pub(crate) fn handle_goto_implementation( pub(crate) fn handle_goto_type_definition( snap: GlobalStateSnapshot, params: lsp_types::request::GotoTypeDefinitionParams, -) -> Result> { +) -> anyhow::Result> { let _p = profile::span("handle_goto_type_definition"); let position = from_proto::file_position(&snap, params.text_document_position_params)?; let nav_info = match snap.analysis.goto_type_definition(position)? { @@ -664,7 +667,7 @@ pub(crate) fn handle_goto_type_definition( pub(crate) fn handle_parent_module( snap: GlobalStateSnapshot, params: lsp_types::TextDocumentPositionParams, -) -> Result> { +) -> anyhow::Result> { let _p = profile::span("handle_parent_module"); if let Ok(file_path) = ¶ms.text_document.uri.to_file_path() { if file_path.file_name().unwrap_or_default() == "Cargo.toml" { @@ -731,7 +734,7 @@ pub(crate) fn handle_parent_module( pub(crate) fn handle_runnables( snap: GlobalStateSnapshot, params: lsp_ext::RunnablesParams, -) -> Result> { +) -> anyhow::Result> { let _p = profile::span("handle_runnables"); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let line_index = snap.file_line_index(file_id)?; @@ -826,7 +829,7 @@ fn should_skip_for_offset(runnable: &Runnable, offset: Option) -> bool pub(crate) fn handle_related_tests( snap: GlobalStateSnapshot, params: lsp_types::TextDocumentPositionParams, -) -> Result> { +) -> anyhow::Result> { let _p = profile::span("handle_related_tests"); let position = from_proto::file_position(&snap, params)?; @@ -844,7 +847,7 @@ pub(crate) fn handle_related_tests( pub(crate) fn handle_completion( snap: GlobalStateSnapshot, params: lsp_types::CompletionParams, -) -> Result> { +) -> anyhow::Result> { let _p = profile::span("handle_completion"); let text_document_position = params.text_document_position.clone(); let position = from_proto::file_position(&snap, params.text_document_position)?; @@ -872,7 +875,7 @@ pub(crate) fn handle_completion( pub(crate) fn handle_completion_resolve( snap: GlobalStateSnapshot, mut original_completion: CompletionItem, -) -> Result { +) -> anyhow::Result { let _p = profile::span("handle_completion_resolve"); if !all_edits_are_disjoint(&original_completion, &[]) { @@ -928,7 +931,7 @@ pub(crate) fn handle_completion_resolve( pub(crate) fn handle_folding_range( snap: GlobalStateSnapshot, params: FoldingRangeParams, -) -> Result>> { +) -> anyhow::Result>> { let _p = profile::span("handle_folding_range"); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let folds = snap.analysis.folding_ranges(file_id)?; @@ -945,7 +948,7 @@ pub(crate) fn handle_folding_range( pub(crate) fn handle_signature_help( snap: GlobalStateSnapshot, params: lsp_types::SignatureHelpParams, -) -> Result> { +) -> anyhow::Result> { let _p = profile::span("handle_signature_help"); let position = from_proto::file_position(&snap, params.text_document_position_params)?; let help = match snap.analysis.signature_help(position)? { @@ -960,7 +963,7 @@ pub(crate) fn handle_signature_help( pub(crate) fn handle_hover( snap: GlobalStateSnapshot, params: lsp_ext::HoverParams, -) -> Result> { +) -> anyhow::Result> { let _p = profile::span("handle_hover"); let range = match params.position { PositionOrRange::Position(position) => Range::new(position, position), @@ -997,7 +1000,7 @@ pub(crate) fn handle_hover( pub(crate) fn handle_prepare_rename( snap: GlobalStateSnapshot, params: lsp_types::TextDocumentPositionParams, -) -> Result> { +) -> anyhow::Result> { let _p = profile::span("handle_prepare_rename"); let position = from_proto::file_position(&snap, params)?; @@ -1011,7 +1014,7 @@ pub(crate) fn handle_prepare_rename( pub(crate) fn handle_rename( snap: GlobalStateSnapshot, params: RenameParams, -) -> Result> { +) -> anyhow::Result> { let _p = profile::span("handle_rename"); let position = from_proto::file_position(&snap, params.text_document_position)?; @@ -1034,7 +1037,7 @@ pub(crate) fn handle_rename( pub(crate) fn handle_references( snap: GlobalStateSnapshot, params: lsp_types::ReferenceParams, -) -> Result>> { +) -> anyhow::Result>> { let _p = profile::span("handle_references"); let position = from_proto::file_position(&snap, params.text_document_position)?; @@ -1077,7 +1080,7 @@ pub(crate) fn handle_references( pub(crate) fn handle_formatting( snap: GlobalStateSnapshot, params: lsp_types::DocumentFormattingParams, -) -> Result>> { +) -> anyhow::Result>> { let _p = profile::span("handle_formatting"); run_rustfmt(&snap, params.text_document, None) @@ -1086,7 +1089,7 @@ pub(crate) fn handle_formatting( pub(crate) fn handle_range_formatting( snap: GlobalStateSnapshot, params: lsp_types::DocumentRangeFormattingParams, -) -> Result>> { +) -> anyhow::Result>> { let _p = profile::span("handle_range_formatting"); run_rustfmt(&snap, params.text_document, Some(params.range)) @@ -1095,7 +1098,7 @@ pub(crate) fn handle_range_formatting( pub(crate) fn handle_code_action( snap: GlobalStateSnapshot, params: lsp_types::CodeActionParams, -) -> Result>> { +) -> anyhow::Result>> { let _p = profile::span("handle_code_action"); if !snap.config.code_action_literals() { @@ -1158,7 +1161,7 @@ pub(crate) fn handle_code_action( pub(crate) fn handle_code_action_resolve( snap: GlobalStateSnapshot, mut code_action: lsp_ext::CodeAction, -) -> Result { +) -> anyhow::Result { let _p = profile::span("handle_code_action_resolve"); let params = match code_action.data.take() { Some(it) => it, @@ -1219,7 +1222,7 @@ pub(crate) fn handle_code_action_resolve( Ok(code_action) } -fn parse_action_id(action_id: &str) -> Result<(usize, SingleResolve), String> { +fn parse_action_id(action_id: &str) -> anyhow::Result<(usize, SingleResolve), String> { let id_parts = action_id.split(':').collect::>(); match id_parts.as_slice() { [assist_id_string, assist_kind_string, index_string] => { @@ -1237,7 +1240,7 @@ fn parse_action_id(action_id: &str) -> Result<(usize, SingleResolve), String> { pub(crate) fn handle_code_lens( snap: GlobalStateSnapshot, params: lsp_types::CodeLensParams, -) -> Result>> { +) -> anyhow::Result>> { let _p = profile::span("handle_code_lens"); let lens_config = snap.config.lens(); @@ -1280,7 +1283,7 @@ pub(crate) fn handle_code_lens( pub(crate) fn handle_code_lens_resolve( snap: GlobalStateSnapshot, code_lens: CodeLens, -) -> Result { +) -> anyhow::Result { let Some(annotation) = from_proto::annotation(&snap, code_lens.clone())? else { return Ok(code_lens) }; let annotation = snap.analysis.resolve_annotation(annotation)?; @@ -1301,7 +1304,7 @@ pub(crate) fn handle_code_lens_resolve( pub(crate) fn handle_document_highlight( snap: GlobalStateSnapshot, params: lsp_types::DocumentHighlightParams, -) -> Result>> { +) -> anyhow::Result>> { let _p = profile::span("handle_document_highlight"); let position = from_proto::file_position(&snap, params.text_document_position_params)?; let line_index = snap.file_line_index(position.file_id)?; @@ -1323,7 +1326,7 @@ pub(crate) fn handle_document_highlight( pub(crate) fn handle_ssr( snap: GlobalStateSnapshot, params: lsp_ext::SsrParams, -) -> Result { +) -> anyhow::Result { let _p = profile::span("handle_ssr"); let selections = params .selections @@ -1343,7 +1346,7 @@ pub(crate) fn handle_ssr( pub(crate) fn handle_inlay_hints( snap: GlobalStateSnapshot, params: InlayHintParams, -) -> Result>> { +) -> anyhow::Result>> { let _p = profile::span("handle_inlay_hints"); let document_uri = ¶ms.text_document.uri; let FileRange { file_id, range } = from_proto::file_range( @@ -1365,7 +1368,7 @@ pub(crate) fn handle_inlay_hints( pub(crate) fn handle_inlay_hints_resolve( _snap: GlobalStateSnapshot, hint: InlayHint, -) -> Result { +) -> anyhow::Result { let _p = profile::span("handle_inlay_hints_resolve"); Ok(hint) } @@ -1373,7 +1376,7 @@ pub(crate) fn handle_inlay_hints_resolve( pub(crate) fn handle_call_hierarchy_prepare( snap: GlobalStateSnapshot, params: CallHierarchyPrepareParams, -) -> Result>> { +) -> anyhow::Result>> { let _p = profile::span("handle_call_hierarchy_prepare"); let position = from_proto::file_position(&snap, params.text_document_position_params)?; @@ -1395,7 +1398,7 @@ pub(crate) fn handle_call_hierarchy_prepare( pub(crate) fn handle_call_hierarchy_incoming( snap: GlobalStateSnapshot, params: CallHierarchyIncomingCallsParams, -) -> Result>> { +) -> anyhow::Result>> { let _p = profile::span("handle_call_hierarchy_incoming"); let item = params.item; @@ -1430,7 +1433,7 @@ pub(crate) fn handle_call_hierarchy_incoming( pub(crate) fn handle_call_hierarchy_outgoing( snap: GlobalStateSnapshot, params: CallHierarchyOutgoingCallsParams, -) -> Result>> { +) -> anyhow::Result>> { let _p = profile::span("handle_call_hierarchy_outgoing"); let item = params.item; @@ -1465,7 +1468,7 @@ pub(crate) fn handle_call_hierarchy_outgoing( pub(crate) fn handle_semantic_tokens_full( snap: GlobalStateSnapshot, params: SemanticTokensParams, -) -> Result> { +) -> anyhow::Result> { let _p = profile::span("handle_semantic_tokens_full"); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; @@ -1495,7 +1498,7 @@ pub(crate) fn handle_semantic_tokens_full( pub(crate) fn handle_semantic_tokens_full_delta( snap: GlobalStateSnapshot, params: SemanticTokensDeltaParams, -) -> Result> { +) -> anyhow::Result> { let _p = profile::span("handle_semantic_tokens_full_delta"); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; @@ -1535,7 +1538,7 @@ pub(crate) fn handle_semantic_tokens_full_delta( pub(crate) fn handle_semantic_tokens_range( snap: GlobalStateSnapshot, params: SemanticTokensRangeParams, -) -> Result> { +) -> anyhow::Result> { let _p = profile::span("handle_semantic_tokens_range"); let frange = from_proto::file_range(&snap, params.text_document, params.range)?; @@ -1561,7 +1564,7 @@ pub(crate) fn handle_semantic_tokens_range( pub(crate) fn handle_open_docs( snap: GlobalStateSnapshot, params: lsp_types::TextDocumentPositionParams, -) -> Result { +) -> anyhow::Result { let _p = profile::span("handle_open_docs"); let position = from_proto::file_position(&snap, params)?; @@ -1600,7 +1603,7 @@ pub(crate) fn handle_open_docs( pub(crate) fn handle_open_cargo_toml( snap: GlobalStateSnapshot, params: lsp_ext::OpenCargoTomlParams, -) -> Result> { +) -> anyhow::Result> { let _p = profile::span("handle_open_cargo_toml"); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; @@ -1618,7 +1621,7 @@ pub(crate) fn handle_open_cargo_toml( pub(crate) fn handle_move_item( snap: GlobalStateSnapshot, params: lsp_ext::MoveItemParams, -) -> Result> { +) -> anyhow::Result> { let _p = profile::span("handle_move_item"); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; let range = from_proto::file_range(&snap, params.text_document, params.range)?; @@ -1792,7 +1795,7 @@ fn run_rustfmt( snap: &GlobalStateSnapshot, text_document: TextDocumentIdentifier, range: Option, -) -> Result>> { +) -> anyhow::Result>> { let file_id = from_proto::file_id(snap, &text_document.uri)?; let file = snap.analysis.file_text(file_id)?; @@ -1942,7 +1945,7 @@ fn run_rustfmt( pub(crate) fn fetch_dependency_list( state: GlobalStateSnapshot, _params: FetchDependencyListParams, -) -> Result { +) -> anyhow::Result { let crates = state.analysis.fetch_crates()?; let crate_infos = crates .into_iter() diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs index 65de4366e9f6..57e26c241bba 100644 --- a/crates/rust-analyzer/src/lib.rs +++ b/crates/rust-analyzer/src/lib.rs @@ -54,13 +54,12 @@ use serde::de::DeserializeOwned; pub use crate::{caps::server_capabilities, main_loop::main_loop, version::version}; -pub type Error = Box; -pub type Result = std::result::Result; - -pub fn from_json(what: &'static str, json: &serde_json::Value) -> Result { - let res = serde_json::from_value(json.clone()) - .map_err(|e| format!("Failed to deserialize {what}: {e}; {json}"))?; - Ok(res) +pub fn from_json( + what: &'static str, + json: &serde_json::Value, +) -> anyhow::Result { + serde_json::from_value(json.clone()) + .map_err(|e| anyhow::format_err!("Failed to deserialize {what}: {e}; {json}")) } #[derive(Debug)] diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 02dd94e5fa59..a6640570fcb4 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -23,10 +23,9 @@ use crate::{ lsp_ext, lsp_utils::{notification_is, Progress}, reload::{BuildDataProgress, ProcMacroProgress, ProjectWorkspaceProgress}, - Result, }; -pub fn main_loop(config: Config, connection: Connection) -> Result<()> { +pub fn main_loop(config: Config, connection: Connection) -> anyhow::Result<()> { tracing::info!("initial config: {:#?}", config); // Windows scheduler implements priority boosts: if thread waits for an @@ -109,7 +108,7 @@ impl fmt::Debug for Event { } impl GlobalState { - fn run(mut self, inbox: Receiver) -> Result<()> { + fn run(mut self, inbox: Receiver) -> anyhow::Result<()> { self.update_status_or_notify(); if self.config.did_save_text_document_dynamic_registration() { @@ -134,7 +133,7 @@ impl GlobalState { self.handle_event(event)?; } - Err("client exited without proper shutdown sequence".into()) + anyhow::bail!("client exited without proper shutdown sequence") } fn register_did_save_capability(&mut self) { @@ -191,7 +190,7 @@ impl GlobalState { } } - fn handle_event(&mut self, event: Event) -> Result<()> { + fn handle_event(&mut self, event: Event) -> anyhow::Result<()> { let loop_start = Instant::now(); // NOTE: don't count blocking select! call as a loop-turn time let _p = profile::span("GlobalState::handle_event"); @@ -758,7 +757,7 @@ impl GlobalState { } /// Handles an incoming notification. - fn on_notification(&mut self, not: Notification) -> Result<()> { + fn on_notification(&mut self, not: Notification) -> anyhow::Result<()> { use crate::handlers::notification as handlers; use lsp_types::notification as notifs; diff --git a/crates/rust-analyzer/tests/slow-tests/support.rs b/crates/rust-analyzer/tests/slow-tests/support.rs index b2a8041ae9b5..1cae8688eb26 100644 --- a/crates/rust-analyzer/tests/slow-tests/support.rs +++ b/crates/rust-analyzer/tests/slow-tests/support.rs @@ -78,7 +78,10 @@ impl<'a> Project<'a> { INIT.call_once(|| { tracing_subscriber::fmt() .with_test_writer() - .with_env_filter(tracing_subscriber::EnvFilter::from_env("RA_LOG")) + // FIXME: I am not smart enough to figure out how to use this with + // `tracing_subscriber::filter::Targets`. + // + // .with_env_filter(tracing_subscriber::EnvFilter::from_env("RA_LOG")) .init(); profile::init_from(crate::PROFILE); }); From c5a9adc2bef3afcaf8bcdb260e218a82911a034e Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sun, 18 Jun 2023 22:20:10 +0200 Subject: [PATCH 012/324] new lint: `type_id_on_box` --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/methods/mod.rs | 35 ++++++++++++ clippy_lints/src/methods/type_id_on_box.rs | 64 ++++++++++++++++++++++ tests/ui/type_id_on_box.fixed | 20 +++++++ tests/ui/type_id_on_box.rs | 20 +++++++ tests/ui/type_id_on_box.stderr | 25 +++++++++ 7 files changed, 166 insertions(+) create mode 100644 clippy_lints/src/methods/type_id_on_box.rs create mode 100644 tests/ui/type_id_on_box.fixed create mode 100644 tests/ui/type_id_on_box.rs create mode 100644 tests/ui/type_id_on_box.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 269be545b0ab..f82a37392590 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5230,6 +5230,7 @@ Released 2018-09-13 [`trivially_copy_pass_by_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref [`try_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#try_err [`type_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_complexity +[`type_id_on_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_id_on_box [`type_repetition_in_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds [`unchecked_duration_subtraction`]: https://rust-lang.github.io/rust-clippy/master/index.html#unchecked_duration_subtraction [`undocumented_unsafe_blocks`]: https://rust-lang.github.io/rust-clippy/master/index.html#undocumented_unsafe_blocks diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 7690e8f72470..0a2db21ca95c 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -403,6 +403,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::SUSPICIOUS_MAP_INFO, crate::methods::SUSPICIOUS_SPLITN_INFO, crate::methods::SUSPICIOUS_TO_OWNED_INFO, + crate::methods::TYPE_ID_ON_BOX_INFO, crate::methods::UNINIT_ASSUMED_INIT_INFO, crate::methods::UNIT_HASH_INFO, crate::methods::UNNECESSARY_FILTER_MAP_INFO, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 99c984ba65a8..e98fe99eac73 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -87,6 +87,7 @@ mod suspicious_command_arg_space; mod suspicious_map; mod suspicious_splitn; mod suspicious_to_owned; +mod type_id_on_box; mod uninit_assumed_init; mod unit_hash; mod unnecessary_filter_map; @@ -2922,6 +2923,37 @@ declare_clippy_lint! { "use of sort() when sort_unstable() is equivalent" } +declare_clippy_lint! { + /// ### What it does + /// Looks for calls to ` as Any>::type_id`. + /// + /// ### Why is this bad? + /// This most certainly does not do what the user expects and is very easy to miss. + /// Calling `type_id` on a `Box` calls `type_id` on the `Box<..>` itself, + /// so this will return the `TypeId` of the `Box` type (not the type id + /// of the value referenced by the box!). + /// + /// ### Example + /// ```rust,ignore + /// use std::any::{Any, TypeId}; + /// + /// let any_box: Box = Box::new(42_i32); + /// assert_eq!(any_box.type_id(), TypeId::of::()); // ⚠️ this fails! + /// ``` + /// Use instead: + /// ```rust + /// use std::any::{Any, TypeId}; + /// + /// let any_box: Box = Box::new(42_i32); + /// assert_eq!((*any_box).type_id(), TypeId::of::()); + /// // ^ dereference first, to call `type_id` on `dyn Any` + /// ``` + #[clippy::version = "1.47.0"] + pub TYPE_ID_ON_BOX, + suspicious, + "calling `.type_id()` on `Box`" +} + declare_clippy_lint! { /// ### What it does /// Detects `().hash(_)`. @@ -3878,6 +3910,9 @@ impl Methods { ("to_os_string" | "to_path_buf" | "to_vec", []) => { implicit_clone::check(cx, name, expr, recv); }, + ("type_id", []) => { + type_id_on_box::check(cx, recv, expr.span); + } ("unwrap", []) => { match method_call(recv) { Some(("get", recv, [get_arg], _, _)) => { diff --git a/clippy_lints/src/methods/type_id_on_box.rs b/clippy_lints/src/methods/type_id_on_box.rs new file mode 100644 index 000000000000..8ccbd0d8d1bd --- /dev/null +++ b/clippy_lints/src/methods/type_id_on_box.rs @@ -0,0 +1,64 @@ +use crate::methods::TYPE_ID_ON_BOX; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::source::snippet; +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_middle::ty::adjustment::Adjust; +use rustc_middle::ty::adjustment::Adjustment; +use rustc_middle::ty::Ty; +use rustc_middle::ty::{self, ExistentialPredicate}; +use rustc_span::{sym, Span}; + +fn is_dyn_trait(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { + if let ty::Dynamic(preds, ..) = ty.kind() { + preds.iter().any(|p| match p.skip_binder() { + ExistentialPredicate::Trait(tr) => cx.tcx.is_diagnostic_item(sym::Any, tr.def_id), + _ => false, + }) + } else { + false + } +} + +pub(super) fn check(cx: &LateContext<'_>, receiver: &Expr<'_>, call_span: Span) { + let recv_adjusts = cx.typeck_results().expr_adjustments(receiver); + + if let Some(Adjustment { target: recv_ty, .. }) = recv_adjusts.last() + && let ty::Ref(_, ty, _) = recv_ty.kind() + && let ty::Adt(adt, substs) = ty.kind() + && adt.is_box() + && is_dyn_trait(cx, substs.type_at(0)) + { + span_lint_and_then( + cx, + TYPE_ID_ON_BOX, + call_span, + "calling `.type_id()` on a `Box`", + |diag| { + let derefs = recv_adjusts + .iter() + .filter(|adj| matches!(adj.kind, Adjust::Deref(None))) + .count(); + + let mut sugg = "*".repeat(derefs + 1); + sugg += &snippet(cx, receiver.span, ""); + + diag.note( + "this returns the type id of the literal type `Box` instead of the \ + type id of the boxed value, which is most likely not what you want" + ) + .note( + "if this is intentional, use `TypeId::of::>()` instead, \ + which makes it more clear" + ) + .span_suggestion( + receiver.span, + "consider dereferencing first", + format!("({sugg})"), + Applicability::MaybeIncorrect, + ); + }, + ); + } +} diff --git a/tests/ui/type_id_on_box.fixed b/tests/ui/type_id_on_box.fixed new file mode 100644 index 000000000000..fc177afacd4d --- /dev/null +++ b/tests/ui/type_id_on_box.fixed @@ -0,0 +1,20 @@ +//@run-rustfix + +#![warn(clippy::type_id_on_box)] + +use std::any::{Any, TypeId}; + +fn existential() -> impl Any { + Box::new(1) as Box +} + +fn main() { + let any_box: Box = Box::new(0usize); + let _ = (*any_box).type_id(); + let _ = TypeId::of::>(); // don't lint, user probably explicitly wants to do this + let _ = (*any_box).type_id(); + let any_box: &Box = &(Box::new(0usize) as Box); + let _ = (**any_box).type_id(); // 2 derefs are needed here + let b = existential(); + let _ = b.type_id(); // don't lint +} diff --git a/tests/ui/type_id_on_box.rs b/tests/ui/type_id_on_box.rs new file mode 100644 index 000000000000..36cf631a092e --- /dev/null +++ b/tests/ui/type_id_on_box.rs @@ -0,0 +1,20 @@ +//@run-rustfix + +#![warn(clippy::type_id_on_box)] + +use std::any::{Any, TypeId}; + +fn existential() -> impl Any { + Box::new(1) as Box +} + +fn main() { + let any_box: Box = Box::new(0usize); + let _ = any_box.type_id(); + let _ = TypeId::of::>(); // don't lint, user probably explicitly wants to do this + let _ = (*any_box).type_id(); + let any_box: &Box = &(Box::new(0usize) as Box); + let _ = any_box.type_id(); // 2 derefs are needed here + let b = existential(); + let _ = b.type_id(); // don't lint +} diff --git a/tests/ui/type_id_on_box.stderr b/tests/ui/type_id_on_box.stderr new file mode 100644 index 000000000000..47e0e814daf6 --- /dev/null +++ b/tests/ui/type_id_on_box.stderr @@ -0,0 +1,25 @@ +error: calling `.type_id()` on a `Box` + --> $DIR/type_id_on_box.rs:13:13 + | +LL | let _ = any_box.type_id(); + | -------^^^^^^^^^^ + | | + | help: consider dereferencing first: `(*any_box)` + | + = note: this returns the type id of the literal type `Box` instead of the type id of the boxed value, which is most likely not what you want + = note: if this is intentional, use `TypeId::of::>()` instead, which makes it more clear + = note: `-D clippy::type-id-on-box` implied by `-D warnings` + +error: calling `.type_id()` on a `Box` + --> $DIR/type_id_on_box.rs:17:13 + | +LL | let _ = any_box.type_id(); // 2 derefs are needed here + | -------^^^^^^^^^^ + | | + | help: consider dereferencing first: `(**any_box)` + | + = note: this returns the type id of the literal type `Box` instead of the type id of the boxed value, which is most likely not what you want + = note: if this is intentional, use `TypeId::of::>()` instead, which makes it more clear + +error: aborting due to 2 previous errors + From 9ab1e8e95c45cbe9cdf657bded08a7d874e48fbd Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sun, 18 Jun 2023 22:27:20 +0200 Subject: [PATCH 013/324] that was definitely not the right version --- clippy_lints/src/methods/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index e98fe99eac73..255a8cc0a95a 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2948,7 +2948,7 @@ declare_clippy_lint! { /// assert_eq!((*any_box).type_id(), TypeId::of::()); /// // ^ dereference first, to call `type_id` on `dyn Any` /// ``` - #[clippy::version = "1.47.0"] + #[clippy::version = "1.72.0"] pub TYPE_ID_ON_BOX, suspicious, "calling `.type_id()` on `Box`" From 26ac76c15f4a12b2debde692dfff02a08d516f6e Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sun, 18 Jun 2023 22:36:08 +0200 Subject: [PATCH 014/324] add it to the methods lint pass --- clippy_lints/src/methods/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 255a8cc0a95a..6c0e15d16d76 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3389,6 +3389,7 @@ impl_lint_pass!(Methods => [ STRING_EXTEND_CHARS, ITER_CLONED_COLLECT, ITER_WITH_DRAIN, + TYPE_ID_ON_BOX, USELESS_ASREF, UNNECESSARY_FOLD, UNNECESSARY_FILTER_MAP, From b0dfecd8c13aaf51946ce43db8a6ed398b9a5bf5 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Mon, 19 Jun 2023 00:36:16 +0200 Subject: [PATCH 015/324] add a few more test cases --- tests/ui/type_id_on_box.fixed | 26 +++++++++++++++++++++++--- tests/ui/type_id_on_box.rs | 26 +++++++++++++++++++++++--- tests/ui/type_id_on_box.stderr | 19 +++++++++++++++---- 3 files changed, 61 insertions(+), 10 deletions(-) diff --git a/tests/ui/type_id_on_box.fixed b/tests/ui/type_id_on_box.fixed index fc177afacd4d..615d809c8975 100644 --- a/tests/ui/type_id_on_box.fixed +++ b/tests/ui/type_id_on_box.fixed @@ -3,6 +3,19 @@ #![warn(clippy::type_id_on_box)] use std::any::{Any, TypeId}; +use std::ops::Deref; + +type SomeBox = Box; + +struct BadBox(Box); + +impl Deref for BadBox { + type Target = Box; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} fn existential() -> impl Any { Box::new(1) as Box @@ -11,10 +24,17 @@ fn existential() -> impl Any { fn main() { let any_box: Box = Box::new(0usize); let _ = (*any_box).type_id(); - let _ = TypeId::of::>(); // don't lint, user probably explicitly wants to do this + let _ = TypeId::of::>(); // Don't lint. We explicitly say "do this instead" if this is intentional let _ = (*any_box).type_id(); let any_box: &Box = &(Box::new(0usize) as Box); - let _ = (**any_box).type_id(); // 2 derefs are needed here + let _ = (**any_box).type_id(); // 2 derefs are needed here to get to the `dyn Any` + let b = existential(); - let _ = b.type_id(); // don't lint + let _ = b.type_id(); // Don't lint. + + let b: SomeBox = Box::new(0usize); + let _ = (*b).type_id(); + + let b = BadBox(Box::new(0usize)); + let _ = b.type_id(); // Don't lint. This is a call to `::type_id`. Not `std::boxed::Box`! } diff --git a/tests/ui/type_id_on_box.rs b/tests/ui/type_id_on_box.rs index 36cf631a092e..74b6c74ae5f6 100644 --- a/tests/ui/type_id_on_box.rs +++ b/tests/ui/type_id_on_box.rs @@ -3,6 +3,19 @@ #![warn(clippy::type_id_on_box)] use std::any::{Any, TypeId}; +use std::ops::Deref; + +type SomeBox = Box; + +struct BadBox(Box); + +impl Deref for BadBox { + type Target = Box; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} fn existential() -> impl Any { Box::new(1) as Box @@ -11,10 +24,17 @@ fn existential() -> impl Any { fn main() { let any_box: Box = Box::new(0usize); let _ = any_box.type_id(); - let _ = TypeId::of::>(); // don't lint, user probably explicitly wants to do this + let _ = TypeId::of::>(); // Don't lint. We explicitly say "do this instead" if this is intentional let _ = (*any_box).type_id(); let any_box: &Box = &(Box::new(0usize) as Box); - let _ = any_box.type_id(); // 2 derefs are needed here + let _ = any_box.type_id(); // 2 derefs are needed here to get to the `dyn Any` + let b = existential(); - let _ = b.type_id(); // don't lint + let _ = b.type_id(); // Don't lint. + + let b: SomeBox = Box::new(0usize); + let _ = b.type_id(); + + let b = BadBox(Box::new(0usize)); + let _ = b.type_id(); // Don't lint. This is a call to `::type_id`. Not `std::boxed::Box`! } diff --git a/tests/ui/type_id_on_box.stderr b/tests/ui/type_id_on_box.stderr index 47e0e814daf6..1525328c0d03 100644 --- a/tests/ui/type_id_on_box.stderr +++ b/tests/ui/type_id_on_box.stderr @@ -1,5 +1,5 @@ error: calling `.type_id()` on a `Box` - --> $DIR/type_id_on_box.rs:13:13 + --> $DIR/type_id_on_box.rs:26:13 | LL | let _ = any_box.type_id(); | -------^^^^^^^^^^ @@ -11,9 +11,9 @@ LL | let _ = any_box.type_id(); = note: `-D clippy::type-id-on-box` implied by `-D warnings` error: calling `.type_id()` on a `Box` - --> $DIR/type_id_on_box.rs:17:13 + --> $DIR/type_id_on_box.rs:30:13 | -LL | let _ = any_box.type_id(); // 2 derefs are needed here +LL | let _ = any_box.type_id(); // 2 derefs are needed here to get to the `dyn Any` | -------^^^^^^^^^^ | | | help: consider dereferencing first: `(**any_box)` @@ -21,5 +21,16 @@ LL | let _ = any_box.type_id(); // 2 derefs are needed here = note: this returns the type id of the literal type `Box` instead of the type id of the boxed value, which is most likely not what you want = note: if this is intentional, use `TypeId::of::>()` instead, which makes it more clear -error: aborting due to 2 previous errors +error: calling `.type_id()` on a `Box` + --> $DIR/type_id_on_box.rs:36:13 + | +LL | let _ = b.type_id(); + | -^^^^^^^^^^ + | | + | help: consider dereferencing first: `(*b)` + | + = note: this returns the type id of the literal type `Box` instead of the type id of the boxed value, which is most likely not what you want + = note: if this is intentional, use `TypeId::of::>()` instead, which makes it more clear + +error: aborting due to 3 previous errors From 9326cf7f0cc9a98aaf16c5dff5e7a311d1d4dfb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Mon, 19 Jun 2023 09:14:04 +0300 Subject: [PATCH 016/324] Merge commit 'cd3bf9fe51676b520c546460e6d8919b8c8ff99f' into sync-from-ra --- .github/workflows/autopublish.yaml | 4 +- .github/workflows/ci.yaml | 8 +- Cargo.lock | 50 +- crates/base-db/src/fixture.rs | 6 +- crates/base-db/src/input.rs | 23 + crates/hir-def/src/body.rs | 50 +- crates/hir-def/src/body/lower.rs | 72 +- crates/hir-def/src/body/pretty.rs | 1 + crates/hir-def/src/db.rs | 23 +- crates/hir-def/src/expander.rs | 12 +- crates/hir-def/src/find_path.rs | 4 +- crates/hir-def/src/hir.rs | 20 +- crates/hir-def/src/hir/type_ref.rs | 119 +-- crates/hir-def/src/item_scope.rs | 4 - crates/hir-def/src/item_tree.rs | 6 - crates/hir-def/src/lib.rs | 301 +++++++- .../builtin_derive_macro.rs | 70 +- .../macro_expansion_tests/builtin_fn_macro.rs | 48 +- crates/hir-def/src/nameres.rs | 23 +- crates/hir-def/src/nameres/collector.rs | 102 ++- crates/hir-def/src/path.rs | 4 +- crates/hir-def/src/path/lower.rs | 4 +- crates/hir-def/src/resolver.rs | 38 +- crates/hir-expand/src/ast_id_map.rs | 7 +- crates/hir-expand/src/attrs.rs | 10 +- crates/hir-expand/src/builtin_derive_macro.rs | 154 ++-- crates/hir-expand/src/builtin_fn_macro.rs | 147 ++-- crates/hir-expand/src/db.rs | 108 ++- crates/hir-expand/src/eager.rs | 84 +- crates/hir-expand/src/lib.rs | 72 +- crates/hir-expand/src/proc_macro.rs | 11 +- crates/hir-ty/Cargo.toml | 8 +- crates/hir-ty/src/autoderef.rs | 24 +- crates/hir-ty/src/chalk_db.rs | 4 +- crates/hir-ty/src/consteval.rs | 36 +- crates/hir-ty/src/consteval/tests.rs | 11 + crates/hir-ty/src/db.rs | 1 + crates/hir-ty/src/diagnostics/unsafe_check.rs | 7 +- crates/hir-ty/src/display.rs | 43 +- crates/hir-ty/src/infer.rs | 47 +- crates/hir-ty/src/infer/closure.rs | 3 +- crates/hir-ty/src/infer/expr.rs | 5 +- crates/hir-ty/src/infer/mutability.rs | 4 +- crates/hir-ty/src/infer/path.rs | 17 +- crates/hir-ty/src/interner.rs | 2 +- crates/hir-ty/src/layout/tests.rs | 35 +- crates/hir-ty/src/lower.rs | 119 +-- crates/hir-ty/src/method_resolution.rs | 2 +- crates/hir-ty/src/mir/borrowck.rs | 16 +- crates/hir-ty/src/mir/eval.rs | 18 +- crates/hir-ty/src/mir/lower.rs | 8 +- crates/hir-ty/src/mir/pretty.rs | 3 + crates/hir-ty/src/tests.rs | 2 + crates/hir-ty/src/tests/regression.rs | 23 + crates/hir-ty/src/tests/simple.rs | 48 ++ crates/hir-ty/src/tests/traits.rs | 10 +- crates/hir-ty/src/utils.rs | 30 +- crates/hir/src/from_id.rs | 3 + crates/hir/src/lib.rs | 92 ++- crates/hir/src/semantics.rs | 18 +- crates/hir/src/source_analyzer.rs | 7 +- crates/hir/src/symbols.rs | 1 + .../src/handlers/add_missing_impl_members.rs | 363 ++++++++- .../src/handlers/extract_type_alias.rs | 49 +- .../src/handlers/generate_delegate_methods.rs | 25 +- .../src/handlers/generate_function.rs | 102 ++- .../ide-assists/src/handlers/inline_call.rs | 3 +- .../src/handlers/inline_const_as_literal.rs | 722 ++++++++++++++++++ crates/ide-assists/src/handlers/raw_string.rs | 3 +- .../replace_derive_with_manual_impl.rs | 28 +- crates/ide-assists/src/lib.rs | 2 + crates/ide-assists/src/tests/generated.rs | 21 + crates/ide-assists/src/utils.rs | 95 ++- crates/ide-completion/src/completions/dot.rs | 122 ++- .../src/completions/item_list/trait_impl.rs | 108 ++- crates/ide-db/src/apply_change.rs | 34 +- crates/ide-db/src/path_transform.rs | 169 +++- crates/ide-db/src/search.rs | 2 + .../ide-db/src/test_data/test_doc_alias.txt | 42 +- .../test_symbol_index_collection.txt | 134 ++-- crates/ide/src/hover/tests.rs | 43 ++ crates/ide/src/inlay_hints/chaining.rs | 12 +- crates/ide/src/lib.rs | 2 +- crates/ide/src/syntax_highlighting.rs | 3 + .../test_data/highlight_strings.html | 3 + crates/ide/src/syntax_highlighting/tests.rs | 3 + crates/parser/src/grammar/types.rs | 2 + .../parser/inline/ok/0017_array_type.rast | 5 +- .../test_data/parser/ok/0030_traits.rast | 5 +- .../parser/ok/0043_complex_assignment.rast | 5 +- crates/proc-macro-srv/src/server.rs | 6 +- crates/project-model/src/workspace.rs | 6 + crates/rust-analyzer/Cargo.toml | 3 +- crates/rust-analyzer/src/cli.rs | 17 +- .../rust-analyzer/src/cli/analysis_stats.rs | 328 +++++--- crates/rust-analyzer/src/cli/diagnostics.rs | 8 +- crates/rust-analyzer/src/cli/flags.rs | 20 +- .../rust-analyzer/src/cli/progress_report.rs | 41 +- crates/rust-analyzer/src/dispatch.rs | 48 +- crates/rust-analyzer/src/global_state.rs | 35 +- .../src/handlers/notification.rs | 4 +- crates/rust-analyzer/src/handlers/request.rs | 24 +- crates/rust-analyzer/src/main_loop.rs | 82 +- crates/rust-analyzer/src/reload.rs | 45 +- crates/rust-analyzer/src/to_proto.rs | 33 +- crates/rust-analyzer/tests/slow-tests/main.rs | 13 +- crates/syntax/rust.ungram | 2 +- crates/syntax/src/ast/generated/nodes.rs | 2 +- crates/syntax/src/ast/make.rs | 6 +- crates/test-utils/src/fixture.rs | 4 + crates/test-utils/src/minicore.rs | 51 +- docs/user/manual.adoc | 21 +- editors/code/.vscodeignore | 1 + lib/la-arena/src/lib.rs | 6 + 114 files changed, 3893 insertions(+), 1252 deletions(-) create mode 100644 crates/ide-assists/src/handlers/inline_const_as_literal.rs diff --git a/.github/workflows/autopublish.yaml b/.github/workflows/autopublish.yaml index 7090c94d93cc..15cedab12726 100644 --- a/.github/workflows/autopublish.yaml +++ b/.github/workflows/autopublish.yaml @@ -28,7 +28,7 @@ jobs: - name: Publish Crates env: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} - PATCH: ${{ github.run_number }} + RUN_NUMBER: ${{ github.run_number }} shell: bash run: | git config --global user.email "runner@gha.local" @@ -53,4 +53,4 @@ jobs: # Remove library crates from the workspaces so we don't auto-publish them as well sed -i 's/ "lib\/\*",//' ./Cargo.toml find crates/rust-analyzer -type f -name '*.rs' -exec sed -i 's/rust_analyzer/ra_ap_rust_analyzer/g' {} + - cargo workspaces publish --yes --force '*' --exact --no-git-commit --allow-dirty --skip-published custom 0.0.$PATCH + cargo workspaces publish --yes --force '*' --exact --no-git-commit --allow-dirty --skip-published custom 0.0.$(($RUN_NUMBER + 133)) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 622da105fdd4..31bb7eed8d73 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -24,6 +24,7 @@ jobs: pull-requests: read outputs: typescript: ${{ steps.filter.outputs.typescript }} + proc_macros: ${{ steps.filter.outputs.proc_macros }} steps: - uses: actions/checkout@v3 - uses: dorny/paths-filter@4067d885736b84de7c414f582ac45897079b0a78 @@ -45,8 +46,8 @@ jobs: runs-on: ${{ matrix.os }} env: CC: deny_c - RUST_CHANNEL: "${{ needs.changes.outputs.proc_macros == 'true' && 'nightly' || 'stable'}}" - USE_SYSROOT_ABI: "${{ needs.changes.outputs.proc_macros == 'true' && '--features sysroot-abi' || ''}}" + RUST_CHANNEL: "${{ needs.changes.outputs.proc_macros == 'true' && 'nightly' || 'stable' }}" + USE_SYSROOT_ABI: "${{ needs.changes.outputs.proc_macros == 'true' && '--features sysroot-abi' || '' }}" strategy: fail-fast: false @@ -62,7 +63,8 @@ jobs: - name: Install Rust toolchain run: | rustup update --no-self-update ${{ env.RUST_CHANNEL }} - rustup component add rustfmt rust-src + rustup component add --toolchain ${{ env.RUST_CHANNEL }} rustfmt rust-src + rustup default ${{ env.RUST_CHANNEL }} - name: Cache Dependencies uses: Swatinem/rust-cache@988c164c3d0e93c4dbab36aaf5bbeb77425b2894 diff --git a/Cargo.lock b/Cargo.lock index e36aef6a6aa8..50c81ca279ee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -177,21 +177,21 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chalk-derive" -version = "0.89.0" +version = "0.91.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea176c50987dc4765961aa165001e8eb5a722a26308c5797a47303ea91686aab" +checksum = "c59178fded594fe78c47b841520e5a4399d00fe15fffee19b945958a878cd02d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.15", "synstructure", ] [[package]] name = "chalk-ir" -version = "0.89.0" +version = "0.91.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "473b480241695428c14e8f84f1c9a47ef232450a50faf3a4041e5c9dc11e0a3b" +checksum = "8824be92876823b828d551bb792f79eb1f69c69d1948abf69fccbf84e448e57b" dependencies = [ "bitflags 1.3.2", "chalk-derive", @@ -200,9 +200,9 @@ dependencies = [ [[package]] name = "chalk-recursive" -version = "0.89.0" +version = "0.91.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6764b4fe67cac3a3758185084efbfbd39bf0352795824ba849ddd2b64cd4bb28" +checksum = "1e110d1260809c238072d1c8ef84060e39983e8ea9d4c6f74b19b0ebbf8904dc" dependencies = [ "chalk-derive", "chalk-ir", @@ -213,9 +213,9 @@ dependencies = [ [[package]] name = "chalk-solve" -version = "0.89.0" +version = "0.91.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55a7e6160966eceb6e7dcc2f479a2af4c477aaf5bccbc640d82515995ab1a6cc" +checksum = "12200b19abf4b0633095f7bd099f3ef609d314754b6adb358c68cc04d10589e5" dependencies = [ "chalk-derive", "chalk-ir", @@ -327,7 +327,7 @@ checksum = "f3cdeb9ec472d588e539a818b2dee436825730da08ad0017c4b1a17676bdc8b7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -1505,7 +1505,6 @@ dependencies = [ "parking_lot 0.12.1", "parking_lot_core 0.9.6", "proc-macro-api", - "proc-macro-srv-cli", "profile", "project-model", "rayon", @@ -1578,7 +1577,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -1637,7 +1636,7 @@ checksum = "d7e29c4601e36bcec74a223228dce795f4cd3616341a4af93520ca1a837c087d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -1660,7 +1659,7 @@ checksum = "395627de918015623b32e7669714206363a7fc00382bf477e72c1f7533e8eafc" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -1731,14 +1730,25 @@ dependencies = [ ] [[package]] -name = "synstructure" -version = "0.12.6" +name = "syn" +version = "2.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" dependencies = [ "proc-macro2", "quote", - "syn", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "285ba80e733fac80aa4270fbcdf83772a79b80aa35c97075320abfee4a915b06" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.15", "unicode-xid", ] @@ -1811,7 +1821,7 @@ checksum = "5420d42e90af0c38c3290abcca25b9b3bdf379fc9f55c528f53a269d9c9a267e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -1913,7 +1923,7 @@ checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] diff --git a/crates/base-db/src/fixture.rs b/crates/base-db/src/fixture.rs index 5b11343173b3..d3abc3870b70 100644 --- a/crates/base-db/src/fixture.rs +++ b/crates/base-db/src/fixture.rs @@ -215,7 +215,7 @@ impl ChangeFixture { None, default_cfg, Default::default(), - Env::default(), + Env::new_for_test_fixture(), false, CrateOrigin::Local { repo: None, name: None }, default_target_data_layout @@ -259,7 +259,7 @@ impl ChangeFixture { None, Default::default(), Default::default(), - Env::default(), + Env::new_for_test_fixture(), false, CrateOrigin::Lang(LangCrateOrigin::Core), target_layout.clone(), @@ -298,7 +298,7 @@ impl ChangeFixture { None, Default::default(), Default::default(), - Env::default(), + Env::new_for_test_fixture(), true, CrateOrigin::Local { repo: None, name: None }, target_layout, diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs index e8d521b42f86..f2e523675bcf 100644 --- a/crates/base-db/src/input.rs +++ b/crates/base-db/src/input.rs @@ -151,6 +151,12 @@ pub enum CrateOrigin { Lang(LangCrateOrigin), } +impl CrateOrigin { + pub fn is_local(&self) -> bool { + matches!(self, CrateOrigin::Local { .. }) + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum LangCrateOrigin { Alloc, @@ -333,6 +339,17 @@ pub struct Env { entries: FxHashMap, } +impl Env { + pub fn new_for_test_fixture() -> Self { + Env { + entries: FxHashMap::from_iter([( + String::from("__ra_is_test_fixture"), + String::from("__ra_is_test_fixture"), + )]), + } + } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Dependency { pub crate_id: CrateId, @@ -456,6 +473,12 @@ impl CrateGraph { self.arena.iter().map(|(idx, _)| idx) } + // FIXME: used for `handle_hack_cargo_workspace`, should be removed later + #[doc(hidden)] + pub fn iter_mut(&mut self) -> impl Iterator + '_ { + self.arena.iter_mut() + } + /// Returns an iterator over all transitive dependencies of the given crate, /// including the crate itself. pub fn transitive_deps(&self, of: CrateId) -> impl Iterator { diff --git a/crates/hir-def/src/body.rs b/crates/hir-def/src/body.rs index 36626ed1a9b1..94dc39b11755 100644 --- a/crates/hir-def/src/body.rs +++ b/crates/hir-def/src/body.rs @@ -37,6 +37,9 @@ pub struct Body { pub pats: Arena, pub bindings: Arena, pub labels: Arena)` on an `Option` value. This can be done more directly by calling `map_or(, )` instead --> $DIR/map_unwrap_or.rs:106:13 diff --git a/tests/ui/map_unwrap_or_fixable.stderr b/tests/ui/map_unwrap_or_fixable.stderr index 1837bc2ca3b8..71dc009f2ce6 100644 --- a/tests/ui/map_unwrap_or_fixable.stderr +++ b/tests/ui/map_unwrap_or_fixable.stderr @@ -5,7 +5,7 @@ LL | let _ = opt.map(|x| x + 1) | _____________^ LL | | // Should lint even though this call is on a separate line. LL | | .unwrap_or_else(|| 0); - | |_____________________________^ help: try this: `opt.map_or_else(|| 0, |x| x + 1)` + | |_____________________________^ help: try: `opt.map_or_else(|| 0, |x| x + 1)` | = note: `-D clippy::map-unwrap-or` implied by `-D warnings` @@ -16,7 +16,7 @@ LL | let _ = res.map(|x| x + 1) | _____________^ LL | | // should lint even though this call is on a separate line LL | | .unwrap_or_else(|_e| 0); - | |_______________________________^ help: try this: `res.map_or_else(|_e| 0, |x| x + 1)` + | |_______________________________^ help: try: `res.map_or_else(|_e| 0, |x| x + 1)` error: aborting due to 2 previous errors diff --git a/tests/ui/match_as_ref.stderr b/tests/ui/match_as_ref.stderr index c3b62849cb33..252abf74bca3 100644 --- a/tests/ui/match_as_ref.stderr +++ b/tests/ui/match_as_ref.stderr @@ -6,7 +6,7 @@ LL | let borrowed: Option<&()> = match owned { LL | | None => None, LL | | Some(ref v) => Some(v), LL | | }; - | |_____^ help: try this: `owned.as_ref()` + | |_____^ help: try: `owned.as_ref()` | = note: `-D clippy::match-as-ref` implied by `-D warnings` @@ -18,7 +18,7 @@ LL | let borrow_mut: Option<&mut ()> = match mut_owned { LL | | None => None, LL | | Some(ref mut v) => Some(v), LL | | }; - | |_____^ help: try this: `mut_owned.as_mut()` + | |_____^ help: try: `mut_owned.as_mut()` error: use `as_ref()` instead --> $DIR/match_as_ref.rs:30:13 @@ -27,7 +27,7 @@ LL | / match self.source { LL | | Some(ref s) => Some(s), LL | | None => None, LL | | } - | |_____________^ help: try this: `self.source.as_ref().map(|x| x as _)` + | |_____________^ help: try: `self.source.as_ref().map(|x| x as _)` error: aborting due to 3 previous errors diff --git a/tests/ui/match_expr_like_matches_macro.stderr b/tests/ui/match_expr_like_matches_macro.stderr index b72fe10b7480..c8c1e5da05fe 100644 --- a/tests/ui/match_expr_like_matches_macro.stderr +++ b/tests/ui/match_expr_like_matches_macro.stderr @@ -6,7 +6,7 @@ LL | let _y = match x { LL | | Some(0) => true, LL | | _ => false, LL | | }; - | |_____^ help: try this: `matches!(x, Some(0))` + | |_____^ help: try: `matches!(x, Some(0))` | = note: `-D clippy::match-like-matches-macro` implied by `-D warnings` @@ -18,7 +18,7 @@ LL | let _w = match x { LL | | Some(_) => true, LL | | _ => false, LL | | }; - | |_____^ help: try this: `x.is_some()` + | |_____^ help: try: `x.is_some()` | = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` @@ -30,7 +30,7 @@ LL | let _z = match x { LL | | Some(_) => false, LL | | None => true, LL | | }; - | |_____^ help: try this: `x.is_none()` + | |_____^ help: try: `x.is_none()` error: match expression looks like `matches!` macro --> $DIR/match_expr_like_matches_macro.rs:33:15 @@ -40,13 +40,13 @@ LL | let _zz = match x { LL | | Some(r) if r == 0 => false, LL | | _ => true, LL | | }; - | |_____^ help: try this: `!matches!(x, Some(r) if r == 0)` + | |_____^ help: try: `!matches!(x, Some(r) if r == 0)` error: if let .. else expression looks like `matches!` macro --> $DIR/match_expr_like_matches_macro.rs:39:16 | LL | let _zzz = if let Some(5) = x { true } else { false }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `matches!(x, Some(5))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(x, Some(5))` error: match expression looks like `matches!` macro --> $DIR/match_expr_like_matches_macro.rs:63:20 @@ -57,7 +57,7 @@ LL | | E::A(_) => true, LL | | E::B(_) => true, LL | | _ => false, LL | | }; - | |_________^ help: try this: `matches!(x, E::A(_) | E::B(_))` + | |_________^ help: try: `matches!(x, E::A(_) | E::B(_))` error: match expression looks like `matches!` macro --> $DIR/match_expr_like_matches_macro.rs:73:20 @@ -70,7 +70,7 @@ LL | | } LL | | E::B(_) => true, LL | | _ => false, LL | | }; - | |_________^ help: try this: `matches!(x, E::A(_) | E::B(_))` + | |_________^ help: try: `matches!(x, E::A(_) | E::B(_))` error: match expression looks like `matches!` macro --> $DIR/match_expr_like_matches_macro.rs:83:20 @@ -81,7 +81,7 @@ LL | | E::B(_) => false, LL | | E::C => false, LL | | _ => true, LL | | }; - | |_________^ help: try this: `!matches!(x, E::B(_) | E::C)` + | |_________^ help: try: `!matches!(x, E::B(_) | E::C)` error: match expression looks like `matches!` macro --> $DIR/match_expr_like_matches_macro.rs:143:18 @@ -91,7 +91,7 @@ LL | let _z = match &z { LL | | Some(3) => true, LL | | _ => false, LL | | }; - | |_________^ help: try this: `matches!(z, Some(3))` + | |_________^ help: try: `matches!(z, Some(3))` error: match expression looks like `matches!` macro --> $DIR/match_expr_like_matches_macro.rs:152:18 @@ -101,7 +101,7 @@ LL | let _z = match &z { LL | | Some(3) => true, LL | | _ => false, LL | | }; - | |_________^ help: try this: `matches!(&z, Some(3))` + | |_________^ help: try: `matches!(&z, Some(3))` error: match expression looks like `matches!` macro --> $DIR/match_expr_like_matches_macro.rs:169:21 @@ -111,7 +111,7 @@ LL | let _ = match &z { LL | | AnEnum::X => true, LL | | _ => false, LL | | }; - | |_____________^ help: try this: `matches!(&z, AnEnum::X)` + | |_____________^ help: try: `matches!(&z, AnEnum::X)` error: match expression looks like `matches!` macro --> $DIR/match_expr_like_matches_macro.rs:183:20 @@ -121,7 +121,7 @@ LL | let _res = match &val { LL | | &Some(ref _a) => true, LL | | _ => false, LL | | }; - | |_________^ help: try this: `matches!(&val, &Some(ref _a))` + | |_________^ help: try: `matches!(&val, &Some(ref _a))` error: match expression looks like `matches!` macro --> $DIR/match_expr_like_matches_macro.rs:195:20 @@ -131,7 +131,7 @@ LL | let _res = match &val { LL | | &Some(ref _a) => true, LL | | _ => false, LL | | }; - | |_________^ help: try this: `matches!(&val, &Some(ref _a))` + | |_________^ help: try: `matches!(&val, &Some(ref _a))` error: match expression looks like `matches!` macro --> $DIR/match_expr_like_matches_macro.rs:253:14 @@ -141,7 +141,7 @@ LL | let _y = match Some(5) { LL | | Some(0) => true, LL | | _ => false, LL | | }; - | |_____^ help: try this: `matches!(Some(5), Some(0))` + | |_____^ help: try: `matches!(Some(5), Some(0))` error: aborting due to 14 previous errors diff --git a/tests/ui/match_on_vec_items.stderr b/tests/ui/match_on_vec_items.stderr index 9b1f052867e0..fc4a3ce19463 100644 --- a/tests/ui/match_on_vec_items.stderr +++ b/tests/ui/match_on_vec_items.stderr @@ -2,7 +2,7 @@ error: indexing into a vector may panic --> $DIR/match_on_vec_items.rs:10:11 | LL | match arr[idx] { - | ^^^^^^^^ help: try this: `arr.get(idx)` + | ^^^^^^^^ help: try: `arr.get(idx)` | = note: `-D clippy::match-on-vec-items` implied by `-D warnings` @@ -10,43 +10,43 @@ error: indexing into a vector may panic --> $DIR/match_on_vec_items.rs:17:11 | LL | match arr[range] { - | ^^^^^^^^^^ help: try this: `arr.get(range)` + | ^^^^^^^^^^ help: try: `arr.get(range)` error: indexing into a vector may panic --> $DIR/match_on_vec_items.rs:30:11 | LL | match arr[idx] { - | ^^^^^^^^ help: try this: `arr.get(idx)` + | ^^^^^^^^ help: try: `arr.get(idx)` error: indexing into a vector may panic --> $DIR/match_on_vec_items.rs:37:11 | LL | match arr[range] { - | ^^^^^^^^^^ help: try this: `arr.get(range)` + | ^^^^^^^^^^ help: try: `arr.get(range)` error: indexing into a vector may panic --> $DIR/match_on_vec_items.rs:50:11 | LL | match arr[idx] { - | ^^^^^^^^ help: try this: `arr.get(idx)` + | ^^^^^^^^ help: try: `arr.get(idx)` error: indexing into a vector may panic --> $DIR/match_on_vec_items.rs:57:11 | LL | match arr[range] { - | ^^^^^^^^^^ help: try this: `arr.get(range)` + | ^^^^^^^^^^ help: try: `arr.get(range)` error: indexing into a vector may panic --> $DIR/match_on_vec_items.rs:70:11 | LL | match arr[idx] { - | ^^^^^^^^ help: try this: `arr.get(idx)` + | ^^^^^^^^ help: try: `arr.get(idx)` error: indexing into a vector may panic --> $DIR/match_on_vec_items.rs:77:11 | LL | match arr[range] { - | ^^^^^^^^^^ help: try this: `arr.get(range)` + | ^^^^^^^^^^ help: try: `arr.get(range)` error: aborting due to 8 previous errors diff --git a/tests/ui/match_ref_pats.stderr b/tests/ui/match_ref_pats.stderr index 7d9646c842ee..1294e0fe56fd 100644 --- a/tests/ui/match_ref_pats.stderr +++ b/tests/ui/match_ref_pats.stderr @@ -35,7 +35,7 @@ error: redundant pattern matching, consider using `is_none()` --> $DIR/match_ref_pats.rs:38:12 | LL | if let &None = a { - | -------^^^^^---- help: try this: `if a.is_none()` + | -------^^^^^---- help: try: `if a.is_none()` | = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` @@ -43,7 +43,7 @@ error: redundant pattern matching, consider using `is_none()` --> $DIR/match_ref_pats.rs:43:12 | LL | if let &None = &b { - | -------^^^^^----- help: try this: `if b.is_none()` + | -------^^^^^----- help: try: `if b.is_none()` error: you don't need to add `&` to all patterns --> $DIR/match_ref_pats.rs:103:9 diff --git a/tests/ui/match_same_arms2.stderr b/tests/ui/match_same_arms2.stderr index 7f0c70745ac0..a73481875738 100644 --- a/tests/ui/match_same_arms2.stderr +++ b/tests/ui/match_same_arms2.stderr @@ -144,7 +144,7 @@ LL | | E::A => false, LL | | E::B => false, LL | | _ => true, LL | | }; - | |_____^ help: try this: `!matches!(x, E::A | E::B)` + | |_____^ help: try: `!matches!(x, E::A | E::B)` | = note: `-D clippy::match-like-matches-macro` implied by `-D warnings` diff --git a/tests/ui/match_wildcard_for_single_variants.stderr b/tests/ui/match_wildcard_for_single_variants.stderr index 105b4c4b41d1..40ff4fbd3160 100644 --- a/tests/ui/match_wildcard_for_single_variants.stderr +++ b/tests/ui/match_wildcard_for_single_variants.stderr @@ -2,7 +2,7 @@ error: wildcard matches only a single variant and will also match any future add --> $DIR/match_wildcard_for_single_variants.rs:24:13 | LL | _ => (), - | ^ help: try this: `Self::Rgb(..)` + | ^ help: try: `Self::Rgb(..)` | = note: `-D clippy::match-wildcard-for-single-variants` implied by `-D warnings` @@ -10,55 +10,55 @@ error: wildcard matches only a single variant and will also match any future add --> $DIR/match_wildcard_for_single_variants.rs:34:9 | LL | _ => {}, - | ^ help: try this: `Foo::C` + | ^ help: try: `Foo::C` error: wildcard matches only a single variant and will also match any future added variants --> $DIR/match_wildcard_for_single_variants.rs:44:9 | LL | _ => {}, - | ^ help: try this: `Color::Blue` + | ^ help: try: `Color::Blue` error: wildcard matches only a single variant and will also match any future added variants --> $DIR/match_wildcard_for_single_variants.rs:52:9 | LL | _ => {}, - | ^ help: try this: `Color::Blue` + | ^ help: try: `Color::Blue` error: wildcard matches only a single variant and will also match any future added variants --> $DIR/match_wildcard_for_single_variants.rs:58:9 | LL | _ => {}, - | ^ help: try this: `Color::Blue` + | ^ help: try: `Color::Blue` error: wildcard matches only a single variant and will also match any future added variants --> $DIR/match_wildcard_for_single_variants.rs:75:9 | LL | &_ => (), - | ^^ help: try this: `Color::Blue` + | ^^ help: try: `Color::Blue` error: wildcard matches only a single variant and will also match any future added variants --> $DIR/match_wildcard_for_single_variants.rs:84:9 | LL | _ => (), - | ^ help: try this: `C::Blue` + | ^ help: try: `C::Blue` error: wildcard matches only a single variant and will also match any future added variants --> $DIR/match_wildcard_for_single_variants.rs:91:9 | LL | _ => (), - | ^ help: try this: `Color::Blue` + | ^ help: try: `Color::Blue` error: wildcard matches only a single variant and will also match any future added variants --> $DIR/match_wildcard_for_single_variants.rs:126:13 | LL | _ => (), - | ^ help: try this: `Enum::__Private` + | ^ help: try: `Enum::__Private` error: wildcard matches only a single variant and will also match any future added variants --> $DIR/match_wildcard_for_single_variants.rs:153:13 | LL | _ => 2, - | ^ help: try this: `Foo::B` + | ^ help: try: `Foo::B` error: aborting due to 10 previous errors diff --git a/tests/ui/methods_fixable.stderr b/tests/ui/methods_fixable.stderr index 187714c75fb9..6f45d100d282 100644 --- a/tests/ui/methods_fixable.stderr +++ b/tests/ui/methods_fixable.stderr @@ -2,7 +2,7 @@ error: called `filter(..).next()` on an `Iterator`. This is more succinctly expr --> $DIR/methods_fixable.rs:11:13 | LL | let _ = v.iter().filter(|&x| *x < 0).next(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `v.iter().find(|&x| *x < 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `v.iter().find(|&x| *x < 0)` | = note: `-D clippy::filter-next` implied by `-D warnings` diff --git a/tests/ui/missing_spin_loop.stderr b/tests/ui/missing_spin_loop.stderr index 485da00dc640..5795c2c21906 100644 --- a/tests/ui/missing_spin_loop.stderr +++ b/tests/ui/missing_spin_loop.stderr @@ -2,7 +2,7 @@ error: busy-waiting loop should at least have a spin loop hint --> $DIR/missing_spin_loop.rs:11:37 | LL | while b.load(Ordering::Acquire) {} - | ^^ help: try this: `{ std::hint::spin_loop() }` + | ^^ help: try: `{ std::hint::spin_loop() }` | = note: `-D clippy::missing-spin-loop` implied by `-D warnings` @@ -10,31 +10,31 @@ error: busy-waiting loop should at least have a spin loop hint --> $DIR/missing_spin_loop.rs:13:37 | LL | while !b.load(Ordering::SeqCst) {} - | ^^ help: try this: `{ std::hint::spin_loop() }` + | ^^ help: try: `{ std::hint::spin_loop() }` error: busy-waiting loop should at least have a spin loop hint --> $DIR/missing_spin_loop.rs:15:46 | LL | while b.load(Ordering::Acquire) == false {} - | ^^ help: try this: `{ std::hint::spin_loop() }` + | ^^ help: try: `{ std::hint::spin_loop() }` error: busy-waiting loop should at least have a spin loop hint --> $DIR/missing_spin_loop.rs:17:49 | LL | while { true == b.load(Ordering::Acquire) } {} - | ^^ help: try this: `{ std::hint::spin_loop() }` + | ^^ help: try: `{ std::hint::spin_loop() }` error: busy-waiting loop should at least have a spin loop hint --> $DIR/missing_spin_loop.rs:19:93 | LL | while b.compare_exchange(true, false, Ordering::Acquire, Ordering::Relaxed) != Ok(true) {} - | ^^ help: try this: `{ std::hint::spin_loop() }` + | ^^ help: try: `{ std::hint::spin_loop() }` error: busy-waiting loop should at least have a spin loop hint --> $DIR/missing_spin_loop.rs:21:94 | LL | while Ok(false) != b.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) {} - | ^^ help: try this: `{ std::hint::spin_loop() }` + | ^^ help: try: `{ std::hint::spin_loop() }` error: aborting due to 6 previous errors diff --git a/tests/ui/missing_spin_loop_no_std.stderr b/tests/ui/missing_spin_loop_no_std.stderr index 2b3b6873c3c4..3322a7aae5f6 100644 --- a/tests/ui/missing_spin_loop_no_std.stderr +++ b/tests/ui/missing_spin_loop_no_std.stderr @@ -2,7 +2,7 @@ error: busy-waiting loop should at least have a spin loop hint --> $DIR/missing_spin_loop_no_std.rs:13:37 | LL | while b.load(Ordering::Acquire) {} - | ^^ help: try this: `{ core::hint::spin_loop() }` + | ^^ help: try: `{ core::hint::spin_loop() }` | = note: `-D clippy::missing-spin-loop` implied by `-D warnings` diff --git a/tests/ui/needless_borrow_pat.stderr b/tests/ui/needless_borrow_pat.stderr index db3b52b8850e..2d9b8f159021 100644 --- a/tests/ui/needless_borrow_pat.stderr +++ b/tests/ui/needless_borrow_pat.stderr @@ -2,7 +2,7 @@ error: this pattern creates a reference to a reference --> $DIR/needless_borrow_pat.rs:59:14 | LL | Some(ref x) => x, - | ^^^^^ help: try this: `x` + | ^^^^^ help: try: `x` | = note: `-D clippy::needless-borrow` implied by `-D warnings` @@ -12,7 +12,7 @@ error: this pattern creates a reference to a reference LL | Some(ref x) => *x, | ^^^^^ | -help: try this +help: try | LL | Some(x) => x, | ~ ~ @@ -23,7 +23,7 @@ error: this pattern creates a reference to a reference LL | Some(ref x) => { | ^^^^^ | -help: try this +help: try | LL ~ Some(x) => { LL | f1(x); @@ -34,13 +34,13 @@ error: this pattern creates a reference to a reference --> $DIR/needless_borrow_pat.rs:81:14 | LL | Some(ref x) => m1!(x), - | ^^^^^ help: try this: `x` + | ^^^^^ help: try: `x` error: this pattern creates a reference to a reference --> $DIR/needless_borrow_pat.rs:86:15 | LL | let _ = |&ref x: &&String| { - | ^^^^^ help: try this: `x` + | ^^^^^ help: try: `x` error: this pattern creates a reference to a reference --> $DIR/needless_borrow_pat.rs:91:10 @@ -48,7 +48,7 @@ error: this pattern creates a reference to a reference LL | let (ref y,) = (&x,); | ^^^^^ | -help: try this +help: try | LL ~ let (y,) = (&x,); LL ~ let _: &String = y; @@ -58,7 +58,7 @@ error: this pattern creates a reference to a reference --> $DIR/needless_borrow_pat.rs:101:14 | LL | Some(ref x) => x.0, - | ^^^^^ help: try this: `x` + | ^^^^^ help: try: `x` error: this pattern creates a reference to a reference --> $DIR/needless_borrow_pat.rs:111:14 @@ -66,7 +66,7 @@ error: this pattern creates a reference to a reference LL | E::A(ref x) | E::B(ref x) => *x, | ^^^^^ ^^^^^ | -help: try this +help: try | LL | E::A(x) | E::B(x) => x, | ~ ~ ~ @@ -75,7 +75,7 @@ error: this pattern creates a reference to a reference --> $DIR/needless_borrow_pat.rs:117:21 | LL | if let Some(ref x) = Some(&String::new()); - | ^^^^^ help: try this: `x` + | ^^^^^ help: try: `x` error: this pattern creates a reference to a reference --> $DIR/needless_borrow_pat.rs:125:12 @@ -83,7 +83,7 @@ error: this pattern creates a reference to a reference LL | fn f2<'a>(&ref x: &&'a String) -> &'a String { | ^^^^^ | -help: try this +help: try | LL ~ fn f2<'a>(&x: &&'a String) -> &'a String { LL | let _: &String = x; @@ -94,7 +94,7 @@ error: this pattern creates a reference to a reference --> $DIR/needless_borrow_pat.rs:132:11 | LL | fn f(&ref x: &&String) { - | ^^^^^ help: try this: `x` + | ^^^^^ help: try: `x` error: this pattern creates a reference to a reference --> $DIR/needless_borrow_pat.rs:140:11 @@ -102,7 +102,7 @@ error: this pattern creates a reference to a reference LL | fn f(&ref x: &&String) { | ^^^^^ | -help: try this +help: try | LL ~ fn f(&x: &&String) { LL ~ let _: &String = x; diff --git a/tests/ui/needless_option_as_deref.stderr b/tests/ui/needless_option_as_deref.stderr index 20d28a968c91..4c0d502a2031 100644 --- a/tests/ui/needless_option_as_deref.stderr +++ b/tests/ui/needless_option_as_deref.stderr @@ -2,7 +2,7 @@ error: derefed type is same as origin --> $DIR/needless_option_as_deref.rs:9:29 | LL | let _: Option<&usize> = Some(&1).as_deref(); - | ^^^^^^^^^^^^^^^^^^^ help: try this: `Some(&1)` + | ^^^^^^^^^^^^^^^^^^^ help: try: `Some(&1)` | = note: `-D clippy::needless-option-as-deref` implied by `-D warnings` @@ -10,13 +10,13 @@ error: derefed type is same as origin --> $DIR/needless_option_as_deref.rs:10:33 | LL | let _: Option<&mut usize> = Some(&mut 1).as_deref_mut(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `Some(&mut 1)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(&mut 1)` error: derefed type is same as origin --> $DIR/needless_option_as_deref.rs:14:13 | LL | let _ = x.as_deref_mut(); - | ^^^^^^^^^^^^^^^^ help: try this: `x` + | ^^^^^^^^^^^^^^^^ help: try: `x` error: aborting due to 3 previous errors diff --git a/tests/ui/needless_splitn.stderr b/tests/ui/needless_splitn.stderr index f607d8e1ab5f..0005f758104a 100644 --- a/tests/ui/needless_splitn.stderr +++ b/tests/ui/needless_splitn.stderr @@ -2,7 +2,7 @@ error: unnecessary use of `splitn` --> $DIR/needless_splitn.rs:14:13 | LL | let _ = str.splitn(2, '=').next(); - | ^^^^^^^^^^^^^^^^^^ help: try this: `str.split('=')` + | ^^^^^^^^^^^^^^^^^^ help: try: `str.split('=')` | = note: `-D clippy::needless-splitn` implied by `-D warnings` @@ -10,73 +10,73 @@ error: unnecessary use of `splitn` --> $DIR/needless_splitn.rs:15:13 | LL | let _ = str.splitn(2, '=').nth(0); - | ^^^^^^^^^^^^^^^^^^ help: try this: `str.split('=')` + | ^^^^^^^^^^^^^^^^^^ help: try: `str.split('=')` error: unnecessary use of `splitn` --> $DIR/needless_splitn.rs:18:18 | LL | let (_, _) = str.splitn(3, '=').next_tuple().unwrap(); - | ^^^^^^^^^^^^^^^^^^ help: try this: `str.split('=')` + | ^^^^^^^^^^^^^^^^^^ help: try: `str.split('=')` error: unnecessary use of `rsplitn` --> $DIR/needless_splitn.rs:21:13 | LL | let _ = str.rsplitn(2, '=').next(); - | ^^^^^^^^^^^^^^^^^^^ help: try this: `str.rsplit('=')` + | ^^^^^^^^^^^^^^^^^^^ help: try: `str.rsplit('=')` error: unnecessary use of `rsplitn` --> $DIR/needless_splitn.rs:22:13 | LL | let _ = str.rsplitn(2, '=').nth(0); - | ^^^^^^^^^^^^^^^^^^^ help: try this: `str.rsplit('=')` + | ^^^^^^^^^^^^^^^^^^^ help: try: `str.rsplit('=')` error: unnecessary use of `rsplitn` --> $DIR/needless_splitn.rs:25:18 | LL | let (_, _) = str.rsplitn(3, '=').next_tuple().unwrap(); - | ^^^^^^^^^^^^^^^^^^^ help: try this: `str.rsplit('=')` + | ^^^^^^^^^^^^^^^^^^^ help: try: `str.rsplit('=')` error: unnecessary use of `splitn` --> $DIR/needless_splitn.rs:27:13 | LL | let _ = str.splitn(5, '=').next(); - | ^^^^^^^^^^^^^^^^^^ help: try this: `str.split('=')` + | ^^^^^^^^^^^^^^^^^^ help: try: `str.split('=')` error: unnecessary use of `splitn` --> $DIR/needless_splitn.rs:28:13 | LL | let _ = str.splitn(5, '=').nth(3); - | ^^^^^^^^^^^^^^^^^^ help: try this: `str.split('=')` + | ^^^^^^^^^^^^^^^^^^ help: try: `str.split('=')` error: unnecessary use of `splitn` --> $DIR/needless_splitn.rs:34:13 | LL | let _ = s.splitn(2, '=').next()?; - | ^^^^^^^^^^^^^^^^ help: try this: `s.split('=')` + | ^^^^^^^^^^^^^^^^ help: try: `s.split('=')` error: unnecessary use of `splitn` --> $DIR/needless_splitn.rs:35:13 | LL | let _ = s.splitn(2, '=').nth(0)?; - | ^^^^^^^^^^^^^^^^ help: try this: `s.split('=')` + | ^^^^^^^^^^^^^^^^ help: try: `s.split('=')` error: unnecessary use of `rsplitn` --> $DIR/needless_splitn.rs:36:13 | LL | let _ = s.rsplitn(2, '=').next()?; - | ^^^^^^^^^^^^^^^^^ help: try this: `s.rsplit('=')` + | ^^^^^^^^^^^^^^^^^ help: try: `s.rsplit('=')` error: unnecessary use of `rsplitn` --> $DIR/needless_splitn.rs:37:13 | LL | let _ = s.rsplitn(2, '=').nth(0)?; - | ^^^^^^^^^^^^^^^^^ help: try this: `s.rsplit('=')` + | ^^^^^^^^^^^^^^^^^ help: try: `s.rsplit('=')` error: unnecessary use of `splitn` --> $DIR/needless_splitn.rs:45:13 | LL | let _ = "key=value".splitn(2, '=').nth(0).unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"key=value".split('=')` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".split('=')` error: aborting due to 13 previous errors diff --git a/tests/ui/numbered_fields.stderr b/tests/ui/numbered_fields.stderr index 60c0d7898063..26f7ad9048b8 100644 --- a/tests/ui/numbered_fields.stderr +++ b/tests/ui/numbered_fields.stderr @@ -7,7 +7,7 @@ LL | | 0: 1u32, LL | | 1: 42, LL | | 2: 23u8, LL | | }; - | |_____^ help: try this instead: `TupleStruct(1u32, 42, 23u8)` + | |_____^ help: try: `TupleStruct(1u32, 42, 23u8)` | = note: `-D clippy::init-numbered-fields` implied by `-D warnings` @@ -20,7 +20,7 @@ LL | | 0: 1u32, LL | | 2: 2u8, LL | | 1: 3u32, LL | | }; - | |_____^ help: try this instead: `TupleStruct(1u32, 3u32, 2u8)` + | |_____^ help: try: `TupleStruct(1u32, 3u32, 2u8)` error: aborting due to 2 previous errors diff --git a/tests/ui/option_map_unit_fn_fixable.stderr b/tests/ui/option_map_unit_fn_fixable.stderr index 0305387b9f8a..5be5f10b0177 100644 --- a/tests/ui/option_map_unit_fn_fixable.stderr +++ b/tests/ui/option_map_unit_fn_fixable.stderr @@ -4,7 +4,7 @@ error: called `map(f)` on an `Option` value where `f` is a function that returns LL | x.field.map(do_nothing); | ^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(x_field) = x.field { do_nothing(x_field) }` + | help: try: `if let Some(x_field) = x.field { do_nothing(x_field) }` | = note: `-D clippy::option-map-unit-fn` implied by `-D warnings` @@ -14,7 +14,7 @@ error: called `map(f)` on an `Option` value where `f` is a function that returns LL | x.field.map(do_nothing); | ^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(x_field) = x.field { do_nothing(x_field) }` + | help: try: `if let Some(x_field) = x.field { do_nothing(x_field) }` error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:42:5 @@ -22,7 +22,7 @@ error: called `map(f)` on an `Option` value where `f` is a function that returns LL | x.field.map(diverge); | ^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(x_field) = x.field { diverge(x_field) }` + | help: try: `if let Some(x_field) = x.field { diverge(x_field) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:48:5 @@ -30,7 +30,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns LL | x.field.map(|value| x.do_option_nothing(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(value) = x.field { x.do_option_nothing(value + captured) }` + | help: try: `if let Some(value) = x.field { x.do_option_nothing(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:50:5 @@ -38,7 +38,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns LL | x.field.map(|value| { x.do_option_plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(value) = x.field { x.do_option_plus_one(value + captured); }` + | help: try: `if let Some(value) = x.field { x.do_option_plus_one(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:53:5 @@ -46,7 +46,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns LL | x.field.map(|value| do_nothing(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }` + | help: try: `if let Some(value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:55:5 @@ -54,7 +54,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns LL | x.field.map(|value| { do_nothing(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }` + | help: try: `if let Some(value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:57:5 @@ -62,7 +62,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns LL | x.field.map(|value| { do_nothing(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }` + | help: try: `if let Some(value) = x.field { do_nothing(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:59:5 @@ -70,7 +70,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns LL | x.field.map(|value| { { do_nothing(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }` + | help: try: `if let Some(value) = x.field { do_nothing(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:62:5 @@ -78,7 +78,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns LL | x.field.map(|value| diverge(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(value) = x.field { diverge(value + captured) }` + | help: try: `if let Some(value) = x.field { diverge(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:64:5 @@ -86,7 +86,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns LL | x.field.map(|value| { diverge(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(value) = x.field { diverge(value + captured) }` + | help: try: `if let Some(value) = x.field { diverge(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:66:5 @@ -94,7 +94,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns LL | x.field.map(|value| { diverge(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(value) = x.field { diverge(value + captured); }` + | help: try: `if let Some(value) = x.field { diverge(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:68:5 @@ -102,7 +102,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns LL | x.field.map(|value| { { diverge(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(value) = x.field { diverge(value + captured); }` + | help: try: `if let Some(value) = x.field { diverge(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:73:5 @@ -110,7 +110,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns LL | x.field.map(|value| { let y = plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(value) = x.field { let y = plus_one(value + captured); }` + | help: try: `if let Some(value) = x.field { let y = plus_one(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:75:5 @@ -118,7 +118,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns LL | x.field.map(|value| { plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(value) = x.field { plus_one(value + captured); }` + | help: try: `if let Some(value) = x.field { plus_one(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:77:5 @@ -126,7 +126,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns LL | x.field.map(|value| { { plus_one(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(value) = x.field { plus_one(value + captured); }` + | help: try: `if let Some(value) = x.field { plus_one(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:80:5 @@ -134,7 +134,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns LL | x.field.map(|ref value| { do_nothing(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(ref value) = x.field { do_nothing(value + captured) }` + | help: try: `if let Some(ref value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:82:5 @@ -142,7 +142,7 @@ error: called `map(f)` on an `Option` value where `f` is a function that returns LL | option().map(do_nothing); | ^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(a) = option() { do_nothing(a) }` + | help: try: `if let Some(a) = option() { do_nothing(a) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` --> $DIR/option_map_unit_fn_fixable.rs:84:5 @@ -150,7 +150,7 @@ error: called `map(f)` on an `Option` value where `f` is a closure that returns LL | option().map(|value| println!("{:?}", value)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Some(value) = option() { println!("{:?}", value) }` + | help: try: `if let Some(value) = option() { println!("{:?}", value) }` error: aborting due to 19 previous errors diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr index 0b5c686bec0d..3965ae52aed1 100644 --- a/tests/ui/or_fun_call.stderr +++ b/tests/ui/or_fun_call.stderr @@ -2,7 +2,7 @@ error: use of `unwrap_or` followed by a function call --> $DIR/or_fun_call.rs:54:22 | LL | with_constructor.unwrap_or(make()); - | ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(make)` + | ^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(make)` | = note: `-D clippy::or-fun-call` implied by `-D warnings` @@ -10,163 +10,163 @@ error: use of `unwrap_or` followed by a call to `new` --> $DIR/or_fun_call.rs:57:14 | LL | with_new.unwrap_or(Vec::new()); - | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or` followed by a function call --> $DIR/or_fun_call.rs:60:21 | LL | with_const_args.unwrap_or(Vec::with_capacity(12)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| Vec::with_capacity(12))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| Vec::with_capacity(12))` error: use of `unwrap_or` followed by a function call --> $DIR/or_fun_call.rs:63:14 | LL | with_err.unwrap_or(make()); - | ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| make())` + | ^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| make())` error: use of `unwrap_or` followed by a function call --> $DIR/or_fun_call.rs:66:19 | LL | with_err_args.unwrap_or(Vec::with_capacity(12)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| Vec::with_capacity(12))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| Vec::with_capacity(12))` error: use of `unwrap_or` followed by a call to `default` --> $DIR/or_fun_call.rs:69:24 | LL | with_default_trait.unwrap_or(Default::default()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or` followed by a call to `default` --> $DIR/or_fun_call.rs:72:23 | LL | with_default_type.unwrap_or(u64::default()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or` followed by a function call --> $DIR/or_fun_call.rs:75:18 | LL | self_default.unwrap_or(::default()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(::default)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(::default)` error: use of `unwrap_or` followed by a call to `default` --> $DIR/or_fun_call.rs:78:18 | LL | real_default.unwrap_or(::default()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or` followed by a call to `new` --> $DIR/or_fun_call.rs:81:14 | LL | with_vec.unwrap_or(vec![]); - | ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or` followed by a function call --> $DIR/or_fun_call.rs:84:21 | LL | without_default.unwrap_or(Foo::new()); - | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(Foo::new)` + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(Foo::new)` error: use of `or_insert` followed by a call to `new` --> $DIR/or_fun_call.rs:87:19 | LL | map.entry(42).or_insert(String::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()` error: use of `or_insert` followed by a call to `new` --> $DIR/or_fun_call.rs:90:23 | LL | map_vec.entry(42).or_insert(vec![]); - | ^^^^^^^^^^^^^^^^^ help: try this: `or_default()` + | ^^^^^^^^^^^^^^^^^ help: try: `or_default()` error: use of `or_insert` followed by a call to `new` --> $DIR/or_fun_call.rs:93:21 | LL | btree.entry(42).or_insert(String::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()` error: use of `or_insert` followed by a call to `new` --> $DIR/or_fun_call.rs:96:25 | LL | btree_vec.entry(42).or_insert(vec![]); - | ^^^^^^^^^^^^^^^^^ help: try this: `or_default()` + | ^^^^^^^^^^^^^^^^^ help: try: `or_default()` error: use of `unwrap_or` followed by a call to `new` --> $DIR/or_fun_call.rs:99:21 | LL | let _ = stringy.unwrap_or(String::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or` followed by a function call --> $DIR/or_fun_call.rs:107:21 | LL | let _ = Some(1).unwrap_or(map[&1]); - | ^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| map[&1])` + | ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| map[&1])` error: use of `unwrap_or` followed by a function call --> $DIR/or_fun_call.rs:109:21 | LL | let _ = Some(1).unwrap_or(map[&1]); - | ^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| map[&1])` + | ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| map[&1])` error: use of `or` followed by a function call --> $DIR/or_fun_call.rs:133:35 | LL | let _ = Some("a".to_string()).or(Some("b".to_string())); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some("b".to_string()))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_else(|| Some("b".to_string()))` error: use of `unwrap_or` followed by a function call --> $DIR/or_fun_call.rs:172:14 | LL | None.unwrap_or(ptr_to_ref(s)); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| ptr_to_ref(s))` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| ptr_to_ref(s))` error: use of `unwrap_or` followed by a function call --> $DIR/or_fun_call.rs:178:14 | LL | None.unwrap_or(unsafe { ptr_to_ref(s) }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })` error: use of `unwrap_or` followed by a function call --> $DIR/or_fun_call.rs:180:14 | LL | None.unwrap_or( unsafe { ptr_to_ref(s) } ); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })` error: use of `unwrap_or` followed by a call to `new` --> $DIR/or_fun_call.rs:194:14 | LL | .unwrap_or(String::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or` followed by a call to `new` --> $DIR/or_fun_call.rs:207:14 | LL | .unwrap_or(String::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or` followed by a call to `new` --> $DIR/or_fun_call.rs:219:14 | LL | .unwrap_or(String::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or` followed by a call to `new` --> $DIR/or_fun_call.rs:230:10 | LL | .unwrap_or(String::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `map_or` followed by a function call --> $DIR/or_fun_call.rs:255:25 | LL | let _ = Some(4).map_or(g(), |v| v); - | ^^^^^^^^^^^^^^^^^^ help: try this: `map_or_else(g, |v| v)` + | ^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(g, |v| v)` error: use of `map_or` followed by a function call --> $DIR/or_fun_call.rs:256:25 | LL | let _ = Some(4).map_or(g(), f); - | ^^^^^^^^^^^^^^ help: try this: `map_or_else(g, f)` + | ^^^^^^^^^^^^^^ help: try: `map_or_else(g, f)` error: aborting due to 28 previous errors diff --git a/tests/ui/or_then_unwrap.stderr b/tests/ui/or_then_unwrap.stderr index da88154c59f7..2a1a52407dc3 100644 --- a/tests/ui/or_then_unwrap.stderr +++ b/tests/ui/or_then_unwrap.stderr @@ -2,7 +2,7 @@ error: found `.or(Some(…)).unwrap()` --> $DIR/or_then_unwrap.rs:24:20 | LL | let _ = option.or(Some("fallback")).unwrap(); // should trigger lint - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or("fallback")` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or("fallback")` | = note: `-D clippy::or-then-unwrap` implied by `-D warnings` @@ -10,13 +10,13 @@ error: found `.or(Ok(…)).unwrap()` --> $DIR/or_then_unwrap.rs:27:20 | LL | let _ = result.or::<&str>(Ok("fallback")).unwrap(); // should trigger lint - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or("fallback")` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or("fallback")` error: found `.or(Some(…)).unwrap()` --> $DIR/or_then_unwrap.rs:31:31 | LL | let _ = option.map(|v| v).or(Some("fallback")).unwrap().to_string().chars(); // should trigger lint - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or("fallback")` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or("fallback")` error: aborting due to 3 previous errors diff --git a/tests/ui/print_literal.stderr b/tests/ui/print_literal.stderr index 6404dacdafa5..71c8d188f167 100644 --- a/tests/ui/print_literal.stderr +++ b/tests/ui/print_literal.stderr @@ -5,7 +5,7 @@ LL | print!("Hello {}", "world"); | ^^^^^^^ | = note: `-D clippy::print-literal` implied by `-D warnings` -help: try this +help: try | LL - print!("Hello {}", "world"); LL + print!("Hello world"); @@ -17,7 +17,7 @@ error: literal with an empty format string LL | println!("Hello {} {}", world, "world"); | ^^^^^^^ | -help: try this +help: try | LL - println!("Hello {} {}", world, "world"); LL + println!("Hello {} world", world); @@ -29,7 +29,7 @@ error: literal with an empty format string LL | println!("Hello {}", "world"); | ^^^^^^^ | -help: try this +help: try | LL - println!("Hello {}", "world"); LL + println!("Hello world"); @@ -41,7 +41,7 @@ error: literal with an empty format string LL | println!("{} {:.4}", "a literal", 5); | ^^^^^^^^^^^ | -help: try this +help: try | LL - println!("{} {:.4}", "a literal", 5); LL + println!("a literal {:.4}", 5); @@ -53,7 +53,7 @@ error: literal with an empty format string LL | println!("{0} {1}", "hello", "world"); | ^^^^^^^ | -help: try this +help: try | LL - println!("{0} {1}", "hello", "world"); LL + println!("hello {1}", "world"); @@ -65,7 +65,7 @@ error: literal with an empty format string LL | println!("{0} {1}", "hello", "world"); | ^^^^^^^ | -help: try this +help: try | LL - println!("{0} {1}", "hello", "world"); LL + println!("{0} world", "hello"); @@ -77,7 +77,7 @@ error: literal with an empty format string LL | println!("{1} {0}", "hello", "world"); | ^^^^^^^ | -help: try this +help: try | LL - println!("{1} {0}", "hello", "world"); LL + println!("world {0}", "hello"); @@ -89,7 +89,7 @@ error: literal with an empty format string LL | println!("{1} {0}", "hello", "world"); | ^^^^^^^ | -help: try this +help: try | LL - println!("{1} {0}", "hello", "world"); LL + println!("{1} hello", "world"); @@ -101,7 +101,7 @@ error: literal with an empty format string LL | println!("{foo} {bar}", foo = "hello", bar = "world"); | ^^^^^^^ | -help: try this +help: try | LL - println!("{foo} {bar}", foo = "hello", bar = "world"); LL + println!("hello {bar}", bar = "world"); @@ -113,7 +113,7 @@ error: literal with an empty format string LL | println!("{foo} {bar}", foo = "hello", bar = "world"); | ^^^^^^^ | -help: try this +help: try | LL - println!("{foo} {bar}", foo = "hello", bar = "world"); LL + println!("{foo} world", foo = "hello"); @@ -125,7 +125,7 @@ error: literal with an empty format string LL | println!("{bar} {foo}", foo = "hello", bar = "world"); | ^^^^^^^ | -help: try this +help: try | LL - println!("{bar} {foo}", foo = "hello", bar = "world"); LL + println!("world {foo}", foo = "hello"); @@ -137,7 +137,7 @@ error: literal with an empty format string LL | println!("{bar} {foo}", foo = "hello", bar = "world"); | ^^^^^^^ | -help: try this +help: try | LL - println!("{bar} {foo}", foo = "hello", bar = "world"); LL + println!("{bar} hello", bar = "world"); diff --git a/tests/ui/redundant_pattern_matching_drop_order.stderr b/tests/ui/redundant_pattern_matching_drop_order.stderr index e9ea3f2e6886..28f33f0c95d7 100644 --- a/tests/ui/redundant_pattern_matching_drop_order.stderr +++ b/tests/ui/redundant_pattern_matching_drop_order.stderr @@ -2,7 +2,7 @@ error: redundant pattern matching, consider using `is_ok()` --> $DIR/redundant_pattern_matching_drop_order.rs:17:12 | LL | if let Ok(_) = m.lock() {} - | -------^^^^^----------- help: try this: `if m.lock().is_ok()` + | -------^^^^^----------- help: try: `if m.lock().is_ok()` | = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important @@ -12,7 +12,7 @@ error: redundant pattern matching, consider using `is_err()` --> $DIR/redundant_pattern_matching_drop_order.rs:18:12 | LL | if let Err(_) = Err::<(), _>(m.lock().unwrap().0) {} - | -------^^^^^^------------------------------------ help: try this: `if Err::<(), _>(m.lock().unwrap().0).is_err()` + | -------^^^^^^------------------------------------ help: try: `if Err::<(), _>(m.lock().unwrap().0).is_err()` | = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important @@ -21,7 +21,7 @@ error: redundant pattern matching, consider using `is_ok()` --> $DIR/redundant_pattern_matching_drop_order.rs:21:16 | LL | if let Ok(_) = Ok::<_, std::sync::MutexGuard<()>>(()) {} - | -------^^^^^----------------------------------------- help: try this: `if Ok::<_, std::sync::MutexGuard<()>>(()).is_ok()` + | -------^^^^^----------------------------------------- help: try: `if Ok::<_, std::sync::MutexGuard<()>>(()).is_ok()` | = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important @@ -30,7 +30,7 @@ error: redundant pattern matching, consider using `is_ok()` --> $DIR/redundant_pattern_matching_drop_order.rs:23:12 | LL | if let Ok(_) = Ok::<_, std::sync::MutexGuard<()>>(()) { - | -------^^^^^----------------------------------------- help: try this: `if Ok::<_, std::sync::MutexGuard<()>>(()).is_ok()` + | -------^^^^^----------------------------------------- help: try: `if Ok::<_, std::sync::MutexGuard<()>>(()).is_ok()` | = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important @@ -39,31 +39,31 @@ error: redundant pattern matching, consider using `is_ok()` --> $DIR/redundant_pattern_matching_drop_order.rs:26:12 | LL | if let Ok(_) = Ok::<_, std::sync::MutexGuard<()>>(()) {} - | -------^^^^^----------------------------------------- help: try this: `if Ok::<_, std::sync::MutexGuard<()>>(()).is_ok()` + | -------^^^^^----------------------------------------- help: try: `if Ok::<_, std::sync::MutexGuard<()>>(()).is_ok()` error: redundant pattern matching, consider using `is_err()` --> $DIR/redundant_pattern_matching_drop_order.rs:27:12 | LL | if let Err(_) = Err::, _>(()) {} - | -------^^^^^^------------------------------------------ help: try this: `if Err::, _>(()).is_err()` + | -------^^^^^^------------------------------------------ help: try: `if Err::, _>(()).is_err()` error: redundant pattern matching, consider using `is_ok()` --> $DIR/redundant_pattern_matching_drop_order.rs:29:12 | LL | if let Ok(_) = Ok::<_, ()>(String::new()) {} - | -------^^^^^----------------------------- help: try this: `if Ok::<_, ()>(String::new()).is_ok()` + | -------^^^^^----------------------------- help: try: `if Ok::<_, ()>(String::new()).is_ok()` error: redundant pattern matching, consider using `is_err()` --> $DIR/redundant_pattern_matching_drop_order.rs:30:12 | LL | if let Err(_) = Err::<(), _>((String::new(), ())) {} - | -------^^^^^^------------------------------------ help: try this: `if Err::<(), _>((String::new(), ())).is_err()` + | -------^^^^^^------------------------------------ help: try: `if Err::<(), _>((String::new(), ())).is_err()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_drop_order.rs:33:12 | LL | if let Some(_) = Some(m.lock()) {} - | -------^^^^^^^----------------- help: try this: `if Some(m.lock()).is_some()` + | -------^^^^^^^----------------- help: try: `if Some(m.lock()).is_some()` | = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important @@ -72,7 +72,7 @@ error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_drop_order.rs:34:12 | LL | if let Some(_) = Some(m.lock().unwrap().0) {} - | -------^^^^^^^---------------------------- help: try this: `if Some(m.lock().unwrap().0).is_some()` + | -------^^^^^^^---------------------------- help: try: `if Some(m.lock().unwrap().0).is_some()` | = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important @@ -81,7 +81,7 @@ error: redundant pattern matching, consider using `is_none()` --> $DIR/redundant_pattern_matching_drop_order.rs:37:16 | LL | if let None = None::> {} - | -------^^^^------------------------------------ help: try this: `if None::>.is_none()` + | -------^^^^------------------------------------ help: try: `if None::>.is_none()` | = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important @@ -90,7 +90,7 @@ error: redundant pattern matching, consider using `is_none()` --> $DIR/redundant_pattern_matching_drop_order.rs:39:12 | LL | if let None = None::> { - | -------^^^^------------------------------------ help: try this: `if None::>.is_none()` + | -------^^^^------------------------------------ help: try: `if None::>.is_none()` | = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important @@ -99,25 +99,25 @@ error: redundant pattern matching, consider using `is_none()` --> $DIR/redundant_pattern_matching_drop_order.rs:43:12 | LL | if let None = None::> {} - | -------^^^^------------------------------------ help: try this: `if None::>.is_none()` + | -------^^^^------------------------------------ help: try: `if None::>.is_none()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_drop_order.rs:45:12 | LL | if let Some(_) = Some(String::new()) {} - | -------^^^^^^^---------------------- help: try this: `if Some(String::new()).is_some()` + | -------^^^^^^^---------------------- help: try: `if Some(String::new()).is_some()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_drop_order.rs:46:12 | LL | if let Some(_) = Some((String::new(), ())) {} - | -------^^^^^^^---------------------------- help: try this: `if Some((String::new(), ())).is_some()` + | -------^^^^^^^---------------------------- help: try: `if Some((String::new(), ())).is_some()` error: redundant pattern matching, consider using `is_ready()` --> $DIR/redundant_pattern_matching_drop_order.rs:49:12 | LL | if let Ready(_) = Ready(m.lock()) {} - | -------^^^^^^^^------------------ help: try this: `if Ready(m.lock()).is_ready()` + | -------^^^^^^^^------------------ help: try: `if Ready(m.lock()).is_ready()` | = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important @@ -126,7 +126,7 @@ error: redundant pattern matching, consider using `is_ready()` --> $DIR/redundant_pattern_matching_drop_order.rs:50:12 | LL | if let Ready(_) = Ready(m.lock().unwrap().0) {} - | -------^^^^^^^^----------------------------- help: try this: `if Ready(m.lock().unwrap().0).is_ready()` + | -------^^^^^^^^----------------------------- help: try: `if Ready(m.lock().unwrap().0).is_ready()` | = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important @@ -135,7 +135,7 @@ error: redundant pattern matching, consider using `is_pending()` --> $DIR/redundant_pattern_matching_drop_order.rs:53:16 | LL | if let Pending = Pending::> {} - | -------^^^^^^^--------------------------------------- help: try this: `if Pending::>.is_pending()` + | -------^^^^^^^--------------------------------------- help: try: `if Pending::>.is_pending()` | = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important @@ -144,7 +144,7 @@ error: redundant pattern matching, consider using `is_pending()` --> $DIR/redundant_pattern_matching_drop_order.rs:55:12 | LL | if let Pending = Pending::> { - | -------^^^^^^^--------------------------------------- help: try this: `if Pending::>.is_pending()` + | -------^^^^^^^--------------------------------------- help: try: `if Pending::>.is_pending()` | = note: this will change drop order of the result, as well as all temporaries = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important @@ -153,19 +153,19 @@ error: redundant pattern matching, consider using `is_pending()` --> $DIR/redundant_pattern_matching_drop_order.rs:59:12 | LL | if let Pending = Pending::> {} - | -------^^^^^^^--------------------------------------- help: try this: `if Pending::>.is_pending()` + | -------^^^^^^^--------------------------------------- help: try: `if Pending::>.is_pending()` error: redundant pattern matching, consider using `is_ready()` --> $DIR/redundant_pattern_matching_drop_order.rs:61:12 | LL | if let Ready(_) = Ready(String::new()) {} - | -------^^^^^^^^----------------------- help: try this: `if Ready(String::new()).is_ready()` + | -------^^^^^^^^----------------------- help: try: `if Ready(String::new()).is_ready()` error: redundant pattern matching, consider using `is_ready()` --> $DIR/redundant_pattern_matching_drop_order.rs:62:12 | LL | if let Ready(_) = Ready((String::new(), ())) {} - | -------^^^^^^^^----------------------------- help: try this: `if Ready((String::new(), ())).is_ready()` + | -------^^^^^^^^----------------------------- help: try: `if Ready((String::new(), ())).is_ready()` error: aborting due to 22 previous errors diff --git a/tests/ui/redundant_pattern_matching_ipaddr.stderr b/tests/ui/redundant_pattern_matching_ipaddr.stderr index 6d1fb2964632..f34dc7098330 100644 --- a/tests/ui/redundant_pattern_matching_ipaddr.stderr +++ b/tests/ui/redundant_pattern_matching_ipaddr.stderr @@ -2,7 +2,7 @@ error: redundant pattern matching, consider using `is_ipv4()` --> $DIR/redundant_pattern_matching_ipaddr.rs:18:12 | LL | if let V4(_) = &ipaddr {} - | -------^^^^^---------- help: try this: `if ipaddr.is_ipv4()` + | -------^^^^^---------- help: try: `if ipaddr.is_ipv4()` | = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` @@ -10,25 +10,25 @@ error: redundant pattern matching, consider using `is_ipv4()` --> $DIR/redundant_pattern_matching_ipaddr.rs:20:12 | LL | if let V4(_) = V4(Ipv4Addr::LOCALHOST) {} - | -------^^^^^-------------------------- help: try this: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()` + | -------^^^^^-------------------------- help: try: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` --> $DIR/redundant_pattern_matching_ipaddr.rs:22:12 | LL | if let V6(_) = V6(Ipv6Addr::LOCALHOST) {} - | -------^^^^^-------------------------- help: try this: `if V6(Ipv6Addr::LOCALHOST).is_ipv6()` + | -------^^^^^-------------------------- help: try: `if V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` --> $DIR/redundant_pattern_matching_ipaddr.rs:24:15 | LL | while let V4(_) = V4(Ipv4Addr::LOCALHOST) {} - | ----------^^^^^-------------------------- help: try this: `while V4(Ipv4Addr::LOCALHOST).is_ipv4()` + | ----------^^^^^-------------------------- help: try: `while V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` --> $DIR/redundant_pattern_matching_ipaddr.rs:26:15 | LL | while let V6(_) = V6(Ipv6Addr::LOCALHOST) {} - | ----------^^^^^-------------------------- help: try this: `while V6(Ipv6Addr::LOCALHOST).is_ipv6()` + | ----------^^^^^-------------------------- help: try: `while V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` --> $DIR/redundant_pattern_matching_ipaddr.rs:36:5 @@ -37,7 +37,7 @@ LL | / match V4(Ipv4Addr::LOCALHOST) { LL | | V4(_) => true, LL | | V6(_) => false, LL | | }; - | |_____^ help: try this: `V4(Ipv4Addr::LOCALHOST).is_ipv4()` + | |_____^ help: try: `V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` --> $DIR/redundant_pattern_matching_ipaddr.rs:41:5 @@ -46,7 +46,7 @@ LL | / match V4(Ipv4Addr::LOCALHOST) { LL | | V4(_) => false, LL | | V6(_) => true, LL | | }; - | |_____^ help: try this: `V4(Ipv4Addr::LOCALHOST).is_ipv6()` + | |_____^ help: try: `V4(Ipv4Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv6()` --> $DIR/redundant_pattern_matching_ipaddr.rs:46:5 @@ -55,7 +55,7 @@ LL | / match V6(Ipv6Addr::LOCALHOST) { LL | | V4(_) => false, LL | | V6(_) => true, LL | | }; - | |_____^ help: try this: `V6(Ipv6Addr::LOCALHOST).is_ipv6()` + | |_____^ help: try: `V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` --> $DIR/redundant_pattern_matching_ipaddr.rs:51:5 @@ -64,49 +64,49 @@ LL | / match V6(Ipv6Addr::LOCALHOST) { LL | | V4(_) => true, LL | | V6(_) => false, LL | | }; - | |_____^ help: try this: `V6(Ipv6Addr::LOCALHOST).is_ipv4()` + | |_____^ help: try: `V6(Ipv6Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv4()` --> $DIR/redundant_pattern_matching_ipaddr.rs:56:20 | LL | let _ = if let V4(_) = V4(Ipv4Addr::LOCALHOST) { - | -------^^^^^-------------------------- help: try this: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()` + | -------^^^^^-------------------------- help: try: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv4()` --> $DIR/redundant_pattern_matching_ipaddr.rs:64:20 | LL | let _ = if let V4(_) = gen_ipaddr() { - | -------^^^^^--------------- help: try this: `if gen_ipaddr().is_ipv4()` + | -------^^^^^--------------- help: try: `if gen_ipaddr().is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` --> $DIR/redundant_pattern_matching_ipaddr.rs:66:19 | LL | } else if let V6(_) = gen_ipaddr() { - | -------^^^^^--------------- help: try this: `if gen_ipaddr().is_ipv6()` + | -------^^^^^--------------- help: try: `if gen_ipaddr().is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` --> $DIR/redundant_pattern_matching_ipaddr.rs:78:12 | LL | if let V4(_) = V4(Ipv4Addr::LOCALHOST) {} - | -------^^^^^-------------------------- help: try this: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()` + | -------^^^^^-------------------------- help: try: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` --> $DIR/redundant_pattern_matching_ipaddr.rs:80:12 | LL | if let V6(_) = V6(Ipv6Addr::LOCALHOST) {} - | -------^^^^^-------------------------- help: try this: `if V6(Ipv6Addr::LOCALHOST).is_ipv6()` + | -------^^^^^-------------------------- help: try: `if V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` --> $DIR/redundant_pattern_matching_ipaddr.rs:82:15 | LL | while let V4(_) = V4(Ipv4Addr::LOCALHOST) {} - | ----------^^^^^-------------------------- help: try this: `while V4(Ipv4Addr::LOCALHOST).is_ipv4()` + | ----------^^^^^-------------------------- help: try: `while V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` --> $DIR/redundant_pattern_matching_ipaddr.rs:84:15 | LL | while let V6(_) = V6(Ipv6Addr::LOCALHOST) {} - | ----------^^^^^-------------------------- help: try this: `while V6(Ipv6Addr::LOCALHOST).is_ipv6()` + | ----------^^^^^-------------------------- help: try: `while V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` --> $DIR/redundant_pattern_matching_ipaddr.rs:86:5 @@ -115,7 +115,7 @@ LL | / match V4(Ipv4Addr::LOCALHOST) { LL | | V4(_) => true, LL | | V6(_) => false, LL | | }; - | |_____^ help: try this: `V4(Ipv4Addr::LOCALHOST).is_ipv4()` + | |_____^ help: try: `V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` --> $DIR/redundant_pattern_matching_ipaddr.rs:91:5 @@ -124,7 +124,7 @@ LL | / match V6(Ipv6Addr::LOCALHOST) { LL | | V4(_) => false, LL | | V6(_) => true, LL | | }; - | |_____^ help: try this: `V6(Ipv6Addr::LOCALHOST).is_ipv6()` + | |_____^ help: try: `V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: aborting due to 18 previous errors diff --git a/tests/ui/redundant_pattern_matching_option.stderr b/tests/ui/redundant_pattern_matching_option.stderr index 717b603c496e..097ca827a426 100644 --- a/tests/ui/redundant_pattern_matching_option.stderr +++ b/tests/ui/redundant_pattern_matching_option.stderr @@ -2,7 +2,7 @@ error: redundant pattern matching, consider using `is_none()` --> $DIR/redundant_pattern_matching_option.rs:15:12 | LL | if let None = None::<()> {} - | -------^^^^------------- help: try this: `if None::<()>.is_none()` + | -------^^^^------------- help: try: `if None::<()>.is_none()` | = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` @@ -10,37 +10,37 @@ error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_option.rs:17:12 | LL | if let Some(_) = Some(42) {} - | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` + | -------^^^^^^^----------- help: try: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_option.rs:19:12 | LL | if let Some(_) = Some(42) { - | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` + | -------^^^^^^^----------- help: try: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_option.rs:25:15 | LL | while let Some(_) = Some(42) {} - | ----------^^^^^^^----------- help: try this: `while Some(42).is_some()` + | ----------^^^^^^^----------- help: try: `while Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` --> $DIR/redundant_pattern_matching_option.rs:27:15 | LL | while let None = Some(42) {} - | ----------^^^^----------- help: try this: `while Some(42).is_none()` + | ----------^^^^----------- help: try: `while Some(42).is_none()` error: redundant pattern matching, consider using `is_none()` --> $DIR/redundant_pattern_matching_option.rs:29:15 | LL | while let None = None::<()> {} - | ----------^^^^------------- help: try this: `while None::<()>.is_none()` + | ----------^^^^------------- help: try: `while None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_option.rs:32:15 | LL | while let Some(_) = v.pop() { - | ----------^^^^^^^---------- help: try this: `while v.pop().is_some()` + | ----------^^^^^^^---------- help: try: `while v.pop().is_some()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_option.rs:40:5 @@ -49,7 +49,7 @@ LL | / match Some(42) { LL | | Some(_) => true, LL | | None => false, LL | | }; - | |_____^ help: try this: `Some(42).is_some()` + | |_____^ help: try: `Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` --> $DIR/redundant_pattern_matching_option.rs:45:5 @@ -58,7 +58,7 @@ LL | / match None::<()> { LL | | Some(_) => false, LL | | None => true, LL | | }; - | |_____^ help: try this: `None::<()>.is_none()` + | |_____^ help: try: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_none()` --> $DIR/redundant_pattern_matching_option.rs:50:13 @@ -68,55 +68,55 @@ LL | let _ = match None::<()> { LL | | Some(_) => false, LL | | None => true, LL | | }; - | |_____^ help: try this: `None::<()>.is_none()` + | |_____^ help: try: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_option.rs:56:20 | LL | let _ = if let Some(_) = opt { true } else { false }; - | -------^^^^^^^------ help: try this: `if opt.is_some()` + | -------^^^^^^^------ help: try: `if opt.is_some()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_option.rs:62:20 | LL | let _ = if let Some(_) = gen_opt() { - | -------^^^^^^^------------ help: try this: `if gen_opt().is_some()` + | -------^^^^^^^------------ help: try: `if gen_opt().is_some()` error: redundant pattern matching, consider using `is_none()` --> $DIR/redundant_pattern_matching_option.rs:64:19 | LL | } else if let None = gen_opt() { - | -------^^^^------------ help: try this: `if gen_opt().is_none()` + | -------^^^^------------ help: try: `if gen_opt().is_none()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_option.rs:70:12 | LL | if let Some(..) = gen_opt() {} - | -------^^^^^^^^------------ help: try this: `if gen_opt().is_some()` + | -------^^^^^^^^------------ help: try: `if gen_opt().is_some()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_option.rs:85:12 | LL | if let Some(_) = Some(42) {} - | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` + | -------^^^^^^^----------- help: try: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` --> $DIR/redundant_pattern_matching_option.rs:87:12 | LL | if let None = None::<()> {} - | -------^^^^------------- help: try this: `if None::<()>.is_none()` + | -------^^^^------------- help: try: `if None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_option.rs:89:15 | LL | while let Some(_) = Some(42) {} - | ----------^^^^^^^----------- help: try this: `while Some(42).is_some()` + | ----------^^^^^^^----------- help: try: `while Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` --> $DIR/redundant_pattern_matching_option.rs:91:15 | LL | while let None = None::<()> {} - | ----------^^^^------------- help: try this: `while None::<()>.is_none()` + | ----------^^^^------------- help: try: `while None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_option.rs:93:5 @@ -125,7 +125,7 @@ LL | / match Some(42) { LL | | Some(_) => true, LL | | None => false, LL | | }; - | |_____^ help: try this: `Some(42).is_some()` + | |_____^ help: try: `Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` --> $DIR/redundant_pattern_matching_option.rs:98:5 @@ -134,19 +134,19 @@ LL | / match None::<()> { LL | | Some(_) => false, LL | | None => true, LL | | }; - | |_____^ help: try this: `None::<()>.is_none()` + | |_____^ help: try: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_none()` --> $DIR/redundant_pattern_matching_option.rs:106:12 | LL | if let None = *(&None::<()>) {} - | -------^^^^----------------- help: try this: `if (&None::<()>).is_none()` + | -------^^^^----------------- help: try: `if (&None::<()>).is_none()` error: redundant pattern matching, consider using `is_none()` --> $DIR/redundant_pattern_matching_option.rs:107:12 | LL | if let None = *&None::<()> {} - | -------^^^^--------------- help: try this: `if (&None::<()>).is_none()` + | -------^^^^--------------- help: try: `if (&None::<()>).is_none()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_option.rs:113:5 @@ -155,7 +155,7 @@ LL | / match x { LL | | Some(_) => true, LL | | _ => false, LL | | }; - | |_____^ help: try this: `x.is_some()` + | |_____^ help: try: `x.is_some()` error: redundant pattern matching, consider using `is_none()` --> $DIR/redundant_pattern_matching_option.rs:118:5 @@ -164,7 +164,7 @@ LL | / match x { LL | | None => true, LL | | _ => false, LL | | }; - | |_____^ help: try this: `x.is_none()` + | |_____^ help: try: `x.is_none()` error: redundant pattern matching, consider using `is_none()` --> $DIR/redundant_pattern_matching_option.rs:123:5 @@ -173,7 +173,7 @@ LL | / match x { LL | | Some(_) => false, LL | | _ => true, LL | | }; - | |_____^ help: try this: `x.is_none()` + | |_____^ help: try: `x.is_none()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_option.rs:128:5 @@ -182,19 +182,19 @@ LL | / match x { LL | | None => false, LL | | _ => true, LL | | }; - | |_____^ help: try this: `x.is_some()` + | |_____^ help: try: `x.is_some()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_option.rs:143:13 | LL | let _ = matches!(x, Some(_)); - | ^^^^^^^^^^^^^^^^^^^^ help: try this: `x.is_some()` + | ^^^^^^^^^^^^^^^^^^^^ help: try: `x.is_some()` error: redundant pattern matching, consider using `is_none()` --> $DIR/redundant_pattern_matching_option.rs:145:13 | LL | let _ = matches!(x, None); - | ^^^^^^^^^^^^^^^^^ help: try this: `x.is_none()` + | ^^^^^^^^^^^^^^^^^ help: try: `x.is_none()` error: aborting due to 28 previous errors diff --git a/tests/ui/redundant_pattern_matching_poll.stderr b/tests/ui/redundant_pattern_matching_poll.stderr index b89fde35fcfa..28d3606c4fb6 100644 --- a/tests/ui/redundant_pattern_matching_poll.stderr +++ b/tests/ui/redundant_pattern_matching_poll.stderr @@ -2,7 +2,7 @@ error: redundant pattern matching, consider using `is_pending()` --> $DIR/redundant_pattern_matching_poll.rs:17:12 | LL | if let Pending = Pending::<()> {} - | -------^^^^^^^---------------- help: try this: `if Pending::<()>.is_pending()` + | -------^^^^^^^---------------- help: try: `if Pending::<()>.is_pending()` | = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` @@ -10,31 +10,31 @@ error: redundant pattern matching, consider using `is_ready()` --> $DIR/redundant_pattern_matching_poll.rs:19:12 | LL | if let Ready(_) = Ready(42) {} - | -------^^^^^^^^------------ help: try this: `if Ready(42).is_ready()` + | -------^^^^^^^^------------ help: try: `if Ready(42).is_ready()` error: redundant pattern matching, consider using `is_ready()` --> $DIR/redundant_pattern_matching_poll.rs:21:12 | LL | if let Ready(_) = Ready(42) { - | -------^^^^^^^^------------ help: try this: `if Ready(42).is_ready()` + | -------^^^^^^^^------------ help: try: `if Ready(42).is_ready()` error: redundant pattern matching, consider using `is_ready()` --> $DIR/redundant_pattern_matching_poll.rs:27:15 | LL | while let Ready(_) = Ready(42) {} - | ----------^^^^^^^^------------ help: try this: `while Ready(42).is_ready()` + | ----------^^^^^^^^------------ help: try: `while Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` --> $DIR/redundant_pattern_matching_poll.rs:29:15 | LL | while let Pending = Ready(42) {} - | ----------^^^^^^^------------ help: try this: `while Ready(42).is_pending()` + | ----------^^^^^^^------------ help: try: `while Ready(42).is_pending()` error: redundant pattern matching, consider using `is_pending()` --> $DIR/redundant_pattern_matching_poll.rs:31:15 | LL | while let Pending = Pending::<()> {} - | ----------^^^^^^^---------------- help: try this: `while Pending::<()>.is_pending()` + | ----------^^^^^^^---------------- help: try: `while Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_ready()` --> $DIR/redundant_pattern_matching_poll.rs:37:5 @@ -43,7 +43,7 @@ LL | / match Ready(42) { LL | | Ready(_) => true, LL | | Pending => false, LL | | }; - | |_____^ help: try this: `Ready(42).is_ready()` + | |_____^ help: try: `Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` --> $DIR/redundant_pattern_matching_poll.rs:42:5 @@ -52,7 +52,7 @@ LL | / match Pending::<()> { LL | | Ready(_) => false, LL | | Pending => true, LL | | }; - | |_____^ help: try this: `Pending::<()>.is_pending()` + | |_____^ help: try: `Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_pending()` --> $DIR/redundant_pattern_matching_poll.rs:47:13 @@ -62,49 +62,49 @@ LL | let _ = match Pending::<()> { LL | | Ready(_) => false, LL | | Pending => true, LL | | }; - | |_____^ help: try this: `Pending::<()>.is_pending()` + | |_____^ help: try: `Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_ready()` --> $DIR/redundant_pattern_matching_poll.rs:53:20 | LL | let _ = if let Ready(_) = poll { true } else { false }; - | -------^^^^^^^^------- help: try this: `if poll.is_ready()` + | -------^^^^^^^^------- help: try: `if poll.is_ready()` error: redundant pattern matching, consider using `is_ready()` --> $DIR/redundant_pattern_matching_poll.rs:57:20 | LL | let _ = if let Ready(_) = gen_poll() { - | -------^^^^^^^^------------- help: try this: `if gen_poll().is_ready()` + | -------^^^^^^^^------------- help: try: `if gen_poll().is_ready()` error: redundant pattern matching, consider using `is_pending()` --> $DIR/redundant_pattern_matching_poll.rs:59:19 | LL | } else if let Pending = gen_poll() { - | -------^^^^^^^------------- help: try this: `if gen_poll().is_pending()` + | -------^^^^^^^------------- help: try: `if gen_poll().is_pending()` error: redundant pattern matching, consider using `is_ready()` --> $DIR/redundant_pattern_matching_poll.rs:75:12 | LL | if let Ready(_) = Ready(42) {} - | -------^^^^^^^^------------ help: try this: `if Ready(42).is_ready()` + | -------^^^^^^^^------------ help: try: `if Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` --> $DIR/redundant_pattern_matching_poll.rs:77:12 | LL | if let Pending = Pending::<()> {} - | -------^^^^^^^---------------- help: try this: `if Pending::<()>.is_pending()` + | -------^^^^^^^---------------- help: try: `if Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_ready()` --> $DIR/redundant_pattern_matching_poll.rs:79:15 | LL | while let Ready(_) = Ready(42) {} - | ----------^^^^^^^^------------ help: try this: `while Ready(42).is_ready()` + | ----------^^^^^^^^------------ help: try: `while Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` --> $DIR/redundant_pattern_matching_poll.rs:81:15 | LL | while let Pending = Pending::<()> {} - | ----------^^^^^^^---------------- help: try this: `while Pending::<()>.is_pending()` + | ----------^^^^^^^---------------- help: try: `while Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_ready()` --> $DIR/redundant_pattern_matching_poll.rs:83:5 @@ -113,7 +113,7 @@ LL | / match Ready(42) { LL | | Ready(_) => true, LL | | Pending => false, LL | | }; - | |_____^ help: try this: `Ready(42).is_ready()` + | |_____^ help: try: `Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` --> $DIR/redundant_pattern_matching_poll.rs:88:5 @@ -122,7 +122,7 @@ LL | / match Pending::<()> { LL | | Ready(_) => false, LL | | Pending => true, LL | | }; - | |_____^ help: try this: `Pending::<()>.is_pending()` + | |_____^ help: try: `Pending::<()>.is_pending()` error: aborting due to 18 previous errors diff --git a/tests/ui/redundant_pattern_matching_result.stderr b/tests/ui/redundant_pattern_matching_result.stderr index f6ce666bb4ff..2b1ce9f54652 100644 --- a/tests/ui/redundant_pattern_matching_result.stderr +++ b/tests/ui/redundant_pattern_matching_result.stderr @@ -2,7 +2,7 @@ error: redundant pattern matching, consider using `is_ok()` --> $DIR/redundant_pattern_matching_result.rs:16:12 | LL | if let Ok(_) = &result {} - | -------^^^^^---------- help: try this: `if result.is_ok()` + | -------^^^^^---------- help: try: `if result.is_ok()` | = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` @@ -10,25 +10,25 @@ error: redundant pattern matching, consider using `is_ok()` --> $DIR/redundant_pattern_matching_result.rs:18:12 | LL | if let Ok(_) = Ok::(42) {} - | -------^^^^^--------------------- help: try this: `if Ok::(42).is_ok()` + | -------^^^^^--------------------- help: try: `if Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` --> $DIR/redundant_pattern_matching_result.rs:20:12 | LL | if let Err(_) = Err::(42) {} - | -------^^^^^^---------------------- help: try this: `if Err::(42).is_err()` + | -------^^^^^^---------------------- help: try: `if Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` --> $DIR/redundant_pattern_matching_result.rs:22:15 | LL | while let Ok(_) = Ok::(10) {} - | ----------^^^^^--------------------- help: try this: `while Ok::(10).is_ok()` + | ----------^^^^^--------------------- help: try: `while Ok::(10).is_ok()` error: redundant pattern matching, consider using `is_err()` --> $DIR/redundant_pattern_matching_result.rs:24:15 | LL | while let Err(_) = Ok::(10) {} - | ----------^^^^^^--------------------- help: try this: `while Ok::(10).is_err()` + | ----------^^^^^^--------------------- help: try: `while Ok::(10).is_err()` error: redundant pattern matching, consider using `is_ok()` --> $DIR/redundant_pattern_matching_result.rs:34:5 @@ -37,7 +37,7 @@ LL | / match Ok::(42) { LL | | Ok(_) => true, LL | | Err(_) => false, LL | | }; - | |_____^ help: try this: `Ok::(42).is_ok()` + | |_____^ help: try: `Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` --> $DIR/redundant_pattern_matching_result.rs:39:5 @@ -46,7 +46,7 @@ LL | / match Ok::(42) { LL | | Ok(_) => false, LL | | Err(_) => true, LL | | }; - | |_____^ help: try this: `Ok::(42).is_err()` + | |_____^ help: try: `Ok::(42).is_err()` error: redundant pattern matching, consider using `is_err()` --> $DIR/redundant_pattern_matching_result.rs:44:5 @@ -55,7 +55,7 @@ LL | / match Err::(42) { LL | | Ok(_) => false, LL | | Err(_) => true, LL | | }; - | |_____^ help: try this: `Err::(42).is_err()` + | |_____^ help: try: `Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` --> $DIR/redundant_pattern_matching_result.rs:49:5 @@ -64,73 +64,73 @@ LL | / match Err::(42) { LL | | Ok(_) => true, LL | | Err(_) => false, LL | | }; - | |_____^ help: try this: `Err::(42).is_ok()` + | |_____^ help: try: `Err::(42).is_ok()` error: redundant pattern matching, consider using `is_ok()` --> $DIR/redundant_pattern_matching_result.rs:54:20 | LL | let _ = if let Ok(_) = Ok::(4) { true } else { false }; - | -------^^^^^--------------------- help: try this: `if Ok::(4).is_ok()` + | -------^^^^^--------------------- help: try: `if Ok::(4).is_ok()` error: redundant pattern matching, consider using `is_ok()` --> $DIR/redundant_pattern_matching_result.rs:62:20 | LL | let _ = if let Ok(_) = gen_res() { - | -------^^^^^------------ help: try this: `if gen_res().is_ok()` + | -------^^^^^------------ help: try: `if gen_res().is_ok()` error: redundant pattern matching, consider using `is_err()` --> $DIR/redundant_pattern_matching_result.rs:64:19 | LL | } else if let Err(_) = gen_res() { - | -------^^^^^^------------ help: try this: `if gen_res().is_err()` + | -------^^^^^^------------ help: try: `if gen_res().is_err()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_result.rs:87:19 | LL | while let Some(_) = r#try!(result_opt()) {} - | ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()` + | ----------^^^^^^^----------------------- help: try: `while r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_result.rs:88:16 | LL | if let Some(_) = r#try!(result_opt()) {} - | -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()` + | -------^^^^^^^----------------------- help: try: `if r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_result.rs:94:12 | LL | if let Some(_) = m!() {} - | -------^^^^^^^------- help: try this: `if m!().is_some()` + | -------^^^^^^^------- help: try: `if m!().is_some()` error: redundant pattern matching, consider using `is_some()` --> $DIR/redundant_pattern_matching_result.rs:95:15 | LL | while let Some(_) = m!() {} - | ----------^^^^^^^------- help: try this: `while m!().is_some()` + | ----------^^^^^^^------- help: try: `while m!().is_some()` error: redundant pattern matching, consider using `is_ok()` --> $DIR/redundant_pattern_matching_result.rs:113:12 | LL | if let Ok(_) = Ok::(42) {} - | -------^^^^^--------------------- help: try this: `if Ok::(42).is_ok()` + | -------^^^^^--------------------- help: try: `if Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` --> $DIR/redundant_pattern_matching_result.rs:115:12 | LL | if let Err(_) = Err::(42) {} - | -------^^^^^^---------------------- help: try this: `if Err::(42).is_err()` + | -------^^^^^^---------------------- help: try: `if Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` --> $DIR/redundant_pattern_matching_result.rs:117:15 | LL | while let Ok(_) = Ok::(10) {} - | ----------^^^^^--------------------- help: try this: `while Ok::(10).is_ok()` + | ----------^^^^^--------------------- help: try: `while Ok::(10).is_ok()` error: redundant pattern matching, consider using `is_err()` --> $DIR/redundant_pattern_matching_result.rs:119:15 | LL | while let Err(_) = Ok::(10) {} - | ----------^^^^^^--------------------- help: try this: `while Ok::(10).is_err()` + | ----------^^^^^^--------------------- help: try: `while Ok::(10).is_err()` error: redundant pattern matching, consider using `is_ok()` --> $DIR/redundant_pattern_matching_result.rs:121:5 @@ -139,7 +139,7 @@ LL | / match Ok::(42) { LL | | Ok(_) => true, LL | | Err(_) => false, LL | | }; - | |_____^ help: try this: `Ok::(42).is_ok()` + | |_____^ help: try: `Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` --> $DIR/redundant_pattern_matching_result.rs:126:5 @@ -148,7 +148,7 @@ LL | / match Err::(42) { LL | | Ok(_) => false, LL | | Err(_) => true, LL | | }; - | |_____^ help: try this: `Err::(42).is_err()` + | |_____^ help: try: `Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` --> $DIR/redundant_pattern_matching_result.rs:136:5 @@ -157,7 +157,7 @@ LL | / match x { LL | | Ok(_) => true, LL | | _ => false, LL | | }; - | |_____^ help: try this: `x.is_ok()` + | |_____^ help: try: `x.is_ok()` error: redundant pattern matching, consider using `is_err()` --> $DIR/redundant_pattern_matching_result.rs:141:5 @@ -166,7 +166,7 @@ LL | / match x { LL | | Ok(_) => false, LL | | _ => true, LL | | }; - | |_____^ help: try this: `x.is_err()` + | |_____^ help: try: `x.is_err()` error: redundant pattern matching, consider using `is_err()` --> $DIR/redundant_pattern_matching_result.rs:146:5 @@ -175,7 +175,7 @@ LL | / match x { LL | | Err(_) => true, LL | | _ => false, LL | | }; - | |_____^ help: try this: `x.is_err()` + | |_____^ help: try: `x.is_err()` error: redundant pattern matching, consider using `is_ok()` --> $DIR/redundant_pattern_matching_result.rs:151:5 @@ -184,19 +184,19 @@ LL | / match x { LL | | Err(_) => false, LL | | _ => true, LL | | }; - | |_____^ help: try this: `x.is_ok()` + | |_____^ help: try: `x.is_ok()` error: redundant pattern matching, consider using `is_ok()` --> $DIR/redundant_pattern_matching_result.rs:172:13 | LL | let _ = matches!(x, Ok(_)); - | ^^^^^^^^^^^^^^^^^^ help: try this: `x.is_ok()` + | ^^^^^^^^^^^^^^^^^^ help: try: `x.is_ok()` error: redundant pattern matching, consider using `is_err()` --> $DIR/redundant_pattern_matching_result.rs:174:13 | LL | let _ = matches!(x, Err(_)); - | ^^^^^^^^^^^^^^^^^^^ help: try this: `x.is_err()` + | ^^^^^^^^^^^^^^^^^^^ help: try: `x.is_err()` error: aborting due to 28 previous errors diff --git a/tests/ui/ref_binding_to_reference.stderr b/tests/ui/ref_binding_to_reference.stderr index eb36cd516a24..016feb103df6 100644 --- a/tests/ui/ref_binding_to_reference.stderr +++ b/tests/ui/ref_binding_to_reference.stderr @@ -5,7 +5,7 @@ LL | Some(ref x) => x, | ^^^^^ | = note: `-D clippy::ref-binding-to-reference` implied by `-D warnings` -help: try this +help: try | LL | Some(x) => &x, | ~ ~~ @@ -16,7 +16,7 @@ error: this pattern creates a reference to a reference LL | Some(ref x) => { | ^^^^^ | -help: try this +help: try | LL ~ Some(x) => { LL | f1(x); @@ -30,7 +30,7 @@ error: this pattern creates a reference to a reference LL | Some(ref x) => m2!(x), | ^^^^^ | -help: try this +help: try | LL | Some(x) => m2!(&x), | ~ ~~ @@ -41,7 +41,7 @@ error: this pattern creates a reference to a reference LL | let _ = |&ref x: &&String| { | ^^^^^ | -help: try this +help: try | LL ~ let _ = |&x: &&String| { LL ~ let _: &&String = &x; @@ -53,7 +53,7 @@ error: this pattern creates a reference to a reference LL | fn f2<'a>(&ref x: &&'a String) -> &'a String { | ^^^^^ | -help: try this +help: try | LL ~ fn f2<'a>(&x: &&'a String) -> &'a String { LL ~ let _: &&String = &x; @@ -66,7 +66,7 @@ error: this pattern creates a reference to a reference LL | fn f(&ref x: &&String) { | ^^^^^ | -help: try this +help: try | LL ~ fn f(&x: &&String) { LL ~ let _: &&String = &x; @@ -78,7 +78,7 @@ error: this pattern creates a reference to a reference LL | fn f(&ref x: &&String) { | ^^^^^ | -help: try this +help: try | LL ~ fn f(&x: &&String) { LL ~ let _: &&String = &x; diff --git a/tests/ui/result_map_unit_fn_fixable.stderr b/tests/ui/result_map_unit_fn_fixable.stderr index 782febd52644..ad941fa8bcc0 100644 --- a/tests/ui/result_map_unit_fn_fixable.stderr +++ b/tests/ui/result_map_unit_fn_fixable.stderr @@ -4,7 +4,7 @@ error: called `map(f)` on an `Result` value where `f` is a function that returns LL | x.field.map(do_nothing); | ^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(x_field) = x.field { do_nothing(x_field) }` + | help: try: `if let Ok(x_field) = x.field { do_nothing(x_field) }` | = note: `-D clippy::result-map-unit-fn` implied by `-D warnings` @@ -14,7 +14,7 @@ error: called `map(f)` on an `Result` value where `f` is a function that returns LL | x.field.map(do_nothing); | ^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(x_field) = x.field { do_nothing(x_field) }` + | help: try: `if let Ok(x_field) = x.field { do_nothing(x_field) }` error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:39:5 @@ -22,7 +22,7 @@ error: called `map(f)` on an `Result` value where `f` is a function that returns LL | x.field.map(diverge); | ^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(x_field) = x.field { diverge(x_field) }` + | help: try: `if let Ok(x_field) = x.field { diverge(x_field) }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:45:5 @@ -30,7 +30,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns LL | x.field.map(|value| x.do_result_nothing(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(value) = x.field { x.do_result_nothing(value + captured) }` + | help: try: `if let Ok(value) = x.field { x.do_result_nothing(value + captured) }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:47:5 @@ -38,7 +38,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns LL | x.field.map(|value| { x.do_result_plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(value) = x.field { x.do_result_plus_one(value + captured); }` + | help: try: `if let Ok(value) = x.field { x.do_result_plus_one(value + captured); }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:50:5 @@ -46,7 +46,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns LL | x.field.map(|value| do_nothing(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(value) = x.field { do_nothing(value + captured) }` + | help: try: `if let Ok(value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:52:5 @@ -54,7 +54,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns LL | x.field.map(|value| { do_nothing(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(value) = x.field { do_nothing(value + captured) }` + | help: try: `if let Ok(value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:54:5 @@ -62,7 +62,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns LL | x.field.map(|value| { do_nothing(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(value) = x.field { do_nothing(value + captured); }` + | help: try: `if let Ok(value) = x.field { do_nothing(value + captured); }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:56:5 @@ -70,7 +70,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns LL | x.field.map(|value| { { do_nothing(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(value) = x.field { do_nothing(value + captured); }` + | help: try: `if let Ok(value) = x.field { do_nothing(value + captured); }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:59:5 @@ -78,7 +78,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns LL | x.field.map(|value| diverge(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(value) = x.field { diverge(value + captured) }` + | help: try: `if let Ok(value) = x.field { diverge(value + captured) }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:61:5 @@ -86,7 +86,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns LL | x.field.map(|value| { diverge(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(value) = x.field { diverge(value + captured) }` + | help: try: `if let Ok(value) = x.field { diverge(value + captured) }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:63:5 @@ -94,7 +94,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns LL | x.field.map(|value| { diverge(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(value) = x.field { diverge(value + captured); }` + | help: try: `if let Ok(value) = x.field { diverge(value + captured); }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:65:5 @@ -102,7 +102,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns LL | x.field.map(|value| { { diverge(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(value) = x.field { diverge(value + captured); }` + | help: try: `if let Ok(value) = x.field { diverge(value + captured); }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:70:5 @@ -110,7 +110,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns LL | x.field.map(|value| { let y = plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(value) = x.field { let y = plus_one(value + captured); }` + | help: try: `if let Ok(value) = x.field { let y = plus_one(value + captured); }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:72:5 @@ -118,7 +118,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns LL | x.field.map(|value| { plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(value) = x.field { plus_one(value + captured); }` + | help: try: `if let Ok(value) = x.field { plus_one(value + captured); }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:74:5 @@ -126,7 +126,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns LL | x.field.map(|value| { { plus_one(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(value) = x.field { plus_one(value + captured); }` + | help: try: `if let Ok(value) = x.field { plus_one(value + captured); }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:77:5 @@ -134,7 +134,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns LL | x.field.map(|ref value| { do_nothing(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(ref value) = x.field { do_nothing(value + captured) }` + | help: try: `if let Ok(ref value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_fixable.rs:79:5 @@ -142,7 +142,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns LL | x.field.map(|value| println!("{:?}", value)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(value) = x.field { println!("{:?}", value) }` + | help: try: `if let Ok(value) = x.field { println!("{:?}", value) }` error: aborting due to 18 previous errors diff --git a/tests/ui/result_map_unit_fn_unfixable.stderr b/tests/ui/result_map_unit_fn_unfixable.stderr index d0e534f63568..75ec1ba80245 100644 --- a/tests/ui/result_map_unit_fn_unfixable.stderr +++ b/tests/ui/result_map_unit_fn_unfixable.stderr @@ -4,7 +4,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns LL | x.field.map(|value| { do_nothing(value); do_nothing(value) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(value) = x.field { ... }` + | help: try: `if let Ok(value) = x.field { ... }` | = note: `-D clippy::result-map-unit-fn` implied by `-D warnings` @@ -14,7 +14,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns LL | x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(value) = x.field { ... }` + | help: try: `if let Ok(value) = x.field { ... }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` --> $DIR/result_map_unit_fn_unfixable.rs:29:5 @@ -23,7 +23,7 @@ LL | // x.field.map(|value| { LL | || do_nothing(value); LL | || do_nothing(value) LL | || }); - | ||______^- help: try this: `if let Ok(value) = x.field { ... }` + | ||______^- help: try: `if let Ok(value) = x.field { ... }` | |______| | @@ -33,7 +33,7 @@ error: called `map(f)` on an `Result` value where `f` is a closure that returns LL | x.field.map(|value| { do_nothing(value); do_nothing(value); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(value) = x.field { ... }` + | help: try: `if let Ok(value) = x.field { ... }` error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()` --> $DIR/result_map_unit_fn_unfixable.rs:37:5 @@ -41,7 +41,7 @@ error: called `map(f)` on an `Result` value where `f` is a function that returns LL | "12".parse::().map(diverge); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(a) = "12".parse::() { diverge(a) }` + | help: try: `if let Ok(a) = "12".parse::() { diverge(a) }` error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()` --> $DIR/result_map_unit_fn_unfixable.rs:43:5 @@ -49,7 +49,7 @@ error: called `map(f)` on an `Result` value where `f` is a function that returns LL | y.map(do_nothing); | ^^^^^^^^^^^^^^^^^- | | - | help: try this: `if let Ok(_y) = y { do_nothing(_y) }` + | help: try: `if let Ok(_y) = y { do_nothing(_y) }` error: aborting due to 6 previous errors diff --git a/tests/ui/single_match.stderr b/tests/ui/single_match.stderr index ef9015132404..76f7e7895898 100644 --- a/tests/ui/single_match.stderr +++ b/tests/ui/single_match.stderr @@ -10,7 +10,7 @@ LL | | }; | |_____^ | = note: `-D clippy::single-match` implied by `-D warnings` -help: try this +help: try | LL ~ if let Some(y) = x { LL + println!("{:?}", y); @@ -27,7 +27,7 @@ LL | | // is expanded before we can do anything. LL | | Some(y) => println!("{:?}", y), LL | | _ => (), LL | | } - | |_____^ help: try this: `if let Some(y) = x { println!("{:?}", y) }` + | |_____^ help: try: `if let Some(y) = x { println!("{:?}", y) }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` --> $DIR/single_match.rs:31:5 @@ -36,7 +36,7 @@ LL | / match z { LL | | (2..=3, 7..=9) => dummy(), LL | | _ => {}, LL | | }; - | |_____^ help: try this: `if let (2..=3, 7..=9) = z { dummy() }` + | |_____^ help: try: `if let (2..=3, 7..=9) = z { dummy() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` --> $DIR/single_match.rs:60:5 @@ -45,7 +45,7 @@ LL | / match x { LL | | Some(y) => dummy(), LL | | None => (), LL | | }; - | |_____^ help: try this: `if let Some(y) = x { dummy() }` + | |_____^ help: try: `if let Some(y) = x { dummy() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` --> $DIR/single_match.rs:65:5 @@ -54,7 +54,7 @@ LL | / match y { LL | | Ok(y) => dummy(), LL | | Err(..) => (), LL | | }; - | |_____^ help: try this: `if let Ok(y) = y { dummy() }` + | |_____^ help: try: `if let Ok(y) = y { dummy() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` --> $DIR/single_match.rs:72:5 @@ -63,7 +63,7 @@ LL | / match c { LL | | Cow::Borrowed(..) => dummy(), LL | | Cow::Owned(..) => (), LL | | }; - | |_____^ help: try this: `if let Cow::Borrowed(..) = c { dummy() }` + | |_____^ help: try: `if let Cow::Borrowed(..) = c { dummy() }` error: you seem to be trying to use `match` for an equality check. Consider using `if` --> $DIR/single_match.rs:93:5 @@ -72,7 +72,7 @@ LL | / match x { LL | | "test" => println!(), LL | | _ => (), LL | | } - | |_____^ help: try this: `if x == "test" { println!() }` + | |_____^ help: try: `if x == "test" { println!() }` error: you seem to be trying to use `match` for an equality check. Consider using `if` --> $DIR/single_match.rs:106:5 @@ -81,7 +81,7 @@ LL | / match x { LL | | Foo::A => println!(), LL | | _ => (), LL | | } - | |_____^ help: try this: `if x == Foo::A { println!() }` + | |_____^ help: try: `if x == Foo::A { println!() }` error: you seem to be trying to use `match` for an equality check. Consider using `if` --> $DIR/single_match.rs:112:5 @@ -90,7 +90,7 @@ LL | / match x { LL | | FOO_C => println!(), LL | | _ => (), LL | | } - | |_____^ help: try this: `if x == FOO_C { println!() }` + | |_____^ help: try: `if x == FOO_C { println!() }` error: you seem to be trying to use `match` for an equality check. Consider using `if` --> $DIR/single_match.rs:117:5 @@ -99,7 +99,7 @@ LL | / match &&x { LL | | Foo::A => println!(), LL | | _ => (), LL | | } - | |_____^ help: try this: `if x == Foo::A { println!() }` + | |_____^ help: try: `if x == Foo::A { println!() }` error: you seem to be trying to use `match` for an equality check. Consider using `if` --> $DIR/single_match.rs:123:5 @@ -108,7 +108,7 @@ LL | / match &x { LL | | Foo::A => println!(), LL | | _ => (), LL | | } - | |_____^ help: try this: `if x == &Foo::A { println!() }` + | |_____^ help: try: `if x == &Foo::A { println!() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` --> $DIR/single_match.rs:140:5 @@ -117,7 +117,7 @@ LL | / match x { LL | | Bar::A => println!(), LL | | _ => (), LL | | } - | |_____^ help: try this: `if let Bar::A = x { println!() }` + | |_____^ help: try: `if let Bar::A = x { println!() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` --> $DIR/single_match.rs:148:5 @@ -126,7 +126,7 @@ LL | / match x { LL | | None => println!(), LL | | _ => (), LL | | }; - | |_____^ help: try this: `if let None = x { println!() }` + | |_____^ help: try: `if let None = x { println!() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` --> $DIR/single_match.rs:170:5 @@ -135,7 +135,7 @@ LL | / match x { LL | | (Some(_), _) => {}, LL | | (None, _) => {}, LL | | } - | |_____^ help: try this: `if let (Some(_), _) = x {}` + | |_____^ help: try: `if let (Some(_), _) = x {}` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` --> $DIR/single_match.rs:176:5 @@ -144,7 +144,7 @@ LL | / match x { LL | | (Some(E::V), _) => todo!(), LL | | (_, _) => {}, LL | | } - | |_____^ help: try this: `if let (Some(E::V), _) = x { todo!() }` + | |_____^ help: try: `if let (Some(E::V), _) = x { todo!() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` --> $DIR/single_match.rs:182:5 @@ -153,7 +153,7 @@ LL | / match (Some(42), Some(E::V), Some(42)) { LL | | (.., Some(E::V), _) => {}, LL | | (..) => {}, LL | | } - | |_____^ help: try this: `if let (.., Some(E::V), _) = (Some(42), Some(E::V), Some(42)) {}` + | |_____^ help: try: `if let (.., Some(E::V), _) = (Some(42), Some(E::V), Some(42)) {}` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` --> $DIR/single_match.rs:254:5 @@ -167,7 +167,7 @@ LL | | _ => {}, LL | | } | |_____^ | -help: try this +help: try | LL ~ if let Some(v) = bar { unsafe { LL + let r = &v as *const i32; @@ -187,7 +187,7 @@ LL | | _ => {}, LL | | } | |_____^ | -help: try this +help: try | LL ~ if let Some(v) = bar { LL + unsafe { diff --git a/tests/ui/single_match_else.stderr b/tests/ui/single_match_else.stderr index 228236f3bb8e..5e7d4062efea 100644 --- a/tests/ui/single_match_else.stderr +++ b/tests/ui/single_match_else.stderr @@ -12,7 +12,7 @@ LL | | }; | |_____^ | = note: `-D clippy::single-match-else` implied by `-D warnings` -help: try this +help: try | LL ~ let _ = if let ExprNode::ExprAddrOf = ExprNode::Butterflies { Some(&NODE) } else { LL + let x = 5; @@ -32,7 +32,7 @@ LL | | }, LL | | } | |_____^ | -help: try this +help: try | LL ~ if let Some(a) = Some(1) { println!("${:?}", a) } else { LL + println!("else block"); @@ -52,7 +52,7 @@ LL | | }, LL | | } | |_____^ | -help: try this +help: try | LL ~ if let Some(a) = Some(1) { println!("${:?}", a) } else { LL + println!("else block"); @@ -72,7 +72,7 @@ LL | | } LL | | } | |_____^ | -help: try this +help: try | LL ~ if let Ok(a) = Result::::Ok(1) { println!("${:?}", a) } else { LL + println!("else block"); @@ -92,7 +92,7 @@ LL | | } LL | | } | |_____^ | -help: try this +help: try | LL ~ if let Cow::Owned(a) = Cow::from("moo") { println!("${:?}", a) } else { LL + println!("else block"); @@ -112,7 +112,7 @@ LL | | }, LL | | } | |_____^ | -help: try this +help: try | LL ~ if let Some(v) = bar { unsafe { LL + let r = &v as *const i32; @@ -135,7 +135,7 @@ LL | | }, LL | | } | |_____^ | -help: try this +help: try | LL ~ if let Some(v) = bar { LL + println!("Some"); @@ -159,7 +159,7 @@ LL | | }, LL | | } | |_____^ | -help: try this +help: try | LL ~ if let Some(v) = bar { unsafe { LL + let r = &v as *const i32; @@ -183,7 +183,7 @@ LL | | }, LL | | } | |_____^ | -help: try this +help: try | LL ~ if let Some(v) = bar { LL + unsafe { diff --git a/tests/ui/string_extend.stderr b/tests/ui/string_extend.stderr index b35c77fd9611..34b43290147e 100644 --- a/tests/ui/string_extend.stderr +++ b/tests/ui/string_extend.stderr @@ -2,7 +2,7 @@ error: calling `.extend(_.chars())` --> $DIR/string_extend.rs:18:5 | LL | s.extend(abc.chars()); - | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.push_str(abc)` + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `s.push_str(abc)` | = note: `-D clippy::string-extend-chars` implied by `-D warnings` @@ -10,19 +10,19 @@ error: calling `.extend(_.chars())` --> $DIR/string_extend.rs:21:5 | LL | s.extend("abc".chars()); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.push_str("abc")` + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.push_str("abc")` error: calling `.extend(_.chars())` --> $DIR/string_extend.rs:24:5 | LL | s.extend(def.chars()); - | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.push_str(&def)` + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `s.push_str(&def)` error: calling `.extend(_.chars())` --> $DIR/string_extend.rs:34:5 | LL | s.extend(abc[0..2].chars()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s.push_str(&abc[0..2])` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.push_str(&abc[0..2])` error: aborting due to 4 previous errors diff --git a/tests/ui/strlen_on_c_strings.stderr b/tests/ui/strlen_on_c_strings.stderr index 296268a5f1df..fcd17f689404 100644 --- a/tests/ui/strlen_on_c_strings.stderr +++ b/tests/ui/strlen_on_c_strings.stderr @@ -2,7 +2,7 @@ error: using `libc::strlen` on a `CString` or `CStr` value --> $DIR/strlen_on_c_strings.rs:15:13 | LL | let _ = unsafe { libc::strlen(cstring.as_ptr()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `cstring.as_bytes().len()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cstring.as_bytes().len()` | = note: `-D clippy::strlen-on-c-strings` implied by `-D warnings` @@ -10,37 +10,37 @@ error: using `libc::strlen` on a `CString` or `CStr` value --> $DIR/strlen_on_c_strings.rs:19:13 | LL | let _ = unsafe { libc::strlen(cstr.as_ptr()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `cstr.to_bytes().len()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cstr.to_bytes().len()` error: using `libc::strlen` on a `CString` or `CStr` value --> $DIR/strlen_on_c_strings.rs:21:13 | LL | let _ = unsafe { strlen(cstr.as_ptr()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `cstr.to_bytes().len()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cstr.to_bytes().len()` error: using `libc::strlen` on a `CString` or `CStr` value --> $DIR/strlen_on_c_strings.rs:24:22 | LL | let _ = unsafe { strlen((*pcstr).as_ptr()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(*pcstr).to_bytes().len()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(*pcstr).to_bytes().len()` error: using `libc::strlen` on a `CString` or `CStr` value --> $DIR/strlen_on_c_strings.rs:29:22 | LL | let _ = unsafe { strlen(unsafe_identity(cstr).as_ptr()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unsafe_identity(cstr).to_bytes().len()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unsafe_identity(cstr).to_bytes().len()` error: using `libc::strlen` on a `CString` or `CStr` value --> $DIR/strlen_on_c_strings.rs:30:13 | LL | let _ = unsafe { strlen(unsafe { unsafe_identity(cstr) }.as_ptr()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unsafe { unsafe_identity(cstr) }.to_bytes().len()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unsafe { unsafe_identity(cstr) }.to_bytes().len()` error: using `libc::strlen` on a `CString` or `CStr` value --> $DIR/strlen_on_c_strings.rs:33:22 | LL | let _ = unsafe { strlen(f(cstr).as_ptr()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `f(cstr).to_bytes().len()` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `f(cstr).to_bytes().len()` error: aborting due to 7 previous errors diff --git a/tests/ui/to_digit_is_some.stderr b/tests/ui/to_digit_is_some.stderr index 10a1b393a390..c4718825dc26 100644 --- a/tests/ui/to_digit_is_some.stderr +++ b/tests/ui/to_digit_is_some.stderr @@ -2,7 +2,7 @@ error: use of `.to_digit(..).is_some()` --> $DIR/to_digit_is_some.rs:9:13 | LL | let _ = d.to_digit(8).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `d.is_digit(8)` + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `d.is_digit(8)` | = note: `-D clippy::to-digit-is-some` implied by `-D warnings` @@ -10,7 +10,7 @@ error: use of `.to_digit(..).is_some()` --> $DIR/to_digit_is_some.rs:10:13 | LL | let _ = char::to_digit(c, 8).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `char::is_digit(c, 8)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `char::is_digit(c, 8)` error: aborting due to 2 previous errors diff --git a/tests/ui/try_err.stderr b/tests/ui/try_err.stderr index 4ad0e2e56a4d..79f7b70224a1 100644 --- a/tests/ui/try_err.stderr +++ b/tests/ui/try_err.stderr @@ -2,7 +2,7 @@ error: returning an `Err(_)` with the `?` operator --> $DIR/try_err.rs:19:9 | LL | Err(err)?; - | ^^^^^^^^^ help: try this: `return Err(err)` + | ^^^^^^^^^ help: try: `return Err(err)` | note: the lint level is defined here --> $DIR/try_err.rs:4:9 @@ -14,25 +14,25 @@ error: returning an `Err(_)` with the `?` operator --> $DIR/try_err.rs:29:9 | LL | Err(err)?; - | ^^^^^^^^^ help: try this: `return Err(err.into())` + | ^^^^^^^^^ help: try: `return Err(err.into())` error: returning an `Err(_)` with the `?` operator --> $DIR/try_err.rs:49:17 | LL | Err(err)?; - | ^^^^^^^^^ help: try this: `return Err(err)` + | ^^^^^^^^^ help: try: `return Err(err)` error: returning an `Err(_)` with the `?` operator --> $DIR/try_err.rs:68:17 | LL | Err(err)?; - | ^^^^^^^^^ help: try this: `return Err(err.into())` + | ^^^^^^^^^ help: try: `return Err(err.into())` error: returning an `Err(_)` with the `?` operator --> $DIR/try_err.rs:88:23 | LL | Err(_) => Err(1)?, - | ^^^^^^^ help: try this: `return Err(1)` + | ^^^^^^^ help: try: `return Err(1)` | = note: this error originates in the macro `__inline_mac_fn_calling_macro` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -40,7 +40,7 @@ error: returning an `Err(_)` with the `?` operator --> $DIR/try_err.rs:95:23 | LL | Err(_) => Err(inline!(1))?, - | ^^^^^^^^^^^^^^^^ help: try this: `return Err(inline!(1))` + | ^^^^^^^^^^^^^^^^ help: try: `return Err(inline!(1))` | = note: this error originates in the macro `__inline_mac_fn_calling_macro` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -48,31 +48,31 @@ error: returning an `Err(_)` with the `?` operator --> $DIR/try_err.rs:122:9 | LL | Err(inline!(inline!(String::from("aasdfasdfasdfa"))))?; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Err(inline!(inline!(String::from("aasdfasdfasdfa"))))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `return Err(inline!(inline!(String::from("aasdfasdfasdfa"))))` error: returning an `Err(_)` with the `?` operator --> $DIR/try_err.rs:129:9 | LL | Err(io::ErrorKind::WriteZero)? - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Err(io::ErrorKind::WriteZero.into()))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `return Poll::Ready(Err(io::ErrorKind::WriteZero.into()))` error: returning an `Err(_)` with the `?` operator --> $DIR/try_err.rs:131:9 | LL | Err(io::Error::new(io::ErrorKind::InvalidInput, "error"))? - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "error")))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `return Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "error")))` error: returning an `Err(_)` with the `?` operator --> $DIR/try_err.rs:139:9 | LL | Err(io::ErrorKind::NotFound)? - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Some(Err(io::ErrorKind::NotFound.into())))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `return Poll::Ready(Some(Err(io::ErrorKind::NotFound.into())))` error: returning an `Err(_)` with the `?` operator --> $DIR/try_err.rs:148:16 | LL | return Err(42)?; - | ^^^^^^^^ help: try this: `Err(42)` + | ^^^^^^^^ help: try: `Err(42)` error: aborting due to 11 previous errors diff --git a/tests/ui/unnecessary_clone.stderr b/tests/ui/unnecessary_clone.stderr index 5686ab6b4531..23639f6d41a0 100644 --- a/tests/ui/unnecessary_clone.stderr +++ b/tests/ui/unnecessary_clone.stderr @@ -2,7 +2,7 @@ error: using `.clone()` on a ref-counted pointer --> $DIR/unnecessary_clone.rs:23:5 | LL | rc.clone(); - | ^^^^^^^^^^ help: try this: `Rc::::clone(&rc)` + | ^^^^^^^^^^ help: try: `Rc::::clone(&rc)` | = note: `-D clippy::clone-on-ref-ptr` implied by `-D warnings` @@ -10,25 +10,25 @@ error: using `.clone()` on a ref-counted pointer --> $DIR/unnecessary_clone.rs:26:5 | LL | arc.clone(); - | ^^^^^^^^^^^ help: try this: `Arc::::clone(&arc)` + | ^^^^^^^^^^^ help: try: `Arc::::clone(&arc)` error: using `.clone()` on a ref-counted pointer --> $DIR/unnecessary_clone.rs:29:5 | LL | rcweak.clone(); - | ^^^^^^^^^^^^^^ help: try this: `Weak::::clone(&rcweak)` + | ^^^^^^^^^^^^^^ help: try: `Weak::::clone(&rcweak)` error: using `.clone()` on a ref-counted pointer --> $DIR/unnecessary_clone.rs:32:5 | LL | arc_weak.clone(); - | ^^^^^^^^^^^^^^^^ help: try this: `Weak::::clone(&arc_weak)` + | ^^^^^^^^^^^^^^^^ help: try: `Weak::::clone(&arc_weak)` error: using `.clone()` on a ref-counted pointer --> $DIR/unnecessary_clone.rs:36:33 | LL | let _: Arc = x.clone(); - | ^^^^^^^^^ help: try this: `Arc::::clone(&x)` + | ^^^^^^^^^ help: try: `Arc::::clone(&x)` error: using `clone` on type `T` which implements the `Copy` trait --> $DIR/unnecessary_clone.rs:40:5 @@ -54,7 +54,7 @@ error: using `.clone()` on a ref-counted pointer --> $DIR/unnecessary_clone.rs:95:14 | LL | Some(try_opt!(Some(rc)).clone()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `Rc::::clone(&try_opt!(Some(rc)))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Rc::::clone(&try_opt!(Some(rc)))` error: aborting due to 9 previous errors diff --git a/tests/ui/unwrap_or.stderr b/tests/ui/unwrap_or.stderr index cf720eaaf052..e384bbbb0155 100644 --- a/tests/ui/unwrap_or.stderr +++ b/tests/ui/unwrap_or.stderr @@ -2,7 +2,7 @@ error: use of `unwrap_or` followed by a function call --> $DIR/unwrap_or.rs:5:47 | LL | let s = Some(String::from("test string")).unwrap_or("Fail".to_string()).len(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "Fail".to_string())` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| "Fail".to_string())` | = note: `-D clippy::or-fun-call` implied by `-D warnings` @@ -10,7 +10,7 @@ error: use of `unwrap_or` followed by a function call --> $DIR/unwrap_or.rs:9:47 | LL | let s = Some(String::from("test string")).unwrap_or("Fail".to_string()).len(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "Fail".to_string())` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| "Fail".to_string())` error: aborting due to 2 previous errors diff --git a/tests/ui/useless_asref.stderr b/tests/ui/useless_asref.stderr index 67ce8b64e0e3..1f51831b2e95 100644 --- a/tests/ui/useless_asref.stderr +++ b/tests/ui/useless_asref.stderr @@ -2,7 +2,7 @@ error: this call to `as_ref` does nothing --> $DIR/useless_asref.rs:43:18 | LL | foo_rstr(rstr.as_ref()); - | ^^^^^^^^^^^^^ help: try this: `rstr` + | ^^^^^^^^^^^^^ help: try: `rstr` | note: the lint level is defined here --> $DIR/useless_asref.rs:2:9 @@ -14,61 +14,61 @@ error: this call to `as_ref` does nothing --> $DIR/useless_asref.rs:45:20 | LL | foo_rslice(rslice.as_ref()); - | ^^^^^^^^^^^^^^^ help: try this: `rslice` + | ^^^^^^^^^^^^^^^ help: try: `rslice` error: this call to `as_mut` does nothing --> $DIR/useless_asref.rs:49:21 | LL | foo_mrslice(mrslice.as_mut()); - | ^^^^^^^^^^^^^^^^ help: try this: `mrslice` + | ^^^^^^^^^^^^^^^^ help: try: `mrslice` error: this call to `as_ref` does nothing --> $DIR/useless_asref.rs:51:20 | LL | foo_rslice(mrslice.as_ref()); - | ^^^^^^^^^^^^^^^^ help: try this: `mrslice` + | ^^^^^^^^^^^^^^^^ help: try: `mrslice` error: this call to `as_ref` does nothing --> $DIR/useless_asref.rs:58:20 | LL | foo_rslice(rrrrrslice.as_ref()); - | ^^^^^^^^^^^^^^^^^^^ help: try this: `rrrrrslice` + | ^^^^^^^^^^^^^^^^^^^ help: try: `rrrrrslice` error: this call to `as_ref` does nothing --> $DIR/useless_asref.rs:60:18 | LL | foo_rstr(rrrrrstr.as_ref()); - | ^^^^^^^^^^^^^^^^^ help: try this: `rrrrrstr` + | ^^^^^^^^^^^^^^^^^ help: try: `rrrrrstr` error: this call to `as_mut` does nothing --> $DIR/useless_asref.rs:65:21 | LL | foo_mrslice(mrrrrrslice.as_mut()); - | ^^^^^^^^^^^^^^^^^^^^ help: try this: `mrrrrrslice` + | ^^^^^^^^^^^^^^^^^^^^ help: try: `mrrrrrslice` error: this call to `as_ref` does nothing --> $DIR/useless_asref.rs:67:20 | LL | foo_rslice(mrrrrrslice.as_ref()); - | ^^^^^^^^^^^^^^^^^^^^ help: try this: `mrrrrrslice` + | ^^^^^^^^^^^^^^^^^^^^ help: try: `mrrrrrslice` error: this call to `as_ref` does nothing --> $DIR/useless_asref.rs:71:16 | LL | foo_rrrrmr((&&&&MoreRef).as_ref()); - | ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(&&&&MoreRef)` + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `(&&&&MoreRef)` error: this call to `as_mut` does nothing --> $DIR/useless_asref.rs:121:13 | LL | foo_mrt(mrt.as_mut()); - | ^^^^^^^^^^^^ help: try this: `mrt` + | ^^^^^^^^^^^^ help: try: `mrt` error: this call to `as_ref` does nothing --> $DIR/useless_asref.rs:123:12 | LL | foo_rt(mrt.as_ref()); - | ^^^^^^^^^^^^ help: try this: `mrt` + | ^^^^^^^^^^^^ help: try: `mrt` error: aborting due to 11 previous errors diff --git a/tests/ui/wildcard_enum_match_arm.stderr b/tests/ui/wildcard_enum_match_arm.stderr index 30d29aa4e77a..5b88ae4ab665 100644 --- a/tests/ui/wildcard_enum_match_arm.stderr +++ b/tests/ui/wildcard_enum_match_arm.stderr @@ -2,7 +2,7 @@ error: wildcard match will also match any future added variants --> $DIR/wildcard_enum_match_arm.rs:40:9 | LL | _ => eprintln!("Not red"), - | ^ help: try this: `Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan` + | ^ help: try: `Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan` | note: the lint level is defined here --> $DIR/wildcard_enum_match_arm.rs:3:9 @@ -14,31 +14,31 @@ error: wildcard match will also match any future added variants --> $DIR/wildcard_enum_match_arm.rs:44:9 | LL | _not_red => eprintln!("Not red"), - | ^^^^^^^^ help: try this: `_not_red @ Color::Green | _not_red @ Color::Blue | _not_red @ Color::Rgb(..) | _not_red @ Color::Cyan` + | ^^^^^^^^ help: try: `_not_red @ Color::Green | _not_red @ Color::Blue | _not_red @ Color::Rgb(..) | _not_red @ Color::Cyan` error: wildcard match will also match any future added variants --> $DIR/wildcard_enum_match_arm.rs:48:9 | LL | not_red => format!("{:?}", not_red), - | ^^^^^^^ help: try this: `not_red @ Color::Green | not_red @ Color::Blue | not_red @ Color::Rgb(..) | not_red @ Color::Cyan` + | ^^^^^^^ help: try: `not_red @ Color::Green | not_red @ Color::Blue | not_red @ Color::Rgb(..) | not_red @ Color::Cyan` error: wildcard match will also match any future added variants --> $DIR/wildcard_enum_match_arm.rs:64:9 | LL | _ => "No red", - | ^ help: try this: `Color::Red | Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan` + | ^ help: try: `Color::Red | Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan` error: wildcard matches known variants and will also match future added variants --> $DIR/wildcard_enum_match_arm.rs:81:9 | LL | _ => {}, - | ^ help: try this: `ErrorKind::PermissionDenied | _` + | ^ help: try: `ErrorKind::PermissionDenied | _` error: wildcard match will also match any future added variants --> $DIR/wildcard_enum_match_arm.rs:99:13 | LL | _ => (), - | ^ help: try this: `Enum::B | Enum::__Private` + | ^ help: try: `Enum::B | Enum::__Private` error: aborting due to 6 previous errors diff --git a/tests/ui/write_literal.stderr b/tests/ui/write_literal.stderr index 1e306ae28a26..8b72c8bd2823 100644 --- a/tests/ui/write_literal.stderr +++ b/tests/ui/write_literal.stderr @@ -5,7 +5,7 @@ LL | write!(v, "Hello {}", "world"); | ^^^^^^^ | = note: `-D clippy::write-literal` implied by `-D warnings` -help: try this +help: try | LL - write!(v, "Hello {}", "world"); LL + write!(v, "Hello world"); @@ -17,7 +17,7 @@ error: literal with an empty format string LL | writeln!(v, "Hello {} {}", world, "world"); | ^^^^^^^ | -help: try this +help: try | LL - writeln!(v, "Hello {} {}", world, "world"); LL + writeln!(v, "Hello {} world", world); @@ -29,7 +29,7 @@ error: literal with an empty format string LL | writeln!(v, "Hello {}", "world"); | ^^^^^^^ | -help: try this +help: try | LL - writeln!(v, "Hello {}", "world"); LL + writeln!(v, "Hello world"); @@ -41,7 +41,7 @@ error: literal with an empty format string LL | writeln!(v, "{} {:.4}", "a literal", 5); | ^^^^^^^^^^^ | -help: try this +help: try | LL - writeln!(v, "{} {:.4}", "a literal", 5); LL + writeln!(v, "a literal {:.4}", 5); @@ -53,7 +53,7 @@ error: literal with an empty format string LL | writeln!(v, "{0} {1}", "hello", "world"); | ^^^^^^^ | -help: try this +help: try | LL - writeln!(v, "{0} {1}", "hello", "world"); LL + writeln!(v, "hello {1}", "world"); @@ -65,7 +65,7 @@ error: literal with an empty format string LL | writeln!(v, "{0} {1}", "hello", "world"); | ^^^^^^^ | -help: try this +help: try | LL - writeln!(v, "{0} {1}", "hello", "world"); LL + writeln!(v, "{0} world", "hello"); @@ -77,7 +77,7 @@ error: literal with an empty format string LL | writeln!(v, "{1} {0}", "hello", "world"); | ^^^^^^^ | -help: try this +help: try | LL - writeln!(v, "{1} {0}", "hello", "world"); LL + writeln!(v, "world {0}", "hello"); @@ -89,7 +89,7 @@ error: literal with an empty format string LL | writeln!(v, "{1} {0}", "hello", "world"); | ^^^^^^^ | -help: try this +help: try | LL - writeln!(v, "{1} {0}", "hello", "world"); LL + writeln!(v, "{1} hello", "world"); @@ -101,7 +101,7 @@ error: literal with an empty format string LL | writeln!(v, "{foo} {bar}", foo = "hello", bar = "world"); | ^^^^^^^ | -help: try this +help: try | LL - writeln!(v, "{foo} {bar}", foo = "hello", bar = "world"); LL + writeln!(v, "hello {bar}", bar = "world"); @@ -113,7 +113,7 @@ error: literal with an empty format string LL | writeln!(v, "{foo} {bar}", foo = "hello", bar = "world"); | ^^^^^^^ | -help: try this +help: try | LL - writeln!(v, "{foo} {bar}", foo = "hello", bar = "world"); LL + writeln!(v, "{foo} world", foo = "hello"); @@ -125,7 +125,7 @@ error: literal with an empty format string LL | writeln!(v, "{bar} {foo}", foo = "hello", bar = "world"); | ^^^^^^^ | -help: try this +help: try | LL - writeln!(v, "{bar} {foo}", foo = "hello", bar = "world"); LL + writeln!(v, "world {foo}", foo = "hello"); @@ -137,7 +137,7 @@ error: literal with an empty format string LL | writeln!(v, "{bar} {foo}", foo = "hello", bar = "world"); | ^^^^^^^ | -help: try this +help: try | LL - writeln!(v, "{bar} {foo}", foo = "hello", bar = "world"); LL + writeln!(v, "{bar} hello", bar = "world"); diff --git a/tests/ui/write_literal_2.stderr b/tests/ui/write_literal_2.stderr index 18591250aad9..c30ec385b35a 100644 --- a/tests/ui/write_literal_2.stderr +++ b/tests/ui/write_literal_2.stderr @@ -13,7 +13,7 @@ LL | writeln!(v, "{}", "{hello}"); | ^^^^^^^^^ | = note: `-D clippy::write-literal` implied by `-D warnings` -help: try this +help: try | LL - writeln!(v, "{}", "{hello}"); LL + writeln!(v, "{{hello}}"); @@ -25,7 +25,7 @@ error: literal with an empty format string LL | writeln!(v, r"{}", r"{hello}"); | ^^^^^^^^^^ | -help: try this +help: try | LL - writeln!(v, r"{}", r"{hello}"); LL + writeln!(v, r"{{hello}}"); @@ -37,7 +37,7 @@ error: literal with an empty format string LL | writeln!(v, "{}", '/''); | ^^^^ | -help: try this +help: try | LL - writeln!(v, "{}", '/''); LL + writeln!(v, "'"); @@ -49,7 +49,7 @@ error: literal with an empty format string LL | writeln!(v, "{}", '"'); | ^^^ | -help: try this +help: try | LL - writeln!(v, "{}", '"'); LL + writeln!(v, "/""); @@ -67,7 +67,7 @@ error: literal with an empty format string LL | writeln!(v, r"{}", '/''); | ^^^^ | -help: try this +help: try | LL - writeln!(v, r"{}", '/''); LL + writeln!(v, r"'"); @@ -80,7 +80,7 @@ LL | / "hello / LL | | world!" | |_______________^ | -help: try this +help: try | LL ~ "some hello / LL ~ world!" @@ -92,7 +92,7 @@ error: literal with an empty format string LL | "1", "2", "3", | ^^^ | -help: try this +help: try | LL ~ "some 1/ LL ~ {} // {}", "2", "3", @@ -104,7 +104,7 @@ error: literal with an empty format string LL | "1", "2", "3", | ^^^ | -help: try this +help: try | LL ~ 2 // {}", LL ~ "1", "3", @@ -116,7 +116,7 @@ error: literal with an empty format string LL | "1", "2", "3", | ^^^ | -help: try this +help: try | LL ~ {} // 3", LL ~ "1", "2", @@ -128,7 +128,7 @@ error: literal with an empty format string LL | writeln!(v, "{}", "//"); | ^^^^ | -help: try this +help: try | LL - writeln!(v, "{}", "//"); LL + writeln!(v, "//"); @@ -140,7 +140,7 @@ error: literal with an empty format string LL | writeln!(v, r"{}", "//"); | ^^^^ | -help: try this +help: try | LL - writeln!(v, r"{}", "//"); LL + writeln!(v, r"/"); @@ -152,7 +152,7 @@ error: literal with an empty format string LL | writeln!(v, r#"{}"#, "//"); | ^^^^ | -help: try this +help: try | LL - writeln!(v, r#"{}"#, "//"); LL + writeln!(v, r#"/"#); @@ -164,7 +164,7 @@ error: literal with an empty format string LL | writeln!(v, "{}", r"/"); | ^^^^ | -help: try this +help: try | LL - writeln!(v, "{}", r"/"); LL + writeln!(v, "//"); @@ -176,7 +176,7 @@ error: literal with an empty format string LL | writeln!(v, "{}", "/r"); | ^^^^ | -help: try this +help: try | LL - writeln!(v, "{}", "/r"); LL + writeln!(v, "/r"); From 15a0da6f3087a0248fb8b62dac49b24fd287afd9 Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Sat, 1 Jul 2023 17:16:56 +0330 Subject: [PATCH 121/324] Fix overflow checking in shift operator --- crates/hir-ty/src/consteval/tests.rs | 1 + crates/hir-ty/src/mir/eval.rs | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs index e50dfdf965ea..9baedc3fb74d 100644 --- a/crates/hir-ty/src/consteval/tests.rs +++ b/crates/hir-ty/src/consteval/tests.rs @@ -108,6 +108,7 @@ fn bit_op() { check_fail(r#"const GOAL: i8 = 1 << 8"#, |e| { e == ConstEvalError::MirEvalError(MirEvalError::Panic("Overflow in Shl".to_string())) }); + check_number(r#"const GOAL: i32 = 100000000i32 << 11"#, (100000000i32 << 11) as i128); } #[test] diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index dd23f1957c72..1c5288207216 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -1037,13 +1037,18 @@ impl Evaluator<'_> { BinOp::Shr => l128.checked_shr(shift_amount), _ => unreachable!(), }; + if shift_amount as usize >= lc.len() * 8 { + return Err(MirEvalError::Panic(format!( + "Overflow in {op:?}" + ))); + } if let Some(r) = r { break 'b r; } }; return Err(MirEvalError::Panic(format!("Overflow in {op:?}"))); }; - check_overflow(r)? + Owned(r.to_le_bytes()[..lc.len()].to_vec()) } BinOp::Offset => not_supported!("offset binop"), } From 6f7452882aceed912b35331be95571fe31660eba Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Sun, 2 Jul 2023 00:42:33 +0330 Subject: [PATCH 122/324] Fix layout of simd types and respect align in mir interpreter --- crates/hir-def/src/data/adt.rs | 1 + crates/hir-ty/src/consteval/tests.rs | 45 ++++++++++++--- crates/hir-ty/src/layout.rs | 85 +++++++++++++++++++++++++++- crates/hir-ty/src/layout/tests.rs | 14 +++++ crates/hir-ty/src/lib.rs | 11 +++- crates/hir-ty/src/mir/eval.rs | 55 ++++++++++++++---- 6 files changed, 189 insertions(+), 22 deletions(-) diff --git a/crates/hir-def/src/data/adt.rs b/crates/hir-def/src/data/adt.rs index 6db5abccc921..612a5ca1a283 100644 --- a/crates/hir-def/src/data/adt.rs +++ b/crates/hir-def/src/data/adt.rs @@ -147,6 +147,7 @@ fn parse_repr_tt(tt: &Subtree) -> Option { } "C" => ReprFlags::IS_C, "transparent" => ReprFlags::IS_TRANSPARENT, + "simd" => ReprFlags::IS_SIMD, repr => { if let Some(builtin) = BuiltinInt::from_suffix(repr) .map(Either::Left) diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs index 9baedc3fb74d..c37c5912f280 100644 --- a/crates/hir-ty/src/consteval/tests.rs +++ b/crates/hir-ty/src/consteval/tests.rs @@ -36,6 +36,18 @@ fn check_fail(ra_fixture: &str, error: impl FnOnce(ConstEvalError) -> bool) { #[track_caller] fn check_number(ra_fixture: &str, answer: i128) { + check_answer(ra_fixture, |b| { + assert_eq!( + b, + &answer.to_le_bytes()[0..b.len()], + "Bytes differ. In decimal form: actual = {}, expected = {answer}", + i128::from_le_bytes(pad16(b, true)) + ); + }); +} + +#[track_caller] +fn check_answer(ra_fixture: &str, check: impl FnOnce(&[u8])) { let (db, file_id) = TestDB::with_single_file(ra_fixture); let r = match eval_goal(&db, file_id) { Ok(t) => t, @@ -47,12 +59,7 @@ fn check_number(ra_fixture: &str, answer: i128) { match &r.data(Interner).value { chalk_ir::ConstValue::Concrete(c) => match &c.interned { ConstScalar::Bytes(b, _) => { - assert_eq!( - b, - &answer.to_le_bytes()[0..b.len()], - "Bytes differ. In decimal form: actual = {}, expected = {answer}", - i128::from_le_bytes(pad16(b, true)) - ); + check(b); } x => panic!("Expected number but found {:?}", x), }, @@ -87,7 +94,7 @@ fn eval_goal(db: &TestDB, file_id: FileId) -> Result { } _ => None, }) - .unwrap(); + .expect("No const named GOAL found in the test"); db.const_eval(const_id.into(), Substitution::empty(Interner)) } @@ -206,6 +213,30 @@ fn raw_pointer_equality() { ); } +#[test] +fn alignment() { + check_answer( + r#" +//- minicore: transmute +use core::mem::transmute; +const GOAL: usize = { + let x: i64 = 2; + transmute(&x) +} + "#, + |b| assert_eq!(b[0] % 8, 0), + ); + check_answer( + r#" +//- minicore: transmute +use core::mem::transmute; +static X: i64 = 12; +const GOAL: usize = transmute(&X); + "#, + |b| assert_eq!(b[0] % 8, 0), + ); +} + #[test] fn locals() { check_number( diff --git a/crates/hir-ty/src/layout.rs b/crates/hir-ty/src/layout.rs index a566c06a5401..2a9b2debd4b9 100644 --- a/crates/hir-ty/src/layout.rs +++ b/crates/hir-ty/src/layout.rs @@ -7,7 +7,7 @@ use hir_def::{ Abi, FieldsShape, Integer, LayoutCalculator, LayoutS, Primitive, ReprOptions, Scalar, Size, StructKind, TargetDataLayout, WrappingRange, }, - LocalEnumVariantId, LocalFieldId, + LocalEnumVariantId, LocalFieldId, StructId, }; use la_arena::{Idx, RawIdx}; use stdx::never; @@ -77,6 +77,78 @@ impl<'a> LayoutCalculator for LayoutCx<'a> { } } +// FIXME: move this to the `rustc_abi`. +fn layout_of_simd_ty( + db: &dyn HirDatabase, + id: StructId, + subst: &Substitution, + krate: CrateId, + dl: &TargetDataLayout, +) -> Result, LayoutError> { + let fields = db.field_types(id.into()); + + // Supported SIMD vectors are homogeneous ADTs with at least one field: + // + // * #[repr(simd)] struct S(T, T, T, T); + // * #[repr(simd)] struct S { x: T, y: T, z: T, w: T } + // * #[repr(simd)] struct S([T; 4]) + // + // where T is a primitive scalar (integer/float/pointer). + + let f0_ty = match fields.iter().next() { + Some(x) => x.1.clone().substitute(Interner, subst), + None => { + user_error!("simd type with zero fields"); + } + }; + + // The element type and number of elements of the SIMD vector + // are obtained from: + // + // * the element type and length of the single array field, if + // the first field is of array type, or + // + // * the homogeneous field type and the number of fields. + let (e_ty, e_len, is_array) = if let TyKind::Array(e_ty, _) = f0_ty.kind(Interner) { + // Extract the number of elements from the layout of the array field: + let FieldsShape::Array { count, .. } = db.layout_of_ty(f0_ty.clone(), krate)?.fields else { + user_error!("Array with non array layout"); + }; + + (e_ty.clone(), count, true) + } else { + // First ADT field is not an array: + (f0_ty, fields.iter().count() as u64, false) + }; + + // Compute the ABI of the element type: + let e_ly = db.layout_of_ty(e_ty, krate)?; + let Abi::Scalar(e_abi) = e_ly.abi else { + user_error!("simd type with inner non scalar type"); + }; + + // Compute the size and alignment of the vector: + let size = e_ly.size.checked_mul(e_len, dl).ok_or(LayoutError::SizeOverflow)?; + let align = dl.vector_align(size); + let size = size.align_to(align.abi); + + // Compute the placement of the vector fields: + let fields = if is_array { + FieldsShape::Arbitrary { offsets: [Size::ZERO].into(), memory_index: [0].into() } + } else { + FieldsShape::Array { stride: e_ly.size, count: e_len } + }; + + Ok(Arc::new(Layout { + variants: Variants::Single { index: struct_variant_idx() }, + fields, + abi: Abi::Vector { element: e_abi, count: e_len }, + largest_niche: e_ly.largest_niche, + size, + align, + })) +} + pub fn layout_of_ty_query( db: &dyn HirDatabase, ty: Ty, @@ -88,7 +160,16 @@ pub fn layout_of_ty_query( let trait_env = Arc::new(TraitEnvironment::empty(krate)); let ty = normalize(db, trait_env, ty.clone()); let result = match ty.kind(Interner) { - TyKind::Adt(AdtId(def), subst) => return db.layout_of_adt(*def, subst.clone(), krate), + TyKind::Adt(AdtId(def), subst) => { + if let hir_def::AdtId::StructId(s) = def { + let data = db.struct_data(*s); + let repr = data.repr.unwrap_or_default(); + if repr.simd() { + return layout_of_simd_ty(db, *s, subst, krate, &target); + } + }; + return db.layout_of_adt(*def, subst.clone(), krate); + } TyKind::Scalar(s) => match s { chalk_ir::Scalar::Bool => Layout::scalar( dl, diff --git a/crates/hir-ty/src/layout/tests.rs b/crates/hir-ty/src/layout/tests.rs index 0257aef7a4c8..2b74f1a1a1d2 100644 --- a/crates/hir-ty/src/layout/tests.rs +++ b/crates/hir-ty/src/layout/tests.rs @@ -270,6 +270,20 @@ struct Goal(Foo); ); } +#[test] +fn simd_types() { + check_size_and_align( + r#" + #[repr(simd)] + struct SimdType(i64, i64); + struct Goal(SimdType); + "#, + "", + 16, + 16, + ); +} + #[test] fn return_position_impl_trait() { size_and_align_expr! { diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs index 1a4d003bf5e9..b3ca2a222580 100644 --- a/crates/hir-ty/src/lib.rs +++ b/crates/hir-ty/src/lib.rs @@ -180,9 +180,16 @@ impl MemoryMap { /// allocator function as `f` and it will return a mapping of old addresses to new addresses. fn transform_addresses( &self, - mut f: impl FnMut(&[u8]) -> Result, + mut f: impl FnMut(&[u8], usize) -> Result, ) -> Result, MirEvalError> { - self.memory.iter().map(|x| Ok((*x.0, f(x.1)?))).collect() + self.memory + .iter() + .map(|x| { + let addr = *x.0; + let align = if addr == 0 { 64 } else { (addr - (addr & (addr - 1))).min(64) }; + Ok((addr, f(x.1, align)?)) + }) + .collect() } fn get<'a>(&'a self, addr: usize, size: usize) -> Option<&'a [u8]> { diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index 1c5288207216..ddcfc57185fb 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -226,16 +226,26 @@ impl IntervalOrOwned { } } +#[cfg(target_pointer_width = "64")] +const STACK_OFFSET: usize = 1 << 60; +#[cfg(target_pointer_width = "64")] +const HEAP_OFFSET: usize = 1 << 59; + +#[cfg(target_pointer_width = "32")] +const STACK_OFFSET: usize = 1 << 30; +#[cfg(target_pointer_width = "32")] +const HEAP_OFFSET: usize = 1 << 29; + impl Address { fn from_bytes(x: &[u8]) -> Result { Ok(Address::from_usize(from_bytes!(usize, x))) } fn from_usize(x: usize) -> Self { - if x > usize::MAX / 2 { - Stack(x - usize::MAX / 2) - } else if x > usize::MAX / 4 { - Heap(x - usize::MAX / 4) + if x > STACK_OFFSET { + Stack(x - STACK_OFFSET) + } else if x > HEAP_OFFSET { + Heap(x - HEAP_OFFSET) } else { Invalid(x) } @@ -247,8 +257,8 @@ impl Address { fn to_usize(&self) -> usize { let as_num = match self { - Stack(x) => *x + usize::MAX / 2, - Heap(x) => *x + usize::MAX / 4, + Stack(x) => *x + STACK_OFFSET, + Heap(x) => *x + HEAP_OFFSET, Invalid(x) => *x, }; as_num @@ -721,8 +731,14 @@ impl Evaluator<'_> { .locals .iter() .map(|(id, x)| { - let size = - self.size_of_sized(&x.ty, &locals, "no unsized local in extending stack")?; + let (size, align) = self.size_align_of_sized( + &x.ty, + &locals, + "no unsized local in extending stack", + )?; + while stack_ptr % align != 0 { + stack_ptr += 1; + } let my_ptr = stack_ptr; stack_ptr += size; Ok((id, Interval { addr: Stack(my_ptr), size })) @@ -1469,8 +1485,8 @@ impl Evaluator<'_> { Ok(match &c.interned { ConstScalar::Bytes(v, memory_map) => { let mut v: Cow<'_, [u8]> = Cow::Borrowed(v); - let patch_map = memory_map.transform_addresses(|b| { - let addr = self.heap_allocate(b.len(), 1); // FIXME: align is wrong + let patch_map = memory_map.transform_addresses(|b, align| { + let addr = self.heap_allocate(b.len(), align); self.write_memory(addr, b)?; Ok(addr.to_usize()) })?; @@ -1574,7 +1590,24 @@ impl Evaluator<'_> { } } - fn heap_allocate(&mut self, size: usize, _align: usize) -> Address { + /// A version of `self.size_align_of` which returns error if the type is unsized. `what` argument should + /// be something that complete this: `error: type {ty} was unsized. {what} should be sized` + fn size_align_of_sized( + &self, + ty: &Ty, + locals: &Locals<'_>, + what: &'static str, + ) -> Result<(usize, usize)> { + match self.size_align_of(ty, locals)? { + Some(x) => Ok(x), + None => Err(MirEvalError::TypeIsUnsized(ty.clone(), what)), + } + } + + fn heap_allocate(&mut self, size: usize, align: usize) -> Address { + while self.heap.len() % align != 0 { + self.heap.push(0); + } let pos = self.heap.len(); self.heap.extend(iter::repeat(0).take(size)); Address::Heap(pos) From 0810827b9735d9c5a0d65edd98978e02516bbe27 Mon Sep 17 00:00:00 2001 From: David Lattimore Date: Sun, 2 Jul 2023 19:06:20 +1000 Subject: [PATCH 123/324] Don't specify proc-macro-test version proc-macro-test is only used as a dev-dependency and isn't published to crates.io, so a version doesn't make sense. Having a version also breaks automatic publishing. --- Cargo.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 7aa12fe4ae11..83d9fd801e29 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,7 +67,6 @@ paths = { path = "./crates/paths", version = "0.0.0" } proc-macro-api = { path = "./crates/proc-macro-api", version = "0.0.0" } proc-macro-srv = { path = "./crates/proc-macro-srv", version = "0.0.0" } proc-macro-srv-cli = { path = "./crates/proc-macro-srv-cli", version = "0.0.0" } -proc-macro-test = { path = "./crates/proc-macro-test", version = "0.0.0" } profile = { path = "./crates/profile", version = "0.0.0" } project-model = { path = "./crates/project-model", version = "0.0.0" } sourcegen = { path = "./crates/sourcegen", version = "0.0.0" } @@ -80,6 +79,9 @@ tt = { path = "./crates/tt", version = "0.0.0" } vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" } vfs = { path = "./crates/vfs", version = "0.0.0" } +# local crates that aren't published to crates.io. These should not have versions. +proc-macro-test = { path = "./crates/proc-macro-test" } + # In-tree crates that are published separately and follow semver. See lib/README.md line-index = { version = "0.1.0-pre.1" } la-arena = { version = "0.3.1" } From 885a18207fb66fc736496a4c9cb8c010881c1ab5 Mon Sep 17 00:00:00 2001 From: Catherine <114838443+Centri3@users.noreply.github.com> Date: Sat, 1 Jul 2023 19:33:08 -0500 Subject: [PATCH 124/324] Fix typos --- book/src/lint_configuration.md | 2 +- clippy_lints/src/methods/map_unwrap_or.rs | 3 ++- clippy_lints/src/min_ident_chars.rs | 2 +- clippy_lints/src/needless_else.rs | 2 +- clippy_lints/src/utils/conf.rs | 2 +- clippy_utils/src/attrs.rs | 4 ++-- clippy_utils/src/check_proc_macro.rs | 2 +- clippy_utils/src/comparisons.rs | 4 ++-- clippy_utils/src/consts.rs | 2 +- clippy_utils/src/eager_or_lazy.rs | 2 +- clippy_utils/src/higher.rs | 8 ++++---- clippy_utils/src/lib.rs | 5 +++-- clippy_utils/src/sugg.rs | 2 +- tests/ui/needless_else.stderr | 2 +- 14 files changed, 22 insertions(+), 20 deletions(-) diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index ae0b51403167..1ade6e3f4813 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -174,7 +174,7 @@ The maximum amount of nesting a block can reside in ## `disallowed-names` The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value -`".."` can be used as part of the list to indicate, that the configured values should be appended to the +`".."` can be used as part of the list to indicate that the configured values should be appended to the default configuration of Clippy. By default, any configuration will replace the default value. **Default Value:** `["foo", "baz", "quux"]` (`Vec`) diff --git a/clippy_lints/src/methods/map_unwrap_or.rs b/clippy_lints/src/methods/map_unwrap_or.rs index 3122f72ee915..72156bbd1b09 100644 --- a/clippy_lints/src/methods/map_unwrap_or.rs +++ b/clippy_lints/src/methods/map_unwrap_or.rs @@ -11,7 +11,8 @@ use rustc_span::symbol::sym; use super::MAP_UNWRAP_OR; /// lint use of `map().unwrap_or_else()` for `Option`s and `Result`s -/// Return true if lint triggered +/// +/// Returns true if the lint was emitted pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, diff --git a/clippy_lints/src/min_ident_chars.rs b/clippy_lints/src/min_ident_chars.rs index d49bb0ca6e29..23593e0d4d97 100644 --- a/clippy_lints/src/min_ident_chars.rs +++ b/clippy_lints/src/min_ident_chars.rs @@ -25,7 +25,7 @@ declare_clippy_lint! { /// ### Example /// ```rust,ignore /// for m in movies { - /// let title = m.t; + /// let title = m.t; /// } /// ``` /// Use instead: diff --git a/clippy_lints/src/needless_else.rs b/clippy_lints/src/needless_else.rs index 4ff1bf7ffc0d..23d4a7b9586d 100644 --- a/clippy_lints/src/needless_else.rs +++ b/clippy_lints/src/needless_else.rs @@ -51,7 +51,7 @@ impl EarlyLintPass for NeedlessElse { cx, NEEDLESS_ELSE, span, - "this else branch is empty", + "this `else` branch is empty", "you can remove it", String::new(), Applicability::MachineApplicable, diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 890639646228..59e997588296 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -319,7 +319,7 @@ define_Conf! { /// Lint: DISALLOWED_NAMES. /// /// The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value - /// `".."` can be used as part of the list to indicate, that the configured values should be appended to the + /// `".."` can be used as part of the list to indicate that the configured values should be appended to the /// default configuration of Clippy. By default, any configuration will replace the default value. (disallowed_names: Vec = super::DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect()), /// Lint: SEMICOLON_INSIDE_BLOCK. diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index 49cb9718ef66..e4cc86f68005 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -143,13 +143,13 @@ pub fn get_unique_attr<'a>( unique_attr } -/// Return true if the attributes contain any of `proc_macro`, +/// Returns true if the attributes contain any of `proc_macro`, /// `proc_macro_derive` or `proc_macro_attribute`, false otherwise pub fn is_proc_macro(attrs: &[ast::Attribute]) -> bool { attrs.iter().any(rustc_ast::Attribute::is_proc_macro_attr) } -/// Return true if the attributes contain `#[doc(hidden)]` +/// Returns true if the attributes contain `#[doc(hidden)]` pub fn is_doc_hidden(attrs: &[ast::Attribute]) -> bool { attrs .iter() diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs index c6d0b654f57b..62792d60652b 100644 --- a/clippy_utils/src/check_proc_macro.rs +++ b/clippy_utils/src/check_proc_macro.rs @@ -339,7 +339,7 @@ fn ty_search_pat(ty: &Ty<'_>) -> (Pat, Pat) { TyKind::Tup(..) => (Pat::Str("("), Pat::Str(")")), TyKind::OpaqueDef(..) => (Pat::Str("impl"), Pat::Str("")), TyKind::Path(qpath) => qpath_search_pat(&qpath), - // NOTE: This is missing `TraitObject`. It always return true then. + // NOTE: This is missing `TraitObject`. It will always return true then. _ => (Pat::Str(""), Pat::Str("")), } } diff --git a/clippy_utils/src/comparisons.rs b/clippy_utils/src/comparisons.rs index 7a18d5e818fb..5e6bf2278442 100644 --- a/clippy_utils/src/comparisons.rs +++ b/clippy_utils/src/comparisons.rs @@ -1,11 +1,11 @@ -//! Utility functions about comparison operators. +//! Utility functions for comparison operators. #![deny(clippy::missing_docs_in_private_items)] use rustc_hir::{BinOpKind, Expr}; #[derive(PartialEq, Eq, Debug, Copy, Clone)] -/// Represent a normalized comparison operator. +/// Represents a normalized comparison operator. pub enum Rel { /// `<` Lt, diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 068820801dfe..87d85d742ce4 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -267,7 +267,7 @@ pub fn constant_with_source<'tcx>( res.map(|x| (x, ctxt.source)) } -/// Attempts to evaluate an expression only if it's value is not dependent on other items. +/// Attempts to evaluate an expression only if its value is not dependent on other items. pub fn constant_simple<'tcx>( lcx: &LateContext<'tcx>, typeck_results: &ty::TypeckResults<'tcx>, diff --git a/clippy_utils/src/eager_or_lazy.rs b/clippy_utils/src/eager_or_lazy.rs index 4a845ca63b49..eda739bceb5c 100644 --- a/clippy_utils/src/eager_or_lazy.rs +++ b/clippy_utils/src/eager_or_lazy.rs @@ -1,7 +1,7 @@ //! Utilities for evaluating whether eagerly evaluated expressions can be made lazy and vice versa. //! //! Things to consider: -//! - has the expression side-effects? +//! - does the expression have side-effects? //! - is the expression computationally expensive? //! //! See lints: diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs index a61e4c380886..357ac40b4559 100644 --- a/clippy_utils/src/higher.rs +++ b/clippy_utils/src/higher.rs @@ -13,7 +13,7 @@ use rustc_lint::LateContext; use rustc_span::{sym, symbol, Span}; /// The essential nodes of a desugared for loop as well as the entire span: -/// `for pat in arg { body }` becomes `(pat, arg, body)`. Return `(pat, arg, body, span)`. +/// `for pat in arg { body }` becomes `(pat, arg, body)`. Returns `(pat, arg, body, span)`. pub struct ForLoop<'tcx> { /// `for` loop item pub pat: &'tcx hir::Pat<'tcx>, @@ -264,7 +264,7 @@ impl<'a> Range<'a> { } } -/// Represent the pre-expansion arguments of a `vec!` invocation. +/// Represents the pre-expansion arguments of a `vec!` invocation. pub enum VecArgs<'a> { /// `vec![elem; len]` Repeat(&'a hir::Expr<'a>, &'a hir::Expr<'a>), @@ -398,7 +398,7 @@ impl<'hir> WhileLet<'hir> { } } -/// Converts a hir binary operator to the corresponding `ast` type. +/// Converts a `hir` binary operator to the corresponding `ast` type. #[must_use] pub fn binop(op: hir::BinOpKind) -> ast::BinOpKind { match op { @@ -436,7 +436,7 @@ pub enum VecInitKind { WithExprCapacity(HirId), } -/// Checks if given expression is an initialization of `Vec` and returns its kind. +/// Checks if the given expression is an initialization of `Vec` and returns its kind. pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option { if let ExprKind::Call(func, args) = expr.kind { match func.kind { diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 727b59f1f432..272228cebd07 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -823,7 +823,7 @@ fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath< false } -/// Return true if the expr is equal to `Default::default` when evaluated. +/// Returns true if the expr is equal to `Default::default` when evaluated. pub fn is_default_equivalent_call(cx: &LateContext<'_>, repl_func: &Expr<'_>) -> bool { if_chain! { if let hir::ExprKind::Path(ref repl_func_qpath) = repl_func.kind; @@ -2527,7 +2527,8 @@ pub fn span_contains_comment(sm: &SourceMap, span: Span) -> bool { }); } -/// Return all the comments a given span contains +/// Returns all the comments a given span contains +/// /// Comments are returned wrapped with their relevant delimiters pub fn span_extract_comment(sm: &SourceMap, span: Span) -> String { let snippet = sm.span_to_snippet(span).unwrap_or_default(); diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index cf781e18cd66..de3aad647572 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -395,7 +395,7 @@ fn binop_to_string(op: AssocOp, lhs: &str, rhs: &str) -> String { } } -/// Return `true` if `sugg` is enclosed in parenthesis. +/// Returns `true` if `sugg` is enclosed in parenthesis. pub fn has_enclosing_paren(sugg: impl AsRef) -> bool { let mut chars = sugg.as_ref().chars(); if chars.next() == Some('(') { diff --git a/tests/ui/needless_else.stderr b/tests/ui/needless_else.stderr index ea6930851644..49cd78501eac 100644 --- a/tests/ui/needless_else.stderr +++ b/tests/ui/needless_else.stderr @@ -1,4 +1,4 @@ -error: this else branch is empty +error: this `else` branch is empty --> $DIR/needless_else.rs:24:7 | LL | } else { From cb3ecf7b792fdc4b00e61935b9e40ca836752492 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Sun, 2 Jul 2023 14:35:19 +0200 Subject: [PATCH 125/324] Merge commit '37f4c1725d3fd7e9c3ffd8783246bc5589debc53' into clippyup --- .cargo/config.toml | 2 + .github/workflows/clippy.yml | 1 - .github/workflows/clippy_bors.yml | 1 - .github/workflows/clippy_dev.yml | 1 - CHANGELOG.md | 200 +++- Cargo.toml | 19 +- book/src/development/adding_lints.md | 19 +- book/src/development/basics.md | 2 +- .../infrastructure/changelog_update.md | 22 + book/src/lint_configuration.md | 581 ++++++---- clippy_dev/src/bless.rs | 60 - clippy_dev/src/fmt.rs | 1 + clippy_dev/src/lib.rs | 7 +- clippy_dev/src/main.rs | 10 +- clippy_dev/src/new_lint.rs | 15 +- clippy_lints/Cargo.toml | 3 +- clippy_lints/src/allow_attributes.rs | 7 +- clippy_lints/src/arc_with_non_send_sync.rs | 72 ++ clippy_lints/src/as_conversions.rs | 11 +- clippy_lints/src/attrs.rs | 68 +- clippy_lints/src/booleans.rs | 2 +- clippy_lints/src/casts/borrow_as_ptr.rs | 10 + clippy_lints/src/casts/cast_possible_wrap.rs | 95 +- clippy_lints/src/casts/mod.rs | 13 +- clippy_lints/src/casts/ptr_cast_constness.rs | 13 +- clippy_lints/src/casts/unnecessary_cast.rs | 140 ++- clippy_lints/src/declared_lints.rs | 28 +- .../src/default_constructed_unit_structs.rs | 2 +- clippy_lints/src/default_numeric_fallback.rs | 2 +- clippy_lints/src/dereference.rs | 41 +- clippy_lints/src/derivable_impls.rs | 39 +- clippy_lints/src/derive.rs | 7 +- clippy_lints/src/doc.rs | 11 +- clippy_lints/src/drop_forget_ref.rs | 52 +- clippy_lints/src/endian_bytes.rs | 216 ++++ clippy_lints/src/enum_clike.rs | 2 +- clippy_lints/src/enum_variants.rs | 31 +- clippy_lints/src/eta_reduction.rs | 8 + clippy_lints/src/excessive_nesting.rs | 181 +++ .../src/extra_unused_type_parameters.rs | 2 + clippy_lints/src/float_literal.rs | 11 +- clippy_lints/src/floating_point_arithmetic.rs | 2 +- clippy_lints/src/format_push_string.rs | 23 +- clippy_lints/src/formatting.rs | 6 + clippy_lints/src/from_over_into.rs | 8 +- clippy_lints/src/incorrect_impls.rs | 124 ++ clippy_lints/src/items_after_test_module.rs | 3 +- clippy_lints/src/large_stack_frames.rs | 162 +++ clippy_lints/src/let_with_type_underscore.rs | 12 +- clippy_lints/src/lib.rs | 121 +- clippy_lints/src/lifetimes.rs | 17 +- .../src/loops/explicit_into_iter_loop.rs | 69 +- clippy_lints/src/loops/explicit_iter_loop.rs | 256 +++- clippy_lints/src/loops/manual_memcpy.rs | 4 +- clippy_lints/src/loops/mod.rs | 95 +- clippy_lints/src/loops/never_loop.rs | 92 +- clippy_lints/src/loops/same_item_push.rs | 2 +- clippy_lints/src/macro_use.rs | 2 +- clippy_lints/src/manual_let_else.rs | 247 ++-- clippy_lints/src/manual_range_patterns.rs | 123 ++ clippy_lints/src/matches/match_same_arms.rs | 29 +- .../src/matches/match_wild_err_arm.rs | 2 +- clippy_lints/src/matches/mod.rs | 10 +- clippy_lints/src/matches/overlapping_arms.rs | 4 +- .../matches/significant_drop_in_scrutinee.rs | 2 +- clippy_lints/src/matches/single_match.rs | 24 +- clippy_lints/src/matches/try_err.rs | 2 +- clippy_lints/src/mem_forget.rs | 46 - clippy_lints/src/methods/drain_collect.rs | 85 ++ clippy_lints/src/methods/get_unwrap.rs | 33 +- clippy_lints/src/methods/iter_nth.rs | 4 +- clippy_lints/src/methods/iter_nth_zero.rs | 35 +- clippy_lints/src/methods/manual_try_fold.rs | 55 + clippy_lints/src/methods/mod.rs | 174 ++- clippy_lints/src/methods/needless_collect.rs | 2 +- .../src/methods/option_map_unwrap_or.rs | 133 ++- clippy_lints/src/methods/str_splitn.rs | 2 +- clippy_lints/src/methods/unnecessary_fold.rs | 213 +++- .../src/methods/unnecessary_literal_unwrap.rs | 95 ++ .../src/methods/unnecessary_to_owned.rs | 5 + clippy_lints/src/min_ident_chars.rs | 153 +++ clippy_lints/src/minmax.rs | 8 +- .../src/misc_early/mixed_case_hex_literals.rs | 2 +- clippy_lints/src/misc_early/mod.rs | 37 + .../misc_early/redundant_at_rest_pattern.rs | 26 + .../src/mismatching_type_param_order.rs | 2 +- clippy_lints/src/missing_fields_in_debug.rs | 5 + .../src/mixed_read_write_in_expression.rs | 12 +- clippy_lints/src/module_style.rs | 10 +- clippy_lints/src/needless_if.rs | 75 ++ clippy_lints/src/needless_pass_by_value.rs | 31 +- clippy_lints/src/no_effect.rs | 47 +- clippy_lints/src/non_copy_const.rs | 18 +- clippy_lints/src/operators/eq_op.rs | 9 +- clippy_lints/src/operators/float_cmp.rs | 2 +- clippy_lints/src/option_if_let_else.rs | 3 + clippy_lints/src/ptr.rs | 105 +- clippy_lints/src/question_mark.rs | 256 ++-- clippy_lints/src/ranges.rs | 6 +- clippy_lints/src/raw_strings.rs | 143 +++ clippy_lints/src/redundant_clone.rs | 17 +- clippy_lints/src/redundant_closure_call.rs | 173 ++- .../src/redundant_type_annotations.rs | 210 ++++ clippy_lints/src/returns.rs | 8 +- .../src/significant_drop_tightening.rs | 587 +++++----- clippy_lints/src/single_call_fn.rs | 133 +++ clippy_lints/src/single_range_in_vec_init.rs | 147 +++ clippy_lints/src/trait_bounds.rs | 43 +- clippy_lints/src/tuple_array_conversions.rs | 235 ++++ .../src/undocumented_unsafe_blocks.rs | 126 +- clippy_lints/src/unused_async.rs | 3 +- clippy_lints/src/upper_case_acronyms.rs | 2 +- clippy_lints/src/useless_conversion.rs | 121 +- clippy_lints/src/utils/conf.rs | 47 +- clippy_lints/src/utils/internal_lints.rs | 1 + .../almost_standard_lint_formulation.rs | 87 ++ .../interning_defined_symbol.rs | 2 +- .../internal_lints/metadata_collector.rs | 28 +- clippy_lints/src/utils/mod.rs | 12 +- clippy_lints/src/vec.rs | 156 ++- clippy_lints/src/visibility.rs | 131 +++ clippy_test_deps/Cargo.toml | 23 + clippy_test_deps/src/lib.rs | 14 + clippy_utils/src/check_proc_macro.rs | 122 +- clippy_utils/src/consts.rs | 147 ++- clippy_utils/src/eager_or_lazy.rs | 23 +- clippy_utils/src/lib.rs | 23 +- clippy_utils/src/macros.rs | 14 +- clippy_utils/src/msrvs.rs | 6 +- clippy_utils/src/numeric_literal.rs | 2 +- clippy_utils/src/qualify_min_const_fn.rs | 82 +- clippy_utils/src/sugg.rs | 2 +- clippy_utils/src/ty.rs | 58 +- clippy_utils/src/usage.rs | 2 +- declare_clippy_lint/src/lib.rs | 4 +- lintcheck/src/main.rs | 2 +- rust-toolchain | 2 +- rustfmt.toml | 1 + src/driver.rs | 2 +- src/main.rs | 8 +- tests/compile-test.rs | 440 +++---- tests/headers.rs | 29 + tests/lint_message_convention.rs | 30 +- tests/missing-test-files.rs | 6 +- .../fail/{src/main.stderr => Cargo.stderr} | 7 +- .../{src/main.stderr => Cargo.stderr} | 7 +- .../{src/main.stderr => Cargo.stderr} | 7 +- .../fail_both_diff/Cargo.stderr | 21 + .../fail_both_diff/src/main.stderr | 22 - .../fail_both_same/Cargo.stderr | 19 + .../fail_cargo/Cargo.stderr | 19 + .../fail_cargo/src/main.stderr | 20 - .../fail_clippy/Cargo.stderr | 19 + .../fail_clippy/src/main.stderr | 20 - .../Cargo.stderr} | 15 +- .../fail_file_attr/src/main.stderr | 20 - .../{src/main.stderr => Cargo.stderr} | 2 - .../ui-cargo/duplicate_mod/fail/Cargo.stderr | 52 + .../duplicate_mod/fail/src/main.stderr | 53 - tests/ui-cargo/feature_name/fail/Cargo.stderr | 43 + .../feature_name/fail/src/main.stderr | 44 - .../module_style/fail_mod/Cargo.stderr | 18 + .../module_style/fail_mod/src/main.stderr | 19 - .../module_style/fail_mod_remap/Cargo.stderr | 10 + .../fail_mod_remap/src/main.stderr | 11 - .../module_style/fail_no_mod/Cargo.stderr | 10 + .../module_style/fail_no_mod/src/main.stderr | 11 - .../multiple_config_files/warn/Cargo.stderr | 2 + .../warn/src/main.stderr | 4 - .../multiple_crate_versions/fail/Cargo.stderr | 5 + .../fail/src/main.stderr | 6 - tests/ui-cargo/update-all-references.sh | 2 +- .../wildcard_dependencies/fail/Cargo.stderr | 5 + .../fail/src/main.stderr | 6 - tests/ui-internal/check_formulation.rs | 54 + tests/ui-internal/check_formulation.stderr | 19 + tests/ui-internal/custom_ice_message.stderr | 6 +- tests/ui-internal/if_chain_style.rs | 7 +- tests/ui-internal/if_chain_style.stderr | 20 +- .../uninlined_format_args.fixed | 1 + .../uninlined_format_args.rs | 1 + .../uninlined_format_args.stderr | 12 +- .../arithmetic_side_effects_allowed.rs | 1 + .../arithmetic_side_effects_allowed.stderr | 18 +- tests/ui-toml/bad_toml/conf_bad_toml.rs | 2 + tests/ui-toml/bad_toml/conf_bad_toml.stderr | 2 +- tests/ui-toml/bad_toml_type/conf_bad_type.rs | 2 + .../bad_toml_type/conf_bad_type.stderr | 2 +- .../conf_deprecated_key.stderr | 4 +- .../duplicated_keys/duplicated_keys.rs | 2 + .../duplicated_keys/duplicated_keys.stderr | 2 +- .../duplicated_keys.stderr | 4 +- .../duplicated_keys.stderr | 4 +- .../auxiliary/proc_macros.rs | 472 ++++++++ tests/ui-toml/excessive_nesting/clippy.toml | 1 + .../excessive_nesting/excessive_nesting.rs | 197 ++++ .../excessive_nesting.stderr | 314 +++++ tests/ui-toml/expect_used/expect_used.rs | 1 + tests/ui-toml/expect_used/expect_used.stderr | 4 +- .../invalid_min_rust_version.rs | 2 + .../ui-toml/lint_decimal_readability/test.rs | 2 +- .../lint_decimal_readability/test.stderr | 10 +- .../index_refutable_slice.rs | 1 + .../min_ident_chars/auxiliary/extern_types.rs | 3 + tests/ui-toml/min_ident_chars/clippy.toml | 2 + .../min_ident_chars/min_ident_chars.rs | 19 + .../min_ident_chars/min_ident_chars.stderr | 46 + .../min_rust_version/min_rust_version.rs | 4 +- tests/ui-toml/module_inception/clippy.toml | 1 + .../module_inception/module_inception.rs | 34 + .../module_inception/module_inception.stderr | 20 + .../auxiliary/proc_macro_derive.rs | 5 - .../conf_nonstandard_macro_braces.fixed | 2 +- .../conf_nonstandard_macro_braces.rs | 2 +- tests/ui-toml/suppress_lint_in_const/test.rs | 10 +- .../suppress_lint_in_const/test.stderr | 18 +- .../conf_disallowed_methods.rs | 2 + .../conf_disallowed_methods.stderr | 28 +- tests/ui-toml/toml_trivially_copy/test.rs | 2 +- tests/ui-toml/toml_trivially_copy/test.stderr | 6 +- .../toml_unknown_key/conf_unknown_key.rs | 2 +- .../toml_unknown_key/conf_unknown_key.stderr | 20 +- .../auxiliary/proc_macro_unsafe.rs | 13 + .../undocumented_unsafe_blocks/clippy.toml | 2 + .../undocumented_unsafe_blocks.rs | 567 +++++++++ .../undocumented_unsafe_blocks.stderr | 314 +++++ tests/ui-toml/unwrap_used/unwrap_used.rs | 9 +- tests/ui-toml/unwrap_used/unwrap_used.stderr | 62 +- tests/ui-toml/update-all-references.sh | 2 +- tests/ui/allow_attributes.fixed | 20 +- tests/ui/allow_attributes.rs | 20 +- tests/ui/allow_attributes.stderr | 4 +- tests/ui/allow_attributes_false_positive.rs | 5 - tests/ui/allow_attributes_without_reason.rs | 32 +- .../ui/allow_attributes_without_reason.stderr | 28 +- tests/ui/almost_complete_range.fixed | 2 +- tests/ui/almost_complete_range.rs | 2 +- tests/ui/arc_with_non_send_sync.rs | 17 + tests/ui/arc_with_non_send_sync.stderr | 11 + tests/ui/arithmetic_side_effects.rs | 17 +- tests/ui/as_conversions.rs | 13 +- tests/ui/as_conversions.stderr | 6 +- tests/ui/as_ptr_cast_mut.rs | 2 +- tests/ui/asm_syntax.rs | 4 +- tests/ui/assertions_on_result_states.fixed | 1 + tests/ui/assertions_on_result_states.rs | 1 + tests/ui/assertions_on_result_states.stderr | 14 +- tests/ui/assign_ops.fixed | 2 +- tests/ui/assign_ops.rs | 2 +- tests/ui/auxiliary/extern_fake_libc.rs | 10 + tests/ui/auxiliary/macro_rules.rs | 8 +- tests/ui/auxiliary/macro_use_helper.rs | 2 + tests/ui/auxiliary/proc_macro_attr.rs | 4 - tests/ui/auxiliary/proc_macro_derive.rs | 114 +- .../proc_macro_suspicious_else_formatting.rs | 5 - tests/ui/auxiliary/proc_macro_unsafe.rs | 5 - tests/ui/auxiliary/proc_macros.rs | 6 +- tests/ui/blocks_in_if_conditions.fixed | 2 +- tests/ui/blocks_in_if_conditions.rs | 2 +- tests/ui/blocks_in_if_conditions_closure.rs | 7 +- .../ui/blocks_in_if_conditions_closure.stderr | 4 +- tests/ui/bool_comparison.fixed | 1 + tests/ui/bool_comparison.rs | 1 + tests/ui/bool_comparison.stderr | 44 +- tests/ui/borrow_as_ptr.fixed | 9 + tests/ui/borrow_as_ptr.rs | 9 + tests/ui/borrow_as_ptr.stderr | 4 +- tests/ui/borrow_deref_ref.fixed | 2 +- tests/ui/borrow_deref_ref.rs | 2 +- .../ui/borrow_interior_mutable_const/enums.rs | 26 +- .../enums.stderr | 24 +- .../borrow_interior_mutable_const/others.rs | 30 +- .../others.stderr | 34 +- .../borrow_interior_mutable_const/traits.rs | 32 +- .../traits.stderr | 36 +- tests/ui/builtin_type_shadow.rs | 2 +- tests/ui/bytecount.rs | 2 +- tests/ui/cast.rs | 8 + tests/ui/cast.stderr | 118 +- tests/ui/cast_slice_different_sizes.rs | 2 +- tests/ui/cfg_features.rs | 12 + tests/ui/cfg_features.stderr | 28 + .../ui/checked_unwrap/complex_conditionals.rs | 6 +- .../complex_conditionals.stderr | 40 +- .../complex_conditionals_nested.rs | 6 +- .../complex_conditionals_nested.stderr | 4 +- .../ui/checked_unwrap/simple_conditionals.rs | 6 +- .../checked_unwrap/simple_conditionals.stderr | 34 +- tests/ui/clone_on_copy_impl.rs | 2 + tests/ui/cloned_instead_of_copied.fixed | 1 + tests/ui/cloned_instead_of_copied.rs | 1 + tests/ui/cloned_instead_of_copied.stderr | 16 +- .../ui/cmp_owned/asymmetric_partial_eq.fixed | 7 +- tests/ui/cmp_owned/asymmetric_partial_eq.rs | 7 +- .../ui/cmp_owned/asymmetric_partial_eq.stderr | 12 +- tests/ui/cmp_owned/with_suggestion.fixed | 2 +- tests/ui/cognitive_complexity.stderr | 10 +- tests/ui/collapsible_else_if.fixed | 2 +- tests/ui/collapsible_else_if.rs | 2 +- tests/ui/collapsible_if.fixed | 1 + tests/ui/collapsible_if.rs | 1 + tests/ui/collapsible_if.stderr | 18 +- tests/ui/collection_is_never_read.rs | 2 +- tests/ui/comparison_to_empty.fixed | 1 + tests/ui/comparison_to_empty.rs | 1 + tests/ui/comparison_to_empty.stderr | 8 +- .../ui/crashes/auxiliary/proc_macro_crash.rs | 8 - tests/ui/crashes/ice-10148.rs | 2 +- tests/ui/crashes/ice-10645.rs | 2 +- tests/ui/crashes/ice-10645.stderr | 4 +- tests/ui/crashes/ice-10912.rs | 4 + tests/ui/crashes/ice-10912.stderr | 16 + tests/ui/crashes/ice-1782.rs | 1 + tests/ui/crashes/ice-2774.stderr | 4 +- tests/ui/crashes/ice-3462.rs | 2 +- tests/ui/crashes/ice-3741.rs | 2 +- tests/ui/crashes/ice-4968.rs | 2 - tests/ui/crashes/ice-5497.rs | 2 +- tests/ui/crashes/ice-5579.rs | 2 + tests/ui/crashes/ice-6250.stderr | 11 +- tests/ui/crashes/ice-6251.stderr | 10 +- tests/ui/crashes/ice-6255.rs | 2 +- tests/ui/crashes/ice-6256.rs | 4 +- tests/ui/crashes/ice-6256.stderr | 2 +- tests/ui/crashes/ice-7169.rs | 2 + tests/ui/crashes/ice-7169.stderr | 2 +- tests/ui/crashes/ice-7410.rs | 4 +- tests/ui/crashes/ice-96721.rs | 2 +- tests/ui/crashes/ice-96721.stderr | 2 +- .../needless_lifetimes_impl_trait.stderr | 4 +- .../entrypoint_recursion.rs | 2 +- .../entrypoint_recursion.stderr | 11 - .../no_std_main_recursion.rs | 2 +- tests/ui/dbg_macro.rs | 1 - tests/ui/dbg_macro.stderr | 36 +- .../declare_interior_mutable_const/enums.rs | 27 +- .../enums.stderr | 49 +- .../declare_interior_mutable_const/others.rs | 16 +- .../others.stderr | 8 +- .../declare_interior_mutable_const/traits.rs | 22 +- .../traits.stderr | 22 +- tests/ui/def_id_nocore.rs | 2 +- tests/ui/default_numeric_fallback_f64.fixed | 2 +- tests/ui/default_numeric_fallback_f64.rs | 2 +- tests/ui/default_numeric_fallback_i32.fixed | 2 +- tests/ui/default_numeric_fallback_i32.rs | 2 +- tests/ui/default_trait_access.fixed | 2 +- tests/ui/default_trait_access.rs | 2 +- tests/ui/deref_addrof.fixed | 4 +- tests/ui/deref_addrof.rs | 4 +- tests/ui/deref_addrof_macro.rs | 2 +- tests/ui/derivable_impls.fixed | 21 + tests/ui/derivable_impls.rs | 21 + tests/ui/derive.rs | 2 +- tests/ui/disallowed_names.rs | 1 + tests/ui/disallowed_names.stderr | 28 +- tests/ui/diverging_sub_expression.rs | 16 + tests/ui/diverging_sub_expression.stderr | 46 +- tests/ui/doc/doc-fixable.fixed | 1 + tests/ui/doc/doc-fixable.rs | 1 + tests/ui/doc/doc-fixable.stderr | 32 +- tests/ui/doc/needless_doctest_main.rs | 20 + tests/ui/doc_unsafe.rs | 2 +- tests/ui/double_comparison.fixed | 1 + tests/ui/double_comparison.rs | 1 + tests/ui/double_comparison.stderr | 16 +- tests/ui/drain_collect.fixed | 77 ++ tests/ui/drain_collect.rs | 77 ++ tests/ui/drain_collect.stderr | 68 ++ tests/ui/else_if_without_else.rs | 4 +- tests/ui/else_if_without_else.stderr | 4 +- tests/ui/empty_line_after_doc_comments.rs | 2 +- tests/ui/empty_line_after_outer_attribute.rs | 2 +- tests/ui/empty_loop.rs | 2 +- tests/ui/empty_loop_no_std.rs | 2 +- tests/ui/endian_bytes.rs | 127 ++ tests/ui/endian_bytes.stderr | 1031 +++++++++++++++++ tests/ui/enum_clike_unportable_variant.rs | 2 +- tests/ui/eprint_with_newline.rs | 2 +- tests/ui/eprint_with_newline.stderr | 12 +- tests/ui/eq_op.rs | 4 +- tests/ui/eq_op.stderr | 20 +- tests/ui/eq_op_macros.rs | 1 + tests/ui/eq_op_macros.stderr | 24 +- tests/ui/equatable_if_let.fixed | 9 +- tests/ui/equatable_if_let.rs | 9 +- tests/ui/equatable_if_let.stderr | 28 +- tests/ui/err_expect.fixed | 2 +- tests/ui/err_expect.rs | 2 +- tests/ui/eta.fixed | 9 +- tests/ui/eta.rs | 9 +- tests/ui/eta.stderr | 52 +- tests/ui/excessive_precision.fixed | 15 +- tests/ui/excessive_precision.rs | 15 +- tests/ui/excessive_precision.stderr | 30 +- tests/ui/expect.rs | 1 + tests/ui/expect.stderr | 6 +- tests/ui/expect_fun_call.fixed | 6 +- tests/ui/expect_fun_call.rs | 6 +- tests/ui/expect_fun_call.stderr | 30 +- tests/ui/expect_tool_lint_rfc_2383.rs | 2 +- tests/ui/explicit_counter_loop.rs | 50 +- tests/ui/explicit_counter_loop.stderr | 10 +- tests/ui/explicit_deref_methods.fixed | 33 +- tests/ui/explicit_deref_methods.rs | 33 +- tests/ui/explicit_deref_methods.stderr | 24 +- tests/ui/explicit_into_iter_loop.fixed | 69 ++ tests/ui/explicit_into_iter_loop.rs | 69 ++ tests/ui/explicit_into_iter_loop.stderr | 40 + tests/ui/explicit_iter_loop.fixed | 154 +++ tests/ui/explicit_iter_loop.rs | 154 +++ tests/ui/explicit_iter_loop.stderr | 142 +++ tests/ui/extra_unused_lifetimes.rs | 2 +- tests/ui/extra_unused_type_parameters.fixed | 12 + tests/ui/extra_unused_type_parameters.rs | 12 + tests/ui/extra_unused_type_parameters.stderr | 16 +- tests/ui/field_reassign_with_default.rs | 4 +- tests/ui/filetype_is_file.rs | 1 + tests/ui/filetype_is_file.stderr | 6 +- tests/ui/find_map.rs | 1 + tests/ui/fn_null_check.rs | 1 + tests/ui/fn_null_check.stderr | 10 +- tests/ui/for_loop_fixable.fixed | 309 ----- tests/ui/for_loop_fixable.rs | 309 ----- tests/ui/for_loop_fixable.stderr | 96 -- tests/ui/for_loop_unfixable.rs | 16 - tests/ui/for_loop_unfixable.stderr | 10 - tests/ui/format.fixed | 4 +- tests/ui/format.rs | 4 +- tests/ui/format.stderr | 30 +- tests/ui/format_push_string.rs | 29 + tests/ui/format_push_string.stderr | 37 +- tests/ui/from_iter_instead_of_collect.fixed | 1 + tests/ui/from_iter_instead_of_collect.rs | 1 + tests/ui/from_iter_instead_of_collect.stderr | 30 +- tests/ui/from_over_into.fixed | 9 + tests/ui/from_over_into.rs | 9 + tests/ui/from_over_into.stderr | 18 +- tests/ui/from_over_into_unfixable.rs | 16 +- tests/ui/from_over_into_unfixable.stderr | 10 +- tests/ui/from_raw_with_void_ptr.rs | 1 + tests/ui/from_raw_with_void_ptr.stderr | 20 +- tests/ui/get_first.fixed | 1 + tests/ui/get_first.rs | 1 + tests/ui/get_first.stderr | 6 +- tests/ui/get_last_with_len.fixed | 2 +- tests/ui/get_last_with_len.rs | 2 +- tests/ui/get_unwrap.fixed | 46 +- tests/ui/get_unwrap.rs | 46 +- tests/ui/get_unwrap.stderr | 80 +- tests/ui/if_same_then_else.rs | 10 +- tests/ui/if_same_then_else.stderr | 24 +- tests/ui/if_same_then_else2.rs | 12 +- tests/ui/if_same_then_else2.stderr | 37 +- tests/ui/ifs_same_cond.rs | 14 +- tests/ui/ifs_same_cond.stderr | 16 +- tests/ui/implicit_hasher.rs | 2 +- .../ui/inconsistent_struct_constructor.fixed | 2 +- tests/ui/inconsistent_struct_constructor.rs | 2 +- .../incorrect_clone_impl_on_copy_type.fixed | 97 ++ tests/ui/incorrect_clone_impl_on_copy_type.rs | 107 ++ .../incorrect_clone_impl_on_copy_type.stderr | 40 + tests/ui/indexing_slicing_index.rs | 7 +- tests/ui/indexing_slicing_index.stderr | 26 +- tests/ui/indexing_slicing_slice.rs | 2 +- tests/ui/into_iter_on_ref.fixed | 54 +- tests/ui/into_iter_on_ref.rs | 54 +- tests/ui/into_iter_on_ref.stderr | 54 +- tests/ui/issue-3145.rs | 2 +- tests/ui/issue-3145.stderr | 2 +- tests/ui/issue_4266.stderr | 8 +- .../block_module.stderr | 17 +- tests/ui/iter_cloned_collect.fixed | 1 + tests/ui/iter_cloned_collect.rs | 1 + tests/ui/iter_cloned_collect.stderr | 10 +- tests/ui/iter_count.fixed | 3 +- tests/ui/iter_count.rs | 3 +- tests/ui/iter_count.stderr | 50 +- tests/ui/iter_next_loop.rs | 16 + tests/ui/iter_next_loop.stderr | 9 + tests/ui/iter_next_slice.fixed | 1 + tests/ui/iter_next_slice.rs | 1 + tests/ui/iter_next_slice.stderr | 8 +- tests/ui/iter_nth.rs | 1 + tests/ui/iter_nth.stderr | 22 +- tests/ui/iter_nth_zero.fixed | 15 + tests/ui/iter_nth_zero.rs | 15 + tests/ui/iter_overeager_cloned.fixed | 2 +- tests/ui/iter_overeager_cloned.rs | 2 +- tests/ui/iter_skip_next.fixed | 1 + tests/ui/iter_skip_next.rs | 1 + tests/ui/iter_skip_next.stderr | 14 +- tests/ui/iter_with_drain.fixed | 2 +- tests/ui/iter_with_drain.rs | 2 +- tests/ui/iterator_step_by_zero.rs | 1 + tests/ui/iterator_step_by_zero.stderr | 14 +- tests/ui/large_enum_variant.rs | 2 +- tests/ui/large_futures.rs | 1 + tests/ui/large_futures.stderr | 16 +- tests/ui/large_stack_frames.rs | 44 + tests/ui/large_stack_frames.stderr | 37 + tests/ui/len_zero.fixed | 2 +- tests/ui/len_zero.rs | 2 +- tests/ui/let_underscore_untyped.rs | 2 +- tests/ui/let_with_type_underscore.rs | 25 +- tests/ui/let_with_type_underscore.stderr | 38 +- tests/ui/lossy_float_literal.fixed | 4 + tests/ui/lossy_float_literal.rs | 4 + tests/ui/lossy_float_literal.stderr | 22 +- tests/ui/macro_use_imports.fixed | 2 +- tests/ui/macro_use_imports.rs | 2 +- tests/ui/macro_use_imports.stderr | 20 +- tests/ui/macro_use_imports_expect.rs | 2 +- tests/ui/manual_assert.edition2018.fixed | 2 +- tests/ui/manual_assert.edition2021.fixed | 2 +- tests/ui/manual_assert.rs | 2 +- tests/ui/manual_async_fn.fixed | 2 +- tests/ui/manual_async_fn.rs | 2 +- tests/ui/manual_filter.fixed | 2 +- tests/ui/manual_filter.rs | 2 +- tests/ui/manual_filter_map.fixed | 1 + tests/ui/manual_filter_map.rs | 1 + tests/ui/manual_filter_map.stderr | 54 +- tests/ui/manual_find_map.fixed | 1 + tests/ui/manual_find_map.rs | 1 + tests/ui/manual_find_map.stderr | 60 +- tests/ui/manual_let_else.rs | 50 +- tests/ui/manual_let_else.stderr | 107 +- tests/ui/manual_let_else_match.rs | 11 +- tests/ui/manual_let_else_match.stderr | 27 +- .../ui/manual_memcpy/without_loop_counters.rs | 1 + .../without_loop_counters.stderr | 26 +- tests/ui/manual_range_patterns.fixed | 35 + tests/ui/manual_range_patterns.rs | 35 + tests/ui/manual_range_patterns.stderr | 51 + tests/ui/manual_rem_euclid.fixed | 2 +- tests/ui/manual_rem_euclid.rs | 2 +- tests/ui/manual_slice_size_calculation.fixed | 2 +- tests/ui/manual_slice_size_calculation.rs | 2 +- tests/ui/manual_try_fold.rs | 100 ++ tests/ui/manual_try_fold.stderr | 28 + tests/ui/manual_unwrap_or.fixed | 2 +- tests/ui/manual_unwrap_or.rs | 2 +- tests/ui/map_clone.fixed | 3 +- tests/ui/map_clone.rs | 3 +- tests/ui/map_clone.stderr | 12 +- tests/ui/map_unwrap_or.rs | 47 + tests/ui/map_unwrap_or.stderr | 44 +- tests/ui/match_on_vec_items.rs | 1 + tests/ui/match_on_vec_items.stderr | 16 +- tests/ui/match_overlapping_arm.rs | 2 +- tests/ui/match_same_arms.rs | 20 +- tests/ui/match_same_arms.stderr | 24 +- tests/ui/match_same_arms2.rs | 23 +- tests/ui/match_same_arms2.stderr | 33 +- tests/ui/match_same_arms_non_exhaustive.rs | 58 + .../ui/match_same_arms_non_exhaustive.stderr | 29 + tests/ui/match_single_binding.fixed | 3 +- tests/ui/match_single_binding.rs | 3 +- tests/ui/match_single_binding.stderr | 48 +- tests/ui/mem_forget.rs | 3 + tests/ui/mem_forget.stderr | 15 +- tests/ui/mem_replace_macro.rs | 2 +- tests/ui/methods.rs | 1 + tests/ui/methods.stderr | 4 +- tests/ui/methods_fixable.fixed | 1 + tests/ui/methods_fixable.rs | 1 + tests/ui/methods_fixable.stderr | 2 +- tests/ui/min_ident_chars.rs | 84 ++ tests/ui/min_ident_chars.stderr | 178 +++ tests/ui/missing_assert_message.rs | 11 +- tests/ui/missing_assert_message.stderr | 32 +- .../ui/missing_const_for_fn/cant_be_const.rs | 45 +- .../ui/missing_const_for_fn/could_be_const.rs | 13 + .../could_be_const.stderr | 30 +- tests/ui/missing_doc.rs | 2 +- tests/ui/missing_doc_impl.rs | 2 +- tests/ui/missing_inline_proc_macro.rs | 1 - tests/ui/missing_panics_doc.rs | 80 +- tests/ui/missing_panics_doc.stderr | 110 +- tests/ui/mistyped_literal_suffix.fixed | 2 +- tests/ui/mistyped_literal_suffix.rs | 2 +- tests/ui/module_inception.rs | 12 + tests/ui/module_inception.stderr | 22 +- tests/ui/multiple_unsafe_ops_per_block.rs | 2 +- tests/ui/must_use_unit.fixed | 2 +- tests/ui/must_use_unit.rs | 2 +- tests/ui/mut_mut.rs | 2 +- .../needless_arbitrary_self_type_unfixable.rs | 2 +- tests/ui/needless_bool/fixable.fixed | 1 + tests/ui/needless_bool/fixable.rs | 1 + tests/ui/needless_bool/fixable.stderr | 42 +- tests/ui/needless_borrow.fixed | 3 +- tests/ui/needless_borrow.rs | 3 +- tests/ui/needless_borrow.stderr | 72 +- tests/ui/needless_borrowed_ref.fixed | 3 +- tests/ui/needless_borrowed_ref.rs | 3 +- tests/ui/needless_borrowed_ref.stderr | 34 +- tests/ui/needless_collect.fixed | 7 +- tests/ui/needless_collect.rs | 7 +- tests/ui/needless_collect_indirect.rs | 3 +- tests/ui/needless_collect_indirect.stderr | 32 +- tests/ui/needless_if.fixed | 93 ++ tests/ui/needless_if.rs | 94 ++ tests/ui/needless_if.stderr | 65 ++ tests/ui/needless_late_init.fixed | 5 +- tests/ui/needless_late_init.rs | 5 +- tests/ui/needless_late_init.stderr | 32 +- tests/ui/needless_lifetimes.fixed | 2 +- tests/ui/needless_lifetimes.rs | 2 +- tests/ui/needless_lifetimes.stderr | 184 +-- tests/ui/needless_option_as_deref.fixed | 1 + tests/ui/needless_option_as_deref.rs | 1 + tests/ui/needless_option_as_deref.stderr | 6 +- tests/ui/needless_pass_by_value_proc_macro.rs | 1 - tests/ui/needless_pub_self.fixed | 33 + tests/ui/needless_pub_self.rs | 33 + tests/ui/needless_pub_self.stderr | 22 + tests/ui/needless_range_loop.rs | 64 +- tests/ui/needless_range_loop.stderr | 28 +- tests/ui/needless_range_loop2.rs | 1 + tests/ui/needless_range_loop2.stderr | 16 +- tests/ui/needless_raw_string.fixed | 16 + tests/ui/needless_raw_string.rs | 16 + tests/ui/needless_raw_string.stderr | 22 + tests/ui/needless_raw_string_hashes.fixed | 19 + tests/ui/needless_raw_string_hashes.rs | 19 + tests/ui/needless_raw_string_hashes.stderr | 58 + tests/ui/never_loop.rs | 38 + tests/ui/never_loop.stderr | 46 +- tests/ui/no_effect.rs | 3 +- tests/ui/no_effect.stderr | 58 +- tests/ui/no_effect_return.rs | 81 ++ tests/ui/no_effect_return.stderr | 70 ++ tests/ui/non_expressive_names.rs | 12 +- tests/ui/non_expressive_names.stderr | 6 +- tests/ui/non_octal_unix_permissions.fixed | 2 +- tests/ui/non_octal_unix_permissions.rs | 2 +- tests/ui/nonminimal_bool.rs | 3 +- tests/ui/nonminimal_bool.stderr | 26 +- tests/ui/nonminimal_bool_methods.fixed | 2 +- tests/ui/nonminimal_bool_methods.rs | 2 +- tests/ui/octal_escapes.stderr | 6 +- tests/ui/ok_expect.rs | 2 + tests/ui/ok_expect.stderr | 10 +- tests/ui/option_as_ref_deref.fixed | 2 +- tests/ui/option_as_ref_deref.rs | 2 +- tests/ui/option_env_unwrap.rs | 2 +- tests/ui/option_if_let_else.fixed | 16 + tests/ui/option_if_let_else.rs | 22 + tests/ui/option_if_let_else.stderr | 20 +- tests/ui/or_fun_call.fixed | 8 +- tests/ui/or_fun_call.rs | 8 +- tests/ui/or_fun_call.stderr | 56 +- tests/ui/or_then_unwrap.fixed | 2 +- tests/ui/or_then_unwrap.rs | 2 +- tests/ui/overflow_check_conditional.rs | 1 + tests/ui/overflow_check_conditional.stderr | 16 +- tests/ui/partialeq_to_none.fixed | 2 +- tests/ui/partialeq_to_none.rs | 2 +- tests/ui/patterns.fixed | 11 + tests/ui/patterns.rs | 11 + tests/ui/patterns.stderr | 6 +- tests/ui/print_with_newline.fixed | 58 + tests/ui/print_with_newline.rs | 2 +- tests/ui/print_with_newline.stderr | 12 +- tests/ui/proc_macro.rs | 1 - tests/ui/proc_macro.stderr | 2 +- tests/ui/ptr_arg.rs | 33 +- tests/ui/ptr_arg.stderr | 60 +- tests/ui/ptr_as_ptr.fixed | 2 +- tests/ui/ptr_as_ptr.rs | 2 +- tests/ui/ptr_cast_constness.fixed | 21 +- tests/ui/ptr_cast_constness.rs | 31 +- tests/ui/ptr_cast_constness.stderr | 46 +- tests/ui/ptr_offset_with_cast.fixed | 2 +- tests/ui/ptr_offset_with_cast.rs | 2 +- tests/ui/pub_with_shorthand.fixed | 38 + tests/ui/pub_with_shorthand.rs | 38 + tests/ui/pub_with_shorthand.stderr | 28 + tests/ui/pub_without_shorthand.fixed | 38 + tests/ui/pub_without_shorthand.rs | 38 + tests/ui/pub_without_shorthand.stderr | 22 + tests/ui/question_mark.fixed | 22 + tests/ui/question_mark.rs | 26 + tests/ui/question_mark.stderr | 42 +- tests/ui/range.rs | 1 + tests/ui/range.stderr | 2 +- tests/ui/rc_clone_in_vec_init/arc.rs | 1 + tests/ui/rc_clone_in_vec_init/arc.stderr | 8 +- tests/ui/rc_clone_in_vec_init/rc.rs | 1 + tests/ui/rc_clone_in_vec_init/rc.stderr | 8 +- tests/ui/rc_clone_in_vec_init/weak.rs | 1 + tests/ui/rc_clone_in_vec_init/weak.stderr | 16 +- tests/ui/redundant_at_rest_pattern.fixed | 27 + tests/ui/redundant_at_rest_pattern.rs | 27 + tests/ui/redundant_at_rest_pattern.stderr | 40 + tests/ui/redundant_clone.fixed | 8 +- tests/ui/redundant_clone.rs | 8 +- tests/ui/redundant_clone.stderr | 60 +- tests/ui/redundant_closure_call_fixable.fixed | 47 + tests/ui/redundant_closure_call_fixable.rs | 47 + .../ui/redundant_closure_call_fixable.stderr | 62 +- ...edundant_pattern_matching_drop_order.fixed | 7 +- .../redundant_pattern_matching_drop_order.rs | 7 +- ...dundant_pattern_matching_drop_order.stderr | 44 +- .../redundant_pattern_matching_ipaddr.fixed | 1 + tests/ui/redundant_pattern_matching_ipaddr.rs | 1 + .../redundant_pattern_matching_ipaddr.stderr | 36 +- .../redundant_pattern_matching_option.fixed | 1 + tests/ui/redundant_pattern_matching_option.rs | 1 + .../redundant_pattern_matching_option.stderr | 56 +- .../ui/redundant_pattern_matching_poll.fixed | 1 + tests/ui/redundant_pattern_matching_poll.rs | 1 + .../ui/redundant_pattern_matching_poll.stderr | 36 +- .../redundant_pattern_matching_result.fixed | 1 + tests/ui/redundant_pattern_matching_result.rs | 1 + .../redundant_pattern_matching_result.stderr | 56 +- tests/ui/redundant_pub_crate.fixed | 8 +- tests/ui/redundant_pub_crate.rs | 8 +- tests/ui/redundant_static_lifetimes.fixed | 22 +- tests/ui/redundant_static_lifetimes.rs | 22 +- tests/ui/redundant_static_lifetimes.stderr | 24 +- .../ui/redundant_static_lifetimes_multiple.rs | 6 +- ...redundant_static_lifetimes_multiple.stderr | 12 +- tests/ui/redundant_type_annotations.rs | 176 +++ tests/ui/redundant_type_annotations.stderr | 106 ++ tests/ui/regex.rs | 7 +- tests/ui/regex.stderr | 52 +- tests/ui/rename.fixed | 6 +- tests/ui/rename.rs | 6 +- tests/ui/rename.stderr | 114 +- tests/ui/same_functions_in_if_condition.rs | 12 +- .../ui/same_functions_in_if_condition.stderr | 4 +- tests/ui/search_is_some.rs | 1 + tests/ui/search_is_some.stderr | 16 +- tests/ui/search_is_some_fixable_none.fixed | 2 +- tests/ui/search_is_some_fixable_none.rs | 2 +- tests/ui/search_is_some_fixable_some.fixed | 2 +- tests/ui/search_is_some_fixable_some.rs | 2 +- tests/ui/self_assignment.rs | 1 + tests/ui/self_assignment.stderr | 22 +- tests/ui/shadow.rs | 4 +- tests/ui/significant_drop_in_scrutinee.fixed | 627 ++++++++++ tests/ui/significant_drop_tightening.fixed | 12 + tests/ui/significant_drop_tightening.rs | 12 + tests/ui/significant_drop_tightening.stderr | 6 +- tests/ui/single_call_fn.rs | 74 ++ tests/ui/single_call_fn.stderr | 55 + tests/ui/single_char_add_str.fixed | 1 + tests/ui/single_char_add_str.rs | 1 + tests/ui/single_char_add_str.stderr | 30 +- tests/ui/single_char_pattern.fixed | 2 +- tests/ui/single_char_pattern.rs | 2 +- tests/ui/single_char_pattern.stderr | 4 +- tests/ui/single_element_loop.fixed | 2 + tests/ui/single_element_loop.rs | 2 + tests/ui/single_element_loop.stderr | 14 +- tests/ui/single_match.fixed | 47 +- tests/ui/single_match.rs | 47 +- tests/ui/single_match.stderr | 36 +- tests/ui/single_match_else.fixed | 2 +- tests/ui/single_match_else.rs | 2 +- tests/ui/single_range_in_vec_init.rs | 58 + tests/ui/single_range_in_vec_init.stderr | 145 +++ tests/ui/skip_while_next.rs | 2 +- tests/ui/stable_sort_primitive.fixed | 1 + tests/ui/stable_sort_primitive.rs | 1 + tests/ui/stable_sort_primitive.stderr | 14 +- tests/ui/starts_ends_with.fixed | 2 +- tests/ui/starts_ends_with.rs | 2 +- tests/ui/string_add.rs | 2 +- tests/ui/string_lit_as_bytes.fixed | 2 +- tests/ui/string_lit_as_bytes.rs | 2 +- tests/ui/suspicious_else_formatting.rs | 16 +- tests/ui/suspicious_else_formatting.stderr | 18 +- tests/ui/suspicious_unary_op_formatting.rs | 1 + .../ui/suspicious_unary_op_formatting.stderr | 8 +- tests/ui/swap.fixed | 3 +- tests/ui/swap.rs | 3 +- tests/ui/swap.stderr | 34 +- tests/ui/tests_outside_test_module.rs | 1 - tests/ui/tests_outside_test_module.stderr | 2 +- ...to_string_in_format_args_incremental.fixed | 9 + .../to_string_in_format_args_incremental.rs | 9 + ...o_string_in_format_args_incremental.stderr | 10 + tests/ui/toplevel_ref_arg.fixed | 4 +- tests/ui/toplevel_ref_arg.rs | 4 +- tests/ui/toplevel_ref_arg_non_rustfix.rs | 2 +- tests/ui/transmute_ptr_to_ptr.rs | 2 +- tests/ui/transmute_ptr_to_ref.fixed | 5 +- tests/ui/transmute_ptr_to_ref.rs | 5 +- tests/ui/transmute_ptr_to_ref.stderr | 48 +- tests/ui/try_err.fixed | 2 +- tests/ui/try_err.rs | 2 +- tests/ui/tuple_array_conversions.rs | 73 ++ tests/ui/tuple_array_conversions.stderr | 83 ++ tests/ui/type_complexity.rs | 2 +- tests/ui/type_repetition_in_bounds.rs | 39 + tests/ui/type_repetition_in_bounds.stderr | 18 +- tests/ui/undocumented_unsafe_blocks.rs | 24 +- tests/ui/undocumented_unsafe_blocks.stderr | 26 +- tests/ui/unicode.fixed | 1 - tests/ui/unicode.rs | 1 - tests/ui/unicode.stderr | 20 +- tests/ui/uninlined_format_args.fixed | 9 +- tests/ui/uninlined_format_args.rs | 9 +- tests/ui/uninlined_format_args.stderr | 142 +-- tests/ui/unit_arg.rs | 2 +- tests/ui/unit_cmp.rs | 3 +- tests/ui/unit_cmp.stderr | 12 +- tests/ui/unit_return_expecting_ord.rs | 1 + tests/ui/unit_return_expecting_ord.stderr | 12 +- tests/ui/unnecessary_cast.fixed | 81 +- tests/ui/unnecessary_cast.rs | 81 +- tests/ui/unnecessary_cast.stderr | 112 +- tests/ui/unnecessary_fold.fixed | 24 + tests/ui/unnecessary_fold.rs | 24 + tests/ui/unnecessary_fold.stderr | 56 +- tests/ui/unnecessary_join.fixed | 2 +- tests/ui/unnecessary_join.rs | 2 +- tests/ui/unnecessary_lazy_eval.fixed | 30 +- tests/ui/unnecessary_lazy_eval.rs | 30 +- tests/ui/unnecessary_lazy_eval.stderr | 102 +- tests/ui/unnecessary_lazy_eval_unfixable.rs | 1 + .../ui/unnecessary_lazy_eval_unfixable.stderr | 6 +- tests/ui/unnecessary_literal_unwrap.fixed | 78 ++ tests/ui/unnecessary_literal_unwrap.rs | 78 ++ tests/ui/unnecessary_literal_unwrap.stderr | 413 +++++++ .../unnecessary_literal_unwrap_unfixable.rs | 116 ++ ...nnecessary_literal_unwrap_unfixable.stderr | 603 ++++++++++ tests/ui/unnecessary_safety_comment.rs | 2 +- tests/ui/unnecessary_sort_by.fixed | 2 +- tests/ui/unnecessary_sort_by.rs | 2 +- .../unnecessary_struct_initialization.fixed | 2 +- tests/ui/unnecessary_struct_initialization.rs | 2 +- tests/ui/unnecessary_to_owned.fixed | 35 +- tests/ui/unnecessary_to_owned.rs | 35 +- tests/ui/unnecessary_unsafety_doc.rs | 2 +- tests/ui/unneeded_field_pattern.rs | 14 +- tests/ui/unneeded_field_pattern.stderr | 4 +- tests/ui/unneeded_wildcard_pattern.fixed | 9 + tests/ui/unneeded_wildcard_pattern.rs | 9 + tests/ui/unneeded_wildcard_pattern.stderr | 30 +- tests/ui/unnested_or_patterns.fixed | 8 +- tests/ui/unnested_or_patterns.rs | 8 +- tests/ui/unnested_or_patterns.stderr | 34 +- tests/ui/unnested_or_patterns2.fixed | 7 +- tests/ui/unnested_or_patterns2.rs | 7 +- tests/ui/unnested_or_patterns2.stderr | 16 +- tests/ui/unseparated_prefix_literals.fixed | 2 +- tests/ui/unseparated_prefix_literals.rs | 2 +- tests/ui/unused_async.rs | 14 + tests/ui/unused_async.stderr | 8 +- tests/ui/unwrap.rs | 1 + tests/ui/unwrap.stderr | 6 +- tests/ui/unwrap_expect_used.rs | 1 + tests/ui/unwrap_expect_used.stderr | 12 +- tests/ui/unwrap_or.rs | 1 + tests/ui/unwrap_or.stderr | 4 +- tests/ui/unwrap_or_else_default.fixed | 2 +- tests/ui/unwrap_or_else_default.rs | 2 +- tests/ui/update-all-references.sh | 2 +- tests/ui/use_self.fixed | 2 +- tests/ui/use_self.rs | 2 +- tests/ui/used_underscore_binding.rs | 2 +- tests/ui/useless_attribute.fixed | 2 +- tests/ui/useless_attribute.rs | 2 +- tests/ui/useless_conversion.fixed | 31 +- tests/ui/useless_conversion.rs | 31 +- tests/ui/useless_conversion.stderr | 62 +- tests/ui/useless_conversion_try.rs | 1 + tests/ui/useless_conversion_try.stderr | 18 +- tests/ui/vec.fixed | 82 +- tests/ui/vec.rs | 82 +- tests/ui/vec.stderr | 56 +- tests/ui/while_let_on_iterator.fixed | 4 +- tests/ui/while_let_on_iterator.rs | 4 +- tests/ui/while_let_on_iterator.stderr | 52 +- tests/ui/wildcard_imports.fixed | 2 +- tests/ui/wildcard_imports.rs | 2 +- tests/ui/wildcard_imports.stderr | 4 +- tests/ui/write_literal_2.rs | 2 +- tests/ui/write_literal_2.stderr | 32 +- tests/ui/write_with_newline.fixed | 63 + tests/ui/write_with_newline.stderr | 12 +- tests/workspace.rs | 40 + tests/workspace_test/Cargo.toml | 2 +- .../pass_mod_with_dep_in_subdir/Cargo.toml | 10 + .../dep_no_mod/Cargo.toml | 9 + .../dep_no_mod/src/foo.rs | 2 + .../dep_no_mod/src/foo/hello.rs | 1 + .../dep_no_mod/src/lib.rs | 5 + .../src/bad/mod.rs | 1 + .../pass_mod_with_dep_in_subdir/src/main.rs | 13 + .../src/more/foo.rs | 1 + .../src/more/inner/mod.rs | 1 + .../src/more/mod.rs | 2 + .../pass_no_mod_with_dep_in_subdir/Cargo.toml | 10 + .../dep_with_mod/Cargo.toml | 9 + .../dep_with_mod/src/lib.rs | 7 + .../dep_with_mod/src/with_mod/inner.rs | 1 + .../dep_with_mod/src/with_mod/inner/stuff.rs | 3 + .../src/with_mod/inner/stuff/most.rs | 1 + .../dep_with_mod/src/with_mod/mod.rs | 3 + .../src/good.rs | 1 + .../src/main.rs | 9 + util/etc/vscode-tasks.json | 4 +- util/gh-pages/index.html | 9 +- util/gh-pages/script.js | 204 +++- util/gh-pages/versions.html | 9 +- util/versions.py | 25 +- 912 files changed, 21813 insertions(+), 5843 deletions(-) delete mode 100644 clippy_dev/src/bless.rs create mode 100644 clippy_lints/src/arc_with_non_send_sync.rs create mode 100644 clippy_lints/src/endian_bytes.rs create mode 100644 clippy_lints/src/excessive_nesting.rs create mode 100644 clippy_lints/src/incorrect_impls.rs create mode 100644 clippy_lints/src/large_stack_frames.rs create mode 100644 clippy_lints/src/manual_range_patterns.rs delete mode 100644 clippy_lints/src/mem_forget.rs create mode 100644 clippy_lints/src/methods/drain_collect.rs create mode 100644 clippy_lints/src/methods/manual_try_fold.rs create mode 100644 clippy_lints/src/methods/unnecessary_literal_unwrap.rs create mode 100644 clippy_lints/src/min_ident_chars.rs create mode 100644 clippy_lints/src/misc_early/redundant_at_rest_pattern.rs create mode 100644 clippy_lints/src/needless_if.rs create mode 100644 clippy_lints/src/raw_strings.rs create mode 100644 clippy_lints/src/redundant_type_annotations.rs create mode 100644 clippy_lints/src/single_call_fn.rs create mode 100644 clippy_lints/src/single_range_in_vec_init.rs create mode 100644 clippy_lints/src/tuple_array_conversions.rs create mode 100644 clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs create mode 100644 clippy_lints/src/visibility.rs create mode 100644 clippy_test_deps/Cargo.toml create mode 100644 clippy_test_deps/src/lib.rs create mode 100644 tests/headers.rs rename tests/ui-cargo/cargo_common_metadata/fail/{src/main.stderr => Cargo.stderr} (74%) rename tests/ui-cargo/cargo_common_metadata/fail_publish/{src/main.stderr => Cargo.stderr} (74%) rename tests/ui-cargo/cargo_common_metadata/fail_publish_true/{src/main.stderr => Cargo.stderr} (74%) create mode 100644 tests/ui-cargo/cargo_rust_version/fail_both_diff/Cargo.stderr delete mode 100644 tests/ui-cargo/cargo_rust_version/fail_both_diff/src/main.stderr create mode 100644 tests/ui-cargo/cargo_rust_version/fail_both_same/Cargo.stderr create mode 100644 tests/ui-cargo/cargo_rust_version/fail_cargo/Cargo.stderr delete mode 100644 tests/ui-cargo/cargo_rust_version/fail_cargo/src/main.stderr create mode 100644 tests/ui-cargo/cargo_rust_version/fail_clippy/Cargo.stderr delete mode 100644 tests/ui-cargo/cargo_rust_version/fail_clippy/src/main.stderr rename tests/ui-cargo/cargo_rust_version/{fail_both_same/src/main.stderr => fail_file_attr/Cargo.stderr} (56%) delete mode 100644 tests/ui-cargo/cargo_rust_version/fail_file_attr/src/main.stderr rename tests/ui-cargo/cargo_rust_version/warn_both_diff/{src/main.stderr => Cargo.stderr} (77%) create mode 100644 tests/ui-cargo/duplicate_mod/fail/Cargo.stderr delete mode 100644 tests/ui-cargo/duplicate_mod/fail/src/main.stderr create mode 100644 tests/ui-cargo/feature_name/fail/Cargo.stderr delete mode 100644 tests/ui-cargo/feature_name/fail/src/main.stderr create mode 100644 tests/ui-cargo/module_style/fail_mod/Cargo.stderr delete mode 100644 tests/ui-cargo/module_style/fail_mod/src/main.stderr create mode 100644 tests/ui-cargo/module_style/fail_mod_remap/Cargo.stderr delete mode 100644 tests/ui-cargo/module_style/fail_mod_remap/src/main.stderr create mode 100644 tests/ui-cargo/module_style/fail_no_mod/Cargo.stderr delete mode 100644 tests/ui-cargo/module_style/fail_no_mod/src/main.stderr create mode 100644 tests/ui-cargo/multiple_config_files/warn/Cargo.stderr delete mode 100644 tests/ui-cargo/multiple_config_files/warn/src/main.stderr create mode 100644 tests/ui-cargo/multiple_crate_versions/fail/Cargo.stderr delete mode 100644 tests/ui-cargo/multiple_crate_versions/fail/src/main.stderr create mode 100644 tests/ui-cargo/wildcard_dependencies/fail/Cargo.stderr delete mode 100644 tests/ui-cargo/wildcard_dependencies/fail/src/main.stderr create mode 100644 tests/ui-internal/check_formulation.rs create mode 100644 tests/ui-internal/check_formulation.stderr create mode 100644 tests/ui-toml/excessive_nesting/auxiliary/proc_macros.rs create mode 100644 tests/ui-toml/excessive_nesting/clippy.toml create mode 100644 tests/ui-toml/excessive_nesting/excessive_nesting.rs create mode 100644 tests/ui-toml/excessive_nesting/excessive_nesting.stderr create mode 100644 tests/ui-toml/min_ident_chars/auxiliary/extern_types.rs create mode 100644 tests/ui-toml/min_ident_chars/clippy.toml create mode 100644 tests/ui-toml/min_ident_chars/min_ident_chars.rs create mode 100644 tests/ui-toml/min_ident_chars/min_ident_chars.stderr create mode 100644 tests/ui-toml/module_inception/clippy.toml create mode 100644 tests/ui-toml/module_inception/module_inception.rs create mode 100644 tests/ui-toml/module_inception/module_inception.stderr create mode 100644 tests/ui-toml/undocumented_unsafe_blocks/auxiliary/proc_macro_unsafe.rs create mode 100644 tests/ui-toml/undocumented_unsafe_blocks/clippy.toml create mode 100644 tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs create mode 100644 tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.stderr delete mode 100644 tests/ui/allow_attributes_false_positive.rs create mode 100644 tests/ui/arc_with_non_send_sync.rs create mode 100644 tests/ui/arc_with_non_send_sync.stderr create mode 100644 tests/ui/auxiliary/extern_fake_libc.rs create mode 100644 tests/ui/cfg_features.rs create mode 100644 tests/ui/cfg_features.stderr create mode 100644 tests/ui/crashes/ice-10912.rs create mode 100644 tests/ui/crashes/ice-10912.stderr delete mode 100644 tests/ui/crate_level_checks/entrypoint_recursion.stderr create mode 100644 tests/ui/doc/needless_doctest_main.rs create mode 100644 tests/ui/drain_collect.fixed create mode 100644 tests/ui/drain_collect.rs create mode 100644 tests/ui/drain_collect.stderr create mode 100644 tests/ui/endian_bytes.rs create mode 100644 tests/ui/endian_bytes.stderr create mode 100644 tests/ui/explicit_into_iter_loop.fixed create mode 100644 tests/ui/explicit_into_iter_loop.rs create mode 100644 tests/ui/explicit_into_iter_loop.stderr create mode 100644 tests/ui/explicit_iter_loop.fixed create mode 100644 tests/ui/explicit_iter_loop.rs create mode 100644 tests/ui/explicit_iter_loop.stderr delete mode 100644 tests/ui/for_loop_fixable.fixed delete mode 100644 tests/ui/for_loop_fixable.rs delete mode 100644 tests/ui/for_loop_fixable.stderr delete mode 100644 tests/ui/for_loop_unfixable.rs delete mode 100644 tests/ui/for_loop_unfixable.stderr create mode 100644 tests/ui/incorrect_clone_impl_on_copy_type.fixed create mode 100644 tests/ui/incorrect_clone_impl_on_copy_type.rs create mode 100644 tests/ui/incorrect_clone_impl_on_copy_type.stderr create mode 100644 tests/ui/iter_next_loop.rs create mode 100644 tests/ui/iter_next_loop.stderr create mode 100644 tests/ui/large_stack_frames.rs create mode 100644 tests/ui/large_stack_frames.stderr create mode 100644 tests/ui/manual_range_patterns.fixed create mode 100644 tests/ui/manual_range_patterns.rs create mode 100644 tests/ui/manual_range_patterns.stderr create mode 100644 tests/ui/manual_try_fold.rs create mode 100644 tests/ui/manual_try_fold.stderr create mode 100644 tests/ui/match_same_arms_non_exhaustive.rs create mode 100644 tests/ui/match_same_arms_non_exhaustive.stderr create mode 100644 tests/ui/min_ident_chars.rs create mode 100644 tests/ui/min_ident_chars.stderr create mode 100644 tests/ui/needless_if.fixed create mode 100644 tests/ui/needless_if.rs create mode 100644 tests/ui/needless_if.stderr create mode 100644 tests/ui/needless_pub_self.fixed create mode 100644 tests/ui/needless_pub_self.rs create mode 100644 tests/ui/needless_pub_self.stderr create mode 100644 tests/ui/needless_raw_string.fixed create mode 100644 tests/ui/needless_raw_string.rs create mode 100644 tests/ui/needless_raw_string.stderr create mode 100644 tests/ui/needless_raw_string_hashes.fixed create mode 100644 tests/ui/needless_raw_string_hashes.rs create mode 100644 tests/ui/needless_raw_string_hashes.stderr create mode 100644 tests/ui/no_effect_return.rs create mode 100644 tests/ui/no_effect_return.stderr create mode 100644 tests/ui/print_with_newline.fixed create mode 100644 tests/ui/pub_with_shorthand.fixed create mode 100644 tests/ui/pub_with_shorthand.rs create mode 100644 tests/ui/pub_with_shorthand.stderr create mode 100644 tests/ui/pub_without_shorthand.fixed create mode 100644 tests/ui/pub_without_shorthand.rs create mode 100644 tests/ui/pub_without_shorthand.stderr create mode 100644 tests/ui/redundant_at_rest_pattern.fixed create mode 100644 tests/ui/redundant_at_rest_pattern.rs create mode 100644 tests/ui/redundant_at_rest_pattern.stderr create mode 100644 tests/ui/redundant_type_annotations.rs create mode 100644 tests/ui/redundant_type_annotations.stderr create mode 100644 tests/ui/significant_drop_in_scrutinee.fixed create mode 100644 tests/ui/single_call_fn.rs create mode 100644 tests/ui/single_call_fn.stderr create mode 100644 tests/ui/single_range_in_vec_init.rs create mode 100644 tests/ui/single_range_in_vec_init.stderr create mode 100644 tests/ui/to_string_in_format_args_incremental.fixed create mode 100644 tests/ui/to_string_in_format_args_incremental.rs create mode 100644 tests/ui/to_string_in_format_args_incremental.stderr create mode 100644 tests/ui/tuple_array_conversions.rs create mode 100644 tests/ui/tuple_array_conversions.stderr create mode 100644 tests/ui/unnecessary_literal_unwrap.fixed create mode 100644 tests/ui/unnecessary_literal_unwrap.rs create mode 100644 tests/ui/unnecessary_literal_unwrap.stderr create mode 100644 tests/ui/unnecessary_literal_unwrap_unfixable.rs create mode 100644 tests/ui/unnecessary_literal_unwrap_unfixable.stderr create mode 100644 tests/ui/write_with_newline.fixed create mode 100644 tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/Cargo.toml create mode 100644 tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/dep_no_mod/Cargo.toml create mode 100644 tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/dep_no_mod/src/foo.rs create mode 100644 tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/dep_no_mod/src/foo/hello.rs create mode 100644 tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/dep_no_mod/src/lib.rs create mode 100644 tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/src/bad/mod.rs create mode 100644 tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/src/main.rs create mode 100644 tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/src/more/foo.rs create mode 100644 tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/src/more/inner/mod.rs create mode 100644 tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/src/more/mod.rs create mode 100644 tests/workspace_test/module_style/pass_no_mod_with_dep_in_subdir/Cargo.toml create mode 100644 tests/workspace_test/module_style/pass_no_mod_with_dep_in_subdir/dep_with_mod/Cargo.toml create mode 100644 tests/workspace_test/module_style/pass_no_mod_with_dep_in_subdir/dep_with_mod/src/lib.rs create mode 100644 tests/workspace_test/module_style/pass_no_mod_with_dep_in_subdir/dep_with_mod/src/with_mod/inner.rs create mode 100644 tests/workspace_test/module_style/pass_no_mod_with_dep_in_subdir/dep_with_mod/src/with_mod/inner/stuff.rs create mode 100644 tests/workspace_test/module_style/pass_no_mod_with_dep_in_subdir/dep_with_mod/src/with_mod/inner/stuff/most.rs create mode 100644 tests/workspace_test/module_style/pass_no_mod_with_dep_in_subdir/dep_with_mod/src/with_mod/mod.rs create mode 100644 tests/workspace_test/module_style/pass_no_mod_with_dep_in_subdir/src/good.rs create mode 100644 tests/workspace_test/module_style/pass_no_mod_with_dep_in_subdir/src/main.rs diff --git a/.cargo/config.toml b/.cargo/config.toml index 4d80d3ce63da..48a63e485681 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,5 +1,7 @@ [alias] uitest = "test --test compile-test" +uibless = "test --test compile-test -- -- --bless" +bless = "test -- -- --bless" dev = "run --package clippy_dev --bin clippy_dev --manifest-path clippy_dev/Cargo.toml --" lintcheck = "run --package lintcheck --bin lintcheck --manifest-path lintcheck/Cargo.toml -- " collect-metadata = "test --test dogfood --features internal -- run_metadata_collection_lint --ignored" diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml index a9d42159c4ba..c582c28cd3cf 100644 --- a/.github/workflows/clippy.yml +++ b/.github/workflows/clippy.yml @@ -25,7 +25,6 @@ env: CARGO_TARGET_DIR: '${{ github.workspace }}/target' NO_FMT_TEST: 1 CARGO_INCREMENTAL: 0 - CARGO_UNSTABLE_SPARSE_REGISTRY: true jobs: base: diff --git a/.github/workflows/clippy_bors.yml b/.github/workflows/clippy_bors.yml index 30a156c925b0..d5ab313ba0e6 100644 --- a/.github/workflows/clippy_bors.yml +++ b/.github/workflows/clippy_bors.yml @@ -11,7 +11,6 @@ env: CARGO_TARGET_DIR: '${{ github.workspace }}/target' NO_FMT_TEST: 1 CARGO_INCREMENTAL: 0 - CARGO_UNSTABLE_SPARSE_REGISTRY: true defaults: run: diff --git a/.github/workflows/clippy_dev.yml b/.github/workflows/clippy_dev.yml index 514706d64c8c..0f0e3f2db925 100644 --- a/.github/workflows/clippy_dev.yml +++ b/.github/workflows/clippy_dev.yml @@ -16,7 +16,6 @@ on: env: RUST_BACKTRACE: 1 CARGO_INCREMENTAL: 0 - CARGO_UNSTABLE_SPARSE_REGISTRY: true jobs: clippy_dev: diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b609b47d819..14d822083d8b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,9 +10,9 @@ document. ## Rust 1.70 -Current beta, released 2023-06-01 +Current stable, released 2023-06-01 -[149392b0...83e42a23](https://github.com/rust-lang/rust-clippy/compare/149392b0...83e42a23) +[**View 85 PRs merged since 1.69**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2023-04-20..2023-06-01+base%3Amaster+sort%3Amerged-desc+) ### New Lints @@ -95,7 +95,7 @@ Current beta, released 2023-06-01 [#10375](https://github.com/rust-lang/rust-clippy/pull/10375) * [`mem_replace_option_with_none`]: No longer lints on field expressions [#10594](https://github.com/rust-lang/rust-clippy/pull/10594) -* [`items_after_statements`]: No longer lints on times from macros +* [`items_after_statements`]: No longer lints on items from macros [#10542](https://github.com/rust-lang/rust-clippy/pull/10542) * [`print_literal`], [`write_literal`]: No longer lint strings coming from the `file!()` macro [#10573](https://github.com/rust-lang/rust-clippy/pull/10573) @@ -135,9 +135,9 @@ Current beta, released 2023-06-01 ## Rust 1.69 -Current stable, released 2023-04-20 +Released 2023-04-20 -[7f27e2e7...149392b0](https://github.com/rust-lang/rust-clippy/compare/7f27e2e7...149392b0) +[**View 86 PRs merged since 1.68**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2023-03-09..2023-04-20+base%3Amaster+sort%3Amerged-desc+) ### New Lints @@ -252,7 +252,7 @@ Current stable, released 2023-04-20 Released 2023-03-09 -[d822110d...7f27e2e7](https://github.com/rust-lang/rust-clippy/compare/d822110d...7f27e2e7) +[**View 85 PRs merged since 1.67**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2023-01-26..2023-03-09+base%3Amaster+sort%3Amerged-desc+) ### New Lints @@ -399,7 +399,7 @@ Released 2023-03-09 Released 2023-01-26 -[4f142aa1...d822110d](https://github.com/rust-lang/rust-clippy/compare/4f142aa1...d822110d) +[**View 68 PRs merged since 1.66**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2022-12-15..2023-01-26+base%3Amaster+sort%3Amerged-desc+) ### New Lints @@ -590,7 +590,8 @@ Released 2023-01-26 Released 2022-12-15 -[b52fb523...4f142aa1](https://github.com/rust-lang/rust-clippy/compare/b52fb523...4f142aa1) +[**View 93 PRs merged since 1.65**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2022-11-03..2022-12-15+base%3Amaster+sort%3Amerged-desc+) + ### New Lints @@ -761,7 +762,8 @@ Released 2022-12-15 Released 2022-11-03 -[3c7e7dbc...b52fb523](https://github.com/rust-lang/rust-clippy/compare/3c7e7dbc...b52fb523) +[**View 129 PRs merged since 1.64**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2022-09-22..2022-11-03+base%3Amaster+sort%3Amerged-desc+) + ### Important Changes @@ -905,7 +907,8 @@ Released 2022-11-03 Released 2022-09-22 -[d7b5cbf0...3c7e7dbc](https://github.com/rust-lang/rust-clippy/compare/d7b5cbf0...3c7e7dbc) +[**View 92 PRs merged since 1.63**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2022-08-11..2022-09-22+base%3Amaster+sort%3Amerged-desc+) + ### New Lints @@ -1055,7 +1058,8 @@ Released 2022-09-22 Released 2022-08-11 -[7c21f91b...d7b5cbf0](https://github.com/rust-lang/rust-clippy/compare/7c21f91b...d7b5cbf0) +[**View 100 PRs merged since 1.62**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2022-06-30..2022-08-11+base%3Amaster+sort%3Amerged-desc+) + ### New Lints @@ -1201,7 +1205,8 @@ Released 2022-08-11 Released 2022-06-30 -[d0cf3481...7c21f91b](https://github.com/rust-lang/rust-clippy/compare/d0cf3481...7c21f91b) +[**View 104 PRs merged since 1.61**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2022-05-19..2022-06-30+base%3Amaster+sort%3Amerged-desc+) + ### New Lints @@ -1358,7 +1363,8 @@ Released 2022-06-30 Released 2022-05-19 -[57b3c4b...d0cf3481](https://github.com/rust-lang/rust-clippy/compare/57b3c4b...d0cf3481) +[**View 93 PRs merged since 1.60**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2022-04-07..2022-05-19+base%3Amaster+sort%3Amerged-desc+) + ### New Lints @@ -1459,7 +1465,8 @@ Released 2022-05-19 Released 2022-04-07 -[0eff589...57b3c4b](https://github.com/rust-lang/rust-clippy/compare/0eff589...57b3c4b) +[**View 75 PRs merged since 1.59**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2022-02-24..2022-04-07+base%3Amaster+sort%3Amerged-desc+) + ### New Lints @@ -1591,7 +1598,8 @@ Released 2022-04-07 Released 2022-02-24 -[e181011...0eff589](https://github.com/rust-lang/rust-clippy/compare/e181011...0eff589) +[**View 63 PRs merged since 1.58**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2022-01-13..2022-02-24+base%3Amaster+sort%3Amerged-desc+) + ### New Lints @@ -1755,7 +1763,8 @@ Released 2022-02-24 Released 2022-01-13 -[00e31fa...e181011](https://github.com/rust-lang/rust-clippy/compare/00e31fa...e181011) +[**View 73 PRs merged since 1.57**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2021-12-02..2022-01-13+base%3Amaster+sort%3Amerged-desc+) + ### Rust 1.58.1 @@ -1876,7 +1885,8 @@ Released 2022-01-13 Released 2021-12-02 -[7bfc26e...00e31fa](https://github.com/rust-lang/rust-clippy/compare/7bfc26e...00e31fa) +[**View 92 PRs merged since 1.56**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2021-10-21..2021-12-02+base%3Amaster+sort%3Amerged-desc+) + ### New Lints @@ -2027,7 +2037,7 @@ Released 2021-12-02 Released 2021-10-21 -[74d1561...7bfc26e](https://github.com/rust-lang/rust-clippy/compare/74d1561...7bfc26e) +[**View 92 PRs merged since 1.55**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2021-09-09..2021-10-21+base%3Amaster+sort%3Amerged-desc+) ### New Lints @@ -2093,7 +2103,7 @@ Released 2021-10-21 Released 2021-09-09 -[3ae8faf...74d1561](https://github.com/rust-lang/rust-clippy/compare/3ae8faf...74d1561) +[**View 61 PRs merged since 1.54**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2021-07-29..2021-09-09+base%3Amaster+sort%3Amerged-desc+) ### Important Changes @@ -2211,7 +2221,8 @@ Released 2021-09-09 Released 2021-07-29 -[7c7683c...3ae8faf](https://github.com/rust-lang/rust-clippy/compare/7c7683c...3ae8faf) +[**View 68 PRs merged since 1.53**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2021-06-17..2021-07-29+base%3Amaster+sort%3Amerged-desc+) + ### New Lints @@ -2339,7 +2350,7 @@ Released 2021-07-29 Released 2021-06-17 -[6ed6f1e...7c7683c](https://github.com/rust-lang/rust-clippy/compare/6ed6f1e...7c7683c) +[**View 80 PRs merged since 1.52**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2021-05-06..2021-06-17+base%3Amaster+sort%3Amerged-desc+) ### New Lints @@ -2523,7 +2534,8 @@ Released 2021-06-17 Released 2021-05-06 -[3e41797...6ed6f1e](https://github.com/rust-lang/rust-clippy/compare/3e41797...6ed6f1e) +[**View 113 PRs merged since 1.51**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2021-03-25..2021-05-06+base%3Amaster+sort%3Amerged-desc+) + ### New Lints @@ -2658,7 +2670,8 @@ Released 2021-05-06 Released 2021-03-25 -[4911ab1...3e41797](https://github.com/rust-lang/rust-clippy/compare/4911ab1...3e41797) +[**View 117 PRs merged since 1.50**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2021-02-11..2021-03-25+base%3Amaster+sort%3Amerged-desc+) + ### New Lints @@ -2773,7 +2786,8 @@ Released 2021-03-25 Released 2021-02-11 -[b20d4c1...4bd77a1](https://github.com/rust-lang/rust-clippy/compare/b20d4c1...4bd77a1) +[**View 90 PRs merged since 1.49**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2020-12-31..2021-02-11+base%3Amaster+sort%3Amerged-desc+) + ### New Lints @@ -2902,7 +2916,8 @@ Released 2021-02-11 Released 2020-12-31 -[e636b88...b20d4c1](https://github.com/rust-lang/rust-clippy/compare/e636b88...b20d4c1) +[**View 85 PRs merged since 1.48**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2020-11-19..2020-12-31+base%3Amaster+sort%3Amerged-desc+) + ### New Lints @@ -3008,7 +3023,7 @@ Released 2020-12-31 Released 2020-11-19 -[09bd400...e636b88](https://github.com/rust-lang/rust-clippy/compare/09bd400...e636b88) +[**View 112 PRs merged since 1.47**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2020-10-08..2020-11-19+base%3Amaster+sort%3Amerged-desc+) ### New lints @@ -3126,7 +3141,8 @@ Released 2020-11-19 Released 2020-10-08 -[c2c07fa...09bd400](https://github.com/rust-lang/rust-clippy/compare/c2c07fa...09bd400) +[**View 80 PRs merged since 1.46**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2020-08-27..2020-10-08+base%3Amaster+sort%3Amerged-desc+) + ### New lints @@ -3228,7 +3244,8 @@ Released 2020-10-08 Released 2020-08-27 -[7ea7cd1...c2c07fa](https://github.com/rust-lang/rust-clippy/compare/7ea7cd1...c2c07fa) +[**View 93 PRs merged since 1.45**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2020-07-16..2020-08-27+base%3Amaster+sort%3Amerged-desc+) + ### New lints @@ -3290,7 +3307,8 @@ Released 2020-08-27 Released 2020-07-16 -[891e1a8...7ea7cd1](https://github.com/rust-lang/rust-clippy/compare/891e1a8...7ea7cd1) +[**View 65 PRs merged since 1.44**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2020-06-04..2020-07-16+base%3Amaster+sort%3Amerged-desc+) + ### New lints @@ -3367,7 +3385,8 @@ and [`similar_names`]. [#5651](https://github.com/rust-lang/rust-clippy/pull/565 Released 2020-06-04 -[204bb9b...891e1a8](https://github.com/rust-lang/rust-clippy/compare/204bb9b...891e1a8) +[**View 88 PRs merged since 1.43**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2020-04-23..2020-06-04+base%3Amaster+sort%3Amerged-desc+) + ### New lints @@ -3450,7 +3469,8 @@ Released 2020-06-04 Released 2020-04-23 -[4ee1206...204bb9b](https://github.com/rust-lang/rust-clippy/compare/4ee1206...204bb9b) +[**View 121 PRs merged since 1.42**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2020-03-12..2020-04-23+base%3Amaster+sort%3Amerged-desc+) + ### New lints @@ -3508,7 +3528,7 @@ Released 2020-04-23 Released 2020-03-12 -[69f99e7...4ee1206](https://github.com/rust-lang/rust-clippy/compare/69f99e7...4ee1206) +[**View 106 PRs merged since 1.41**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2020-01-30..2020-03-12+base%3Amaster+sort%3Amerged-desc+) ### New lints @@ -3575,7 +3595,7 @@ Released 2020-03-12 Released 2020-01-30 -[c8e3cfb...69f99e7](https://github.com/rust-lang/rust-clippy/compare/c8e3cfb...69f99e7) +[**View 107 PRs merged since 1.40**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2019-12-19..2020-01-30+base%3Amaster+sort%3Amerged-desc+) * New Lints: * [`exit`] [#4697](https://github.com/rust-lang/rust-clippy/pull/4697) @@ -3620,7 +3640,8 @@ Released 2020-01-30 Released 2019-12-19 -[4e7e71b...c8e3cfb](https://github.com/rust-lang/rust-clippy/compare/4e7e71b...c8e3cfb) +[**View 69 😺 PRs merged since 1.39**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2019-11-07..2019-12-19+base%3Amaster+sort%3Amerged-desc+) + * New Lints: * [`unneeded_wildcard_pattern`] [#4537](https://github.com/rust-lang/rust-clippy/pull/4537) @@ -3662,7 +3683,7 @@ Released 2019-12-19 Released 2019-11-07 -[3aea860...4e7e71b](https://github.com/rust-lang/rust-clippy/compare/3aea860...4e7e71b) +[**View 84 PRs merged since 1.38**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2019-09-26..2019-11-07+base%3Amaster+sort%3Amerged-desc+) * New Lints: * [`uninit_assumed_init`] [#4479](https://github.com/rust-lang/rust-clippy/pull/4479) @@ -3706,7 +3727,7 @@ Released 2019-11-07 Released 2019-09-26 -[e3cb40e...3aea860](https://github.com/rust-lang/rust-clippy/compare/e3cb40e...3aea860) +[**View 102 PRs merged since 1.37**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2019-08-15..2019-09-26+base%3Amaster+sort%3Amerged-desc+) * New Lints: * [`main_recursion`] [#4203](https://github.com/rust-lang/rust-clippy/pull/4203) @@ -3736,7 +3757,7 @@ Released 2019-09-26 Released 2019-08-15 -[082cfa7...e3cb40e](https://github.com/rust-lang/rust-clippy/compare/082cfa7...e3cb40e) +[**View 83 PRs merged since 1.36**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2019-07-04..2019-08-15+base%3Amaster+sort%3Amerged-desc+) * New Lints: * [`checked_conversions`] [#4088](https://github.com/rust-lang/rust-clippy/pull/4088) @@ -3760,7 +3781,8 @@ Released 2019-08-15 Released 2019-07-04 -[eb9f9b1...082cfa7](https://github.com/rust-lang/rust-clippy/compare/eb9f9b1...082cfa7) +[**View 75 PRs merged since 1.35**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2019-05-20..2019-07-04+base%3Amaster+sort%3Amerged-desc+) + * New lints: [`find_map`], [`filter_map_next`] [#4039](https://github.com/rust-lang/rust-clippy/pull/4039) * New lint: [`path_buf_push_overwrite`] [#3954](https://github.com/rust-lang/rust-clippy/pull/3954) @@ -3791,7 +3813,8 @@ Released 2019-07-04 Released 2019-05-20 -[1fac380..37f5c1e](https://github.com/rust-lang/rust-clippy/compare/1fac380...37f5c1e) +[**View 90 PRs merged since 1.34**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2019-04-10..2019-05-20+base%3Amaster+sort%3Amerged-desc+) + * New lint: `drop_bounds` to detect `T: Drop` bounds * Split [`redundant_closure`] into [`redundant_closure`] and [`redundant_closure_for_method_calls`] [#4110](https://github.com/rust-lang/rust-clippy/pull/4101) @@ -3819,7 +3842,8 @@ Released 2019-05-20 Released 2019-04-10 -[1b89724...1fac380](https://github.com/rust-lang/rust-clippy/compare/1b89724...1fac380) +[**View 66 PRs merged since 1.33**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2019-02-26..2019-04-10+base%3Amaster+sort%3Amerged-desc+) + * New lint: [`assertions_on_constants`] to detect for example `assert!(true)` * New lint: [`dbg_macro`] to detect uses of the `dbg!` macro @@ -3849,7 +3873,7 @@ Released 2019-04-10 Released 2019-02-26 -[b2601be...1b89724](https://github.com/rust-lang/rust-clippy/compare/b2601be...1b89724) +[**View 83 PRs merged since 1.32**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2019-01-17..2019-02-26+base%3Amaster+sort%3Amerged-desc+) * New lints: [`implicit_return`], [`vec_box`], [`cast_ref_to_mut`] * The `rust-clippy` repository is now part of the `rust-lang` org. @@ -3882,7 +3906,7 @@ Released 2019-02-26 Released 2019-01-17 -[2e26fdc2...b2601be](https://github.com/rust-lang/rust-clippy/compare/2e26fdc2...b2601be) +[**View 106 PRs merged since 1.31**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2018-12-06..2019-01-17+base%3Amaster+sort%3Amerged-desc+) * New lints: [`slow_vector_initialization`], `mem_discriminant_non_enum`, [`redundant_clone`], [`wildcard_dependencies`], @@ -3912,7 +3936,8 @@ Released 2019-01-17 Released 2018-12-06 -[125907ad..2e26fdc2](https://github.com/rust-lang/rust-clippy/compare/125907ad..2e26fdc2) +[**View 85 PRs merged since 1.30**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2018-10-25..2018-12-06+base%3Amaster+sort%3Amerged-desc+) + * Clippy has been relicensed under a dual MIT / Apache license. See [#3093](https://github.com/rust-lang/rust-clippy/issues/3093) for more @@ -3952,7 +3977,8 @@ Released 2018-12-06 Released 2018-10-25 -[14207503...125907ad](https://github.com/rust-lang/rust-clippy/compare/14207503...125907ad) +[**View 106 PRs merged since 1.29**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2018-09-13..2018-10-25+base%3Amaster+sort%3Amerged-desc+) + * Deprecate `assign_ops` lint * New lints: [`mistyped_literal_suffixes`], [`ptr_offset_with_cast`], @@ -4628,6 +4654,7 @@ Released 2018-09-13 [`almost_complete_range`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_range [`almost_swapped`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_swapped [`approx_constant`]: https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant +[`arc_with_non_send_sync`]: https://rust-lang.github.io/rust-clippy/master/index.html#arc_with_non_send_sync [`arithmetic_side_effects`]: https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects [`as_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_conversions [`as_ptr_cast_mut`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_ptr_cast_mut @@ -4641,6 +4668,7 @@ Released 2018-09-13 [`await_holding_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#await_holding_lock [`await_holding_refcell_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#await_holding_refcell_ref [`bad_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#bad_bit_mask +[`big_endian_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#big_endian_bytes [`bind_instead_of_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#bind_instead_of_map [`blacklisted_name`]: https://rust-lang.github.io/rust-clippy/master/index.html#blacklisted_name [`blanket_clippy_restriction_lints`]: https://rust-lang.github.io/rust-clippy/master/index.html#blanket_clippy_restriction_lints @@ -4735,6 +4763,7 @@ Released 2018-09-13 [`double_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_must_use [`double_neg`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_neg [`double_parens`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_parens +[`drain_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#drain_collect [`drop_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_bounds [`drop_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_copy [`drop_non_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_non_drop @@ -4757,6 +4786,7 @@ Released 2018-09-13 [`erasing_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#erasing_op [`err_expect`]: https://rust-lang.github.io/rust-clippy/master/index.html#err_expect [`eval_order_dependence`]: https://rust-lang.github.io/rust-clippy/master/index.html#eval_order_dependence +[`excessive_nesting`]: https://rust-lang.github.io/rust-clippy/master/index.html#excessive_nesting [`excessive_precision`]: https://rust-lang.github.io/rust-clippy/master/index.html#excessive_precision [`exhaustive_enums`]: https://rust-lang.github.io/rust-clippy/master/index.html#exhaustive_enums [`exhaustive_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#exhaustive_structs @@ -4811,6 +4841,7 @@ Released 2018-09-13 [`get_first`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_first [`get_last_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_last_with_len [`get_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_unwrap +[`host_endian_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#host_endian_bytes [`identity_conversion`]: https://rust-lang.github.io/rust-clippy/master/index.html#identity_conversion [`identity_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#identity_op [`if_let_mutex`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_mutex @@ -4829,6 +4860,7 @@ Released 2018-09-13 [`imprecise_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#imprecise_flops [`inconsistent_digit_grouping`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_digit_grouping [`inconsistent_struct_constructor`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_struct_constructor +[`incorrect_clone_impl_on_copy_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#incorrect_clone_impl_on_copy_type [`index_refutable_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice [`indexing_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing [`ineffective_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#ineffective_bit_mask @@ -4879,6 +4911,7 @@ Released 2018-09-13 [`large_futures`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_futures [`large_include_file`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_include_file [`large_stack_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays +[`large_stack_frames`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_frames [`large_types_passed_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value [`len_without_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_without_is_empty [`len_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_zero @@ -4892,6 +4925,7 @@ Released 2018-09-13 [`let_with_type_underscore`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_with_type_underscore [`lines_filter_map_ok`]: https://rust-lang.github.io/rust-clippy/master/index.html#lines_filter_map_ok [`linkedlist`]: https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist +[`little_endian_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#little_endian_bytes [`logic_bug`]: https://rust-lang.github.io/rust-clippy/master/index.html#logic_bug [`lossy_float_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#lossy_float_literal [`macro_use_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#macro_use_imports @@ -4915,6 +4949,7 @@ Released 2018-09-13 [`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive [`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or [`manual_range_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains +[`manual_range_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_patterns [`manual_rem_euclid`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_rem_euclid [`manual_retain`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_retain [`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic @@ -4924,6 +4959,7 @@ Released 2018-09-13 [`manual_string_new`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_string_new [`manual_strip`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip [`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap +[`manual_try_fold`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_try_fold [`manual_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_unwrap_or [`manual_while_let_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_while_let_some [`many_single_char_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names @@ -4947,11 +4983,13 @@ Released 2018-09-13 [`match_wild_err_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wild_err_arm [`match_wildcard_for_single_variants`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wildcard_for_single_variants [`maybe_infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#maybe_infinite_iter +[`maybe_misused_cfg`]: https://rust-lang.github.io/rust-clippy/master/index.html#maybe_misused_cfg [`mem_discriminant_non_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_discriminant_non_enum [`mem_forget`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_forget [`mem_replace_option_with_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_option_with_none [`mem_replace_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_default [`mem_replace_with_uninit`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_uninit +[`min_ident_chars`]: https://rust-lang.github.io/rust-clippy/master/index.html#min_ident_chars [`min_max`]: https://rust-lang.github.io/rust-clippy/master/index.html#min_max [`misaligned_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#misaligned_transmute [`mismatched_target_os`]: https://rust-lang.github.io/rust-clippy/master/index.html#mismatched_target_os @@ -5002,6 +5040,7 @@ Released 2018-09-13 [`needless_doctest_main`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_doctest_main [`needless_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_else [`needless_for_each`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_for_each +[`needless_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_if [`needless_late_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_late_init [`needless_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes [`needless_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_match @@ -5009,8 +5048,11 @@ Released 2018-09-13 [`needless_option_take`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_option_take [`needless_parens_on_range_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_parens_on_range_literals [`needless_pass_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_value +[`needless_pub_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_pub_self [`needless_question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_question_mark [`needless_range_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_range_loop +[`needless_raw_string_hashes`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_raw_string_hashes +[`needless_raw_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_raw_strings [`needless_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_return [`needless_splitn`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_splitn [`needless_update`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_update @@ -5081,6 +5123,8 @@ Released 2018-09-13 [`ptr_offset_with_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_offset_with_cast [`pub_enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_enum_variant_names [`pub_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_use +[`pub_with_shorthand`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_with_shorthand +[`pub_without_shorthand`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_without_shorthand [`question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#question_mark [`question_mark_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#question_mark_used [`range_minus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_minus_one @@ -5094,6 +5138,7 @@ Released 2018-09-13 [`recursive_format_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#recursive_format_impl [`redundant_allocation`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation [`redundant_async_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_async_block +[`redundant_at_rest_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_at_rest_pattern [`redundant_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_clone [`redundant_closure`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure [`redundant_closure_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure_call @@ -5106,6 +5151,7 @@ Released 2018-09-13 [`redundant_pub_crate`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pub_crate [`redundant_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_slicing [`redundant_static_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes +[`redundant_type_annotations`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_type_annotations [`ref_binding_to_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_binding_to_reference [`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref [`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref @@ -5146,6 +5192,7 @@ Released 2018-09-13 [`significant_drop_in_scrutinee`]: https://rust-lang.github.io/rust-clippy/master/index.html#significant_drop_in_scrutinee [`significant_drop_tightening`]: https://rust-lang.github.io/rust-clippy/master/index.html#significant_drop_tightening [`similar_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#similar_names +[`single_call_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_call_fn [`single_char_add_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_add_str [`single_char_lifetime_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_lifetime_names [`single_char_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_pattern @@ -5154,6 +5201,7 @@ Released 2018-09-13 [`single_element_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_element_loop [`single_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match [`single_match_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match_else +[`single_range_in_vec_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_range_in_vec_init [`size_of_in_element_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#size_of_in_element_count [`size_of_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#size_of_ref [`skip_while_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#skip_while_next @@ -5216,6 +5264,7 @@ Released 2018-09-13 [`trivial_regex`]: https://rust-lang.github.io/rust-clippy/master/index.html#trivial_regex [`trivially_copy_pass_by_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref [`try_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#try_err +[`tuple_array_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#tuple_array_conversions [`type_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_complexity [`type_repetition_in_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds [`unchecked_duration_subtraction`]: https://rust-lang.github.io/rust-clippy/master/index.html#unchecked_duration_subtraction @@ -5238,6 +5287,7 @@ Released 2018-09-13 [`unnecessary_fold`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fold [`unnecessary_join`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_join [`unnecessary_lazy_evaluations`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations +[`unnecessary_literal_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_literal_unwrap [`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 [`unnecessary_owned_empty_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_owned_empty_strings @@ -5311,3 +5361,65 @@ Released 2018-09-13 [`zero_width_space`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_width_space [`zst_offset`]: https://rust-lang.github.io/rust-clippy/master/index.html#zst_offset + +[`arithmetic-side-effects-allowed`]: https://doc.rust-lang.org/clippy/lint_configuration.html#arithmetic-side-effects-allowed +[`arithmetic-side-effects-allowed-binary`]: https://doc.rust-lang.org/clippy/lint_configuration.html#arithmetic-side-effects-allowed-binary +[`arithmetic-side-effects-allowed-unary`]: https://doc.rust-lang.org/clippy/lint_configuration.html#arithmetic-side-effects-allowed-unary +[`avoid-breaking-exported-api`]: https://doc.rust-lang.org/clippy/lint_configuration.html#avoid-breaking-exported-api +[`msrv`]: https://doc.rust-lang.org/clippy/lint_configuration.html#msrv +[`cognitive-complexity-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#cognitive-complexity-threshold +[`excessive-nesting-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#excessive-nesting-threshold +[`disallowed-names`]: https://doc.rust-lang.org/clippy/lint_configuration.html#disallowed-names +[`semicolon-inside-block-ignore-singleline`]: https://doc.rust-lang.org/clippy/lint_configuration.html#semicolon-inside-block-ignore-singleline +[`semicolon-outside-block-ignore-multiline`]: https://doc.rust-lang.org/clippy/lint_configuration.html#semicolon-outside-block-ignore-multiline +[`doc-valid-idents`]: https://doc.rust-lang.org/clippy/lint_configuration.html#doc-valid-idents +[`too-many-arguments-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#too-many-arguments-threshold +[`type-complexity-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#type-complexity-threshold +[`single-char-binding-names-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#single-char-binding-names-threshold +[`too-large-for-stack`]: https://doc.rust-lang.org/clippy/lint_configuration.html#too-large-for-stack +[`enum-variant-name-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enum-variant-name-threshold +[`enum-variant-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enum-variant-size-threshold +[`verbose-bit-mask-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#verbose-bit-mask-threshold +[`literal-representation-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#literal-representation-threshold +[`trivial-copy-size-limit`]: https://doc.rust-lang.org/clippy/lint_configuration.html#trivial-copy-size-limit +[`pass-by-value-size-limit`]: https://doc.rust-lang.org/clippy/lint_configuration.html#pass-by-value-size-limit +[`too-many-lines-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#too-many-lines-threshold +[`array-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#array-size-threshold +[`stack-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#stack-size-threshold +[`vec-box-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#vec-box-size-threshold +[`max-trait-bounds`]: https://doc.rust-lang.org/clippy/lint_configuration.html#max-trait-bounds +[`max-struct-bools`]: https://doc.rust-lang.org/clippy/lint_configuration.html#max-struct-bools +[`max-fn-params-bools`]: https://doc.rust-lang.org/clippy/lint_configuration.html#max-fn-params-bools +[`warn-on-all-wildcard-imports`]: https://doc.rust-lang.org/clippy/lint_configuration.html#warn-on-all-wildcard-imports +[`disallowed-macros`]: https://doc.rust-lang.org/clippy/lint_configuration.html#disallowed-macros +[`disallowed-methods`]: https://doc.rust-lang.org/clippy/lint_configuration.html#disallowed-methods +[`disallowed-types`]: https://doc.rust-lang.org/clippy/lint_configuration.html#disallowed-types +[`unreadable-literal-lint-fractions`]: https://doc.rust-lang.org/clippy/lint_configuration.html#unreadable-literal-lint-fractions +[`upper-case-acronyms-aggressive`]: https://doc.rust-lang.org/clippy/lint_configuration.html#upper-case-acronyms-aggressive +[`matches-for-let-else`]: https://doc.rust-lang.org/clippy/lint_configuration.html#matches-for-let-else +[`cargo-ignore-publish`]: https://doc.rust-lang.org/clippy/lint_configuration.html#cargo-ignore-publish +[`standard-macro-braces`]: https://doc.rust-lang.org/clippy/lint_configuration.html#standard-macro-braces +[`enforced-import-renames`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enforced-import-renames +[`allowed-scripts`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-scripts +[`enable-raw-pointer-heuristic-for-send`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enable-raw-pointer-heuristic-for-send +[`max-suggested-slice-pattern-length`]: https://doc.rust-lang.org/clippy/lint_configuration.html#max-suggested-slice-pattern-length +[`await-holding-invalid-types`]: https://doc.rust-lang.org/clippy/lint_configuration.html#await-holding-invalid-types +[`max-include-file-size`]: https://doc.rust-lang.org/clippy/lint_configuration.html#max-include-file-size +[`allow-expect-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-expect-in-tests +[`allow-unwrap-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-unwrap-in-tests +[`allow-dbg-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-dbg-in-tests +[`allow-print-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-print-in-tests +[`large-error-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#large-error-threshold +[`ignore-interior-mutability`]: https://doc.rust-lang.org/clippy/lint_configuration.html#ignore-interior-mutability +[`allow-mixed-uninlined-format-args`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-mixed-uninlined-format-args +[`suppress-restriction-lint-in-const`]: https://doc.rust-lang.org/clippy/lint_configuration.html#suppress-restriction-lint-in-const +[`missing-docs-in-crate-items`]: https://doc.rust-lang.org/clippy/lint_configuration.html#missing-docs-in-crate-items +[`future-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#future-size-threshold +[`unnecessary-box-size`]: https://doc.rust-lang.org/clippy/lint_configuration.html#unnecessary-box-size +[`allow-private-module-inception`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-private-module-inception +[`allowed-idents-below-min-chars`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-idents-below-min-chars +[`min-ident-chars-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#min-ident-chars-threshold +[`accept-comment-above-statement`]: https://doc.rust-lang.org/clippy/lint_configuration.html#accept-comment-above-statement +[`accept-comment-above-attributes`]: https://doc.rust-lang.org/clippy/lint_configuration.html#accept-comment-above-attributes +[`allow-one-hash-in-raw-strings`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-one-hash-in-raw-strings + diff --git a/Cargo.toml b/Cargo.toml index ca8bf9fac91a..76c804f935e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,27 +27,14 @@ tempfile = { version = "3.2", optional = true } termize = "0.1" [dev-dependencies] -compiletest_rs = { version = "0.10", features = ["tmp"] } +ui_test = "0.11.5" tester = "0.9" regex = "1.5" toml = "0.7.3" walkdir = "2.3" # This is used by the `collect-metadata` alias. filetime = "0.2" - -# UI test dependencies -clap = { version = "4.1.4", features = ["derive"] } -clippy_utils = { path = "clippy_utils" } -derive-new = "0.5" -if_chain = "1.0" itertools = "0.10.1" -quote = "1.0" -serde = { version = "1.0.125", features = ["derive"] } -syn = { version = "2.0", features = ["full"] } -futures = "0.3" -parking_lot = "0.12" -tokio = { version = "1", features = ["io-util"] } -rustc-semver = "1.1" [build-dependencies] rustc_tools_util = "0.3.0" @@ -60,3 +47,7 @@ internal = ["clippy_lints/internal", "tempfile"] [package.metadata.rust-analyzer] # This package uses #[feature(rustc_private)] rustc_private = true + +[[test]] +name = "compile-test" +harness = false diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md index c26aa883ebae..a0db80892502 100644 --- a/book/src/development/adding_lints.md +++ b/book/src/development/adding_lints.md @@ -122,20 +122,17 @@ fn main() { } ``` -Now we can run the test with `TESTNAME=foo_functions cargo uitest`, currently +Now we can run the test with `TESTNAME=foo_functions cargo uibless`, currently this test is meaningless though. While we are working on implementing our lint, we can keep running the UI test. -That allows us to check if the output is turning into what we want. +That allows us to check if the output is turning into what we want by checking the +`.stderr` file that gets updated on every test run. -Once we are satisfied with the output, we need to run `cargo dev bless` to -update the `.stderr` file for our lint. Please note that, we should run -`TESTNAME=foo_functions cargo uitest` every time before running `cargo dev -bless`. Running `TESTNAME=foo_functions cargo uitest` should pass then. When we +Running `TESTNAME=foo_functions cargo uitest` should pass on its own. When we commit our lint, we need to commit the generated `.stderr` files, too. In -general, you should only commit files changed by `cargo dev bless` for the -specific lint you are creating/editing. Note that if the generated files are -empty, they should be removed. +general, you should only commit files changed by `cargo bless` for the +specific lint you are creating/editing. > _Note:_ you can run multiple test files by specifying a comma separated list: > `TESTNAME=foo_functions,test2,test3`. @@ -169,7 +166,7 @@ additionally run [rustfix] for that test. Rustfix will apply the suggestions from the lint to the code of the test file and compare that to the contents of a `.fixed` file. -Use `cargo dev bless` to automatically generate the `.fixed` file after running +Use `cargo bless` to automatically generate the `.fixed` file while running the tests. [rustfix]: https://github.com/rust-lang/rustfix @@ -417,7 +414,7 @@ fn is_foo_fn(fn_kind: FnKind<'_>) -> bool { Now we should also run the full test suite with `cargo test`. At this point running `cargo test` should produce the expected output. Remember to run `cargo -dev bless` to update the `.stderr` file. +bless` to update the `.stderr` file. `cargo test` (as opposed to `cargo uitest`) will also ensure that our lint implementation is not violating any Clippy lints itself. diff --git a/book/src/development/basics.md b/book/src/development/basics.md index 7615dc12f9eb..f4c109ff1191 100644 --- a/book/src/development/basics.md +++ b/book/src/development/basics.md @@ -66,7 +66,7 @@ If the output of a [UI test] differs from the expected output, you can update the reference file with: ```bash -cargo dev bless +cargo bless ``` For example, this is necessary if you fix a typo in an error message of a lint, diff --git a/book/src/development/infrastructure/changelog_update.md b/book/src/development/infrastructure/changelog_update.md index df9b1bbe18f3..52445494436c 100644 --- a/book/src/development/infrastructure/changelog_update.md +++ b/book/src/development/infrastructure/changelog_update.md @@ -56,6 +56,28 @@ and open that file in your editor of choice. When updating the changelog it's also a good idea to make sure that `commit1` is already correct in the current changelog. +#### PR ranges + +We developed the concept of PR ranges to help the user understand the size of a new update. To create a PR range, +get the current release date and the date that the last version was released (YYYY-MM-DD) and use the following link: + +``` +[**View PRs merged since 1.**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A..+base%3Amaster+sort%3Amerged-desc+) +``` + +> Note: Be sure to check click the link and check how many PRs got merged between + +Example: + +``` +[**View 85 PRs merged since 1.69**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2023-04-20..2023-06-01+base%3Amaster+sort%3Amerged-desc+) +``` + +Which renders to: +[**View 85 PRs merged since 1.69**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2023-04-20..2023-06-01+base%3Amaster+sort%3Amerged-desc+) + +Note that **commit ranges should not be included**, only PR ranges. + ### 3. Authoring the final changelog The above script should have dumped all the relevant PRs to the file you diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md index 5646c9b15208..60d7ce6e6155 100644 --- a/book/src/lint_configuration.md +++ b/book/src/lint_configuration.md @@ -3,63 +3,14 @@ This file is generated by `cargo collect-metadata`. Please use that command to update the file and do not edit it by hand. --> -## Lint Configuration Options -|
Option
| Default Value | -|--|--| -| [arithmetic-side-effects-allowed](#arithmetic-side-effects-allowed) | `{}` | -| [arithmetic-side-effects-allowed-binary](#arithmetic-side-effects-allowed-binary) | `[]` | -| [arithmetic-side-effects-allowed-unary](#arithmetic-side-effects-allowed-unary) | `{}` | -| [avoid-breaking-exported-api](#avoid-breaking-exported-api) | `true` | -| [msrv](#msrv) | `None` | -| [cognitive-complexity-threshold](#cognitive-complexity-threshold) | `25` | -| [disallowed-names](#disallowed-names) | `["foo", "baz", "quux"]` | -| [semicolon-inside-block-ignore-singleline](#semicolon-inside-block-ignore-singleline) | `false` | -| [semicolon-outside-block-ignore-multiline](#semicolon-outside-block-ignore-multiline) | `false` | -| [doc-valid-idents](#doc-valid-idents) | `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS", "WebGL", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` | -| [too-many-arguments-threshold](#too-many-arguments-threshold) | `7` | -| [type-complexity-threshold](#type-complexity-threshold) | `250` | -| [single-char-binding-names-threshold](#single-char-binding-names-threshold) | `4` | -| [too-large-for-stack](#too-large-for-stack) | `200` | -| [enum-variant-name-threshold](#enum-variant-name-threshold) | `3` | -| [enum-variant-size-threshold](#enum-variant-size-threshold) | `200` | -| [verbose-bit-mask-threshold](#verbose-bit-mask-threshold) | `1` | -| [literal-representation-threshold](#literal-representation-threshold) | `16384` | -| [trivial-copy-size-limit](#trivial-copy-size-limit) | `None` | -| [pass-by-value-size-limit](#pass-by-value-size-limit) | `256` | -| [too-many-lines-threshold](#too-many-lines-threshold) | `100` | -| [array-size-threshold](#array-size-threshold) | `512000` | -| [vec-box-size-threshold](#vec-box-size-threshold) | `4096` | -| [max-trait-bounds](#max-trait-bounds) | `3` | -| [max-struct-bools](#max-struct-bools) | `3` | -| [max-fn-params-bools](#max-fn-params-bools) | `3` | -| [warn-on-all-wildcard-imports](#warn-on-all-wildcard-imports) | `false` | -| [disallowed-macros](#disallowed-macros) | `[]` | -| [disallowed-methods](#disallowed-methods) | `[]` | -| [disallowed-types](#disallowed-types) | `[]` | -| [unreadable-literal-lint-fractions](#unreadable-literal-lint-fractions) | `true` | -| [upper-case-acronyms-aggressive](#upper-case-acronyms-aggressive) | `false` | -| [matches-for-let-else](#matches-for-let-else) | `WellKnownTypes` | -| [cargo-ignore-publish](#cargo-ignore-publish) | `false` | -| [standard-macro-braces](#standard-macro-braces) | `[]` | -| [enforced-import-renames](#enforced-import-renames) | `[]` | -| [allowed-scripts](#allowed-scripts) | `["Latin"]` | -| [enable-raw-pointer-heuristic-for-send](#enable-raw-pointer-heuristic-for-send) | `true` | -| [max-suggested-slice-pattern-length](#max-suggested-slice-pattern-length) | `3` | -| [await-holding-invalid-types](#await-holding-invalid-types) | `[]` | -| [max-include-file-size](#max-include-file-size) | `1000000` | -| [allow-expect-in-tests](#allow-expect-in-tests) | `false` | -| [allow-unwrap-in-tests](#allow-unwrap-in-tests) | `false` | -| [allow-dbg-in-tests](#allow-dbg-in-tests) | `false` | -| [allow-print-in-tests](#allow-print-in-tests) | `false` | -| [large-error-threshold](#large-error-threshold) | `128` | -| [ignore-interior-mutability](#ignore-interior-mutability) | `["bytes::Bytes"]` | -| [allow-mixed-uninlined-format-args](#allow-mixed-uninlined-format-args) | `true` | -| [suppress-restriction-lint-in-const](#suppress-restriction-lint-in-const) | `false` | -| [missing-docs-in-crate-items](#missing-docs-in-crate-items) | `false` | -| [future-size-threshold](#future-size-threshold) | `16384` | -| [unnecessary-box-size](#unnecessary-box-size) | `128` | +# Lint Configuration Options -### arithmetic-side-effects-allowed +The following list shows each configuration option, along with a description, its default value, an example +and lints affected. + +--- + +## `arithmetic-side-effects-allowed` Suppress checking of the passed type names in all types of operations. If a specific operation is desired, consider using `arithmetic_side_effects_allowed_binary` or `arithmetic_side_effects_allowed_unary` instead. @@ -77,10 +28,12 @@ A type, say `SomeType`, listed in this configuration has the same behavior of **Default Value:** `{}` (`rustc_data_structures::fx::FxHashSet`) -* [arithmetic_side_effects](https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects) +--- +**Affected lints:** +* [`arithmetic_side_effects`](https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects) -### arithmetic-side-effects-allowed-binary +## `arithmetic-side-effects-allowed-binary` Suppress checking of the passed type pair names in binary operations like addition or multiplication. @@ -98,10 +51,12 @@ arithmetic-side-effects-allowed-binary = [["SomeType" , "f32"], ["AnotherType", **Default Value:** `[]` (`Vec<[String; 2]>`) -* [arithmetic_side_effects](https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects) +--- +**Affected lints:** +* [`arithmetic_side_effects`](https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects) -### arithmetic-side-effects-allowed-unary +## `arithmetic-side-effects-allowed-unary` Suppress checking of the passed type names in unary operations like "negation" (`-`). #### Example @@ -112,116 +67,145 @@ arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"] **Default Value:** `{}` (`rustc_data_structures::fx::FxHashSet`) -* [arithmetic_side_effects](https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects) +--- +**Affected lints:** +* [`arithmetic_side_effects`](https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects) -### avoid-breaking-exported-api +## `avoid-breaking-exported-api` Suppress lints whenever the suggested change would cause breakage for other crates. **Default Value:** `true` (`bool`) -* [enum_variant_names](https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names) -* [large_types_passed_by_value](https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value) -* [trivially_copy_pass_by_ref](https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref) -* [unnecessary_wraps](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_wraps) -* [unused_self](https://rust-lang.github.io/rust-clippy/master/index.html#unused_self) -* [upper_case_acronyms](https://rust-lang.github.io/rust-clippy/master/index.html#upper_case_acronyms) -* [wrong_self_convention](https://rust-lang.github.io/rust-clippy/master/index.html#wrong_self_convention) -* [box_collection](https://rust-lang.github.io/rust-clippy/master/index.html#box_collection) -* [redundant_allocation](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation) -* [rc_buffer](https://rust-lang.github.io/rust-clippy/master/index.html#rc_buffer) -* [vec_box](https://rust-lang.github.io/rust-clippy/master/index.html#vec_box) -* [option_option](https://rust-lang.github.io/rust-clippy/master/index.html#option_option) -* [linkedlist](https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist) -* [rc_mutex](https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex) -* [unnecessary_box_returns](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_box_returns) +--- +**Affected lints:** +* [`enum_variant_names`](https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names) +* [`large_types_passed_by_value`](https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value) +* [`trivially_copy_pass_by_ref`](https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref) +* [`unnecessary_wraps`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_wraps) +* [`unused_self`](https://rust-lang.github.io/rust-clippy/master/index.html#unused_self) +* [`upper_case_acronyms`](https://rust-lang.github.io/rust-clippy/master/index.html#upper_case_acronyms) +* [`wrong_self_convention`](https://rust-lang.github.io/rust-clippy/master/index.html#wrong_self_convention) +* [`box_collection`](https://rust-lang.github.io/rust-clippy/master/index.html#box_collection) +* [`redundant_allocation`](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation) +* [`rc_buffer`](https://rust-lang.github.io/rust-clippy/master/index.html#rc_buffer) +* [`vec_box`](https://rust-lang.github.io/rust-clippy/master/index.html#vec_box) +* [`option_option`](https://rust-lang.github.io/rust-clippy/master/index.html#option_option) +* [`linkedlist`](https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist) +* [`rc_mutex`](https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex) +* [`unnecessary_box_returns`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_box_returns) +* [`single_call_fn`](https://rust-lang.github.io/rust-clippy/master/index.html#single_call_fn) -### msrv +## `msrv` The minimum rust version that the project supports **Default Value:** `None` (`Option`) -* [manual_split_once](https://rust-lang.github.io/rust-clippy/master/index.html#manual_split_once) -* [manual_str_repeat](https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat) -* [cloned_instead_of_copied](https://rust-lang.github.io/rust-clippy/master/index.html#cloned_instead_of_copied) -* [redundant_field_names](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names) -* [redundant_static_lifetimes](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes) -* [filter_map_next](https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_next) -* [checked_conversions](https://rust-lang.github.io/rust-clippy/master/index.html#checked_conversions) -* [manual_range_contains](https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains) -* [use_self](https://rust-lang.github.io/rust-clippy/master/index.html#use_self) -* [mem_replace_with_default](https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_default) -* [manual_non_exhaustive](https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive) -* [option_as_ref_deref](https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref) -* [map_unwrap_or](https://rust-lang.github.io/rust-clippy/master/index.html#map_unwrap_or) -* [match_like_matches_macro](https://rust-lang.github.io/rust-clippy/master/index.html#match_like_matches_macro) -* [manual_strip](https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip) -* [missing_const_for_fn](https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn) -* [unnested_or_patterns](https://rust-lang.github.io/rust-clippy/master/index.html#unnested_or_patterns) -* [from_over_into](https://rust-lang.github.io/rust-clippy/master/index.html#from_over_into) -* [ptr_as_ptr](https://rust-lang.github.io/rust-clippy/master/index.html#ptr_as_ptr) -* [if_then_some_else_none](https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none) -* [approx_constant](https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant) -* [deprecated_cfg_attr](https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_cfg_attr) -* [index_refutable_slice](https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice) -* [map_clone](https://rust-lang.github.io/rust-clippy/master/index.html#map_clone) -* [borrow_as_ptr](https://rust-lang.github.io/rust-clippy/master/index.html#borrow_as_ptr) -* [manual_bits](https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits) -* [err_expect](https://rust-lang.github.io/rust-clippy/master/index.html#err_expect) -* [cast_abs_to_unsigned](https://rust-lang.github.io/rust-clippy/master/index.html#cast_abs_to_unsigned) -* [uninlined_format_args](https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args) -* [manual_clamp](https://rust-lang.github.io/rust-clippy/master/index.html#manual_clamp) -* [manual_let_else](https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else) -* [unchecked_duration_subtraction](https://rust-lang.github.io/rust-clippy/master/index.html#unchecked_duration_subtraction) -* [collapsible_str_replace](https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_str_replace) -* [seek_from_current](https://rust-lang.github.io/rust-clippy/master/index.html#seek_from_current) -* [seek_rewind](https://rust-lang.github.io/rust-clippy/master/index.html#seek_rewind) -* [unnecessary_lazy_evaluations](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations) -* [transmute_ptr_to_ref](https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref) -* [almost_complete_range](https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_range) -* [needless_borrow](https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow) -* [derivable_impls](https://rust-lang.github.io/rust-clippy/master/index.html#derivable_impls) -* [manual_is_ascii_check](https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check) -* [manual_rem_euclid](https://rust-lang.github.io/rust-clippy/master/index.html#manual_rem_euclid) -* [manual_retain](https://rust-lang.github.io/rust-clippy/master/index.html#manual_retain) +--- +**Affected lints:** +* [`manual_split_once`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_split_once) +* [`manual_str_repeat`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat) +* [`cloned_instead_of_copied`](https://rust-lang.github.io/rust-clippy/master/index.html#cloned_instead_of_copied) +* [`redundant_field_names`](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names) +* [`option_map_unwrap_or`](https://rust-lang.github.io/rust-clippy/master/index.html#option_map_unwrap_or) +* [`redundant_static_lifetimes`](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes) +* [`filter_map_next`](https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_next) +* [`checked_conversions`](https://rust-lang.github.io/rust-clippy/master/index.html#checked_conversions) +* [`manual_range_contains`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains) +* [`use_self`](https://rust-lang.github.io/rust-clippy/master/index.html#use_self) +* [`mem_replace_with_default`](https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_default) +* [`manual_non_exhaustive`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive) +* [`option_as_ref_deref`](https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref) +* [`map_unwrap_or`](https://rust-lang.github.io/rust-clippy/master/index.html#map_unwrap_or) +* [`match_like_matches_macro`](https://rust-lang.github.io/rust-clippy/master/index.html#match_like_matches_macro) +* [`manual_strip`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip) +* [`missing_const_for_fn`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn) +* [`unnested_or_patterns`](https://rust-lang.github.io/rust-clippy/master/index.html#unnested_or_patterns) +* [`from_over_into`](https://rust-lang.github.io/rust-clippy/master/index.html#from_over_into) +* [`ptr_as_ptr`](https://rust-lang.github.io/rust-clippy/master/index.html#ptr_as_ptr) +* [`if_then_some_else_none`](https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none) +* [`approx_constant`](https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant) +* [`deprecated_cfg_attr`](https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_cfg_attr) +* [`index_refutable_slice`](https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice) +* [`map_clone`](https://rust-lang.github.io/rust-clippy/master/index.html#map_clone) +* [`borrow_as_ptr`](https://rust-lang.github.io/rust-clippy/master/index.html#borrow_as_ptr) +* [`manual_bits`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits) +* [`err_expect`](https://rust-lang.github.io/rust-clippy/master/index.html#err_expect) +* [`cast_abs_to_unsigned`](https://rust-lang.github.io/rust-clippy/master/index.html#cast_abs_to_unsigned) +* [`uninlined_format_args`](https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args) +* [`manual_clamp`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_clamp) +* [`manual_let_else`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else) +* [`unchecked_duration_subtraction`](https://rust-lang.github.io/rust-clippy/master/index.html#unchecked_duration_subtraction) +* [`collapsible_str_replace`](https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_str_replace) +* [`seek_from_current`](https://rust-lang.github.io/rust-clippy/master/index.html#seek_from_current) +* [`seek_rewind`](https://rust-lang.github.io/rust-clippy/master/index.html#seek_rewind) +* [`unnecessary_lazy_evaluations`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations) +* [`transmute_ptr_to_ref`](https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref) +* [`almost_complete_range`](https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_range) +* [`needless_borrow`](https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow) +* [`derivable_impls`](https://rust-lang.github.io/rust-clippy/master/index.html#derivable_impls) +* [`manual_is_ascii_check`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check) +* [`manual_rem_euclid`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_rem_euclid) +* [`manual_retain`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_retain) +* [`type_repetition_in_bounds`](https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds) +* [`tuple_array_conversions`](https://rust-lang.github.io/rust-clippy/master/index.html#tuple_array_conversions) +* [`manual_try_fold`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_try_fold) -### cognitive-complexity-threshold +## `cognitive-complexity-threshold` The maximum cognitive complexity a function can have **Default Value:** `25` (`u64`) -* [cognitive_complexity](https://rust-lang.github.io/rust-clippy/master/index.html#cognitive_complexity) +--- +**Affected lints:** +* [`cognitive_complexity`](https://rust-lang.github.io/rust-clippy/master/index.html#cognitive_complexity) -### disallowed-names +## `excessive-nesting-threshold` +The maximum amount of nesting a block can reside in + +**Default Value:** `0` (`u64`) + +--- +**Affected lints:** +* [`excessive_nesting`](https://rust-lang.github.io/rust-clippy/master/index.html#excessive_nesting) + + +## `disallowed-names` The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value `".."` can be used as part of the list to indicate, that the configured values should be appended to the default configuration of Clippy. By default, any configuration will replace the default value. **Default Value:** `["foo", "baz", "quux"]` (`Vec`) -* [disallowed_names](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names) +--- +**Affected lints:** +* [`disallowed_names`](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names) -### semicolon-inside-block-ignore-singleline +## `semicolon-inside-block-ignore-singleline` Whether to lint only if it's multiline. **Default Value:** `false` (`bool`) -* [semicolon_inside_block](https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_inside_block) +--- +**Affected lints:** +* [`semicolon_inside_block`](https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_inside_block) -### semicolon-outside-block-ignore-multiline +## `semicolon-outside-block-ignore-multiline` Whether to lint only if it's singleline. **Default Value:** `false` (`bool`) -* [semicolon_outside_block](https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_outside_block) +--- +**Affected lints:** +* [`semicolon_outside_block`](https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_outside_block) -### doc-valid-idents +## `doc-valid-idents` The list of words this lint should not consider as identifiers needing ticks. The value `".."` can be used as part of the list to indicate, that the configured values should be appended to the default configuration of Clippy. By default, any configuration will replace the default value. For example: @@ -230,207 +214,267 @@ default configuration of Clippy. By default, any configuration will replace the Default list: -**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS", "WebGL", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` (`Vec`) +**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS", "WebGL", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` (`Vec`) -* [doc_markdown](https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown) +--- +**Affected lints:** +* [`doc_markdown`](https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown) -### too-many-arguments-threshold +## `too-many-arguments-threshold` The maximum number of argument a function or method can have **Default Value:** `7` (`u64`) -* [too_many_arguments](https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments) +--- +**Affected lints:** +* [`too_many_arguments`](https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments) -### type-complexity-threshold +## `type-complexity-threshold` The maximum complexity a type can have **Default Value:** `250` (`u64`) -* [type_complexity](https://rust-lang.github.io/rust-clippy/master/index.html#type_complexity) +--- +**Affected lints:** +* [`type_complexity`](https://rust-lang.github.io/rust-clippy/master/index.html#type_complexity) -### single-char-binding-names-threshold +## `single-char-binding-names-threshold` The maximum number of single char bindings a scope may have **Default Value:** `4` (`u64`) -* [many_single_char_names](https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names) +--- +**Affected lints:** +* [`many_single_char_names`](https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names) -### too-large-for-stack +## `too-large-for-stack` The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap **Default Value:** `200` (`u64`) -* [boxed_local](https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local) -* [useless_vec](https://rust-lang.github.io/rust-clippy/master/index.html#useless_vec) +--- +**Affected lints:** +* [`boxed_local`](https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local) +* [`useless_vec`](https://rust-lang.github.io/rust-clippy/master/index.html#useless_vec) -### enum-variant-name-threshold +## `enum-variant-name-threshold` The minimum number of enum variants for the lints about variant names to trigger **Default Value:** `3` (`u64`) -* [enum_variant_names](https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names) +--- +**Affected lints:** +* [`enum_variant_names`](https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names) -### enum-variant-size-threshold +## `enum-variant-size-threshold` The maximum size of an enum's variant to avoid box suggestion **Default Value:** `200` (`u64`) -* [large_enum_variant](https://rust-lang.github.io/rust-clippy/master/index.html#large_enum_variant) +--- +**Affected lints:** +* [`large_enum_variant`](https://rust-lang.github.io/rust-clippy/master/index.html#large_enum_variant) -### verbose-bit-mask-threshold +## `verbose-bit-mask-threshold` The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros' **Default Value:** `1` (`u64`) -* [verbose_bit_mask](https://rust-lang.github.io/rust-clippy/master/index.html#verbose_bit_mask) +--- +**Affected lints:** +* [`verbose_bit_mask`](https://rust-lang.github.io/rust-clippy/master/index.html#verbose_bit_mask) -### literal-representation-threshold +## `literal-representation-threshold` The lower bound for linting decimal literals **Default Value:** `16384` (`u64`) -* [decimal_literal_representation](https://rust-lang.github.io/rust-clippy/master/index.html#decimal_literal_representation) +--- +**Affected lints:** +* [`decimal_literal_representation`](https://rust-lang.github.io/rust-clippy/master/index.html#decimal_literal_representation) -### trivial-copy-size-limit +## `trivial-copy-size-limit` The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by reference. **Default Value:** `None` (`Option`) -* [trivially_copy_pass_by_ref](https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref) +--- +**Affected lints:** +* [`trivially_copy_pass_by_ref`](https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref) -### pass-by-value-size-limit +## `pass-by-value-size-limit` The minimum size (in bytes) to consider a type for passing by reference instead of by value. **Default Value:** `256` (`u64`) -* [large_types_passed_by_value](https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value) +--- +**Affected lints:** +* [`large_types_passed_by_value`](https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value) -### too-many-lines-threshold +## `too-many-lines-threshold` The maximum number of lines a function or method can have **Default Value:** `100` (`u64`) -* [too_many_lines](https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines) +--- +**Affected lints:** +* [`too_many_lines`](https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines) -### array-size-threshold +## `array-size-threshold` The maximum allowed size for arrays on the stack **Default Value:** `512000` (`u64`) -* [large_stack_arrays](https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays) -* [large_const_arrays](https://rust-lang.github.io/rust-clippy/master/index.html#large_const_arrays) +--- +**Affected lints:** +* [`large_stack_arrays`](https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays) +* [`large_const_arrays`](https://rust-lang.github.io/rust-clippy/master/index.html#large_const_arrays) -### vec-box-size-threshold +## `stack-size-threshold` +The maximum allowed stack size for functions in bytes + +**Default Value:** `512000` (`u64`) + +--- +**Affected lints:** +* [`large_stack_frames`](https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_frames) + + +## `vec-box-size-threshold` The size of the boxed type in bytes, where boxing in a `Vec` is allowed **Default Value:** `4096` (`u64`) -* [vec_box](https://rust-lang.github.io/rust-clippy/master/index.html#vec_box) +--- +**Affected lints:** +* [`vec_box`](https://rust-lang.github.io/rust-clippy/master/index.html#vec_box) -### max-trait-bounds +## `max-trait-bounds` The maximum number of bounds a trait can have to be linted **Default Value:** `3` (`u64`) -* [type_repetition_in_bounds](https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds) +--- +**Affected lints:** +* [`type_repetition_in_bounds`](https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds) -### max-struct-bools +## `max-struct-bools` The maximum number of bool fields a struct can have **Default Value:** `3` (`u64`) -* [struct_excessive_bools](https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools) +--- +**Affected lints:** +* [`struct_excessive_bools`](https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools) -### max-fn-params-bools +## `max-fn-params-bools` The maximum number of bool parameters a function can have **Default Value:** `3` (`u64`) -* [fn_params_excessive_bools](https://rust-lang.github.io/rust-clippy/master/index.html#fn_params_excessive_bools) +--- +**Affected lints:** +* [`fn_params_excessive_bools`](https://rust-lang.github.io/rust-clippy/master/index.html#fn_params_excessive_bools) -### warn-on-all-wildcard-imports +## `warn-on-all-wildcard-imports` Whether to allow certain wildcard imports (prelude, super in tests). **Default Value:** `false` (`bool`) -* [wildcard_imports](https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_imports) +--- +**Affected lints:** +* [`wildcard_imports`](https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_imports) -### disallowed-macros +## `disallowed-macros` The list of disallowed macros, written as fully qualified paths. **Default Value:** `[]` (`Vec`) -* [disallowed_macros](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_macros) +--- +**Affected lints:** +* [`disallowed_macros`](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_macros) -### disallowed-methods +## `disallowed-methods` The list of disallowed methods, written as fully qualified paths. **Default Value:** `[]` (`Vec`) -* [disallowed_methods](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods) +--- +**Affected lints:** +* [`disallowed_methods`](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods) -### disallowed-types +## `disallowed-types` The list of disallowed types, written as fully qualified paths. **Default Value:** `[]` (`Vec`) -* [disallowed_types](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types) +--- +**Affected lints:** +* [`disallowed_types`](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types) -### unreadable-literal-lint-fractions +## `unreadable-literal-lint-fractions` Should the fraction of a decimal be linted to include separators. **Default Value:** `true` (`bool`) -* [unreadable_literal](https://rust-lang.github.io/rust-clippy/master/index.html#unreadable_literal) +--- +**Affected lints:** +* [`unreadable_literal`](https://rust-lang.github.io/rust-clippy/master/index.html#unreadable_literal) -### upper-case-acronyms-aggressive +## `upper-case-acronyms-aggressive` Enables verbose mode. Triggers if there is more than one uppercase char next to each other **Default Value:** `false` (`bool`) -* [upper_case_acronyms](https://rust-lang.github.io/rust-clippy/master/index.html#upper_case_acronyms) +--- +**Affected lints:** +* [`upper_case_acronyms`](https://rust-lang.github.io/rust-clippy/master/index.html#upper_case_acronyms) -### matches-for-let-else +## `matches-for-let-else` Whether the matches should be considered by the lint, and whether there should be filtering for common types. **Default Value:** `WellKnownTypes` (`crate::manual_let_else::MatchLintBehaviour`) -* [manual_let_else](https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else) +--- +**Affected lints:** +* [`manual_let_else`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else) -### cargo-ignore-publish +## `cargo-ignore-publish` For internal testing only, ignores the current `publish` settings in the Cargo manifest. **Default Value:** `false` (`bool`) -* [_cargo_common_metadata](https://rust-lang.github.io/rust-clippy/master/index.html#_cargo_common_metadata) +--- +**Affected lints:** +* [`_cargo_common_metadata`](https://rust-lang.github.io/rust-clippy/master/index.html#_cargo_common_metadata) -### standard-macro-braces +## `standard-macro-braces` Enforce the named macros always use the braces specified. A `MacroMatcher` can be added like so `{ name = "macro_name", brace = "(" }`. If the macro @@ -439,119 +483,147 @@ could be used with a full path two `MacroMatcher`s have to be added one with the **Default Value:** `[]` (`Vec`) -* [nonstandard_macro_braces](https://rust-lang.github.io/rust-clippy/master/index.html#nonstandard_macro_braces) +--- +**Affected lints:** +* [`nonstandard_macro_braces`](https://rust-lang.github.io/rust-clippy/master/index.html#nonstandard_macro_braces) -### enforced-import-renames +## `enforced-import-renames` The list of imports to always rename, a fully qualified path followed by the rename. **Default Value:** `[]` (`Vec`) -* [missing_enforced_import_renames](https://rust-lang.github.io/rust-clippy/master/index.html#missing_enforced_import_renames) +--- +**Affected lints:** +* [`missing_enforced_import_renames`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_enforced_import_renames) -### allowed-scripts +## `allowed-scripts` The list of unicode scripts allowed to be used in the scope. **Default Value:** `["Latin"]` (`Vec`) -* [disallowed_script_idents](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_script_idents) +--- +**Affected lints:** +* [`disallowed_script_idents`](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_script_idents) -### enable-raw-pointer-heuristic-for-send +## `enable-raw-pointer-heuristic-for-send` Whether to apply the raw pointer heuristic to determine if a type is `Send`. **Default Value:** `true` (`bool`) -* [non_send_fields_in_send_ty](https://rust-lang.github.io/rust-clippy/master/index.html#non_send_fields_in_send_ty) +--- +**Affected lints:** +* [`non_send_fields_in_send_ty`](https://rust-lang.github.io/rust-clippy/master/index.html#non_send_fields_in_send_ty) -### max-suggested-slice-pattern-length +## `max-suggested-slice-pattern-length` When Clippy suggests using a slice pattern, this is the maximum number of elements allowed in the slice pattern that is suggested. If more elements are necessary, the lint is suppressed. For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements. **Default Value:** `3` (`u64`) -* [index_refutable_slice](https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice) +--- +**Affected lints:** +* [`index_refutable_slice`](https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice) -### await-holding-invalid-types +## `await-holding-invalid-types` **Default Value:** `[]` (`Vec`) -* [await_holding_invalid_type](https://rust-lang.github.io/rust-clippy/master/index.html#await_holding_invalid_type) +--- +**Affected lints:** +* [`await_holding_invalid_type`](https://rust-lang.github.io/rust-clippy/master/index.html#await_holding_invalid_type) -### max-include-file-size +## `max-include-file-size` The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes **Default Value:** `1000000` (`u64`) -* [large_include_file](https://rust-lang.github.io/rust-clippy/master/index.html#large_include_file) +--- +**Affected lints:** +* [`large_include_file`](https://rust-lang.github.io/rust-clippy/master/index.html#large_include_file) -### allow-expect-in-tests +## `allow-expect-in-tests` Whether `expect` should be allowed in test functions or `#[cfg(test)]` **Default Value:** `false` (`bool`) -* [expect_used](https://rust-lang.github.io/rust-clippy/master/index.html#expect_used) +--- +**Affected lints:** +* [`expect_used`](https://rust-lang.github.io/rust-clippy/master/index.html#expect_used) -### allow-unwrap-in-tests +## `allow-unwrap-in-tests` Whether `unwrap` should be allowed in test functions or `#[cfg(test)]` **Default Value:** `false` (`bool`) -* [unwrap_used](https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used) +--- +**Affected lints:** +* [`unwrap_used`](https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used) -### allow-dbg-in-tests +## `allow-dbg-in-tests` Whether `dbg!` should be allowed in test functions or `#[cfg(test)]` **Default Value:** `false` (`bool`) -* [dbg_macro](https://rust-lang.github.io/rust-clippy/master/index.html#dbg_macro) +--- +**Affected lints:** +* [`dbg_macro`](https://rust-lang.github.io/rust-clippy/master/index.html#dbg_macro) -### allow-print-in-tests +## `allow-print-in-tests` Whether print macros (ex. `println!`) should be allowed in test functions or `#[cfg(test)]` **Default Value:** `false` (`bool`) -* [print_stdout](https://rust-lang.github.io/rust-clippy/master/index.html#print_stdout) -* [print_stderr](https://rust-lang.github.io/rust-clippy/master/index.html#print_stderr) +--- +**Affected lints:** +* [`print_stdout`](https://rust-lang.github.io/rust-clippy/master/index.html#print_stdout) +* [`print_stderr`](https://rust-lang.github.io/rust-clippy/master/index.html#print_stderr) -### large-error-threshold +## `large-error-threshold` The maximum size of the `Err`-variant in a `Result` returned from a function **Default Value:** `128` (`u64`) -* [result_large_err](https://rust-lang.github.io/rust-clippy/master/index.html#result_large_err) +--- +**Affected lints:** +* [`result_large_err`](https://rust-lang.github.io/rust-clippy/master/index.html#result_large_err) -### ignore-interior-mutability +## `ignore-interior-mutability` A list of paths to types that should be treated like `Arc`, i.e. ignored but for the generic parameters for determining interior mutability **Default Value:** `["bytes::Bytes"]` (`Vec`) -* [mutable_key_type](https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key_type) -* [ifs_same_cond](https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond) +--- +**Affected lints:** +* [`mutable_key_type`](https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key_type) +* [`ifs_same_cond`](https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond) -### allow-mixed-uninlined-format-args +## `allow-mixed-uninlined-format-args` Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)` **Default Value:** `true` (`bool`) -* [uninlined_format_args](https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args) +--- +**Affected lints:** +* [`uninlined_format_args`](https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args) -### suppress-restriction-lint-in-const +## `suppress-restriction-lint-in-const` Whether to suppress a restriction lint in constant code. In same cases the restructured operation might not be unavoidable, as the suggested counterparts are unavailable in constant code. This @@ -560,32 +632,101 @@ if no suggestion can be made. **Default Value:** `false` (`bool`) -* [indexing_slicing](https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing) +--- +**Affected lints:** +* [`indexing_slicing`](https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing) -### missing-docs-in-crate-items +## `missing-docs-in-crate-items` Whether to **only** check for missing documentation in items visible within the current crate. For example, `pub(crate)` items. **Default Value:** `false` (`bool`) -* [missing_docs_in_private_items](https://rust-lang.github.io/rust-clippy/master/index.html#missing_docs_in_private_items) +--- +**Affected lints:** +* [`missing_docs_in_private_items`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_docs_in_private_items) -### future-size-threshold +## `future-size-threshold` The maximum byte size a `Future` can have, before it triggers the `clippy::large_futures` lint **Default Value:** `16384` (`u64`) -* [large_futures](https://rust-lang.github.io/rust-clippy/master/index.html#large_futures) +--- +**Affected lints:** +* [`large_futures`](https://rust-lang.github.io/rust-clippy/master/index.html#large_futures) -### unnecessary-box-size +## `unnecessary-box-size` The byte size a `T` in `Box` can have, below which it triggers the `clippy::unnecessary_box` lint **Default Value:** `128` (`u64`) -* [unnecessary_box_returns](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_box_returns) +--- +**Affected lints:** +* [`unnecessary_box_returns`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_box_returns) +## `allow-private-module-inception` +Whether to allow module inception if it's not public. + +**Default Value:** `false` (`bool`) + +--- +**Affected lints:** +* [`module_inception`](https://rust-lang.github.io/rust-clippy/master/index.html#module_inception) + + +## `allowed-idents-below-min-chars` +Allowed names below the minimum allowed characters. The value `".."` can be used as part of +the list to indicate, that the configured values should be appended to the default +configuration of Clippy. By default, any configuration will replace the default value. + +**Default Value:** `{"j", "z", "i", "y", "n", "x", "w"}` (`rustc_data_structures::fx::FxHashSet`) + +--- +**Affected lints:** +* [`min_ident_chars`](https://rust-lang.github.io/rust-clippy/master/index.html#min_ident_chars) + + +## `min-ident-chars-threshold` +Minimum chars an ident can have, anything below or equal to this will be linted. + +**Default Value:** `1` (`u64`) + +--- +**Affected lints:** +* [`min_ident_chars`](https://rust-lang.github.io/rust-clippy/master/index.html#min_ident_chars) + + +## `accept-comment-above-statement` +Whether to accept a safety comment to be placed above the statement containing the `unsafe` block + +**Default Value:** `false` (`bool`) + +--- +**Affected lints:** +* [`undocumented_unsafe_blocks`](https://rust-lang.github.io/rust-clippy/master/index.html#undocumented_unsafe_blocks) + + +## `accept-comment-above-attributes` +Whether to accept a safety comment to be placed above the attributes for the `unsafe` block + +**Default Value:** `false` (`bool`) + +--- +**Affected lints:** +* [`undocumented_unsafe_blocks`](https://rust-lang.github.io/rust-clippy/master/index.html#undocumented_unsafe_blocks) + + +## `allow-one-hash-in-raw-strings` +Whether to allow `r#""#` when `r""` can be used + +**Default Value:** `false` (`bool`) + +--- +**Affected lints:** +* [`unnecessary_raw_string_hashes`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_raw_string_hashes) + diff --git a/clippy_dev/src/bless.rs b/clippy_dev/src/bless.rs deleted file mode 100644 index 92b2771f3fe7..000000000000 --- a/clippy_dev/src/bless.rs +++ /dev/null @@ -1,60 +0,0 @@ -//! `bless` updates the reference files in the repo with changed output files -//! from the last test run. - -use crate::cargo_clippy_path; -use std::ffi::OsStr; -use std::fs; -use std::path::{Path, PathBuf}; -use std::sync::LazyLock; -use walkdir::{DirEntry, WalkDir}; - -static CLIPPY_BUILD_TIME: LazyLock> = - LazyLock::new(|| cargo_clippy_path().metadata().ok()?.modified().ok()); - -/// # Panics -/// -/// Panics if the path to a test file is broken -pub fn bless(ignore_timestamp: bool) { - let extensions = ["stdout", "stderr", "fixed"].map(OsStr::new); - - WalkDir::new(build_dir()) - .into_iter() - .map(Result::unwrap) - .filter(|entry| entry.path().extension().map_or(false, |ext| extensions.contains(&ext))) - .for_each(|entry| update_reference_file(&entry, ignore_timestamp)); -} - -fn update_reference_file(test_output_entry: &DirEntry, ignore_timestamp: bool) { - let test_output_path = test_output_entry.path(); - - let reference_file_name = test_output_entry.file_name().to_str().unwrap().replace(".stage-id", ""); - let reference_file_path = Path::new("tests") - .join(test_output_path.strip_prefix(build_dir()).unwrap()) - .with_file_name(reference_file_name); - - // If the test output was not updated since the last clippy build, it may be outdated - if !ignore_timestamp && !updated_since_clippy_build(test_output_entry).unwrap_or(true) { - return; - } - - let test_output_file = fs::read(test_output_path).expect("Unable to read test output file"); - let reference_file = fs::read(&reference_file_path).unwrap_or_default(); - - if test_output_file != reference_file { - // If a test run caused an output file to change, update the reference file - println!("updating {}", reference_file_path.display()); - fs::copy(test_output_path, &reference_file_path).expect("Could not update reference file"); - } -} - -fn updated_since_clippy_build(entry: &DirEntry) -> Option { - let clippy_build_time = (*CLIPPY_BUILD_TIME)?; - let modified = entry.metadata().ok()?.modified().ok()?; - Some(modified >= clippy_build_time) -} - -fn build_dir() -> PathBuf { - let mut path = std::env::current_exe().unwrap(); - path.set_file_name("test"); - path -} diff --git a/clippy_dev/src/fmt.rs b/clippy_dev/src/fmt.rs index 256231441817..ee559d45dd16 100644 --- a/clippy_dev/src/fmt.rs +++ b/clippy_dev/src/fmt.rs @@ -35,6 +35,7 @@ struct FmtContext { } // the "main" function of cargo dev fmt +#[allow(clippy::missing_panics_doc)] pub fn run(check: bool, verbose: bool) { fn try_run(context: &FmtContext) -> Result { let mut success = true; diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index 56a269288c05..4624451cff4f 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -14,7 +14,6 @@ use std::io; use std::path::PathBuf; use std::process::{self, ExitStatus}; -pub mod bless; pub mod dogfood; pub mod fmt; pub mod lint; @@ -29,6 +28,10 @@ static CARGO_CLIPPY_EXE: &str = "cargo-clippy"; static CARGO_CLIPPY_EXE: &str = "cargo-clippy.exe"; /// Returns the path to the `cargo-clippy` binary +/// +/// # Panics +/// +/// Panics if the path of current executable could not be retrieved. #[must_use] pub fn cargo_clippy_path() -> PathBuf { let mut path = std::env::current_exe().expect("failed to get current executable name"); @@ -61,6 +64,8 @@ pub fn clippy_project_root() -> PathBuf { panic!("error: Can't determine root of project. Please run inside a Clippy working dir."); } +/// # Panics +/// Panics if given command result was failed. pub fn exit_if_err(status: io::Result) { match status.expect("failed to run command").code() { Some(0) => {}, diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs index c03fbe9d275f..43eaccdf5a31 100644 --- a/clippy_dev/src/main.rs +++ b/clippy_dev/src/main.rs @@ -3,7 +3,7 @@ #![warn(rust_2018_idioms, unused_lifetimes)] use clap::{Arg, ArgAction, ArgMatches, Command}; -use clippy_dev::{bless, dogfood, fmt, lint, new_lint, serve, setup, update_lints}; +use clippy_dev::{dogfood, fmt, lint, new_lint, serve, setup, update_lints}; use indoc::indoc; use std::convert::Infallible; @@ -11,8 +11,8 @@ fn main() { let matches = get_clap_config(); match matches.subcommand() { - Some(("bless", matches)) => { - bless::bless(matches.get_flag("ignore-timestamp")); + Some(("bless", _)) => { + eprintln!("use `cargo bless` to automatically replace `.stderr` and `.fixed` files as tests are being run"); }, Some(("dogfood", matches)) => { dogfood::dogfood( @@ -35,7 +35,7 @@ fn main() { }, Some(("new_lint", matches)) => { match new_lint::create( - matches.get_one::("pass"), + matches.get_one::("pass").unwrap(), matches.get_one::("name"), matches.get_one::("category").map(String::as_str), matches.get_one::("type").map(String::as_str), @@ -176,7 +176,7 @@ fn get_clap_config() -> ArgMatches { .help("Specify whether the lint runs during the early or late pass") .value_parser(["early", "late"]) .conflicts_with("type") - .required_unless_present("type"), + .default_value("late"), Arg::new("name") .short('n') .long("name") diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index 13a277034278..f11aa547bd73 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -36,8 +36,9 @@ impl Context for io::Result { /// # Errors /// /// This function errors out if the files couldn't be created or written to. +#[allow(clippy::missing_panics_doc)] pub fn create( - pass: Option<&String>, + pass: &String, lint_name: Option<&String>, category: Option<&str>, mut ty: Option<&str>, @@ -49,7 +50,7 @@ pub fn create( } let lint = LintData { - pass: pass.map_or("", String::as_str), + pass, name: lint_name.expect("`name` argument is validated by clap"), category: category.expect("`category` argument is validated by clap"), ty, @@ -63,6 +64,14 @@ pub fn create( add_lint(&lint, msrv).context("Unable to add lint to clippy_lints/src/lib.rs")?; } + if pass == "early" { + println!( + "\n\ + NOTE: Use a late pass unless you need something specific from\ + an early pass, as they lack many features and utilities" + ); + } + Ok(()) } @@ -87,7 +96,7 @@ fn create_test(lint: &LintData<'_>) -> io::Result<()> { path.push("src"); fs::create_dir(&path)?; - let header = format!("// compile-flags: --crate-name={lint_name}"); + let header = format!("//@compile-flags: --crate-name={lint_name}"); write_file(path.join("main.rs"), get_test_file_contents(lint_name, Some(&header)))?; Ok(()) diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index be9261a47041..c23054443bb9 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -22,6 +22,7 @@ serde = { version = "1.0", features = ["derive"] } serde_json = { version = "1.0", optional = true } tempfile = { version = "3.3.0", optional = true } toml = "0.7.3" +regex = { version = "1.5", optional = true } unicode-normalization = "0.1" unicode-script = { version = "0.5", default-features = false } semver = "1.0" @@ -31,7 +32,7 @@ url = "2.2" [features] deny-warnings = ["clippy_utils/deny-warnings"] # build clippy with internal lints enabled, off by default -internal = ["clippy_utils/internal", "serde_json", "tempfile"] +internal = ["clippy_utils/internal", "serde_json", "tempfile", "regex"] [package.metadata.rust-analyzer] # This crate uses #[feature(rustc_private)] diff --git a/clippy_lints/src/allow_attributes.rs b/clippy_lints/src/allow_attributes.rs index 554efdc58e1c..eb21184713e8 100644 --- a/clippy_lints/src/allow_attributes.rs +++ b/clippy_lints/src/allow_attributes.rs @@ -1,5 +1,5 @@ -use ast::AttrStyle; -use clippy_utils::diagnostics::span_lint_and_sugg; +use ast::{AttrStyle, Attribute}; +use clippy_utils::{diagnostics::span_lint_and_sugg, is_from_proc_macro}; use rustc_ast as ast; use rustc_errors::Applicability; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -50,13 +50,14 @@ declare_lint_pass!(AllowAttribute => [ALLOW_ATTRIBUTES]); impl LateLintPass<'_> for AllowAttribute { // Separate each crate's features. - fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) { + fn check_attribute<'cx>(&mut self, cx: &LateContext<'cx>, attr: &'cx Attribute) { if_chain! { if !in_external_macro(cx.sess(), attr.span); if cx.tcx.features().lint_reasons; if let AttrStyle::Outer = attr.style; if let Some(ident) = attr.ident(); if ident.name == rustc_span::symbol::sym::allow; + if !is_from_proc_macro(cx, &attr); then { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/arc_with_non_send_sync.rs b/clippy_lints/src/arc_with_non_send_sync.rs new file mode 100644 index 000000000000..a1e44668e1ad --- /dev/null +++ b/clippy_lints/src/arc_with_non_send_sync.rs @@ -0,0 +1,72 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::last_path_segment; +use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; +use if_chain::if_chain; + +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_lint::LateLintPass; +use rustc_middle::ty; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::symbol::sym; + +declare_clippy_lint! { + /// ### What it does. + /// This lint warns when you use `Arc` with a type that does not implement `Send` or `Sync`. + /// + /// ### Why is this bad? + /// Wrapping a type in Arc doesn't add thread safety to the underlying data, so data races + /// could occur when touching the underlying data. + /// + /// ### Example + /// ```rust + /// # use std::cell::RefCell; + /// # use std::sync::Arc; + /// + /// fn main() { + /// // This is safe, as `i32` implements `Send` and `Sync`. + /// let a = Arc::new(42); + /// + /// // This is not safe, as `RefCell` does not implement `Sync`. + /// let b = Arc::new(RefCell::new(42)); + /// } + /// ``` + #[clippy::version = "1.72.0"] + pub ARC_WITH_NON_SEND_SYNC, + correctness, + "using `Arc` with a type that does not implement `Send` or `Sync`" +} +declare_lint_pass!(ArcWithNonSendSync => [ARC_WITH_NON_SEND_SYNC]); + +impl LateLintPass<'_> for ArcWithNonSendSync { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + let ty = cx.typeck_results().expr_ty(expr); + if_chain! { + if is_type_diagnostic_item(cx, ty, sym::Arc); + if let ExprKind::Call(func, [arg]) = expr.kind; + if let ExprKind::Path(func_path) = func.kind; + if last_path_segment(&func_path).ident.name == sym::new; + if let arg_ty = cx.typeck_results().expr_ty(arg); + if !matches!(arg_ty.kind(), ty::Param(_)); + if !cx.tcx + .lang_items() + .sync_trait() + .map_or(false, |id| implements_trait(cx, arg_ty, id, &[])) || + !cx.tcx + .get_diagnostic_item(sym::Send) + .map_or(false, |id| implements_trait(cx, arg_ty, id, &[])); + + then { + span_lint_and_help( + cx, + ARC_WITH_NON_SEND_SYNC, + expr.span, + "usage of `Arc` where `T` is not `Send` or `Sync`", + None, + "consider using `Rc` instead or wrapping `T` in a std::sync type like \ + `Mutex`", + ); + } + } + } +} diff --git a/clippy_lints/src/as_conversions.rs b/clippy_lints/src/as_conversions.rs index c7a76e5f9077..b9dda49ca412 100644 --- a/clippy_lints/src/as_conversions.rs +++ b/clippy_lints/src/as_conversions.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_help; -use rustc_ast::ast::{Expr, ExprKind}; -use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; +use clippy_utils::is_from_proc_macro; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -45,9 +46,9 @@ declare_clippy_lint! { declare_lint_pass!(AsConversions => [AS_CONVERSIONS]); -impl EarlyLintPass for AsConversions { - fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - if in_external_macro(cx.sess(), expr.span) { +impl<'tcx> LateLintPass<'tcx> for AsConversions { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { + if in_external_macro(cx.sess(), expr.span) || is_from_proc_macro(cx, expr) { return; } diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 897495ba1087..2ba78f99569a 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -1,9 +1,12 @@ //! checks for attributes -use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::macros::{is_panic, macro_backtrace}; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments}; +use clippy_utils::{ + diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then}, + is_from_proc_macro, +}; use if_chain::if_chain; use rustc_ast::{AttrKind, AttrStyle, Attribute, LitKind, MetaItemKind, MetaItemLit, NestedMetaItem}; use rustc_errors::Applicability; @@ -362,6 +365,32 @@ declare_clippy_lint! { "ensure that all `cfg(any())` and `cfg(all())` have more than one condition" } +declare_clippy_lint! { + /// ### What it does + /// Checks for `#[cfg(features = "...")]` and suggests to replace it with + /// `#[cfg(feature = "...")]`. + /// + /// ### Why is this bad? + /// Misspelling `feature` as `features` can be sometimes hard to spot. It + /// may cause conditional compilation not work quitely. + /// + /// ### Example + /// ```rust + /// #[cfg(features = "some-feature")] + /// fn conditional() { } + /// ``` + /// + /// Use instead: + /// ```rust + /// #[cfg(feature = "some-feature")] + /// fn conditional() { } + /// ``` + #[clippy::version = "1.69.0"] + pub MAYBE_MISUSED_CFG, + suspicious, + "prevent from misusing the wrong attr name" +} + declare_lint_pass!(Attributes => [ ALLOW_ATTRIBUTES_WITHOUT_REASON, INLINE_ALWAYS, @@ -540,7 +569,7 @@ fn check_clippy_lint_names(cx: &LateContext<'_>, name: Symbol, items: &[NestedMe } } -fn check_lint_reason(cx: &LateContext<'_>, name: Symbol, items: &[NestedMetaItem], attr: &'_ Attribute) { +fn check_lint_reason<'cx>(cx: &LateContext<'cx>, name: Symbol, items: &[NestedMetaItem], attr: &'cx Attribute) { // Check for the feature if !cx.tcx.features().lint_reasons { return; @@ -555,7 +584,7 @@ fn check_lint_reason(cx: &LateContext<'_>, name: Symbol, items: &[NestedMetaItem } // Check if the attribute is in an external macro and therefore out of the developer's control - if in_external_macro(cx.sess(), attr.span) { + if in_external_macro(cx.sess(), attr.span) || is_from_proc_macro(cx, &attr) { return; } @@ -676,6 +705,7 @@ impl_lint_pass!(EarlyAttributes => [ EMPTY_LINE_AFTER_OUTER_ATTR, EMPTY_LINE_AFTER_DOC_COMMENTS, NON_MINIMAL_CFG, + MAYBE_MISUSED_CFG, ]); impl EarlyLintPass for EarlyAttributes { @@ -687,6 +717,7 @@ impl EarlyLintPass for EarlyAttributes { check_deprecated_cfg_attr(cx, attr, &self.msrv); check_mismatched_target_os(cx, attr); check_minimal_cfg_condition(cx, attr); + check_misused_cfg(cx, attr); } extract_msrv_attr!(EarlyContext); @@ -777,7 +808,7 @@ fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute, msrv: &Msr } fn check_nested_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) { - for item in items.iter() { + for item in items { if let NestedMetaItem::MetaItem(meta) = item { if !meta.has_name(sym::any) && !meta.has_name(sym::all) { continue; @@ -810,6 +841,27 @@ fn check_nested_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) { } } +fn check_nested_misused_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) { + for item in items { + if let NestedMetaItem::MetaItem(meta) = item { + if meta.has_name(sym!(features)) && let Some(val) = meta.value_str() { + span_lint_and_sugg( + cx, + MAYBE_MISUSED_CFG, + meta.span, + "feature may misspelled as features", + "use", + format!("feature = \"{val}\""), + Applicability::MaybeIncorrect, + ); + } + if let MetaItemKind::List(list) = &meta.kind { + check_nested_misused_cfg(cx, list); + } + } + } +} + fn check_minimal_cfg_condition(cx: &EarlyContext<'_>, attr: &Attribute) { if attr.has_name(sym::cfg) && let Some(items) = attr.meta_item_list() @@ -818,6 +870,14 @@ fn check_minimal_cfg_condition(cx: &EarlyContext<'_>, attr: &Attribute) { } } +fn check_misused_cfg(cx: &EarlyContext<'_>, attr: &Attribute) { + if attr.has_name(sym::cfg) && + let Some(items) = attr.meta_item_list() + { + check_nested_misused_cfg(cx, &items); + } +} + fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) { fn find_os(name: &str) -> Option<&'static str> { UNIX_SYSTEMS diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index ff0102255a0a..04cca9e3177c 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -440,7 +440,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { diag.span_suggestions( e.span, "try", - suggestions.into_iter(), + suggestions, // nonminimal_bool can produce minimal but // not human readable expressions (#3141) Applicability::Unspecified, diff --git a/clippy_lints/src/casts/borrow_as_ptr.rs b/clippy_lints/src/casts/borrow_as_ptr.rs index 294d22d34de9..b7256dd2eae9 100644 --- a/clippy_lints/src/casts/borrow_as_ptr.rs +++ b/clippy_lints/src/casts/borrow_as_ptr.rs @@ -4,6 +4,7 @@ use clippy_utils::source::snippet_with_context; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Ty, TyKind}; use rustc_lint::LateContext; +use rustc_middle::ty::adjustment::Adjust; use super::BORROW_AS_PTR; @@ -23,6 +24,15 @@ pub(super) fn check<'tcx>( }; let mut app = Applicability::MachineApplicable; let snip = snippet_with_context(cx, e.span, cast_expr.span.ctxt(), "..", &mut app).0; + // Fix #9884 + if !e.is_place_expr(|base| { + cx.typeck_results() + .adjustments() + .get(base.hir_id) + .is_some_and(|x| x.iter().any(|adj| matches!(adj.kind, Adjust::Deref(_)))) + }) { + return; + } span_lint_and_sugg( cx, diff --git a/clippy_lints/src/casts/cast_possible_wrap.rs b/clippy_lints/src/casts/cast_possible_wrap.rs index 28ecdea7ea06..ffa571abb391 100644 --- a/clippy_lints/src/casts/cast_possible_wrap.rs +++ b/clippy_lints/src/casts/cast_possible_wrap.rs @@ -1,41 +1,90 @@ -use clippy_utils::diagnostics::span_lint; -use clippy_utils::ty::is_isize_or_usize; use rustc_hir::Expr; -use rustc_lint::LateContext; +use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty::Ty; use super::{utils, CAST_POSSIBLE_WRAP}; +// this should be kept in sync with the allowed bit widths of `usize` and `isize` +const ALLOWED_POINTER_SIZES: [u64; 3] = [16, 32, 64]; + +// whether the lint should be emitted, and the required pointer size, if it matters +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +enum EmitState { + NoLint, + LintAlways, + LintOnPtrSize(u64), +} + pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { if !(cast_from.is_integral() && cast_to.is_integral()) { return; } - let arch_64_suffix = " on targets with 64-bit wide pointers"; - let arch_32_suffix = " on targets with 32-bit wide pointers"; - let cast_unsigned_to_signed = !cast_from.is_signed() && cast_to.is_signed(); + // emit a lint if a cast is: + // 1. unsigned to signed + // and + // 2. either: + // + // 2a. between two types of constant size that are always the same size + // 2b. between one target-dependent size and one constant size integer, + // and the constant integer is in the allowed set of target dependent sizes + // (the ptr size could be chosen to be the same as the constant size) + + if cast_from.is_signed() || !cast_to.is_signed() { + return; + } + let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx); let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx); - let (should_lint, suffix) = match (is_isize_or_usize(cast_from), is_isize_or_usize(cast_to)) { - (true, true) | (false, false) => (to_nbits == from_nbits && cast_unsigned_to_signed, ""), - (true, false) => (to_nbits <= 32 && cast_unsigned_to_signed, arch_32_suffix), - (false, true) => ( - cast_unsigned_to_signed, - if from_nbits == 64 { - arch_64_suffix + let should_lint = match (cast_from.is_ptr_sized_integral(), cast_to.is_ptr_sized_integral()) { + (true, true) => { + // casts between two ptr sized integers are trivially always the same size + // so do not depend on any specific pointer size to be the same + EmitState::LintAlways + }, + (true, false) => { + // the first type is `usize` and the second is a constant sized signed integer + if ALLOWED_POINTER_SIZES.contains(&to_nbits) { + EmitState::LintOnPtrSize(to_nbits) } else { - arch_32_suffix - }, + EmitState::NoLint + } + }, + (false, true) => { + // the first type is a constant sized unsigned integer, and the second is `isize` + if ALLOWED_POINTER_SIZES.contains(&from_nbits) { + EmitState::LintOnPtrSize(from_nbits) + } else { + EmitState::NoLint + } + }, + (false, false) => { + // the types are both a constant known size + // and do not depend on any specific pointer size to be the same + if from_nbits == to_nbits { + EmitState::LintAlways + } else { + EmitState::NoLint + } + }, + }; + + let message = match should_lint { + EmitState::NoLint => return, + EmitState::LintAlways => format!("casting `{cast_from}` to `{cast_to}` may wrap around the value"), + EmitState::LintOnPtrSize(ptr_size) => format!( + "casting `{cast_from}` to `{cast_to}` may wrap around the value on targets with {ptr_size}-bit wide pointers", ), }; - if should_lint { - span_lint( - cx, - CAST_POSSIBLE_WRAP, - expr.span, - &format!("casting `{cast_from}` to `{cast_to}` may wrap around the value{suffix}",), - ); - } + cx.struct_span_lint(CAST_POSSIBLE_WRAP, expr.span, message, |diag| { + if let EmitState::LintOnPtrSize(16) = should_lint { + diag + .note("`usize` and `isize` may be as small as 16 bits on some platforms") + .note("for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types") + } else { + diag + } + }); } diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index b90dab07a274..0ac6ef6496a8 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -118,9 +118,10 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does /// Checks for casts from an unsigned type to a signed type of - /// the same size. Performing such a cast is a 'no-op' for the compiler, - /// i.e., nothing is changed at the bit level, and the binary representation of - /// the value is reinterpreted. This can cause wrapping if the value is too big + /// the same size, or possibly smaller due to target dependent integers. + /// Performing such a cast is a 'no-op' for the compiler, i.e., nothing is + /// changed at the bit level, and the binary representation of the value is + /// reinterpreted. This can cause wrapping if the value is too big /// for the target signed type. However, the cast works as defined, so this lint /// is `Allow` by default. /// @@ -174,8 +175,8 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for casts to the same type, casts of int literals to integer types - /// and casts of float literals to float types. + /// Checks for casts to the same type, casts of int literals to integer types, casts of float + /// literals to float types and casts between raw pointers without changing type or constness. /// /// ### Why is this bad? /// It's just unnecessary. @@ -522,7 +523,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Check for the usage of `as _` conversion using inferred type. + /// Checks for the usage of `as _` conversion using inferred type. /// /// ### Why is this bad? /// The conversion might include lossy conversion and dangerous cast that might go diff --git a/clippy_lints/src/casts/ptr_cast_constness.rs b/clippy_lints/src/casts/ptr_cast_constness.rs index ab015f8822e1..f0c1df014307 100644 --- a/clippy_lints/src/casts/ptr_cast_constness.rs +++ b/clippy_lints/src/casts/ptr_cast_constness.rs @@ -9,20 +9,21 @@ use rustc_middle::ty::{self, Ty, TypeAndMut}; use super::PTR_CAST_CONSTNESS; -pub(super) fn check( +pub(super) fn check<'tcx>( cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, - cast_from: Ty<'_>, - cast_to: Ty<'_>, + cast_from: Ty<'tcx>, + cast_to: Ty<'tcx>, msrv: &Msrv, ) { if_chain! { if msrv.meets(POINTER_CAST_CONSTNESS); - if let ty::RawPtr(TypeAndMut { mutbl: from_mutbl, .. }) = cast_from.kind(); - if let ty::RawPtr(TypeAndMut { mutbl: to_mutbl, .. }) = cast_to.kind(); + if let ty::RawPtr(TypeAndMut { mutbl: from_mutbl, ty: from_ty }) = cast_from.kind(); + if let ty::RawPtr(TypeAndMut { mutbl: to_mutbl, ty: to_ty }) = cast_to.kind(); if matches!((from_mutbl, to_mutbl), (Mutability::Not, Mutability::Mut) | (Mutability::Mut, Mutability::Not)); + if from_ty == to_ty; then { let sugg = Sugg::hir(cx, cast_expr, "_"); let constness = match *to_mutbl { @@ -34,7 +35,7 @@ pub(super) fn check( cx, PTR_CAST_CONSTNESS, expr.span, - "`as` casting between raw pointers while changing its constness", + "`as` casting between raw pointers while changing only its constness", &format!("try `pointer::cast_{constness}`, a safer alternative"), format!("{}.cast_{constness}()", sugg.maybe_par()), Applicability::MachineApplicable, diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs index 804ae841100a..71cf2aea0f8d 100644 --- a/clippy_lints/src/casts/unnecessary_cast.rs +++ b/clippy_lints/src/casts/unnecessary_cast.rs @@ -1,18 +1,21 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::numeric_literal::NumericLiteral; use clippy_utils::source::snippet_opt; -use clippy_utils::{get_parent_expr, path_to_local}; +use clippy_utils::visitors::{for_each_expr, Visitable}; +use clippy_utils::{get_parent_expr, get_parent_node, is_hir_ty_cfg_dependant, is_ty_alias, path_to_local}; use if_chain::if_chain; use rustc_ast::{LitFloatType, LitIntType, LitKind}; use rustc_errors::Applicability; -use rustc_hir::def::Res; -use rustc_hir::{Expr, ExprKind, Lit, QPath, TyKind, UnOp}; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::{Expr, ExprKind, Lit, Node, Path, QPath, TyKind, UnOp}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, FloatTy, InferTy, Ty}; +use std::ops::ControlFlow; use super::UNNECESSARY_CAST; +#[expect(clippy::too_many_lines)] pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &Expr<'tcx>, @@ -20,19 +23,84 @@ pub(super) fn check<'tcx>( cast_from: Ty<'tcx>, cast_to: Ty<'tcx>, ) -> bool { - // skip non-primitive type cast + let cast_str = snippet_opt(cx, cast_expr.span).unwrap_or_default(); + + if_chain! { + if let ty::RawPtr(..) = cast_from.kind(); + // check both mutability and type are the same + if cast_from.kind() == cast_to.kind(); + if let ExprKind::Cast(_, cast_to_hir) = expr.kind; + // Ignore casts to e.g. type aliases and infer types + // - p as pointer_alias + // - p as _ + if let TyKind::Ptr(to_pointee) = cast_to_hir.kind; + then { + match to_pointee.ty.kind { + // Ignore casts to pointers that are aliases or cfg dependant, e.g. + // - p as *const std::ffi::c_char (alias) + // - p as *const std::os::raw::c_char (cfg dependant) + TyKind::Path(qpath) => { + if is_ty_alias(&qpath) || is_hir_ty_cfg_dependant(cx, to_pointee.ty) { + return false; + } + }, + // Ignore `p as *const _` + TyKind::Infer => return false, + _ => {}, + } + + span_lint_and_sugg( + cx, + UNNECESSARY_CAST, + expr.span, + &format!("casting raw pointers to the same type and constness is unnecessary (`{cast_from}` -> `{cast_to}`)"), + "try", + cast_str.clone(), + Applicability::MachineApplicable, + ); + } + } + + // skip cast of local that is a type alias + if let ExprKind::Cast(inner, ..) = expr.kind + && let ExprKind::Path(qpath) = inner.kind + && let QPath::Resolved(None, Path { res, .. }) = qpath + && let Res::Local(hir_id) = res + && let parent = cx.tcx.hir().get_parent(*hir_id) + && let Node::Local(local) = parent + { + if let Some(ty) = local.ty + && let TyKind::Path(qpath) = ty.kind + && is_ty_alias(&qpath) + { + return false; + } + + if let Some(expr) = local.init + && let ExprKind::Cast(.., cast_to) = expr.kind + && let TyKind::Path(qpath) = cast_to.kind + && is_ty_alias(&qpath) + { + return false; + } + } + + // skip cast of fn call that returns type alias + if let ExprKind::Cast(inner, ..) = expr.kind && is_cast_from_ty_alias(cx, inner, cast_from) { + return false; + } + + // skip cast to non-primitive type if_chain! { if let ExprKind::Cast(_, cast_to) = expr.kind; if let TyKind::Path(QPath::Resolved(_, path)) = &cast_to.kind; if let Res::PrimTy(_) = path.res; then {} else { - return false + return false; } } - let cast_str = snippet_opt(cx, cast_expr.span).unwrap_or_default(); - if let Some(lit) = get_numeric_literal(cast_expr) { let literal_str = &cast_str; @@ -162,3 +230,61 @@ fn fp_ty_mantissa_nbits(typ: Ty<'_>) -> u32 { _ => 0, } } + +/// Finds whether an `Expr` returns a type alias. +/// +/// TODO: Maybe we should move this to `clippy_utils` so others won't need to go down this dark, +/// dark path reimplementing this (or something similar). +fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx>, cast_from: Ty<'tcx>) -> bool { + for_each_expr(expr, |expr| { + // Calls are a `Path`, and usage of locals are a `Path`. So, this checks + // - call() as i32 + // - local as i32 + if let ExprKind::Path(qpath) = expr.kind { + let res = cx.qpath_res(&qpath, expr.hir_id); + // Function call + if let Res::Def(DefKind::Fn, def_id) = res { + let Some(snippet) = snippet_opt(cx, cx.tcx.def_span(def_id)) else { + return ControlFlow::Continue(()); + }; + // This is the worst part of this entire function. This is the only way I know of to + // check whether a function returns a type alias. Sure, you can get the return type + // from a function in the current crate as an hir ty, but how do you get it for + // external functions?? Simple: It's impossible. So, we check whether a part of the + // function's declaration snippet is exactly equal to the `Ty`. That way, we can + // see whether it's a type alias. + // + // Will this work for more complex types? Probably not! + if !snippet + .split("->") + .skip(0) + .map(|s| { + s.trim() == cast_from.to_string() + || s.split("where").any(|ty| ty.trim() == cast_from.to_string()) + }) + .any(|a| a) + { + return ControlFlow::Break(()); + } + // Local usage + } else if let Res::Local(hir_id) = res + && let Some(parent) = get_parent_node(cx.tcx, hir_id) + && let Node::Local(l) = parent + { + if let Some(e) = l.init && is_cast_from_ty_alias(cx, e, cast_from) { + return ControlFlow::Break::<()>(()); + } + + if let Some(ty) = l.ty + && let TyKind::Path(qpath) = ty.kind + && is_ty_alias(&qpath) + { + return ControlFlow::Break::<()>(()); + } + } + } + + ControlFlow::Continue(()) + }) + .is_some() +} diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index f1d1355123ab..9d9ee6ba3079 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -3,6 +3,8 @@ // Manual edits will be overwritten. pub(crate) static LINTS: &[&crate::LintInfo] = &[ + #[cfg(feature = "internal")] + crate::utils::internal_lints::almost_standard_lint_formulation::ALMOST_STANDARD_LINT_FORMULATION_INFO, #[cfg(feature = "internal")] crate::utils::internal_lints::clippy_lints_internal::CLIPPY_LINTS_INTERNAL_INFO, #[cfg(feature = "internal")] @@ -38,6 +40,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::allow_attributes::ALLOW_ATTRIBUTES_INFO, crate::almost_complete_range::ALMOST_COMPLETE_RANGE_INFO, crate::approx_const::APPROX_CONSTANT_INFO, + crate::arc_with_non_send_sync::ARC_WITH_NON_SEND_SYNC_INFO, crate::as_conversions::AS_CONVERSIONS_INFO, crate::asm_syntax::INLINE_ASM_X86_ATT_SYNTAX_INFO, crate::asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX_INFO, @@ -51,6 +54,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::attrs::EMPTY_LINE_AFTER_DOC_COMMENTS_INFO, crate::attrs::EMPTY_LINE_AFTER_OUTER_ATTR_INFO, crate::attrs::INLINE_ALWAYS_INFO, + crate::attrs::MAYBE_MISUSED_CFG_INFO, crate::attrs::MISMATCHED_TARGET_OS_INFO, crate::attrs::NON_MINIMAL_CFG_INFO, crate::attrs::USELESS_ATTRIBUTE_INFO, @@ -136,11 +140,15 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::double_parens::DOUBLE_PARENS_INFO, crate::drop_forget_ref::DROP_NON_DROP_INFO, crate::drop_forget_ref::FORGET_NON_DROP_INFO, + crate::drop_forget_ref::MEM_FORGET_INFO, crate::duplicate_mod::DUPLICATE_MOD_INFO, crate::else_if_without_else::ELSE_IF_WITHOUT_ELSE_INFO, crate::empty_drop::EMPTY_DROP_INFO, crate::empty_enum::EMPTY_ENUM_INFO, crate::empty_structs_with_brackets::EMPTY_STRUCTS_WITH_BRACKETS_INFO, + crate::endian_bytes::BIG_ENDIAN_BYTES_INFO, + crate::endian_bytes::HOST_ENDIAN_BYTES_INFO, + crate::endian_bytes::LITTLE_ENDIAN_BYTES_INFO, crate::entry::MAP_ENTRY_INFO, crate::enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT_INFO, crate::enum_variants::ENUM_VARIANT_NAMES_INFO, @@ -152,6 +160,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS_INFO, crate::excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS_INFO, crate::excessive_bools::STRUCT_EXCESSIVE_BOOLS_INFO, + crate::excessive_nesting::EXCESSIVE_NESTING_INFO, crate::exhaustive_items::EXHAUSTIVE_ENUMS_INFO, crate::exhaustive_items::EXHAUSTIVE_STRUCTS_INFO, crate::exit::EXIT_INFO, @@ -197,6 +206,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::implicit_saturating_add::IMPLICIT_SATURATING_ADD_INFO, crate::implicit_saturating_sub::IMPLICIT_SATURATING_SUB_INFO, crate::inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR_INFO, + crate::incorrect_impls::INCORRECT_CLONE_IMPL_ON_COPY_TYPE_INFO, crate::index_refutable_slice::INDEX_REFUTABLE_SLICE_INFO, crate::indexing_slicing::INDEXING_SLICING_INFO, crate::indexing_slicing::OUT_OF_BOUNDS_INDEXING_INFO, @@ -219,6 +229,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::large_futures::LARGE_FUTURES_INFO, crate::large_include_file::LARGE_INCLUDE_FILE_INFO, crate::large_stack_arrays::LARGE_STACK_ARRAYS_INFO, + crate::large_stack_frames::LARGE_STACK_FRAMES_INFO, crate::len_zero::COMPARISON_TO_EMPTY_INFO, crate::len_zero::LEN_WITHOUT_IS_EMPTY_INFO, crate::len_zero::LEN_ZERO_INFO, @@ -266,6 +277,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::manual_let_else::MANUAL_LET_ELSE_INFO, crate::manual_main_separator_str::MANUAL_MAIN_SEPARATOR_STR_INFO, crate::manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE_INFO, + crate::manual_range_patterns::MANUAL_RANGE_PATTERNS_INFO, crate::manual_rem_euclid::MANUAL_REM_EUCLID_INFO, crate::manual_retain::MANUAL_RETAIN_INFO, crate::manual_slice_size_calculation::MANUAL_SLICE_SIZE_CALCULATION_INFO, @@ -299,7 +311,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::matches::TRY_ERR_INFO, crate::matches::WILDCARD_ENUM_MATCH_ARM_INFO, crate::matches::WILDCARD_IN_OR_PATTERNS_INFO, - crate::mem_forget::MEM_FORGET_INFO, crate::mem_replace::MEM_REPLACE_OPTION_WITH_NONE_INFO, crate::mem_replace::MEM_REPLACE_WITH_DEFAULT_INFO, crate::mem_replace::MEM_REPLACE_WITH_UNINIT_INFO, @@ -314,6 +325,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::CLONE_ON_COPY_INFO, crate::methods::CLONE_ON_REF_PTR_INFO, crate::methods::COLLAPSIBLE_STR_REPLACE_INFO, + crate::methods::DRAIN_COLLECT_INFO, crate::methods::ERR_EXPECT_INFO, crate::methods::EXPECT_FUN_CALL_INFO, crate::methods::EXPECT_USED_INFO, @@ -352,6 +364,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::MANUAL_SATURATING_ARITHMETIC_INFO, crate::methods::MANUAL_SPLIT_ONCE_INFO, crate::methods::MANUAL_STR_REPEAT_INFO, + crate::methods::MANUAL_TRY_FOLD_INFO, crate::methods::MAP_CLONE_INFO, crate::methods::MAP_COLLECT_RESULT_UNIT_INFO, crate::methods::MAP_ERR_IGNORE_INFO, @@ -398,6 +411,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::UNNECESSARY_FOLD_INFO, crate::methods::UNNECESSARY_JOIN_INFO, crate::methods::UNNECESSARY_LAZY_EVALUATIONS_INFO, + crate::methods::UNNECESSARY_LITERAL_UNWRAP_INFO, crate::methods::UNNECESSARY_SORT_BY_INFO, crate::methods::UNNECESSARY_TO_OWNED_INFO, crate::methods::UNWRAP_OR_ELSE_DEFAULT_INFO, @@ -407,6 +421,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::VERBOSE_FILE_READS_INFO, crate::methods::WRONG_SELF_CONVENTION_INFO, crate::methods::ZST_OFFSET_INFO, + crate::min_ident_chars::MIN_IDENT_CHARS_INFO, crate::minmax::MIN_MAX_INFO, crate::misc::SHORT_CIRCUIT_STATEMENT_INFO, crate::misc::TOPLEVEL_REF_ARG_INFO, @@ -416,6 +431,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::misc_early::DOUBLE_NEG_INFO, crate::misc_early::DUPLICATE_UNDERSCORE_ARGUMENT_INFO, crate::misc_early::MIXED_CASE_HEX_LITERALS_INFO, + crate::misc_early::REDUNDANT_AT_REST_PATTERN_INFO, crate::misc_early::REDUNDANT_PATTERN_INFO, crate::misc_early::SEPARATED_LITERAL_SUFFIX_INFO, crate::misc_early::UNNEEDED_FIELD_PATTERN_INFO, @@ -450,6 +466,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::needless_continue::NEEDLESS_CONTINUE_INFO, crate::needless_else::NEEDLESS_ELSE_INFO, crate::needless_for_each::NEEDLESS_FOR_EACH_INFO, + crate::needless_if::NEEDLESS_IF_INFO, crate::needless_late_init::NEEDLESS_LATE_INIT_INFO, crate::needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS_INFO, crate::needless_pass_by_value::NEEDLESS_PASS_BY_VALUE_INFO, @@ -524,6 +541,8 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::ranges::RANGE_MINUS_ONE_INFO, crate::ranges::RANGE_PLUS_ONE_INFO, crate::ranges::REVERSED_EMPTY_RANGES_INFO, + crate::raw_strings::NEEDLESS_RAW_STRINGS_INFO, + crate::raw_strings::NEEDLESS_RAW_STRING_HASHES_INFO, crate::rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT_INFO, crate::read_zero_byte_vec::READ_ZERO_BYTE_VEC_INFO, crate::redundant_async_block::REDUNDANT_ASYNC_BLOCK_INFO, @@ -535,6 +554,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::redundant_slicing::DEREF_BY_SLICING_INFO, crate::redundant_slicing::REDUNDANT_SLICING_INFO, crate::redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES_INFO, + crate::redundant_type_annotations::REDUNDANT_TYPE_ANNOTATIONS_INFO, crate::ref_option_ref::REF_OPTION_REF_INFO, crate::ref_patterns::REF_PATTERNS_INFO, crate::reference::DEREF_ADDROF_INFO, @@ -553,8 +573,10 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::shadow::SHADOW_SAME_INFO, crate::shadow::SHADOW_UNRELATED_INFO, crate::significant_drop_tightening::SIGNIFICANT_DROP_TIGHTENING_INFO, + crate::single_call_fn::SINGLE_CALL_FN_INFO, crate::single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES_INFO, crate::single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS_INFO, + crate::single_range_in_vec_init::SINGLE_RANGE_IN_VEC_INIT_INFO, crate::size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT_INFO, crate::size_of_ref::SIZE_OF_REF_INFO, crate::slow_vector_initialization::SLOW_VECTOR_INITIALIZATION_INFO, @@ -602,6 +624,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::transmute::UNSOUND_COLLECTION_TRANSMUTE_INFO, crate::transmute::USELESS_TRANSMUTE_INFO, crate::transmute::WRONG_TRANSMUTE_INFO, + crate::tuple_array_conversions::TUPLE_ARRAY_CONVERSIONS_INFO, crate::types::BORROWED_BOX_INFO, crate::types::BOX_COLLECTION_INFO, crate::types::LINKEDLIST_INFO, @@ -644,6 +667,9 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::useless_conversion::USELESS_CONVERSION_INFO, crate::vec::USELESS_VEC_INFO, crate::vec_init_then_push::VEC_INIT_THEN_PUSH_INFO, + crate::visibility::NEEDLESS_PUB_SELF_INFO, + crate::visibility::PUB_WITHOUT_SHORTHAND_INFO, + crate::visibility::PUB_WITH_SHORTHAND_INFO, crate::wildcard_imports::ENUM_GLOB_USE_INFO, crate::wildcard_imports::WILDCARD_IMPORTS_INFO, crate::write::PRINTLN_EMPTY_STRING_INFO, diff --git a/clippy_lints/src/default_constructed_unit_structs.rs b/clippy_lints/src/default_constructed_unit_structs.rs index fb037bbcbf3e..ca9514ccc7d0 100644 --- a/clippy_lints/src/default_constructed_unit_structs.rs +++ b/clippy_lints/src/default_constructed_unit_structs.rs @@ -8,7 +8,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { /// ### What it does - /// Check for construction on unit struct using `default`. + /// Checks for construction on unit struct using `default`. /// /// ### Why is this bad? /// This adds code complexity and an unnecessary function call. diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index 4e1a6cd4d735..e53a9877b20c 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -161,7 +161,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { let fields_def = &variant.fields; // Push field type then visit each field expr. - for field in fields.iter() { + for field in *fields { let bound = fields_def .iter() diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 1ecaa1a123ce..73556c1053ec 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -56,9 +56,11 @@ declare_clippy_lint! { /// let b = &*a; /// ``` /// - /// This lint excludes: + /// This lint excludes all of: /// ```rust,ignore /// let _ = d.unwrap().deref(); + /// let _ = Foo::deref(&foo); + /// let _ = ::deref(&foo); /// ``` #[clippy::version = "1.44.0"] pub EXPLICIT_DEREF_METHODS, @@ -355,15 +357,17 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { // start auto-deref. // 4. If the chain of non-user-defined derefs ends with a mutable re-borrow, and re-borrow // adjustments will not be inserted automatically, then leave one further reference to avoid - // moving a mutable borrow. - // e.g. - // fn foo(x: &mut Option<&mut T>, y: &mut T) { - // let x = match x { - // // Removing the borrow will cause `x` to be moved - // Some(x) => &mut *x, - // None => y - // }; - // } + // moving a mutable borrow. e.g. + // + // ```rust + // fn foo(x: &mut Option<&mut T>, y: &mut T) { + // let x = match x { + // // Removing the borrow will cause `x` to be moved + // Some(x) => &mut *x, + // None => y + // }; + // } + // ``` let deref_msg = "this expression creates a reference which is immediately dereferenced by the compiler"; let borrow_msg = "this expression borrows a value the compiler would automatically borrow"; @@ -1481,7 +1485,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data target_mut, } => { let mut app = Applicability::MachineApplicable; - let (expr_str, expr_is_macro_call) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app); + let (expr_str, _expr_is_macro_call) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app); let ty = cx.typeck_results().expr_ty(expr); let (_, ref_count) = peel_mid_ty_refs(ty); let deref_str = if ty_changed_count >= ref_count && ref_count != 0 { @@ -1504,11 +1508,20 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data "&" }; - let expr_str = if !expr_is_macro_call && is_final_ufcs && expr.precedence().order() < PREC_PREFIX { - format!("({expr_str})") + // expr_str (the suggestion) is never shown if is_final_ufcs is true, since it's + // `expr.kind == ExprKind::Call`. Therefore, this is, afaik, always unnecessary. + /* + expr_str = if !expr_is_macro_call && is_final_ufcs && expr.precedence().order() < PREC_PREFIX { + Cow::Owned(format!("({expr_str})")) } else { - expr_str.into_owned() + expr_str }; + */ + + // Fix #10850, do not lint if it's `Foo::deref` instead of `foo.deref()`. + if is_final_ufcs { + return; + } span_lint_and_sugg( cx, diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs index 8f68f90a2a13..ec0ca50cfec7 100644 --- a/clippy_lints/src/derivable_impls.rs +++ b/clippy_lints/src/derivable_impls.rs @@ -4,11 +4,13 @@ use clippy_utils::source::indent_of; use clippy_utils::{is_default_equivalent, peel_blocks}; use rustc_errors::Applicability; use rustc_hir::{ + self as hir, def::{CtorKind, CtorOf, DefKind, Res}, - Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, Ty, TyKind, + Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{Adt, AdtDef, SubstsRef}; +use rustc_middle::ty::adjustment::{Adjust, PointerCast}; +use rustc_middle::ty::{self, Adt, AdtDef, SubstsRef, Ty, TypeckResults}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::sym; @@ -75,13 +77,23 @@ 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, substs) => def.is_box() && substs[0].as_type().map_or(false, contains_trait_object), + ty::Dynamic(..) => true, + _ => false, + } +} + fn check_struct<'tcx>( cx: &LateContext<'tcx>, item: &'tcx Item<'_>, - self_ty: &Ty<'_>, + self_ty: &hir::Ty<'_>, func_expr: &Expr<'_>, adt_def: AdtDef<'_>, substs: SubstsRef<'_>, + typeck_results: &'tcx TypeckResults<'tcx>, ) { if let TyKind::Path(QPath::Resolved(_, p)) = self_ty.kind { if let Some(PathSegment { args, .. }) = p.segments.last() { @@ -96,10 +108,23 @@ fn check_struct<'tcx>( } } } + + // the default() call might unsize coerce to a trait object (e.g. Box to Box), + // which would not be the same if derived (see #10158). + // this closure checks both if the expr is equivalent to a `default()` call and does not + // have such coercions. + let is_default_without_adjusts = |expr| { + is_default_equivalent(cx, expr) + && typeck_results.expr_adjustments(expr).iter().all(|adj| { + !matches!(adj.kind, Adjust::Pointer(PointerCast::Unsize) + if contains_trait_object(adj.target)) + }) + }; + let should_emit = match peel_blocks(func_expr).kind { - ExprKind::Tup(fields) => fields.iter().all(|e| is_default_equivalent(cx, e)), - ExprKind::Call(callee, args) if is_path_self(callee) => args.iter().all(|e| is_default_equivalent(cx, e)), - ExprKind::Struct(_, fields, _) => fields.iter().all(|ef| is_default_equivalent(cx, ef.expr)), + ExprKind::Tup(fields) => fields.iter().all(is_default_without_adjusts), + ExprKind::Call(callee, args) if is_path_self(callee) => args.iter().all(is_default_without_adjusts), + ExprKind::Struct(_, fields, _) => fields.iter().all(|ef| is_default_without_adjusts(ef.expr)), _ => false, }; @@ -197,7 +222,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls { then { if adt_def.is_struct() { - check_struct(cx, item, self_ty, func_expr, adt_def, substs); + check_struct(cx, item, self_ty, func_expr, adt_def, substs, cx.tcx.typeck_body(*b)); } else if adt_def.is_enum() && self.msrv.meets(msrvs::DEFAULT_ENUM_ATTRIBUTE) { check_enum(cx, item, func_expr, adt_def); } diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index 10a2f0cb1e7e..a005a360e9ce 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -14,8 +14,8 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::traits::Reveal; use rustc_middle::ty::{ - self, BoundConstness, ClauseKind, GenericArgKind, GenericParamDefKind, ImplPolarity, ParamEnv, - ToPredicate, TraitPredicate, Ty, TyCtxt, + self, BoundConstness, ClauseKind, GenericArgKind, GenericParamDefKind, ImplPolarity, ParamEnv, ToPredicate, + TraitPredicate, Ty, TyCtxt, }; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::def_id::LocalDefId; @@ -520,7 +520,8 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> trait_ref: ty::TraitRef::new(tcx, eq_trait_id, [tcx.mk_param_from_def(param)]), constness: BoundConstness::NotConst, polarity: ImplPolarity::Positive, - }).to_predicate(tcx) + }) + .to_predicate(tcx) }), )), Reveal::UserFacing, diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 384aca7feadd..87d88f707529 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -571,6 +571,7 @@ fn check_doc<'a, Events: Iterator, Range, Span)> = Vec::new(); @@ -584,6 +585,8 @@ fn check_doc<'a, Events: Iterator, Range, Range Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> { if is_panic(self.cx, macro_call.def_id) || matches!( self.cx.tcx.item_name(macro_call.def_id).as_str(), - "assert" | "assert_eq" | "assert_ne" | "todo" + "assert" | "assert_eq" | "assert_ne" ) { self.panic_span = Some(macro_call.span); } } - // check for `unwrap` - if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { + // check for `unwrap` and `expect` for both `Option` and `Result` + if let Some(arglists) = method_chain_args(expr, &["unwrap"]).or(method_chain_args(expr, &["expect"])) { let receiver_ty = self.typeck_results.expr_ty(arglists[0].0).peel_refs(); if is_type_diagnostic_item(self.cx, receiver_ty, sym::Option) || is_type_diagnostic_item(self.cx, receiver_ty, sym::Result) diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs index 7a4b9a87aeb4..976ce47e8694 100644 --- a/clippy_lints/src/drop_forget_ref.rs +++ b/clippy_lints/src/drop_forget_ref.rs @@ -6,6 +6,7 @@ use rustc_hir::{Arm, Expr, ExprKind, LangItem, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; +use std::borrow::Cow; declare_clippy_lint! { /// ### What it does @@ -47,6 +48,27 @@ declare_clippy_lint! { "call to `std::mem::forget` with a value which does not implement `Drop`" } +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `std::mem::forget(t)` where `t` is + /// `Drop` or has a field that implements `Drop`. + /// + /// ### Why is this bad? + /// `std::mem::forget(t)` prevents `t` from running its + /// destructor, possibly causing leaks. + /// + /// ### Example + /// ```rust + /// # use std::mem; + /// # use std::rc::Rc; + /// mem::forget(Rc::new(55)) + /// ``` + #[clippy::version = "pre 1.29.0"] + pub MEM_FORGET, + restriction, + "`mem::forget` usage on `Drop` types, likely to cause memory leaks" +} + const DROP_NON_DROP_SUMMARY: &str = "call to `std::mem::drop` with a value that does not implement `Drop`. \ Dropping such a type only extends its contained lifetimes"; const FORGET_NON_DROP_SUMMARY: &str = "call to `std::mem::forget` with a value that does not implement `Drop`. \ @@ -55,6 +77,7 @@ const FORGET_NON_DROP_SUMMARY: &str = "call to `std::mem::forget` with a value t declare_lint_pass!(DropForgetRef => [ DROP_NON_DROP, FORGET_NON_DROP, + MEM_FORGET, ]); impl<'tcx> LateLintPass<'tcx> for DropForgetRef { @@ -67,7 +90,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef { let arg_ty = cx.typeck_results().expr_ty(arg); let is_copy = is_copy(cx, arg_ty); let drop_is_single_call_in_arm = is_single_call_in_arm(cx, arg, expr); - let (lint, msg) = match fn_name { + let (lint, msg, note_span) = match fn_name { // early return for uplifted lints: dropping_references, dropping_copy_types, forgetting_references, forgetting_copy_types sym::mem_drop if arg_ty.is_ref() && !drop_is_single_call_in_arm => return, sym::mem_forget if arg_ty.is_ref() => return, @@ -81,19 +104,34 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef { || drop_is_single_call_in_arm ) => { - (DROP_NON_DROP, DROP_NON_DROP_SUMMARY) - }, - sym::mem_forget if !arg_ty.needs_drop(cx.tcx, cx.param_env) => { - (FORGET_NON_DROP, FORGET_NON_DROP_SUMMARY) + (DROP_NON_DROP, DROP_NON_DROP_SUMMARY.into(), Some(arg.span)) }, + sym::mem_forget => { + if arg_ty.needs_drop(cx.tcx, cx.param_env) { + ( + 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)) { + "`Drop` type" + } else { + "type with `Drop` fields" + } + )), + None, + ) + } else { + (FORGET_NON_DROP, FORGET_NON_DROP_SUMMARY.into(), Some(arg.span)) + } + } _ => return, }; span_lint_and_note( cx, lint, expr.span, - msg, - Some(arg.span), + &msg, + note_span, &format!("argument has type `{arg_ty}`"), ); } diff --git a/clippy_lints/src/endian_bytes.rs b/clippy_lints/src/endian_bytes.rs new file mode 100644 index 000000000000..f470987833e4 --- /dev/null +++ b/clippy_lints/src/endian_bytes.rs @@ -0,0 +1,216 @@ +use crate::Lint; +use clippy_utils::{diagnostics::span_lint_and_then, is_lint_allowed}; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::{lint::in_external_macro, ty::Ty}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::Symbol; +use std::borrow::Cow; + +declare_clippy_lint! { + /// ### What it does + /// Checks for the usage of the `to_ne_bytes` method and/or the function `from_ne_bytes`. + /// + /// ### Why is this bad? + /// It's not, but some may prefer to specify the target endianness explicitly. + /// + /// ### Example + /// ```rust,ignore + /// let _x = 2i32.to_ne_bytes(); + /// let _y = 2i64.to_ne_bytes(); + /// ``` + #[clippy::version = "1.71.0"] + pub HOST_ENDIAN_BYTES, + restriction, + "disallows usage of the `to_ne_bytes` method" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for the usage of the `to_le_bytes` method and/or the function `from_le_bytes`. + /// + /// ### Why is this bad? + /// It's not, but some may wish to lint usage of this method, either to suggest using the host + /// endianness or big endian. + /// + /// ### Example + /// ```rust,ignore + /// let _x = 2i32.to_le_bytes(); + /// let _y = 2i64.to_le_bytes(); + /// ``` + #[clippy::version = "1.71.0"] + pub LITTLE_ENDIAN_BYTES, + restriction, + "disallows usage of the `to_le_bytes` method" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for the usage of the `to_be_bytes` method and/or the function `from_be_bytes`. + /// + /// ### Why is this bad? + /// It's not, but some may wish to lint usage of this method, either to suggest using the host + /// endianness or little endian. + /// + /// ### Example + /// ```rust,ignore + /// let _x = 2i32.to_be_bytes(); + /// let _y = 2i64.to_be_bytes(); + /// ``` + #[clippy::version = "1.71.0"] + pub BIG_ENDIAN_BYTES, + restriction, + "disallows usage of the `to_be_bytes` method" +} + +declare_lint_pass!(EndianBytes => [HOST_ENDIAN_BYTES, LITTLE_ENDIAN_BYTES, BIG_ENDIAN_BYTES]); + +const HOST_NAMES: [&str; 2] = ["from_ne_bytes", "to_ne_bytes"]; +const LITTLE_NAMES: [&str; 2] = ["from_le_bytes", "to_le_bytes"]; +const BIG_NAMES: [&str; 2] = ["from_be_bytes", "to_be_bytes"]; + +#[derive(Clone, Debug)] +enum LintKind { + Host, + Little, + Big, +} + +#[derive(Clone, Copy, PartialEq)] +enum Prefix { + From, + To, +} + +impl LintKind { + fn allowed(&self, cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + is_lint_allowed(cx, self.as_lint(), expr.hir_id) + } + + fn as_lint(&self) -> &'static Lint { + match self { + LintKind::Host => HOST_ENDIAN_BYTES, + LintKind::Little => LITTLE_ENDIAN_BYTES, + LintKind::Big => BIG_ENDIAN_BYTES, + } + } + + fn as_name(&self, prefix: Prefix) -> &str { + let index = usize::from(prefix == Prefix::To); + + match self { + LintKind::Host => HOST_NAMES[index], + LintKind::Little => LITTLE_NAMES[index], + LintKind::Big => BIG_NAMES[index], + } + } +} + +impl LateLintPass<'_> for EndianBytes { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + if in_external_macro(cx.sess(), expr.span) { + return; + } + + if_chain! { + if let ExprKind::MethodCall(method_name, receiver, args, ..) = expr.kind; + if args.is_empty(); + let ty = cx.typeck_results().expr_ty(receiver); + if ty.is_primitive_ty(); + if maybe_lint_endian_bytes(cx, expr, Prefix::To, method_name.ident.name, ty); + then { + return; + } + } + + if_chain! { + if let ExprKind::Call(function, ..) = expr.kind; + if let ExprKind::Path(qpath) = function.kind; + if let Some(def_id) = cx.qpath_res(&qpath, function.hir_id).opt_def_id(); + if let Some(function_name) = cx.get_def_path(def_id).last(); + let ty = cx.typeck_results().expr_ty(expr); + if ty.is_primitive_ty(); + then { + maybe_lint_endian_bytes(cx, expr, Prefix::From, *function_name, ty); + } + } + } +} + +fn maybe_lint_endian_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, prefix: Prefix, name: Symbol, ty: Ty<'_>) -> bool { + let ne = LintKind::Host.as_name(prefix); + let le = LintKind::Little.as_name(prefix); + let be = LintKind::Big.as_name(prefix); + + let (lint, other_lints) = match name.as_str() { + name if name == ne => ((&LintKind::Host), [(&LintKind::Little), (&LintKind::Big)]), + name if name == le => ((&LintKind::Little), [(&LintKind::Host), (&LintKind::Big)]), + name if name == be => ((&LintKind::Big), [(&LintKind::Host), (&LintKind::Little)]), + _ => return false, + }; + + let mut help = None; + + 'build_help: { + // all lints disallowed, don't give help here + if [&[lint], other_lints.as_slice()] + .concat() + .iter() + .all(|lint| !lint.allowed(cx, expr)) + { + break 'build_help; + } + + // ne_bytes and all other lints allowed + if lint.as_name(prefix) == ne && other_lints.iter().all(|lint| lint.allowed(cx, expr)) { + help = Some(Cow::Borrowed("specify the desired endianness explicitly")); + break 'build_help; + } + + // le_bytes where ne_bytes allowed but be_bytes is not, or le_bytes where ne_bytes allowed but + // le_bytes is not + if (lint.as_name(prefix) == le || lint.as_name(prefix) == be) && LintKind::Host.allowed(cx, expr) { + help = Some(Cow::Borrowed("use the native endianness instead")); + break 'build_help; + } + + let allowed_lints = other_lints.iter().filter(|lint| lint.allowed(cx, expr)); + let len = allowed_lints.clone().count(); + + let mut help_str = "use ".to_owned(); + + for (i, lint) in allowed_lints.enumerate() { + let only_one = len == 1; + if !only_one { + help_str.push_str("either of "); + } + + help_str.push_str(&format!("`{ty}::{}` ", lint.as_name(prefix))); + + if i != len && !only_one { + help_str.push_str("or "); + } + } + + help = Some(Cow::Owned(help_str + "instead")); + } + + span_lint_and_then( + cx, + lint.as_lint(), + expr.span, + &format!( + "usage of the {}`{ty}::{}`{}", + if prefix == Prefix::From { "function " } else { "" }, + lint.as_name(prefix), + if prefix == Prefix::To { " method" } else { "" }, + ), + move |diag| { + if let Some(help) = help { + diag.help(help); + } + }, + ); + + true +} diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs index e275efaba25f..d85650712db8 100644 --- a/clippy_lints/src/enum_clike.rs +++ b/clippy_lints/src/enum_clike.rs @@ -51,7 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant { .const_eval_poly(def_id.to_def_id()) .ok() .map(|val| rustc_middle::mir::ConstantKind::from_value(val, ty)); - if let Some(Constant::Int(val)) = constant.and_then(|c| miri_to_const(cx.tcx, c)) { + if let Some(Constant::Int(val)) = constant.and_then(|c| miri_to_const(cx, c)) { if let ty::Adt(adt, _) = ty.kind() { if adt.is_enum() { ty = adt.repr().discr_type().to_ty(cx.tcx); diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/enum_variants.rs index faac63404199..d4df6f7aa2d0 100644 --- a/clippy_lints/src/enum_variants.rs +++ b/clippy_lints/src/enum_variants.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_hir}; use clippy_utils::source::is_present_in_source; use clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_start}; -use rustc_hir::{EnumDef, Item, ItemKind, Variant}; +use rustc_hir::{EnumDef, Item, ItemKind, OwnerId, Variant}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; @@ -105,18 +105,20 @@ declare_clippy_lint! { } pub struct EnumVariantNames { - modules: Vec<(Symbol, String)>, + modules: Vec<(Symbol, String, OwnerId)>, threshold: u64, avoid_breaking_exported_api: bool, + allow_private_module_inception: bool, } impl EnumVariantNames { #[must_use] - pub fn new(threshold: u64, avoid_breaking_exported_api: bool) -> Self { + pub fn new(threshold: u64, avoid_breaking_exported_api: bool, allow_private_module_inception: bool) -> Self { Self { modules: Vec::new(), threshold, avoid_breaking_exported_api, + allow_private_module_inception, } } } @@ -252,18 +254,19 @@ impl LateLintPass<'_> for EnumVariantNames { let item_name = item.ident.name.as_str(); let item_camel = to_camel_case(item_name); if !item.span.from_expansion() && is_present_in_source(cx, item.span) { - if let Some((mod_name, mod_camel)) = self.modules.last() { + if let [.., (mod_name, mod_camel, owner_id)] = &*self.modules { // constants don't have surrounding modules if !mod_camel.is_empty() { - if mod_name == &item.ident.name { - if let ItemKind::Mod(..) = item.kind { - span_lint( - cx, - MODULE_INCEPTION, - item.span, - "module has the same name as its containing module", - ); - } + if mod_name == &item.ident.name + && let ItemKind::Mod(..) = item.kind + && (!self.allow_private_module_inception || cx.tcx.visibility(owner_id.def_id).is_public()) + { + span_lint( + cx, + MODULE_INCEPTION, + item.span, + "module has the same name as its containing module", + ); } // The `module_name_repetitions` lint should only trigger if the item has the module in its // name. Having the same name is accepted. @@ -302,6 +305,6 @@ impl LateLintPass<'_> for EnumVariantNames { check_variant(cx, self.threshold, def, item_name, item.span); } } - self.modules.push((item.ident.name, item_camel)); + self.modules.push((item.ident.name, item_camel, item.owner_id)); } } diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index c919b4de65de..58e62d1f3d37 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -120,6 +120,13 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { if !is_type_diagnostic_item(cx, callee_ty_unadjusted, sym::Arc); if !is_type_diagnostic_item(cx, callee_ty_unadjusted, sym::Rc); if let ty::Closure(_, substs) = *closure_ty.kind(); + // Don't lint if this is an inclusive range expression. + // They desugar to a call to `RangeInclusiveNew` which would have odd suggestions. (#10684) + if !matches!(higher::Range::hir(body.value), Some(higher::Range { + start: Some(_), + end: Some(_), + limits: rustc_ast::RangeLimits::Closed + })); then { span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure", |diag| { if let Some(mut snippet) = snippet_opt(cx, callee.span) { @@ -136,6 +143,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { // Mutable closure is used after current expr; we cannot consume it. snippet = format!("&mut {snippet}"); } + diag.span_suggestion( expr.span, "replace the closure with the function itself", diff --git a/clippy_lints/src/excessive_nesting.rs b/clippy_lints/src/excessive_nesting.rs new file mode 100644 index 000000000000..d04d833e6304 --- /dev/null +++ b/clippy_lints/src/excessive_nesting.rs @@ -0,0 +1,181 @@ +use clippy_utils::{diagnostics::span_lint_and_help, source::snippet}; +use rustc_ast::{ + node_id::NodeSet, + visit::{walk_block, walk_item, Visitor}, + Block, Crate, Inline, Item, ItemKind, ModKind, NodeId, +}; +use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::Span; + +declare_clippy_lint! { + /// ### What it does + /// Checks for blocks which are nested beyond a certain threshold. + /// + /// Note: Even though this lint is warn-by-default, it will only trigger if a maximum nesting level is defined in the clippy.toml file. + /// + /// ### Why is this bad? + /// It can severely hinder readability. + /// + /// ### Example + /// An example clippy.toml configuration: + /// ```toml + /// # clippy.toml + /// excessive-nesting-threshold = 3 + /// ``` + /// ```rust,ignore + /// // lib.rs + /// pub mod a { + /// pub struct X; + /// impl X { + /// pub fn run(&self) { + /// if true { + /// // etc... + /// } + /// } + /// } + /// } + /// ``` + /// Use instead: + /// ```rust,ignore + /// // a.rs + /// fn private_run(x: &X) { + /// if true { + /// // etc... + /// } + /// } + /// + /// pub struct X; + /// impl X { + /// pub fn run(&self) { + /// private_run(self); + /// } + /// } + /// ``` + /// ```rust,ignore + /// // lib.rs + /// pub mod a; + /// ``` + #[clippy::version = "1.70.0"] + pub EXCESSIVE_NESTING, + complexity, + "checks for blocks nested beyond a certain threshold" +} +impl_lint_pass!(ExcessiveNesting => [EXCESSIVE_NESTING]); + +#[derive(Clone)] +pub struct ExcessiveNesting { + pub excessive_nesting_threshold: u64, + pub nodes: NodeSet, +} + +impl ExcessiveNesting { + pub fn check_node_id(&self, cx: &EarlyContext<'_>, span: Span, node_id: NodeId) { + if self.nodes.contains(&node_id) { + span_lint_and_help( + cx, + EXCESSIVE_NESTING, + span, + "this block is too nested", + None, + "try refactoring your code to minimize nesting", + ); + } + } +} + +impl EarlyLintPass for ExcessiveNesting { + fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) { + if self.excessive_nesting_threshold == 0 { + return; + } + + let mut visitor = NestingVisitor { + conf: self, + cx, + nest_level: 0, + }; + + for item in &krate.items { + visitor.visit_item(item); + } + } + + fn check_block(&mut self, cx: &EarlyContext<'_>, block: &Block) { + self.check_node_id(cx, block.span, block.id); + } + + fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { + self.check_node_id(cx, item.span, item.id); + } +} + +struct NestingVisitor<'conf, 'cx> { + conf: &'conf mut ExcessiveNesting, + cx: &'cx EarlyContext<'cx>, + nest_level: u64, +} + +impl NestingVisitor<'_, '_> { + fn check_indent(&mut self, span: Span, id: NodeId) -> bool { + if self.nest_level > self.conf.excessive_nesting_threshold && !in_external_macro(self.cx.sess(), span) { + self.conf.nodes.insert(id); + + return true; + } + + false + } +} + +impl<'conf, 'cx> Visitor<'_> for NestingVisitor<'conf, 'cx> { + fn visit_block(&mut self, block: &Block) { + if block.span.from_expansion() { + return; + } + + // TODO: This should be rewritten using `LateLintPass` so we can use `is_from_proc_macro` instead, + // but for now, this is fine. + let snippet = snippet(self.cx, block.span, "{}").trim().to_owned(); + if !snippet.starts_with('{') || !snippet.ends_with('}') { + return; + } + + self.nest_level += 1; + + if !self.check_indent(block.span, block.id) { + walk_block(self, block); + } + + self.nest_level -= 1; + } + + fn visit_item(&mut self, item: &Item) { + if item.span.from_expansion() { + return; + } + + match &item.kind { + ItemKind::Trait(_) | ItemKind::Impl(_) | ItemKind::Mod(.., ModKind::Loaded(_, Inline::Yes, _)) => { + self.nest_level += 1; + + if !self.check_indent(item.span, item.id) { + walk_item(self, item); + } + + self.nest_level -= 1; + }, + // Reset nesting level for non-inline modules (since these are in another file) + ItemKind::Mod(..) => walk_item( + &mut NestingVisitor { + conf: self.conf, + cx: self.cx, + nest_level: 0, + }, + item, + ), + _ => walk_item(self, item), + } + } +} diff --git a/clippy_lints/src/extra_unused_type_parameters.rs b/clippy_lints/src/extra_unused_type_parameters.rs index eeb4de8b58f4..126bed6789c4 100644 --- a/clippy_lints/src/extra_unused_type_parameters.rs +++ b/clippy_lints/src/extra_unused_type_parameters.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; +use clippy_utils::is_from_proc_macro; use clippy_utils::trait_ref_of_method; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; @@ -265,6 +266,7 @@ impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { if let ItemKind::Fn(_, generics, body_id) = item.kind && !self.is_empty_exported_or_macro(cx, item.span, item.owner_id.def_id, body_id) + && !is_from_proc_macro(cx, item) { let mut walker = TypeWalker::new(cx, generics); walk_item(&mut walker, item); diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs index 93bf50fd5e79..d182bb621950 100644 --- a/clippy_lints/src/float_literal.rs +++ b/clippy_lints/src/float_literal.rs @@ -82,19 +82,24 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral { LitFloatType::Suffixed(ast::FloatTy::F64) => Some("f64"), LitFloatType::Unsuffixed => None }; - let (is_whole, mut float_str) = match fty { + let (is_whole, is_inf, mut float_str) = match fty { FloatTy::F32 => { let value = sym_str.parse::().unwrap(); - (value.fract() == 0.0, formatter.format(value)) + (value.fract() == 0.0, value.is_infinite(), formatter.format(value)) }, FloatTy::F64 => { let value = sym_str.parse::().unwrap(); - (value.fract() == 0.0, formatter.format(value)) + + (value.fract() == 0.0, value.is_infinite(), formatter.format(value)) }, }; + if is_inf { + return; + } + if is_whole && !sym_str.contains(|c| c == 'e' || c == 'E') { // Normalize the literal by stripping the fractional portion if sym_str.split('.').next().unwrap() != float_str { diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index 3c55a563af45..5e0fcd743392 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -215,7 +215,7 @@ fn check_ln1p(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) { // ranges [-16777215, 16777216) for type f32 as whole number floats outside // this range are lossy and ambiguous. #[expect(clippy::cast_possible_truncation)] -fn get_integer_from_float_constant(value: &Constant) -> Option { +fn get_integer_from_float_constant(value: &Constant<'_>) -> Option { match value { F32(num) if num.fract() == 0.0 => { if (-16_777_215.0..16_777_216.0).contains(num) { diff --git a/clippy_lints/src/format_push_string.rs b/clippy_lints/src/format_push_string.rs index 68c5c3673fe1..45f67020c2db 100644 --- a/clippy_lints/src/format_push_string.rs +++ b/clippy_lints/src/format_push_string.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::is_type_lang_item; -use clippy_utils::{match_def_path, paths, peel_hir_expr_refs}; -use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem}; +use clippy_utils::{higher, match_def_path, paths}; +use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem, MatchSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; @@ -44,10 +44,24 @@ fn is_string(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { is_type_lang_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), LangItem::String) } fn is_format(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { - if let Some(macro_def_id) = e.span.ctxt().outer_expn_data().macro_def_id { + let e = e.peel_blocks().peel_borrows(); + + if e.span.from_expansion() + && let Some(macro_def_id) = e.span.ctxt().outer_expn_data().macro_def_id + { cx.tcx.get_diagnostic_name(macro_def_id) == Some(sym::format_macro) + } else if let Some(higher::If { then, r#else, .. }) = higher::If::hir(e) { + is_format(cx, then) || r#else.is_some_and(|e| is_format(cx, e)) } else { - false + match higher::IfLetOrMatch::parse(cx, e) { + Some(higher::IfLetOrMatch::Match(_, arms, MatchSource::Normal)) => { + arms.iter().any(|arm| is_format(cx, arm.body)) + }, + Some(higher::IfLetOrMatch::IfLet(_, _, then, r#else)) => { + is_format(cx, then) ||r#else.is_some_and(|e| is_format(cx, e)) + }, + _ => false, + } } } @@ -68,7 +82,6 @@ impl<'tcx> LateLintPass<'tcx> for FormatPushString { }, _ => return, }; - let (arg, _) = peel_hir_expr_refs(arg); if is_format(cx, arg) { span_lint_and_help( cx, diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index 4762b354392b..d03480c21084 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -236,6 +236,12 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) { } } + // Don't warn if the only thing inside post_else_post_eol is a comment block. + let trimmed_post_else_post_eol = post_else_post_eol.trim(); + if trimmed_post_else_post_eol.starts_with("/*") && trimmed_post_else_post_eol.ends_with("*/") { + return + } + let else_desc = if is_if(else_) { "if" } else { "{..}" }; span_lint_and_note( cx, diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs index 10ce2a0f0c7e..92d67ef359dc 100644 --- a/clippy_lints/src/from_over_into.rs +++ b/clippy_lints/src/from_over_into.rs @@ -134,9 +134,10 @@ impl<'a, 'tcx> Visitor<'tcx> for SelfFinder<'a, 'tcx> { kw::SelfUpper => self.upper.push(segment.ident.span), _ => continue, } + + self.invalid |= segment.ident.span.from_expansion(); } - self.invalid |= path.span.from_expansion(); if !self.invalid { walk_path(self, path); } @@ -156,6 +157,11 @@ fn convert_to_from( self_ty: &Ty<'_>, impl_item_ref: &ImplItemRef, ) -> Option> { + if !target_ty.find_self_aliases().is_empty() { + // It's tricky to expand self-aliases correctly, we'll ignore it to not cause a + // bad suggestion/fix. + return None; + } let impl_item = cx.tcx.hir().impl_item(impl_item_ref.id); let ImplItemKind::Fn(ref sig, body_id) = impl_item.kind else { return None }; let body = cx.tcx.hir().body(body_id); diff --git a/clippy_lints/src/incorrect_impls.rs b/clippy_lints/src/incorrect_impls.rs new file mode 100644 index 000000000000..13cc0b23ba33 --- /dev/null +++ b/clippy_lints/src/incorrect_impls.rs @@ -0,0 +1,124 @@ +use clippy_utils::{diagnostics::span_lint_and_sugg, get_parent_node, last_path_segment, ty::implements_trait}; +use rustc_errors::Applicability; +use rustc_hir::{ExprKind, ImplItem, ImplItemKind, ItemKind, Node, UnOp}; +use rustc_hir_analysis::hir_ty_to_ty; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::EarlyBinder; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::{sym, symbol}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for manual implementations of `Clone` when `Copy` is already implemented. + /// + /// ### Why is this bad? + /// If both `Clone` and `Copy` are implemented, they must agree. This is done by dereferencing + /// `self` in `Clone`'s implementation. Anything else is incorrect. + /// + /// ### Example + /// ```rust,ignore + /// #[derive(Eq, PartialEq)] + /// struct A(u32); + /// + /// impl Clone for A { + /// fn clone(&self) -> Self { + /// Self(self.0) + /// } + /// } + /// + /// impl Copy for A {} + /// ``` + /// Use instead: + /// ```rust,ignore + /// #[derive(Eq, PartialEq)] + /// struct A(u32); + /// + /// impl Clone for A { + /// fn clone(&self) -> Self { + /// *self + /// } + /// } + /// + /// impl Copy for A {} + /// ``` + #[clippy::version = "1.72.0"] + pub INCORRECT_CLONE_IMPL_ON_COPY_TYPE, + correctness, + "manual implementation of `Clone` on a `Copy` type" +} +declare_lint_pass!(IncorrectImpls => [INCORRECT_CLONE_IMPL_ON_COPY_TYPE]); + +impl LateLintPass<'_> for IncorrectImpls { + #[expect(clippy::needless_return)] + fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &ImplItem<'_>) { + let node = get_parent_node(cx.tcx, impl_item.hir_id()); + let Some(Node::Item(item)) = node else { + return; + }; + let ItemKind::Impl(imp) = item.kind else { + return; + }; + let Some(trait_impl) = cx.tcx.impl_trait_ref(item.owner_id).map(EarlyBinder::skip_binder) else { + return; + }; + let trait_impl_def_id = trait_impl.def_id; + if cx.tcx.is_automatically_derived(item.owner_id.to_def_id()) { + return; + } + let ImplItemKind::Fn(_, impl_item_id) = cx.tcx.hir().impl_item(impl_item.impl_item_id()).kind else { + return; + }; + let body = cx.tcx.hir().body(impl_item_id); + let ExprKind::Block(block, ..) = body.value.kind else { + return; + }; + // Above is duplicated from the `duplicate_manual_partial_ord_impl` branch. + // Remove it while solving conflicts once that PR is merged. + + // Actual implementation; remove this comment once aforementioned PR is merged + if cx.tcx.is_diagnostic_item(sym::Clone, trait_impl_def_id) + && let Some(copy_def_id) = cx.tcx.get_diagnostic_item(sym::Copy) + && implements_trait( + cx, + hir_ty_to_ty(cx.tcx, imp.self_ty), + copy_def_id, + trait_impl.substs, + ) + { + if impl_item.ident.name == sym::clone { + if block.stmts.is_empty() + && let Some(expr) = block.expr + && let ExprKind::Unary(UnOp::Deref, inner) = expr.kind + && let ExprKind::Path(qpath) = inner.kind + && last_path_segment(&qpath).ident.name == symbol::kw::SelfLower + {} else { + span_lint_and_sugg( + cx, + INCORRECT_CLONE_IMPL_ON_COPY_TYPE, + block.span, + "incorrect implementation of `clone` on a `Copy` type", + "change this to", + "{ *self }".to_owned(), + Applicability::MaybeIncorrect, + ); + + return; + } + } + + if impl_item.ident.name == sym::clone_from { + span_lint_and_sugg( + cx, + INCORRECT_CLONE_IMPL_ON_COPY_TYPE, + impl_item.span, + "incorrect implementation of `clone_from` on a `Copy` type", + "remove this", + String::new(), + Applicability::MaybeIncorrect, + ); + + return; + } + } + } +} diff --git a/clippy_lints/src/items_after_test_module.rs b/clippy_lints/src/items_after_test_module.rs index b992d689aa97..40378ee8205c 100644 --- a/clippy_lints/src/items_after_test_module.rs +++ b/clippy_lints/src/items_after_test_module.rs @@ -1,4 +1,4 @@ -use clippy_utils::{diagnostics::span_lint_and_help, is_in_cfg_test}; +use clippy_utils::{diagnostics::span_lint_and_help, is_from_proc_macro, is_in_cfg_test}; use rustc_hir::{HirId, ItemId, ItemKind, Mod}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; @@ -59,6 +59,7 @@ impl LateLintPass<'_> for ItemsAfterTestModule { if !matches!(item.kind, ItemKind::Mod(_)); if !is_in_cfg_test(cx.tcx, itid.hir_id()); // The item isn't in the testing module itself if !in_external_macro(cx.sess(), item.span); + if !is_from_proc_macro(cx, item); then { span_lint_and_help(cx, ITEMS_AFTER_TEST_MODULE, test_mod_span.unwrap().with_hi(item.span.hi()), "items were found after the testing module", None, "move the items to before the testing module was defined"); diff --git a/clippy_lints/src/large_stack_frames.rs b/clippy_lints/src/large_stack_frames.rs new file mode 100644 index 000000000000..9c0cc978a391 --- /dev/null +++ b/clippy_lints/src/large_stack_frames.rs @@ -0,0 +1,162 @@ +use std::ops::AddAssign; + +use clippy_utils::diagnostics::span_lint_and_note; +use clippy_utils::fn_has_unsatisfiable_preds; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::intravisit::FnKind; +use rustc_hir::Body; +use rustc_hir::FnDecl; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::declare_tool_lint; +use rustc_session::impl_lint_pass; +use rustc_span::Span; + +declare_clippy_lint! { + /// ### What it does + /// Checks for functions that use a lot of stack space. + /// + /// This often happens when constructing a large type, such as an array with a lot of elements, + /// or constructing *many* smaller-but-still-large structs, or copying around a lot of large types. + /// + /// This lint is a more general version of [`large_stack_arrays`](https://rust-lang.github.io/rust-clippy/master/#large_stack_arrays) + /// that is intended to look at functions as a whole instead of only individual array expressions inside of a function. + /// + /// ### Why is this bad? + /// The stack region of memory is very limited in size (usually *much* smaller than the heap) and attempting to + /// use too much will result in a stack overflow and crash the program. + /// To avoid this, you should consider allocating large types on the heap instead (e.g. by boxing them). + /// + /// Keep in mind that the code path to construction of large types does not even need to be reachable; + /// it purely needs to *exist* inside of the function to contribute to the stack size. + /// For example, this causes a stack overflow even though the branch is unreachable: + /// ```rust,ignore + /// fn main() { + /// if false { + /// let x = [0u8; 10000000]; // 10 MB stack array + /// black_box(&x); + /// } + /// } + /// ``` + /// + /// ### Known issues + /// False positives. The stack size that clippy sees is an estimated value and can be vastly different + /// from the actual stack usage after optimizations passes have run (especially true in release mode). + /// Modern compilers are very smart and are able to optimize away a lot of unnecessary stack allocations. + /// In debug mode however, it is usually more accurate. + /// + /// This lint works by summing up the size of all variables that the user typed, variables that were + /// implicitly introduced by the compiler for temporaries, function arguments and the return value, + /// and comparing them against a (configurable, but high-by-default). + /// + /// ### Example + /// This function creates four 500 KB arrays on the stack. Quite big but just small enough to not trigger `large_stack_arrays`. + /// However, looking at the function as a whole, it's clear that this uses a lot of stack space. + /// ```rust + /// struct QuiteLargeType([u8; 500_000]); + /// fn foo() { + /// // ... some function that uses a lot of stack space ... + /// let _x1 = QuiteLargeType([0; 500_000]); + /// let _x2 = QuiteLargeType([0; 500_000]); + /// let _x3 = QuiteLargeType([0; 500_000]); + /// let _x4 = QuiteLargeType([0; 500_000]); + /// } + /// ``` + /// + /// Instead of doing this, allocate the arrays on the heap. + /// This currently requires going through a `Vec` first and then converting it to a `Box`: + /// ```rust + /// struct NotSoLargeType(Box<[u8]>); + /// + /// fn foo() { + /// let _x1 = NotSoLargeType(vec![0; 500_000].into_boxed_slice()); + /// // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Now heap allocated. + /// // The size of `NotSoLargeType` is 16 bytes. + /// // ... + /// } + /// ``` + #[clippy::version = "1.71.0"] + pub LARGE_STACK_FRAMES, + nursery, + "checks for functions that allocate a lot of stack space" +} + +pub struct LargeStackFrames { + maximum_allowed_size: u64, +} + +impl LargeStackFrames { + #[must_use] + pub fn new(size: u64) -> Self { + Self { + maximum_allowed_size: size, + } + } +} + +impl_lint_pass!(LargeStackFrames => [LARGE_STACK_FRAMES]); + +#[derive(Copy, Clone)] +enum Space { + Used(u64), + Overflow, +} + +impl Space { + pub fn exceeds_limit(self, limit: u64) -> bool { + match self { + Self::Used(used) => used > limit, + Self::Overflow => true, + } + } +} + +impl AddAssign for Space { + fn add_assign(&mut self, rhs: u64) { + if let Self::Used(lhs) = self { + match lhs.checked_add(rhs) { + Some(sum) => *self = Self::Used(sum), + None => *self = Self::Overflow, + } + } + } +} + +impl<'tcx> LateLintPass<'tcx> for LargeStackFrames { + fn check_fn( + &mut self, + cx: &LateContext<'tcx>, + _: FnKind<'tcx>, + _: &'tcx FnDecl<'tcx>, + _: &'tcx Body<'tcx>, + span: Span, + local_def_id: LocalDefId, + ) { + let def_id = local_def_id.to_def_id(); + // Building MIR for `fn`s with unsatisfiable preds results in ICE. + if fn_has_unsatisfiable_preds(cx, def_id) { + return; + } + + let mir = cx.tcx.optimized_mir(def_id); + let param_env = cx.tcx.param_env(def_id); + + let mut frame_size = Space::Used(0); + + for local in &mir.local_decls { + if let Ok(layout) = cx.tcx.layout_of(param_env.and(local.ty)) { + frame_size += layout.size.bytes(); + } + } + + if frame_size.exceeds_limit(self.maximum_allowed_size) { + span_lint_and_note( + cx, + LARGE_STACK_FRAMES, + span, + "this function allocates a large amount of stack space", + None, + "allocating large amounts of stack space can overflow the stack", + ); + } + } +} diff --git a/clippy_lints/src/let_with_type_underscore.rs b/clippy_lints/src/let_with_type_underscore.rs index 2f10e3d25813..4e9d77ea156a 100644 --- a/clippy_lints/src/let_with_type_underscore.rs +++ b/clippy_lints/src/let_with_type_underscore.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::source::snippet; use rustc_hir::{Local, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; @@ -25,14 +26,21 @@ declare_clippy_lint! { declare_lint_pass!(UnderscoreTyped => [LET_WITH_TYPE_UNDERSCORE]); impl LateLintPass<'_> for UnderscoreTyped { - fn check_local<'tcx>(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) { + fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) { if_chain! { if !in_external_macro(cx.tcx.sess, local.span); if let Some(ty) = local.ty; // Ensure that it has a type defined if let TyKind::Infer = &ty.kind; // that type is '_' if local.span.ctxt() == ty.span.ctxt(); then { - span_lint_and_help(cx, + // NOTE: Using `is_from_proc_macro` on `init` will require that it's initialized, + // this doesn't. Alternatively, `WithSearchPat` can be implemented for `Ty` + if snippet(cx, ty.span, "_").trim() != "_" { + return; + } + + span_lint_and_help( + cx, LET_WITH_TYPE_UNDERSCORE, local.span, "variable declared with type underscore", diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 4a23edb58aaa..87329ee5e14a 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -68,6 +68,7 @@ mod renamed_lints; mod allow_attributes; mod almost_complete_range; mod approx_const; +mod arc_with_non_send_sync; mod as_conversions; mod asm_syntax; mod assertions_on_constants; @@ -114,6 +115,7 @@ mod else_if_without_else; mod empty_drop; mod empty_enum; mod empty_structs_with_brackets; +mod endian_bytes; mod entry; mod enum_clike; mod enum_variants; @@ -121,6 +123,7 @@ mod equatable_if_let; mod escape; mod eta_reduction; mod excessive_bools; +mod excessive_nesting; mod exhaustive_items; mod exit; mod explicit_write; @@ -147,6 +150,7 @@ mod implicit_return; mod implicit_saturating_add; mod implicit_saturating_sub; mod inconsistent_struct_constructor; +mod incorrect_impls; mod index_refutable_slice; mod indexing_slicing; mod infinite_iter; @@ -165,6 +169,7 @@ mod large_enum_variant; mod large_futures; mod large_include_file; mod large_stack_arrays; +mod large_stack_frames; mod len_zero; mod let_if_seq; mod let_underscore; @@ -183,6 +188,7 @@ mod manual_is_ascii_check; mod manual_let_else; mod manual_main_separator_str; mod manual_non_exhaustive; +mod manual_range_patterns; mod manual_rem_euclid; mod manual_retain; mod manual_slice_size_calculation; @@ -191,9 +197,9 @@ mod manual_strip; mod map_unit_fn; mod match_result_ok; mod matches; -mod mem_forget; mod mem_replace; mod methods; +mod min_ident_chars; mod minmax; mod misc; mod misc_early; @@ -220,6 +226,7 @@ mod needless_borrowed_ref; mod needless_continue; mod needless_else; mod needless_for_each; +mod needless_if; mod needless_late_init; mod needless_parens_on_range_literals; mod needless_pass_by_value; @@ -256,6 +263,7 @@ mod pub_use; mod question_mark; mod question_mark_used; mod ranges; +mod raw_strings; mod rc_clone_in_vec_init; mod read_zero_byte_vec; mod redundant_async_block; @@ -266,6 +274,7 @@ mod redundant_field_names; mod redundant_pub_crate; mod redundant_slicing; mod redundant_static_lifetimes; +mod redundant_type_annotations; mod ref_option_ref; mod ref_patterns; mod reference; @@ -279,8 +288,10 @@ mod semicolon_if_nothing_returned; mod serde_api; mod shadow; mod significant_drop_tightening; +mod single_call_fn; mod single_char_lifetime_names; mod single_component_path_imports; +mod single_range_in_vec_init; mod size_of_in_element_count; mod size_of_ref; mod slow_vector_initialization; @@ -300,6 +311,7 @@ mod to_digit_is_some; mod trailing_empty_array; mod trait_bounds; mod transmute; +mod tuple_array_conversions; mod types; mod undocumented_unsafe_blocks; mod unicode; @@ -327,6 +339,7 @@ mod use_self; mod useless_conversion; mod vec; mod vec_init_then_push; +mod visibility; mod wildcard_imports; mod write; mod zero_div_zero; @@ -486,26 +499,27 @@ pub(crate) struct LintInfo { explanation: &'static str, } -pub fn explain(name: &str) { +pub fn explain(name: &str) -> i32 { let target = format!("clippy::{}", name.to_ascii_uppercase()); - match declared_lints::LINTS.iter().find(|info| info.lint.name == target) { - Some(info) => { - println!("{}", info.explanation); - // Check if the lint has configuration - let mdconf = get_configuration_metadata(); - if let Some(config_vec_positions) = mdconf - .iter() - .find_all(|cconf| cconf.lints.contains(&info.lint.name_lower()[8..].to_owned())) - { - // If it has, print it - println!("### Configuration for {}:\n", info.lint.name_lower()); - for position in config_vec_positions { - let conf = &mdconf[position]; - println!(" - {}: {} (default: {})", conf.name, conf.doc, conf.default); - } + if let Some(info) = declared_lints::LINTS.iter().find(|info| info.lint.name == target) { + println!("{}", info.explanation); + // Check if the lint has configuration + let mdconf = get_configuration_metadata(); + if let Some(config_vec_positions) = mdconf + .iter() + .find_all(|cconf| cconf.lints.contains(&info.lint.name_lower()[8..].to_owned())) + { + // If it has, print it + println!("### Configuration for {}:\n", info.lint.name_lower()); + for position in config_vec_positions { + let conf = &mdconf[position]; + println!(" - {}: {} (default: {})", conf.name, conf.doc, conf.default); } - }, - None => println!("unknown lint: {name}"), + } + 0 + } else { + println!("unknown lint: {name}"); + 1 } } @@ -564,6 +578,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::::default()); store.register_late_pass(|_| Box::new(utils::internal_lints::outer_expn_data_pass::OuterExpnDataPass)); store.register_late_pass(|_| Box::new(utils::internal_lints::msrv_attr_impl::MsrvAttrImpl)); + store.register_late_pass(|_| { + Box::new(utils::internal_lints::almost_standard_lint_formulation::AlmostStandardFormulation::new()) + }); } let arithmetic_side_effects_allowed = conf.arithmetic_side_effects_allowed.clone(); @@ -672,7 +689,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: }); store.register_late_pass(|_| Box::::default()); store.register_late_pass(|_| Box::new(unit_types::UnitTypes)); - store.register_late_pass(|_| Box::new(loops::Loops)); + store.register_late_pass(move |_| Box::new(loops::Loops::new(msrv()))); store.register_late_pass(|_| Box::::default()); store.register_late_pass(|_| Box::new(lifetimes::Lifetimes)); store.register_late_pass(|_| Box::new(entry::HashMapPass)); @@ -693,7 +710,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: }); let too_large_for_stack = conf.too_large_for_stack; store.register_late_pass(move |_| Box::new(escape::BoxedLocal { too_large_for_stack })); - store.register_late_pass(move |_| Box::new(vec::UselessVec { too_large_for_stack })); + store.register_late_pass(move |_| { + Box::new(vec::UselessVec { + too_large_for_stack, + msrv: msrv(), + }) + }); store.register_late_pass(|_| Box::new(panic_unimplemented::PanicUnimplemented)); store.register_late_pass(|_| Box::new(strings::StringLitAsBytes)); store.register_late_pass(|_| Box::new(derive::Derive)); @@ -725,7 +747,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: let missing_docs_in_crate_items = conf.missing_docs_in_crate_items; store.register_late_pass(move |_| Box::new(doc::DocMarkdown::new(doc_valid_idents.clone()))); store.register_late_pass(|_| Box::new(neg_multiply::NegMultiply)); - store.register_late_pass(|_| Box::new(mem_forget::MemForget)); store.register_late_pass(|_| Box::new(let_if_seq::LetIfSeq)); store.register_late_pass(|_| Box::new(mixed_read_write_in_expression::EvalOrderDependence)); store.register_late_pass(move |_| Box::new(missing_doc::MissingDoc::new(missing_docs_in_crate_items))); @@ -751,7 +772,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::::default()); store.register_late_pass(|_| Box::new(implicit_hasher::ImplicitHasher)); store.register_late_pass(|_| Box::new(fallible_impl_from::FallibleImplFrom)); - store.register_late_pass(|_| Box::new(question_mark::QuestionMark)); + store.register_late_pass(|_| Box::::default()); store.register_late_pass(|_| Box::new(question_mark_used::QuestionMarkUsed)); store.register_early_pass(|| Box::new(suspicious_operation_groupings::SuspiciousOperationGroupings)); store.register_late_pass(|_| Box::new(suspicious_trait_impl::SuspiciousImpl)); @@ -773,7 +794,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(assertions_on_result_states::AssertionsOnResultStates)); store.register_late_pass(|_| Box::new(inherent_to_string::InherentToString)); let max_trait_bounds = conf.max_trait_bounds; - store.register_late_pass(move |_| Box::new(trait_bounds::TraitBounds::new(max_trait_bounds))); + store.register_late_pass(move |_| Box::new(trait_bounds::TraitBounds::new(max_trait_bounds, msrv()))); store.register_late_pass(|_| Box::new(comparison_chain::ComparisonChain)); let ignore_interior_mutability = conf.ignore_interior_mutability.clone(); store.register_late_pass(move |_| Box::new(mut_key::MutableKeyType::new(ignore_interior_mutability.clone()))); @@ -785,7 +806,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| Box::new(int_plus_one::IntPlusOne)); store.register_early_pass(|| Box::new(formatting::Formatting)); store.register_early_pass(|| Box::new(misc_early::MiscEarlyLints)); - store.register_early_pass(|| Box::new(redundant_closure_call::RedundantClosureCall)); store.register_late_pass(|_| Box::new(redundant_closure_call::RedundantClosureCall)); store.register_early_pass(|| Box::new(unused_unit::UnusedUnit)); store.register_late_pass(|_| Box::new(returns::Return)); @@ -810,10 +830,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: )) }); let enum_variant_name_threshold = conf.enum_variant_name_threshold; + let allow_private_module_inception = conf.allow_private_module_inception; store.register_late_pass(move |_| { Box::new(enum_variants::EnumVariantNames::new( enum_variant_name_threshold, avoid_breaking_exported_api, + allow_private_module_inception, )) }); store.register_early_pass(|| Box::new(tabs_in_doc_comments::TabsInDocComments)); @@ -833,7 +855,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move |_| Box::new(large_stack_arrays::LargeStackArrays::new(array_size_threshold))); store.register_late_pass(move |_| Box::new(large_const_arrays::LargeConstArrays::new(array_size_threshold))); store.register_late_pass(|_| Box::new(floating_point_arithmetic::FloatingPointArithmetic)); - store.register_early_pass(|| Box::new(as_conversions::AsConversions)); + store.register_late_pass(|_| Box::new(as_conversions::AsConversions)); store.register_late_pass(|_| Box::new(let_underscore::LetUnderscore)); store.register_early_pass(|| Box::::default()); let max_fn_params_bools = conf.max_fn_params_bools; @@ -909,7 +931,14 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: enable_raw_pointer_heuristic_for_send, )) }); - store.register_late_pass(move |_| Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks)); + let accept_comment_above_statement = conf.accept_comment_above_statement; + let accept_comment_above_attributes = conf.accept_comment_above_attributes; + store.register_late_pass(move |_| { + Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks::new( + accept_comment_above_statement, + accept_comment_above_attributes, + )) + }); let allow_mixed_uninlined = conf.allow_mixed_uninlined_format_args; store.register_late_pass(move |_| Box::new(format_args::FormatArgs::new(msrv(), allow_mixed_uninlined))); store.register_late_pass(|_| Box::new(trailing_empty_array::TrailingEmptyArray)); @@ -1002,11 +1031,49 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(tests_outside_test_module::TestsOutsideTestModule)); store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation)); store.register_early_pass(|| Box::new(suspicious_doc_comments::SuspiciousDocComments)); + let excessive_nesting_threshold = conf.excessive_nesting_threshold; + store.register_early_pass(move || { + Box::new(excessive_nesting::ExcessiveNesting { + excessive_nesting_threshold, + nodes: rustc_ast::node_id::NodeSet::new(), + }) + }); store.register_late_pass(|_| Box::new(items_after_test_module::ItemsAfterTestModule)); store.register_early_pass(|| Box::new(ref_patterns::RefPatterns)); store.register_late_pass(|_| Box::new(default_constructed_unit_structs::DefaultConstructedUnitStructs)); store.register_early_pass(|| Box::new(needless_else::NeedlessElse)); store.register_late_pass(|_| Box::new(missing_fields_in_debug::MissingFieldsInDebug)); + store.register_late_pass(|_| Box::new(endian_bytes::EndianBytes)); + store.register_late_pass(|_| Box::new(redundant_type_annotations::RedundantTypeAnnotations)); + store.register_late_pass(|_| Box::new(arc_with_non_send_sync::ArcWithNonSendSync)); + store.register_late_pass(|_| Box::new(needless_if::NeedlessIf)); + let allowed_idents_below_min_chars = conf.allowed_idents_below_min_chars.clone(); + let min_ident_chars_threshold = conf.min_ident_chars_threshold; + store.register_late_pass(move |_| { + Box::new(min_ident_chars::MinIdentChars { + allowed_idents_below_min_chars: allowed_idents_below_min_chars.clone(), + min_ident_chars_threshold, + }) + }); + let stack_size_threshold = conf.stack_size_threshold; + store.register_late_pass(move |_| Box::new(large_stack_frames::LargeStackFrames::new(stack_size_threshold))); + store.register_late_pass(|_| Box::new(single_range_in_vec_init::SingleRangeInVecInit)); + store.register_late_pass(|_| Box::new(incorrect_impls::IncorrectImpls)); + store.register_late_pass(move |_| { + Box::new(single_call_fn::SingleCallFn { + avoid_breaking_exported_api, + def_id_to_usage: rustc_data_structures::fx::FxHashMap::default(), + }) + }); + let needless_raw_string_hashes_allow_one = conf.allow_one_hash_in_raw_strings; + store.register_early_pass(move || { + Box::new(raw_strings::RawStrings { + needless_raw_string_hashes_allow_one, + }) + }); + store.register_late_pass(|_| Box::new(manual_range_patterns::ManualRangePatterns)); + store.register_early_pass(|| Box::new(visibility::Visibility)); + store.register_late_pass(move |_| Box::new(tuple_array_conversions::TupleArrayConversions { msrv: msrv() })); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 986ffcad883d..852f6736585b 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::trait_ref_of_method; +use itertools::Itertools; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; use rustc_hir::intravisit::nested_filter::{self as hir_nested_filter, NestedFilter}; @@ -201,7 +202,19 @@ fn check_fn_inner<'tcx>( span_lint_and_then( cx, NEEDLESS_LIFETIMES, - span.with_hi(sig.decl.output.span().hi()), + elidable_lts + .iter() + .map(|<| cx.tcx.def_span(lt)) + .chain(usages.iter().filter_map(|usage| { + if let LifetimeName::Param(def_id) = usage.res + && elidable_lts.contains(&def_id) + { + return Some(usage.ident.span); + } + + None + })) + .collect_vec(), &format!("the following explicit lifetimes could be elided: {lts}"), |diag| { if sig.header.is_async() { @@ -562,7 +575,7 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_ // if the bounds define new lifetimes, they are fine to occur let allowed_lts = allowed_lts_from(pred.bound_generic_params); // now walk the bounds - for bound in pred.bounds.iter() { + for bound in pred.bounds { walk_param_bound(&mut visitor, bound); } // and check that all lifetimes are allowed diff --git a/clippy_lints/src/loops/explicit_into_iter_loop.rs b/clippy_lints/src/loops/explicit_into_iter_loop.rs index 175e2b382e3f..93d6b8086469 100644 --- a/clippy_lints/src/loops/explicit_into_iter_loop.rs +++ b/clippy_lints/src/loops/explicit_into_iter_loop.rs @@ -5,15 +5,76 @@ use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; +use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; use rustc_span::symbol::sym; +#[derive(Clone, Copy)] +enum AdjustKind { + None, + Borrow, + BorrowMut, + Reborrow, + ReborrowMut, +} +impl AdjustKind { + fn borrow(mutbl: AutoBorrowMutability) -> Self { + match mutbl { + AutoBorrowMutability::Not => Self::Borrow, + AutoBorrowMutability::Mut { .. } => Self::BorrowMut, + } + } + + fn reborrow(mutbl: AutoBorrowMutability) -> Self { + match mutbl { + AutoBorrowMutability::Not => Self::Reborrow, + AutoBorrowMutability::Mut { .. } => Self::ReborrowMut, + } + } + + fn display(self) -> &'static str { + match self { + Self::None => "", + Self::Borrow => "&", + Self::BorrowMut => "&mut ", + Self::Reborrow => "&*", + Self::ReborrowMut => "&mut *", + } + } +} + pub(super) fn check(cx: &LateContext<'_>, self_arg: &Expr<'_>, call_expr: &Expr<'_>) { - let self_ty = cx.typeck_results().expr_ty(self_arg); - let self_ty_adjusted = cx.typeck_results().expr_ty_adjusted(self_arg); - if !(self_ty == self_ty_adjusted && is_trait_method(cx, call_expr, sym::IntoIterator)) { + if !is_trait_method(cx, call_expr, sym::IntoIterator) { return; } + let typeck = cx.typeck_results(); + let self_ty = typeck.expr_ty(self_arg); + let adjust = match typeck.expr_adjustments(self_arg) { + [] => AdjustKind::None, + &[ + Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(_, mutbl)), + .. + }, + ] => AdjustKind::borrow(mutbl), + &[ + Adjustment { + kind: Adjust::Deref(_), .. + }, + Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(_, mutbl)), + target, + }, + ] => { + if self_ty == target && matches!(mutbl, AutoBorrowMutability::Not) { + AdjustKind::None + } else { + AdjustKind::reborrow(mutbl) + } + }, + _ => return, + }; + let mut applicability = Applicability::MachineApplicable; let object = snippet_with_applicability(cx, self_arg.span, "_", &mut applicability); span_lint_and_sugg( @@ -23,7 +84,7 @@ pub(super) fn check(cx: &LateContext<'_>, self_arg: &Expr<'_>, call_expr: &Expr< "it is more concise to loop over containers instead of using explicit \ iteration methods", "to write this more concisely, try", - object.to_string(), + format!("{}{object}", adjust.display()), applicability, ); } diff --git a/clippy_lints/src/loops/explicit_iter_loop.rs b/clippy_lints/src/loops/explicit_iter_loop.rs index 151c7f1d5d25..f3347e33077b 100644 --- a/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/clippy_lints/src/loops/explicit_iter_loop.rs @@ -1,75 +1,235 @@ use super::EXPLICIT_ITER_LOOP; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_trait_method; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::ty::{ + implements_trait, implements_trait_with_env, is_copy, make_normalized_projection, + make_normalized_projection_with_regions, normalize_with_regions, +}; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability}; use rustc_lint::LateContext; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; +use rustc_middle::ty::{self, EarlyBinder, Ty, TypeAndMut}; use rustc_span::sym; -pub(super) fn check(cx: &LateContext<'_>, self_arg: &Expr<'_>, arg: &Expr<'_>, method_name: &str) { - let should_lint = match method_name { - "iter" | "iter_mut" => is_ref_iterable_type(cx, self_arg), - "into_iter" if is_trait_method(cx, arg, sym::IntoIterator) => { - let receiver_ty = cx.typeck_results().expr_ty(self_arg); - let receiver_ty_adjusted = cx.typeck_results().expr_ty_adjusted(self_arg); - let ref_receiver_ty = cx.tcx.mk_ref( - cx.tcx.lifetimes.re_erased, - ty::TypeAndMut { - ty: receiver_ty, - mutbl: Mutability::Not, - }, - ); - receiver_ty_adjusted == ref_receiver_ty - }, - _ => false, - }; - - if !should_lint { +pub(super) fn check(cx: &LateContext<'_>, self_arg: &Expr<'_>, call_expr: &Expr<'_>, msrv: &Msrv) { + let Some((adjust, ty)) = is_ref_iterable(cx, self_arg, call_expr) else { return; + }; + if let ty::Array(_, count) = *ty.peel_refs().kind() { + if !ty.is_ref() { + if !msrv.meets(msrvs::ARRAY_INTO_ITERATOR) { + return; + } + } else if count + .try_eval_target_usize(cx.tcx, cx.param_env) + .map_or(true, |x| x > 32) + && !msrv.meets(msrvs::ARRAY_IMPL_ANY_LEN) + { + return; + } } let mut applicability = Applicability::MachineApplicable; let object = snippet_with_applicability(cx, self_arg.span, "_", &mut applicability); - let muta = if method_name == "iter_mut" { "mut " } else { "" }; span_lint_and_sugg( cx, EXPLICIT_ITER_LOOP, - arg.span, + call_expr.span, "it is more concise to loop over references to containers instead of using explicit \ iteration methods", "to write this more concisely, try", - format!("&{muta}{object}"), + format!("{}{object}", adjust.display()), applicability, ); } -/// Returns `true` if the type of expr is one that provides `IntoIterator` impls -/// for `&T` and `&mut T`, such as `Vec`. -#[rustfmt::skip] -fn is_ref_iterable_type(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { - // no walk_ptrs_ty: calling iter() on a reference can make sense because it - // will allow further borrows afterwards - let ty = cx.typeck_results().expr_ty(e); - is_iterable_array(ty, cx) || - is_type_diagnostic_item(cx, ty, sym::Vec) || - is_type_diagnostic_item(cx, ty, sym::LinkedList) || - is_type_diagnostic_item(cx, ty, sym::HashMap) || - is_type_diagnostic_item(cx, ty, sym::HashSet) || - is_type_diagnostic_item(cx, ty, sym::VecDeque) || - is_type_diagnostic_item(cx, ty, sym::BinaryHeap) || - is_type_diagnostic_item(cx, ty, sym::BTreeMap) || - is_type_diagnostic_item(cx, ty, sym::BTreeSet) +#[derive(Clone, Copy)] +enum AdjustKind { + None, + Borrow, + BorrowMut, + Deref, + Reborrow, + ReborrowMut, } +impl AdjustKind { + fn borrow(mutbl: Mutability) -> Self { + match mutbl { + Mutability::Not => Self::Borrow, + Mutability::Mut => Self::BorrowMut, + } + } -fn is_iterable_array<'tcx>(ty: Ty<'tcx>, cx: &LateContext<'tcx>) -> bool { - // IntoIterator is currently only implemented for array sizes <= 32 in rustc - match ty.kind() { - ty::Array(_, n) => n - .try_eval_target_usize(cx.tcx, cx.param_env) - .map_or(false, |val| (0..=32).contains(&val)), - _ => false, + fn auto_borrow(mutbl: AutoBorrowMutability) -> Self { + match mutbl { + AutoBorrowMutability::Not => Self::Borrow, + AutoBorrowMutability::Mut { .. } => Self::BorrowMut, + } + } + + fn reborrow(mutbl: Mutability) -> Self { + match mutbl { + Mutability::Not => Self::Reborrow, + Mutability::Mut => Self::ReborrowMut, + } + } + + fn auto_reborrow(mutbl: AutoBorrowMutability) -> Self { + match mutbl { + AutoBorrowMutability::Not => Self::Reborrow, + AutoBorrowMutability::Mut { .. } => Self::ReborrowMut, + } + } + + fn display(self) -> &'static str { + match self { + Self::None => "", + Self::Borrow => "&", + Self::BorrowMut => "&mut ", + Self::Deref => "*", + Self::Reborrow => "&*", + Self::ReborrowMut => "&mut *", + } + } +} + +/// Checks if an `iter` or `iter_mut` call returns `IntoIterator::IntoIter`. Returns how the +/// argument needs to be adjusted. +#[expect(clippy::too_many_lines)] +fn is_ref_iterable<'tcx>( + cx: &LateContext<'tcx>, + self_arg: &Expr<'_>, + call_expr: &Expr<'_>, +) -> Option<(AdjustKind, Ty<'tcx>)> { + let typeck = cx.typeck_results(); + if let Some(trait_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator) + && let Some(fn_id) = typeck.type_dependent_def_id(call_expr.hir_id) + && let sig = cx.tcx.liberate_late_bound_regions(fn_id, cx.tcx.fn_sig(fn_id).skip_binder()) + && let &[req_self_ty, req_res_ty] = &**sig.inputs_and_output + && let param_env = cx.tcx.param_env(fn_id) + && implements_trait_with_env(cx.tcx, param_env, req_self_ty, trait_id, []) + && let Some(into_iter_ty) = + make_normalized_projection_with_regions(cx.tcx, param_env, trait_id, sym!(IntoIter), [req_self_ty]) + && let req_res_ty = normalize_with_regions(cx.tcx, param_env, req_res_ty) + && into_iter_ty == req_res_ty + { + let adjustments = typeck.expr_adjustments(self_arg); + let self_ty = typeck.expr_ty(self_arg); + let self_is_copy = is_copy(cx, self_ty); + + if adjustments.is_empty() && self_is_copy { + // Exact type match, already checked earlier + return Some((AdjustKind::None, self_ty)); + } + + let res_ty = cx.tcx.erase_regions(EarlyBinder::bind(req_res_ty) + .subst(cx.tcx, typeck.node_substs(call_expr.hir_id))); + let mutbl = if let ty::Ref(_, _, mutbl) = *req_self_ty.kind() { + Some(mutbl) + } else { + None + }; + + if !adjustments.is_empty() { + if self_is_copy { + // Using by value won't consume anything + if implements_trait(cx, self_ty, trait_id, &[]) + && let Some(ty) = + make_normalized_projection(cx.tcx, cx.param_env, trait_id, sym!(IntoIter), [self_ty]) + && ty == res_ty + { + return Some((AdjustKind::None, self_ty)); + } + } else if let ty::Ref(region, ty, Mutability::Mut) = *self_ty.kind() + && let Some(mutbl) = mutbl + { + // Attempt to reborrow the mutable reference + let self_ty = if mutbl.is_mut() { + self_ty + } else { + cx.tcx.mk_ref(region, TypeAndMut { ty, mutbl }) + }; + if implements_trait(cx, self_ty, trait_id, &[]) + && let Some(ty) = + make_normalized_projection(cx.tcx, cx.param_env, trait_id, sym!(IntoIter), [self_ty]) + && ty == res_ty + { + return Some((AdjustKind::reborrow(mutbl), self_ty)); + } + } + } + if let Some(mutbl) = mutbl + && !self_ty.is_ref() + { + // Attempt to borrow + let self_ty = cx.tcx.mk_ref(cx.tcx.lifetimes.re_erased, TypeAndMut { + ty: self_ty, + mutbl, + }); + if implements_trait(cx, self_ty, trait_id, &[]) + && let Some(ty) = make_normalized_projection(cx.tcx, cx.param_env, trait_id, sym!(IntoIter), [self_ty]) + && ty == res_ty + { + return Some((AdjustKind::borrow(mutbl), self_ty)); + } + } + + match adjustments { + [] => Some((AdjustKind::None, self_ty)), + &[ + Adjustment { kind: Adjust::Deref(_), ..}, + Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(_, mutbl)), + target, + }, + .. + ] => { + if target != self_ty + && implements_trait(cx, target, trait_id, &[]) + && let Some(ty) = + make_normalized_projection(cx.tcx, cx.param_env, trait_id, sym!(IntoIter), [target]) + && ty == res_ty + { + Some((AdjustKind::auto_reborrow(mutbl), target)) + } else { + None + } + } + &[Adjustment { kind: Adjust::Deref(_), target }, ..] => { + if is_copy(cx, target) + && implements_trait(cx, target, trait_id, &[]) + && let Some(ty) = + make_normalized_projection(cx.tcx, cx.param_env, trait_id, sym!(IntoIter), [target]) + && ty == res_ty + { + Some((AdjustKind::Deref, target)) + } else { + None + } + } + &[ + Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(_, mutbl)), + target, + }, + .. + ] => { + if self_ty.is_ref() + && implements_trait(cx, target, trait_id, &[]) + && let Some(ty) = + make_normalized_projection(cx.tcx, cx.param_env, trait_id, sym!(IntoIter), [target]) + && ty == res_ty + { + Some((AdjustKind::auto_borrow(mutbl), target)) + } else { + None + } + } + _ => None, + } + } else { + None } } diff --git a/clippy_lints/src/loops/manual_memcpy.rs b/clippy_lints/src/loops/manual_memcpy.rs index d4c3f76b8641..7d1f8ef29c81 100644 --- a/clippy_lints/src/loops/manual_memcpy.rs +++ b/clippy_lints/src/loops/manual_memcpy.rs @@ -51,7 +51,7 @@ pub(super) fn check<'tcx>( iter_b = Some(get_assignment(body)); } - let assignments = iter_a.into_iter().flatten().chain(iter_b.into_iter()); + let assignments = iter_a.into_iter().flatten().chain(iter_b); let big_sugg = assignments // The only statements in the for loops can be indexed assignments from @@ -402,7 +402,7 @@ fn get_assignments<'a, 'tcx>( StmtKind::Local(..) | StmtKind::Item(..) => None, StmtKind::Expr(e) | StmtKind::Semi(e) => Some(e), }) - .chain((*expr).into_iter()) + .chain(*expr) .filter(move |e| { if let ExprKind::AssignOp(_, place, _) = e.kind { path_to_local(place).map_or(false, |id| { diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index f83ad388a742..529189b52acd 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -20,9 +20,10 @@ mod while_let_loop; mod while_let_on_iterator; use clippy_utils::higher; +use clippy_utils::msrvs::Msrv; use rustc_hir::{Expr, ExprKind, LoopSource, Pat}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; use utils::{make_iterator_snippet, IncrementVisitor, InitializeVisitor}; @@ -479,7 +480,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Check for unnecessary `if let` usage in a for loop + /// Checks for unnecessary `if let` usage in a for loop /// where only the `Some` or `Ok` variant of the iterator element is used. /// /// ### Why is this bad? @@ -511,7 +512,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Check for empty spin loops + /// Checks for empty spin loops /// /// ### Why is this bad? /// The loop body should have something like `thread::park()` or at least @@ -547,7 +548,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Check for manual implementations of Iterator::find + /// Checks for manual implementations of Iterator::find /// /// ### Why is this bad? /// It doesn't affect performance, but using `find` is shorter and easier to read. @@ -606,7 +607,15 @@ declare_clippy_lint! { "checking for emptiness of a `Vec` in the loop condition and popping an element in the body" } -declare_lint_pass!(Loops => [ +pub struct Loops { + msrv: Msrv, +} +impl Loops { + pub fn new(msrv: Msrv) -> Self { + Self { msrv } + } +} +impl_lint_pass!(Loops => [ MANUAL_MEMCPY, MANUAL_FLATTEN, NEEDLESS_RANGE_LOOP, @@ -645,7 +654,7 @@ impl<'tcx> LateLintPass<'tcx> for Loops { if body.span.from_expansion() { return; } - check_for_loop(cx, pat, arg, body, expr, span); + self.check_for_loop(cx, pat, arg, body, expr, span); if let ExprKind::Block(block, _) = body.kind { never_loop::check(cx, block, loop_id, span, for_loop.as_ref()); } @@ -678,46 +687,48 @@ impl<'tcx> LateLintPass<'tcx> for Loops { manual_while_let_some::check(cx, condition, body, span); } } + + extract_msrv_attr!(LateContext); } -fn check_for_loop<'tcx>( - cx: &LateContext<'tcx>, - pat: &'tcx Pat<'_>, - arg: &'tcx Expr<'_>, - body: &'tcx Expr<'_>, - expr: &'tcx Expr<'_>, - span: Span, -) { - let is_manual_memcpy_triggered = manual_memcpy::check(cx, pat, arg, body, expr); - if !is_manual_memcpy_triggered { - needless_range_loop::check(cx, pat, arg, body, expr); - explicit_counter_loop::check(cx, pat, arg, body, expr); +impl Loops { + fn check_for_loop<'tcx>( + &self, + cx: &LateContext<'tcx>, + pat: &'tcx Pat<'_>, + arg: &'tcx Expr<'_>, + body: &'tcx Expr<'_>, + expr: &'tcx Expr<'_>, + span: Span, + ) { + let is_manual_memcpy_triggered = manual_memcpy::check(cx, pat, arg, body, expr); + if !is_manual_memcpy_triggered { + needless_range_loop::check(cx, pat, arg, body, expr); + explicit_counter_loop::check(cx, pat, arg, body, expr); + } + self.check_for_loop_arg(cx, pat, arg); + for_kv_map::check(cx, pat, arg, body); + mut_range_bound::check(cx, arg, body); + single_element_loop::check(cx, pat, arg, body, expr); + same_item_push::check(cx, pat, arg, body, expr); + manual_flatten::check(cx, pat, arg, body, span); + manual_find::check(cx, pat, arg, body, span, expr); } - check_for_loop_arg(cx, pat, arg); - for_kv_map::check(cx, pat, arg, body); - mut_range_bound::check(cx, arg, body); - single_element_loop::check(cx, pat, arg, body, expr); - same_item_push::check(cx, pat, arg, body, expr); - manual_flatten::check(cx, pat, arg, body, span); - manual_find::check(cx, pat, arg, body, span, expr); -} -fn check_for_loop_arg(cx: &LateContext<'_>, _: &Pat<'_>, arg: &Expr<'_>) { - if let ExprKind::MethodCall(method, self_arg, [], _) = arg.kind { - let method_name = method.ident.as_str(); - // check for looping over x.iter() or x.iter_mut(), could use &x or &mut x - match method_name { - "iter" | "iter_mut" => { - explicit_iter_loop::check(cx, self_arg, arg, method_name); - }, - "into_iter" => { - explicit_iter_loop::check(cx, self_arg, arg, method_name); - explicit_into_iter_loop::check(cx, self_arg, arg); - }, - "next" => { - iter_next_loop::check(cx, arg); - }, - _ => {}, + fn check_for_loop_arg(&self, cx: &LateContext<'_>, _: &Pat<'_>, arg: &Expr<'_>) { + if let ExprKind::MethodCall(method, self_arg, [], _) = arg.kind { + match method.ident.as_str() { + "iter" | "iter_mut" => { + explicit_iter_loop::check(cx, self_arg, arg, &self.msrv); + }, + "into_iter" => { + explicit_into_iter_loop::check(cx, self_arg, arg); + }, + "next" => { + iter_next_loop::check(cx, arg); + }, + _ => {}, + } } } } diff --git a/clippy_lints/src/loops/never_loop.rs b/clippy_lints/src/loops/never_loop.rs index 10b5e1edf925..ee338c6beb06 100644 --- a/clippy_lints/src/loops/never_loop.rs +++ b/clippy_lints/src/loops/never_loop.rs @@ -1,22 +1,23 @@ use super::utils::make_iterator_snippet; use super::NEVER_LOOP; -use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::consts::constant; use clippy_utils::higher::ForLoop; use clippy_utils::source::snippet; +use clippy_utils::{consts::Constant, diagnostics::span_lint_and_then}; use rustc_errors::Applicability; use rustc_hir::{Block, Destination, Expr, ExprKind, HirId, InlineAsmOperand, Pat, Stmt, StmtKind}; use rustc_lint::LateContext; use rustc_span::Span; use std::iter::{once, Iterator}; -pub(super) fn check( - cx: &LateContext<'_>, - block: &Block<'_>, +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + block: &Block<'tcx>, loop_id: HirId, span: Span, for_loop: Option<&ForLoop<'_>>, ) { - match never_loop_block(block, &mut Vec::new(), loop_id) { + match never_loop_block(cx, block, &mut Vec::new(), loop_id) { NeverLoopResult::AlwaysBreak => { span_lint_and_then(cx, NEVER_LOOP, span, "this loop never actually loops", |diag| { if let Some(ForLoop { @@ -95,7 +96,12 @@ fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult, ignore_ids: &[HirI } } -fn never_loop_block(block: &Block<'_>, ignore_ids: &mut Vec, main_loop_id: HirId) -> NeverLoopResult { +fn never_loop_block<'tcx>( + cx: &LateContext<'tcx>, + block: &Block<'tcx>, + ignore_ids: &mut Vec, + main_loop_id: HirId, +) -> NeverLoopResult { let iter = block .stmts .iter() @@ -103,10 +109,10 @@ fn never_loop_block(block: &Block<'_>, ignore_ids: &mut Vec, main_loop_id .chain(block.expr.map(|expr| (expr, None))); iter.map(|(e, els)| { - let e = never_loop_expr(e, ignore_ids, main_loop_id); + let e = never_loop_expr(cx, e, ignore_ids, main_loop_id); // els is an else block in a let...else binding els.map_or(e, |els| { - combine_branches(e, never_loop_block(els, ignore_ids, main_loop_id), ignore_ids) + combine_branches(e, never_loop_block(cx, els, ignore_ids, main_loop_id), ignore_ids) }) }) .fold(NeverLoopResult::Otherwise, combine_seq) @@ -122,7 +128,12 @@ fn stmt_to_expr<'tcx>(stmt: &Stmt<'tcx>) -> Option<(&'tcx Expr<'tcx>, Option<&'t } #[allow(clippy::too_many_lines)] -fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec, main_loop_id: HirId) -> NeverLoopResult { +fn never_loop_expr<'tcx>( + cx: &LateContext<'tcx>, + expr: &Expr<'tcx>, + ignore_ids: &mut Vec, + main_loop_id: HirId, +) -> NeverLoopResult { match expr.kind { ExprKind::Unary(_, e) | ExprKind::Cast(e, _) @@ -130,45 +141,51 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec, main_loop_id: H | ExprKind::Field(e, _) | ExprKind::AddrOf(_, _, e) | ExprKind::Repeat(e, _) - | ExprKind::DropTemps(e) => never_loop_expr(e, ignore_ids, main_loop_id), - ExprKind::Let(let_expr) => never_loop_expr(let_expr.init, ignore_ids, main_loop_id), - ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(&mut es.iter(), ignore_ids, main_loop_id), + | ExprKind::DropTemps(e) => never_loop_expr(cx, e, ignore_ids, main_loop_id), + ExprKind::Let(let_expr) => never_loop_expr(cx, let_expr.init, ignore_ids, main_loop_id), + ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(cx, &mut es.iter(), ignore_ids, main_loop_id), ExprKind::MethodCall(_, receiver, es, _) => never_loop_expr_all( + cx, &mut std::iter::once(receiver).chain(es.iter()), ignore_ids, main_loop_id, ), ExprKind::Struct(_, fields, base) => { - let fields = never_loop_expr_all(&mut fields.iter().map(|f| f.expr), ignore_ids, main_loop_id); + let fields = never_loop_expr_all(cx, &mut fields.iter().map(|f| f.expr), ignore_ids, main_loop_id); if let Some(base) = base { - combine_seq(fields, never_loop_expr(base, ignore_ids, main_loop_id)) + combine_seq(fields, never_loop_expr(cx, base, ignore_ids, main_loop_id)) } else { fields } }, - ExprKind::Call(e, es) => never_loop_expr_all(&mut once(e).chain(es.iter()), ignore_ids, main_loop_id), + ExprKind::Call(e, es) => never_loop_expr_all(cx, &mut once(e).chain(es.iter()), ignore_ids, main_loop_id), ExprKind::Binary(_, e1, e2) | ExprKind::Assign(e1, e2, _) | ExprKind::AssignOp(_, e1, e2) - | ExprKind::Index(e1, e2) => never_loop_expr_all(&mut [e1, e2].iter().copied(), ignore_ids, main_loop_id), + | ExprKind::Index(e1, e2) => never_loop_expr_all(cx, &mut [e1, e2].iter().copied(), ignore_ids, main_loop_id), ExprKind::Loop(b, _, _, _) => { // Break can come from the inner loop so remove them. - absorb_break(never_loop_block(b, ignore_ids, main_loop_id)) + absorb_break(never_loop_block(cx, b, ignore_ids, main_loop_id)) }, ExprKind::If(e, e2, e3) => { - let e1 = never_loop_expr(e, ignore_ids, main_loop_id); - let e2 = never_loop_expr(e2, ignore_ids, main_loop_id); + let e1 = never_loop_expr(cx, e, ignore_ids, main_loop_id); + let e2 = never_loop_expr(cx, e2, ignore_ids, main_loop_id); + // If we know the `if` condition evaluates to `true`, don't check everything past it; it + // should just return whatever's evaluated for `e1` and `e2` since `e3` is unreachable + if let Some(Constant::Bool(true)) = constant(cx, cx.typeck_results(), e) { + return combine_seq(e1, e2); + } let e3 = e3.as_ref().map_or(NeverLoopResult::Otherwise, |e| { - never_loop_expr(e, ignore_ids, main_loop_id) + never_loop_expr(cx, e, ignore_ids, main_loop_id) }); combine_seq(e1, combine_branches(e2, e3, ignore_ids)) }, ExprKind::Match(e, arms, _) => { - let e = never_loop_expr(e, ignore_ids, main_loop_id); + let e = never_loop_expr(cx, e, ignore_ids, main_loop_id); if arms.is_empty() { e } else { - let arms = never_loop_expr_branch(&mut arms.iter().map(|a| a.body), ignore_ids, main_loop_id); + let arms = never_loop_expr_branch(cx, &mut arms.iter().map(|a| a.body), ignore_ids, main_loop_id); combine_seq(e, arms) } }, @@ -176,7 +193,7 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec, main_loop_id: H if l.is_some() { ignore_ids.push(b.hir_id); } - let ret = never_loop_block(b, ignore_ids, main_loop_id); + let ret = never_loop_block(cx, b, ignore_ids, main_loop_id); if l.is_some() { ignore_ids.pop(); } @@ -198,31 +215,30 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec, main_loop_id: H // checks if break targets a block instead of a loop ExprKind::Break(Destination { target_id: Ok(t), .. }, e) if ignore_ids.contains(&t) => e .map_or(NeverLoopResult::IgnoreUntilEnd(t), |e| { - never_loop_expr(e, ignore_ids, main_loop_id) + never_loop_expr(cx, e, ignore_ids, main_loop_id) }), ExprKind::Break(_, e) | ExprKind::Ret(e) => e.as_ref().map_or(NeverLoopResult::AlwaysBreak, |e| { combine_seq( - never_loop_expr(e, ignore_ids, main_loop_id), + never_loop_expr(cx, e, ignore_ids, main_loop_id), NeverLoopResult::AlwaysBreak, ) }), - ExprKind::Become(e) => { - combine_seq( - never_loop_expr(e, ignore_ids, main_loop_id), - NeverLoopResult::AlwaysBreak, - ) - } + ExprKind::Become(e) => combine_seq( + never_loop_expr(cx, e, ignore_ids, main_loop_id), + NeverLoopResult::AlwaysBreak, + ), ExprKind::InlineAsm(asm) => asm .operands .iter() .map(|(o, _)| match o { InlineAsmOperand::In { expr, .. } | InlineAsmOperand::InOut { expr, .. } => { - never_loop_expr(expr, ignore_ids, main_loop_id) + never_loop_expr(cx, expr, ignore_ids, main_loop_id) }, InlineAsmOperand::Out { expr, .. } => { - never_loop_expr_all(&mut expr.iter().copied(), ignore_ids, main_loop_id) + never_loop_expr_all(cx, &mut expr.iter().copied(), ignore_ids, main_loop_id) }, InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => never_loop_expr_all( + cx, &mut once(*in_expr).chain(out_expr.iter().copied()), ignore_ids, main_loop_id, @@ -242,22 +258,24 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec, main_loop_id: H } } -fn never_loop_expr_all<'a, T: Iterator>>( +fn never_loop_expr_all<'tcx, T: Iterator>>( + cx: &LateContext<'tcx>, es: &mut T, ignore_ids: &mut Vec, main_loop_id: HirId, ) -> NeverLoopResult { - es.map(|e| never_loop_expr(e, ignore_ids, main_loop_id)) + es.map(|e| never_loop_expr(cx, e, ignore_ids, main_loop_id)) .fold(NeverLoopResult::Otherwise, combine_seq) } -fn never_loop_expr_branch<'a, T: Iterator>>( +fn never_loop_expr_branch<'tcx, T: Iterator>>( + cx: &LateContext<'tcx>, e: &mut T, ignore_ids: &mut Vec, main_loop_id: HirId, ) -> NeverLoopResult { e.fold(NeverLoopResult::AlwaysBreak, |a, b| { - combine_branches(a, never_loop_expr(b, ignore_ids, main_loop_id), ignore_ids) + combine_branches(a, never_loop_expr(cx, b, ignore_ids, main_loop_id), ignore_ids) }) } diff --git a/clippy_lints/src/loops/same_item_push.rs b/clippy_lints/src/loops/same_item_push.rs index 9d9341559ac7..f7b3b2358a0b 100644 --- a/clippy_lints/src/loops/same_item_push.rs +++ b/clippy_lints/src/loops/same_item_push.rs @@ -148,7 +148,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SameItemPushVisitor<'a, 'tcx> { } fn visit_block(&mut self, b: &'tcx Block<'_>) { - for stmt in b.stmts.iter() { + for stmt in b.stmts { self.visit_stmt(stmt); } } diff --git a/clippy_lints/src/macro_use.rs b/clippy_lints/src/macro_use.rs index e2e6a87a3015..8e322a979072 100644 --- a/clippy_lints/src/macro_use.rs +++ b/clippy_lints/src/macro_use.rs @@ -100,7 +100,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { }); if !id.is_local(); then { - for kid in cx.tcx.module_children(id).iter() { + for kid in cx.tcx.module_children(id) { if let Res::Def(DefKind::Macro(_mac_type), mac_id) = kid.res { let span = mac_attr.span; let def_path = cx.tcx.def_path_str(mac_id); diff --git a/clippy_lints/src/manual_let_else.rs b/clippy_lints/src/manual_let_else.rs index 389b0a4a62dc..59e421c16220 100644 --- a/clippy_lints/src/manual_let_else.rs +++ b/clippy_lints/src/manual_let_else.rs @@ -6,17 +6,18 @@ use clippy_utils::source::snippet_with_context; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::{Descend, Visitable}; use if_chain::if_chain; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{Expr, ExprKind, HirId, ItemId, Local, MatchSource, Pat, PatKind, QPath, Stmt, StmtKind, Ty}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::symbol::sym; +use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; use serde::Deserialize; use std::ops::ControlFlow; +use std::slice; declare_clippy_lint! { /// ### What it does @@ -81,11 +82,11 @@ impl<'tcx> LateLintPass<'tcx> for ManualLetElse { { match if_let_or_match { IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else) => if_chain! { - if expr_is_simple_identity(let_pat, if_then); + if let Some(ident_map) = expr_simple_identity_map(local.pat, let_pat, if_then); if let Some(if_else) = if_else; if expr_diverges(cx, if_else); then { - emit_manual_let_else(cx, stmt.span, if_let_expr, local.pat, let_pat, if_else); + emit_manual_let_else(cx, stmt.span, if_let_expr, &ident_map, let_pat, if_else); } }, IfLetOrMatch::Match(match_expr, arms, source) => { @@ -118,11 +119,11 @@ impl<'tcx> LateLintPass<'tcx> for ManualLetElse { return; } let pat_arm = &arms[1 - idx]; - if !expr_is_simple_identity(pat_arm.pat, pat_arm.body) { - return; - } + let Some(ident_map) = expr_simple_identity_map(local.pat, pat_arm.pat, pat_arm.body) else { + return + }; - emit_manual_let_else(cx, stmt.span, match_expr, local.pat, pat_arm.pat, diverging_arm.body); + emit_manual_let_else(cx, stmt.span, match_expr, &ident_map, pat_arm.pat, diverging_arm.body); }, } }; @@ -135,7 +136,7 @@ fn emit_manual_let_else( cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, - local: &Pat<'_>, + ident_map: &FxHashMap>, pat: &Pat<'_>, else_body: &Expr<'_>, ) { @@ -146,8 +147,8 @@ fn emit_manual_let_else( "this could be rewritten as `let...else`", |diag| { // This is far from perfect, for example there needs to be: - // * tracking for multi-binding cases: let (foo, bar) = if let (Some(foo), Ok(bar)) = ... - // * renamings of the bindings for many `PatKind`s like structs, slices, etc. + // * renamings of the bindings for many `PatKind`s like slices, etc. + // * limitations in the existing replacement algorithms // * unused binding collision detection with existing ones // for this to be machine applicable. let mut app = Applicability::HasPlaceholders; @@ -159,57 +160,126 @@ fn emit_manual_let_else( } else { format!("{{ {sn_else} }}") }; - let sn_bl = replace_in_pattern(cx, span, local, pat, &mut app); + let sn_bl = replace_in_pattern(cx, span, ident_map, pat, &mut app, true); let sugg = format!("let {sn_bl} = {sn_expr} else {else_bl};"); diag.span_suggestion(span, "consider writing", sugg, app); }, ); } -// replaces the locals in the pattern +/// Replaces the locals in the pattern +/// +/// For this example: +/// +/// ```ignore +/// let (a, FooBar { b, c }) = if let Bar { Some(a_i), b_i } = ex { (a_i, b_i) } else { return }; +/// ``` +/// +/// We have: +/// +/// ```ignore +/// pat: Bar { Some(a_i), b_i } +/// ident_map: (a_i) -> (a), (b_i) -> (FooBar { b, c }) +/// ``` +/// +/// We return: +/// +/// ```ignore +/// Bar { Some(a), b_i: FooBar { b, c } } +/// ``` fn replace_in_pattern( cx: &LateContext<'_>, span: Span, - local: &Pat<'_>, + ident_map: &FxHashMap>, pat: &Pat<'_>, app: &mut Applicability, + top_level: bool, ) -> String { - let mut bindings_count = 0; - pat.each_binding_or_first(&mut |_, _, _, _| bindings_count += 1); - // If the pattern creates multiple bindings, exit early, - // as otherwise we might paste the pattern to the positions of multiple bindings. - if bindings_count > 1 { - let (sn_pat, _) = snippet_with_context(cx, pat.span, span.ctxt(), "", app); - return sn_pat.into_owned(); - } + // We put a labeled block here so that we can implement the fallback in this function. + // As the function has multiple call sites, implementing the fallback via an Option + // return type and unwrap_or_else would cause repetition. Similarly, the function also + // invokes the fall back multiple times. + 'a: { + // If the ident map is empty, there is no replacement to do. + // The code following this if assumes a non-empty ident_map. + if ident_map.is_empty() { + break 'a; + } - match pat.kind { - PatKind::Binding(..) => { - let (sn_bdg, _) = snippet_with_context(cx, local.span, span.ctxt(), "", app); - return sn_bdg.to_string(); - }, - PatKind::Or(pats) => { - let patterns = pats - .iter() - .map(|pat| replace_in_pattern(cx, span, local, pat, app)) - .collect::>(); - let or_pat = patterns.join(" | "); - return format!("({or_pat})"); - }, - // Replace the variable name iff `TupleStruct` has one argument like `Variant(v)`. - PatKind::TupleStruct(ref w, args, dot_dot_pos) => { - let mut args = args - .iter() - .map(|pat| replace_in_pattern(cx, span, local, pat, app)) - .collect::>(); - if let Some(pos) = dot_dot_pos.as_opt_usize() { - args.insert(pos, "..".to_owned()); - } - let args = args.join(", "); - let sn_wrapper = cx.sess().source_map().span_to_snippet(w.span()).unwrap_or_default(); - return format!("{sn_wrapper}({args})"); - }, - _ => {}, + match pat.kind { + PatKind::Binding(_ann, _id, binding_name, opt_subpt) => { + let Some(pat_to_put) = ident_map.get(&binding_name.name) else { break 'a }; + let (sn_ptp, _) = snippet_with_context(cx, pat_to_put.span, span.ctxt(), "", app); + if let Some(subpt) = opt_subpt { + let subpt = replace_in_pattern(cx, span, ident_map, subpt, app, false); + return format!("{sn_ptp} @ {subpt}"); + } + return sn_ptp.to_string(); + }, + PatKind::Or(pats) => { + let patterns = pats + .iter() + .map(|pat| replace_in_pattern(cx, span, ident_map, pat, app, false)) + .collect::>(); + let or_pat = patterns.join(" | "); + if top_level { + return format!("({or_pat})"); + } + return or_pat; + }, + PatKind::Struct(path, fields, has_dot_dot) => { + let fields = fields + .iter() + .map(|fld| { + if let PatKind::Binding(_, _, name, None) = fld.pat.kind && + let Some(pat_to_put) = ident_map.get(&name.name) + { + let (sn_fld_name, _) = snippet_with_context(cx, fld.ident.span, span.ctxt(), "", app); + let (sn_ptp, _) = snippet_with_context(cx, pat_to_put.span, span.ctxt(), "", app); + // TODO: this is a bit of a hack, but it does its job. Ideally, we'd check if pat_to_put is + // a PatKind::Binding but that is also hard to get right. + if sn_fld_name == sn_ptp { + // Field init shorthand + return format!("{sn_fld_name}"); + } + return format!("{sn_fld_name}: {sn_ptp}"); + } + let (sn_fld, _) = snippet_with_context(cx, fld.span, span.ctxt(), "", app); + sn_fld.into_owned() + }) + .collect::>(); + let fields_string = fields.join(", "); + + let dot_dot_str = if has_dot_dot { " .." } else { "" }; + let (sn_pth, _) = snippet_with_context(cx, path.span(), span.ctxt(), "", app); + return format!("{sn_pth} {{ {fields_string}{dot_dot_str} }}"); + }, + // Replace the variable name iff `TupleStruct` has one argument like `Variant(v)`. + PatKind::TupleStruct(ref w, args, dot_dot_pos) => { + let mut args = args + .iter() + .map(|pat| replace_in_pattern(cx, span, ident_map, pat, app, false)) + .collect::>(); + if let Some(pos) = dot_dot_pos.as_opt_usize() { + args.insert(pos, "..".to_owned()); + } + let args = args.join(", "); + let sn_wrapper = cx.sess().source_map().span_to_snippet(w.span()).unwrap_or_default(); + return format!("{sn_wrapper}({args})"); + }, + PatKind::Tuple(args, dot_dot_pos) => { + let mut args = args + .iter() + .map(|pat| replace_in_pattern(cx, span, ident_map, pat, app, false)) + .collect::>(); + if let Some(pos) = dot_dot_pos.as_opt_usize() { + args.insert(pos, "..".to_owned()); + } + let args = args.join(", "); + return format!("({args})"); + }, + _ => {}, + } } let (sn_pat, _) = snippet_with_context(cx, pat.span, span.ctxt(), "", app); sn_pat.into_owned() @@ -353,37 +423,74 @@ fn pat_allowed_for_else(cx: &LateContext<'_>, pat: &'_ Pat<'_>, check_types: boo !has_disallowed } -/// Checks if the passed block is a simple identity referring to bindings created by the pattern -fn expr_is_simple_identity(pat: &'_ Pat<'_>, expr: &'_ Expr<'_>) -> bool { - // We support patterns with multiple bindings and tuples, like: - // let ... = if let (Some(foo), bar) = g() { (foo, bar) } else { ... } +/// Checks if the passed block is a simple identity referring to bindings created by the pattern, +/// and if yes, returns a mapping between the relevant sub-pattern and the identifier it corresponds +/// to. +/// +/// We support patterns with multiple bindings and tuples, e.g.: +/// +/// ```ignore +/// let (foo_o, bar_o) = if let (Some(foo), bar) = g() { (foo, bar) } else { ... } +/// ``` +/// +/// The expected params would be: +/// +/// ```ignore +/// local_pat: (foo_o, bar_o) +/// let_pat: (Some(foo), bar) +/// expr: (foo, bar) +/// ``` +/// +/// We build internal `sub_pats` so that it looks like `[foo_o, bar_o]` and `paths` so that it looks +/// like `[foo, bar]`. Then we turn that into `FxHashMap [(foo) -> (foo_o), (bar) -> (bar_o)]` which +/// we return. +fn expr_simple_identity_map<'a, 'hir>( + local_pat: &'a Pat<'hir>, + let_pat: &'_ Pat<'hir>, + expr: &'_ Expr<'hir>, +) -> Option>> { let peeled = peel_blocks(expr); - let paths = match peeled.kind { - ExprKind::Tup(exprs) | ExprKind::Array(exprs) => exprs, - ExprKind::Path(_) => std::slice::from_ref(peeled), - _ => return false, + let (sub_pats, paths) = match (local_pat.kind, peeled.kind) { + (PatKind::Tuple(pats, _), ExprKind::Tup(exprs)) | (PatKind::Slice(pats, ..), ExprKind::Array(exprs)) => { + (pats, exprs) + }, + (_, ExprKind::Path(_)) => (slice::from_ref(local_pat), slice::from_ref(peeled)), + _ => return None, }; + + // There is some length mismatch, which indicates usage of .. in the patterns above e.g.: + // let (a, ..) = if let [a, b, _c] = ex { (a, b) } else { ... }; + // We bail in these cases as they should be rare. + if paths.len() != sub_pats.len() { + return None; + } + let mut pat_bindings = FxHashSet::default(); - pat.each_binding_or_first(&mut |_ann, _hir_id, _sp, ident| { + let_pat.each_binding_or_first(&mut |_ann, _hir_id, _sp, ident| { pat_bindings.insert(ident); }); if pat_bindings.len() < paths.len() { - return false; + // This rebinds some bindings from the outer scope, or it repeats some copy-able bindings multiple + // times. We don't support these cases so we bail here. E.g.: + // let foo = 0; + // let (new_foo, bar, bar_copied) = if let Some(bar) = Some(0) { (foo, bar, bar) } else { .. }; + return None; } - for path in paths { - if_chain! { - if let ExprKind::Path(QPath::Resolved(_ty, path)) = path.kind; - if let [path_seg] = path.segments; - then { - if !pat_bindings.remove(&path_seg.ident) { - return false; - } - } else { - return false; + let mut ident_map = FxHashMap::default(); + for (sub_pat, path) in sub_pats.iter().zip(paths.iter()) { + if let ExprKind::Path(QPath::Resolved(_ty, path)) = path.kind && + let [path_seg] = path.segments + { + let ident = path_seg.ident; + if !pat_bindings.remove(&ident) { + return None; } + ident_map.insert(ident.name, sub_pat); + } else { + return None; } } - true + Some(ident_map) } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize)] diff --git a/clippy_lints/src/manual_range_patterns.rs b/clippy_lints/src/manual_range_patterns.rs new file mode 100644 index 000000000000..65ff555209a6 --- /dev/null +++ b/clippy_lints/src/manual_range_patterns.rs @@ -0,0 +1,123 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use rustc_ast::LitKind; +use rustc_data_structures::fx::FxHashSet; +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_hir::ExprKind; +use rustc_hir::PatKind; +use rustc_hir::RangeEnd; +use rustc_lint::LintContext; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::lint::in_external_macro; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// ### What it does + /// Looks for combined OR patterns that are all contained in a specific range, + /// e.g. `6 | 4 | 5 | 9 | 7 | 8` can be rewritten as `4..=9`. + /// + /// ### Why is this bad? + /// Using an explicit range is more concise and easier to read. + /// + /// ### Example + /// ```rust + /// let x = 6; + /// let foo = matches!(x, 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10); + /// ``` + /// Use instead: + /// ```rust + /// let x = 6; + /// let foo = matches!(x, 1..=10); + /// ``` + #[clippy::version = "1.72.0"] + pub MANUAL_RANGE_PATTERNS, + complexity, + "manually writing range patterns using a combined OR pattern (`|`)" +} +declare_lint_pass!(ManualRangePatterns => [MANUAL_RANGE_PATTERNS]); + +fn expr_as_u128(expr: &Expr<'_>) -> Option { + if let ExprKind::Lit(lit) = expr.kind + && let LitKind::Int(num, _) = lit.node + { + Some(num) + } else { + None + } +} + +impl LateLintPass<'_> for ManualRangePatterns { + fn check_pat(&mut self, cx: &LateContext<'_>, pat: &'_ rustc_hir::Pat<'_>) { + if in_external_macro(cx.sess(), pat.span) { + return; + } + + // a pattern like 1 | 2 seems fine, lint if there are at least 3 alternatives + if let PatKind::Or(pats) = pat.kind + && pats.len() >= 3 + { + let mut min = u128::MAX; + let mut max = 0; + let mut numbers_found = FxHashSet::default(); + let mut ranges_found = Vec::new(); + + for pat in pats { + if let PatKind::Lit(lit) = pat.kind + && let Some(num) = expr_as_u128(lit) + { + numbers_found.insert(num); + + min = min.min(num); + max = max.max(num); + } else if let PatKind::Range(Some(left), Some(right), end) = pat.kind + && let Some(left) = expr_as_u128(left) + && let Some(right) = expr_as_u128(right) + && right >= left + { + min = min.min(left); + max = max.max(right); + ranges_found.push(left..=match end { + RangeEnd::Included => right, + RangeEnd::Excluded => right - 1, + }); + } else { + return; + } + } + + let contains_whole_range = 'contains: { + let mut num = min; + while num <= max { + if numbers_found.contains(&num) { + num += 1; + } + // Given a list of (potentially overlapping) ranges like: + // 1..=5, 3..=7, 6..=10 + // We want to find the range with the highest end that still contains the current number + else if let Some(range) = ranges_found + .iter() + .filter(|range| range.contains(&num)) + .max_by_key(|range| range.end()) + { + num = range.end() + 1; + } else { + break 'contains false; + } + } + break 'contains true; + }; + + if contains_whole_range { + span_lint_and_sugg( + cx, + MANUAL_RANGE_PATTERNS, + pat.span, + "this OR pattern can be rewritten using a range", + "try", + format!("{min}..={max}"), + Applicability::MachineApplicable, + ); + } + } + } +} diff --git a/clippy_lints/src/matches/match_same_arms.rs b/clippy_lints/src/matches/match_same_arms.rs index ae8262ace968..3d2fbea63f5e 100644 --- a/clippy_lints/src/matches/match_same_arms.rs +++ b/clippy_lints/src/matches/match_same_arms.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; -use clippy_utils::{path_to_local, search_same, SpanlessEq, SpanlessHash}; +use clippy_utils::{is_lint_allowed, path_to_local, search_same, SpanlessEq, SpanlessHash}; use core::cmp::Ordering; use core::iter; use core::slice; @@ -9,6 +9,7 @@ use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_hir::{Arm, Expr, ExprKind, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatKind, RangeEnd}; +use rustc_lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; use rustc_lint::LateContext; use rustc_middle::ty; use rustc_span::Symbol; @@ -103,17 +104,21 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) { let indexed_arms: Vec<(usize, &Arm<'_>)> = arms.iter().enumerate().collect(); for (&(i, arm1), &(j, arm2)) in search_same(&indexed_arms, hash, eq) { if matches!(arm2.pat.kind, PatKind::Wild) { - span_lint_and_then( - cx, - MATCH_SAME_ARMS, - arm1.span, - "this match arm has an identical body to the `_` wildcard arm", - |diag| { - diag.span_suggestion(arm1.span, "try removing the arm", "", Applicability::MaybeIncorrect) - .help("or try changing either arm body") - .span_note(arm2.span, "`_` wildcard arm here"); - }, - ); + if !cx.tcx.features().non_exhaustive_omitted_patterns_lint + || is_lint_allowed(cx, NON_EXHAUSTIVE_OMITTED_PATTERNS, arm2.hir_id) + { + span_lint_and_then( + cx, + MATCH_SAME_ARMS, + arm1.span, + "this match arm has an identical body to the `_` wildcard arm", + |diag| { + diag.span_suggestion(arm1.span, "try removing the arm", "", Applicability::MaybeIncorrect) + .help("or try changing either arm body") + .span_note(arm2.span, "`_` wildcard arm here"); + }, + ); + } } else { let back_block = backwards_blocking_idxs[j]; let (keep_arm, move_arm) = if back_block < i || (back_block == 0 && forwards_blocking_idxs[i] <= j) { diff --git a/clippy_lints/src/matches/match_wild_err_arm.rs b/clippy_lints/src/matches/match_wild_err_arm.rs index 6424ac31d9f6..de911f7a0280 100644 --- a/clippy_lints/src/matches/match_wild_err_arm.rs +++ b/clippy_lints/src/matches/match_wild_err_arm.rs @@ -25,7 +25,7 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<' let mut ident_bind_name = kw::Underscore; if !matching_wild { // Looking for unused bindings (i.e.: `_e`) - for pat in inner.iter() { + for pat in inner { if let PatKind::Binding(_, id, ident, None) = pat.kind { if ident.as_str().starts_with('_') && !is_local_used(cx, arm.body, id) { ident_bind_name = ident.name; diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs index 0d91051632a1..00fa3eb9bfe5 100644 --- a/clippy_lints/src/matches/mod.rs +++ b/clippy_lints/src/matches/mod.rs @@ -38,6 +38,11 @@ declare_clippy_lint! { /// Checks for matches with a single arm where an `if let` /// will usually suffice. /// + /// This intentionally does not lint if there are comments + /// inside of the other arm, so as to allow the user to document + /// why having another explicit pattern with an empty body is necessary, + /// or because the comments need to be preserved for other reasons. + /// /// ### Why is this bad? /// Just readability – `if let` nests less than a `match`. /// @@ -559,6 +564,9 @@ declare_clippy_lint! { /// ### What it does /// Checks for `match` with identical arm bodies. /// + /// Note: Does not lint on wildcards if the `non_exhaustive_omitted_patterns_lint` feature is + /// enabled and disallowed. + /// /// ### Why is this bad? /// This is probably a copy & paste error. If arm bodies /// are the same on purpose, you can factor them @@ -777,7 +785,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Check for temporaries returned from function calls in a match scrutinee that have the + /// Checks for temporaries returned from function calls in a match scrutinee that have the /// `clippy::has_significant_drop` attribute. /// /// ### Why is this bad? diff --git a/clippy_lints/src/matches/overlapping_arms.rs b/clippy_lints/src/matches/overlapping_arms.rs index abf2525a61c6..8be3c178a291 100644 --- a/clippy_lints/src/matches/overlapping_arms.rs +++ b/clippy_lints/src/matches/overlapping_arms.rs @@ -41,7 +41,7 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) cx.tcx.valtree_to_const_val((ty, min_val_const.to_valtree())), ty, ); - miri_to_const(cx.tcx, min_constant)? + miri_to_const(cx, min_constant)? }, }; let rhs_const = match rhs { @@ -52,7 +52,7 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) cx.tcx.valtree_to_const_val((ty, max_val_const.to_valtree())), ty, ); - miri_to_const(cx.tcx, max_constant)? + miri_to_const(cx, max_constant)? }, }; let lhs_val = lhs_const.int_value(cx, ty)?; diff --git a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs index 93ef07d36aea..37528d9f7f20 100644 --- a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs +++ b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs @@ -140,7 +140,7 @@ impl<'a, 'tcx> SigDropChecker<'a, 'tcx> { } } - for generic_arg in b.iter() { + for generic_arg in *b { if let GenericArgKind::Type(ty) = generic_arg.unpack() { if self.has_sig_drop_attr(cx, ty) { return true; diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index ad47c13896c5..35627d6c6491 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{expr_block, snippet}; +use clippy_utils::source::{expr_block, get_source_text, snippet}; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, peel_mid_ty_refs}; use clippy_utils::{is_lint_allowed, is_unit_expr, is_wild, peel_blocks, peel_hir_pat_refs, peel_n_hir_expr_refs}; use core::cmp::max; @@ -7,10 +7,26 @@ use rustc_errors::Applicability; use rustc_hir::{Arm, BindingAnnotation, Block, Expr, ExprKind, Pat, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; -use rustc_span::sym; +use rustc_span::{sym, Span}; use super::{MATCH_BOOL, SINGLE_MATCH, SINGLE_MATCH_ELSE}; +/// Checks if there are comments contained within a span. +/// This is a very "naive" check, as it just looks for the literal characters // and /* in the +/// source text. This won't be accurate if there are potentially expressions contained within the +/// span, e.g. a string literal `"//"`, but we know that this isn't the case for empty +/// match arms. +fn empty_arm_has_comment(cx: &LateContext<'_>, span: Span) -> bool { + if let Some(ff) = get_source_text(cx, span) + && let Some(text) = ff.as_str() + { + text.as_bytes().windows(2) + .any(|w| w == b"//" || w == b"/*") + } else { + false + } +} + #[rustfmt::skip] pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) { if arms.len() == 2 && arms[0].guard.is_none() && arms[1].guard.is_none() { @@ -25,7 +41,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: return; } let els = arms[1].body; - let els = if is_unit_expr(peel_blocks(els)) { + let els = if is_unit_expr(peel_blocks(els)) && !empty_arm_has_comment(cx, els.span) { None } else if let ExprKind::Block(Block { stmts, expr: block_expr, .. }, _) = els.kind { if stmts.len() == 1 && block_expr.is_none() || stmts.is_empty() && block_expr.is_some() { @@ -35,7 +51,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: // block with 2+ statements or 1 expr and 1+ statement Some(els) } else { - // not a block, don't lint + // not a block or an emtpy block w/ comments, don't lint return; }; diff --git a/clippy_lints/src/matches/try_err.rs b/clippy_lints/src/matches/try_err.rs index 704c34c32bf7..3a7f1e034f31 100644 --- a/clippy_lints/src/matches/try_err.rs +++ b/clippy_lints/src/matches/try_err.rs @@ -81,7 +81,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, scrutine /// Finds function return type by examining return expressions in match arms. fn find_return_type<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx ExprKind<'_>) -> Option> { if let ExprKind::Match(_, arms, MatchSource::TryDesugar) = expr { - for arm in arms.iter() { + for arm in *arms { if let ExprKind::Ret(Some(ret)) = arm.body.kind { return Some(cx.typeck_results().expr_ty(ret)); } diff --git a/clippy_lints/src/mem_forget.rs b/clippy_lints/src/mem_forget.rs deleted file mode 100644 index d6c235b5a693..000000000000 --- a/clippy_lints/src/mem_forget.rs +++ /dev/null @@ -1,46 +0,0 @@ -use clippy_utils::diagnostics::span_lint; -use rustc_hir::{Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::sym; - -declare_clippy_lint! { - /// ### What it does - /// Checks for usage of `std::mem::forget(t)` where `t` is - /// `Drop`. - /// - /// ### Why is this bad? - /// `std::mem::forget(t)` prevents `t` from running its - /// destructor, possibly causing leaks. - /// - /// ### Example - /// ```rust - /// # use std::mem; - /// # use std::rc::Rc; - /// mem::forget(Rc::new(55)) - /// ``` - #[clippy::version = "pre 1.29.0"] - pub MEM_FORGET, - restriction, - "`mem::forget` usage on `Drop` types, likely to cause memory leaks" -} - -declare_lint_pass!(MemForget => [MEM_FORGET]); - -impl<'tcx> LateLintPass<'tcx> for MemForget { - fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - if let ExprKind::Call(path_expr, [ref first_arg, ..]) = e.kind { - if let ExprKind::Path(ref qpath) = path_expr.kind { - if let Some(def_id) = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id() { - if cx.tcx.is_diagnostic_item(sym::mem_forget, def_id) { - let forgot_ty = cx.typeck_results().expr_ty(first_arg); - - if forgot_ty.ty_adt_def().map_or(false, |def| def.has_dtor(cx.tcx)) { - span_lint(cx, MEM_FORGET, e.span, "usage of `mem::forget` on `Drop` type"); - } - } - } - } - } - } -} diff --git a/clippy_lints/src/methods/drain_collect.rs b/clippy_lints/src/methods/drain_collect.rs new file mode 100644 index 000000000000..d0c79dc11b07 --- /dev/null +++ b/clippy_lints/src/methods/drain_collect.rs @@ -0,0 +1,85 @@ +use crate::methods::DRAIN_COLLECT; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_range_full; +use clippy_utils::source::snippet; +use clippy_utils::ty::is_type_lang_item; +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_hir::ExprKind; +use rustc_hir::LangItem; +use rustc_hir::Path; +use rustc_hir::QPath; +use rustc_lint::LateContext; +use rustc_middle::query::Key; +use rustc_middle::ty; +use rustc_middle::ty::Ty; +use rustc_span::sym; +use rustc_span::Symbol; + +/// Checks if both types match the given diagnostic item, e.g.: +/// +/// `vec![1,2].drain(..).collect::>()` +/// ^^^^^^^^^ ^^^^^^ true +/// `vec![1,2].drain(..).collect::>()` +/// ^^^^^^^^^ ^^^^^^^^^^ false +fn types_match_diagnostic_item(cx: &LateContext<'_>, expr: Ty<'_>, recv: Ty<'_>, sym: Symbol) -> bool { + if let Some(expr_adt_did) = expr.ty_adt_id() + && let Some(recv_adt_did) = recv.ty_adt_id() + { + cx.tcx.is_diagnostic_item(sym, expr_adt_did) && cx.tcx.is_diagnostic_item(sym, recv_adt_did) + } else { + false + } +} + +/// Checks `std::{vec::Vec, collections::VecDeque}`. +fn check_vec(cx: &LateContext<'_>, args: &[Expr<'_>], expr: Ty<'_>, recv: Ty<'_>, recv_path: &Path<'_>) -> bool { + (types_match_diagnostic_item(cx, expr, recv, sym::Vec) + || types_match_diagnostic_item(cx, expr, recv, sym::VecDeque)) + && matches!(args, [arg] if is_range_full(cx, arg, Some(recv_path))) +} + +/// Checks `std::string::String` +fn check_string(cx: &LateContext<'_>, args: &[Expr<'_>], expr: Ty<'_>, recv: Ty<'_>, recv_path: &Path<'_>) -> bool { + is_type_lang_item(cx, expr, LangItem::String) + && is_type_lang_item(cx, recv, LangItem::String) + && matches!(args, [arg] if is_range_full(cx, arg, Some(recv_path))) +} + +/// Checks `std::collections::{HashSet, HashMap, BinaryHeap}`. +fn check_collections(cx: &LateContext<'_>, expr: Ty<'_>, recv: Ty<'_>) -> Option<&'static str> { + types_match_diagnostic_item(cx, expr, recv, sym::HashSet) + .then_some("HashSet") + .or_else(|| types_match_diagnostic_item(cx, expr, recv, sym::HashMap).then_some("HashMap")) + .or_else(|| types_match_diagnostic_item(cx, expr, recv, sym::BinaryHeap).then_some("BinaryHeap")) +} + +pub(super) fn check(cx: &LateContext<'_>, args: &[Expr<'_>], expr: &Expr<'_>, recv: &Expr<'_>) { + let expr_ty = cx.typeck_results().expr_ty(expr); + let recv_ty = cx.typeck_results().expr_ty(recv); + let recv_ty_no_refs = recv_ty.peel_refs(); + + if let ExprKind::Path(QPath::Resolved(_, recv_path)) = recv.kind + && let Some(typename) = check_vec(cx, args, expr_ty, recv_ty_no_refs, recv_path) + .then_some("Vec") + .or_else(|| check_string(cx, args, expr_ty, recv_ty_no_refs, recv_path).then_some("String")) + .or_else(|| check_collections(cx, expr_ty, recv_ty_no_refs)) + { + let recv = snippet(cx, recv.span, ""); + let sugg = if let ty::Ref(..) = recv_ty.kind() { + format!("std::mem::take({recv})") + } else { + format!("std::mem::take(&mut {recv})") + }; + + span_lint_and_sugg( + cx, + DRAIN_COLLECT, + expr.span, + &format!("you seem to be trying to move all elements into a new `{typename}`"), + "consider using `mem::take`", + sugg, + Applicability::MachineApplicable, + ); + } +} diff --git a/clippy_lints/src/methods/get_unwrap.rs b/clippy_lints/src/methods/get_unwrap.rs index ffc3a4d780e5..e35fb12ed791 100644 --- a/clippy_lints/src/methods/get_unwrap.rs +++ b/clippy_lints/src/methods/get_unwrap.rs @@ -3,7 +3,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::get_parent_expr; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; -use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -23,21 +22,15 @@ pub(super) fn check<'tcx>( let mut applicability = Applicability::MachineApplicable; let expr_ty = cx.typeck_results().expr_ty(recv); let get_args_str = snippet_with_applicability(cx, get_arg.span, "..", &mut applicability); - let mut needs_ref; let caller_type = if derefs_to_slice(cx, recv, expr_ty).is_some() { - needs_ref = get_args_str.parse::().is_ok(); "slice" } else if is_type_diagnostic_item(cx, expr_ty, sym::Vec) { - needs_ref = get_args_str.parse::().is_ok(); "Vec" } else if is_type_diagnostic_item(cx, expr_ty, sym::VecDeque) { - needs_ref = get_args_str.parse::().is_ok(); "VecDeque" } else if !is_mut && is_type_diagnostic_item(cx, expr_ty, sym::HashMap) { - needs_ref = true; "HashMap" } else if !is_mut && is_type_diagnostic_item(cx, expr_ty, sym::BTreeMap) { - needs_ref = true; "BTreeMap" } else { return; // caller is not a type that we want to lint @@ -45,18 +38,24 @@ pub(super) fn check<'tcx>( let mut span = expr.span; - // Handle the case where the result is immediately dereferenced - // by not requiring ref and pulling the dereference into the - // suggestion. - if_chain! { - if needs_ref; - if let Some(parent) = get_parent_expr(cx, expr); - if let hir::ExprKind::Unary(hir::UnOp::Deref, _) = parent.kind; - then { - needs_ref = false; + // Handle the case where the result is immediately dereferenced, + // either directly be the user, or as a result of a method call or the like + // by not requiring an explicit reference + let needs_ref = if let Some(parent) = get_parent_expr(cx, expr) + && let hir::ExprKind::Unary(hir::UnOp::Deref, _) + | hir::ExprKind::MethodCall(..) + | hir::ExprKind::Field(..) + | hir::ExprKind::Index(..) = parent.kind + { + if let hir::ExprKind::Unary(hir::UnOp::Deref, _) = parent.kind { + // if the user explicitly dereferences the result, we can adjust + // the span to also include the deref part span = parent.span; } - } + false + } else { + true + }; let mut_str = if is_mut { "_mut" } else { "" }; let borrow_str = if !needs_ref { diff --git a/clippy_lints/src/methods/iter_nth.rs b/clippy_lints/src/methods/iter_nth.rs index ceee12784cbb..121043104058 100644 --- a/clippy_lints/src/methods/iter_nth.rs +++ b/clippy_lints/src/methods/iter_nth.rs @@ -20,9 +20,9 @@ pub(super) fn check<'tcx>( let caller_type = if derefs_to_slice(cx, iter_recv, cx.typeck_results().expr_ty(iter_recv)).is_some() { "slice" } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(iter_recv), sym::Vec) { - "Vec" + "`Vec`" } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(iter_recv), sym::VecDeque) { - "VecDeque" + "`VecDeque`" } else { iter_nth_zero::check(cx, expr, nth_recv, nth_arg); return; // caller is not a type that we want to lint diff --git a/clippy_lints/src/methods/iter_nth_zero.rs b/clippy_lints/src/methods/iter_nth_zero.rs index d1609eebfdca..e1f950d5a4a5 100644 --- a/clippy_lints/src/methods/iter_nth_zero.rs +++ b/clippy_lints/src/methods/iter_nth_zero.rs @@ -1,8 +1,8 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_trait_method; use clippy_utils::source::snippet_with_applicability; -use if_chain::if_chain; +use clippy_utils::{is_lang_item_or_ctor, is_trait_method}; +use hir::{LangItem, OwnerNode}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -11,20 +11,21 @@ use rustc_span::sym; use super::ITER_NTH_ZERO; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) { - if_chain! { - if is_trait_method(cx, expr, sym::Iterator); - if let Some(Constant::Int(0)) = constant(cx, cx.typeck_results(), arg); - then { - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - ITER_NTH_ZERO, - expr.span, - "called `.nth(0)` on a `std::iter::Iterator`, when `.next()` is equivalent", - "try calling `.next()` instead of `.nth(0)`", - format!("{}.next()", snippet_with_applicability(cx, recv.span, "..", &mut applicability)), - applicability, - ); - } + if let OwnerNode::Item(item) = cx.tcx.hir().owner(cx.tcx.hir().get_parent_item(expr.hir_id)) + && let def_id = item.owner_id.to_def_id() + && is_trait_method(cx, expr, sym::Iterator) + && let Some(Constant::Int(0)) = constant(cx, cx.typeck_results(), arg) + && !is_lang_item_or_ctor(cx, def_id, LangItem::IteratorNext) + { + let mut app = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + ITER_NTH_ZERO, + expr.span, + "called `.nth(0)` on a `std::iter::Iterator`, when `.next()` is equivalent", + "try calling `.next()` instead of `.nth(0)`", + format!("{}.next()", snippet_with_applicability(cx, recv.span, "..", &mut app)), + app, + ); } } diff --git a/clippy_lints/src/methods/manual_try_fold.rs b/clippy_lints/src/methods/manual_try_fold.rs new file mode 100644 index 000000000000..576a58499b15 --- /dev/null +++ b/clippy_lints/src/methods/manual_try_fold.rs @@ -0,0 +1,55 @@ +use clippy_utils::{ + diagnostics::span_lint_and_sugg, + is_from_proc_macro, + msrvs::{Msrv, ITERATOR_TRY_FOLD}, + source::snippet_opt, + ty::implements_trait, +}; +use rustc_errors::Applicability; +use rustc_hir::{ + def::{DefKind, Res}, + Expr, ExprKind, +}; +use rustc_lint::{LateContext, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_span::Span; + +use super::MANUAL_TRY_FOLD; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &Expr<'tcx>, + init: &Expr<'_>, + acc: &Expr<'_>, + fold_span: Span, + msrv: &Msrv, +) { + if !in_external_macro(cx.sess(), fold_span) + && msrv.meets(ITERATOR_TRY_FOLD) + && let init_ty = cx.typeck_results().expr_ty(init) + && let Some(try_trait) = cx.tcx.lang_items().try_trait() + && implements_trait(cx, init_ty, try_trait, &[]) + && let ExprKind::Call(path, [first, rest @ ..]) = init.kind + && let ExprKind::Path(qpath) = path.kind + && let Res::Def(DefKind::Ctor(_, _), _) = cx.qpath_res(&qpath, path.hir_id) + && let ExprKind::Closure(closure) = acc.kind + && !is_from_proc_macro(cx, expr) + && let Some(args_snip) = closure.fn_arg_span.and_then(|fn_arg_span| snippet_opt(cx, fn_arg_span)) + { + let init_snip = rest + .is_empty() + .then_some(first.span) + .and_then(|span| snippet_opt(cx, span)) + .unwrap_or("...".to_owned()); + + span_lint_and_sugg( + cx, + MANUAL_TRY_FOLD, + fold_span, + "usage of `Iterator::fold` on a type that implements `Try`", + "use `try_fold` instead", + format!("try_fold({init_snip}, {args_snip} ...)", ), + Applicability::HasPlaceholders, + ); + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 88cbefbb5d3d..24dbe8c1d751 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -14,6 +14,7 @@ mod clone_on_copy; mod clone_on_ref_ptr; mod cloned_instead_of_copied; mod collapsible_str_replace; +mod drain_collect; mod err_expect; mod expect_fun_call; mod expect_used; @@ -49,6 +50,7 @@ mod manual_next_back; mod manual_ok_or; mod manual_saturating_arithmetic; mod manual_str_repeat; +mod manual_try_fold; mod map_clone; mod map_collect_result_unit; mod map_err_ignore; @@ -93,6 +95,7 @@ mod unnecessary_fold; mod unnecessary_iter_cloned; mod unnecessary_join; mod unnecessary_lazy_eval; +mod unnecessary_literal_unwrap; mod unnecessary_sort_by; mod unnecessary_to_owned; mod unwrap_or_else_default; @@ -273,6 +276,32 @@ declare_clippy_lint! { "using `.unwrap()` on `Result` or `Option`, which should at least get a better message using `expect()`" } +declare_clippy_lint! { + /// ### What it does + /// Checks for `.unwrap()` related calls on `Result`s and `Option`s that are constructed. + /// + /// ### Why is this bad? + /// It is better to write the value directly without the indirection. + /// + /// ### Examples + /// ```rust + /// let val1 = Some(1).unwrap(); + /// let val2 = Ok::<_, ()>(1).unwrap(); + /// let val3 = Err::<(), _>(1).unwrap_err(); + /// ``` + /// + /// Use instead: + /// ```rust + /// let val1 = 1; + /// let val2 = 1; + /// let val3 = 1; + /// ``` + #[clippy::version = "1.69.0"] + pub UNNECESSARY_LITERAL_UNWRAP, + complexity, + "using `unwrap()` related calls on `Result` and `Option` constructors" +} + declare_clippy_lint! { /// ### What it does /// Checks for `.expect()` or `.expect_err()` calls on `Result`s and `.expect()` call on `Option`s. @@ -485,6 +514,7 @@ declare_clippy_lint! { /// # let result: Result = Ok(1); /// # fn some_function(foo: ()) -> usize { 1 } /// option.map(|a| a + 1).unwrap_or(0); + /// option.map(|a| a > 10).unwrap_or(false); /// result.map(|a| a + 1).unwrap_or_else(some_function); /// ``` /// @@ -494,6 +524,7 @@ declare_clippy_lint! { /// # let result: Result = Ok(1); /// # fn some_function(foo: ()) -> usize { 1 } /// option.map_or(0, |a| a + 1); + /// option.is_some_and(|a| a > 10); /// result.map_or_else(some_function, |a| a + 1); /// ``` #[clippy::version = "1.45.0"] @@ -3220,6 +3251,71 @@ declare_clippy_lint! { "manual reverse iteration of `DoubleEndedIterator`" } +declare_clippy_lint! { + /// ### What it does + /// Checks for calls to `.drain()` that clear the collection, immediately followed by a call to `.collect()`. + /// + /// > "Collection" in this context refers to any type with a `drain` method: + /// > `Vec`, `VecDeque`, `BinaryHeap`, `HashSet`,`HashMap`, `String` + /// + /// ### Why is this bad? + /// Using `mem::take` is faster as it avoids the allocation. + /// When using `mem::take`, the old collection is replaced with an empty one and ownership of + /// the old collection is returned. + /// + /// ### Known issues + /// `mem::take(&mut vec)` is almost equivalent to `vec.drain(..).collect()`, except that + /// it also moves the **capacity**. The user might have explicitly written it this way + /// to keep the capacity on the original `Vec`. + /// + /// ### Example + /// ```rust + /// fn remove_all(v: &mut Vec) -> Vec { + /// v.drain(..).collect() + /// } + /// ``` + /// Use instead: + /// ```rust + /// use std::mem; + /// fn remove_all(v: &mut Vec) -> Vec { + /// mem::take(v) + /// } + /// ``` + #[clippy::version = "1.71.0"] + pub DRAIN_COLLECT, + perf, + "calling `.drain(..).collect()` to move all elements into a new collection" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `Iterator::fold` with a type that implements `Try`. + /// + /// ### Why is this bad? + /// The code should use `try_fold` instead, which short-circuits on failure, thus opening the + /// door for additional optimizations not possible with `fold` as rustc can guarantee the + /// function is never called on `None`, `Err`, etc., alleviating otherwise necessary checks. It's + /// also slightly more idiomatic. + /// + /// ### Known issues + /// This lint doesn't take into account whether a function does something on the failure case, + /// i.e., whether short-circuiting will affect behavior. Refactoring to `try_fold` is not + /// desirable in those cases. + /// + /// ### Example + /// ```rust + /// vec![1, 2, 3].iter().fold(Some(0i32), |sum, i| sum?.checked_add(*i)); + /// ``` + /// Use instead: + /// ```rust + /// vec![1, 2, 3].iter().try_fold(0i32, |sum, i| sum.checked_add(*i)); + /// ``` + #[clippy::version = "1.72.0"] + pub MANUAL_TRY_FOLD, + perf, + "checks for usage of `Iterator::fold` with a type that implements `Try`" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -3349,6 +3445,9 @@ impl_lint_pass!(Methods => [ SUSPICIOUS_COMMAND_ARG_SPACE, CLEAR_WITH_DRAIN, MANUAL_NEXT_BACK, + UNNECESSARY_LITERAL_UNWRAP, + DRAIN_COLLECT, + MANUAL_TRY_FOLD, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3578,6 +3677,9 @@ impl Methods { manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg); } }, + Some(("drain", recv, args, ..)) => { + drain_collect::check(cx, args, expr, recv); + } _ => {}, } }, @@ -3606,12 +3708,18 @@ impl Methods { case_sensitive_file_extension_comparisons::check(cx, expr, span, recv, arg); } }, - ("expect", [_]) => match method_call(recv) { - Some(("ok", recv, [], _, _)) => ok_expect::check(cx, expr, recv), - Some(("err", recv, [], err_span, _)) => err_expect::check(cx, expr, recv, span, err_span, &self.msrv), - _ => expect_used::check(cx, expr, recv, false, self.allow_expect_in_tests), + ("expect", [_]) => { + match method_call(recv) { + Some(("ok", recv, [], _, _)) => ok_expect::check(cx, expr, recv), + Some(("err", recv, [], err_span, _)) => err_expect::check(cx, expr, recv, span, err_span, &self.msrv), + _ => expect_used::check(cx, expr, recv, false, self.allow_expect_in_tests), + } + unnecessary_literal_unwrap::check(cx, expr, recv, name, args); + }, + ("expect_err", [_]) => { + unnecessary_literal_unwrap::check(cx, expr, recv, name, args); + expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests); }, - ("expect_err", [_]) => expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests), ("extend", [arg]) => { string_extend_chars::check(cx, expr, recv, arg); extend_with_drain::check(cx, expr, recv, arg); @@ -3632,7 +3740,10 @@ impl Methods { Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, true), _ => {}, }, - ("fold", [init, acc]) => unnecessary_fold::check(cx, expr, init, acc, span), + ("fold", [init, acc]) => { + manual_try_fold::check(cx, expr, init, acc, call_span, &self.msrv); + unnecessary_fold::check(cx, expr, init, acc, span); + }, ("for_each", [_]) => { if let Some(("inspect", _, [_], span2, _)) = method_call(recv) { inspect_for_each::check(cx, expr, span2); @@ -3816,28 +3927,41 @@ impl Methods { }, _ => {}, } + unnecessary_literal_unwrap::check(cx, expr, recv, name, args); unwrap_used::check(cx, expr, recv, false, self.allow_unwrap_in_tests); }, - ("unwrap_err", []) => unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests), - ("unwrap_or", [u_arg]) => match method_call(recv) { - Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), lhs, [rhs], _, _)) => { - manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]); - }, - Some(("map", m_recv, [m_arg], span, _)) => { - option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span); - }, - Some(("then_some", t_recv, [t_arg], _, _)) => { - obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg); - }, - _ => {}, + ("unwrap_err", []) => { + unnecessary_literal_unwrap::check(cx, expr, recv, name, args); + unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests); }, - ("unwrap_or_else", [u_arg]) => match method_call(recv) { - Some(("map", recv, [map_arg], _, _)) - if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, &self.msrv) => {}, - _ => { - unwrap_or_else_default::check(cx, expr, recv, u_arg); - unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or"); - }, + ("unwrap_or", [u_arg]) => { + match method_call(recv) { + Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), lhs, [rhs], _, _)) => { + manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]); + }, + Some(("map", m_recv, [m_arg], span, _)) => { + option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span, &self.msrv); + }, + Some(("then_some", t_recv, [t_arg], _, _)) => { + obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg); + }, + _ => {}, + } + unnecessary_literal_unwrap::check(cx, expr, recv, name, args); + }, + ("unwrap_or_default", []) => { + unnecessary_literal_unwrap::check(cx, expr, recv, name, args); + } + ("unwrap_or_else", [u_arg]) => { + match method_call(recv) { + Some(("map", recv, [map_arg], _, _)) + if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, &self.msrv) => {}, + _ => { + unwrap_or_else_default::check(cx, expr, recv, u_arg); + unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or"); + }, + } + unnecessary_literal_unwrap::check(cx, expr, recv, name, args); }, ("zip", [arg]) => { if let ExprKind::MethodCall(name, iter_recv, [], _) = recv.kind diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs index 0699997d0d2b..ac209d014062 100644 --- a/clippy_lints/src/methods/needless_collect.rs +++ b/clippy_lints/src/methods/needless_collect.rs @@ -322,7 +322,7 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { // Check function calls on our collection - if let ExprKind::MethodCall(method_name, recv, [args @ ..], _) = &expr.kind { + if let ExprKind::MethodCall(method_name, recv, args, _) = &expr.kind { if method_name.ident.name == sym!(collect) && is_trait_method(self.cx, expr, sym::Iterator) { self.current_mutably_captured_ids = get_captured_ids(self.cx, self.cx.typeck_results().expr_ty(recv)); self.visit_expr(recv); diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index 4c6328481e43..f4f158c0439e 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -1,19 +1,26 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_copy; use clippy_utils::ty::is_type_diagnostic_item; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; +use rustc_hir::def::Res; use rustc_hir::intravisit::{walk_path, Visitor}; +use rustc_hir::ExprKind; +use rustc_hir::Node; +use rustc_hir::PatKind; +use rustc_hir::QPath; use rustc_hir::{self, HirId, Path}; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; use rustc_span::source_map::Span; -use rustc_span::{sym, Symbol}; +use rustc_span::sym; use super::MAP_UNWRAP_OR; /// lint use of `map().unwrap_or()` for `Option`s +#[expect(clippy::too_many_arguments)] pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, expr: &rustc_hir::Expr<'_>, @@ -22,12 +29,27 @@ pub(super) fn check<'tcx>( unwrap_recv: &rustc_hir::Expr<'_>, unwrap_arg: &'tcx rustc_hir::Expr<'_>, map_span: Span, + msrv: &Msrv, ) { // lint if the caller of `map()` is an `Option` if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option) { if !is_copy(cx, cx.typeck_results().expr_ty(unwrap_arg)) { - // Do not lint if the `map` argument uses identifiers in the `map` - // argument that are also used in the `unwrap_or` argument + // Replacing `.map().unwrap_or(
)` with `.map_or(, )` can sometimes lead to + // borrowck errors, see #10579 for one such instance. + // In particular, if `a` causes a move and `f` references that moved binding, then we cannot lint: + // ``` + // let x = vec![1, 2]; + // x.get(0..1).map(|s| s.to_vec()).unwrap_or(x); + // ``` + // This compiles, but changing it to `map_or` will produce a compile error: + // ``` + // let x = vec![1, 2]; + // x.get(0..1).map_or(x, |s| s.to_vec()) + // ^ moving `x` here + // ^^^^^^^^^^^ while it is borrowed here (and later used in the closure) + // ``` + // So, we have to check that `a` is not referenced anywhere (even outside of the `.map` closure!) + // before the call to `unwrap_or`. let mut unwrap_visitor = UnwrapVisitor { cx, @@ -35,14 +57,18 @@ pub(super) fn check<'tcx>( }; unwrap_visitor.visit_expr(unwrap_arg); - let mut map_expr_visitor = MapExprVisitor { + let mut reference_visitor = ReferenceVisitor { cx, identifiers: unwrap_visitor.identifiers, - found_identifier: false, + found_reference: false, + unwrap_or_span: unwrap_arg.span, }; - map_expr_visitor.visit_expr(map_arg); - if map_expr_visitor.found_identifier { + let map = cx.tcx.hir(); + let body = map.body(map.body_owned_by(map.enclosing_body_owner(expr.hir_id))); + reference_visitor.visit_body(body); + + if reference_visitor.found_reference { return; } } @@ -51,16 +77,29 @@ pub(super) fn check<'tcx>( return; } + // is_some_and is stabilised && `unwrap_or` argument is false; suggest `is_some_and` instead + let suggest_is_some_and = msrv.meets(msrvs::OPTION_IS_SOME_AND) + && matches!(&unwrap_arg.kind, ExprKind::Lit(lit) + if matches!(lit.node, rustc_ast::LitKind::Bool(false))); + let mut applicability = Applicability::MachineApplicable; // get snippet for unwrap_or() let unwrap_snippet = snippet_with_applicability(cx, unwrap_arg.span, "..", &mut applicability); // lint message // comparing the snippet from source to raw text ("None") below is safe // because we already have checked the type. - let arg = if unwrap_snippet == "None" { "None" } else { "" }; + let arg = if unwrap_snippet == "None" { + "None" + } else if suggest_is_some_and { + "false" + } else { + "" + }; let unwrap_snippet_none = unwrap_snippet == "None"; let suggest = if unwrap_snippet_none { "and_then()" + } else if suggest_is_some_and { + "is_some_and()" } else { "map_or(, )" }; @@ -75,12 +114,18 @@ pub(super) fn check<'tcx>( let mut suggestion = vec![ ( map_span, - String::from(if unwrap_snippet_none { "and_then" } else { "map_or" }), + String::from(if unwrap_snippet_none { + "and_then" + } else if suggest_is_some_and { + "is_some_and" + } else { + "map_or" + }), ), (expr.span.with_lo(unwrap_recv.span.hi()), String::new()), ]; - if !unwrap_snippet_none { + if !unwrap_snippet_none && !suggest_is_some_and { suggestion.push((map_arg_span.with_hi(map_arg_span.lo()), format!("{unwrap_snippet}, "))); } @@ -91,35 +136,18 @@ pub(super) fn check<'tcx>( struct UnwrapVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, - identifiers: FxHashSet, + identifiers: FxHashSet, } impl<'a, 'tcx> Visitor<'tcx> for UnwrapVisitor<'a, 'tcx> { type NestedFilter = nested_filter::All; - fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) { - self.identifiers.insert(ident(path)); - walk_path(self, path); - } - - fn nested_visit_map(&mut self) -> Self::Map { - self.cx.tcx.hir() - } -} - -struct MapExprVisitor<'a, 'tcx> { - cx: &'a LateContext<'tcx>, - identifiers: FxHashSet, - found_identifier: bool, -} - -impl<'a, 'tcx> Visitor<'tcx> for MapExprVisitor<'a, 'tcx> { - type NestedFilter = nested_filter::All; - - fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) { - if self.identifiers.contains(&ident(path)) { - self.found_identifier = true; - return; + fn visit_path(&mut self, path: &Path<'tcx>, _: HirId) { + if let Res::Local(local_id) = path.res + && let Some(Node::Pat(pat)) = self.cx.tcx.hir().find(local_id) + && let PatKind::Binding(_, local_id, ..) = pat.kind + { + self.identifiers.insert(local_id); } walk_path(self, path); } @@ -129,10 +157,35 @@ impl<'a, 'tcx> Visitor<'tcx> for MapExprVisitor<'a, 'tcx> { } } -fn ident(path: &Path<'_>) -> Symbol { - path.segments - .last() - .expect("segments should be composed of at least 1 element") - .ident - .name +struct ReferenceVisitor<'a, 'tcx> { + cx: &'a LateContext<'tcx>, + identifiers: FxHashSet, + found_reference: bool, + unwrap_or_span: Span, +} + +impl<'a, 'tcx> Visitor<'tcx> for ReferenceVisitor<'a, 'tcx> { + type NestedFilter = nested_filter::All; + fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'_>) { + // If we haven't found a reference yet, check if this references + // one of the locals that was moved in the `unwrap_or` argument. + // We are only interested in exprs that appear before the `unwrap_or` call. + if !self.found_reference { + if expr.span < self.unwrap_or_span + && let ExprKind::Path(ref path) = expr.kind + && let QPath::Resolved(_, path) = path + && let Res::Local(local_id) = path.res + && let Some(Node::Pat(pat)) = self.cx.tcx.hir().find(local_id) + && let PatKind::Binding(_, local_id, ..) = pat.kind + && self.identifiers.contains(&local_id) + { + self.found_reference = true; + } + rustc_hir::intravisit::walk_expr(self, expr); + } + } + + fn nested_visit_map(&mut self) -> Self::Map { + self.cx.tcx.hir() + } } diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index 5ea12c441840..88a3c2620a40 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -289,7 +289,7 @@ fn parse_iter_usage<'tcx>( ) -> Option { let (kind, span) = match iter.next() { Some((_, Node::Expr(e))) if e.span.ctxt() == ctxt => { - let ExprKind::MethodCall(name, _, [args @ ..], _) = e.kind else { + let ExprKind::MethodCall(name, _, args, _) = e.kind else { return None; }; let did = cx.typeck_results().type_dependent_def_id(e.hir_id)?; diff --git a/clippy_lints/src/methods/unnecessary_fold.rs b/clippy_lints/src/methods/unnecessary_fold.rs index 5a3d12fd790e..8ec15a1c1b76 100644 --- a/clippy_lints/src/methods/unnecessary_fold.rs +++ b/clippy_lints/src/methods/unnecessary_fold.rs @@ -7,10 +7,113 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::PatKind; use rustc_lint::LateContext; +use rustc_middle::ty; use rustc_span::{source_map::Span, sym}; use super::UNNECESSARY_FOLD; +/// Do we need to suggest turbofish when suggesting a replacement method? +/// Changing `fold` to `sum` needs it sometimes when the return type can't be +/// inferred. This checks for some common cases where it can be safely omitted +fn needs_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { + let parent = cx.tcx.hir().get_parent(expr.hir_id); + + // some common cases where turbofish isn't needed: + // - assigned to a local variable with a type annotation + if let hir::Node::Local(local) = parent + && local.ty.is_some() + { + return false; + } + + // - part of a function call argument, can be inferred from the function signature (provided that + // the parameter is not a generic type parameter) + if let hir::Node::Expr(parent_expr) = parent + && let hir::ExprKind::Call(recv, args) = parent_expr.kind + && let hir::ExprKind::Path(ref qpath) = recv.kind + && let Some(fn_def_id) = cx.qpath_res(qpath, recv.hir_id).opt_def_id() + && let fn_sig = cx.tcx.fn_sig(fn_def_id).skip_binder().skip_binder() + && let Some(arg_pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id) + && let Some(ty) = fn_sig.inputs().get(arg_pos) + && !matches!(ty.kind(), ty::Param(_)) + { + return false; + } + + // if it's neither of those, stay on the safe side and suggest turbofish, + // even if it could work! + true +} + +#[derive(Copy, Clone)] +struct Replacement { + method_name: &'static str, + has_args: bool, + has_generic_return: bool, +} + +fn check_fold_with_op( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + acc: &hir::Expr<'_>, + fold_span: Span, + op: hir::BinOpKind, + replacement: Replacement, +) { + if_chain! { + // Extract the body of the closure passed to fold + if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = acc.kind; + let closure_body = cx.tcx.hir().body(body); + let closure_expr = peel_blocks(closure_body.value); + + // Check if the closure body is of the form `acc some_expr(x)` + if let hir::ExprKind::Binary(ref bin_op, left_expr, right_expr) = closure_expr.kind; + if bin_op.node == op; + + // Extract the names of the two arguments to the closure + if let [param_a, param_b] = closure_body.params; + if let PatKind::Binding(_, first_arg_id, ..) = strip_pat_refs(param_a.pat).kind; + if let PatKind::Binding(_, second_arg_id, second_arg_ident, _) = strip_pat_refs(param_b.pat).kind; + + if path_to_local_id(left_expr, first_arg_id); + if replacement.has_args || path_to_local_id(right_expr, second_arg_id); + + then { + let mut applicability = Applicability::MachineApplicable; + + let turbofish = if replacement.has_generic_return { + format!("::<{}>", cx.typeck_results().expr_ty_adjusted(right_expr).peel_refs()) + } else { + String::new() + }; + + let sugg = if replacement.has_args { + format!( + "{method}{turbofish}(|{second_arg_ident}| {r})", + method = replacement.method_name, + r = snippet_with_applicability(cx, right_expr.span, "EXPR", &mut applicability), + ) + } else { + format!( + "{method}{turbofish}()", + method = replacement.method_name, + ) + }; + + span_lint_and_sugg( + cx, + UNNECESSARY_FOLD, + fold_span.with_hi(expr.span.hi()), + // TODO #2371 don't suggest e.g., .any(|x| f(x)) if we can suggest .any(f) + "this `.fold` can be written more succinctly using another method", + "try", + sugg, + applicability, + ); + } + } +} + pub(super) fn check( cx: &LateContext<'_>, expr: &hir::Expr<'_>, @@ -18,60 +121,6 @@ pub(super) fn check( acc: &hir::Expr<'_>, fold_span: Span, ) { - fn check_fold_with_op( - cx: &LateContext<'_>, - expr: &hir::Expr<'_>, - acc: &hir::Expr<'_>, - fold_span: Span, - op: hir::BinOpKind, - replacement_method_name: &str, - replacement_has_args: bool, - ) { - if_chain! { - // Extract the body of the closure passed to fold - if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = acc.kind; - let closure_body = cx.tcx.hir().body(body); - let closure_expr = peel_blocks(closure_body.value); - - // Check if the closure body is of the form `acc some_expr(x)` - if let hir::ExprKind::Binary(ref bin_op, left_expr, right_expr) = closure_expr.kind; - if bin_op.node == op; - - // Extract the names of the two arguments to the closure - if let [param_a, param_b] = closure_body.params; - if let PatKind::Binding(_, first_arg_id, ..) = strip_pat_refs(param_a.pat).kind; - if let PatKind::Binding(_, second_arg_id, second_arg_ident, _) = strip_pat_refs(param_b.pat).kind; - - if path_to_local_id(left_expr, first_arg_id); - if replacement_has_args || path_to_local_id(right_expr, second_arg_id); - - then { - let mut applicability = Applicability::MachineApplicable; - let sugg = if replacement_has_args { - format!( - "{replacement_method_name}(|{second_arg_ident}| {r})", - r = snippet_with_applicability(cx, right_expr.span, "EXPR", &mut applicability), - ) - } else { - format!( - "{replacement_method_name}()", - ) - }; - - span_lint_and_sugg( - cx, - UNNECESSARY_FOLD, - fold_span.with_hi(expr.span.hi()), - // TODO #2371 don't suggest e.g., .any(|x| f(x)) if we can suggest .any(f) - "this `.fold` can be written more succinctly using another method", - "try", - sugg, - applicability, - ); - } - } - } - // Check that this is a call to Iterator::fold rather than just some function called fold if !is_trait_method(cx, expr, sym::Iterator) { return; @@ -80,11 +129,59 @@ pub(super) fn check( // Check if the first argument to .fold is a suitable literal if let hir::ExprKind::Lit(lit) = init.kind { match lit.node { - ast::LitKind::Bool(false) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Or, "any", true), - ast::LitKind::Bool(true) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::And, "all", true), - ast::LitKind::Int(0, _) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Add, "sum", false), + ast::LitKind::Bool(false) => { + check_fold_with_op( + cx, + expr, + acc, + fold_span, + hir::BinOpKind::Or, + Replacement { + has_args: true, + has_generic_return: false, + method_name: "any", + }, + ); + }, + ast::LitKind::Bool(true) => { + check_fold_with_op( + cx, + expr, + acc, + fold_span, + hir::BinOpKind::And, + Replacement { + has_args: true, + has_generic_return: false, + method_name: "all", + }, + ); + }, + ast::LitKind::Int(0, _) => check_fold_with_op( + cx, + expr, + acc, + fold_span, + hir::BinOpKind::Add, + Replacement { + has_args: false, + has_generic_return: needs_turbofish(cx, expr), + method_name: "sum", + }, + ), ast::LitKind::Int(1, _) => { - check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Mul, "product", false); + check_fold_with_op( + cx, + expr, + acc, + fold_span, + hir::BinOpKind::Mul, + Replacement { + has_args: false, + has_generic_return: needs_turbofish(cx, expr), + method_name: "product", + }, + ); }, _ => (), } diff --git a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs new file mode 100644 index 000000000000..7877f6a386cb --- /dev/null +++ b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs @@ -0,0 +1,95 @@ +use clippy_utils::{diagnostics::span_lint_and_then, is_res_lang_ctor, last_path_segment, path_res, MaybePath}; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; + +use super::UNNECESSARY_LITERAL_UNWRAP; + +fn get_ty_from_args<'a>(args: Option<&'a [hir::GenericArg<'a>]>, index: usize) -> Option<&'a hir::Ty<'a>> { + let args = args?; + + if args.len() <= index { + return None; + } + + match args[index] { + hir::GenericArg::Type(ty) => match ty.kind { + hir::TyKind::Infer => None, + _ => Some(ty), + }, + _ => None, + } +} + +pub(super) fn check( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + recv: &hir::Expr<'_>, + method: &str, + args: &[hir::Expr<'_>], +) { + let init = clippy_utils::expr_or_init(cx, recv); + + let (constructor, call_args, ty) = if let hir::ExprKind::Call(call, call_args) = init.kind { + let Some(qpath) = call.qpath_opt() else { return }; + + let args = last_path_segment(qpath).args.map(|args| args.args); + let res = cx.qpath_res(qpath, call.hir_id()); + + if is_res_lang_ctor(cx, res, hir::LangItem::OptionSome) { + ("Some", call_args, get_ty_from_args(args, 0)) + } else if is_res_lang_ctor(cx, res, hir::LangItem::ResultOk) { + ("Ok", call_args, get_ty_from_args(args, 0)) + } else if is_res_lang_ctor(cx, res, hir::LangItem::ResultErr) { + ("Err", call_args, get_ty_from_args(args, 1)) + } else { + return; + } + } else if is_res_lang_ctor(cx, path_res(cx, init), hir::LangItem::OptionNone) { + let call_args: &[hir::Expr<'_>] = &[]; + ("None", call_args, None) + } else { + return; + }; + + let help_message = format!("used `{method}()` on `{constructor}` value"); + let suggestion_message = format!("remove the `{constructor}` and `{method}()`"); + + span_lint_and_then(cx, UNNECESSARY_LITERAL_UNWRAP, expr.span, &help_message, |diag| { + let suggestions = match (constructor, method, ty) { + ("None", "unwrap", _) => Some(vec![(expr.span, "panic!()".to_string())]), + ("None", "expect", _) => Some(vec![ + (expr.span.with_hi(args[0].span.lo()), "panic!(".to_string()), + (expr.span.with_lo(args[0].span.hi()), ")".to_string()), + ]), + (_, _, Some(_)) => None, + ("Ok", "unwrap_err", None) | ("Err", "unwrap", None) => Some(vec![ + ( + recv.span.with_hi(call_args[0].span.lo()), + "panic!(\"{:?}\", ".to_string(), + ), + (expr.span.with_lo(call_args[0].span.hi()), ")".to_string()), + ]), + ("Ok", "expect_err", None) | ("Err", "expect", None) => Some(vec![ + ( + recv.span.with_hi(call_args[0].span.lo()), + "panic!(\"{1}: {:?}\", ".to_string(), + ), + (call_args[0].span.with_lo(args[0].span.lo()), ", ".to_string()), + ]), + (_, _, None) => Some(vec![ + (recv.span.with_hi(call_args[0].span.lo()), String::new()), + (expr.span.with_lo(call_args[0].span.hi()), String::new()), + ]), + }; + + match (init.span == recv.span, suggestions) { + (true, Some(suggestions)) => { + diag.multipart_suggestion(suggestion_message, suggestions, Applicability::MachineApplicable); + }, + _ => { + diag.span_help(init.span, suggestion_message); + }, + } + }); +} diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 80eb00a1b42d..16ef24bd4e34 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -144,6 +144,11 @@ fn check_addr_of_expr( if let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref); if implements_trait(cx, receiver_ty, deref_trait_id, &[]); if cx.get_associated_type(receiver_ty, deref_trait_id, "Target") == Some(target_ty); + // Make sure that it's actually calling the right `.to_string()`, (#10033) + // *or* this is a `Cow::into_owned()` call (which would be the wrong into_owned receiver (str != Cow) + // but that's ok for Cow::into_owned specifically) + if cx.typeck_results().expr_ty_adjusted(receiver).peel_refs() == target_ty + || is_cow_into_owned(cx, method_name, method_def_id); then { if n_receiver_refs > 0 { span_lint_and_sugg( diff --git a/clippy_lints/src/min_ident_chars.rs b/clippy_lints/src/min_ident_chars.rs new file mode 100644 index 000000000000..d49bb0ca6e29 --- /dev/null +++ b/clippy_lints/src/min_ident_chars.rs @@ -0,0 +1,153 @@ +use clippy_utils::{diagnostics::span_lint, is_from_proc_macro}; +use rustc_data_structures::fx::FxHashSet; +use rustc_hir::{ + def::{DefKind, Res}, + intravisit::{walk_item, Visitor}, + GenericParamKind, HirId, Item, ItemKind, ItemLocalId, Node, Pat, PatKind, +}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::Span; +use std::borrow::Cow; + +declare_clippy_lint! { + /// ### What it does + /// Checks for idents which comprise of a single letter. + /// + /// Note: This lint can be very noisy when enabled; it may be desirable to only enable it + /// temporarily. + /// + /// ### Why is this bad? + /// In many cases it's not, but at times it can severely hinder readability. Some codebases may + /// wish to disallow this to improve readability. + /// + /// ### Example + /// ```rust,ignore + /// for m in movies { + /// let title = m.t; + /// } + /// ``` + /// Use instead: + /// ```rust,ignore + /// for movie in movies { + /// let title = movie.title; + /// } + /// ``` + #[clippy::version = "1.72.0"] + pub MIN_IDENT_CHARS, + restriction, + "disallows idents that are too short" +} +impl_lint_pass!(MinIdentChars => [MIN_IDENT_CHARS]); + +#[derive(Clone)] +pub struct MinIdentChars { + pub allowed_idents_below_min_chars: FxHashSet, + pub min_ident_chars_threshold: u64, +} + +impl MinIdentChars { + #[expect(clippy::cast_possible_truncation)] + fn is_ident_too_short(&self, cx: &LateContext<'_>, str: &str, span: Span) -> bool { + !in_external_macro(cx.sess(), span) + && str.len() <= self.min_ident_chars_threshold as usize + && !str.starts_with('_') + && !str.is_empty() + && self.allowed_idents_below_min_chars.get(&str.to_owned()).is_none() + } +} + +impl LateLintPass<'_> for MinIdentChars { + fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { + if self.min_ident_chars_threshold == 0 { + return; + } + + walk_item(&mut IdentVisitor { conf: self, cx }, item); + } + + // This is necessary as `Node::Pat`s are not visited in `visit_id`. :/ + fn check_pat(&mut self, cx: &LateContext<'_>, pat: &Pat<'_>) { + if let PatKind::Binding(_, _, ident, ..) = pat.kind + && let str = ident.as_str() + && self.is_ident_too_short(cx, str, ident.span) + { + emit_min_ident_chars(self, cx, str, ident.span); + } + } +} + +struct IdentVisitor<'cx, 'tcx> { + conf: &'cx MinIdentChars, + cx: &'cx LateContext<'tcx>, +} + +impl Visitor<'_> for IdentVisitor<'_, '_> { + fn visit_id(&mut self, hir_id: HirId) { + let Self { conf, cx } = *self; + // FIXME(#112534) Reimplementation of `find`, as it uses indexing, which can (and will in + // async functions, or really anything async) panic. This should probably be fixed on the + // rustc side, this is just a temporary workaround. + let node = if hir_id.local_id == ItemLocalId::from_u32(0) { + // In this case, we can just use `find`, `Owner`'s `node` field is private anyway so we can't + // reimplement it even if we wanted to + cx.tcx.hir().find(hir_id) + } else { + let Some(owner) = cx.tcx.hir_owner_nodes(hir_id.owner).as_owner() else { + return; + }; + owner.nodes.get(hir_id.local_id).copied().flatten().map(|p| p.node) + }; + let Some(node) = node else { + return; + }; + let Some(ident) = node.ident() else { + return; + }; + + let str = ident.as_str(); + if conf.is_ident_too_short(cx, str, ident.span) { + if let Node::Item(item) = node && let ItemKind::Use(..) = item.kind { + return; + } + // `struct Awa(T)` + // ^ + if let Node::PathSegment(path) = node { + if let Res::Def(def_kind, ..) = path.res && let DefKind::TyParam = def_kind { + return; + } + if matches!(path.res, Res::PrimTy(..)) || path.res.opt_def_id().is_some_and(|def_id| !def_id.is_local()) + { + return; + } + } + // `struct Awa(T)` + // ^ + if let Node::GenericParam(generic_param) = node + && let GenericParamKind::Type { .. } = generic_param.kind + { + return; + } + + if is_from_proc_macro(cx, &ident) { + return; + } + + emit_min_ident_chars(conf, cx, str, ident.span); + } + } +} + +fn emit_min_ident_chars(conf: &MinIdentChars, cx: &impl LintContext, ident: &str, span: Span) { + let help = if conf.min_ident_chars_threshold == 1 { + Cow::Borrowed("this ident consists of a single char") + } else { + Cow::Owned(format!( + "this ident is too short ({} <= {})", + ident.len(), + conf.min_ident_chars_threshold, + )) + }; + span_lint(cx, MIN_IDENT_CHARS, span, &help); +} diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs index 4f967755bfa1..e0904f17b8de 100644 --- a/clippy_lints/src/minmax.rs +++ b/clippy_lints/src/minmax.rs @@ -66,7 +66,7 @@ enum MinMax { Max, } -fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Constant, &'a Expr<'a>)> { +fn min_max<'a, 'tcx>(cx: &LateContext<'tcx>, expr: &'a Expr<'a>) -> Option<(MinMax, Constant<'tcx>, &'a Expr<'a>)> { match expr.kind { ExprKind::Call(path, args) => { if let ExprKind::Path(ref qpath) = path.kind { @@ -99,12 +99,12 @@ fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Cons } } -fn fetch_const<'a>( - cx: &LateContext<'_>, +fn fetch_const<'a, 'tcx>( + cx: &LateContext<'tcx>, receiver: Option<&'a Expr<'a>>, args: &'a [Expr<'a>], m: MinMax, -) -> Option<(MinMax, Constant, &'a Expr<'a>)> { +) -> Option<(MinMax, Constant<'tcx>, &'a Expr<'a>)> { let mut args = receiver.into_iter().chain(args); let first_arg = args.next()?; let second_arg = args.next()?; diff --git a/clippy_lints/src/misc_early/mixed_case_hex_literals.rs b/clippy_lints/src/misc_early/mixed_case_hex_literals.rs index ddb8b9173a53..9151cc633200 100644 --- a/clippy_lints/src/misc_early/mixed_case_hex_literals.rs +++ b/clippy_lints/src/misc_early/mixed_case_hex_literals.rs @@ -13,7 +13,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, lit_span: Span, suffix: &str, lit_sni return; } let mut seen = (false, false); - for ch in lit_snip.as_bytes()[2..=maybe_last_sep_idx].iter() { + for ch in &lit_snip.as_bytes()[2..=maybe_last_sep_idx] { match ch { b'a'..=b'f' => seen.0 = true, b'A'..=b'F' => seen.1 = true, diff --git a/clippy_lints/src/misc_early/mod.rs b/clippy_lints/src/misc_early/mod.rs index 78be6b9e23fa..b226b8781237 100644 --- a/clippy_lints/src/misc_early/mod.rs +++ b/clippy_lints/src/misc_early/mod.rs @@ -2,6 +2,7 @@ mod builtin_type_shadow; mod double_neg; mod literal_suffix; mod mixed_case_hex_literals; +mod redundant_at_rest_pattern; mod redundant_pattern; mod unneeded_field_pattern; mod unneeded_wildcard_pattern; @@ -318,6 +319,36 @@ declare_clippy_lint! { "tuple patterns with a wildcard pattern (`_`) is next to a rest pattern (`..`)" } +declare_clippy_lint! { + /// ### What it does + /// Checks for `[all @ ..]` patterns. + /// + /// ### Why is this bad? + /// In all cases, `all` works fine and can often make code simpler, as you possibly won't need + /// to convert from say a `Vec` to a slice by dereferencing. + /// + /// ### Example + /// ```rust,ignore + /// if let [all @ ..] = &*v { + /// // NOTE: Type is a slice here + /// println!("all elements: {all:#?}"); + /// } + /// ``` + /// Use instead: + /// ```rust,ignore + /// if let all = v { + /// // NOTE: Type is a `Vec` here + /// println!("all elements: {all:#?}"); + /// } + /// // or + /// println!("all elements: {v:#?}"); + /// ``` + #[clippy::version = "1.72.0"] + pub REDUNDANT_AT_REST_PATTERN, + complexity, + "checks for `[all @ ..]` where `all` would suffice" +} + declare_lint_pass!(MiscEarlyLints => [ UNNEEDED_FIELD_PATTERN, DUPLICATE_UNDERSCORE_ARGUMENT, @@ -329,6 +360,7 @@ declare_lint_pass!(MiscEarlyLints => [ BUILTIN_TYPE_SHADOW, REDUNDANT_PATTERN, UNNEEDED_WILDCARD_PATTERN, + REDUNDANT_AT_REST_PATTERN, ]); impl EarlyLintPass for MiscEarlyLints { @@ -339,8 +371,13 @@ impl EarlyLintPass for MiscEarlyLints { } fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &Pat) { + if in_external_macro(cx.sess(), pat.span) { + return; + } + unneeded_field_pattern::check(cx, pat); redundant_pattern::check(cx, pat); + redundant_at_rest_pattern::check(cx, pat); unneeded_wildcard_pattern::check(cx, pat); } diff --git a/clippy_lints/src/misc_early/redundant_at_rest_pattern.rs b/clippy_lints/src/misc_early/redundant_at_rest_pattern.rs new file mode 100644 index 000000000000..0c81ee5eced8 --- /dev/null +++ b/clippy_lints/src/misc_early/redundant_at_rest_pattern.rs @@ -0,0 +1,26 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use rustc_ast::{Pat, PatKind}; +use rustc_errors::Applicability; +use rustc_lint::{EarlyContext, LintContext}; +use rustc_middle::lint::in_external_macro; + +use super::REDUNDANT_AT_REST_PATTERN; + +pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) { + if !in_external_macro(cx.sess(), pat.span) + && let PatKind::Slice(slice) = &pat.kind + && let [one] = &**slice + && let PatKind::Ident(annotation, ident, Some(rest)) = &one.kind + && let PatKind::Rest = rest.kind + { + span_lint_and_sugg( + cx, + REDUNDANT_AT_REST_PATTERN, + pat.span, + "using a rest pattern to bind an entire slice to a local", + "this is better represented with just the binding", + format!("{}{ident}", annotation.prefix_str()), + Applicability::MachineApplicable, + ); + } +} diff --git a/clippy_lints/src/mismatching_type_param_order.rs b/clippy_lints/src/mismatching_type_param_order.rs index 9de4b56b77b5..28e041dee0db 100644 --- a/clippy_lints/src/mismatching_type_param_order.rs +++ b/clippy_lints/src/mismatching_type_param_order.rs @@ -59,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeParamMismatch { then { // get the name and span of the generic parameters in the Impl let mut impl_params = Vec::new(); - for p in generic_args.args.iter() { + for p in generic_args.args { match p { GenericArg::Type(Ty {kind: TyKind::Path(QPath::Resolved(_, path)), ..}) => impl_params.push((path.segments[0].ident.to_string(), path.span)), diff --git a/clippy_lints/src/missing_fields_in_debug.rs b/clippy_lints/src/missing_fields_in_debug.rs index b6f0de7e504f..1138d1163a4a 100644 --- a/clippy_lints/src/missing_fields_in_debug.rs +++ b/clippy_lints/src/missing_fields_in_debug.rs @@ -207,6 +207,11 @@ impl<'tcx> LateLintPass<'tcx> for MissingFieldsInDebug { if let ItemKind::Impl(Impl { of_trait: Some(trait_ref), self_ty, items, .. }) = item.kind && let Res::Def(DefKind::Trait, trait_def_id) = trait_ref.path.res && let TyKind::Path(QPath::Resolved(_, self_path)) = &self_ty.kind + // don't trigger if self is a generic parameter, e.g. `impl Debug for T` + // this can only happen in core itself, where the trait is defined, + // but it caused ICEs in the past: + // https://github.com/rust-lang/rust-clippy/issues/10887 + && !matches!(self_path.res, Res::Def(DefKind::TyParam, _)) && cx.match_def_path(trait_def_id, &[sym::core, sym::fmt, sym::Debug]) // don't trigger if this impl was derived && !cx.tcx.has_attr(item.owner_id, sym::automatically_derived) diff --git a/clippy_lints/src/mixed_read_write_in_expression.rs b/clippy_lints/src/mixed_read_write_in_expression.rs index f0be7771bb1a..57ec3a1f1e63 100644 --- a/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/clippy_lints/src/mixed_read_write_in_expression.rs @@ -114,7 +114,7 @@ struct DivergenceVisitor<'a, 'tcx> { impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> { fn maybe_walk_expr(&mut self, e: &'tcx Expr<'_>) { match e.kind { - ExprKind::Closure { .. } => {}, + ExprKind::Closure(..) | ExprKind::If(..) | ExprKind::Loop(..) => {}, ExprKind::Match(e, arms, _) => { self.visit_expr(e); for arm in arms { @@ -128,6 +128,7 @@ impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> { _ => walk_expr(self, e), } } + fn report_diverging_sub_expr(&mut self, e: &Expr<'_>) { span_lint(self.cx, DIVERGING_SUB_EXPRESSION, e.span, "sub-expression diverges"); } @@ -136,6 +137,15 @@ impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> { fn visit_expr(&mut self, e: &'tcx Expr<'_>) { match e.kind { + // fix #10776 + ExprKind::Block(block, ..) => match (block.stmts, block.expr) { + ([], Some(e)) => self.visit_expr(e), + ([stmt], None) => match stmt.kind { + StmtKind::Expr(e) | StmtKind::Semi(e) => self.visit_expr(e), + _ => {}, + }, + _ => {}, + }, ExprKind::Continue(_) | ExprKind::Break(_, _) | ExprKind::Ret(_) => self.report_diverging_sub_expr(e), ExprKind::Call(func, _) => { let typ = self.cx.typeck_results().expr_ty(func); diff --git a/clippy_lints/src/module_style.rs b/clippy_lints/src/module_style.rs index 349fcd2274d3..439cae812b7f 100644 --- a/clippy_lints/src/module_style.rs +++ b/clippy_lints/src/module_style.rs @@ -2,6 +2,7 @@ use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_lint::{EarlyContext, EarlyLintPass, Level, LintContext}; use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::def_id::LOCAL_CRATE; use rustc_span::{FileName, SourceFile, Span, SyntaxContext}; use std::ffi::OsStr; use std::path::{Component, Path}; @@ -90,7 +91,14 @@ impl EarlyLintPass for ModStyle { // `{ foo => path/to/foo.rs, .. } let mut file_map = FxHashMap::default(); for file in files.iter() { - if let FileName::Real(name) = &file.name && let Some(lp) = name.local_path() { + if let FileName::Real(name) = &file.name + && let Some(lp) = name.local_path() + && file.cnum == LOCAL_CRATE + { + // [#8887](https://github.com/rust-lang/rust-clippy/issues/8887) + // Only check files in the current crate. + // Fix false positive that crate dependency in workspace sub directory + // is checked unintentionally. let path = if lp.is_relative() { lp } else if let Ok(relative) = lp.strip_prefix(trim_to_src) { diff --git a/clippy_lints/src/needless_if.rs b/clippy_lints/src/needless_if.rs new file mode 100644 index 000000000000..ad5c3e1dc822 --- /dev/null +++ b/clippy_lints/src/needless_if.rs @@ -0,0 +1,75 @@ +use clippy_utils::{diagnostics::span_lint_and_sugg, higher::If, is_from_proc_macro, source::snippet_opt}; +use rustc_errors::Applicability; +use rustc_hir::{ExprKind, Stmt, StmtKind}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for empty `if` branches with no else branch. + /// + /// ### Why is this bad? + /// It can be entirely omitted, and often the condition too. + /// + /// ### Known issues + /// This will usually only suggest to remove the `if` statement, not the condition. Other lints + /// such as `no_effect` will take care of removing the condition if it's unnecessary. + /// + /// ### Example + /// ```rust,ignore + /// if really_expensive_condition(&i) {} + /// if really_expensive_condition_with_side_effects(&mut i) {} + /// ``` + /// Use instead: + /// ```rust,ignore + /// // + /// really_expensive_condition_with_side_effects(&mut i); + /// ``` + #[clippy::version = "1.72.0"] + pub NEEDLESS_IF, + complexity, + "checks for empty if branches" +} +declare_lint_pass!(NeedlessIf => [NEEDLESS_IF]); + +impl LateLintPass<'_> for NeedlessIf { + fn check_stmt<'tcx>(&mut self, cx: &LateContext<'tcx>, stmt: &Stmt<'tcx>) { + if let StmtKind::Expr(expr) = stmt.kind + && let Some(If {cond, then, r#else: None }) = If::hir(expr) + && let ExprKind::Block(block, ..) = then.kind + && block.stmts.is_empty() + && block.expr.is_none() + && !in_external_macro(cx.sess(), expr.span) + && !is_from_proc_macro(cx, expr) + && let Some(then_snippet) = snippet_opt(cx, then.span) + // Ignore + // - empty macro expansions + // - empty reptitions in macro expansions + // - comments + // - #[cfg]'d out code + && then_snippet.chars().all(|ch| matches!(ch, '{' | '}') || ch.is_ascii_whitespace()) + && let Some(cond_snippet) = snippet_opt(cx, cond.span) + { + span_lint_and_sugg( + cx, + NEEDLESS_IF, + stmt.span, + "this `if` branch is empty", + "you can remove it", + if cond.can_have_side_effects() || !cx.tcx.hir().attrs(stmt.hir_id).is_empty() { + // `{ foo }` or `{ foo } && bar` placed into a statement position would be + // interpreted as a block statement, force it to be an expression + if cond_snippet.starts_with('{') { + format!("({cond_snippet});") + } else { + format!("{cond_snippet};") + } + } else { + String::new() + }, + Applicability::MachineApplicable, + ); + } + } +} diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index c0970048cdfe..ece10474715f 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -7,13 +7,12 @@ use clippy_utils::ty::{ use clippy_utils::{get_trait_def_id, is_self, paths}; use if_chain::if_chain; use rustc_ast::ast::Attribute; -use rustc_data_structures::fx::FxHashSet; use rustc_errors::{Applicability, Diagnostic}; use rustc_hir::intravisit::FnKind; use rustc_hir::{ BindingAnnotation, Body, FnDecl, GenericArg, HirId, Impl, ItemKind, Mutability, Node, PatKind, QPath, TyKind, }; -use rustc_hir::{HirIdMap, HirIdSet, LangItem}; +use rustc_hir::{HirIdSet, LangItem}; use rustc_hir_typeck::expr_use_visitor as euv; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; @@ -126,9 +125,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { .filter_map(|pred| { // Note that we do not want to deal with qualified predicates here. match pred.kind().no_bound_vars() { - Some(ty::ClauseKind::Trait(pred)) if pred.def_id() != sized_trait => { - Some(pred) - }, + Some(ty::ClauseKind::Trait(pred)) if pred.def_id() != sized_trait => Some(pred), _ => None, } }) @@ -136,11 +133,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { // Collect moved variables and spans which will need dereferencings from the // function body. - let MovedVariablesCtxt { - moved_vars, - spans_need_deref, - .. - } = { + let MovedVariablesCtxt { moved_vars } = { let mut ctx = MovedVariablesCtxt::default(); let infcx = cx.tcx.infer_ctxt().build(); euv::ExprUseVisitor::new(&mut ctx, &infcx, fn_def_id, cx.param_env, cx.typeck_results()).consume_body(body); @@ -211,7 +204,6 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { } } - let deref_span = spans_need_deref.get(&canonical_id); if_chain! { if is_type_diagnostic_item(cx, ty, sym::Vec); if let Some(clone_spans) = @@ -247,7 +239,6 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { } // cannot be destructured, no need for `*` suggestion - assert!(deref_span.is_none()); return; } } @@ -275,23 +266,12 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { ); } - assert!(deref_span.is_none()); return; } } - let mut spans = vec![(input.span, format!("&{}", snippet(cx, input.span, "_")))]; + let spans = vec![(input.span, format!("&{}", snippet(cx, input.span, "_")))]; - // Suggests adding `*` to dereference the added reference. - if let Some(deref_span) = deref_span { - spans.extend( - deref_span - .iter() - .copied() - .map(|span| (span, format!("*{}", snippet(cx, span, "")))), - ); - spans.sort_by_key(|&(span, _)| span); - } multispan_sugg(diag, "consider taking a reference instead", spans); }; @@ -320,9 +300,6 @@ fn requires_exact_signature(attrs: &[Attribute]) -> bool { #[derive(Default)] struct MovedVariablesCtxt { moved_vars: HirIdSet, - /// Spans which need to be prefixed with `*` for dereferencing the - /// suggested additional reference. - spans_need_deref: HirIdMap>, } impl MovedVariablesCtxt { diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index e3712190e672..a4c7da7e48db 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -1,11 +1,16 @@ use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; -use clippy_utils::is_lint_allowed; use clippy_utils::peel_blocks; use clippy_utils::source::snippet_opt; use clippy_utils::ty::has_drop; +use clippy_utils::{get_parent_node, is_lint_allowed}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{is_range_literal, BinOpKind, BlockCheckMode, Expr, ExprKind, PatKind, Stmt, StmtKind, UnsafeSource}; +use rustc_hir::{ + is_range_literal, BinOpKind, BlockCheckMode, Expr, ExprKind, FnRetTy, ItemKind, Node, PatKind, Stmt, StmtKind, + UnsafeSource, +}; +use rustc_hir_analysis::hir_ty_to_ty; +use rustc_infer::infer::TyCtxtInferExt as _; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -86,7 +91,43 @@ impl<'tcx> LateLintPass<'tcx> for NoEffect { fn check_no_effect(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool { if let StmtKind::Semi(expr) = stmt.kind { if has_no_effect(cx, expr) { - span_lint_hir(cx, NO_EFFECT, expr.hir_id, stmt.span, "statement with no effect"); + span_lint_hir_and_then( + cx, + NO_EFFECT, + expr.hir_id, + stmt.span, + "statement with no effect", + |diag| { + for parent in cx.tcx.hir().parent_iter(stmt.hir_id) { + if let Node::Item(item) = parent.1 + && let ItemKind::Fn(sig, ..) = item.kind + && let FnRetTy::Return(ret_ty) = sig.decl.output + && let Some(Node::Block(block)) = get_parent_node(cx.tcx, stmt.hir_id) + && let [.., final_stmt] = block.stmts + && final_stmt.hir_id == stmt.hir_id + { + let expr_ty = cx.typeck_results().expr_ty(expr); + let mut ret_ty = hir_ty_to_ty(cx.tcx, ret_ty); + + // Remove `impl Future` to get `T` + if cx.tcx.ty_is_opaque_future(ret_ty) && + let Some(true_ret_ty) = cx.tcx.infer_ctxt().build().get_impl_future_output_ty(ret_ty) + { + ret_ty = true_ret_ty; + } + + if ret_ty == expr_ty { + diag.span_suggestion( + stmt.span.shrink_to_lo(), + "did you mean to return it?", + "return ", + Applicability::MaybeIncorrect, + ); + } + } + } + }, + ); return true; } } else if let StmtKind::Local(local) = stmt.kind { diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index ac49ccdb5011..75f1e95276a6 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -182,15 +182,15 @@ fn is_value_unfrozen_raw<'tcx>( // have a value that is a frozen variant with a generic param (an example is // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::GENERIC_VARIANT`). // However, it prevents a number of false negatives that is, I think, important: - // 1. assoc consts in trait defs referring to consts of themselves - // (an example is `declare_interior_mutable_const::traits::ConcreteTypes::ANOTHER_ATOMIC`). - // 2. a path expr referring to assoc consts whose type is doesn't have - // any frozen variants in trait defs (i.e. without substitute for `Self`). - // (e.g. borrowing `borrow_interior_mutable_const::trait::ConcreteTypes::ATOMIC`) - // 3. similar to the false positive above; - // but the value is an unfrozen variant, or the type has no enums. (An example is - // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::UNFROZEN_VARIANT` - // and `declare_interior_mutable_const::enums::BothOfCellAndGeneric::NO_ENUM`). + // 1. assoc consts in trait defs referring to consts of themselves (an example is + // `declare_interior_mutable_const::traits::ConcreteTypes::ANOTHER_ATOMIC`). + // 2. a path expr referring to assoc consts whose type is doesn't have any frozen variants in trait + // defs (i.e. without substitute for `Self`). (e.g. borrowing + // `borrow_interior_mutable_const::trait::ConcreteTypes::ATOMIC`) + // 3. similar to the false positive above; but the value is an unfrozen variant, or the type has no + // enums. (An example is + // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::UNFROZEN_VARIANT` and + // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::NO_ENUM`). // One might be able to prevent these FNs correctly, and replace this with `false`; // e.g. implementing `has_frozen_variant` described above, and not running this function // when the type doesn't have any frozen variants would be the 'correct' way for the 2nd diff --git a/clippy_lints/src/operators/eq_op.rs b/clippy_lints/src/operators/eq_op.rs index 67913f7392c0..78965b7d6f74 100644 --- a/clippy_lints/src/operators/eq_op.rs +++ b/clippy_lints/src/operators/eq_op.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint; +use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::macros::{find_assert_eq_args, first_node_macro_backtrace}; use clippy_utils::{ast_utils::is_useless_with_eq_exprs, eq_expr_value, is_in_test_function}; use rustc_hir::{BinOpKind, Expr}; @@ -35,11 +35,16 @@ pub(crate) fn check<'tcx>( right: &'tcx Expr<'_>, ) { if is_useless_with_eq_exprs(op.into()) && eq_expr_value(cx, left, right) && !is_in_test_function(cx.tcx, e.hir_id) { - span_lint( + span_lint_and_then( cx, EQ_OP, e.span, &format!("equal expressions as operands to `{}`", op.as_str()), + |diag| { + if let BinOpKind::Ne = op && cx.typeck_results().expr_ty(left).is_floating_point() { + diag.note("if you intended to check if the operand is NaN, use `.is_nan()` instead"); + } + }, ); } } diff --git a/clippy_lints/src/operators/float_cmp.rs b/clippy_lints/src/operators/float_cmp.rs index 15dff126be76..f3e0c58a7871 100644 --- a/clippy_lints/src/operators/float_cmp.rs +++ b/clippy_lints/src/operators/float_cmp.rs @@ -85,7 +85,7 @@ fn get_lint_and_message(is_local: bool, is_comparing_arrays: bool) -> (&'static } } -fn is_allowed(val: &Constant) -> bool { +fn is_allowed(val: &Constant<'_>) -> bool { match val { &Constant::F32(f) => f == 0.0 || f.is_infinite(), &Constant::F64(f) => f == 0.0 || f.is_infinite(), diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index aa6d40042688..abdccc47f547 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -140,6 +140,9 @@ fn try_get_option_occurrence<'tcx>( let (as_ref, as_mut) = match &expr.kind { ExprKind::AddrOf(_, Mutability::Not, _) => (true, false), ExprKind::AddrOf(_, Mutability::Mut, _) => (false, true), + _ if let Some(mutb) = cx.typeck_results().expr_ty(expr).ref_mutability() => { + (mutb == Mutability::Not, mutb == Mutability::Mut) + } _ => (bind_annotation == BindingAnnotation::REF, bind_annotation == BindingAnnotation::REF_MUT), }; diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index b8911f109076..866a04466c90 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -5,6 +5,7 @@ use clippy_utils::source::snippet_opt; use clippy_utils::ty::expr_sig; use clippy_utils::visitors::contains_unsafe_block; use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local, paths}; +use hir::LifetimeName; use if_chain::if_chain; use rustc_errors::{Applicability, MultiSpan}; use rustc_hir::def_id::DefId; @@ -15,6 +16,7 @@ use rustc_hir::{ ImplItemKind, ItemKind, Lifetime, Mutability, Node, Param, PatKind, QPath, TraitFn, TraitItem, TraitItemKind, TyKind, Unsafety, }; +use rustc_hir_analysis::hir_ty_to_ty; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::{Obligation, ObligationCause}; use rustc_lint::{LateContext, LateLintPass}; @@ -166,6 +168,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr { cx, cx.tcx.fn_sig(item.owner_id).subst_identity().skip_binder().inputs(), sig.decl.inputs, + &sig.decl.output, &[], ) .filter(|arg| arg.mutability() == Mutability::Not) @@ -218,7 +221,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr { check_mut_from_ref(cx, sig, Some(body)); let decl = sig.decl; let sig = cx.tcx.fn_sig(item_id).subst_identity().skip_binder(); - let lint_args: Vec<_> = check_fn_args(cx, sig.inputs(), decl.inputs, body.params) + let lint_args: Vec<_> = check_fn_args(cx, sig.inputs(), decl.inputs, &decl.output, body.params) .filter(|arg| !is_trait_item || arg.mutability() == Mutability::Not) .collect(); let results = check_ptr_arg_usage(cx, body, &lint_args); @@ -407,29 +410,27 @@ impl<'tcx> DerefTy<'tcx> { } } +#[expect(clippy::too_many_lines)] fn check_fn_args<'cx, 'tcx: 'cx>( cx: &'cx LateContext<'tcx>, tys: &'tcx [Ty<'tcx>], hir_tys: &'tcx [hir::Ty<'tcx>], + ret_ty: &'tcx FnRetTy<'tcx>, params: &'tcx [Param<'tcx>], ) -> impl Iterator> + 'cx { tys.iter() .zip(hir_tys.iter()) .enumerate() - .filter_map(|(i, (ty, hir_ty))| { - if_chain! { - if let ty::Ref(_, ty, mutability) = *ty.kind(); - if let ty::Adt(adt, substs) = *ty.kind(); - - if let TyKind::Ref(lt, ref ty) = hir_ty.kind; - if let TyKind::Path(QPath::Resolved(None, path)) = ty.ty.kind; - + .filter_map(move |(i, (ty, hir_ty))| { + if let ty::Ref(_, ty, mutability) = *ty.kind() + && let ty::Adt(adt, substs) = *ty.kind() + && let TyKind::Ref(lt, ref ty) = hir_ty.kind + && let TyKind::Path(QPath::Resolved(None, path)) = ty.ty.kind // Check that the name as typed matches the actual name of the type. // e.g. `fn foo(_: &Foo)` shouldn't trigger the lint when `Foo` is an alias for `Vec` - if let [.., name] = path.segments; - if cx.tcx.item_name(adt.did()) == name.ident.name; - - then { + && let [.., name] = path.segments + && cx.tcx.item_name(adt.did()) == name.ident.name + { let emission_id = params.get(i).map_or(hir_ty.hir_id, |param| param.hir_id); let (method_renames, deref_ty) = match cx.tcx.get_diagnostic_name(adt.did()) { Some(sym::Vec) => ( @@ -454,30 +455,65 @@ fn check_fn_args<'cx, 'tcx: 'cx>( DerefTy::Path, ), Some(sym::Cow) if mutability == Mutability::Not => { - let ty_name = name.args + if let Some((lifetime, ty)) = name.args .and_then(|args| { - args.args.iter().find_map(|a| match a { - GenericArg::Type(x) => Some(x), - _ => None, - }) + if let [GenericArg::Lifetime(lifetime), ty] = args.args { + return Some((lifetime, ty)); + } + None }) - .and_then(|arg| snippet_opt(cx, arg.span)) - .unwrap_or_else(|| substs.type_at(1).to_string()); - span_lint_hir_and_then( - cx, - PTR_ARG, - emission_id, - hir_ty.span, - "using a reference to `Cow` is not recommended", - |diag| { - diag.span_suggestion( - hir_ty.span, - "change this to", - format!("&{}{ty_name}", mutability.prefix_str()), - Applicability::Unspecified, - ); + { + if !lifetime.is_anonymous() + && let FnRetTy::Return(ret_ty) = ret_ty + && let ret_ty = hir_ty_to_ty(cx.tcx, ret_ty) + && ret_ty + .walk() + .filter_map(|arg| { + arg.as_region().and_then(|lifetime| { + match lifetime.kind() { + ty::ReEarlyBound(r) => Some(r.def_id), + ty::ReLateBound(_, r) => r.kind.get_id(), + ty::ReFree(r) => r.bound_region.get_id(), + ty::ReStatic + | ty::ReVar(_) + | ty::RePlaceholder(_) + | ty::ReErased + | ty::ReError(_) => None, + } + }) + }) + .any(|def_id| { + matches!( + lifetime.res, + LifetimeName::Param(param_def_id) if def_id + .as_local() + .is_some_and(|def_id| def_id == param_def_id), + ) + }) + { + // `&Cow<'a, T>` when the return type uses 'a is okay + return None; } - ); + + let ty_name = + snippet_opt(cx, ty.span()).unwrap_or_else(|| substs.type_at(1).to_string()); + + span_lint_hir_and_then( + cx, + PTR_ARG, + emission_id, + hir_ty.span, + "using a reference to `Cow` is not recommended", + |diag| { + diag.span_suggestion( + hir_ty.span, + "change this to", + format!("&{}{ty_name}", mutability.prefix_str()), + Applicability::Unspecified, + ); + } + ); + } return None; }, _ => return None, @@ -495,7 +531,6 @@ fn check_fn_args<'cx, 'tcx: 'cx>( }, deref_ty, }); - } } None }) diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index 5269bbd1f1ac..e3d940ad2a44 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -1,19 +1,20 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::higher; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{ eq_expr_value, get_parent_node, in_constant, is_else_clause, is_res_lang_ctor, path_to_local, path_to_local_id, peel_blocks, peel_blocks_with_stmt, }; +use clippy_utils::{higher, is_path_lang_item}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def::Res; -use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; +use rustc_hir::LangItem::{self, OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::{BindingAnnotation, ByRef, Expr, ExprKind, Node, PatKind, PathSegment, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::declare_tool_lint; +use rustc_session::impl_lint_pass; use rustc_span::{sym, symbol::Symbol}; declare_clippy_lint! { @@ -41,7 +42,16 @@ declare_clippy_lint! { "checks for expressions that could be replaced by the question mark operator" } -declare_lint_pass!(QuestionMark => [QUESTION_MARK]); +#[derive(Default)] +pub struct QuestionMark { + /// Keeps track of how many try blocks we are in at any point during linting. + /// This allows us to answer the question "are we inside of a try block" + /// very quickly, without having to walk up the parent chain, by simply checking + /// if it is greater than zero. + /// As for why we need this in the first place: + try_block_depth_stack: Vec, +} +impl_lint_pass!(QuestionMark => [QUESTION_MARK]); enum IfBlockType<'hir> { /// An `if x.is_xxx() { a } else { b } ` expression. @@ -68,98 +78,6 @@ enum IfBlockType<'hir> { ), } -/// Checks if the given expression on the given context matches the following structure: -/// -/// ```ignore -/// if option.is_none() { -/// return None; -/// } -/// ``` -/// -/// ```ignore -/// if result.is_err() { -/// return result; -/// } -/// ``` -/// -/// If it matches, it will suggest to use the question mark operator instead -fn check_is_none_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { - if_chain! { - if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr); - if !is_else_clause(cx.tcx, expr); - if let ExprKind::MethodCall(segment, caller, ..) = &cond.kind; - let caller_ty = cx.typeck_results().expr_ty(caller); - let if_block = IfBlockType::IfIs(caller, caller_ty, segment.ident.name, then, r#else); - if is_early_return(sym::Option, cx, &if_block) || is_early_return(sym::Result, cx, &if_block); - then { - let mut applicability = Applicability::MachineApplicable; - let receiver_str = snippet_with_applicability(cx, caller.span, "..", &mut applicability); - let by_ref = !caller_ty.is_copy_modulo_regions(cx.tcx, cx.param_env) && - !matches!(caller.kind, ExprKind::Call(..) | ExprKind::MethodCall(..)); - let sugg = if let Some(else_inner) = r#else { - if eq_expr_value(cx, caller, peel_blocks(else_inner)) { - format!("Some({receiver_str}?)") - } else { - return; - } - } else { - format!("{receiver_str}{}?;", if by_ref { ".as_ref()" } else { "" }) - }; - - span_lint_and_sugg( - cx, - QUESTION_MARK, - expr.span, - "this block may be rewritten with the `?` operator", - "replace it with", - sugg, - applicability, - ); - } - } -} - -fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { - if_chain! { - if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else }) = higher::IfLet::hir(cx, expr); - if !is_else_clause(cx.tcx, expr); - if let PatKind::TupleStruct(ref path1, [field], ddpos) = let_pat.kind; - if ddpos.as_opt_usize().is_none(); - if let PatKind::Binding(BindingAnnotation(by_ref, _), bind_id, ident, None) = field.kind; - let caller_ty = cx.typeck_results().expr_ty(let_expr); - let if_block = IfBlockType::IfLet( - cx.qpath_res(path1, let_pat.hir_id), - caller_ty, - ident.name, - let_expr, - if_then, - if_else - ); - if (is_early_return(sym::Option, cx, &if_block) && path_to_local_id(peel_blocks(if_then), bind_id)) - || is_early_return(sym::Result, cx, &if_block); - if if_else.map(|e| eq_expr_value(cx, let_expr, peel_blocks(e))).filter(|e| *e).is_none(); - then { - let mut applicability = Applicability::MachineApplicable; - let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability); - let requires_semi = matches!(get_parent_node(cx.tcx, expr.hir_id), Some(Node::Stmt(_))); - let sugg = format!( - "{receiver_str}{}?{}", - if by_ref == ByRef::Yes { ".as_ref()" } else { "" }, - if requires_semi { ";" } else { "" } - ); - span_lint_and_sugg( - cx, - QUESTION_MARK, - expr.span, - "this block may be rewritten with the `?` operator", - "replace it with", - sugg, - applicability, - ); - } - } -} - fn is_early_return(smbl: Symbol, cx: &LateContext<'_>, if_block: &IfBlockType<'_>) -> bool { match *if_block { IfBlockType::IfIs(caller, caller_ty, call_sym, if_then, _) => { @@ -230,11 +148,147 @@ fn expr_return_none_or_err( } } -impl<'tcx> LateLintPass<'tcx> for QuestionMark { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if !in_constant(cx, expr.hir_id) { - check_is_none_or_err_and_early_return(cx, expr); - check_if_let_some_or_err_and_early_return(cx, expr); +impl QuestionMark { + fn inside_try_block(&self) -> bool { + self.try_block_depth_stack.last() > Some(&0) + } + + /// Checks if the given expression on the given context matches the following structure: + /// + /// ```ignore + /// if option.is_none() { + /// return None; + /// } + /// ``` + /// + /// ```ignore + /// if result.is_err() { + /// return result; + /// } + /// ``` + /// + /// If it matches, it will suggest to use the question mark operator instead + fn check_is_none_or_err_and_early_return<'tcx>(&self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { + if_chain! { + if !self.inside_try_block(); + if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr); + if !is_else_clause(cx.tcx, expr); + if let ExprKind::MethodCall(segment, caller, ..) = &cond.kind; + let caller_ty = cx.typeck_results().expr_ty(caller); + let if_block = IfBlockType::IfIs(caller, caller_ty, segment.ident.name, then, r#else); + if is_early_return(sym::Option, cx, &if_block) || is_early_return(sym::Result, cx, &if_block); + then { + let mut applicability = Applicability::MachineApplicable; + let receiver_str = snippet_with_applicability(cx, caller.span, "..", &mut applicability); + let by_ref = !caller_ty.is_copy_modulo_regions(cx.tcx, cx.param_env) && + !matches!(caller.kind, ExprKind::Call(..) | ExprKind::MethodCall(..)); + let sugg = if let Some(else_inner) = r#else { + if eq_expr_value(cx, caller, peel_blocks(else_inner)) { + format!("Some({receiver_str}?)") + } else { + return; + } + } else { + format!("{receiver_str}{}?;", if by_ref { ".as_ref()" } else { "" }) + }; + + span_lint_and_sugg( + cx, + QUESTION_MARK, + expr.span, + "this block may be rewritten with the `?` operator", + "replace it with", + sugg, + applicability, + ); + } + } + } + + fn check_if_let_some_or_err_and_early_return<'tcx>(&self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { + if_chain! { + if !self.inside_try_block(); + if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else }) = higher::IfLet::hir(cx, expr); + if !is_else_clause(cx.tcx, expr); + if let PatKind::TupleStruct(ref path1, [field], ddpos) = let_pat.kind; + if ddpos.as_opt_usize().is_none(); + if let PatKind::Binding(BindingAnnotation(by_ref, _), bind_id, ident, None) = field.kind; + let caller_ty = cx.typeck_results().expr_ty(let_expr); + let if_block = IfBlockType::IfLet( + cx.qpath_res(path1, let_pat.hir_id), + caller_ty, + ident.name, + let_expr, + if_then, + if_else + ); + if (is_early_return(sym::Option, cx, &if_block) && path_to_local_id(peel_blocks(if_then), bind_id)) + || is_early_return(sym::Result, cx, &if_block); + if if_else.map(|e| eq_expr_value(cx, let_expr, peel_blocks(e))).filter(|e| *e).is_none(); + then { + let mut applicability = Applicability::MachineApplicable; + let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability); + let requires_semi = matches!(get_parent_node(cx.tcx, expr.hir_id), Some(Node::Stmt(_))); + let sugg = format!( + "{receiver_str}{}?{}", + if by_ref == ByRef::Yes { ".as_ref()" } else { "" }, + if requires_semi { ";" } else { "" } + ); + span_lint_and_sugg( + cx, + QUESTION_MARK, + expr.span, + "this block may be rewritten with the `?` operator", + "replace it with", + sugg, + applicability, + ); + } + } + } +} + +fn is_try_block(cx: &LateContext<'_>, bl: &rustc_hir::Block<'_>) -> bool { + if let Some(expr) = bl.expr + && let rustc_hir::ExprKind::Call(callee, _) = expr.kind + { + is_path_lang_item(cx, callee, LangItem::TryTraitFromOutput) + } else { + false + } +} + +impl<'tcx> LateLintPass<'tcx> for QuestionMark { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if !in_constant(cx, expr.hir_id) { + self.check_is_none_or_err_and_early_return(cx, expr); + self.check_if_let_some_or_err_and_early_return(cx, expr); + } + } + + fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx rustc_hir::Block<'tcx>) { + if is_try_block(cx, block) { + *self + .try_block_depth_stack + .last_mut() + .expect("blocks are always part of bodies and must have a depth") += 1; + } + } + + fn check_body(&mut self, _: &LateContext<'tcx>, _: &'tcx rustc_hir::Body<'tcx>) { + self.try_block_depth_stack.push(0); + } + + fn check_body_post(&mut self, _: &LateContext<'tcx>, _: &'tcx rustc_hir::Body<'tcx>) { + self.try_block_depth_stack.pop(); + } + + fn check_block_post(&mut self, cx: &LateContext<'tcx>, block: &'tcx rustc_hir::Block<'tcx>) { + if is_try_block(cx, block) { + *self + .try_block_depth_stack + .last_mut() + .expect("blocks are always part of bodies and must have a depth") -= 1; } } } diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index dd7ded491e79..d2018aba9e3d 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -296,8 +296,8 @@ fn check_possible_range_contains( } } -struct RangeBounds<'a> { - val: Constant, +struct RangeBounds<'a, 'tcx> { + val: Constant<'tcx>, expr: &'a Expr<'a>, id: HirId, name_span: Span, @@ -309,7 +309,7 @@ struct RangeBounds<'a> { // Takes a binary expression such as x <= 2 as input // Breaks apart into various pieces, such as the value of the number, // hir id of the variable, and direction/inclusiveness of the operator -fn check_range_bounds<'a>(cx: &'a LateContext<'_>, ex: &'a Expr<'_>) -> Option> { +fn check_range_bounds<'a, 'tcx>(cx: &'a LateContext<'tcx>, ex: &'a Expr<'_>) -> Option> { if let ExprKind::Binary(ref op, l, r) = ex.kind { let (inclusive, ordering) = match op.node { BinOpKind::Gt => (false, Ordering::Greater), diff --git a/clippy_lints/src/raw_strings.rs b/clippy_lints/src/raw_strings.rs new file mode 100644 index 000000000000..f45bb1ef3e1f --- /dev/null +++ b/clippy_lints/src/raw_strings.rs @@ -0,0 +1,143 @@ +use std::{iter::once, ops::ControlFlow}; + +use clippy_utils::{diagnostics::span_lint_and_sugg, source::snippet}; +use rustc_ast::{ + ast::{Expr, ExprKind}, + token::LitKind, +}; +use rustc_errors::Applicability; +use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_session::{declare_tool_lint, impl_lint_pass}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for raw string literals where a string literal can be used instead. + /// + /// ### Why is this bad? + /// It's just unnecessary, but there are many cases where using a raw string literal is more + /// idiomatic than a string literal, so it's opt-in. + /// + /// ### Example + /// ```rust + /// let r = r"Hello, world!"; + /// ``` + /// Use instead: + /// ```rust + /// let r = "Hello, world!"; + /// ``` + #[clippy::version = "1.72.0"] + pub NEEDLESS_RAW_STRINGS, + restriction, + "suggests using a string literal when a raw string literal is unnecessary" +} +declare_clippy_lint! { + /// ### What it does + /// Checks for raw string literals with an unnecessary amount of hashes around them. + /// + /// ### Why is this bad? + /// It's just unnecessary, and makes it look like there's more escaping needed than is actually + /// necessary. + /// + /// ### Example + /// ```rust + /// let r = r###"Hello, "world"!"###; + /// ``` + /// Use instead: + /// ```rust + /// let r = r#"Hello, "world"!"#; + /// ``` + #[clippy::version = "1.72.0"] + pub NEEDLESS_RAW_STRING_HASHES, + style, + "suggests reducing the number of hashes around a raw string literal" +} +impl_lint_pass!(RawStrings => [NEEDLESS_RAW_STRINGS, NEEDLESS_RAW_STRING_HASHES]); + +pub struct RawStrings { + pub needless_raw_string_hashes_allow_one: bool, +} + +impl EarlyLintPass for RawStrings { + fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { + if !in_external_macro(cx.sess(), expr.span) + && let ExprKind::Lit(lit) = expr.kind + && let LitKind::StrRaw(max) | LitKind::ByteStrRaw(max) | LitKind::CStrRaw(max) = lit.kind + { + let str = lit.symbol.as_str(); + let prefix = match lit.kind { + LitKind::StrRaw(..) => "r", + LitKind::ByteStrRaw(..) => "br", + LitKind::CStrRaw(..) => "cr", + _ => unreachable!(), + }; + if !snippet(cx, expr.span, prefix).trim().starts_with(prefix) { + return; + } + + if !str.contains(['\\', '"']) { + span_lint_and_sugg( + cx, + NEEDLESS_RAW_STRINGS, + expr.span, + "unnecessary raw string literal", + "try", + format!("{}\"{}\"", prefix.replace('r', ""), lit.symbol), + Applicability::MachineApplicable, + ); + + return; + } + + let req = { + let mut following_quote = false; + let mut req = 0; + // `once` so a raw string ending in hashes is still checked + let num = str.as_bytes().iter().chain(once(&0)).try_fold(0u8, |acc, &b| { + match b { + b'"' => (following_quote, req) = (true, 1), + // I'm a bit surprised the compiler didn't optimize this out, there's no + // branch but it still ends up doing an unnecessary comparison, it's: + // - cmp r9b,1h + // - sbb cl,-1h + // which will add 1 if it's true. With this change, it becomes: + // - add cl,r9b + // isn't that so much nicer? + b'#' => req += u8::from(following_quote), + _ => { + if following_quote { + following_quote = false; + + if req == max { + return ControlFlow::Break(req); + } + + return ControlFlow::Continue(acc.max(req)); + } + }, + } + + ControlFlow::Continue(acc) + }); + + match num { + ControlFlow::Continue(num) | ControlFlow::Break(num) => num, + } + }; + + if req < max { + let hashes = "#".repeat(req as usize); + + span_lint_and_sugg( + cx, + NEEDLESS_RAW_STRING_HASHES, + expr.span, + "unnecessary hashes around raw string literal", + "try", + format!(r#"{prefix}{hashes}"{}"{hashes}"#, lit.symbol), + Applicability::MachineApplicable, + ); + } + } + } +} diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index 944a33cc3e53..e36adef555e6 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -57,7 +57,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.32.0"] pub REDUNDANT_CLONE, - perf, + nursery, "`clone()` of an owned value that is going to be dropped immediately" } @@ -320,8 +320,6 @@ fn base_local_and_movability<'tcx>( mir: &mir::Body<'tcx>, place: mir::Place<'tcx>, ) -> (mir::Local, CannotMoveOut) { - use rustc_middle::mir::PlaceRef; - // Dereference. You cannot move things out from a borrowed value. let mut deref = false; // Accessing a field of an ADT that has `Drop`. Moving the field out will cause E0509. @@ -330,17 +328,14 @@ fn base_local_and_movability<'tcx>( // underlying type implements Copy let mut slice = false; - let PlaceRef { local, mut projection } = place.as_ref(); - while let [base @ .., elem] = projection { - projection = base; + for (base, elem) in place.as_ref().iter_projections() { + let base_ty = base.ty(&mir.local_decls, cx.tcx).ty; deref |= matches!(elem, mir::ProjectionElem::Deref); - field |= matches!(elem, mir::ProjectionElem::Field(..)) - && has_drop(cx, mir::Place::ty_from(local, projection, &mir.local_decls, cx.tcx).ty); - slice |= matches!(elem, mir::ProjectionElem::Index(..)) - && !is_copy(cx, mir::Place::ty_from(local, projection, &mir.local_decls, cx.tcx).ty); + field |= matches!(elem, mir::ProjectionElem::Field(..)) && has_drop(cx, base_ty); + slice |= matches!(elem, mir::ProjectionElem::Index(..)) && !is_copy(cx, base_ty); } - (local, deref || field || slice) + (place.local, deref || field || slice) } #[derive(Default)] diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index 2a42e73488f1..b6ce4ebc28f2 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -1,14 +1,14 @@ +use crate::rustc_lint::LintContext; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; +use clippy_utils::get_parent_expr; use clippy_utils::sugg::Sugg; use if_chain::if_chain; -use rustc_ast::ast; -use rustc_ast::visit as ast_visit; -use rustc_ast::visit::Visitor as AstVisitor; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit as hir_visit; use rustc_hir::intravisit::Visitor as HirVisitor; -use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; +use rustc_hir::intravisit::Visitor; +use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -51,59 +51,136 @@ impl ReturnVisitor { } } -impl<'ast> ast_visit::Visitor<'ast> for ReturnVisitor { - fn visit_expr(&mut self, ex: &'ast ast::Expr) { - if let ast::ExprKind::Ret(_) | ast::ExprKind::Try(_) = ex.kind { +impl<'tcx> Visitor<'tcx> for ReturnVisitor { + fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) { + if let hir::ExprKind::Ret(_) | hir::ExprKind::Match(.., hir::MatchSource::TryDesugar) = ex.kind { self.found_return = true; + } else { + hir_visit::walk_expr(self, ex); } - - ast_visit::walk_expr(self, ex); } } -impl EarlyLintPass for RedundantClosureCall { - fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) { - if in_external_macro(cx.sess(), expr.span) { - return; - } - if_chain! { - if let ast::ExprKind::Call(ref paren, _) = expr.kind; - if let ast::ExprKind::Paren(ref closure) = paren.kind; - if let ast::ExprKind::Closure(box ast::Closure { ref asyncness, ref fn_decl, ref body, .. }) = closure.kind; - then { - let mut visitor = ReturnVisitor::new(); - visitor.visit_expr(body); - if !visitor.found_return { - span_lint_and_then( - cx, - REDUNDANT_CLOSURE_CALL, - expr.span, - "try not to call a closure in the expression where it is declared", - |diag| { - if fn_decl.inputs.is_empty() { - let mut app = Applicability::MachineApplicable; - let mut hint = Sugg::ast(cx, body, "..", closure.span.ctxt(), &mut app); - - if asyncness.is_async() { - // `async x` is a syntax error, so it becomes `async { x }` - if !matches!(body.kind, ast::ExprKind::Block(_, _)) { - hint = hint.blockify(); - } - - hint = hint.asyncify(); - } - - diag.span_suggestion(expr.span, "try doing something like", hint.to_string(), app); - } - }, - ); - } - } - } +/// Checks if the body is owned by an async closure +fn is_async_closure(body: &hir::Body<'_>) -> bool { + if let hir::ExprKind::Closure(closure) = body.value.kind + && let [resume_ty] = closure.fn_decl.inputs + && let hir::TyKind::Path(hir::QPath::LangItem(hir::LangItem::ResumeTy, ..)) = resume_ty.kind + { + true + } else { + false } } +/// Tries to find the innermost closure: +/// ```rust,ignore +/// (|| || || || 42)()()()() +/// ^^^^^^^^^^^^^^ given this nested closure expression +/// ^^^^^ we want to return this closure +/// ``` +/// It also has a parameter for how many steps to go in at most, so as to +/// not take more closures than there are calls. +fn find_innermost_closure<'tcx>( + cx: &LateContext<'tcx>, + mut expr: &'tcx hir::Expr<'tcx>, + mut steps: usize, +) -> Option<(&'tcx hir::Expr<'tcx>, &'tcx hir::FnDecl<'tcx>, hir::IsAsync)> { + let mut data = None; + + while let hir::ExprKind::Closure(closure) = expr.kind + && let body = cx.tcx.hir().body(closure.body) + && { + let mut visitor = ReturnVisitor::new(); + visitor.visit_expr(body.value); + !visitor.found_return + } + && steps > 0 + { + expr = body.value; + data = Some((body.value, closure.fn_decl, if is_async_closure(body) { + hir::IsAsync::Async + } else { + hir::IsAsync::NotAsync + })); + steps -= 1; + } + + data +} + +/// "Walks up" the chain of calls to find the outermost call expression, and returns the depth: +/// ```rust,ignore +/// (|| || || 3)()()() +/// ^^ this is the call expression we were given +/// ^^ this is what we want to return (and the depth is 3) +/// ``` +fn get_parent_call_exprs<'tcx>( + cx: &LateContext<'tcx>, + mut expr: &'tcx hir::Expr<'tcx>, +) -> (&'tcx hir::Expr<'tcx>, usize) { + let mut depth = 1; + while let Some(parent) = get_parent_expr(cx, expr) + && let hir::ExprKind::Call(recv, _) = parent.kind + && expr.span == recv.span + { + expr = parent; + depth += 1; + } + (expr, depth) +} + impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { + if in_external_macro(cx.sess(), expr.span) { + return; + } + + if let hir::ExprKind::Call(recv, _) = expr.kind + // don't lint if the receiver is a call, too. + // we do this in order to prevent linting multiple times; consider: + // `(|| || 1)()()` + // ^^ we only want to lint for this call (but we walk up the calls to consider both calls). + // without this check, we'd end up linting twice. + && !matches!(recv.kind, hir::ExprKind::Call(..)) + && let (full_expr, call_depth) = get_parent_call_exprs(cx, expr) + && let Some((body, fn_decl, generator_kind)) = find_innermost_closure(cx, recv, call_depth) + { + span_lint_and_then( + cx, + REDUNDANT_CLOSURE_CALL, + full_expr.span, + "try not to call a closure in the expression where it is declared", + |diag| { + if fn_decl.inputs.is_empty() { + let mut applicability = Applicability::MachineApplicable; + let mut hint = Sugg::hir_with_context(cx, body, full_expr.span.ctxt(), "..", &mut applicability); + + if generator_kind.is_async() + && let hir::ExprKind::Closure(closure) = body.kind + { + let async_closure_body = cx.tcx.hir().body(closure.body); + + // `async x` is a syntax error, so it becomes `async { x }` + if !matches!(async_closure_body.value.kind, hir::ExprKind::Block(_, _)) { + hint = hint.blockify(); + } + + hint = hint.asyncify(); + } + + diag.span_suggestion( + full_expr.span, + "try doing something like", + hint.maybe_par(), + applicability + ); + } + } + ); + } + } + fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) { fn count_closure_usage<'tcx>( cx: &LateContext<'tcx>, diff --git a/clippy_lints/src/redundant_type_annotations.rs b/clippy_lints/src/redundant_type_annotations.rs new file mode 100644 index 000000000000..8e9234bba3c8 --- /dev/null +++ b/clippy_lints/src/redundant_type_annotations.rs @@ -0,0 +1,210 @@ +use clippy_utils::diagnostics::span_lint; +use rustc_ast::LitKind; +use rustc_hir as hir; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::Ty; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// ### What it does + /// Warns about needless / redundant type annotations. + /// + /// ### Why is this bad? + /// Code without type annotations is shorter and in most cases + /// more idiomatic and easier to modify. + /// + /// ### Limitations + /// This lint doesn't support: + /// + /// - Generics + /// - Refs returned from anything else than a `MethodCall` + /// - Complex types (tuples, arrays, etc...) + /// - `Path` to anything else than a primitive type. + /// + /// ### Example + /// ```rust + /// let foo: String = String::new(); + /// ``` + /// Use instead: + /// ```rust + /// let foo = String::new(); + /// ``` + #[clippy::version = "1.70.0"] + pub REDUNDANT_TYPE_ANNOTATIONS, + restriction, + "warns about needless / redundant type annotations." +} +declare_lint_pass!(RedundantTypeAnnotations => [REDUNDANT_TYPE_ANNOTATIONS]); + +fn is_same_type<'tcx>(cx: &LateContext<'tcx>, ty_resolved_path: hir::def::Res, func_return_type: Ty<'tcx>) -> bool { + // type annotation is primitive + if let hir::def::Res::PrimTy(primty) = ty_resolved_path + && func_return_type.is_primitive() + && let Some(func_return_type_sym) = func_return_type.primitive_symbol() + { + return primty.name() == func_return_type_sym; + } + + // type annotation is any other non generic type + if let hir::def::Res::Def(_, defid) = ty_resolved_path + && let Some(annotation_ty) = cx.tcx.type_of(defid).no_bound_vars() + { + return annotation_ty == func_return_type; + } + + false +} + +fn func_hir_id_to_func_ty<'tcx>(cx: &LateContext<'tcx>, hir_id: hir::hir_id::HirId) -> Option> { + if let Some((defkind, func_defid)) = cx.typeck_results().type_dependent_def(hir_id) + && defkind == hir::def::DefKind::AssocFn + && let Some(init_ty) = cx.tcx.type_of(func_defid).no_bound_vars() + { + Some(init_ty) + } else { + None + } +} + +fn func_ty_to_return_type<'tcx>(cx: &LateContext<'tcx>, func_ty: Ty<'tcx>) -> Option> { + if func_ty.is_fn() { + Some(func_ty.fn_sig(cx.tcx).output().skip_binder()) + } else { + None + } +} + +/// Extracts the fn Ty, e.g. `fn() -> std::string::String {f}` +fn extract_fn_ty<'tcx>( + cx: &LateContext<'tcx>, + call: &hir::Expr<'tcx>, + func_return_path: &hir::QPath<'tcx>, +) -> Option> { + match func_return_path { + // let a: String = f(); where f: fn f() -> String + hir::QPath::Resolved(_, resolved_path) => { + if let hir::def::Res::Def(_, defid) = resolved_path.res + && let Some(middle_ty_init) = cx.tcx.type_of(defid).no_bound_vars() + { + Some(middle_ty_init) + } else { + None + } + }, + // Associated functions like + // let a: String = String::new(); + // let a: String = String::get_string(); + hir::QPath::TypeRelative(..) => func_hir_id_to_func_ty(cx, call.hir_id), + hir::QPath::LangItem(..) => None, + } +} + +fn is_redundant_in_func_call<'tcx>( + cx: &LateContext<'tcx>, + ty_resolved_path: hir::def::Res, + call: &hir::Expr<'tcx>, +) -> bool { + if let hir::ExprKind::Path(init_path) = &call.kind { + let func_type = extract_fn_ty(cx, call, init_path); + + if let Some(func_type) = func_type + && let Some(init_return_type) = func_ty_to_return_type(cx, func_type) + { + return is_same_type(cx, ty_resolved_path, init_return_type); + } + } + + false +} + +fn extract_primty(ty_kind: &hir::TyKind<'_>) -> Option { + if let hir::TyKind::Path(ty_path) = ty_kind + && let hir::QPath::Resolved(_, resolved_path_ty) = ty_path + && let hir::def::Res::PrimTy(primty) = resolved_path_ty.res + { + Some(primty) + } else { + None + } +} + +impl LateLintPass<'_> for RedundantTypeAnnotations { + fn check_local<'tcx>(&mut self, cx: &LateContext<'tcx>, local: &'tcx rustc_hir::Local<'tcx>) { + // type annotation part + if !local.span.from_expansion() + && let Some(ty) = &local.ty + + // initialization part + && let Some(init) = local.init + { + match &init.kind { + // When the initialization is a call to a function + hir::ExprKind::Call(init_call, _) => { + if let hir::TyKind::Path(ty_path) = &ty.kind + && let hir::QPath::Resolved(_, resolved_path_ty) = ty_path + + && is_redundant_in_func_call(cx, resolved_path_ty.res, init_call) { + span_lint(cx, REDUNDANT_TYPE_ANNOTATIONS, local.span, "redundant type annotation"); + } + }, + hir::ExprKind::MethodCall(_, _, _, _) => { + let mut is_ref = false; + let mut ty_kind = &ty.kind; + + // If the annotation is a ref we "peel" it + if let hir::TyKind::Ref(_, mut_ty) = &ty.kind { + is_ref = true; + ty_kind = &mut_ty.ty.kind; + } + + if let hir::TyKind::Path(ty_path) = ty_kind + && let hir::QPath::Resolved(_, resolved_path_ty) = ty_path + && let Some(func_ty) = func_hir_id_to_func_ty(cx, init.hir_id) + && let Some(return_type) = func_ty_to_return_type(cx, func_ty) + && is_same_type(cx, resolved_path_ty.res, if is_ref { + return_type.peel_refs() + } else { + return_type + }) + { + span_lint(cx, REDUNDANT_TYPE_ANNOTATIONS, local.span, "redundant type annotation"); + } + }, + // When the initialization is a path for example u32::MAX + hir::ExprKind::Path(init_path) => { + // TODO: check for non primty + if let Some(primty) = extract_primty(&ty.kind) + + && let hir::QPath::TypeRelative(init_ty, _) = init_path + && let Some(primty_init) = extract_primty(&init_ty.kind) + + && primty == primty_init + { + span_lint(cx, REDUNDANT_TYPE_ANNOTATIONS, local.span, "redundant type annotation"); + } + }, + hir::ExprKind::Lit(init_lit) => { + match init_lit.node { + // In these cases the annotation is redundant + LitKind::Str(..) + | LitKind::ByteStr(..) + | LitKind::Byte(..) + | LitKind::Char(..) + | LitKind::Bool(..) + | LitKind::CStr(..) => { + span_lint(cx, REDUNDANT_TYPE_ANNOTATIONS, local.span, "redundant type annotation"); + }, + LitKind::Int(..) | LitKind::Float(..) => { + // If the initialization value is a suffixed literal we lint + if init_lit.node.is_suffixed() { + span_lint(cx, REDUNDANT_TYPE_ANNOTATIONS, local.span, "redundant type annotation"); + } + }, + LitKind::Err => (), + } + } + _ => () + } + }; + } +} diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 631ecf1428d6..958351ad81bb 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -25,6 +25,12 @@ declare_clippy_lint! { /// It is just extraneous code. Remove it to make your code /// more rusty. /// + /// ### Known problems + /// In the case of some temporaries, e.g. locks, eliding the variable binding could lead + /// to deadlocks. See [this issue](https://github.com/rust-lang/rust/issues/37612). + /// This could become relevant if the code is later changed to use the code that would have been + /// bound without first assigning it to a let-binding. + /// /// ### Example /// ```rust /// fn foo() -> String { @@ -286,7 +292,7 @@ fn check_final_expr<'tcx>( // (except for unit type functions) so we don't match it ExprKind::Match(_, arms, MatchSource::Normal) => { let match_ty = cx.typeck_results().expr_ty(peeled_drop_expr); - for arm in arms.iter() { + for arm in *arms { check_final_expr(cx, arm.body, semi_spans.clone(), RetReplacement::Unit, Some(match_ty)); } }, diff --git a/clippy_lints/src/significant_drop_tightening.rs b/clippy_lints/src/significant_drop_tightening.rs index b930b2c8dd7b..fffa8a380c2f 100644 --- a/clippy_lints/src/significant_drop_tightening.rs +++ b/clippy_lints/src/significant_drop_tightening.rs @@ -1,10 +1,10 @@ use clippy_utils::{ diagnostics::span_lint_and_then, - get_attr, + expr_or_init, get_attr, path_to_local, source::{indent_of, snippet}, }; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::{Applicability, Diagnostic}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; +use rustc_errors::Applicability; use rustc_hir::{ self as hir, intravisit::{walk_expr, Visitor}, @@ -13,6 +13,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::{subst::GenericArgKind, Ty, TypeAndMut}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{symbol::Ident, Span, DUMMY_SP}; +use std::borrow::Cow; declare_clippy_lint! { /// ### What it does @@ -56,255 +57,102 @@ impl_lint_pass!(SignificantDropTightening<'_> => [SIGNIFICANT_DROP_TIGHTENING]); #[derive(Default)] pub struct SignificantDropTightening<'tcx> { + apas: FxIndexMap, /// Auxiliary structure used to avoid having to verify the same type multiple times. seen_types: FxHashSet>, type_cache: FxHashMap, bool>, } -impl<'tcx> SignificantDropTightening<'tcx> { - /// Unifies the statements of a block with its return expression. - fn all_block_stmts<'ret, 'rslt, 'stmts>( - block_stmts: &'stmts [hir::Stmt<'tcx>], - dummy_ret_stmt: Option<&'ret hir::Stmt<'tcx>>, - ) -> impl Iterator> - where - 'ret: 'rslt, - 'stmts: 'rslt, - { - block_stmts.iter().chain(dummy_ret_stmt) - } - - /// Searches for at least one statement that could slow down the release of a significant drop. - fn at_least_one_stmt_is_expensive<'stmt>(stmts: impl Iterator>) -> bool - where - 'tcx: 'stmt, - { - for stmt in stmts { - match stmt.kind { - hir::StmtKind::Expr(expr) if let hir::ExprKind::Path(_) = expr.kind => {} - hir::StmtKind::Local(local) if let Some(expr) = local.init - && let hir::ExprKind::Path(_) = expr.kind => {}, - _ => return true - }; - } - false - } - - /// Verifies if the expression is of type `drop(some_lock_path)` to assert that the temporary - /// is already being dropped before the end of its scope. - fn has_drop(expr: &'tcx hir::Expr<'_>, init_bind_ident: Ident) -> bool { - if let hir::ExprKind::Call(fun, args) = expr.kind - && let hir::ExprKind::Path(hir::QPath::Resolved(_, fun_path)) = &fun.kind - && let [fun_ident, ..] = fun_path.segments - && fun_ident.ident.name == rustc_span::sym::drop - && let [first_arg, ..] = args - && let hir::ExprKind::Path(hir::QPath::Resolved(_, arg_path)) = &first_arg.kind - && let [first_arg_ps, .. ] = arg_path.segments - { - first_arg_ps.ident == init_bind_ident - } - else { - false - } - } - - /// Tries to find types marked with `#[has_significant_drop]` of an expression `expr` that is - /// originated from `stmt` and then performs common logic on `sdap`. - fn modify_sdap_if_sig_drop_exists( +impl<'tcx> LateLintPass<'tcx> for SignificantDropTightening<'tcx> { + fn check_fn( &mut self, cx: &LateContext<'tcx>, - expr: &'tcx hir::Expr<'_>, - idx: usize, - sdap: &mut SigDropAuxParams, - stmt: &hir::Stmt<'_>, - cb: impl Fn(&mut SigDropAuxParams), + _: hir::intravisit::FnKind<'_>, + _: &hir::FnDecl<'_>, + body: &'tcx hir::Body<'_>, + _: Span, + _: hir::def_id::LocalDefId, ) { - let mut sig_drop_finder = SigDropFinder::new(cx, &mut self.seen_types, &mut self.type_cache); - sig_drop_finder.visit_expr(expr); - if sig_drop_finder.has_sig_drop { - cb(sdap); - if sdap.number_of_stmts > 0 { - sdap.last_use_stmt_idx = idx; - sdap.last_use_stmt_span = stmt.span; - if let hir::ExprKind::MethodCall(_, _, _, span) = expr.kind { - sdap.last_use_method_span = span; - } + self.apas.clear(); + let initial_dummy_stmt = dummy_stmt_expr(body.value); + let mut ap = AuxParams::new(&mut self.apas, &initial_dummy_stmt); + StmtsChecker::new(&mut ap, cx, &mut self.seen_types, &mut self.type_cache).visit_body(body); + for apa in ap.apas.values() { + if apa.counter <= 1 || !apa.has_expensive_expr_after_last_attr { + continue; } - sdap.number_of_stmts = sdap.number_of_stmts.wrapping_add(1); - } - } - - /// Shows generic overall messages as well as specialized messages depending on the usage. - fn set_suggestions(cx: &LateContext<'tcx>, block_span: Span, diag: &mut Diagnostic, sdap: &SigDropAuxParams) { - match sdap.number_of_stmts { - 0 | 1 => {}, - 2 => { - let indent = " ".repeat(indent_of(cx, sdap.last_use_stmt_span).unwrap_or(0)); - let init_method = snippet(cx, sdap.init_method_span, ".."); - let usage_method = snippet(cx, sdap.last_use_method_span, ".."); - let stmt = if let Some(last_use_bind_span) = sdap.last_use_bind_span { - format!( - "\n{indent}let {} = {init_method}.{usage_method};", - snippet(cx, last_use_bind_span, ".."), - ) - } else { - format!("\n{indent}{init_method}.{usage_method};") - }; - diag.span_suggestion_verbose( - sdap.init_stmt_span, - "merge the temporary construction with its single usage", - stmt, - Applicability::MaybeIncorrect, - ); - diag.span_suggestion( - sdap.last_use_stmt_span, - "remove separated single usage", - "", - Applicability::MaybeIncorrect, - ); - }, - _ => { - diag.span_suggestion( - sdap.last_use_stmt_span.shrink_to_hi(), - "drop the temporary after the end of its last usage", - format!( - "\n{}drop({});", - " ".repeat(indent_of(cx, sdap.last_use_stmt_span).unwrap_or(0)), - sdap.init_bind_ident - ), - Applicability::MaybeIncorrect, - ); - }, - } - diag.note("this might lead to unnecessary resource contention"); - diag.span_label( - block_span, - format!( - "temporary `{}` is currently being dropped at the end of its contained scope", - sdap.init_bind_ident - ), - ); - } -} - -impl<'tcx> LateLintPass<'tcx> for SignificantDropTightening<'tcx> { - fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) { - let dummy_ret_stmt = block.expr.map(|expr| hir::Stmt { - hir_id: hir::HirId::INVALID, - kind: hir::StmtKind::Expr(expr), - span: DUMMY_SP, - }); - let mut sdap = SigDropAuxParams::default(); - for (idx, stmt) in Self::all_block_stmts(block.stmts, dummy_ret_stmt.as_ref()).enumerate() { - match stmt.kind { - hir::StmtKind::Expr(expr) => self.modify_sdap_if_sig_drop_exists( - cx, - expr, - idx, - &mut sdap, - stmt, - |_| {} - ), - hir::StmtKind::Local(local) if let Some(expr) = local.init => self.modify_sdap_if_sig_drop_exists( - cx, - expr, - idx, - &mut sdap, - stmt, - |local_sdap| { - if local_sdap.number_of_stmts == 0 { - if let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind { - local_sdap.init_bind_ident = ident; - } - if let hir::ExprKind::MethodCall(_, local_expr, _, span) = expr.kind { - local_sdap.init_method_span = local_expr.span.to(span); - } - local_sdap.init_stmt_span = stmt.span; - } - else if let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind { - local_sdap.last_use_bind_span = Some(ident.span); - } - } - ), - hir::StmtKind::Semi(expr) => { - if Self::has_drop(expr, sdap.init_bind_ident) { - return; - } - self.modify_sdap_if_sig_drop_exists(cx, expr, idx, &mut sdap, stmt, |_| {}); - }, - _ => {} - }; - } - - let idx = sdap.last_use_stmt_idx.wrapping_add(1); - let stmts_after_last_use = Self::all_block_stmts(block.stmts, dummy_ret_stmt.as_ref()).skip(idx); - if sdap.number_of_stmts > 1 && Self::at_least_one_stmt_is_expensive(stmts_after_last_use) { span_lint_and_then( cx, SIGNIFICANT_DROP_TIGHTENING, - sdap.init_bind_ident.span, + apa.first_bind_ident.span, "temporary with significant `Drop` can be early dropped", |diag| { - Self::set_suggestions(cx, block.span, diag, &sdap); + match apa.counter { + 0 | 1 => {}, + 2 => { + let indent = " ".repeat(indent_of(cx, apa.last_stmt_span).unwrap_or(0)); + let init_method = snippet(cx, apa.first_method_span, ".."); + let usage_method = snippet(cx, apa.last_method_span, ".."); + let stmt = if apa.last_bind_ident == Ident::empty() { + format!("\n{indent}{init_method}.{usage_method};") + } else { + format!( + "\n{indent}let {} = {init_method}.{usage_method};", + snippet(cx, apa.last_bind_ident.span, ".."), + ) + }; + diag.span_suggestion_verbose( + apa.first_stmt_span, + "merge the temporary construction with its single usage", + stmt, + Applicability::MaybeIncorrect, + ); + diag.span_suggestion( + apa.last_stmt_span, + "remove separated single usage", + "", + Applicability::MaybeIncorrect, + ); + }, + _ => { + diag.span_suggestion( + apa.last_stmt_span.shrink_to_hi(), + "drop the temporary after the end of its last usage", + format!( + "\n{}drop({});", + " ".repeat(indent_of(cx, apa.last_stmt_span).unwrap_or(0)), + apa.first_bind_ident + ), + Applicability::MaybeIncorrect, + ); + }, + } + diag.note("this might lead to unnecessary resource contention"); + diag.span_label( + apa.first_block_span, + format!( + "temporary `{}` is currently being dropped at the end of its contained scope", + apa.first_bind_ident + ), + ); }, ); } } } -/// Auxiliary parameters used on each block check. -struct SigDropAuxParams { - /// The binding or variable that references the initial construction of the type marked with - /// `#[has_significant_drop]`. - init_bind_ident: Ident, - /// Similar to `init_bind_ident` but encompasses the right-hand method call. - init_method_span: Span, - /// Similar to `init_bind_ident` but encompasses the whole contained statement. - init_stmt_span: Span, - - /// The last visited binding or variable span within a block that had any referenced inner type - /// marked with `#[has_significant_drop]`. - last_use_bind_span: Option, - /// Index of the last visited statement within a block that had any referenced inner type - /// marked with `#[has_significant_drop]`. - last_use_stmt_idx: usize, - /// Similar to `last_use_bind_span` but encompasses the whole contained statement. - last_use_stmt_span: Span, - /// Similar to `last_use_bind_span` but encompasses the right-hand method call. - last_use_method_span: Span, - - /// Total number of statements within a block that have any referenced inner type marked with - /// `#[has_significant_drop]`. - number_of_stmts: usize, -} - -impl Default for SigDropAuxParams { - fn default() -> Self { - Self { - init_bind_ident: Ident::empty(), - init_method_span: DUMMY_SP, - init_stmt_span: DUMMY_SP, - last_use_bind_span: None, - last_use_method_span: DUMMY_SP, - last_use_stmt_idx: 0, - last_use_stmt_span: DUMMY_SP, - number_of_stmts: 0, - } - } -} - -/// Checks the existence of the `#[has_significant_drop]` attribute -struct SigDropChecker<'cx, 'sdt, 'tcx> { +/// Checks the existence of the `#[has_significant_drop]` attribute. +struct AttrChecker<'cx, 'others, 'tcx> { cx: &'cx LateContext<'tcx>, - seen_types: &'sdt mut FxHashSet>, - type_cache: &'sdt mut FxHashMap, bool>, + seen_types: &'others mut FxHashSet>, + type_cache: &'others mut FxHashMap, bool>, } -impl<'cx, 'sdt, 'tcx> SigDropChecker<'cx, 'sdt, 'tcx> { +impl<'cx, 'others, 'tcx> AttrChecker<'cx, 'others, 'tcx> { pub(crate) fn new( cx: &'cx LateContext<'tcx>, - seen_types: &'sdt mut FxHashSet>, - type_cache: &'sdt mut FxHashMap, bool>, + seen_types: &'others mut FxHashSet>, + type_cache: &'others mut FxHashMap, bool>, ) -> Self { seen_types.clear(); Self { @@ -314,7 +162,17 @@ impl<'cx, 'sdt, 'tcx> SigDropChecker<'cx, 'sdt, 'tcx> { } } - pub(crate) fn has_sig_drop_attr_uncached(&mut self, ty: Ty<'tcx>) -> bool { + fn has_sig_drop_attr(&mut self, ty: Ty<'tcx>) -> bool { + // The borrow checker prevents us from using something fancier like or_insert_with. + if let Some(ty) = self.type_cache.get(&ty) { + return *ty; + } + let value = self.has_sig_drop_attr_uncached(ty); + self.type_cache.insert(ty, value); + value + } + + fn has_sig_drop_attr_uncached(&mut self, ty: Ty<'tcx>) -> bool { if let Some(adt) = ty.ty_adt_def() { let mut iter = get_attr( self.cx.sess(), @@ -333,7 +191,7 @@ impl<'cx, 'sdt, 'tcx> SigDropChecker<'cx, 'sdt, 'tcx> { return true; } } - for generic_arg in b.iter() { + for generic_arg in *b { if let GenericArgKind::Type(ty) = generic_arg.unpack() { if self.has_sig_drop_attr(ty) { return true; @@ -350,73 +208,244 @@ impl<'cx, 'sdt, 'tcx> SigDropChecker<'cx, 'sdt, 'tcx> { } } - pub(crate) fn has_sig_drop_attr(&mut self, ty: Ty<'tcx>) -> bool { - // The borrow checker prevents us from using something fancier like or_insert_with. - if let Some(ty) = self.type_cache.get(&ty) { - return *ty; - } - let value = self.has_sig_drop_attr_uncached(ty); - self.type_cache.insert(ty, value); - value - } - fn has_seen_ty(&mut self, ty: Ty<'tcx>) -> bool { !self.seen_types.insert(ty) } } -/// Performs recursive calls to find any inner type marked with `#[has_significant_drop]`. -struct SigDropFinder<'cx, 'sdt, 'tcx> { - cx: &'cx LateContext<'tcx>, - has_sig_drop: bool, - sig_drop_checker: SigDropChecker<'cx, 'sdt, 'tcx>, +struct StmtsChecker<'ap, 'lc, 'others, 'stmt, 'tcx> { + ap: &'ap mut AuxParams<'others, 'stmt, 'tcx>, + cx: &'lc LateContext<'tcx>, + seen_types: &'others mut FxHashSet>, + type_cache: &'others mut FxHashMap, bool>, } -impl<'cx, 'sdt, 'tcx> SigDropFinder<'cx, 'sdt, 'tcx> { +impl<'ap, 'lc, 'others, 'stmt, 'tcx> StmtsChecker<'ap, 'lc, 'others, 'stmt, 'tcx> { fn new( - cx: &'cx LateContext<'tcx>, - seen_types: &'sdt mut FxHashSet>, - type_cache: &'sdt mut FxHashMap, bool>, + ap: &'ap mut AuxParams<'others, 'stmt, 'tcx>, + cx: &'lc LateContext<'tcx>, + seen_types: &'others mut FxHashSet>, + type_cache: &'others mut FxHashMap, bool>, ) -> Self { Self { + ap, cx, - has_sig_drop: false, - sig_drop_checker: SigDropChecker::new(cx, seen_types, type_cache), + seen_types, + type_cache, + } + } + + fn manage_has_expensive_expr_after_last_attr(&mut self) { + let has_expensive_stmt = match self.ap.curr_stmt.kind { + hir::StmtKind::Expr(expr) if !is_expensive_expr(expr) => false, + hir::StmtKind::Local(local) if let Some(expr) = local.init + && let hir::ExprKind::Path(_) = expr.kind => false, + _ => true + }; + if has_expensive_stmt { + for apa in self.ap.apas.values_mut() { + let last_stmt_is_not_dummy = apa.last_stmt_span != DUMMY_SP; + let last_stmt_is_not_curr = self.ap.curr_stmt.span != apa.last_stmt_span; + let block_equals_curr = self.ap.curr_block_hir_id == apa.first_block_hir_id; + let block_is_ancestor = self + .cx + .tcx + .hir() + .parent_iter(self.ap.curr_block_hir_id) + .any(|(id, _)| id == apa.first_block_hir_id); + if last_stmt_is_not_dummy && last_stmt_is_not_curr && (block_equals_curr || block_is_ancestor) { + apa.has_expensive_expr_after_last_attr = true; + } + } } } } -impl<'cx, 'sdt, 'tcx> Visitor<'tcx> for SigDropFinder<'cx, 'sdt, 'tcx> { - fn visit_expr(&mut self, ex: &'tcx hir::Expr<'_>) { - if self - .sig_drop_checker - .has_sig_drop_attr(self.cx.typeck_results().expr_ty(ex)) - { - self.has_sig_drop = true; - return; +impl<'ap, 'lc, 'others, 'stmt, 'tcx> Visitor<'tcx> for StmtsChecker<'ap, 'lc, 'others, 'stmt, 'tcx> { + fn visit_block(&mut self, block: &'tcx hir::Block<'tcx>) { + self.ap.curr_block_hir_id = block.hir_id; + self.ap.curr_block_span = block.span; + for stmt in block.stmts { + self.ap.curr_stmt = Cow::Borrowed(stmt); + self.visit_stmt(stmt); + self.ap.curr_block_hir_id = block.hir_id; + self.ap.curr_block_span = block.span; + self.manage_has_expensive_expr_after_last_attr(); } + if let Some(expr) = block.expr { + self.ap.curr_stmt = Cow::Owned(dummy_stmt_expr(expr)); + self.visit_expr(expr); + self.ap.curr_block_hir_id = block.hir_id; + self.ap.curr_block_span = block.span; + self.manage_has_expensive_expr_after_last_attr(); + } + } - match ex.kind { - hir::ExprKind::MethodCall(_, expr, ..) => { - self.visit_expr(expr); - }, - hir::ExprKind::Array(..) - | hir::ExprKind::Assign(..) - | hir::ExprKind::AssignOp(..) - | hir::ExprKind::Binary(..) - | hir::ExprKind::Call(..) - | hir::ExprKind::Field(..) - | hir::ExprKind::If(..) - | hir::ExprKind::Index(..) - | hir::ExprKind::Match(..) - | hir::ExprKind::Repeat(..) - | hir::ExprKind::Ret(..) - | hir::ExprKind::Tup(..) - | hir::ExprKind::Unary(..) - | hir::ExprKind::Yield(..) => { - walk_expr(self, ex); - }, - _ => {}, + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { + let modify_apa_params = |apa: &mut AuxParamsAttr| { + apa.counter = apa.counter.wrapping_add(1); + apa.has_expensive_expr_after_last_attr = false; + }; + let mut ac = AttrChecker::new(self.cx, self.seen_types, self.type_cache); + if ac.has_sig_drop_attr(self.cx.typeck_results().expr_ty(expr)) { + if let hir::StmtKind::Local(local) = self.ap.curr_stmt.kind + && let hir::PatKind::Binding(_, hir_id, ident, _) = local.pat.kind + && !self.ap.apas.contains_key(&hir_id) + && { + if let Some(local_hir_id) = path_to_local(expr) { + local_hir_id == hir_id + } + else { + true + } + } + { + let mut apa = AuxParamsAttr { + first_bind_ident: ident, + first_block_hir_id: self.ap.curr_block_hir_id, + first_block_span: self.ap.curr_block_span, + first_method_span: { + let expr_or_init = expr_or_init(self.cx, expr); + if let hir::ExprKind::MethodCall(_, local_expr, _, span) = expr_or_init.kind { + local_expr.span.to(span) + } + else { + expr_or_init.span + } + }, + first_stmt_span: self.ap.curr_stmt.span, + ..Default::default() + }; + modify_apa_params(&mut apa); + let _ = self.ap.apas.insert(hir_id, apa); + } else { + let Some(hir_id) = path_to_local(expr) else { return; }; + let Some(apa) = self.ap.apas.get_mut(&hir_id) else { return; }; + match self.ap.curr_stmt.kind { + hir::StmtKind::Local(local) => { + if let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind { + apa.last_bind_ident = ident; + } + if let Some(local_init) = local.init + && let hir::ExprKind::MethodCall(_, _, _, span) = local_init.kind + { + apa.last_method_span = span; + } + }, + hir::StmtKind::Semi(expr) => { + if has_drop(expr, &apa.first_bind_ident) { + apa.has_expensive_expr_after_last_attr = false; + apa.last_stmt_span = DUMMY_SP; + return; + } + if let hir::ExprKind::MethodCall(_, _, _, span) = expr.kind { + apa.last_method_span = span; + } + }, + _ => {}, + } + apa.last_stmt_span = self.ap.curr_stmt.span; + modify_apa_params(apa); + } + } + walk_expr(self, expr); + } +} + +/// Auxiliary parameters used on each block check of an item +struct AuxParams<'others, 'stmt, 'tcx> { + //// See [AuxParamsAttr]. + apas: &'others mut FxIndexMap, + /// The current block identifier that is being visited. + curr_block_hir_id: hir::HirId, + /// The current block span that is being visited. + curr_block_span: Span, + /// The current statement that is being visited. + curr_stmt: Cow<'stmt, hir::Stmt<'tcx>>, +} + +impl<'others, 'stmt, 'tcx> AuxParams<'others, 'stmt, 'tcx> { + fn new(apas: &'others mut FxIndexMap, curr_stmt: &'stmt hir::Stmt<'tcx>) -> Self { + Self { + apas, + curr_block_hir_id: hir::HirId::INVALID, + curr_block_span: DUMMY_SP, + curr_stmt: Cow::Borrowed(curr_stmt), } } } + +/// Auxiliary parameters used on expression created with `#[has_significant_drop]`. +#[derive(Debug)] +struct AuxParamsAttr { + /// The number of times `#[has_significant_drop]` was referenced. + counter: usize, + /// If an expensive expression follows the last use of anything marked with + /// `#[has_significant_drop]`. + has_expensive_expr_after_last_attr: bool, + + /// The identifier of the block that involves the first `#[has_significant_drop]`. + first_block_hir_id: hir::HirId, + /// The span of the block that involves the first `#[has_significant_drop]`. + first_block_span: Span, + /// The binding or variable that references the initial construction of the type marked with + /// `#[has_significant_drop]`. + first_bind_ident: Ident, + /// Similar to `init_bind_ident` but encompasses the right-hand method call. + first_method_span: Span, + /// Similar to `init_bind_ident` but encompasses the whole contained statement. + first_stmt_span: Span, + + /// The last visited binding or variable span within a block that had any referenced inner type + /// marked with `#[has_significant_drop]`. + last_bind_ident: Ident, + /// Similar to `last_bind_span` but encompasses the right-hand method call. + last_method_span: Span, + /// Similar to `last_bind_span` but encompasses the whole contained statement. + last_stmt_span: Span, +} + +impl Default for AuxParamsAttr { + fn default() -> Self { + Self { + counter: 0, + has_expensive_expr_after_last_attr: false, + first_block_hir_id: hir::HirId::INVALID, + first_bind_ident: Ident::empty(), + first_block_span: DUMMY_SP, + first_method_span: DUMMY_SP, + first_stmt_span: DUMMY_SP, + last_bind_ident: Ident::empty(), + last_method_span: DUMMY_SP, + last_stmt_span: DUMMY_SP, + } + } +} + +fn dummy_stmt_expr<'any>(expr: &'any hir::Expr<'any>) -> hir::Stmt<'any> { + hir::Stmt { + hir_id: hir::HirId::INVALID, + kind: hir::StmtKind::Expr(expr), + span: DUMMY_SP, + } +} + +fn has_drop(expr: &hir::Expr<'_>, first_bind_ident: &Ident) -> bool { + if let hir::ExprKind::Call(fun, args) = expr.kind + && let hir::ExprKind::Path(hir::QPath::Resolved(_, fun_path)) = &fun.kind + && let [fun_ident, ..] = fun_path.segments + && fun_ident.ident.name == rustc_span::sym::drop + && let [first_arg, ..] = args + && let hir::ExprKind::Path(hir::QPath::Resolved(_, arg_path)) = &first_arg.kind + && let [first_arg_ps, .. ] = arg_path.segments + { + &first_arg_ps.ident == first_bind_ident + } + else { + false + } +} + +fn is_expensive_expr(expr: &hir::Expr<'_>) -> bool { + !matches!(expr.kind, hir::ExprKind::Path(_)) +} diff --git a/clippy_lints/src/single_call_fn.rs b/clippy_lints/src/single_call_fn.rs new file mode 100644 index 000000000000..42753d2e9511 --- /dev/null +++ b/clippy_lints/src/single_call_fn.rs @@ -0,0 +1,133 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::{is_from_proc_macro, is_in_test_function}; +use rustc_data_structures::fx::FxHashMap; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::{intravisit::FnKind, Body, Expr, ExprKind, FnDecl}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::hir::nested_filter::OnlyBodies; +use rustc_middle::lint::in_external_macro; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::Span; + +declare_clippy_lint! { + /// ### What it does + /// Checks for functions that are only used once. Does not lint tests. + /// + /// ### Why is this bad? + /// It's usually not, splitting a function into multiple parts often improves readability and in + /// the case of generics, can prevent the compiler from duplicating the function dozens of + /// time; instead, only duplicating a thunk. But this can prevent segmentation across a + /// codebase, where many small functions are used only once. + /// + /// Note: If this lint is used, prepare to allow this a lot. + /// + /// ### Example + /// ```rust + /// pub fn a(t: &T) + /// where + /// T: AsRef, + /// { + /// a_inner(t.as_ref()) + /// } + /// + /// fn a_inner(t: &str) { + /// /* snip */ + /// } + /// + /// ``` + /// Use instead: + /// ```rust + /// pub fn a(t: &T) + /// where + /// T: AsRef, + /// { + /// let t = t.as_ref(); + /// /* snip */ + /// } + /// + /// ``` + #[clippy::version = "1.72.0"] + pub SINGLE_CALL_FN, + restriction, + "checks for functions that are only used once" +} +impl_lint_pass!(SingleCallFn => [SINGLE_CALL_FN]); + +#[derive(Clone)] +pub struct SingleCallFn { + pub avoid_breaking_exported_api: bool, + pub def_id_to_usage: FxHashMap)>, +} + +impl<'tcx> LateLintPass<'tcx> for SingleCallFn { + fn check_fn( + &mut self, + cx: &LateContext<'tcx>, + kind: FnKind<'tcx>, + _: &'tcx FnDecl<'_>, + body: &'tcx Body<'_>, + span: Span, + def_id: LocalDefId, + ) { + if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id) + || in_external_macro(cx.sess(), span) + || is_from_proc_macro(cx, &(&kind, body, cx.tcx.local_def_id_to_hir_id(def_id), span)) + || is_in_test_function(cx.tcx, body.value.hir_id) + { + return; + } + + self.def_id_to_usage.insert(def_id, (span, vec![])); + } + + fn check_crate_post(&mut self, cx: &LateContext<'tcx>) { + let mut v = FnUsageVisitor { + cx, + def_id_to_usage: &mut self.def_id_to_usage, + }; + cx.tcx.hir().visit_all_item_likes_in_crate(&mut v); + + for usage in self.def_id_to_usage.values() { + let single_call_fn_span = usage.0; + if let [caller_span] = *usage.1 { + span_lint_and_help( + cx, + SINGLE_CALL_FN, + single_call_fn_span, + "this function is only used once", + Some(caller_span), + "used here", + ); + } + } + } +} + +struct FnUsageVisitor<'a, 'tcx> { + cx: &'a LateContext<'tcx>, + def_id_to_usage: &'a mut FxHashMap)>, +} + +impl<'a, 'tcx> Visitor<'tcx> for FnUsageVisitor<'a, 'tcx> { + type NestedFilter = OnlyBodies; + + fn nested_visit_map(&mut self) -> Self::Map { + self.cx.tcx.hir() + } + + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { + let Self { cx, .. } = *self; + + if let ExprKind::Path(qpath) = expr.kind + && let res = cx.qpath_res(&qpath, expr.hir_id) + && let Some(call_def_id) = res.opt_def_id() + && let Some(def_id) = call_def_id.as_local() + && let Some(usage) = self.def_id_to_usage.get_mut(&def_id) + { + usage.1.push(expr.span); + } + + walk_expr(self, expr); + } +} diff --git a/clippy_lints/src/single_range_in_vec_init.rs b/clippy_lints/src/single_range_in_vec_init.rs new file mode 100644 index 000000000000..dfe8be7a6a61 --- /dev/null +++ b/clippy_lints/src/single_range_in_vec_init.rs @@ -0,0 +1,147 @@ +use clippy_utils::{ + diagnostics::span_lint_and_then, get_trait_def_id, higher::VecArgs, macros::root_macro_call_first_node, + source::snippet_opt, ty::implements_trait, +}; +use rustc_ast::{LitIntType, LitKind, UintTy}; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, LangItem, QPath}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use std::fmt::{self, Display, Formatter}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for `Vec` or array initializations that contain only one range. + /// + /// ### Why is this bad? + /// This is almost always incorrect, as it will result in a `Vec` that has only one element. + /// Almost always, the programmer intended for it to include all elements in the range or for + /// the end of the range to be the length instead. + /// + /// ### Example + /// ```rust + /// let x = [0..200]; + /// ``` + /// Use instead: + /// ```rust + /// // If it was intended to include every element in the range... + /// let x = (0..200).collect::>(); + /// // ...Or if 200 was meant to be the len + /// let x = [0; 200]; + /// ``` + #[clippy::version = "1.72.0"] + pub SINGLE_RANGE_IN_VEC_INIT, + suspicious, + "checks for initialization of `Vec` or arrays which consist of a single range" +} +declare_lint_pass!(SingleRangeInVecInit => [SINGLE_RANGE_IN_VEC_INIT]); + +enum SuggestedType { + Vec, + Array, +} + +impl SuggestedType { + fn starts_with(&self) -> &'static str { + if matches!(self, SuggestedType::Vec) { + "vec!" + } else { + "[" + } + } + + fn ends_with(&self) -> &'static str { + if matches!(self, SuggestedType::Vec) { "" } else { "]" } + } +} + +impl Display for SuggestedType { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + if matches!(&self, SuggestedType::Vec) { + write!(f, "a `Vec`") + } else { + write!(f, "an array") + } + } +} + +impl LateLintPass<'_> for SingleRangeInVecInit { + fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { + // inner_expr: `vec![0..200]` or `[0..200]` + // ^^^^^^ ^^^^^^^ + // span: `vec![0..200]` or `[0..200]` + // ^^^^^^^^^^^^ ^^^^^^^^ + // suggested_type: What to print, "an array" or "a `Vec`" + let (inner_expr, span, suggested_type) = if let ExprKind::Array([inner_expr]) = expr.kind + && !expr.span.from_expansion() + { + (inner_expr, expr.span, SuggestedType::Array) + } else if let Some(macro_call) = root_macro_call_first_node(cx, expr) + && let Some(VecArgs::Vec([expr])) = VecArgs::hir(cx, expr) + { + (expr, macro_call.span, SuggestedType::Vec) + } else { + return; + }; + + let ExprKind::Struct(QPath::LangItem(lang_item, ..), [start, end], None) = inner_expr.kind else { + return; + }; + + if matches!(lang_item, LangItem::Range) + && let ty = cx.typeck_results().expr_ty(start.expr) + && let Some(snippet) = snippet_opt(cx, span) + // `is_from_proc_macro` will skip any `vec![]`. Let's not! + && snippet.starts_with(suggested_type.starts_with()) + && snippet.ends_with(suggested_type.ends_with()) + && let Some(start_snippet) = snippet_opt(cx, start.span) + && let Some(end_snippet) = snippet_opt(cx, end.span) + { + let should_emit_every_value = if let Some(step_def_id) = get_trait_def_id(cx, &["core", "iter", "Step"]) + && implements_trait(cx, ty, step_def_id, &[]) + { + true + } else { + false + }; + let should_emit_of_len = if let Some(copy_def_id) = cx.tcx.lang_items().copy_trait() + && implements_trait(cx, ty, copy_def_id, &[]) + && let ExprKind::Lit(lit_kind) = end.expr.kind + && let LitKind::Int(.., suffix_type) = lit_kind.node + && let LitIntType::Unsigned(UintTy::Usize) | LitIntType::Unsuffixed = suffix_type + { + true + } else { + false + }; + + if should_emit_every_value || should_emit_of_len { + span_lint_and_then( + cx, + SINGLE_RANGE_IN_VEC_INIT, + span, + &format!("{suggested_type} of `Range` that is only one element"), + |diag| { + if should_emit_every_value { + diag.span_suggestion( + span, + "if you wanted a `Vec` that contains the entire range, try", + format!("({start_snippet}..{end_snippet}).collect::>()"), + Applicability::MaybeIncorrect, + ); + } + + if should_emit_of_len { + diag.span_suggestion( + inner_expr.span, + format!("if you wanted {suggested_type} of len {end_snippet}, try"), + format!("{start_snippet}; {end_snippet}"), + Applicability::MaybeIncorrect, + ); + } + }, + ); + } + } + } +} diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index 4ccda15068bb..6db330dfa617 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability}; -use clippy_utils::{SpanlessEq, SpanlessHash}; +use clippy_utils::{is_from_proc_macro, SpanlessEq, SpanlessHash}; use core::hash::{Hash, Hasher}; use if_chain::if_chain; use itertools::Itertools; @@ -9,7 +10,7 @@ use rustc_data_structures::unhash::UnhashMap; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{ - GenericArg, GenericBound, Generics, Item, ItemKind, Node, Path, PathSegment, PredicateOrigin, QPath, + GenericArg, GenericBound, Generics, Item, ItemKind, LangItem, Node, Path, PathSegment, PredicateOrigin, QPath, TraitBoundModifier, TraitItem, TraitRef, Ty, TyKind, WherePredicate, }; use rustc_lint::{LateContext, LateLintPass}; @@ -86,15 +87,16 @@ declare_clippy_lint! { "check if the same trait bounds are specified more than once during a generic declaration" } -#[derive(Copy, Clone)] +#[derive(Clone)] pub struct TraitBounds { max_trait_bounds: u64, + msrv: Msrv, } impl TraitBounds { #[must_use] - pub fn new(max_trait_bounds: u64) -> Self { - Self { max_trait_bounds } + pub fn new(max_trait_bounds: u64, msrv: Msrv) -> Self { + Self { max_trait_bounds, msrv } } } @@ -139,7 +141,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds { ) = cx.tcx.hir().get_if_local(*def_id); then { if self_bounds_map.is_empty() { - for bound in self_bounds.iter() { + for bound in *self_bounds { let Some((self_res, self_segments, _)) = get_trait_info_from_bound(bound) else { continue }; self_bounds_map.insert(self_res, self_segments); } @@ -184,7 +186,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds { // Iterate the bounds and add them to our seen hash // If we haven't yet seen it, add it to the fixed traits - for bound in bounds.iter() { + for bound in bounds { let Some(def_id) = bound.trait_ref.trait_def_id() else { continue; }; let new_trait = seen_def_ids.insert(def_id); @@ -222,10 +224,24 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds { } } } + + extract_msrv_attr!(LateContext); } impl TraitBounds { - fn check_type_repetition<'tcx>(self, cx: &LateContext<'tcx>, gen: &'tcx Generics<'_>) { + /// Is the given bound a `?Sized` bound, and is combining it (i.e. `T: X + ?Sized`) an error on + /// this MSRV? See for details. + fn cannot_combine_maybe_bound(&self, cx: &LateContext<'_>, bound: &GenericBound<'_>) -> bool { + if !self.msrv.meets(msrvs::MAYBE_BOUND_IN_WHERE) + && let GenericBound::Trait(tr, TraitBoundModifier::Maybe) = bound + { + cx.tcx.lang_items().get(LangItem::Sized) == tr.trait_ref.path.res.opt_def_id() + } else { + false + } + } + + fn check_type_repetition<'tcx>(&self, cx: &LateContext<'tcx>, gen: &'tcx Generics<'_>) { struct SpanlessTy<'cx, 'tcx> { ty: &'tcx Ty<'tcx>, cx: &'cx LateContext<'tcx>, @@ -256,11 +272,10 @@ impl TraitBounds { if p.origin != PredicateOrigin::ImplTrait; if p.bounds.len() as u64 <= self.max_trait_bounds; if !p.span.from_expansion(); - if let Some(ref v) = map.insert( - SpanlessTy { ty: p.bounded_ty, cx }, - p.bounds.iter().collect::>() - ); - + let bounds = p.bounds.iter().filter(|b| !self.cannot_combine_maybe_bound(cx, b)).collect::>(); + if !bounds.is_empty(); + if let Some(ref v) = map.insert(SpanlessTy { ty: p.bounded_ty, cx }, bounds); + if !is_from_proc_macro(cx, p.bounded_ty); then { let trait_bounds = v .iter() @@ -342,7 +357,7 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) { "this trait bound is already specified in the where clause", None, "consider removing this trait bound", - ); + ); } } } diff --git a/clippy_lints/src/tuple_array_conversions.rs b/clippy_lints/src/tuple_array_conversions.rs new file mode 100644 index 000000000000..bd983306508b --- /dev/null +++ b/clippy_lints/src/tuple_array_conversions.rs @@ -0,0 +1,235 @@ +use clippy_utils::{ + diagnostics::span_lint_and_help, + is_from_proc_macro, + msrvs::{self, Msrv}, + path_to_local, +}; +use rustc_ast::LitKind; +use rustc_hir::{Expr, ExprKind, HirId, Node, Pat}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::{lint::in_external_macro, ty}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use std::iter::once; + +declare_clippy_lint! { + /// ### What it does + /// Checks for tuple<=>array conversions that are not done with `.into()`. + /// + /// ### Why is this bad? + /// It's unnecessary complexity. `.into()` works for tuples<=>arrays at or below 12 elements and + /// conveys the intent a lot better, while also leaving less room for hard to spot bugs! + /// + /// ### Example + /// ```rust,ignore + /// let t1 = &[(1, 2), (3, 4)]; + /// let v1: Vec<[u32; 2]> = t1.iter().map(|&(a, b)| [a, b]).collect(); + /// ``` + /// Use instead: + /// ```rust,ignore + /// let t1 = &[(1, 2), (3, 4)]; + /// let v1: Vec<[u32; 2]> = t1.iter().map(|&t| t.into()).collect(); + /// ``` + #[clippy::version = "1.72.0"] + pub TUPLE_ARRAY_CONVERSIONS, + complexity, + "checks for tuple<=>array conversions that are not done with `.into()`" +} +impl_lint_pass!(TupleArrayConversions => [TUPLE_ARRAY_CONVERSIONS]); + +#[derive(Clone)] +pub struct TupleArrayConversions { + pub msrv: Msrv, +} + +impl LateLintPass<'_> for TupleArrayConversions { + fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if !in_external_macro(cx.sess(), expr.span) && self.msrv.meets(msrvs::TUPLE_ARRAY_CONVERSIONS) { + match expr.kind { + ExprKind::Array(elements) if (1..=12).contains(&elements.len()) => check_array(cx, expr, elements), + ExprKind::Tup(elements) if (1..=12).contains(&elements.len()) => check_tuple(cx, expr, elements), + _ => {}, + } + } + } + + extract_msrv_attr!(LateContext); +} + +#[expect( + clippy::blocks_in_if_conditions, + reason = "not a FP, but this is much easier to understand" +)] +fn check_array<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, elements: &'tcx [Expr<'tcx>]) { + if should_lint( + cx, + elements, + // This is cursed. + Some, + |(first_id, local)| { + if let Node::Pat(pat) = local + && let parent = parent_pat(cx, pat) + && parent.hir_id == first_id + { + return matches!( + cx.typeck_results().pat_ty(parent).peel_refs().kind(), + ty::Tuple(len) if len.len() == elements.len() + ); + } + + false + }, + ) || should_lint( + cx, + elements, + |(i, expr)| { + if let ExprKind::Field(path, field) = expr.kind && field.as_str() == i.to_string() { + return Some((i, path)); + }; + + None + }, + |(first_id, local)| { + if let Node::Pat(pat) = local + && let parent = parent_pat(cx, pat) + && parent.hir_id == first_id + { + return matches!( + cx.typeck_results().pat_ty(parent).peel_refs().kind(), + ty::Tuple(len) if len.len() == elements.len() + ); + } + + false + }, + ) { + emit_lint(cx, expr, ToType::Array); + } +} + +#[expect( + clippy::blocks_in_if_conditions, + reason = "not a FP, but this is much easier to understand" +)] +#[expect(clippy::cast_possible_truncation)] +fn check_tuple<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, elements: &'tcx [Expr<'tcx>]) { + if should_lint(cx, elements, Some, |(first_id, local)| { + if let Node::Pat(pat) = local + && let parent = parent_pat(cx, pat) + && parent.hir_id == first_id + { + return matches!( + cx.typeck_results().pat_ty(parent).peel_refs().kind(), + ty::Array(_, len) if len.eval_target_usize(cx.tcx, cx.param_env) as usize == elements.len() + ); + } + + false + }) || should_lint( + cx, + elements, + |(i, expr)| { + if let ExprKind::Index(path, index) = expr.kind + && let ExprKind::Lit(lit) = index.kind + && let LitKind::Int(val, _) = lit.node + && val as usize == i + { + return Some((i, path)); + }; + + None + }, + |(first_id, local)| { + if let Node::Pat(pat) = local + && let parent = parent_pat(cx, pat) + && parent.hir_id == first_id + { + return matches!( + cx.typeck_results().pat_ty(parent).peel_refs().kind(), + ty::Array(_, len) if len.eval_target_usize(cx.tcx, cx.param_env) as usize == elements.len() + ); + } + + false + }, + ) { + emit_lint(cx, expr, ToType::Tuple); + } +} + +/// Walks up the `Pat` until it's reached the final containing `Pat`. +fn parent_pat<'tcx>(cx: &LateContext<'tcx>, start: &'tcx Pat<'tcx>) -> &'tcx Pat<'tcx> { + let mut end = start; + for (_, node) in cx.tcx.hir().parent_iter(start.hir_id) { + if let Node::Pat(pat) = node { + end = pat; + } else { + break; + } + } + end +} + +#[derive(Clone, Copy)] +enum ToType { + Array, + Tuple, +} + +impl ToType { + fn msg(self) -> &'static str { + match self { + ToType::Array => "it looks like you're trying to convert a tuple to an array", + ToType::Tuple => "it looks like you're trying to convert an array to a tuple", + } + } + + fn help(self) -> &'static str { + match self { + ToType::Array => "use `.into()` instead, or `<[T; N]>::from` if type annotations are needed", + ToType::Tuple => "use `.into()` instead, or `<(T0, T1, ..., Tn)>::from` if type annotations are needed", + } + } +} + +fn emit_lint<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, to_type: ToType) -> bool { + if !is_from_proc_macro(cx, expr) { + span_lint_and_help( + cx, + TUPLE_ARRAY_CONVERSIONS, + expr.span, + to_type.msg(), + None, + to_type.help(), + ); + + return true; + } + + false +} + +fn should_lint<'tcx>( + cx: &LateContext<'tcx>, + elements: &'tcx [Expr<'tcx>], + map: impl FnMut((usize, &'tcx Expr<'tcx>)) -> Option<(usize, &Expr<'_>)>, + predicate: impl FnMut((HirId, &Node<'tcx>)) -> bool, +) -> bool { + if let Some(elements) = elements + .iter() + .enumerate() + .map(map) + .collect::>>() + && let Some(locals) = elements + .iter() + .map(|(_, element)| path_to_local(element).and_then(|local| cx.tcx.hir().find(local))) + .collect::>>() + && let [first, rest @ ..] = &*locals + && let Node::Pat(first_pat) = first + && let parent = parent_pat(cx, first_pat).hir_id + && rest.iter().chain(once(first)).map(|i| (parent, i)).all(predicate) + { + return true; + } + + false +} diff --git a/clippy_lints/src/undocumented_unsafe_blocks.rs b/clippy_lints/src/undocumented_unsafe_blocks.rs index 2920684ade33..a9deee967849 100644 --- a/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -11,7 +11,7 @@ use rustc_hir::{Block, BlockCheckMode, ItemKind, Node, UnsafeSource}; use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{BytePos, Pos, Span, SyntaxContext}; declare_clippy_lint! { @@ -92,7 +92,22 @@ declare_clippy_lint! { "annotating safe code with a safety comment" } -declare_lint_pass!(UndocumentedUnsafeBlocks => [UNDOCUMENTED_UNSAFE_BLOCKS, UNNECESSARY_SAFETY_COMMENT]); +#[derive(Copy, Clone)] +pub struct UndocumentedUnsafeBlocks { + accept_comment_above_statement: bool, + accept_comment_above_attributes: bool, +} + +impl UndocumentedUnsafeBlocks { + pub fn new(accept_comment_above_statement: bool, accept_comment_above_attributes: bool) -> Self { + Self { + accept_comment_above_statement, + accept_comment_above_attributes, + } + } +} + +impl_lint_pass!(UndocumentedUnsafeBlocks => [UNDOCUMENTED_UNSAFE_BLOCKS, UNNECESSARY_SAFETY_COMMENT]); impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) { @@ -101,7 +116,12 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks { && !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, block.hir_id) && !is_unsafe_from_proc_macro(cx, block.span) && !block_has_safety_comment(cx, block.span) - && !block_parents_have_safety_comment(cx, block.hir_id) + && !block_parents_have_safety_comment( + self.accept_comment_above_statement, + self.accept_comment_above_attributes, + cx, + block.hir_id, + ) { let source_map = cx.tcx.sess.source_map(); let span = if source_map.is_multiline(block.span) { @@ -313,29 +333,95 @@ fn is_unsafe_from_proc_macro(cx: &LateContext<'_>, span: Span) -> bool { // Checks if any parent {expression, statement, block, local, const, static} // has a safety comment -fn block_parents_have_safety_comment(cx: &LateContext<'_>, id: hir::HirId) -> bool { +fn block_parents_have_safety_comment( + accept_comment_above_statement: bool, + accept_comment_above_attributes: bool, + cx: &LateContext<'_>, + id: hir::HirId, +) -> bool { if let Some(node) = get_parent_node(cx.tcx, id) { return match node { - Node::Expr(expr) => !is_branchy(expr) && span_in_body_has_safety_comment(cx, expr.span), + Node::Expr(expr) => { + if let Some( + Node::Local(hir::Local { span, .. }) + | Node::Item(hir::Item { + kind: hir::ItemKind::Const(..) | ItemKind::Static(..), + span, + .. + }), + ) = get_parent_node(cx.tcx, expr.hir_id) + { + let hir_id = match get_parent_node(cx.tcx, expr.hir_id) { + Some(Node::Local(hir::Local { hir_id, .. })) => *hir_id, + Some(Node::Item(hir::Item { owner_id, .. })) => { + cx.tcx.hir().local_def_id_to_hir_id(owner_id.def_id) + }, + _ => unreachable!(), + }; + + // if unsafe block is part of a let/const/static statement, + // and accept_comment_above_statement is set to true + // we accept the safety comment in the line the precedes this statement. + accept_comment_above_statement + && span_with_attrs_in_body_has_safety_comment( + cx, + *span, + hir_id, + accept_comment_above_attributes, + ) + } else { + !is_branchy(expr) + && span_with_attrs_in_body_has_safety_comment( + cx, + expr.span, + expr.hir_id, + accept_comment_above_attributes, + ) + } + }, Node::Stmt(hir::Stmt { kind: - hir::StmtKind::Local(hir::Local { span, .. }) - | hir::StmtKind::Expr(hir::Expr { span, .. }) - | hir::StmtKind::Semi(hir::Expr { span, .. }), + hir::StmtKind::Local(hir::Local { span, hir_id, .. }) + | hir::StmtKind::Expr(hir::Expr { span, hir_id, .. }) + | hir::StmtKind::Semi(hir::Expr { span, hir_id, .. }), .. }) - | Node::Local(hir::Local { span, .. }) - | Node::Item(hir::Item { + | Node::Local(hir::Local { span, hir_id, .. }) => { + span_with_attrs_in_body_has_safety_comment(cx, *span, *hir_id, accept_comment_above_attributes) + }, + Node::Item(hir::Item { kind: hir::ItemKind::Const(..) | ItemKind::Static(..), span, + owner_id, .. - }) => span_in_body_has_safety_comment(cx, *span), + }) => span_with_attrs_in_body_has_safety_comment( + cx, + *span, + cx.tcx.hir().local_def_id_to_hir_id(owner_id.def_id), + accept_comment_above_attributes, + ), _ => false, }; } false } +/// Extends `span` to also include its attributes, then checks if that span has a safety comment. +fn span_with_attrs_in_body_has_safety_comment( + cx: &LateContext<'_>, + span: Span, + hir_id: HirId, + accept_comment_above_attributes: bool, +) -> bool { + let span = if accept_comment_above_attributes { + include_attrs_in_span(cx, hir_id, span) + } else { + span + }; + + span_in_body_has_safety_comment(cx, span) +} + /// Checks if an expression is "branchy", e.g. loop, match/if/etc. fn is_branchy(expr: &hir::Expr<'_>) -> bool { matches!( @@ -360,6 +446,15 @@ fn block_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool { ) || span_in_body_has_safety_comment(cx, span) } +fn include_attrs_in_span(cx: &LateContext<'_>, hir_id: HirId, span: Span) -> Span { + span.to(cx + .tcx + .hir() + .attrs(hir_id) + .iter() + .fold(span, |acc, attr| acc.to(attr.span))) +} + enum HasSafetyComment { Yes(BytePos), No, @@ -546,7 +641,14 @@ fn get_body_search_span(cx: &LateContext<'_>) -> Option { for (_, node) in map.parent_iter(body.hir_id) { match node { Node::Expr(e) => span = e.span, - Node::Block(_) | Node::Arm(_) | Node::Stmt(_) | Node::Local(_) => (), + Node::Block(_) + | Node::Arm(_) + | Node::Stmt(_) + | Node::Local(_) + | Node::Item(hir::Item { + kind: hir::ItemKind::Const(..) | ItemKind::Static(..), + .. + }) => (), _ => break, } } diff --git a/clippy_lints/src/unused_async.rs b/clippy_lints/src/unused_async.rs index 117dda092223..5e42cf7e4f3f 100644 --- a/clippy_lints/src/unused_async.rs +++ b/clippy_lints/src/unused_async.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::is_def_id_trait_method; use rustc_hir::intravisit::{walk_body, walk_expr, walk_fn, FnKind, Visitor}; use rustc_hir::{Body, Expr, ExprKind, FnDecl, YieldSource}; use rustc_lint::{LateContext, LateLintPass}; @@ -91,7 +92,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync { span: Span, def_id: LocalDefId, ) { - if !span.from_expansion() && fn_kind.asyncness().is_async() { + if !span.from_expansion() && fn_kind.asyncness().is_async() && !is_def_id_trait_method(cx, def_id) { let mut visitor = AsyncFnVisitor { cx, found_await: false, diff --git a/clippy_lints/src/upper_case_acronyms.rs b/clippy_lints/src/upper_case_acronyms.rs index 1d2d3eb12e11..4df1e3299ed9 100644 --- a/clippy_lints/src/upper_case_acronyms.rs +++ b/clippy_lints/src/upper_case_acronyms.rs @@ -65,7 +65,7 @@ fn correct_ident(ident: &str) -> String { let mut ident = fragments.clone().next().unwrap(); for (ref prev, ref curr) in fragments.tuple_windows() { - if [prev, curr] + if <[&String; 2]>::from((prev, curr)) .iter() .all(|s| s.len() == 1 && s.chars().next().unwrap().is_ascii_uppercase()) { diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 28c3fc859e33..b6c11cfb3556 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -1,16 +1,17 @@ -use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; +use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::is_ty_alias; -use clippy_utils::source::{snippet, snippet_with_context}; +use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_copy, is_type_diagnostic_item, same_type_and_consts}; use clippy_utils::{get_parent_expr, is_trait_method, match_def_path, path_to_local, paths}; use if_chain::if_chain; use rustc_errors::Applicability; +use rustc_hir::def_id::DefId; use rustc_hir::{BindingAnnotation, Expr, ExprKind, HirId, MatchSource, Node, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::sym; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does @@ -43,6 +44,64 @@ pub struct UselessConversion { impl_lint_pass!(UselessConversion => [USELESS_CONVERSION]); +enum MethodOrFunction { + Method, + Function, +} + +impl MethodOrFunction { + /// Maps the argument position in `pos` to the parameter position. + /// For methods, `self` is skipped. + fn param_pos(self, pos: usize) -> usize { + match self { + MethodOrFunction::Method => pos + 1, + MethodOrFunction::Function => pos, + } + } +} + +/// Returns the span of the `IntoIterator` trait bound in the function pointed to by `fn_did` +fn into_iter_bound(cx: &LateContext<'_>, fn_did: DefId, into_iter_did: DefId, param_index: u32) -> Option { + cx.tcx + .predicates_of(fn_did) + .predicates + .iter() + .find_map(|&(ref pred, span)| { + if let ty::ClauseKind::Trait(tr) = pred.kind().skip_binder() + && tr.def_id() == into_iter_did + && tr.self_ty().is_param(param_index) + { + Some(span) + } else { + None + } + }) +} + +/// Extracts the receiver of a `.into_iter()` method call. +fn into_iter_call<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>) -> Option<&'hir Expr<'hir>> { + if let ExprKind::MethodCall(name, recv, _, _) = expr.kind + && is_trait_method(cx, expr, sym::IntoIterator) + && name.ident.name == sym::into_iter + { + Some(recv) + } else { + None + } +} + +/// Same as [`into_iter_call`], but tries to look for the innermost `.into_iter()` call, e.g.: +/// `foo.into_iter().into_iter()` +/// ^^^ we want this expression +fn into_iter_deep_call<'hir>(cx: &LateContext<'_>, mut expr: &'hir Expr<'hir>) -> (&'hir Expr<'hir>, usize) { + let mut depth = 0; + while let Some(recv) = into_iter_call(cx, expr) { + expr = recv; + depth += 1; + } + (expr, depth) +} + #[expect(clippy::too_many_lines)] impl<'tcx> LateLintPass<'tcx> for UselessConversion { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { @@ -82,9 +141,59 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { ); } } - if is_trait_method(cx, e, sym::IntoIterator) && name.ident.name == sym::into_iter { - if get_parent_expr(cx, e).is_some() && - let Some(id) = path_to_local(recv) && + if let Some(into_iter_recv) = into_iter_call(cx, e) + // Make sure that there is no parent expression, or if there is, make sure it's not a `.into_iter()` call. + // The reason for that is that we only want to lint once (the outermost call) + // in cases like `foo.into_iter().into_iter()` + && get_parent_expr(cx, e) + .and_then(|parent| into_iter_call(cx, parent)) + .is_none() + { + if let Some(parent) = get_parent_expr(cx, e) { + let parent_fn = match parent.kind { + ExprKind::Call(recv, args) if let ExprKind::Path(ref qpath) = recv.kind => { + cx.qpath_res(qpath, recv.hir_id).opt_def_id() + .map(|did| (did, args, MethodOrFunction::Function)) + } + ExprKind::MethodCall(.., args, _) => { + cx.typeck_results().type_dependent_def_id(parent.hir_id) + .map(|did| (did, args, MethodOrFunction::Method)) + } + _ => None, + }; + + if let Some((parent_fn_did, args, kind)) = parent_fn + && let Some(into_iter_did) = cx.tcx.get_diagnostic_item(sym::IntoIterator) + && let sig = cx.tcx.fn_sig(parent_fn_did).skip_binder().skip_binder() + && let Some(arg_pos) = args.iter().position(|x| x.hir_id == e.hir_id) + && let Some(&into_iter_param) = sig.inputs().get(kind.param_pos(arg_pos)) + && let ty::Param(param) = into_iter_param.kind() + && let Some(span) = into_iter_bound(cx, parent_fn_did, into_iter_did, param.index) + { + // Get the "innermost" `.into_iter()` call, e.g. given this expression: + // `foo.into_iter().into_iter()` + // ^^^ + let (into_iter_recv, depth) = into_iter_deep_call(cx, into_iter_recv); + + let plural = if depth == 0 { "" } else { "s" }; + let mut applicability = Applicability::MachineApplicable; + let sugg = snippet_with_applicability(cx, into_iter_recv.span.source_callsite(), "", &mut applicability).into_owned(); + span_lint_and_then(cx, USELESS_CONVERSION, e.span, "explicit call to `.into_iter()` in function argument accepting `IntoIterator`", |diag| { + diag.span_suggestion( + e.span, + format!("consider removing the `.into_iter()`{plural}"), + sugg, + applicability, + ); + diag.span_note(span, "this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`"); + }); + + // Early return to avoid linting again with contradicting suggestions + return; + } + } + + if let Some(id) = path_to_local(recv) && let Node::Pat(pat) = cx.tcx.hir().get(id) && let PatKind::Binding(ann, ..) = pat.kind && ann != BindingAnnotation::MUT diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 35f40830681d..f1d05c7529be 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -21,6 +21,7 @@ const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[ "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", + "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", @@ -34,6 +35,7 @@ const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[ "CamelCase", ]; const DEFAULT_DISALLOWED_NAMES: &[&str] = &["foo", "baz", "quux"]; +const DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS: &[&str] = &["i", "j", "x", "y", "z", "w", "n"]; /// Holds information used by `MISSING_ENFORCED_IMPORT_RENAMES` lint. #[derive(Clone, Debug, Deserialize)] @@ -288,11 +290,11 @@ define_Conf! { /// arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"] /// ``` (arithmetic_side_effects_allowed_unary: rustc_data_structures::fx::FxHashSet = <_>::default()), - /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX, UNNECESSARY_BOX_RETURNS. + /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX, UNNECESSARY_BOX_RETURNS, SINGLE_CALL_FN. /// /// Suppress lints whenever the suggested change would cause breakage for other crates. (avoid_breaking_exported_api: bool = true), - /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN. + /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD. /// /// The minimum rust version that the project supports (msrv: Option = None), @@ -305,6 +307,10 @@ define_Conf! { /// /// The maximum cognitive complexity a function can have (cognitive_complexity_threshold: u64 = 25), + /// Lint: EXCESSIVE_NESTING. + /// + /// The maximum amount of nesting a block can reside in + (excessive_nesting_threshold: u64 = 0), /// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY. /// /// Use the Cognitive Complexity lint instead. @@ -382,6 +388,10 @@ define_Conf! { /// /// The maximum allowed size for arrays on the stack (array_size_threshold: u64 = 512_000), + /// Lint: LARGE_STACK_FRAMES. + /// + /// The maximum allowed stack size for functions in bytes + (stack_size_threshold: u64 = 512_000), /// Lint: VEC_BOX. /// /// The size of the boxed type in bytes, where boxing in a `Vec` is allowed @@ -514,6 +524,33 @@ define_Conf! { /// /// The byte size a `T` in `Box` can have, below which it triggers the `clippy::unnecessary_box` lint (unnecessary_box_size: u64 = 128), + /// Lint: MODULE_INCEPTION. + /// + /// Whether to allow module inception if it's not public. + (allow_private_module_inception: bool = false), + /// Lint: MIN_IDENT_CHARS. + /// + /// Allowed names below the minimum allowed characters. The value `".."` can be used as part of + /// the list to indicate, that the configured values should be appended to the default + /// configuration of Clippy. By default, any configuration will replace the default value. + (allowed_idents_below_min_chars: rustc_data_structures::fx::FxHashSet = + super::DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS.iter().map(ToString::to_string).collect()), + /// Lint: MIN_IDENT_CHARS. + /// + /// Minimum chars an ident can have, anything below or equal to this will be linted. + (min_ident_chars_threshold: u64 = 1), + /// Lint: UNDOCUMENTED_UNSAFE_BLOCKS. + /// + /// Whether to accept a safety comment to be placed above the statement containing the `unsafe` block + (accept_comment_above_statement: bool = false), + /// Lint: UNDOCUMENTED_UNSAFE_BLOCKS. + /// + /// Whether to accept a safety comment to be placed above the attributes for the `unsafe` block + (accept_comment_above_attributes: bool = false), + /// Lint: UNNECESSARY_RAW_STRING_HASHES. + /// + /// Whether to allow `r#""#` when `r""` can be used + (allow_one_hash_in_raw_strings: bool = false), } /// Search for the configuration file. @@ -581,6 +618,12 @@ pub fn read(sess: &Session, path: &Path) -> TryConf { Ok(mut conf) => { extend_vec_if_indicator_present(&mut conf.conf.doc_valid_idents, DEFAULT_DOC_VALID_IDENTS); extend_vec_if_indicator_present(&mut conf.conf.disallowed_names, DEFAULT_DISALLOWED_NAMES); + // TODO: THIS SHOULD BE TESTED, this comment will be gone soon + if conf.conf.allowed_idents_below_min_chars.contains(&"..".to_owned()) { + conf.conf + .allowed_idents_below_min_chars + .extend(DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS.iter().map(ToString::to_string)); + } conf }, diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 71f6c9909ddd..e222a5448c9c 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -1,3 +1,4 @@ +pub mod almost_standard_lint_formulation; pub mod clippy_lints_internal; pub mod collapsible_calls; pub mod compiler_lint_functions; diff --git a/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs b/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs new file mode 100644 index 000000000000..570a88a0ed2b --- /dev/null +++ b/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs @@ -0,0 +1,87 @@ +use crate::utils::internal_lints::lint_without_lint_pass::is_lint_ref_type; +use clippy_utils::diagnostics::span_lint_and_help; +use regex::Regex; +use rustc_ast as ast; +use rustc_hir::{Item, ItemKind, Mutability}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; + +declare_clippy_lint! { + /// ### What it does + /// Checks if lint formulations have a standardized format. + /// + /// ### Why is this bad? + /// It's not neccessarily bad, but we try to enforce a standard in Clippy. + /// + /// ### Example + /// `Checks for use...` can be written as `Checks for usage...` . + pub ALMOST_STANDARD_LINT_FORMULATION, + internal, + "lint formulations must have a standardized format." +} + +impl_lint_pass!(AlmostStandardFormulation => [ALMOST_STANDARD_LINT_FORMULATION]); + +pub struct AlmostStandardFormulation { + standard_formulations: Vec>, +} + +#[derive(Debug)] +struct StandardFormulations<'a> { + wrong_pattern: Regex, + correction: &'a str, +} + +impl AlmostStandardFormulation { + pub fn new() -> Self { + let standard_formulations = vec![StandardFormulations { + wrong_pattern: Regex::new("^(Check for|Detects? uses?)").unwrap(), + correction: "Checks for", + }]; + Self { standard_formulations } + } +} + +impl<'tcx> LateLintPass<'tcx> for AlmostStandardFormulation { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { + let mut check_next = false; + if let ItemKind::Static(ty, Mutability::Not, _) = item.kind { + let lines = cx + .tcx + .hir() + .attrs(item.hir_id()) + .iter() + .filter_map(|attr| ast::Attribute::doc_str(attr).map(|sym| (sym, attr))); + if is_lint_ref_type(cx, ty) { + for (line, attr) in lines { + let cur_line = line.as_str().trim(); + if check_next && !cur_line.is_empty() { + for formulation in &self.standard_formulations { + let starts_with_correct_formulation = cur_line.starts_with(formulation.correction); + if !starts_with_correct_formulation && formulation.wrong_pattern.is_match(cur_line) { + if let Some(ident) = attr.ident() { + span_lint_and_help( + cx, + ALMOST_STANDARD_LINT_FORMULATION, + ident.span, + "non-standard lint formulation", + None, + &format!("try using `{}` instead", formulation.correction), + ); + } + return; + } + } + return; + } else if cur_line.contains("What it does") { + check_next = true; + } else if cur_line.contains("Why is this bad") { + // Formulation documentation is done. Can add check to ensure that missing formulation is added + // and add a check if it matches no accepted formulation + return; + } + } + } + } + } +} diff --git a/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs b/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs index f8978e30a8e2..dced9fcf9abd 100644 --- a/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs +++ b/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs @@ -75,7 +75,7 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol { for &module in &[&paths::KW_MODULE, &paths::SYM_MODULE] { for def_id in def_path_def_ids(cx, module) { - for item in cx.tcx.module_children(def_id).iter() { + for item in cx.tcx.module_children(def_id) { if_chain! { if let Res::Def(DefKind::Const, item_def_id) = item.res; let ty = cx.tcx.type_of(item_def_id).subst_identity(); diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs index 7a1cd3effaef..107a62806a82 100644 --- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -104,6 +104,8 @@ const APPLICABILITY_UNRESOLVED_STR: &str = "Unresolved"; /// The version that will be displayed if none has been defined const VERSION_DEFAULT_STR: &str = "Unknown"; +const CHANGELOG_PATH: &str = "../CHANGELOG.md"; + declare_clippy_lint! { /// ### What it does /// Collects metadata about clippy lints for the website. @@ -195,8 +197,14 @@ This lint has the following configuration variables: fn get_markdown_docs(&self) -> String { format!( - "## Lint Configuration Options\n|
Option
| Default Value |\n|--|--|\n{}\n\n{}\n", - self.configs_to_markdown(ClippyConfiguration::to_markdown_table_entry), + r#"# Lint Configuration Options + +The following list shows each configuration option, along with a description, its default value, an example +and lints affected. + +--- + +{}"#, self.configs_to_markdown(ClippyConfiguration::to_markdown_paragraph), ) } @@ -254,6 +262,22 @@ Please use that command to update the file and do not edit it by hand. self.get_markdown_docs(), ) .unwrap(); + + // Write configuration links to CHANGELOG.md + let mut changelog = std::fs::read_to_string(CHANGELOG_PATH).unwrap(); + let mut changelog_file = OpenOptions::new().read(true).write(true).open(CHANGELOG_PATH).unwrap(); + + if let Some(position) = changelog.find("") { + // I know this is kinda wasteful, we just don't have regex on `clippy_lints` so... this is the best + // we can do AFAIK. + changelog = changelog[..position].to_string(); + } + writeln!( + changelog_file, + "{changelog}\n{}\n", + self.configs_to_markdown(ClippyConfiguration::to_markdown_link) + ) + .unwrap(); } } diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index d3ea7cafa80c..fb08256931f6 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -12,6 +12,9 @@ fn to_kebab(config_name: &str) -> String { config_name.replace('_', "-") } +#[cfg(feature = "internal")] +const BOOK_CONFIGS_PATH: &str = "https://doc.rust-lang.org/clippy/lint_configuration.html"; + // ================================================================== // Configuration // ================================================================== @@ -51,7 +54,7 @@ impl ClippyConfiguration { #[cfg(feature = "internal")] fn to_markdown_paragraph(&self) -> String { format!( - "### {}\n{}\n\n**Default Value:** `{}` (`{}`)\n\n{}\n\n", + "## `{}`\n{}\n\n**Default Value:** `{}` (`{}`)\n\n---\n**Affected lints:**\n{}\n\n", self.name, self.doc .lines() @@ -62,14 +65,13 @@ impl ClippyConfiguration { self.lints .iter() .map(|name| name.to_string().split_whitespace().next().unwrap().to_string()) - .map(|name| format!("* [{name}](https://rust-lang.github.io/rust-clippy/master/index.html#{name})")) + .map(|name| format!("* [`{name}`](https://rust-lang.github.io/rust-clippy/master/index.html#{name})")) .join("\n"), ) } - #[cfg(feature = "internal")] - fn to_markdown_table_entry(&self) -> String { - format!("| [{}](#{}) | `{}` |", self.name, self.name, self.default) + fn to_markdown_link(&self) -> String { + format!("[`{}`]: {BOOK_CONFIGS_PATH}#{}", self.name, self.name) } } diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index 7329e508106d..2a594e750b9b 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -1,26 +1,32 @@ +use std::ops::ControlFlow; + use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::higher; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_copy; +use clippy_utils::visitors::for_each_local_use_after_expr; +use clippy_utils::{get_parent_expr, higher, is_trait_method}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability}; +use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Node, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; +use rustc_span::sym; #[expect(clippy::module_name_repetitions)] -#[derive(Copy, Clone)] +#[derive(Clone)] pub struct UselessVec { pub too_large_for_stack: u64, + pub msrv: Msrv, } declare_clippy_lint! { /// ### What it does - /// Checks for usage of `&vec![..]` when using `&[..]` would + /// Checks for usage of `vec![..]` when using `[..]` would /// be possible. /// /// ### Why is this bad? @@ -46,16 +52,73 @@ declare_clippy_lint! { impl_lint_pass!(UselessVec => [USELESS_VEC]); +fn adjusts_to_slice(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { + matches!(cx.typeck_results().expr_ty_adjusted(e).kind(), ty::Ref(_, ty, _) if ty.is_slice()) +} + +/// Checks if the given expression is a method call to a `Vec` method +/// that also exists on slices. If this returns true, it means that +/// this expression does not actually require a `Vec` and could just work with an array. +fn is_allowed_vec_method(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { + const ALLOWED_METHOD_NAMES: &[&str] = &["len", "as_ptr", "is_empty"]; + + if let ExprKind::MethodCall(path, ..) = e.kind { + ALLOWED_METHOD_NAMES.contains(&path.ident.name.as_str()) + } else { + is_trait_method(cx, e, sym::IntoIterator) + } +} + impl<'tcx> LateLintPass<'tcx> for UselessVec { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - // search for `&vec![_]` expressions where the adjusted type is `&[_]` + // search for `&vec![_]` or `vec![_]` expressions where the adjusted type is `&[_]` if_chain! { - if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(expr).kind(); - if let ty::Slice(..) = ty.kind(); - if let ExprKind::AddrOf(BorrowKind::Ref, mutability, addressee) = expr.kind; - if let Some(vec_args) = higher::VecArgs::hir(cx, addressee); + if adjusts_to_slice(cx, expr); + if let Some(vec_args) = higher::VecArgs::hir(cx, expr.peel_borrows()); then { - self.check_vec_macro(cx, &vec_args, mutability, expr.span); + let (suggest_slice, span) = if let ExprKind::AddrOf(BorrowKind::Ref, mutability, _) = expr.kind { + // `expr` is `&vec![_]`, so suggest `&[_]` (or `&mut[_]` resp.) + (SuggestedType::SliceRef(mutability), expr.span) + } else { + // `expr` is the `vec![_]` expansion, so suggest `[_]` + // and also use the span of the actual `vec![_]` expression + (SuggestedType::Array, expr.span.ctxt().outer_expn_data().call_site) + }; + + self.check_vec_macro(cx, &vec_args, span, suggest_slice); + } + } + + // search for `let foo = vec![_]` expressions where all uses of `foo` + // adjust to slices or call a method that exist on slices (e.g. len) + if let Some(vec_args) = higher::VecArgs::hir(cx, expr) + && let Node::Local(local) = cx.tcx.hir().get_parent(expr.hir_id) + // for now ignore locals with type annotations. + // this is to avoid compile errors when doing the suggestion here: let _: Vec<_> = vec![..]; + && local.ty.is_none() + && let PatKind::Binding(_, id, ..) = local.pat.kind + && is_copy(cx, vec_type(cx.typeck_results().expr_ty_adjusted(expr))) + { + let only_slice_uses = for_each_local_use_after_expr(cx, id, expr.hir_id, |expr| { + // allow indexing into a vec and some set of allowed method calls that exist on slices, too + if let Some(parent) = get_parent_expr(cx, expr) + && (adjusts_to_slice(cx, expr) + || matches!(parent.kind, ExprKind::Index(..)) + || is_allowed_vec_method(cx, parent)) + { + ControlFlow::Continue(()) + } else { + ControlFlow::Break(()) + } + }).is_continue(); + + if only_slice_uses { + self.check_vec_macro( + cx, + &vec_args, + expr.span.ctxt().outer_expn_data().call_site, + SuggestedType::Array + ); } } @@ -63,25 +126,36 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec { if_chain! { if let Some(higher::ForLoop { arg, .. }) = higher::ForLoop::hir(expr); if let Some(vec_args) = higher::VecArgs::hir(cx, arg); - if is_copy(cx, vec_type(cx.typeck_results().expr_ty_adjusted(arg))); + if self.msrv.meets(msrvs::ARRAY_INTO_ITERATOR); then { // report the error around the `vec!` not inside `:` let span = arg.span.ctxt().outer_expn_data().call_site; - self.check_vec_macro(cx, &vec_args, Mutability::Not, span); + self.check_vec_macro(cx, &vec_args, span, SuggestedType::Array); } } } + + extract_msrv_attr!(LateContext); +} + +#[derive(Copy, Clone)] +enum SuggestedType { + /// Suggest using a slice `&[..]` / `&mut [..]` + SliceRef(Mutability), + /// Suggest using an array: `[..]` + Array, } impl UselessVec { fn check_vec_macro<'tcx>( - self, + &mut self, cx: &LateContext<'tcx>, vec_args: &higher::VecArgs<'tcx>, - mutability: Mutability, span: Span, + suggest_slice: SuggestedType, ) { let mut applicability = Applicability::MachineApplicable; + let snippet = match *vec_args { higher::VecArgs::Repeat(elem, len) => { if let Some(Constant::Int(len_constant)) = constant(cx, cx.typeck_results(), len) { @@ -90,21 +164,13 @@ impl UselessVec { return; } - match mutability { - Mutability::Mut => { - format!( - "&mut [{}; {}]", - snippet_with_applicability(cx, elem.span, "elem", &mut applicability), - snippet_with_applicability(cx, len.span, "len", &mut applicability) - ) - }, - Mutability::Not => { - format!( - "&[{}; {}]", - snippet_with_applicability(cx, elem.span, "elem", &mut applicability), - snippet_with_applicability(cx, len.span, "len", &mut applicability) - ) - }, + let elem = snippet_with_applicability(cx, elem.span, "elem", &mut applicability); + let len = snippet_with_applicability(cx, len.span, "len", &mut applicability); + + match suggest_slice { + SuggestedType::SliceRef(Mutability::Mut) => format!("&mut [{elem}; {len}]"), + SuggestedType::SliceRef(Mutability::Not) => format!("&[{elem}; {len}]"), + SuggestedType::Array => format!("[{elem}; {len}]"), } } else { return; @@ -116,22 +182,24 @@ impl UselessVec { return; } let span = args[0].span.to(last.span); + let args = snippet_with_applicability(cx, span, "..", &mut applicability); - match mutability { - Mutability::Mut => { - format!( - "&mut [{}]", - snippet_with_applicability(cx, span, "..", &mut applicability) - ) + match suggest_slice { + SuggestedType::SliceRef(Mutability::Mut) => { + format!("&mut [{args}]") }, - Mutability::Not => { - format!("&[{}]", snippet_with_applicability(cx, span, "..", &mut applicability)) + SuggestedType::SliceRef(Mutability::Not) => { + format!("&[{args}]") + }, + SuggestedType::Array => { + format!("[{args}]") }, } } else { - match mutability { - Mutability::Mut => "&mut []".into(), - Mutability::Not => "&[]".into(), + match suggest_slice { + SuggestedType::SliceRef(Mutability::Mut) => "&mut []".to_owned(), + SuggestedType::SliceRef(Mutability::Not) => "&[]".to_owned(), + SuggestedType::Array => "[]".to_owned(), } } }, @@ -142,7 +210,13 @@ impl UselessVec { USELESS_VEC, span, "useless use of `vec!`", - "you can use a slice directly", + &format!( + "you can use {} directly", + match suggest_slice { + SuggestedType::SliceRef(_) => "a slice", + SuggestedType::Array => "an array", + } + ), snippet, applicability, ); diff --git a/clippy_lints/src/visibility.rs b/clippy_lints/src/visibility.rs new file mode 100644 index 000000000000..43248bccc13d --- /dev/null +++ b/clippy_lints/src/visibility.rs @@ -0,0 +1,131 @@ +use clippy_utils::{diagnostics::span_lint_and_sugg, source::snippet_opt}; +use rustc_ast::ast::{Item, VisibilityKind}; +use rustc_errors::Applicability; +use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::{symbol::kw, Span}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `pub(self)` and `pub(in self)`. + /// + /// ### Why is this bad? + /// It's unnecessary, omitting the `pub` entirely will give the same results. + /// + /// ### Example + /// ```rust,ignore + /// pub(self) type OptBox = Option>; + /// ``` + /// Use instead: + /// ```rust,ignore + /// type OptBox = Option>; + /// ``` + #[clippy::version = "1.72.0"] + pub NEEDLESS_PUB_SELF, + style, + "checks for usage of `pub(self)` and `pub(in self)`." +} +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `pub()` with `in`. + /// + /// ### Why is this bad? + /// Consistency. Use it or don't, just be consistent about it. + /// + /// Also see the `pub_without_shorthand` lint for an alternative. + /// + /// ### Example + /// ```rust,ignore + /// pub(super) type OptBox = Option>; + /// ``` + /// Use instead: + /// ```rust,ignore + /// pub(in super) type OptBox = Option>; + /// ``` + #[clippy::version = "1.72.0"] + pub PUB_WITH_SHORTHAND, + restriction, + "disallows usage of `pub()`, without `in`" +} +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `pub()` without `in`. + /// + /// Note: As you cannot write a module's path in `pub()`, this will only trigger on + /// `pub(super)` and the like. + /// + /// ### Why is this bad? + /// Consistency. Use it or don't, just be consistent about it. + /// + /// Also see the `pub_with_shorthand` lint for an alternative. + /// + /// ### Example + /// ```rust,ignore + /// pub(in super) type OptBox = Option>; + /// ``` + /// Use instead: + /// ```rust,ignore + /// pub(super) type OptBox = Option>; + /// ``` + #[clippy::version = "1.72.0"] + pub PUB_WITHOUT_SHORTHAND, + restriction, + "disallows usage of `pub(in )` with `in`" +} +declare_lint_pass!(Visibility => [NEEDLESS_PUB_SELF, PUB_WITH_SHORTHAND, PUB_WITHOUT_SHORTHAND]); + +impl EarlyLintPass for Visibility { + fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { + if !in_external_macro(cx.sess(), item.span) + && let VisibilityKind::Restricted { path, shorthand, .. } = &item.vis.kind + { + if **path == kw::SelfLower && let Some(false) = is_from_proc_macro(cx, item.vis.span) { + span_lint_and_sugg( + cx, + NEEDLESS_PUB_SELF, + item.vis.span, + &format!("unnecessary `pub({}self)`", if *shorthand { "" } else { "in " }), + "remove it", + String::new(), + Applicability::MachineApplicable, + ); + } + + if (**path == kw::Super || **path == kw::SelfLower || **path == kw::Crate) + && !*shorthand + && let [.., last] = &*path.segments + && let Some(false) = is_from_proc_macro(cx, item.vis.span) + { + span_lint_and_sugg( + cx, + PUB_WITHOUT_SHORTHAND, + item.vis.span, + "usage of `pub` with `in`", + "remove it", + format!("pub({})", last.ident), + Applicability::MachineApplicable, + ); + } + + if *shorthand + && let [.., last] = &*path.segments + && let Some(false) = is_from_proc_macro(cx, item.vis.span) + { + span_lint_and_sugg( + cx, + PUB_WITH_SHORTHAND, + item.vis.span, + "usage of `pub` without `in`", + "add it", + format!("pub(in {})", last.ident), + Applicability::MachineApplicable, + ); + } + } + } +} + +fn is_from_proc_macro(cx: &EarlyContext<'_>, span: Span) -> Option { + snippet_opt(cx, span).map(|s| !s.starts_with("pub")) +} diff --git a/clippy_test_deps/Cargo.toml b/clippy_test_deps/Cargo.toml new file mode 100644 index 000000000000..362c08e0d779 --- /dev/null +++ b/clippy_test_deps/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "clippy_test_deps" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +clippy_utils = { path = "../clippy_utils" } +derive-new = "0.5" +if_chain = "1.0" +itertools = "0.10.1" +quote = "1.0" +serde = { version = "1.0.125", features = ["derive"] } +syn = { version = "2.0", features = ["full"] } +futures = "0.3" +parking_lot = "0.12" +tokio = { version = "1", features = ["io-util"] } +regex = "1.5" +clippy_lints = { path = "../clippy_lints" } + +[features] +internal = ["clippy_lints/internal"] diff --git a/clippy_test_deps/src/lib.rs b/clippy_test_deps/src/lib.rs new file mode 100644 index 000000000000..7d12d9af8195 --- /dev/null +++ b/clippy_test_deps/src/lib.rs @@ -0,0 +1,14 @@ +pub fn add(left: usize, right: usize) -> usize { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs index 9edaae853734..c6d0b654f57b 100644 --- a/clippy_utils/src/check_proc_macro.rs +++ b/clippy_utils/src/check_proc_macro.rs @@ -12,25 +12,33 @@ //! code was written, and check if the span contains that text. Note this will only work correctly //! if the span is not from a `macro_rules` based macro. -use rustc_ast::ast::{IntTy, LitIntType, LitKind, StrStyle, UintTy}; +use rustc_ast::{ + ast::{AttrKind, Attribute, IntTy, LitIntType, LitKind, StrStyle, UintTy}, + token::CommentKind, + AttrStyle, +}; use rustc_hir::{ intravisit::FnKind, Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, HirId, - Impl, ImplItem, ImplItemKind, IsAuto, Item, ItemKind, LoopSource, MatchSource, Node, QPath, TraitItem, - TraitItemKind, UnOp, UnsafeSource, Unsafety, Variant, VariantData, YieldSource, + Impl, ImplItem, ImplItemKind, IsAuto, Item, ItemKind, LoopSource, MatchSource, MutTy, Node, QPath, TraitItem, + TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Unsafety, Variant, VariantData, YieldSource, }; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; -use rustc_span::{Span, Symbol}; +use rustc_span::{symbol::Ident, Span, Symbol}; use rustc_target::spec::abi::Abi; /// The search pattern to look for. Used by `span_matches_pat` -#[derive(Clone, Copy)] +#[derive(Clone)] pub enum Pat { /// A single string. Str(&'static str), + /// A single string. + OwnedStr(String), /// Any of the given strings. MultiStr(&'static [&'static str]), + /// Any of the given strings. + OwnedMultiStr(Vec), /// The string representation of the symbol. Sym(Symbol), /// Any decimal or hexadecimal digit depending on the location. @@ -51,12 +59,16 @@ fn span_matches_pat(sess: &Session, span: Span, start_pat: Pat, end_pat: Pat) -> let end_str = s.trim_end_matches(|c: char| c.is_whitespace() || c == ')' || c == ','); (match start_pat { Pat::Str(text) => start_str.starts_with(text), + Pat::OwnedStr(text) => start_str.starts_with(&text), 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), } && match end_pat { Pat::Str(text) => end_str.ends_with(text), + Pat::OwnedStr(text) => end_str.starts_with(&text), Pat::MultiStr(texts) => texts.iter().any(|s| start_str.ends_with(s)), + Pat::OwnedMultiStr(texts) => texts.iter().any(|s| start_str.starts_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), }) @@ -271,14 +283,79 @@ fn fn_kind_pat(tcx: TyCtxt<'_>, kind: &FnKind<'_>, body: &Body<'_>, hir_id: HirI (start_pat, end_pat) } -pub trait WithSearchPat { +fn attr_search_pat(attr: &Attribute) -> (Pat, Pat) { + match attr.kind { + AttrKind::Normal(..) => { + let mut pat = if matches!(attr.style, AttrStyle::Outer) { + (Pat::Str("#["), Pat::Str("]")) + } else { + (Pat::Str("#!["), Pat::Str("]")) + }; + + if let Some(ident) = attr.ident() && let Pat::Str(old_pat) = pat.0 { + // TODO: I feel like it's likely we can use `Cow` instead but this will require quite a bit of + // refactoring + // NOTE: This will likely have false positives, like `allow = 1` + pat.0 = Pat::OwnedMultiStr(vec![ident.to_string(), old_pat.to_owned()]); + pat.1 = Pat::Str(""); + } + + pat + }, + AttrKind::DocComment(_kind @ CommentKind::Line, ..) => { + if matches!(attr.style, AttrStyle::Outer) { + (Pat::Str("///"), Pat::Str("")) + } else { + (Pat::Str("//!"), Pat::Str("")) + } + }, + AttrKind::DocComment(_kind @ CommentKind::Block, ..) => { + if matches!(attr.style, AttrStyle::Outer) { + (Pat::Str("/**"), Pat::Str("*/")) + } else { + (Pat::Str("/*!"), Pat::Str("*/")) + } + }, + } +} + +fn ty_search_pat(ty: &Ty<'_>) -> (Pat, Pat) { + match ty.kind { + TyKind::Slice(..) | TyKind::Array(..) => (Pat::Str("["), Pat::Str("]")), + TyKind::Ptr(MutTy { mutbl, ty }) => ( + if mutbl.is_mut() { + Pat::Str("*const") + } else { + Pat::Str("*mut") + }, + ty_search_pat(ty).1, + ), + TyKind::Ref(_, MutTy { ty, .. }) => (Pat::Str("&"), ty_search_pat(ty).1), + TyKind::BareFn(bare_fn) => ( + Pat::OwnedStr(format!("{}{} fn", bare_fn.unsafety.prefix_str(), bare_fn.abi.name())), + ty_search_pat(ty).1, + ), + TyKind::Never => (Pat::Str("!"), Pat::Str("")), + TyKind::Tup(..) => (Pat::Str("("), Pat::Str(")")), + TyKind::OpaqueDef(..) => (Pat::Str("impl"), Pat::Str("")), + TyKind::Path(qpath) => qpath_search_pat(&qpath), + // NOTE: This is missing `TraitObject`. It always return true then. + _ => (Pat::Str(""), Pat::Str("")), + } +} + +fn ident_search_pat(ident: Ident) -> (Pat, Pat) { + (Pat::OwnedStr(ident.name.as_str().to_owned()), Pat::Str("")) +} + +pub trait WithSearchPat<'cx> { type Context: LintContext; fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat); fn span(&self) -> Span; } macro_rules! impl_with_search_pat { ($cx:ident: $ty:ident with $fn:ident $(($tcx:ident))?) => { - impl<'cx> WithSearchPat for $ty<'cx> { + impl<'cx> WithSearchPat<'cx> for $ty<'cx> { type Context = $cx<'cx>; #[allow(unused_variables)] fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat) { @@ -297,8 +374,9 @@ impl_with_search_pat!(LateContext: TraitItem with trait_item_search_pat); impl_with_search_pat!(LateContext: ImplItem with impl_item_search_pat); impl_with_search_pat!(LateContext: FieldDef with field_def_search_pat); impl_with_search_pat!(LateContext: Variant with variant_search_pat); +impl_with_search_pat!(LateContext: Ty with ty_search_pat); -impl<'cx> WithSearchPat for (&FnKind<'cx>, &Body<'cx>, HirId, Span) { +impl<'cx> WithSearchPat<'cx> for (&FnKind<'cx>, &Body<'cx>, HirId, Span) { type Context = LateContext<'cx>; fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat) { @@ -310,11 +388,37 @@ impl<'cx> WithSearchPat for (&FnKind<'cx>, &Body<'cx>, HirId, Span) { } } +// `Attribute` does not have the `hir` associated lifetime, so we cannot use the macro +impl<'cx> WithSearchPat<'cx> for &'cx Attribute { + type Context = LateContext<'cx>; + + fn search_pat(&self, _cx: &Self::Context) -> (Pat, Pat) { + attr_search_pat(self) + } + + fn span(&self) -> Span { + self.span + } +} + +// `Ident` does not have the `hir` associated lifetime, so we cannot use the macro +impl<'cx> WithSearchPat<'cx> for Ident { + type Context = LateContext<'cx>; + + fn search_pat(&self, _cx: &Self::Context) -> (Pat, Pat) { + ident_search_pat(*self) + } + + fn span(&self) -> Span { + self.span + } +} + /// Checks if the item likely came from a proc-macro. /// /// This should be called after `in_external_macro` and the initial pattern matching of the ast as /// it is significantly slower than both of those. -pub fn is_from_proc_macro(cx: &T::Context, item: &T) -> bool { +pub fn is_from_proc_macro<'cx, T: WithSearchPat<'cx>>(cx: &T::Context, item: &T) -> bool { let (start_pat, end_pat) = item.search_pat(cx); !span_matches_pat(cx.sess(), item.span(), start_pat, end_pat) } diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index cc3183759ae7..068820801dfe 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -6,7 +6,7 @@ use if_chain::if_chain; use rustc_ast::ast::{self, LitFloatType, LitKind}; use rustc_data_structures::sync::Lrc; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{BinOp, BinOpKind, Block, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp}; +use rustc_hir::{BinOp, BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp}; use rustc_lexer::tokenize; use rustc_lint::LateContext; use rustc_middle::mir; @@ -14,7 +14,7 @@ use rustc_middle::mir::interpret::Scalar; use rustc_middle::ty::{self, EarlyBinder, FloatTy, ScalarInt, Ty, TyCtxt}; use rustc_middle::ty::{List, SubstsRef}; use rustc_middle::{bug, span_bug}; -use rustc_span::symbol::Symbol; +use rustc_span::symbol::{Ident, Symbol}; use rustc_span::SyntaxContext; use std::cmp::Ordering::{self, Equal}; use std::hash::{Hash, Hasher}; @@ -22,7 +22,8 @@ use std::iter; /// A `LitKind`-like enum to fold constant `Expr`s into. #[derive(Debug, Clone)] -pub enum Constant { +pub enum Constant<'tcx> { + Adt(rustc_middle::mir::ConstantKind<'tcx>), /// A `String` (e.g., "abc"). Str(String), /// A binary string (e.g., `b"abc"`). @@ -38,20 +39,20 @@ pub enum Constant { /// `true` or `false`. Bool(bool), /// An array of constants. - Vec(Vec), + Vec(Vec>), /// Also an array, but with only one constant, repeated N times. - Repeat(Box, u64), + Repeat(Box>, u64), /// A tuple of constants. - Tuple(Vec), + Tuple(Vec>), /// A raw pointer. RawPtr(u128), /// A reference - Ref(Box), + Ref(Box>), /// A literal with syntax error. Err, } -impl PartialEq for Constant { +impl<'tcx> PartialEq for Constant<'tcx> { fn eq(&self, other: &Self) -> bool { match (self, other) { (Self::Str(ls), Self::Str(rs)) => ls == rs, @@ -80,13 +81,16 @@ impl PartialEq for Constant { } } -impl Hash for Constant { +impl<'tcx> Hash for Constant<'tcx> { fn hash(&self, state: &mut H) where H: Hasher, { std::mem::discriminant(self).hash(state); match *self { + Self::Adt(ref elem) => { + elem.hash(state); + }, Self::Str(ref s) => { s.hash(state); }, @@ -126,7 +130,7 @@ impl Hash for Constant { } } -impl Constant { +impl<'tcx> Constant<'tcx> { pub fn partial_cmp(tcx: TyCtxt<'_>, cmp_type: Ty<'_>, left: &Self, right: &Self) -> Option { match (left, right) { (Self::Str(ls), Self::Str(rs)) => Some(ls.cmp(rs)), @@ -209,7 +213,7 @@ impl Constant { } /// Parses a `LitKind` to a `Constant`. -pub fn lit_to_mir_constant(lit: &LitKind, ty: Option>) -> Constant { +pub fn lit_to_mir_constant<'tcx>(lit: &LitKind, ty: Option>) -> Constant<'tcx> { match *lit { LitKind::Str(ref is, _) => Constant::Str(is.to_string()), LitKind::Byte(b) => Constant::Int(u128::from(b)), @@ -248,7 +252,7 @@ pub fn constant<'tcx>( lcx: &LateContext<'tcx>, typeck_results: &ty::TypeckResults<'tcx>, e: &Expr<'_>, -) -> Option { +) -> Option> { ConstEvalLateContext::new(lcx, typeck_results).expr(e) } @@ -257,7 +261,7 @@ pub fn constant_with_source<'tcx>( lcx: &LateContext<'tcx>, typeck_results: &ty::TypeckResults<'tcx>, e: &Expr<'_>, -) -> Option<(Constant, ConstantSource)> { +) -> Option<(Constant<'tcx>, ConstantSource)> { let mut ctxt = ConstEvalLateContext::new(lcx, typeck_results); let res = ctxt.expr(e); res.map(|x| (x, ctxt.source)) @@ -268,7 +272,7 @@ pub fn constant_simple<'tcx>( lcx: &LateContext<'tcx>, typeck_results: &ty::TypeckResults<'tcx>, e: &Expr<'_>, -) -> Option { +) -> Option> { constant_with_source(lcx, typeck_results, e).and_then(|(c, s)| s.is_local().then_some(c)) } @@ -338,8 +342,10 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { } /// Simple constant folding: Insert an expression, get a constant or none. - pub fn expr(&mut self, e: &Expr<'_>) -> Option { + pub fn expr(&mut self, e: &Expr<'_>) -> Option> { match e.kind { + ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.lcx.tcx.hir().body(body).value), + ExprKind::DropTemps(e) => self.expr(e), ExprKind::Path(ref qpath) => self.fetch_path(qpath, e.hir_id, self.typeck_results.expr_ty(e)), ExprKind::Block(block, _) => self.block(block), ExprKind::Lit(lit) => { @@ -392,13 +398,25 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { }, ExprKind::Index(arr, index) => self.index(arr, index), ExprKind::AddrOf(_, _, inner) => self.expr(inner).map(|r| Constant::Ref(Box::new(r))), - // TODO: add other expressions. + ExprKind::Field(local_expr, ref field) => { + let result = self.expr(local_expr); + if let Some(Constant::Adt(constant)) = &self.expr(local_expr) + && let ty::Adt(adt_def, _) = constant.ty().kind() + && adt_def.is_struct() + && let Some(desired_field) = field_of_struct(*adt_def, self.lcx, *constant, field) + { + miri_to_const(self.lcx, desired_field) + } + else { + result + } + }, _ => None, } } #[expect(clippy::cast_possible_wrap)] - fn constant_not(&self, o: &Constant, ty: Ty<'_>) -> Option { + fn constant_not(&self, o: &Constant<'tcx>, ty: Ty<'_>) -> Option> { use self::Constant::{Bool, Int}; match *o { Bool(b) => Some(Bool(!b)), @@ -414,7 +432,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { } } - fn constant_negate(&self, o: &Constant, ty: Ty<'_>) -> Option { + fn constant_negate(&self, o: &Constant<'tcx>, ty: Ty<'_>) -> Option> { use self::Constant::{Int, F32, F64}; match *o { Int(value) => { @@ -433,28 +451,25 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { /// Create `Some(Vec![..])` of all constants, unless there is any /// non-constant part. - fn multi(&mut self, vec: &[Expr<'_>]) -> Option> { + fn multi(&mut self, vec: &[Expr<'_>]) -> Option>> { vec.iter().map(|elem| self.expr(elem)).collect::>() } /// Lookup a possibly constant expression from an `ExprKind::Path`. - fn fetch_path(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'tcx>) -> Option { + fn fetch_path(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'tcx>) -> Option> { let res = self.typeck_results.qpath_res(qpath, id); match res { Res::Def(DefKind::Const | DefKind::AssocConst, def_id) => { // Check if this constant is based on `cfg!(..)`, // which is NOT constant for our purposes. - if let Some(node) = self.lcx.tcx.hir().get_if_local(def_id) && - let Node::Item(&Item { - kind: ItemKind::Const(_, body_id), - .. - }) = node && - let Node::Expr(&Expr { - kind: ExprKind::Lit(_), - span, - .. - }) = self.lcx.tcx.hir().get(body_id.hir_id) && - is_direct_expn_of(span, "cfg").is_some() { + if let Some(node) = self.lcx.tcx.hir().get_if_local(def_id) + && let Node::Item(Item { kind: ItemKind::Const(_, body_id), .. }) = node + && let Node::Expr(Expr { kind: ExprKind::Lit(_), span, .. }) = self.lcx + .tcx + .hir() + .get(body_id.hir_id) + && is_direct_expn_of(*span, "cfg").is_some() + { return None; } @@ -464,23 +479,21 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { } else { EarlyBinder::bind(substs).subst(self.lcx.tcx, self.substs) }; - let result = self .lcx .tcx .const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, substs), None) .ok() .map(|val| rustc_middle::mir::ConstantKind::from_value(val, ty))?; - let result = miri_to_const(self.lcx.tcx, result)?; + let result = miri_to_const(self.lcx, result)?; self.source = ConstantSource::Constant; Some(result) }, - // FIXME: cover all usable cases. _ => None, } } - fn index(&mut self, lhs: &'_ Expr<'_>, index: &'_ Expr<'_>) -> Option { + fn index(&mut self, lhs: &'_ Expr<'_>, index: &'_ Expr<'_>) -> Option> { let lhs = self.expr(lhs); let index = self.expr(index); @@ -506,7 +519,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { } /// A block can only yield a constant if it only has one constant expression. - fn block(&mut self, block: &Block<'_>) -> Option { + fn block(&mut self, block: &Block<'_>) -> Option> { if block.stmts.is_empty() && let Some(expr) = block.expr { @@ -539,7 +552,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { } } - fn ifthenelse(&mut self, cond: &Expr<'_>, then: &Expr<'_>, otherwise: Option<&Expr<'_>>) -> Option { + fn ifthenelse(&mut self, cond: &Expr<'_>, then: &Expr<'_>, otherwise: Option<&Expr<'_>>) -> Option> { if let Some(Constant::Bool(b)) = self.expr(cond) { if b { self.expr(then) @@ -551,7 +564,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { } } - fn binop(&mut self, op: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> Option { + fn binop(&mut self, op: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> Option> { let l = self.expr(left)?; let r = self.expr(right); match (l, r) { @@ -644,23 +657,21 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { } } -pub fn miri_to_const<'tcx>(tcx: TyCtxt<'tcx>, result: mir::ConstantKind<'tcx>) -> Option { +pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::ConstantKind<'tcx>) -> Option> { use rustc_middle::mir::interpret::ConstValue; match result { - mir::ConstantKind::Val(ConstValue::Scalar(Scalar::Int(int)), _) => { - match result.ty().kind() { - ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)), - ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.assert_bits(int.size()))), - ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits( - int.try_into().expect("invalid f32 bit representation"), - ))), - ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits( - int.try_into().expect("invalid f64 bit representation"), - ))), - ty::RawPtr(_) => Some(Constant::RawPtr(int.assert_bits(int.size()))), - // FIXME: implement other conversions. - _ => None, - } + mir::ConstantKind::Val(ConstValue::Scalar(Scalar::Int(int)), _) => match result.ty().kind() { + ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)), + ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)), + ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.assert_bits(int.size()))), + ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits( + int.try_into().expect("invalid f32 bit representation"), + ))), + ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits( + int.try_into().expect("invalid f64 bit representation"), + ))), + ty::RawPtr(_) => Some(Constant::RawPtr(int.assert_bits(int.size()))), + _ => None, }, mir::ConstantKind::Val(ConstValue::Slice { data, start, end }, _) => match result.ty().kind() { ty::Ref(_, tam, _) => match tam.kind() { @@ -676,35 +687,53 @@ pub fn miri_to_const<'tcx>(tcx: TyCtxt<'tcx>, result: mir::ConstantKind<'tcx>) - _ => None, }, mir::ConstantKind::Val(ConstValue::ByRef { alloc, offset: _ }, _) => match result.ty().kind() { + ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)), ty::Array(sub_type, len) => match sub_type.kind() { - ty::Float(FloatTy::F32) => match len.kind().try_to_target_usize(tcx) { + ty::Float(FloatTy::F32) => match len.kind().try_to_target_usize(lcx.tcx) { Some(len) => alloc .inner() .inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * usize::try_from(len).unwrap())) .to_owned() .array_chunks::<4>() .map(|&chunk| Some(Constant::F32(f32::from_le_bytes(chunk)))) - .collect::>>() + .collect::>>>() .map(Constant::Vec), _ => None, }, - ty::Float(FloatTy::F64) => match len.kind().try_to_target_usize(tcx) { + ty::Float(FloatTy::F64) => match len.kind().try_to_target_usize(lcx.tcx) { Some(len) => alloc .inner() .inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * usize::try_from(len).unwrap())) .to_owned() .array_chunks::<8>() .map(|&chunk| Some(Constant::F64(f64::from_le_bytes(chunk)))) - .collect::>>() + .collect::>>>() .map(Constant::Vec), _ => None, }, - // FIXME: implement other array type conversions. _ => None, }, _ => None, }, - // FIXME: implement other conversions. _ => None, } } + +fn field_of_struct<'tcx>( + adt_def: ty::AdtDef<'tcx>, + lcx: &LateContext<'tcx>, + result: mir::ConstantKind<'tcx>, + field: &Ident, +) -> Option> { + let dc = lcx.tcx.destructure_mir_constant(lcx.param_env, result); + if let Some(dc_variant) = dc.variant + && let Some(variant) = adt_def.variants().get(dc_variant) + && let Some(field_idx) = variant.fields.iter().position(|el| el.name == field.name) + && let Some(dc_field) = dc.fields.get(field_idx) + { + Some(*dc_field) + } + else { + None + } +} diff --git a/clippy_utils/src/eager_or_lazy.rs b/clippy_utils/src/eager_or_lazy.rs index 659c693f87ae..4a845ca63b49 100644 --- a/clippy_utils/src/eager_or_lazy.rs +++ b/clippy_utils/src/eager_or_lazy.rs @@ -16,6 +16,7 @@ use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{def_id::DefId, Block, Expr, ExprKind, QPath, UnOp}; use rustc_lint::LateContext; use rustc_middle::ty; +use rustc_middle::ty::adjustment::Adjust; use rustc_span::{sym, Symbol}; use std::cmp; use std::ops; @@ -114,6 +115,20 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS if self.eagerness == ForceNoChange { return; } + + // Autoderef through a user-defined `Deref` impl can have side-effects, + // so don't suggest changing it. + if self + .cx + .typeck_results() + .expr_adjustments(e) + .iter() + .any(|adj| matches!(adj.kind, Adjust::Deref(Some(_)))) + { + self.eagerness |= NoChange; + return; + } + match e.kind { ExprKind::Call( &Expr { @@ -173,11 +188,15 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS self.eagerness = Lazy; } }, - + // Custom `Deref` impl might have side effects + ExprKind::Unary(UnOp::Deref, e) + if self.cx.typeck_results().expr_ty(e).builtin_deref(true).is_none() => + { + self.eagerness |= NoChange; + }, // Dereferences should be cheap, but dereferencing a raw pointer earlier may not be safe. ExprKind::Unary(UnOp::Deref, e) if !self.cx.typeck_results().expr_ty(e).is_unsafe_ptr() => (), ExprKind::Unary(UnOp::Deref, _) => self.eagerness |= NoChange, - ExprKind::Unary(_, e) if matches!( self.cx.typeck_results().expr_ty(e).kind(), diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 8c883445a798..727b59f1f432 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -20,6 +20,7 @@ extern crate rustc_ast; extern crate rustc_ast_pretty; extern crate rustc_attr; +extern crate rustc_const_eval; extern crate rustc_data_structures; // The `rustc_driver` crate seems to be required in order to use the `rust_ast` crate. #[allow(unused_extern_crates)] @@ -326,6 +327,18 @@ pub fn is_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) .map_or(false, |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. +pub fn is_def_id_trait_method(cx: &LateContext<'_>, def_id: LocalDefId) -> bool { + if let Some(hir_id) = cx.tcx.opt_local_def_id_to_hir_id(def_id) + && let Node::Item(item) = cx.tcx.hir().get_parent(hir_id) + && let ItemKind::Impl(imp) = item.kind + { + imp.of_trait.is_some() + } else { + false + } +} + /// Checks if the given expression is a path referring an item on the trait /// that is marked with the given diagnostic item. /// @@ -1498,7 +1511,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti && let Some(min_val) = bnd_ty.numeric_min_val(cx.tcx) && let const_val = cx.tcx.valtree_to_const_val((bnd_ty, min_val.to_valtree())) && let min_const_kind = ConstantKind::from_value(const_val, bnd_ty) - && let Some(min_const) = miri_to_const(cx.tcx, min_const_kind) + && let Some(min_const) = miri_to_const(cx, min_const_kind) && let Some(start_const) = constant(cx, cx.typeck_results(), start) { start_const == min_const @@ -1514,7 +1527,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti && let Some(max_val) = bnd_ty.numeric_max_val(cx.tcx) && let const_val = cx.tcx.valtree_to_const_val((bnd_ty, max_val.to_valtree())) && let max_const_kind = ConstantKind::from_value(const_val, bnd_ty) - && let Some(max_const) = miri_to_const(cx.tcx, max_const_kind) + && let Some(max_const) = miri_to_const(cx, max_const_kind) && let Some(end_const) = constant(cx, cx.typeck_results(), end) { end_const == max_const @@ -2396,7 +2409,7 @@ fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalDefId, f: impl Fn(&[Symbol /// Checks if the function containing the given `HirId` is a `#[test]` function /// -/// Note: Add `// compile-flags: --test` to UI tests with a `#[test]` function +/// Note: Add `//@compile-flags: --test` to UI tests with a `#[test]` function pub fn is_in_test_function(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { with_test_item_names(tcx, tcx.parent_module(id), |names| { tcx.hir() @@ -2418,7 +2431,7 @@ pub fn is_in_test_function(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { /// Checks if the item containing the given `HirId` has `#[cfg(test)]` attribute applied /// -/// Note: Add `// compile-flags: --test` to UI tests with a `#[cfg(test)]` function +/// Note: Add `//@compile-flags: --test` to UI tests with a `#[cfg(test)]` function pub fn is_in_cfg_test(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { fn is_cfg_test(attr: &Attribute) -> bool { if attr.has_name(sym::cfg) @@ -2440,7 +2453,7 @@ pub fn is_in_cfg_test(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { /// Checks whether item either has `test` attribute applied, or /// is a module with `test` in its name. /// -/// Note: Add `// compile-flags: --test` to UI tests with a `#[test]` function +/// Note: Add `//@compile-flags: --test` to UI tests with a `#[test]` function pub fn is_test_module_or_function(tcx: TyCtxt<'_>, item: &Item<'_>) -> bool { is_in_test_function(tcx, item.hir_id()) || matches!(item.kind, ItemKind::Mod(..)) diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index e4a4936ff42f..00f3abaec8a4 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -9,7 +9,7 @@ use rustc_hir::{self as hir, Expr, ExprKind, HirId, Node, QPath}; use rustc_lint::LateContext; use rustc_span::def_id::DefId; use rustc_span::hygiene::{self, MacroKind, SyntaxContext}; -use rustc_span::{sym, BytePos, ExpnData, ExpnId, ExpnKind, Span, Symbol}; +use rustc_span::{sym, BytePos, ExpnData, ExpnId, ExpnKind, Span, SpanData, Symbol}; use std::cell::RefCell; use std::ops::ControlFlow; use std::sync::atomic::{AtomicBool, Ordering}; @@ -415,8 +415,18 @@ pub fn find_format_arg_expr<'hir, 'ast>( start: &'hir Expr<'hir>, target: &'ast FormatArgument, ) -> Result<&'hir rustc_hir::Expr<'hir>, &'ast rustc_ast::Expr> { + let SpanData { + lo, + hi, + ctxt, + parent: _, + } = target.expr.span.data(); + for_each_expr(start, |expr| { - if expr.span == target.expr.span { + // When incremental compilation is enabled spans gain a parent during AST to HIR lowering, + // since we're comparing an AST span to a HIR one we need to ignore the parent field + let data = expr.span.data(); + if data.lo == lo && data.hi == hi && data.ctxt == ctxt { ControlFlow::Break(expr) } else { ControlFlow::Continue(()) diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 6f102308f0bf..3637476c4087 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -19,6 +19,8 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { + 1,71,0 { TUPLE_ARRAY_CONVERSIONS } + 1,70,0 { OPTION_IS_SOME_AND } 1,68,0 { PATH_MAIN_SEPARATOR_STR } 1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS } 1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE } @@ -28,7 +30,7 @@ msrv_aliases! { 1,52,0 { STR_SPLIT_ONCE, REM_EUCLID_CONST } 1,51,0 { BORROW_AS_PTR, SEEK_FROM_CURRENT, UNSIGNED_ABS } 1,50,0 { BOOL_THEN, CLAMP } - 1,47,0 { TAU, IS_ASCII_DIGIT_CONST } + 1,47,0 { TAU, IS_ASCII_DIGIT_CONST, ARRAY_IMPL_ANY_LEN } 1,46,0 { CONST_IF_MATCH } 1,45,0 { STR_STRIP_PREFIX } 1,43,0 { LOG2_10, LOG10_2 } @@ -42,11 +44,13 @@ msrv_aliases! { 1,34,0 { TRY_FROM } 1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES } 1,28,0 { FROM_BOOL } + 1,27,0 { ITERATOR_TRY_FOLD } 1,26,0 { RANGE_INCLUSIVE, STRING_RETAIN } 1,24,0 { IS_ASCII_DIGIT } 1,18,0 { HASH_MAP_RETAIN, HASH_SET_RETAIN } 1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST, EXPECT_ERR } 1,16,0 { STR_REPEAT } + 1,15,0 { MAYBE_BOUND_IN_WHERE } } fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option) -> Option { diff --git a/clippy_utils/src/numeric_literal.rs b/clippy_utils/src/numeric_literal.rs index c225398ad2a8..bbe4149fe2ab 100644 --- a/clippy_utils/src/numeric_literal.rs +++ b/clippy_utils/src/numeric_literal.rs @@ -161,7 +161,7 @@ impl<'a> NumericLiteral<'a> { } if let Some((separator, exponent)) = self.exponent { - if exponent != "0" { + if !exponent.is_empty() && exponent != "0" { output.push_str(separator); Self::group_digits(&mut output, exponent, group_size, true, false); } diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index b7e83ce6caac..c9938caefb06 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -4,17 +4,24 @@ // differ from the time of `rustc` even if the name stays the same. use crate::msrvs::Msrv; +use hir::LangItem; +use rustc_const_eval::transform::check_consts::ConstCx; use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::traits::Obligation; use rustc_middle::mir::{ Body, CastKind, NonDivergingIntrinsic, NullOp, Operand, Place, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, }; +use rustc_middle::traits::{ImplSource, ObligationCause}; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt}; +use rustc_middle::ty::{BoundConstness, TraitRef}; use rustc_semver::RustcVersion; use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_trait_selection::traits::{ObligationCtxt, SelectionContext}; use std::borrow::Cow; type McfResult = Result<(), (Span, Cow<'static, str>)>; @@ -32,7 +39,7 @@ pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv) body.local_decls.iter().next().unwrap().source_info.span, )?; - for bb in body.basic_blocks.iter() { + for bb in &*body.basic_blocks { check_terminator(tcx, body, bb.terminator(), msrv)?; for stmt in &bb.statements { check_statement(tcx, body, def_id, stmt)?; @@ -60,7 +67,7 @@ fn check_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult { return Err((span, "function pointers in const fn are unstable".into())); }, ty::Dynamic(preds, _, _) => { - for pred in preds.iter() { + for pred in *preds { match pred.skip_binder() { ty::ExistentialPredicate::AutoTrait(_) | ty::ExistentialPredicate::Projection(_) => { return Err(( @@ -227,7 +234,19 @@ fn check_statement<'tcx>( fn check_operand<'tcx>(tcx: TyCtxt<'tcx>, operand: &Operand<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult { match operand { - Operand::Move(place) | Operand::Copy(place) => check_place(tcx, *place, span, body), + Operand::Move(place) => { + if !place.projection.as_ref().is_empty() + && !is_ty_const_destruct(tcx, place.ty(&body.local_decls, tcx).ty, body) + { + return Err(( + span, + "cannot drop locals with a non constant destructor in const fn".into(), + )); + } + + check_place(tcx, *place, span, body) + }, + Operand::Copy(place) => check_place(tcx, *place, span, body), Operand::Constant(c) => match c.check_static_ptr(tcx) { Some(_) => Err((span, "cannot access `static` items in const fn".into())), None => Ok(()), @@ -236,12 +255,10 @@ fn check_operand<'tcx>(tcx: TyCtxt<'tcx>, operand: &Operand<'tcx>, span: Span, b } fn check_place<'tcx>(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult { - let mut cursor = place.projection.as_ref(); - while let [ref proj_base @ .., elem] = *cursor { - cursor = proj_base; + for (base, elem) in place.as_ref().iter_projections() { match elem { ProjectionElem::Field(..) => { - let base_ty = Place::ty_from(place.local, proj_base, body, tcx).ty; + let base_ty = base.ty(body, tcx).ty; if let Some(def) = base_ty.ty_adt_def() { // No union field accesses in `const fn` if def.is_union() { @@ -276,15 +293,19 @@ fn check_terminator<'tcx>( | TerminatorKind::Resume | TerminatorKind::Terminate | TerminatorKind::Unreachable => Ok(()), - - TerminatorKind::Drop { place, .. } => check_place(tcx, *place, span, body), - + TerminatorKind::Drop { place, .. } => { + if !is_ty_const_destruct(tcx, place.ty(&body.local_decls, tcx).ty, body) { + return Err(( + span, + "cannot drop locals with a non constant destructor in const fn".into(), + )); + } + Ok(()) + }, TerminatorKind::SwitchInt { discr, targets: _ } => check_operand(tcx, discr, span, body), - TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => { Err((span, "const fn generators are unstable".into())) }, - TerminatorKind::Call { func, args, @@ -328,7 +349,6 @@ fn check_terminator<'tcx>( Err((span, "can only call other const fns within const fn".into())) } }, - TerminatorKind::Assert { cond, expected: _, @@ -336,7 +356,6 @@ fn check_terminator<'tcx>( target: _, unwind: _, } => check_operand(tcx, cond, span, body), - TerminatorKind::InlineAsm { .. } => Err((span, "cannot use inline assembly in const fn".into())), } } @@ -350,8 +369,7 @@ fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: &Msrv) -> bool { // as a part of an unimplemented MSRV check https://github.com/rust-lang/rust/issues/65262. // HACK(nilstrieb): CURRENT_RUSTC_VERSION can return versions like 1.66.0-dev. `rustc-semver` - // doesn't accept the `-dev` version number so we have to strip it - // off. + // doesn't accept the `-dev` version number so we have to strip it off. let short_version = since .as_str() .split('-') @@ -369,3 +387,35 @@ fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: &Msrv) -> bool { } }) } + +#[expect(clippy::similar_names)] // bit too pedantic +fn is_ty_const_destruct<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx>) -> bool { + // Avoid selecting for simple cases, such as builtin types. + if ty::util::is_trivially_const_drop(ty) { + return true; + } + + let obligation = Obligation::new( + tcx, + ObligationCause::dummy_with_span(body.span), + ConstCx::new(tcx, body).param_env.with_const(), + TraitRef::from_lang_item(tcx, LangItem::Destruct, body.span, [ty]).with_constness(BoundConstness::ConstIfConst), + ); + + let infcx = tcx.infer_ctxt().build(); + let mut selcx = SelectionContext::new(&infcx); + let Some(impl_src) = selcx.select(&obligation).ok().flatten() else { + return false; + }; + + if !matches!( + impl_src, + ImplSource::Builtin(_) | ImplSource::Param(_, ty::BoundConstness::ConstIfConst) + ) { + return false; + } + + let ocx = ObligationCtxt::new(&infcx); + ocx.register_obligations(impl_src.nested_obligations()); + ocx.select_all_or_error().is_empty() +} diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index b38b9553558c..cf781e18cd66 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -944,7 +944,7 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { }, // item is used in a call // i.e.: `Call`: `|x| please(x)` or `MethodCall`: `|x| [1, 2, 3].contains(x)` - ExprKind::Call(_, [call_args @ ..]) | ExprKind::MethodCall(_, _, [call_args @ ..], _) => { + ExprKind::Call(_, call_args) | ExprKind::MethodCall(_, _, call_args, _) => { let expr = self.cx.tcx.hir().expect_expr(cmt.hir_id); let arg_ty_kind = self.cx.typeck_results().expr_ty(expr).kind(); diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 8d3aecd4785b..9c39d22c61b2 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -17,8 +17,8 @@ use rustc_lint::LateContext; use rustc_middle::mir::interpret::{ConstValue, Scalar}; use rustc_middle::ty::{ self, layout::ValidityRequirement, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, IntTy, List, ParamEnv, - Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, - TypeVisitableExt, TypeVisitor, UintTy, VariantDef, VariantDiscr, + Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, + UintTy, VariantDef, VariantDiscr, }; use rustc_middle::ty::{GenericArg, GenericArgKind}; use rustc_span::symbol::Ident; @@ -277,7 +277,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { false }, ty::Dynamic(binder, _, _) => { - for predicate in binder.iter() { + for predicate in *binder { if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() { if cx.tcx.has_attr(trait_ref.def_id, sym::must_use) { return true; @@ -760,9 +760,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option } inputs = Some(i); }, - ty::ClauseKind::Projection(p) - if Some(p.projection_ty.def_id) == lang_items.fn_once_output() => - { + ty::ClauseKind::Projection(p) if Some(p.projection_ty.def_id) == lang_items.fn_once_output() => { if output.is_some() { // Multiple different fn trait impls. Is this even allowed? return None; @@ -1180,3 +1178,51 @@ pub fn is_interior_mut_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { _ => false, } } + +pub fn make_normalized_projection_with_regions<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + container_id: DefId, + assoc_ty: Symbol, + substs: impl IntoIterator>>, +) -> Option> { + fn helper<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: AliasTy<'tcx>) -> Option> { + #[cfg(debug_assertions)] + if let Some((i, subst)) = ty + .substs + .iter() + .enumerate() + .find(|(_, subst)| subst.has_late_bound_regions()) + { + debug_assert!( + false, + "substs contain late-bound region at index `{i}` which can't be normalized.\n\ + use `TyCtxt::erase_late_bound_regions`\n\ + note: subst is `{subst:#?}`", + ); + return None; + } + let cause = rustc_middle::traits::ObligationCause::dummy(); + match tcx + .infer_ctxt() + .build() + .at(&cause, param_env) + .query_normalize(tcx.mk_projection(ty.def_id, ty.substs)) + { + Ok(ty) => Some(ty.value), + Err(e) => { + debug_assert!(false, "failed to normalize type `{ty}`: {e:#?}"); + None + }, + } + } + helper(tcx, param_env, make_projection(tcx, container_id, assoc_ty, substs)?) +} + +pub fn normalize_with_regions<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { + let cause = rustc_middle::traits::ObligationCause::dummy(); + match tcx.infer_ctxt().build().at(&cause, param_env).query_normalize(ty) { + Ok(ty) => ty.value, + Err(_) => ty, + } +} diff --git a/clippy_utils/src/usage.rs b/clippy_utils/src/usage.rs index ab3976a13bdb..9855085216fe 100644 --- a/clippy_utils/src/usage.rs +++ b/clippy_utils/src/usage.rs @@ -82,7 +82,7 @@ pub struct ParamBindingIdCollector { impl<'tcx> ParamBindingIdCollector { fn collect_binding_hir_ids(body: &'tcx hir::Body<'tcx>) -> Vec { let mut hir_ids: Vec = Vec::new(); - for param in body.params.iter() { + for param in body.params { let mut finder = ParamBindingIdCollector { binding_hir_ids: Vec::new(), }; diff --git a/declare_clippy_lint/src/lib.rs b/declare_clippy_lint/src/lib.rs index 5232e4ab7d75..0057256f659b 100644 --- a/declare_clippy_lint/src/lib.rs +++ b/declare_clippy_lint/src/lib.rs @@ -85,8 +85,8 @@ impl Parse for ClippyLint { /// 2. The `LINT_NAME`. See [lint naming][lint_naming] on lint naming conventions. /// 3. The `lint_level`, which is a mapping from *one* of our lint groups to `Allow`, `Warn` or /// `Deny`. The lint level here has nothing to do with what lint groups the lint is a part of. -/// 4. The `description` that contains a short explanation on what's wrong with code where the -/// lint is triggered. +/// 4. The `description` that contains a short explanation on what's wrong with code where the lint +/// is triggered. /// /// Currently the categories `style`, `correctness`, `suspicious`, `complexity` and `perf` are /// enabled by default. As said in the README.md of this repository, if the lint level mapping diff --git a/lintcheck/src/main.rs b/lintcheck/src/main.rs index 03d1877d6c64..de56a6f82757 100644 --- a/lintcheck/src/main.rs +++ b/lintcheck/src/main.rs @@ -474,7 +474,7 @@ fn read_crates(toml_path: &Path) -> (Vec, RecursiveOptions) { }); } else if let Some(ref versions) = tk.versions { // if we have multiple versions, save each one - for ver in versions.iter() { + for ver in versions { crate_sources.push(CrateSource::CratesIo { name: tk.name.clone(), version: ver.to_string(), diff --git a/rust-toolchain b/rust-toolchain index 0d2e1eee6438..4475d914cedb 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-06-02" +channel = "nightly-2023-06-29" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/rustfmt.toml b/rustfmt.toml index 10d39762043e..18b2a33469da 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -5,3 +5,4 @@ wrap_comments = true edition = "2021" error_on_line_overflow = true version = "Two" +ignore = ["tests/ui/crashes/ice-10912.rs"] diff --git a/src/driver.rs b/src/driver.rs index f3cc94aeff01..1eb288b153a5 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -16,9 +16,9 @@ extern crate rustc_session; extern crate rustc_span; use rustc_interface::interface; -use rustc_session::EarlyErrorHandler; use rustc_session::config::ErrorOutputType; use rustc_session::parse::ParseSess; +use rustc_session::EarlyErrorHandler; use rustc_span::symbol::Symbol; use std::env; diff --git a/src/main.rs b/src/main.rs index 188ff87abfc5..cdc85cb33ca2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,7 +6,7 @@ use std::env; use std::path::PathBuf; use std::process::{self, Command}; -const CARGO_CLIPPY_HELP: &str = r#"Checks a package to catch common mistakes and improve your Rust code. +const CARGO_CLIPPY_HELP: &str = "Checks a package to catch common mistakes and improve your Rust code. Usage: cargo clippy [options] [--] [...] @@ -31,7 +31,7 @@ with: You can use tool lints to allow or deny lints from your code, e.g.: #[allow(clippy::needless_lifetimes)] -"#; +"; fn show_help() { println!("{CARGO_CLIPPY_HELP}"); @@ -57,7 +57,9 @@ pub fn main() { if let Some(pos) = env::args().position(|a| a == "--explain") { if let Some(mut lint) = env::args().nth(pos + 1) { lint.make_ascii_lowercase(); - clippy_lints::explain(&lint.strip_prefix("clippy::").unwrap_or(&lint).replace('-', "_")); + process::exit(clippy_lints::explain( + &lint.strip_prefix("clippy::").unwrap_or(&lint).replace('-', "_"), + )); } else { show_help(); } diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 35d75cc51c21..dce6f2fc2726 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -4,16 +4,14 @@ #![cfg_attr(feature = "deny-warnings", deny(warnings))] #![warn(rust_2018_idioms, unused_lifetimes)] -use compiletest_rs as compiletest; -use compiletest_rs::common::Mode as TestMode; +use compiletest::{status_emitter, CommandBuilder}; +use ui_test as compiletest; +use ui_test::Mode as TestMode; -use std::collections::HashMap; use std::env::{self, remove_var, set_var, var_os}; use std::ffi::{OsStr, OsString}; use std::fs; -use std::io; use std::path::{Path, PathBuf}; -use std::sync::LazyLock; use test_utils::IS_RUSTC_TEST_SUITE; mod test_utils; @@ -21,143 +19,41 @@ mod test_utils; // whether to run internal tests or not const RUN_INTERNAL_TESTS: bool = cfg!(feature = "internal"); -/// All crates used in UI tests are listed here -static TEST_DEPENDENCIES: &[&str] = &[ - "clippy_lints", - "clippy_utils", - "derive_new", - "futures", - "if_chain", - "itertools", - "quote", - "regex", - "serde", - "serde_derive", - "syn", - "tokio", - "parking_lot", - "rustc_semver", -]; - -// Test dependencies may need an `extern crate` here to ensure that they show up -// in the depinfo file (otherwise cargo thinks they are unused) -#[allow(unused_extern_crates)] -extern crate clippy_lints; -#[allow(unused_extern_crates)] -extern crate clippy_utils; -#[allow(unused_extern_crates)] -extern crate derive_new; -#[allow(unused_extern_crates)] -extern crate futures; -#[allow(unused_extern_crates)] -extern crate if_chain; -#[allow(unused_extern_crates)] -extern crate itertools; -#[allow(unused_extern_crates)] -extern crate parking_lot; -#[allow(unused_extern_crates)] -extern crate quote; -#[allow(unused_extern_crates)] -extern crate rustc_semver; -#[allow(unused_extern_crates)] -extern crate syn; -#[allow(unused_extern_crates)] -extern crate tokio; - -/// Produces a string with an `--extern` flag for all UI test crate -/// dependencies. -/// -/// The dependency files are located by parsing the depinfo file for this test -/// module. This assumes the `-Z binary-dep-depinfo` flag is enabled. All test -/// dependencies must be added to Cargo.toml at the project root. Test -/// dependencies that are not *directly* used by this test module require an -/// `extern crate` declaration. -static EXTERN_FLAGS: LazyLock = LazyLock::new(|| { - let current_exe_depinfo = { - let mut path = env::current_exe().unwrap(); - path.set_extension("d"); - fs::read_to_string(path).unwrap() - }; - let mut crates: HashMap<&str, &str> = HashMap::with_capacity(TEST_DEPENDENCIES.len()); - for line in current_exe_depinfo.lines() { - // each dependency is expected to have a Makefile rule like `/path/to/crate-hash.rlib:` - let parse_name_path = || { - if line.starts_with(char::is_whitespace) { - return None; - } - let path_str = line.strip_suffix(':')?; - let path = Path::new(path_str); - if !matches!(path.extension()?.to_str()?, "rlib" | "so" | "dylib" | "dll") { - return None; - } - let (name, _hash) = path.file_stem()?.to_str()?.rsplit_once('-')?; - // the "lib" prefix is not present for dll files - let name = name.strip_prefix("lib").unwrap_or(name); - Some((name, path_str)) - }; - if let Some((name, path)) = parse_name_path() { - if TEST_DEPENDENCIES.contains(&name) { - // A dependency may be listed twice if it is available in sysroot, - // and the sysroot dependencies are listed first. As of the writing, - // this only seems to apply to if_chain. - crates.insert(name, path); - } - } - } - let not_found: Vec<&str> = TEST_DEPENDENCIES - .iter() - .copied() - .filter(|n| !crates.contains_key(n)) - .collect(); - assert!( - not_found.is_empty(), - "dependencies not found in depinfo: {not_found:?}\n\ - help: Make sure the `-Z binary-dep-depinfo` rust flag is enabled\n\ - help: Try adding to dev-dependencies in Cargo.toml\n\ - help: Be sure to also add `extern crate ...;` to tests/compile-test.rs", - ); - crates - .into_iter() - .map(|(name, path)| format!(" --extern {name}={path}")) - .collect() -}); - fn base_config(test_dir: &str) -> compiletest::Config { let mut config = compiletest::Config { - edition: Some("2021".into()), - mode: TestMode::Ui, - strict_headers: true, - ..Default::default() + mode: TestMode::Yolo, + stderr_filters: vec![], + stdout_filters: vec![], + output_conflict_handling: if var_os("BLESS").is_some() || env::args().any(|arg| arg == "--bless") { + compiletest::OutputConflictHandling::Bless + } else { + compiletest::OutputConflictHandling::Error("cargo test -- -- --bless".into()) + }, + dependencies_crate_manifest_path: Some("clippy_test_deps/Cargo.toml".into()), + target: None, + out_dir: "target/ui_test".into(), + ..compiletest::Config::rustc(Path::new("tests").join(test_dir)) }; - if let Ok(filters) = env::var("TESTNAME") { - config.filters = filters.split(',').map(ToString::to_string).collect(); - } - - if let Some(path) = option_env!("RUSTC_LIB_PATH") { - let path = PathBuf::from(path); - config.run_lib_path = path.clone(); - config.compile_lib_path = path; + if let Some(_path) = option_env!("RUSTC_LIB_PATH") { + //let path = PathBuf::from(path); + //config.run_lib_path = path.clone(); + //config.compile_lib_path = path; } let current_exe_path = env::current_exe().unwrap(); let deps_path = current_exe_path.parent().unwrap(); let profile_path = deps_path.parent().unwrap(); - // Using `-L dependency={}` enforces that external dependencies are added with `--extern`. - // This is valuable because a) it allows us to monitor what external dependencies are used - // and b) it ensures that conflicting rlibs are resolved properly. - let host_libs = option_env!("HOST_LIBS") - .map(|p| format!(" -L dependency={}", Path::new(p).join("deps").display())) - .unwrap_or_default(); - config.target_rustcflags = Some(format!( - "--emit=metadata -Dwarnings -Zui-testing -L dependency={}{host_libs}{}", - deps_path.display(), - &*EXTERN_FLAGS, - )); + config.program.args.push("--emit=metadata".into()); + config.program.args.push("-Aunused".into()); + config.program.args.push("-Zui-testing".into()); + config.program.args.push("-Dwarnings".into()); - config.src_base = Path::new("tests").join(test_dir); - config.build_base = profile_path.join("test").join(test_dir); - config.rustc_path = profile_path.join(if cfg!(windows) { + // Normalize away slashes in windows paths. + config.stderr_filter(r"\\", "/"); + + //config.build_base = profile_path.join("test").join(test_dir); + config.program.program = profile_path.join(if cfg!(windows) { "clippy-driver.exe" } else { "clippy-driver" @@ -165,9 +61,18 @@ fn base_config(test_dir: &str) -> compiletest::Config { config } +fn test_filter() -> Box bool> { + if let Ok(filters) = env::var("TESTNAME") { + let filters: Vec<_> = filters.split(',').map(ToString::to_string).collect(); + Box::new(move |path| filters.iter().any(|f| path.to_string_lossy().contains(f))) + } else { + Box::new(|_| true) + } +} + fn run_ui() { - let mut config = base_config("ui"); - config.rustfix_coverage = true; + let config = base_config("ui"); + //config.rustfix_coverage = true; // use tests/clippy.toml let _g = VarGuard::set("CARGO_MANIFEST_DIR", fs::canonicalize("tests").unwrap()); let _threads = VarGuard::set( @@ -179,7 +84,19 @@ fn run_ui() { .to_string() }), ); - compiletest::run_tests(&config); + eprintln!(" Compiler: {}", config.program.display()); + + let name = config.root_dir.display().to_string(); + + let test_filter = test_filter(); + + compiletest::run_tests_generic( + config, + move |path| compiletest::default_file_filter(path) && test_filter(path), + compiletest::default_per_file_config, + (status_emitter::Text, status_emitter::Gha:: { name }), + ) + .unwrap(); check_rustfix_coverage(); } @@ -188,177 +105,124 @@ fn run_internal_tests() { if !RUN_INTERNAL_TESTS { return; } - let config = base_config("ui-internal"); - compiletest::run_tests(&config); + let mut config = base_config("ui-internal"); + config.dependency_builder.args.push("--features".into()); + config.dependency_builder.args.push("internal".into()); + compiletest::run_tests(config).unwrap(); } fn run_ui_toml() { - fn run_tests(config: &compiletest::Config, mut tests: Vec) -> Result { - let mut result = true; - let opts = compiletest::test_opts(config); - for dir in fs::read_dir(&config.src_base)? { - let dir = dir?; - if !dir.file_type()?.is_dir() { - continue; - } - let dir_path = dir.path(); - let _g = VarGuard::set("CARGO_MANIFEST_DIR", &dir_path); - for file in fs::read_dir(&dir_path)? { - let file = file?; - let file_path = file.path(); - if file.file_type()?.is_dir() { - continue; - } - if file_path.extension() != Some(OsStr::new("rs")) { - continue; - } - let paths = compiletest::common::TestPaths { - file: file_path, - base: config.src_base.clone(), - relative_dir: dir_path.file_name().unwrap().into(), - }; - let test_name = compiletest::make_test_name(config, &paths); - let index = tests - .iter() - .position(|test| test.desc.name == test_name) - .expect("The test should be in there"); - result &= tester::run_tests_console(&opts, vec![tests.swap_remove(index)])?; - } - } - Ok(result) - } - let mut config = base_config("ui-toml"); - config.src_base = config.src_base.canonicalize().unwrap(); - let tests = compiletest::make_tests(&config); + config.stderr_filter( + ®ex::escape( + &std::path::Path::new(file!()) + .parent() + .unwrap() + .canonicalize() + .unwrap() + .parent() + .unwrap() + .display() + .to_string() + .replace('\\', "/"), + ), + "$$DIR", + ); - let res = run_tests(&config, tests); - match res { - Ok(true) => {}, - Ok(false) => panic!("Some tests failed"), - Err(e) => { - panic!("I/O failure during tests: {e:?}"); + let name = config.root_dir.display().to_string(); + + let test_filter = test_filter(); + + ui_test::run_tests_generic( + config, + |path| test_filter(path) && path.extension() == Some("rs".as_ref()), + |config, path| { + let mut config = config.clone(); + config + .program + .envs + .push(("CLIPPY_CONF_DIR".into(), Some(path.parent().unwrap().into()))); + Some(config) }, - } + (status_emitter::Text, status_emitter::Gha:: { name }), + ) + .unwrap(); } fn run_ui_cargo() { - fn run_tests( - config: &compiletest::Config, - filters: &[String], - mut tests: Vec, - ) -> Result { - let mut result = true; - let opts = compiletest::test_opts(config); - - for dir in fs::read_dir(&config.src_base)? { - let dir = dir?; - if !dir.file_type()?.is_dir() { - continue; - } - - // Use the filter if provided - let dir_path = dir.path(); - for filter in filters { - if !dir_path.ends_with(filter) { - continue; - } - } - - for case in fs::read_dir(&dir_path)? { - let case = case?; - if !case.file_type()?.is_dir() { - continue; - } - - let src_path = case.path().join("src"); - - // When switching between branches, if the previous branch had a test - // that the current branch does not have, the directory is not removed - // because an ignored Cargo.lock file exists. - if !src_path.exists() { - continue; - } - - env::set_current_dir(&src_path)?; - - let cargo_toml_path = case.path().join("Cargo.toml"); - let cargo_content = fs::read(cargo_toml_path)?; - let cargo_parsed: toml::Value = toml::from_str( - std::str::from_utf8(&cargo_content).expect("`Cargo.toml` is not a valid utf-8 file!"), - ) - .expect("Can't parse `Cargo.toml`"); - - let _g = VarGuard::set("CARGO_MANIFEST_DIR", case.path()); - let _h = VarGuard::set( - "CARGO_PKG_RUST_VERSION", - cargo_parsed - .get("package") - .and_then(|p| p.get("rust-version")) - .and_then(toml::Value::as_str) - .unwrap_or(""), - ); - - for file in fs::read_dir(&src_path)? { - let file = file?; - if file.file_type()?.is_dir() { - continue; - } - - // Search for the main file to avoid running a test for each file in the project - let file_path = file.path(); - match file_path.file_name().and_then(OsStr::to_str) { - Some("main.rs") => {}, - _ => continue, - } - let _g = VarGuard::set("CLIPPY_CONF_DIR", case.path()); - let paths = compiletest::common::TestPaths { - file: file_path, - base: config.src_base.clone(), - relative_dir: src_path.strip_prefix(&config.src_base).unwrap().into(), - }; - let test_name = compiletest::make_test_name(config, &paths); - let index = tests - .iter() - .position(|test| test.desc.name == test_name) - .expect("The test should be in there"); - result &= tester::run_tests_console(&opts, vec![tests.swap_remove(index)])?; - } - } - } - Ok(result) - } - if IS_RUSTC_TEST_SUITE { return; } let mut config = base_config("ui-cargo"); - config.src_base = config.src_base.canonicalize().unwrap(); + config.program.input_file_flag = CommandBuilder::cargo().input_file_flag; + config.program.out_dir_flag = CommandBuilder::cargo().out_dir_flag; + config.program.args = vec!["clippy".into(), "--color".into(), "never".into(), "--quiet".into()]; + config + .program + .envs + .push(("RUSTFLAGS".into(), Some("-Dwarnings".into()))); + // We need to do this while we still have a rustc in the `program` field. + config.fill_host_and_target().unwrap(); + config.dependencies_crate_manifest_path = None; + config.program.program.set_file_name(if cfg!(windows) { + "cargo-clippy.exe" + } else { + "cargo-clippy" + }); + config.edition = None; - let tests = compiletest::make_tests(&config); + config.stderr_filter( + ®ex::escape( + &std::path::Path::new(file!()) + .parent() + .unwrap() + .canonicalize() + .unwrap() + .parent() + .unwrap() + .display() + .to_string() + .replace('\\', "/"), + ), + "$$DIR", + ); - let current_dir = env::current_dir().unwrap(); - let res = run_tests(&config, &config.filters, tests); - env::set_current_dir(current_dir).unwrap(); + let name = config.root_dir.display().to_string(); - match res { - Ok(true) => {}, - Ok(false) => panic!("Some tests failed"), - Err(e) => { - panic!("I/O failure during tests: {e:?}"); + let test_filter = test_filter(); + + ui_test::run_tests_generic( + config, + |path| test_filter(path) && path.ends_with("Cargo.toml"), + |config, path| { + let mut config = config.clone(); + config.out_dir = PathBuf::from("target/ui_test_cargo/").join(path.parent().unwrap()); + Some(config) }, - } + (status_emitter::Text, status_emitter::Gha:: { name }), + ) + .unwrap(); } -#[test] -fn compile_test() { +fn main() { + // Support being run by cargo nextest - https://nexte.st/book/custom-test-harnesses.html + if env::args().any(|arg| arg == "--list") { + if !env::args().any(|arg| arg == "--ignored") { + println!("compile_test: test"); + } + + return; + } + set_var("CLIPPY_DISABLE_DOCS_LINKS", "true"); run_ui(); run_ui_toml(); run_ui_cargo(); run_internal_tests(); + rustfix_coverage_known_exceptions_accuracy(); + ui_cargo_toml_metadata(); } const RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS: &[&str] = &[ @@ -384,7 +248,6 @@ const RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS: &[&str] = &[ "needless_for_each_unfixable.rs", "nonminimal_bool.rs", "print_literal.rs", - "print_with_newline.rs", "redundant_static_lifetimes_multiple.rs", "ref_binding_to_reference.rs", "repl_uninit.rs", @@ -399,7 +262,6 @@ const RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS: &[&str] = &[ "unnecessary_lazy_eval_unfixable.rs", "write_literal.rs", "write_literal_2.rs", - "write_with_newline.rs", ]; fn check_rustfix_coverage() { @@ -432,25 +294,15 @@ fn check_rustfix_coverage() { } } -#[test] fn rustfix_coverage_known_exceptions_accuracy() { for filename in RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS { let rs_path = Path::new("tests/ui").join(filename); - assert!( - rs_path.exists(), - "`{}` does not exist", - rs_path.strip_prefix(env!("CARGO_MANIFEST_DIR")).unwrap().display() - ); + assert!(rs_path.exists(), "`{}` does not exist", rs_path.display()); let fixed_path = rs_path.with_extension("fixed"); - assert!( - !fixed_path.exists(), - "`{}` exists", - fixed_path.strip_prefix(env!("CARGO_MANIFEST_DIR")).unwrap().display() - ); + assert!(!fixed_path.exists(), "`{}` exists", fixed_path.display()); } } -#[test] fn ui_cargo_toml_metadata() { let ui_cargo_path = Path::new("tests/ui-cargo"); let cargo_common_metadata_path = ui_cargo_path.join("cargo_common_metadata"); diff --git a/tests/headers.rs b/tests/headers.rs new file mode 100644 index 000000000000..1d1e566cbf6f --- /dev/null +++ b/tests/headers.rs @@ -0,0 +1,29 @@ +use regex::Regex; +use std::fs; +use walkdir::WalkDir; + +#[test] +fn old_test_headers() { + let old_headers = Regex::new( + r"^//( ?\[\w+\])? ?((check|build|run|ignore|aux|only|needs|rustc|unset|no|normalize|run|compile)-|edition|incremental|revisions).*", + ) + .unwrap(); + let mut failed = false; + + for entry in WalkDir::new("tests") { + let entry = entry.unwrap(); + if !entry.file_type().is_file() { + continue; + } + + let file = fs::read_to_string(entry.path()).unwrap(); + + if let Some(header) = old_headers.find(&file) { + println!("Found header `{}` in {}", header.as_str(), entry.path().display()); + + failed = true; + } + } + + assert!(!failed, "use `//@foo` style test headers instead"); +} diff --git a/tests/lint_message_convention.rs b/tests/lint_message_convention.rs index 8feea800fdbe..15e5cdd6992c 100644 --- a/tests/lint_message_convention.rs +++ b/tests/lint_message_convention.rs @@ -20,16 +20,16 @@ impl Message { // also no punctuation (except for "?" ?) at the end of a line static REGEX_SET: LazyLock = LazyLock::new(|| { RegexSet::new([ - r"error: [A-Z]", - r"help: [A-Z]", - r"warning: [A-Z]", - r"note: [A-Z]", - r"try this: [A-Z]", - r"error: .*[.!]$", - r"help: .*[.!]$", - r"warning: .*[.!]$", - r"note: .*[.!]$", - r"try this: .*[.!]$", + "error: [A-Z]", + "help: [A-Z]", + "warning: [A-Z]", + "note: [A-Z]", + "try this: [A-Z]", + "error: .*[.!]$", + "help: .*[.!]$", + "warning: .*[.!]$", + "note: .*[.!]$", + "try this: .*[.!]$", ]) .unwrap() }); @@ -39,11 +39,11 @@ impl Message { static EXCEPTIONS_SET: LazyLock = LazyLock::new(|| { RegexSet::new([ r"\.\.\.$", - r".*C-like enum variant discriminant is not portable to 32-bit targets", - r".*Intel x86 assembly syntax used", - r".*AT&T x86 assembly syntax used", - r"note: Clippy version: .*", - r"the compiler unexpectedly panicked. this is a bug.", + ".*C-like enum variant discriminant is not portable to 32-bit targets", + ".*Intel x86 assembly syntax used", + ".*AT&T x86 assembly syntax used", + "note: Clippy version: .*", + "the compiler unexpectedly panicked. this is a bug.", ]) .unwrap() }); diff --git a/tests/missing-test-files.rs b/tests/missing-test-files.rs index caedd5d76cd6..0d35a22cd9a4 100644 --- a/tests/missing-test-files.rs +++ b/tests/missing-test-files.rs @@ -41,8 +41,8 @@ fn explore_directory(dir: &Path) -> Vec { x.path().extension().and_then(OsStr::to_str), y.path().extension().and_then(OsStr::to_str), ) { - (Some("rs"), _) => Ordering::Less, - (_, Some("rs")) => Ordering::Greater, + (Some("rs" | "toml"), _) => Ordering::Less, + (_, Some("rs" | "toml")) => Ordering::Greater, _ => Ordering::Equal, } }); @@ -54,7 +54,7 @@ fn explore_directory(dir: &Path) -> Vec { let file_prefix = path.file_prefix().unwrap().to_str().unwrap().to_string(); if let Some(ext) = path.extension() { match ext.to_str().unwrap() { - "rs" => current_file = file_prefix.clone(), + "rs" | "toml" => current_file = file_prefix.clone(), "stderr" | "stdout" => { if file_prefix != current_file { missing_files.push(path.to_str().unwrap().to_string()); diff --git a/tests/ui-cargo/cargo_common_metadata/fail/src/main.stderr b/tests/ui-cargo/cargo_common_metadata/fail/Cargo.stderr similarity index 74% rename from tests/ui-cargo/cargo_common_metadata/fail/src/main.stderr rename to tests/ui-cargo/cargo_common_metadata/fail/Cargo.stderr index 86953142befa..e161507b5339 100644 --- a/tests/ui-cargo/cargo_common_metadata/fail/src/main.stderr +++ b/tests/ui-cargo/cargo_common_metadata/fail/Cargo.stderr @@ -1,6 +1,6 @@ error: package `cargo_common_metadata_fail` is missing `package.description` metadata - | - = note: `-D clippy::cargo-common-metadata` implied by `-D warnings` + | + = note: `-D clippy::cargo-common-metadata` implied by `-D warnings` error: package `cargo_common_metadata_fail` is missing `either package.license or package.license_file` metadata @@ -12,5 +12,4 @@ error: package `cargo_common_metadata_fail` is missing `package.keywords` metada error: package `cargo_common_metadata_fail` is missing `package.categories` metadata -error: aborting due to 6 previous errors - +error: could not compile `cargo_common_metadata_fail` (bin "cargo_common_metadata_fail") due to 6 previous errors diff --git a/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.stderr b/tests/ui-cargo/cargo_common_metadata/fail_publish/Cargo.stderr similarity index 74% rename from tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.stderr rename to tests/ui-cargo/cargo_common_metadata/fail_publish/Cargo.stderr index ac1b5e8e9034..dbf494cc342d 100644 --- a/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.stderr +++ b/tests/ui-cargo/cargo_common_metadata/fail_publish/Cargo.stderr @@ -1,6 +1,6 @@ error: package `cargo_common_metadata_fail_publish` is missing `package.description` metadata - | - = note: `-D clippy::cargo-common-metadata` implied by `-D warnings` + | + = note: `-D clippy::cargo-common-metadata` implied by `-D warnings` error: package `cargo_common_metadata_fail_publish` is missing `either package.license or package.license_file` metadata @@ -12,5 +12,4 @@ error: package `cargo_common_metadata_fail_publish` is missing `package.keywords error: package `cargo_common_metadata_fail_publish` is missing `package.categories` metadata -error: aborting due to 6 previous errors - +error: could not compile `cargo_common_metadata_fail_publish` (bin "cargo_common_metadata_fail_publish") due to 6 previous errors diff --git a/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.stderr b/tests/ui-cargo/cargo_common_metadata/fail_publish_true/Cargo.stderr similarity index 74% rename from tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.stderr rename to tests/ui-cargo/cargo_common_metadata/fail_publish_true/Cargo.stderr index be32c0dc418f..ae5967406f62 100644 --- a/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.stderr +++ b/tests/ui-cargo/cargo_common_metadata/fail_publish_true/Cargo.stderr @@ -1,6 +1,6 @@ error: package `cargo_common_metadata_fail_publish_true` is missing `package.description` metadata - | - = note: `-D clippy::cargo-common-metadata` implied by `-D warnings` + | + = note: `-D clippy::cargo-common-metadata` implied by `-D warnings` error: package `cargo_common_metadata_fail_publish_true` is missing `either package.license or package.license_file` metadata @@ -12,5 +12,4 @@ error: package `cargo_common_metadata_fail_publish_true` is missing `package.key error: package `cargo_common_metadata_fail_publish_true` is missing `package.categories` metadata -error: aborting due to 6 previous errors - +error: could not compile `cargo_common_metadata_fail_publish_true` (bin "cargo_common_metadata_fail_publish_true") due to 6 previous errors diff --git a/tests/ui-cargo/cargo_rust_version/fail_both_diff/Cargo.stderr b/tests/ui-cargo/cargo_rust_version/fail_both_diff/Cargo.stderr new file mode 100644 index 000000000000..dfbf19d33a5e --- /dev/null +++ b/tests/ui-cargo/cargo_rust_version/fail_both_diff/Cargo.stderr @@ -0,0 +1,21 @@ +warning: the MSRV in `clippy.toml` and `Cargo.toml` differ; using `1.59.0` from `clippy.toml` + +error: unnecessary structure name repetition + --> src/main.rs:6:21 + | +6 | pub fn bar() -> Foo { + | ^^^ help: use the applicable keyword: `Self` + | +note: the lint level is defined here + --> src/main.rs:1:9 + | +1 | #![deny(clippy::use_self)] + | ^^^^^^^^^^^^^^^^ + +error: unnecessary structure name repetition + --> src/main.rs:7:9 + | +7 | Foo + | ^^^ help: use the applicable keyword: `Self` + +error: could not compile `fail-both-diff` (bin "fail-both-diff") due to 2 previous errors; 1 warning emitted diff --git a/tests/ui-cargo/cargo_rust_version/fail_both_diff/src/main.stderr b/tests/ui-cargo/cargo_rust_version/fail_both_diff/src/main.stderr deleted file mode 100644 index 163f8bb35e79..000000000000 --- a/tests/ui-cargo/cargo_rust_version/fail_both_diff/src/main.stderr +++ /dev/null @@ -1,22 +0,0 @@ -warning: the MSRV in `clippy.toml` and `Cargo.toml` differ; using `1.59.0` from `clippy.toml` - -error: unnecessary structure name repetition - --> $DIR/main.rs:6:21 - | -LL | pub fn bar() -> Foo { - | ^^^ help: use the applicable keyword: `Self` - | -note: the lint level is defined here - --> $DIR/main.rs:1:9 - | -LL | #![deny(clippy::use_self)] - | ^^^^^^^^^^^^^^^^ - -error: unnecessary structure name repetition - --> $DIR/main.rs:7:9 - | -LL | Foo - | ^^^ help: use the applicable keyword: `Self` - -error: aborting due to 2 previous errors; 1 warning emitted - diff --git a/tests/ui-cargo/cargo_rust_version/fail_both_same/Cargo.stderr b/tests/ui-cargo/cargo_rust_version/fail_both_same/Cargo.stderr new file mode 100644 index 000000000000..407a9055de80 --- /dev/null +++ b/tests/ui-cargo/cargo_rust_version/fail_both_same/Cargo.stderr @@ -0,0 +1,19 @@ +error: unnecessary structure name repetition + --> src/main.rs:6:21 + | +6 | pub fn bar() -> Foo { + | ^^^ help: use the applicable keyword: `Self` + | +note: the lint level is defined here + --> src/main.rs:1:9 + | +1 | #![deny(clippy::use_self)] + | ^^^^^^^^^^^^^^^^ + +error: unnecessary structure name repetition + --> src/main.rs:7:9 + | +7 | Foo + | ^^^ help: use the applicable keyword: `Self` + +error: could not compile `fail-both-same` (bin "fail-both-same") due to 2 previous errors diff --git a/tests/ui-cargo/cargo_rust_version/fail_cargo/Cargo.stderr b/tests/ui-cargo/cargo_rust_version/fail_cargo/Cargo.stderr new file mode 100644 index 000000000000..566f5a68689b --- /dev/null +++ b/tests/ui-cargo/cargo_rust_version/fail_cargo/Cargo.stderr @@ -0,0 +1,19 @@ +error: unnecessary structure name repetition + --> src/main.rs:6:21 + | +6 | pub fn bar() -> Foo { + | ^^^ help: use the applicable keyword: `Self` + | +note: the lint level is defined here + --> src/main.rs:1:9 + | +1 | #![deny(clippy::use_self)] + | ^^^^^^^^^^^^^^^^ + +error: unnecessary structure name repetition + --> src/main.rs:7:9 + | +7 | Foo + | ^^^ help: use the applicable keyword: `Self` + +error: could not compile `fail-cargo` (bin "fail-cargo") due to 2 previous errors diff --git a/tests/ui-cargo/cargo_rust_version/fail_cargo/src/main.stderr b/tests/ui-cargo/cargo_rust_version/fail_cargo/src/main.stderr deleted file mode 100644 index 259d39b12526..000000000000 --- a/tests/ui-cargo/cargo_rust_version/fail_cargo/src/main.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error: unnecessary structure name repetition - --> $DIR/main.rs:6:21 - | -LL | pub fn bar() -> Foo { - | ^^^ help: use the applicable keyword: `Self` - | -note: the lint level is defined here - --> $DIR/main.rs:1:9 - | -LL | #![deny(clippy::use_self)] - | ^^^^^^^^^^^^^^^^ - -error: unnecessary structure name repetition - --> $DIR/main.rs:7:9 - | -LL | Foo - | ^^^ help: use the applicable keyword: `Self` - -error: aborting due to 2 previous errors - diff --git a/tests/ui-cargo/cargo_rust_version/fail_clippy/Cargo.stderr b/tests/ui-cargo/cargo_rust_version/fail_clippy/Cargo.stderr new file mode 100644 index 000000000000..83d4be3bae46 --- /dev/null +++ b/tests/ui-cargo/cargo_rust_version/fail_clippy/Cargo.stderr @@ -0,0 +1,19 @@ +error: unnecessary structure name repetition + --> src/main.rs:6:21 + | +6 | pub fn bar() -> Foo { + | ^^^ help: use the applicable keyword: `Self` + | +note: the lint level is defined here + --> src/main.rs:1:9 + | +1 | #![deny(clippy::use_self)] + | ^^^^^^^^^^^^^^^^ + +error: unnecessary structure name repetition + --> src/main.rs:7:9 + | +7 | Foo + | ^^^ help: use the applicable keyword: `Self` + +error: could not compile `fail-clippy` (bin "fail-clippy") due to 2 previous errors diff --git a/tests/ui-cargo/cargo_rust_version/fail_clippy/src/main.stderr b/tests/ui-cargo/cargo_rust_version/fail_clippy/src/main.stderr deleted file mode 100644 index 259d39b12526..000000000000 --- a/tests/ui-cargo/cargo_rust_version/fail_clippy/src/main.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error: unnecessary structure name repetition - --> $DIR/main.rs:6:21 - | -LL | pub fn bar() -> Foo { - | ^^^ help: use the applicable keyword: `Self` - | -note: the lint level is defined here - --> $DIR/main.rs:1:9 - | -LL | #![deny(clippy::use_self)] - | ^^^^^^^^^^^^^^^^ - -error: unnecessary structure name repetition - --> $DIR/main.rs:7:9 - | -LL | Foo - | ^^^ help: use the applicable keyword: `Self` - -error: aborting due to 2 previous errors - diff --git a/tests/ui-cargo/cargo_rust_version/fail_both_same/src/main.stderr b/tests/ui-cargo/cargo_rust_version/fail_file_attr/Cargo.stderr similarity index 56% rename from tests/ui-cargo/cargo_rust_version/fail_both_same/src/main.stderr rename to tests/ui-cargo/cargo_rust_version/fail_file_attr/Cargo.stderr index 259d39b12526..14a6b5047b18 100644 --- a/tests/ui-cargo/cargo_rust_version/fail_both_same/src/main.stderr +++ b/tests/ui-cargo/cargo_rust_version/fail_file_attr/Cargo.stderr @@ -1,20 +1,19 @@ error: unnecessary structure name repetition - --> $DIR/main.rs:6:21 + --> src/main.rs:11:21 | -LL | pub fn bar() -> Foo { +11 | pub fn bar() -> Foo { | ^^^ help: use the applicable keyword: `Self` | note: the lint level is defined here - --> $DIR/main.rs:1:9 + --> src/main.rs:6:9 | -LL | #![deny(clippy::use_self)] +6 | #![deny(clippy::use_self)] | ^^^^^^^^^^^^^^^^ error: unnecessary structure name repetition - --> $DIR/main.rs:7:9 + --> src/main.rs:12:9 | -LL | Foo +12 | Foo | ^^^ help: use the applicable keyword: `Self` -error: aborting due to 2 previous errors - +error: could not compile `fail-file-attr` (bin "fail-file-attr") due to 2 previous errors diff --git a/tests/ui-cargo/cargo_rust_version/fail_file_attr/src/main.stderr b/tests/ui-cargo/cargo_rust_version/fail_file_attr/src/main.stderr deleted file mode 100644 index 97e6c3d5a559..000000000000 --- a/tests/ui-cargo/cargo_rust_version/fail_file_attr/src/main.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error: unnecessary structure name repetition - --> $DIR/main.rs:11:21 - | -LL | pub fn bar() -> Foo { - | ^^^ help: use the applicable keyword: `Self` - | -note: the lint level is defined here - --> $DIR/main.rs:6:9 - | -LL | #![deny(clippy::use_self)] - | ^^^^^^^^^^^^^^^^ - -error: unnecessary structure name repetition - --> $DIR/main.rs:12:9 - | -LL | Foo - | ^^^ help: use the applicable keyword: `Self` - -error: aborting due to 2 previous errors - diff --git a/tests/ui-cargo/cargo_rust_version/warn_both_diff/src/main.stderr b/tests/ui-cargo/cargo_rust_version/warn_both_diff/Cargo.stderr similarity index 77% rename from tests/ui-cargo/cargo_rust_version/warn_both_diff/src/main.stderr rename to tests/ui-cargo/cargo_rust_version/warn_both_diff/Cargo.stderr index eeae5b7b275e..e89388b501bf 100644 --- a/tests/ui-cargo/cargo_rust_version/warn_both_diff/src/main.stderr +++ b/tests/ui-cargo/cargo_rust_version/warn_both_diff/Cargo.stderr @@ -1,4 +1,2 @@ warning: the MSRV in `clippy.toml` and `Cargo.toml` differ; using `1.13.0` from `clippy.toml` -warning: 1 warning emitted - diff --git a/tests/ui-cargo/duplicate_mod/fail/Cargo.stderr b/tests/ui-cargo/duplicate_mod/fail/Cargo.stderr new file mode 100644 index 000000000000..fde3a1e65991 --- /dev/null +++ b/tests/ui-cargo/duplicate_mod/fail/Cargo.stderr @@ -0,0 +1,52 @@ +error: file is loaded as a module multiple times: `src/b.rs` + --> src/main.rs:5:1 + | +5 | mod b; + | ^^^^^^ first loaded here +6 | / #[path = "b.rs"] +7 | | mod b2; + | |_______^ loaded again here + | + = help: replace all but one `mod` item with `use` items + = note: `-D clippy::duplicate-mod` implied by `-D warnings` + +error: file is loaded as a module multiple times: `src/c.rs` + --> src/main.rs:9:1 + | +9 | mod c; + | ^^^^^^ first loaded here +10 | / #[path = "c.rs"] +11 | | mod c2; + | |_______^ loaded again here +12 | / #[path = "c.rs"] +13 | | mod c3; + | |_______^ loaded again here + | + = help: replace all but one `mod` item with `use` items + +error: file is loaded as a module multiple times: `src/d.rs` + --> src/main.rs:18:1 + | +18 | mod d; + | ^^^^^^ first loaded here +19 | / #[path = "d.rs"] +20 | | mod d2; + | |_______^ loaded again here + | + = help: replace all but one `mod` item with `use` items + +error: file is loaded as a module multiple times: `src/from_other_module.rs` + --> src/main.rs:15:1 + | +15 | mod from_other_module; + | ^^^^^^^^^^^^^^^^^^^^^^ first loaded here + | + ::: src/other_module/mod.rs:1:1 + | +1 | / #[path = "../from_other_module.rs"] +2 | | mod m; + | |______^ loaded again here + | + = help: replace all but one `mod` item with `use` items + +error: could not compile `duplicate_mod` (bin "duplicate_mod") due to 4 previous errors diff --git a/tests/ui-cargo/duplicate_mod/fail/src/main.stderr b/tests/ui-cargo/duplicate_mod/fail/src/main.stderr deleted file mode 100644 index 3b80d89a6865..000000000000 --- a/tests/ui-cargo/duplicate_mod/fail/src/main.stderr +++ /dev/null @@ -1,53 +0,0 @@ -error: file is loaded as a module multiple times: `$DIR/b.rs` - --> $DIR/main.rs:5:1 - | -LL | mod b; - | ^^^^^^ first loaded here -LL | / #[path = "b.rs"] -LL | | mod b2; - | |_______^ loaded again here - | - = help: replace all but one `mod` item with `use` items - = note: `-D clippy::duplicate-mod` implied by `-D warnings` - -error: file is loaded as a module multiple times: `$DIR/c.rs` - --> $DIR/main.rs:9:1 - | -LL | mod c; - | ^^^^^^ first loaded here -LL | / #[path = "c.rs"] -LL | | mod c2; - | |_______^ loaded again here -LL | / #[path = "c.rs"] -LL | | mod c3; - | |_______^ loaded again here - | - = help: replace all but one `mod` item with `use` items - -error: file is loaded as a module multiple times: `$DIR/d.rs` - --> $DIR/main.rs:18:1 - | -LL | mod d; - | ^^^^^^ first loaded here -LL | / #[path = "d.rs"] -LL | | mod d2; - | |_______^ loaded again here - | - = help: replace all but one `mod` item with `use` items - -error: file is loaded as a module multiple times: `$DIR/from_other_module.rs` - --> $DIR/main.rs:15:1 - | -LL | mod from_other_module; - | ^^^^^^^^^^^^^^^^^^^^^^ first loaded here - | - ::: $DIR/other_module/mod.rs:1:1 - | -LL | / #[path = "../from_other_module.rs"] -LL | | mod m; - | |______^ loaded again here - | - = help: replace all but one `mod` item with `use` items - -error: aborting due to 4 previous errors - diff --git a/tests/ui-cargo/feature_name/fail/Cargo.stderr b/tests/ui-cargo/feature_name/fail/Cargo.stderr new file mode 100644 index 000000000000..da2db45d3b83 --- /dev/null +++ b/tests/ui-cargo/feature_name/fail/Cargo.stderr @@ -0,0 +1,43 @@ +error: the "no-" prefix in the feature name "no-qaq" is negative + | + = help: consider renaming the feature to "qaq", but make sure the feature adds functionality + = note: `-D clippy::negative-feature-names` implied by `-D warnings` + +error: the "no_" prefix in the feature name "no_qaq" is negative + | + = help: consider renaming the feature to "qaq", but make sure the feature adds functionality + +error: the "not-" prefix in the feature name "not-orz" is negative + | + = help: consider renaming the feature to "orz", but make sure the feature adds functionality + +error: the "not_" prefix in the feature name "not_orz" is negative + | + = help: consider renaming the feature to "orz", but make sure the feature adds functionality + +error: the "-support" suffix in the feature name "qvq-support" is redundant + | + = help: consider renaming the feature to "qvq" + = note: `-D clippy::redundant-feature-names` implied by `-D warnings` + +error: the "_support" suffix in the feature name "qvq_support" is redundant + | + = help: consider renaming the feature to "qvq" + +error: the "use-" prefix in the feature name "use-qwq" is redundant + | + = help: consider renaming the feature to "qwq" + +error: the "use_" prefix in the feature name "use_qwq" is redundant + | + = help: consider renaming the feature to "qwq" + +error: the "with-" prefix in the feature name "with-owo" is redundant + | + = help: consider renaming the feature to "owo" + +error: the "with_" prefix in the feature name "with_owo" is redundant + | + = help: consider renaming the feature to "owo" + +error: could not compile `feature_name` (bin "feature_name") due to 10 previous errors diff --git a/tests/ui-cargo/feature_name/fail/src/main.stderr b/tests/ui-cargo/feature_name/fail/src/main.stderr deleted file mode 100644 index c6a11fa93eb5..000000000000 --- a/tests/ui-cargo/feature_name/fail/src/main.stderr +++ /dev/null @@ -1,44 +0,0 @@ -error: the "no-" prefix in the feature name "no-qaq" is negative - | - = help: consider renaming the feature to "qaq", but make sure the feature adds functionality - = note: `-D clippy::negative-feature-names` implied by `-D warnings` - -error: the "no_" prefix in the feature name "no_qaq" is negative - | - = help: consider renaming the feature to "qaq", but make sure the feature adds functionality - -error: the "not-" prefix in the feature name "not-orz" is negative - | - = help: consider renaming the feature to "orz", but make sure the feature adds functionality - -error: the "not_" prefix in the feature name "not_orz" is negative - | - = help: consider renaming the feature to "orz", but make sure the feature adds functionality - -error: the "-support" suffix in the feature name "qvq-support" is redundant - | - = help: consider renaming the feature to "qvq" - = note: `-D clippy::redundant-feature-names` implied by `-D warnings` - -error: the "_support" suffix in the feature name "qvq_support" is redundant - | - = help: consider renaming the feature to "qvq" - -error: the "use-" prefix in the feature name "use-qwq" is redundant - | - = help: consider renaming the feature to "qwq" - -error: the "use_" prefix in the feature name "use_qwq" is redundant - | - = help: consider renaming the feature to "qwq" - -error: the "with-" prefix in the feature name "with-owo" is redundant - | - = help: consider renaming the feature to "owo" - -error: the "with_" prefix in the feature name "with_owo" is redundant - | - = help: consider renaming the feature to "owo" - -error: aborting due to 10 previous errors - diff --git a/tests/ui-cargo/module_style/fail_mod/Cargo.stderr b/tests/ui-cargo/module_style/fail_mod/Cargo.stderr new file mode 100644 index 000000000000..c2907f319e64 --- /dev/null +++ b/tests/ui-cargo/module_style/fail_mod/Cargo.stderr @@ -0,0 +1,18 @@ +error: `mod.rs` files are required, found `src/bad/inner.rs` + --> src/bad/inner.rs:1:1 + | +1 | pub mod stuff; + | ^ + | + = help: move `src/bad/inner.rs` to `src/bad/inner/mod.rs` + = note: `-D clippy::self-named-module-files` implied by `-D warnings` + +error: `mod.rs` files are required, found `src/bad/inner/stuff.rs` + --> src/bad/inner/stuff.rs:1:1 + | +1 | pub mod most; + | ^ + | + = help: move `src/bad/inner/stuff.rs` to `src/bad/inner/stuff/mod.rs` + +error: could not compile `fail-mod` (bin "fail-mod") due to 2 previous errors diff --git a/tests/ui-cargo/module_style/fail_mod/src/main.stderr b/tests/ui-cargo/module_style/fail_mod/src/main.stderr deleted file mode 100644 index 697c8b57c4a2..000000000000 --- a/tests/ui-cargo/module_style/fail_mod/src/main.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error: `mod.rs` files are required, found `bad/inner.rs` - --> $DIR/bad/inner.rs:1:1 - | -LL | pub mod stuff; - | ^ - | - = help: move `bad/inner.rs` to `bad/inner/mod.rs` - = note: `-D clippy::self-named-module-files` implied by `-D warnings` - -error: `mod.rs` files are required, found `bad/inner/stuff.rs` - --> $DIR/bad/inner/stuff.rs:1:1 - | -LL | pub mod most; - | ^ - | - = help: move `bad/inner/stuff.rs` to `bad/inner/stuff/mod.rs` - -error: aborting due to 2 previous errors - diff --git a/tests/ui-cargo/module_style/fail_mod_remap/Cargo.stderr b/tests/ui-cargo/module_style/fail_mod_remap/Cargo.stderr new file mode 100644 index 000000000000..fcf1a3c5e66c --- /dev/null +++ b/tests/ui-cargo/module_style/fail_mod_remap/Cargo.stderr @@ -0,0 +1,10 @@ +error: `mod.rs` files are required, found `src/bad.rs` + --> src/bad.rs:1:1 + | +1 | pub mod inner; + | ^ + | + = help: move `src/bad.rs` to `src/bad/mod.rs` + = note: `-D clippy::self-named-module-files` implied by `-D warnings` + +error: could not compile `fail-mod-remap` (bin "fail-mod-remap") due to previous error diff --git a/tests/ui-cargo/module_style/fail_mod_remap/src/main.stderr b/tests/ui-cargo/module_style/fail_mod_remap/src/main.stderr deleted file mode 100644 index ea6ea98064a7..000000000000 --- a/tests/ui-cargo/module_style/fail_mod_remap/src/main.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error: `mod.rs` files are required, found `bad.rs` - --> /remapped/module_style/fail_mod_remap/src/bad.rs:1:1 - | -LL | pub mod inner; - | ^ - | - = help: move `bad.rs` to `bad/mod.rs` - = note: `-D clippy::self-named-module-files` implied by `-D warnings` - -error: aborting due to previous error - diff --git a/tests/ui-cargo/module_style/fail_no_mod/Cargo.stderr b/tests/ui-cargo/module_style/fail_no_mod/Cargo.stderr new file mode 100644 index 000000000000..f61642ca2efd --- /dev/null +++ b/tests/ui-cargo/module_style/fail_no_mod/Cargo.stderr @@ -0,0 +1,10 @@ +error: `mod.rs` files are not allowed, found `src/bad/mod.rs` + --> src/bad/mod.rs:1:1 + | +1 | pub struct Thing; + | ^ + | + = help: move `src/bad/mod.rs` to `src/bad.rs` + = note: `-D clippy::mod-module-files` implied by `-D warnings` + +error: could not compile `fail-no-mod` (bin "fail-no-mod") due to previous error diff --git a/tests/ui-cargo/module_style/fail_no_mod/src/main.stderr b/tests/ui-cargo/module_style/fail_no_mod/src/main.stderr deleted file mode 100644 index f40ceea234b9..000000000000 --- a/tests/ui-cargo/module_style/fail_no_mod/src/main.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error: `mod.rs` files are not allowed, found `bad/mod.rs` - --> $DIR/bad/mod.rs:1:1 - | -LL | pub struct Thing; - | ^ - | - = help: move `bad/mod.rs` to `bad.rs` - = note: `-D clippy::mod-module-files` implied by `-D warnings` - -error: aborting due to previous error - diff --git a/tests/ui-cargo/multiple_config_files/warn/Cargo.stderr b/tests/ui-cargo/multiple_config_files/warn/Cargo.stderr new file mode 100644 index 000000000000..d82b9e73f786 --- /dev/null +++ b/tests/ui-cargo/multiple_config_files/warn/Cargo.stderr @@ -0,0 +1,2 @@ +warning: using config file `$DIR/$DIR/.clippy.toml`, `$DIR/$DIR/clippy.toml` will be ignored + diff --git a/tests/ui-cargo/multiple_config_files/warn/src/main.stderr b/tests/ui-cargo/multiple_config_files/warn/src/main.stderr deleted file mode 100644 index aa1b3c638a03..000000000000 --- a/tests/ui-cargo/multiple_config_files/warn/src/main.stderr +++ /dev/null @@ -1,4 +0,0 @@ -warning: using config file `$SRC_DIR/.clippy.toml`, `$SRC_DIR/clippy.toml` will be ignored - -warning: 1 warning emitted - diff --git a/tests/ui-cargo/multiple_crate_versions/fail/Cargo.stderr b/tests/ui-cargo/multiple_crate_versions/fail/Cargo.stderr new file mode 100644 index 000000000000..5bcce920455c --- /dev/null +++ b/tests/ui-cargo/multiple_crate_versions/fail/Cargo.stderr @@ -0,0 +1,5 @@ +error: multiple versions for dependency `winapi`: 0.2.8, 0.3.9 + | + = note: `-D clippy::multiple-crate-versions` implied by `-D warnings` + +error: could not compile `multiple_crate_versions` (bin "multiple_crate_versions") due to previous error diff --git a/tests/ui-cargo/multiple_crate_versions/fail/src/main.stderr b/tests/ui-cargo/multiple_crate_versions/fail/src/main.stderr deleted file mode 100644 index f3113e093650..000000000000 --- a/tests/ui-cargo/multiple_crate_versions/fail/src/main.stderr +++ /dev/null @@ -1,6 +0,0 @@ -error: multiple versions for dependency `winapi`: 0.2.8, 0.3.9 - | - = note: `-D clippy::multiple-crate-versions` implied by `-D warnings` - -error: aborting due to previous error - diff --git a/tests/ui-cargo/update-all-references.sh b/tests/ui-cargo/update-all-references.sh index 4391499a1e1f..d42043070261 100755 --- a/tests/ui-cargo/update-all-references.sh +++ b/tests/ui-cargo/update-all-references.sh @@ -1,3 +1,3 @@ #!/bin/bash -echo "Please use 'cargo dev bless' instead." +echo "Please use 'cargo bless' instead." diff --git a/tests/ui-cargo/wildcard_dependencies/fail/Cargo.stderr b/tests/ui-cargo/wildcard_dependencies/fail/Cargo.stderr new file mode 100644 index 000000000000..b1578c9f3249 --- /dev/null +++ b/tests/ui-cargo/wildcard_dependencies/fail/Cargo.stderr @@ -0,0 +1,5 @@ +error: wildcard dependency for `regex` + | + = note: `-D clippy::wildcard-dependencies` implied by `-D warnings` + +error: could not compile `wildcard_dependencies` (bin "wildcard_dependencies") due to previous error diff --git a/tests/ui-cargo/wildcard_dependencies/fail/src/main.stderr b/tests/ui-cargo/wildcard_dependencies/fail/src/main.stderr deleted file mode 100644 index 9e65d2f99420..000000000000 --- a/tests/ui-cargo/wildcard_dependencies/fail/src/main.stderr +++ /dev/null @@ -1,6 +0,0 @@ -error: wildcard dependency for `regex` - | - = note: `-D clippy::wildcard-dependencies` implied by `-D warnings` - -error: aborting due to previous error - diff --git a/tests/ui-internal/check_formulation.rs b/tests/ui-internal/check_formulation.rs new file mode 100644 index 000000000000..43fc996033ea --- /dev/null +++ b/tests/ui-internal/check_formulation.rs @@ -0,0 +1,54 @@ +#![warn(clippy::almost_standard_lint_formulation)] +#![feature(rustc_private)] + +#[macro_use] +extern crate rustc_middle; +#[macro_use] +extern crate rustc_session; +extern crate rustc_lint; + +declare_tool_lint! { + /// # What it does + /// + /// Checks for usage of correct lint formulations + #[clippy::version = "pre 1.29.0"] + pub clippy::VALID, + Warn, + "One", + report_in_external_macro: true +} + +declare_tool_lint! { + /// # What it does + /// Check for lint formulations that are correct + #[clippy::version = "pre 1.29.0"] + pub clippy::INVALID1, + Warn, + "One", + report_in_external_macro: true +} + +declare_tool_lint! { + /// # What it does + /// Detects uses of incorrect formulations + #[clippy::version = "pre 1.29.0"] + pub clippy::INVALID2, + Warn, + "One", + report_in_external_macro: true +} + +declare_tool_lint! { + /// # What it does + /// Detects uses of incorrect formulations (allowed with attribute) + #[allow(clippy::almost_standard_lint_formulation)] + #[clippy::version = "pre 1.29.0"] + pub clippy::ALLOWED_INVALID, + Warn, + "One", + report_in_external_macro: true +} + +declare_lint_pass!(Pass => [VALID, INVALID1, INVALID2]); + +fn main() {} diff --git a/tests/ui-internal/check_formulation.stderr b/tests/ui-internal/check_formulation.stderr new file mode 100644 index 000000000000..10eabca4b9d7 --- /dev/null +++ b/tests/ui-internal/check_formulation.stderr @@ -0,0 +1,19 @@ +error: non-standard lint formulation + --> $DIR/check_formulation.rs:23:5 + | +LL | /// Check for lint formulations that are correct + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try using `Checks for` instead + = note: `-D clippy::almost-standard-lint-formulation` implied by `-D warnings` + +error: non-standard lint formulation + --> $DIR/check_formulation.rs:33:5 + | +LL | /// Detects uses of incorrect formulations + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try using `Checks for` instead + +error: aborting due to 2 previous errors + diff --git a/tests/ui-internal/custom_ice_message.stderr b/tests/ui-internal/custom_ice_message.stderr index b9ea5a64de75..b88aeae2a9b8 100644 --- a/tests/ui-internal/custom_ice_message.stderr +++ b/tests/ui-internal/custom_ice_message.stderr @@ -7,7 +7,7 @@ note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy note: rustc running on -note: compiler flags: -C prefer-dynamic -Z ui-testing +note: compiler flags: -Z ui-testing + +note: Clippy version: foo -query stack during panic: -thread panicked while processing panic. aborting. diff --git a/tests/ui-internal/if_chain_style.rs b/tests/ui-internal/if_chain_style.rs index b0d89e038aa8..b462b20e04c6 100644 --- a/tests/ui-internal/if_chain_style.rs +++ b/tests/ui-internal/if_chain_style.rs @@ -1,5 +1,10 @@ #![warn(clippy::if_chain_style)] -#![allow(clippy::no_effect, clippy::nonminimal_bool, clippy::missing_clippy_version_attribute)] +#![allow( + clippy::needless_if, + clippy::no_effect, + clippy::nonminimal_bool, + clippy::missing_clippy_version_attribute +)] extern crate if_chain; diff --git a/tests/ui-internal/if_chain_style.stderr b/tests/ui-internal/if_chain_style.stderr index d8f1ffb21ba6..b12df2786520 100644 --- a/tests/ui-internal/if_chain_style.stderr +++ b/tests/ui-internal/if_chain_style.stderr @@ -1,5 +1,5 @@ error: this `if` can be part of the inner `if_chain!` - --> $DIR/if_chain_style.rs:9:5 + --> $DIR/if_chain_style.rs:14:5 | LL | / if true { LL | | let x = ""; @@ -11,14 +11,14 @@ LL | | } | |_____^ | help: this `let` statement can also be in the `if_chain!` - --> $DIR/if_chain_style.rs:10:9 + --> $DIR/if_chain_style.rs:15:9 | LL | let x = ""; | ^^^^^^^^^^^ = note: `-D clippy::if-chain-style` implied by `-D warnings` error: `if a && b;` should be `if a; if b;` - --> $DIR/if_chain_style.rs:19:12 + --> $DIR/if_chain_style.rs:24:12 | LL | if true | ____________^ @@ -27,25 +27,25 @@ LL | | && false; | |____________________^ error: `let` expression should be inside `then { .. }` - --> $DIR/if_chain_style.rs:24:9 + --> $DIR/if_chain_style.rs:29:9 | LL | let x = ""; | ^^^^^^^^^^^ error: this `if` can be part of the outer `if_chain!` - --> $DIR/if_chain_style.rs:35:13 + --> $DIR/if_chain_style.rs:40:13 | LL | if true {} | ^^^^^^^^^^ | help: this `let` statement can also be in the `if_chain!` - --> $DIR/if_chain_style.rs:33:13 + --> $DIR/if_chain_style.rs:38:13 | LL | let x = ""; | ^^^^^^^^^^^ error: `if_chain!` only has one `if` - --> $DIR/if_chain_style.rs:29:5 + --> $DIR/if_chain_style.rs:34:5 | LL | / if_chain! { LL | | // single `if` condition @@ -59,13 +59,13 @@ LL | | } = note: this error originates in the macro `__if_chain` which comes from the expansion of the macro `if_chain` (in Nightly builds, run with -Z macro-backtrace for more info) error: `let` expression should be above the `if_chain!` - --> $DIR/if_chain_style.rs:40:9 + --> $DIR/if_chain_style.rs:45:9 | LL | let x = ""; | ^^^^^^^^^^^ error: this `if_chain!` can be merged with the outer `if_chain!` - --> $DIR/if_chain_style.rs:46:13 + --> $DIR/if_chain_style.rs:51:13 | LL | / if_chain! { LL | | if true; @@ -75,7 +75,7 @@ LL | | } | |_____________^ | help: these `let` statements can also be in the `if_chain!` - --> $DIR/if_chain_style.rs:43:13 + --> $DIR/if_chain_style.rs:48:13 | LL | / let x = ""; LL | | let x = ""; diff --git a/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.fixed b/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.fixed index 23e7bc16d239..c90856845280 100644 --- a/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.fixed +++ b/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.fixed @@ -1,5 +1,6 @@ //@run-rustfix #![warn(clippy::uninlined_format_args)] +#![allow(clippy::unnecessary_literal_unwrap)] fn main() { let local_i32 = 1; diff --git a/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.rs b/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.rs index d66b2b8ff6a0..661350c5c6d5 100644 --- a/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.rs +++ b/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.rs @@ -1,5 +1,6 @@ //@run-rustfix #![warn(clippy::uninlined_format_args)] +#![allow(clippy::unnecessary_literal_unwrap)] fn main() { let local_i32 = 1; diff --git a/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.stderr b/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.stderr index 1be0cda12fc1..6ec79a618de1 100644 --- a/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.stderr +++ b/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.stderr @@ -1,5 +1,5 @@ error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:9:5 + --> $DIR/uninlined_format_args.rs:10:5 | LL | println!("val='{}'", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -12,7 +12,7 @@ LL + println!("val='{local_i32}'"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:10:5 + --> $DIR/uninlined_format_args.rs:11:5 | LL | println!("Hello {} is {:.*}", "x", local_i32, local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL + println!("Hello {} is {local_f64:.local_i32$}", "x"); | error: literal with an empty format string - --> $DIR/uninlined_format_args.rs:10:35 + --> $DIR/uninlined_format_args.rs:11:35 | LL | println!("Hello {} is {:.*}", "x", local_i32, local_f64); | ^^^ @@ -37,7 +37,7 @@ LL + println!("Hello x is {:.*}", local_i32, local_f64); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:11:5 + --> $DIR/uninlined_format_args.rs:12:5 | LL | println!("Hello {} is {:.*}", local_i32, 5, local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + println!("Hello {local_i32} is {local_f64:.*}", 5); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:12:5 + --> $DIR/uninlined_format_args.rs:13:5 | LL | println!("Hello {} is {2:.*}", local_i32, 5, local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + println!("Hello {local_i32} is {local_f64:.*}", 5); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:13:5 + --> $DIR/uninlined_format_args.rs:14:5 | LL | println!("{}, {}", local_i32, local_opt.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs b/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs index fb5b1b193f84..33f7c8ba8042 100644 --- a/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs +++ b/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs @@ -1,4 +1,5 @@ #![warn(clippy::arithmetic_side_effects)] +#![allow(clippy::unnecessary_literal_unwrap)] use core::ops::{Add, Neg}; diff --git a/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.stderr b/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.stderr index ad89534aa1b0..4f98ca192311 100644 --- a/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.stderr +++ b/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.stderr @@ -1,5 +1,5 @@ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects_allowed.rs:68:13 + --> $DIR/arithmetic_side_effects_allowed.rs:69:13 | LL | let _ = Baz + Baz; | ^^^^^^^^^ @@ -7,49 +7,49 @@ LL | let _ = Baz + Baz; = note: `-D clippy::arithmetic-side-effects` implied by `-D warnings` error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects_allowed.rs:79:13 + --> $DIR/arithmetic_side_effects_allowed.rs:80:13 | LL | let _ = 1i32 + Baz; | ^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects_allowed.rs:82:13 + --> $DIR/arithmetic_side_effects_allowed.rs:83:13 | LL | let _ = 1i64 + Foo; | ^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects_allowed.rs:86:13 + --> $DIR/arithmetic_side_effects_allowed.rs:87:13 | LL | let _ = 1i64 + Baz; | ^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects_allowed.rs:97:13 + --> $DIR/arithmetic_side_effects_allowed.rs:98:13 | LL | let _ = Baz + 1i32; | ^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects_allowed.rs:100:13 + --> $DIR/arithmetic_side_effects_allowed.rs:101:13 | LL | let _ = Foo + 1i64; | ^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects_allowed.rs:104:13 + --> $DIR/arithmetic_side_effects_allowed.rs:105:13 | LL | let _ = Baz + 1i64; | ^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects_allowed.rs:113:13 + --> $DIR/arithmetic_side_effects_allowed.rs:114:13 | LL | let _ = -Bar; | ^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects_allowed.rs:115:13 + --> $DIR/arithmetic_side_effects_allowed.rs:116:13 | LL | let _ = -Baz; | ^^^^ diff --git a/tests/ui-toml/bad_toml/conf_bad_toml.rs b/tests/ui-toml/bad_toml/conf_bad_toml.rs index f328e4d9d04c..c69fcd300335 100644 --- a/tests/ui-toml/bad_toml/conf_bad_toml.rs +++ b/tests/ui-toml/bad_toml/conf_bad_toml.rs @@ -1 +1,3 @@ +//@error-in-other-file: error reading Clippy's configuration file: expected `.`, `=` + fn main() {} diff --git a/tests/ui-toml/bad_toml/conf_bad_toml.stderr b/tests/ui-toml/bad_toml/conf_bad_toml.stderr index 5b7e8c0db744..f7d53763a438 100644 --- a/tests/ui-toml/bad_toml/conf_bad_toml.stderr +++ b/tests/ui-toml/bad_toml/conf_bad_toml.stderr @@ -1,5 +1,5 @@ error: error reading Clippy's configuration file: expected `.`, `=` - --> $DIR/clippy.toml:1:4 + --> $DIR/$DIR/clippy.toml:1:4 | LL | fn this_is_obviously(not: a, toml: file) { | ^ diff --git a/tests/ui-toml/bad_toml_type/conf_bad_type.rs b/tests/ui-toml/bad_toml_type/conf_bad_type.rs index f328e4d9d04c..688c92d8717d 100644 --- a/tests/ui-toml/bad_toml_type/conf_bad_type.rs +++ b/tests/ui-toml/bad_toml_type/conf_bad_type.rs @@ -1 +1,3 @@ +//@error-in-other-file: invalid type: integer `42`, expected a sequence + fn main() {} diff --git a/tests/ui-toml/bad_toml_type/conf_bad_type.stderr b/tests/ui-toml/bad_toml_type/conf_bad_type.stderr index 386e1135df90..fb0a14081524 100644 --- a/tests/ui-toml/bad_toml_type/conf_bad_type.stderr +++ b/tests/ui-toml/bad_toml_type/conf_bad_type.stderr @@ -1,5 +1,5 @@ error: error reading Clippy's configuration file: invalid type: integer `42`, expected a sequence - --> $DIR/clippy.toml:1:20 + --> $DIR/$DIR/clippy.toml:1:20 | LL | disallowed-names = 42 | ^^ diff --git a/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr b/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr index 123ad94dd09d..89d84eb24556 100644 --- a/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr +++ b/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr @@ -1,11 +1,11 @@ warning: error reading Clippy's configuration file: deprecated field `cyclomatic-complexity-threshold`. Please use `cognitive-complexity-threshold` instead - --> $DIR/clippy.toml:2:1 + --> $DIR/$DIR/clippy.toml:2:1 | LL | cyclomatic-complexity-threshold = 2 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: error reading Clippy's configuration file: deprecated field `blacklisted-names`. Please use `disallowed-names` instead - --> $DIR/clippy.toml:3:1 + --> $DIR/$DIR/clippy.toml:3:1 | LL | blacklisted-names = [ "..", "wibble" ] | ^^^^^^^^^^^^^^^^^ diff --git a/tests/ui-toml/duplicated_keys/duplicated_keys.rs b/tests/ui-toml/duplicated_keys/duplicated_keys.rs index f328e4d9d04c..187775545ed7 100644 --- a/tests/ui-toml/duplicated_keys/duplicated_keys.rs +++ b/tests/ui-toml/duplicated_keys/duplicated_keys.rs @@ -1 +1,3 @@ +//@error-in-other-file: duplicate key `cognitive-complexity-threshold` + fn main() {} diff --git a/tests/ui-toml/duplicated_keys/duplicated_keys.stderr b/tests/ui-toml/duplicated_keys/duplicated_keys.stderr index 54997735274e..7c56dfdb948e 100644 --- a/tests/ui-toml/duplicated_keys/duplicated_keys.stderr +++ b/tests/ui-toml/duplicated_keys/duplicated_keys.stderr @@ -1,5 +1,5 @@ error: error reading Clippy's configuration file: duplicate key `cognitive-complexity-threshold` in document root - --> $DIR/clippy.toml:2:1 + --> $DIR/$DIR/clippy.toml:2:1 | LL | cognitive-complexity-threshold = 4 | ^ diff --git a/tests/ui-toml/duplicated_keys_deprecated/duplicated_keys.stderr b/tests/ui-toml/duplicated_keys_deprecated/duplicated_keys.stderr index 2ae7848f183b..0af8c0add6c6 100644 --- a/tests/ui-toml/duplicated_keys_deprecated/duplicated_keys.stderr +++ b/tests/ui-toml/duplicated_keys_deprecated/duplicated_keys.stderr @@ -1,11 +1,11 @@ error: error reading Clippy's configuration file: duplicate field `cognitive_complexity_threshold` (provided as `cyclomatic_complexity_threshold`) - --> $DIR/clippy.toml:3:1 + --> $DIR/$DIR/clippy.toml:3:1 | LL | cyclomatic-complexity-threshold = 3 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: error reading Clippy's configuration file: deprecated field `cyclomatic-complexity-threshold`. Please use `cognitive-complexity-threshold` instead - --> $DIR/clippy.toml:3:1 + --> $DIR/$DIR/clippy.toml:3:1 | LL | cyclomatic-complexity-threshold = 3 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui-toml/duplicated_keys_deprecated_2/duplicated_keys.stderr b/tests/ui-toml/duplicated_keys_deprecated_2/duplicated_keys.stderr index 53ad42712469..a4b1e9c335ca 100644 --- a/tests/ui-toml/duplicated_keys_deprecated_2/duplicated_keys.stderr +++ b/tests/ui-toml/duplicated_keys_deprecated_2/duplicated_keys.stderr @@ -1,11 +1,11 @@ error: error reading Clippy's configuration file: duplicate field `cognitive-complexity-threshold` - --> $DIR/clippy.toml:4:1 + --> $DIR/$DIR/clippy.toml:4:1 | LL | cognitive-complexity-threshold = 4 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: error reading Clippy's configuration file: deprecated field `cyclomatic-complexity-threshold`. Please use `cognitive-complexity-threshold` instead - --> $DIR/clippy.toml:2:1 + --> $DIR/$DIR/clippy.toml:2:1 | LL | cyclomatic-complexity-threshold = 3 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui-toml/excessive_nesting/auxiliary/proc_macros.rs b/tests/ui-toml/excessive_nesting/auxiliary/proc_macros.rs new file mode 100644 index 000000000000..ebadd4e440a9 --- /dev/null +++ b/tests/ui-toml/excessive_nesting/auxiliary/proc_macros.rs @@ -0,0 +1,472 @@ +// NOTE: Copied from `ui/auxiliary/proc_macros.rs`, couldn't get `../` to work for some reason + +#![feature(let_chains)] +#![feature(proc_macro_span)] +#![allow(clippy::excessive_nesting, dead_code)] + +extern crate proc_macro; + +use core::mem; +use proc_macro::{ + token_stream::IntoIter, + Delimiter::{self, Brace, Parenthesis}, + Group, Ident, Literal, Punct, + Spacing::{self, Alone, Joint}, + Span, TokenStream, TokenTree as TT, +}; + +type Result = core::result::Result; + +/// Make a `compile_error!` pointing to the given span. +fn make_error(msg: &str, span: Span) -> TokenStream { + TokenStream::from_iter([ + TT::Ident(Ident::new("compile_error", span)), + TT::Punct(punct_with_span('!', Alone, span)), + TT::Group({ + let mut msg = Literal::string(msg); + msg.set_span(span); + group_with_span(Parenthesis, TokenStream::from_iter([TT::Literal(msg)]), span) + }), + ]) +} + +fn expect_tt(tt: Option, f: impl FnOnce(TT) -> Option, expected: &str, span: Span) -> Result { + match tt { + None => Err(make_error( + &format!("unexpected end of input, expected {expected}"), + span, + )), + Some(tt) => { + let span = tt.span(); + match f(tt) { + Some(x) => Ok(x), + None => Err(make_error(&format!("unexpected token, expected {expected}"), span)), + } + }, + } +} + +fn punct_with_span(c: char, spacing: Spacing, span: Span) -> Punct { + let mut p = Punct::new(c, spacing); + p.set_span(span); + p +} + +fn group_with_span(delimiter: Delimiter, stream: TokenStream, span: Span) -> Group { + let mut g = Group::new(delimiter, stream); + g.set_span(span); + g +} + +/// Token used to escape the following token from the macro's span rules. +const ESCAPE_CHAR: char = '$'; + +/// Takes a single token followed by a sequence of tokens. Returns the sequence of tokens with their +/// span set to that of the first token. Tokens may be escaped with either `#ident` or `#(tokens)`. +#[proc_macro] +pub fn with_span(input: TokenStream) -> TokenStream { + let mut iter = input.into_iter(); + let span = iter.next().unwrap().span(); + let mut res = TokenStream::new(); + if let Err(e) = write_with_span(span, iter, &mut res) { + e + } else { + res + } +} + +/// Takes a sequence of tokens and return the tokens with the span set such that they appear to be +/// from an external macro. Tokens may be escaped with either `#ident` or `#(tokens)`. +#[proc_macro] +pub fn external(input: TokenStream) -> TokenStream { + let mut res = TokenStream::new(); + if let Err(e) = write_with_span(Span::mixed_site(), input.into_iter(), &mut res) { + e + } else { + res + } +} + +/// Copies all the tokens, replacing all their spans with the given span. Tokens can be escaped +/// either by `#ident` or `#(tokens)`. +fn write_with_span(s: Span, mut input: IntoIter, out: &mut TokenStream) -> Result<()> { + while let Some(tt) = input.next() { + match tt { + TT::Punct(p) if p.as_char() == ESCAPE_CHAR => { + expect_tt( + input.next(), + |tt| match tt { + tt @ (TT::Ident(_) | TT::Literal(_)) => { + out.extend([tt]); + Some(()) + }, + TT::Punct(mut p) if p.as_char() == ESCAPE_CHAR => { + p.set_span(s); + out.extend([TT::Punct(p)]); + Some(()) + }, + TT::Group(g) if g.delimiter() == Parenthesis => { + out.extend([TT::Group(group_with_span(Delimiter::None, g.stream(), g.span()))]); + Some(()) + }, + _ => None, + }, + "an ident, a literal, or parenthesized tokens", + p.span(), + )?; + }, + TT::Group(g) => { + let mut stream = TokenStream::new(); + write_with_span(s, g.stream().into_iter(), &mut stream)?; + out.extend([TT::Group(group_with_span(g.delimiter(), stream, s))]); + }, + mut tt => { + tt.set_span(s); + out.extend([tt]); + }, + } + } + Ok(()) +} + +/// Within the item this attribute is attached to, an `inline!` macro is available which expands the +/// contained tokens as though they came from a macro expansion. +/// +/// Within the `inline!` macro, any token preceded by `$` is passed as though it were an argument +/// with an automatically chosen fragment specifier. `$ident` will be passed as `ident`, `$1` or +/// `$"literal"` will be passed as `literal`, `$'lt` will be passed as `lifetime`, and `$(...)` will +/// pass the contained tokens as a `tt` sequence (the wrapping parenthesis are removed). If another +/// specifier is required it can be specified within parenthesis like `$(@expr ...)`. This will +/// expand the remaining tokens as a single argument. +/// +/// Multiple `inline!` macros may be nested within each other. This will expand as nested macro +/// calls. However, any arguments will be passed as though they came from the outermost context. +#[proc_macro_attribute] +pub fn inline_macros(args: TokenStream, input: TokenStream) -> TokenStream { + let mut args = args.into_iter(); + let mac_name = match args.next() { + Some(TT::Ident(name)) => Some(name), + Some(tt) => { + return make_error( + "unexpected argument, expected either an ident or no arguments", + tt.span(), + ); + }, + None => None, + }; + if let Some(tt) = args.next() { + return make_error( + "unexpected argument, expected either an ident or no arguments", + tt.span(), + ); + }; + + let mac_name = if let Some(mac_name) = mac_name { + Ident::new(&format!("__inline_mac_{mac_name}"), Span::call_site()) + } else { + let mut input = match LookaheadIter::new(input.clone().into_iter()) { + Some(x) => x, + None => return input, + }; + loop { + match input.next() { + None => break Ident::new("__inline_mac", Span::call_site()), + Some(TT::Ident(kind)) => match &*kind.to_string() { + "impl" => break Ident::new("__inline_mac_impl", Span::call_site()), + kind @ ("struct" | "enum" | "union" | "fn" | "mod" | "trait" | "type" | "const" | "static") => { + if let TT::Ident(name) = &input.tt { + break Ident::new(&format!("__inline_mac_{kind}_{name}"), Span::call_site()); + } else { + break Ident::new(&format!("__inline_mac_{kind}"), Span::call_site()); + } + }, + _ => {}, + }, + _ => {}, + } + } + }; + + let mut expander = Expander::default(); + let mut mac = MacWriter::new(mac_name); + if let Err(e) = expander.expand(input.into_iter(), &mut mac) { + return e; + } + let mut out = TokenStream::new(); + mac.finish(&mut out); + out.extend(expander.expn); + out +} + +/// Wraps a `TokenStream` iterator with a single token lookahead. +struct LookaheadIter { + tt: TT, + iter: IntoIter, +} +impl LookaheadIter { + fn new(mut iter: IntoIter) -> Option { + iter.next().map(|tt| Self { tt, iter }) + } + + /// Get's the lookahead token, replacing it with the next token in the stream. + /// Note: If there isn't a next token, this will not return the lookahead token. + fn next(&mut self) -> Option { + self.iter.next().map(|tt| mem::replace(&mut self.tt, tt)) + } +} + +/// Builds the macro used to implement all the `inline!` macro calls. +struct MacWriter { + name: Ident, + macros: TokenStream, + next_idx: usize, +} +impl MacWriter { + fn new(name: Ident) -> Self { + Self { + name, + macros: TokenStream::new(), + next_idx: 0, + } + } + + /// Inserts a new `inline!` call. + fn insert(&mut self, name_span: Span, bang_span: Span, body: Group, expander: &mut Expander) -> Result<()> { + let idx = self.next_idx; + self.next_idx += 1; + + let mut inner = Expander::for_arm(idx); + inner.expand(body.stream().into_iter(), self)?; + let new_arm = inner.arm.unwrap(); + + self.macros.extend([ + TT::Group(Group::new(Parenthesis, new_arm.args_def)), + TT::Punct(Punct::new('=', Joint)), + TT::Punct(Punct::new('>', Alone)), + TT::Group(Group::new(Parenthesis, inner.expn)), + TT::Punct(Punct::new(';', Alone)), + ]); + + expander.expn.extend([ + TT::Ident({ + let mut name = self.name.clone(); + name.set_span(name_span); + name + }), + TT::Punct(punct_with_span('!', Alone, bang_span)), + ]); + let mut call_body = TokenStream::from_iter([TT::Literal(Literal::usize_unsuffixed(idx))]); + if let Some(arm) = expander.arm.as_mut() { + if !new_arm.args.is_empty() { + arm.add_sub_args(new_arm.args, &mut call_body); + } + } else { + call_body.extend(new_arm.args); + } + let mut g = Group::new(body.delimiter(), call_body); + g.set_span(body.span()); + expander.expn.extend([TT::Group(g)]); + Ok(()) + } + + /// Creates the macro definition. + fn finish(self, out: &mut TokenStream) { + if self.next_idx != 0 { + out.extend([ + TT::Ident(Ident::new("macro_rules", Span::call_site())), + TT::Punct(Punct::new('!', Alone)), + TT::Ident(self.name), + TT::Group(Group::new(Brace, self.macros)), + ]) + } + } +} + +struct MacroArm { + args_def: TokenStream, + args: Vec, +} +impl MacroArm { + fn add_single_arg_def(&mut self, kind: &str, dollar_span: Span, arg_span: Span, out: &mut TokenStream) { + let mut name = Ident::new(&format!("_{}", self.args.len()), Span::call_site()); + self.args_def.extend([ + TT::Punct(Punct::new('$', Alone)), + TT::Ident(name.clone()), + TT::Punct(Punct::new(':', Alone)), + TT::Ident(Ident::new(kind, Span::call_site())), + ]); + name.set_span(arg_span); + out.extend([TT::Punct(punct_with_span('$', Alone, dollar_span)), TT::Ident(name)]); + } + + fn add_parenthesized_arg_def(&mut self, kind: Ident, dollar_span: Span, arg_span: Span, out: &mut TokenStream) { + let mut name = Ident::new(&format!("_{}", self.args.len()), Span::call_site()); + self.args_def.extend([TT::Group(Group::new( + Parenthesis, + TokenStream::from_iter([ + TT::Punct(Punct::new('$', Alone)), + TT::Ident(name.clone()), + TT::Punct(Punct::new(':', Alone)), + TT::Ident(kind), + ]), + ))]); + name.set_span(arg_span); + out.extend([TT::Punct(punct_with_span('$', Alone, dollar_span)), TT::Ident(name)]); + } + + fn add_multi_arg_def(&mut self, dollar_span: Span, arg_span: Span, out: &mut TokenStream) { + let mut name = Ident::new(&format!("_{}", self.args.len()), Span::call_site()); + self.args_def.extend([TT::Group(Group::new( + Parenthesis, + TokenStream::from_iter([ + TT::Punct(Punct::new('$', Alone)), + TT::Group(Group::new( + Parenthesis, + TokenStream::from_iter([ + TT::Punct(Punct::new('$', Alone)), + TT::Ident(name.clone()), + TT::Punct(Punct::new(':', Alone)), + TT::Ident(Ident::new("tt", Span::call_site())), + ]), + )), + TT::Punct(Punct::new('*', Alone)), + ]), + ))]); + name.set_span(arg_span); + out.extend([ + TT::Punct(punct_with_span('$', Alone, dollar_span)), + TT::Group(group_with_span( + Parenthesis, + TokenStream::from_iter([TT::Punct(punct_with_span('$', Alone, dollar_span)), TT::Ident(name)]), + dollar_span, + )), + TT::Punct(punct_with_span('*', Alone, dollar_span)), + ]); + } + + fn add_arg(&mut self, dollar_span: Span, tt: TT, input: &mut IntoIter, out: &mut TokenStream) -> Result<()> { + match tt { + TT::Punct(p) if p.as_char() == ESCAPE_CHAR => out.extend([TT::Punct(p)]), + TT::Punct(p) if p.as_char() == '\'' && p.spacing() == Joint => { + let lt_name = expect_tt( + input.next(), + |tt| match tt { + TT::Ident(x) => Some(x), + _ => None, + }, + "lifetime name", + p.span(), + )?; + let arg_span = p.span().join(lt_name.span()).unwrap_or(p.span()); + self.add_single_arg_def("lifetime", dollar_span, arg_span, out); + self.args.extend([TT::Punct(p), TT::Ident(lt_name)]); + }, + TT::Ident(x) => { + self.add_single_arg_def("ident", dollar_span, x.span(), out); + self.args.push(TT::Ident(x)); + }, + TT::Literal(x) => { + self.add_single_arg_def("literal", dollar_span, x.span(), out); + self.args.push(TT::Literal(x)); + }, + TT::Group(g) if g.delimiter() == Parenthesis => { + let mut inner = g.stream().into_iter(); + if let Some(TT::Punct(p)) = inner.next() + && p.as_char() == '@' + { + let kind = expect_tt( + inner.next(), + |tt| match tt { + TT::Ident(kind) => Some(kind), + _ => None, + }, + "a macro fragment specifier", + p.span(), + )?; + self.add_parenthesized_arg_def(kind, dollar_span, g.span(), out); + self.args.push(TT::Group(group_with_span(Parenthesis, inner.collect(), g.span()))) + } else { + self.add_multi_arg_def(dollar_span, g.span(), out); + self.args.push(TT::Group(g)); + } + }, + tt => return Err(make_error("unsupported escape", tt.span())), + }; + Ok(()) + } + + fn add_sub_args(&mut self, args: Vec, out: &mut TokenStream) { + self.add_multi_arg_def(Span::call_site(), Span::call_site(), out); + self.args + .extend([TT::Group(Group::new(Parenthesis, TokenStream::from_iter(args)))]); + } +} + +#[derive(Default)] +struct Expander { + arm: Option, + expn: TokenStream, +} +impl Expander { + fn for_arm(idx: usize) -> Self { + Self { + arm: Some(MacroArm { + args_def: TokenStream::from_iter([TT::Literal(Literal::usize_unsuffixed(idx))]), + args: Vec::new(), + }), + expn: TokenStream::new(), + } + } + + fn write_tt(&mut self, tt: TT, mac: &mut MacWriter) -> Result<()> { + match tt { + TT::Group(g) => { + let outer = mem::take(&mut self.expn); + self.expand(g.stream().into_iter(), mac)?; + let inner = mem::replace(&mut self.expn, outer); + self.expn + .extend([TT::Group(group_with_span(g.delimiter(), inner, g.span()))]); + }, + tt => self.expn.extend([tt]), + } + Ok(()) + } + + fn expand(&mut self, input: IntoIter, mac: &mut MacWriter) -> Result<()> { + let Some(mut input) = LookaheadIter::new(input) else { + return Ok(()); + }; + while let Some(tt) = input.next() { + if let TT::Punct(p) = &tt + && p.as_char() == ESCAPE_CHAR + && let Some(arm) = self.arm.as_mut() + { + arm.add_arg(p.span(), mem::replace(&mut input.tt, tt), &mut input.iter, &mut self.expn)?; + if input.next().is_none() { + return Ok(()); + } + } else if let TT::Punct(p) = &input.tt + && p.as_char() == '!' + && let TT::Ident(name) = &tt + && name.to_string() == "inline" + { + let g = expect_tt( + input.iter.next(), + |tt| match tt { + TT::Group(g) => Some(g), + _ => None, + }, + "macro arguments", + p.span(), + )?; + mac.insert(name.span(), p.span(), g, self)?; + if input.next().is_none() { + return Ok(()); + } + } else { + self.write_tt(tt, mac)?; + } + } + self.write_tt(input.tt, mac) + } +} diff --git a/tests/ui-toml/excessive_nesting/clippy.toml b/tests/ui-toml/excessive_nesting/clippy.toml new file mode 100644 index 000000000000..e60ac978cac9 --- /dev/null +++ b/tests/ui-toml/excessive_nesting/clippy.toml @@ -0,0 +1 @@ +excessive-nesting-threshold = 4 diff --git a/tests/ui-toml/excessive_nesting/excessive_nesting.rs b/tests/ui-toml/excessive_nesting/excessive_nesting.rs new file mode 100644 index 000000000000..c28220b973ec --- /dev/null +++ b/tests/ui-toml/excessive_nesting/excessive_nesting.rs @@ -0,0 +1,197 @@ +//@aux-build:proc_macros.rs:proc-macro +#![rustfmt::skip] +#![feature(custom_inner_attributes)] +#![allow(unused)] +#![allow(clippy::let_and_return)] +#![allow(clippy::redundant_closure_call)] +#![allow(clippy::no_effect)] +#![allow(clippy::unnecessary_operation)] +#![allow(clippy::never_loop)] +#![allow(clippy::needless_if)] +#![warn(clippy::excessive_nesting)] +#![allow(clippy::collapsible_if)] + +#[macro_use] +extern crate proc_macros; + +static X: u32 = { + let x = { + let y = { + let z = { + let w = { 3 }; + w + }; + z + }; + y + }; + x +}; + +macro_rules! xx { + () => {{ + { + { + { + { + { + { + { + { + { + { + println!("ehe"); // should not lint + } + } + } + } + } + } + } + } + } + } + }}; +} + +struct A; + +impl A { + pub fn a(&self, v: u32) { + struct B; + + impl B { + pub fn b() { + struct C; + + impl C { + pub fn c() {} + } + } + } + } +} + +struct D { d: u32 } + +trait Lol { + fn lmao() { + fn bb() { + fn cc() { + let x = { 1 }; // not a warning, but cc is + } + + let x = { 1 }; // warning + } + } +} + +#[allow(clippy::excessive_nesting)] +fn l() {{{{{{{{{}}}}}}}}} + +use a::{b::{c::{d::{e::{f::{}}}}}}; // should not lint + +pub mod a { + pub mod b { + pub mod c { + pub mod d { + pub mod e { + pub mod f {} + } // not here + } // only warning should be here + } + } +} + +fn a_but_not(v: u32) {} + +fn main() { + let a = A; + + a_but_not({{{{{{{{0}}}}}}}}); + a.a({{{{{{{{{0}}}}}}}}}); + (0, {{{{{{{1}}}}}}}); + + if true { + if true { + if true { + if true { + if true { + + } + } + } + } + } + + let y = (|| { + let x = (|| { + let y = (|| { + let z = (|| { + let w = { 3 }; + w + })(); + z + })(); + y + })(); + x + })(); + + external! { {{{{{{{{{{{{{{{{}}}}}}}}}}}}}}}} }; // ensure this isn't linted in external macros + with_span! { span {{{{{{{{{{{{}}}}}}}}}}}} }; // don't lint for proc macros + xx!(); // ensure this is never linted + let boo = true; + !{boo as u32 + !{boo as u32 + !{boo as u32}}}; + + // this is a mess, but that's intentional + let mut y = 1; + y += {{{{{5}}}}}; + let z = y + {{{{{{{{{5}}}}}}}}}; + [0, {{{{{{{{{{0}}}}}}}}}}]; + let mut xx = [0; {{{{{{{{100}}}}}}}}]; + xx[{{{{{{{{{{{{{{{{{{{{{{{{3}}}}}}}}}}}}}}}}}}}}}}}}]; + &mut {{{{{{{{{{y}}}}}}}}}}; + + for i in {{{{xx}}}} {{{{{{{{}}}}}}}} + + while let Some(i) = {{{{{{Some(1)}}}}}} {{{{{{{}}}}}}} + + while {{{{{{{{true}}}}}}}} {{{{{{{{{}}}}}}}}} + + let d = D { d: {{{{{{{{{{{{{{{{{{{{{{{3}}}}}}}}}}}}}}}}}}}}}}} }; + + {{{{1;}}}}..{{{{{{3}}}}}}; + {{{{1;}}}}..={{{{{{{{{{{{{{{{{{{{{{{{{{6}}}}}}}}}}}}}}}}}}}}}}}}}}; + ..{{{{{{{5}}}}}}}; + ..={{{{{3}}}}}; + {{{{{1;}}}}}..; + + loop { break {{{{1}}}} }; + loop {{{{{{}}}}}} + + match {{{{{{true}}}}}} { + true => {{{{}}}}, + false => {{{{}}}}, + } + + { + { + { + { + println!("warning! :)"); + } + } + } + } +} + +async fn b() -> u32 { + async fn c() -> u32 {{{{{{{0}}}}}}} + + c().await +} + +async fn a() { + {{{{b().await}}}}; +} diff --git a/tests/ui-toml/excessive_nesting/excessive_nesting.stderr b/tests/ui-toml/excessive_nesting/excessive_nesting.stderr new file mode 100644 index 000000000000..1a7311b33e86 --- /dev/null +++ b/tests/ui-toml/excessive_nesting/excessive_nesting.stderr @@ -0,0 +1,314 @@ +error: this block is too nested + --> $DIR/excessive_nesting.rs:21:25 + | +LL | let w = { 3 }; + | ^^^^^ + | + = help: try refactoring your code to minimize nesting + = note: `-D clippy::excessive-nesting` implied by `-D warnings` + +error: this block is too nested + --> $DIR/excessive_nesting.rs:67:17 + | +LL | / impl C { +LL | | pub fn c() {} +LL | | } + | |_________________^ + | + = help: try refactoring your code to minimize nesting + +error: this block is too nested + --> $DIR/excessive_nesting.rs:81:25 + | +LL | let x = { 1 }; // not a warning, but cc is + | ^^^^^ + | + = help: try refactoring your code to minimize nesting + +error: this block is too nested + --> $DIR/excessive_nesting.rs:98:17 + | +LL | / pub mod e { +LL | | pub mod f {} +LL | | } // not here + | |_________________^ + | + = help: try refactoring your code to minimize nesting + +error: this block is too nested + --> $DIR/excessive_nesting.rs:111:18 + | +LL | a_but_not({{{{{{{{0}}}}}}}}); + | ^^^^^^^^^^^ + | + = help: try refactoring your code to minimize nesting + +error: this block is too nested + --> $DIR/excessive_nesting.rs:112:12 + | +LL | a.a({{{{{{{{{0}}}}}}}}}); + | ^^^^^^^^^^^^^ + | + = help: try refactoring your code to minimize nesting + +error: this block is too nested + --> $DIR/excessive_nesting.rs:113:12 + | +LL | (0, {{{{{{{1}}}}}}}); + | ^^^^^^^^^ + | + = help: try refactoring your code to minimize nesting + +error: this block is too nested + --> $DIR/excessive_nesting.rs:118:25 + | +LL | if true { + | _________________________^ +LL | | if true { +LL | | +LL | | } +LL | | } + | |_________________^ + | + = help: try refactoring your code to minimize nesting + +error: this block is too nested + --> $DIR/excessive_nesting.rs:130:29 + | +LL | let z = (|| { + | _____________________________^ +LL | | let w = { 3 }; +LL | | w +LL | | })(); + | |_________________^ + | + = help: try refactoring your code to minimize nesting + +error: this block is too nested + --> $DIR/excessive_nesting.rs:149:13 + | +LL | y += {{{{{5}}}}}; + | ^^^^^ + | + = help: try refactoring your code to minimize nesting + +error: this block is too nested + --> $DIR/excessive_nesting.rs:150:20 + | +LL | let z = y + {{{{{{{{{5}}}}}}}}}; + | ^^^^^^^^^^^^^ + | + = help: try refactoring your code to minimize nesting + +error: this block is too nested + --> $DIR/excessive_nesting.rs:151:12 + | +LL | [0, {{{{{{{{{{0}}}}}}}}}}]; + | ^^^^^^^^^^^^^^^ + | + = help: try refactoring your code to minimize nesting + +error: this block is too nested + --> $DIR/excessive_nesting.rs:152:25 + | +LL | let mut xx = [0; {{{{{{{{100}}}}}}}}]; + | ^^^^^^^^^^^^^ + | + = help: try refactoring your code to minimize nesting + +error: this block is too nested + --> $DIR/excessive_nesting.rs:153:11 + | +LL | xx[{{{{{{{{{{{{{{{{{{{{{{{{3}}}}}}}}}}}}}}}}}}}}}}}}]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try refactoring your code to minimize nesting + +error: this block is too nested + --> $DIR/excessive_nesting.rs:154:13 + | +LL | &mut {{{{{{{{{{y}}}}}}}}}}; + | ^^^^^^^^^^^^^^^ + | + = help: try refactoring your code to minimize nesting + +error: this block is too nested + --> $DIR/excessive_nesting.rs:156:17 + | +LL | for i in {{{{xx}}}} {{{{{{{{}}}}}}}} + | ^^^^ + | + = help: try refactoring your code to minimize nesting + +error: this block is too nested + --> $DIR/excessive_nesting.rs:156:28 + | +LL | for i in {{{{xx}}}} {{{{{{{{}}}}}}}} + | ^^^^^^^^^^ + | + = help: try refactoring your code to minimize nesting + +error: this block is too nested + --> $DIR/excessive_nesting.rs:158:28 + | +LL | while let Some(i) = {{{{{{Some(1)}}}}}} {{{{{{{}}}}}}} + | ^^^^^^^^^^^^^ + | + = help: try refactoring your code to minimize nesting + +error: this block is too nested + --> $DIR/excessive_nesting.rs:158:48 + | +LL | while let Some(i) = {{{{{{Some(1)}}}}}} {{{{{{{}}}}}}} + | ^^^^^^^^ + | + = help: try refactoring your code to minimize nesting + +error: this block is too nested + --> $DIR/excessive_nesting.rs:160:14 + | +LL | while {{{{{{{{true}}}}}}}} {{{{{{{{{}}}}}}}}} + | ^^^^^^^^^^^^^^ + | + = help: try refactoring your code to minimize nesting + +error: this block is too nested + --> $DIR/excessive_nesting.rs:160:35 + | +LL | while {{{{{{{{true}}}}}}}} {{{{{{{{{}}}}}}}}} + | ^^^^^^^^^^^^ + | + = help: try refactoring your code to minimize nesting + +error: this block is too nested + --> $DIR/excessive_nesting.rs:162:23 + | +LL | let d = D { d: {{{{{{{{{{{{{{{{{{{{{{{3}}}}}}}}}}}}}}}}}}}}}}} }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try refactoring your code to minimize nesting + +error: this block is too nested + --> $DIR/excessive_nesting.rs:164:8 + | +LL | {{{{1;}}}}..{{{{{{3}}}}}}; + | ^^^^ + | + = help: try refactoring your code to minimize nesting + +error: this block is too nested + --> $DIR/excessive_nesting.rs:164:20 + | +LL | {{{{1;}}}}..{{{{{{3}}}}}}; + | ^^^^^^^ + | + = help: try refactoring your code to minimize nesting + +error: this block is too nested + --> $DIR/excessive_nesting.rs:165:8 + | +LL | {{{{1;}}}}..={{{{{{{{{{{{{{{{{{{{{{{{{{6}}}}}}}}}}}}}}}}}}}}}}}}}}; + | ^^^^ + | + = help: try refactoring your code to minimize nesting + +error: this block is too nested + --> $DIR/excessive_nesting.rs:165:21 + | +LL | {{{{1;}}}}..={{{{{{{{{{{{{{{{{{{{{{{{{{6}}}}}}}}}}}}}}}}}}}}}}}}}}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: try refactoring your code to minimize nesting + +error: this block is too nested + --> $DIR/excessive_nesting.rs:166:10 + | +LL | ..{{{{{{{5}}}}}}}; + | ^^^^^^^^^ + | + = help: try refactoring your code to minimize nesting + +error: this block is too nested + --> $DIR/excessive_nesting.rs:167:11 + | +LL | ..={{{{{3}}}}}; + | ^^^^^ + | + = help: try refactoring your code to minimize nesting + +error: this block is too nested + --> $DIR/excessive_nesting.rs:168:8 + | +LL | {{{{{1;}}}}}..; + | ^^^^^^ + | + = help: try refactoring your code to minimize nesting + +error: this block is too nested + --> $DIR/excessive_nesting.rs:170:20 + | +LL | loop { break {{{{1}}}} }; + | ^^^^^ + | + = help: try refactoring your code to minimize nesting + +error: this block is too nested + --> $DIR/excessive_nesting.rs:171:13 + | +LL | loop {{{{{{}}}}}} + | ^^^^^^ + | + = help: try refactoring your code to minimize nesting + +error: this block is too nested + --> $DIR/excessive_nesting.rs:173:14 + | +LL | match {{{{{{true}}}}}} { + | ^^^^^^^^^^ + | + = help: try refactoring your code to minimize nesting + +error: this block is too nested + --> $DIR/excessive_nesting.rs:174:20 + | +LL | true => {{{{}}}}, + | ^^ + | + = help: try refactoring your code to minimize nesting + +error: this block is too nested + --> $DIR/excessive_nesting.rs:175:21 + | +LL | false => {{{{}}}}, + | ^^ + | + = help: try refactoring your code to minimize nesting + +error: this block is too nested + --> $DIR/excessive_nesting.rs:181:17 + | +LL | / { +LL | | println!("warning! :)"); +LL | | } + | |_________________^ + | + = help: try refactoring your code to minimize nesting + +error: this block is too nested + --> $DIR/excessive_nesting.rs:190:28 + | +LL | async fn c() -> u32 {{{{{{{0}}}}}}} + | ^^^^^^^^^ + | + = help: try refactoring your code to minimize nesting + +error: this block is too nested + --> $DIR/excessive_nesting.rs:196:8 + | +LL | {{{{b().await}}}}; + | ^^^^^^^^^^^ + | + = help: try refactoring your code to minimize nesting + +error: aborting due to 37 previous errors + diff --git a/tests/ui-toml/expect_used/expect_used.rs b/tests/ui-toml/expect_used/expect_used.rs index 9e267c893005..206788e19f02 100644 --- a/tests/ui-toml/expect_used/expect_used.rs +++ b/tests/ui-toml/expect_used/expect_used.rs @@ -1,5 +1,6 @@ //@compile-flags: --test #![warn(clippy::expect_used)] +#![allow(clippy::unnecessary_literal_unwrap)] fn expect_option() { let opt = Some(0); diff --git a/tests/ui-toml/expect_used/expect_used.stderr b/tests/ui-toml/expect_used/expect_used.stderr index 1e9bb48c333c..9eef0e1bfaa1 100644 --- a/tests/ui-toml/expect_used/expect_used.stderr +++ b/tests/ui-toml/expect_used/expect_used.stderr @@ -1,5 +1,5 @@ error: used `expect()` on an `Option` value - --> $DIR/expect_used.rs:6:13 + --> $DIR/expect_used.rs:7:13 | LL | let _ = opt.expect(""); | ^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | let _ = opt.expect(""); = note: `-D clippy::expect-used` implied by `-D warnings` error: used `expect()` on a `Result` value - --> $DIR/expect_used.rs:11:13 + --> $DIR/expect_used.rs:12:13 | LL | let _ = res.expect(""); | ^^^^^^^^^^^^^^ diff --git a/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.rs b/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.rs index 2ebf28645e51..03fa719975b6 100644 --- a/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.rs +++ b/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.rs @@ -1,3 +1,5 @@ +//@error-in-other-file: `invalid.version` is not a valid Rust version + #![allow(clippy::redundant_clone)] fn main() {} diff --git a/tests/ui-toml/lint_decimal_readability/test.rs b/tests/ui-toml/lint_decimal_readability/test.rs index 2498672d77fb..bd5110138c8c 100644 --- a/tests/ui-toml/lint_decimal_readability/test.rs +++ b/tests/ui-toml/lint_decimal_readability/test.rs @@ -1,5 +1,5 @@ #![allow(clippy::excessive_precision)] -#[deny(clippy::unreadable_literal)] +#![warn(clippy::unreadable_literal)] fn allow_inconsistent_digit_grouping() { #![allow(clippy::inconsistent_digit_grouping)] diff --git a/tests/ui-toml/lint_decimal_readability/test.stderr b/tests/ui-toml/lint_decimal_readability/test.stderr index be505bda4792..ac9d89d0cbee 100644 --- a/tests/ui-toml/lint_decimal_readability/test.stderr +++ b/tests/ui-toml/lint_decimal_readability/test.stderr @@ -6,5 +6,13 @@ LL | let _fail1 = 100_200_300.123456789; | = note: `-D clippy::inconsistent-digit-grouping` implied by `-D warnings` -error: aborting due to previous error +error: long literal lacking separators + --> $DIR/test.rs:22:18 + | +LL | let _fail2 = 100200300.300200100; + | ^^^^^^^^^^^^^^^^^^^ help: consider: `100_200_300.300_200_100` + | + = note: `-D clippy::unreadable-literal` implied by `-D warnings` + +error: aborting due to 2 previous errors diff --git a/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs b/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs index 21849a14fa95..da76bb20fd96 100644 --- a/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs +++ b/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs @@ -3,6 +3,7 @@ fn below_limit() { let slice: Option<&[u32]> = Some(&[1, 2, 3]); if let Some(slice) = slice { + //~^ ERROR: binding can be a slice pattern // This would usually not be linted but is included now due to the // index limit in the config file println!("{}", slice[7]); diff --git a/tests/ui-toml/min_ident_chars/auxiliary/extern_types.rs b/tests/ui-toml/min_ident_chars/auxiliary/extern_types.rs new file mode 100644 index 000000000000..06a144f2218c --- /dev/null +++ b/tests/ui-toml/min_ident_chars/auxiliary/extern_types.rs @@ -0,0 +1,3 @@ +#![allow(nonstandard_style, unused)] + +pub struct Aaa; diff --git a/tests/ui-toml/min_ident_chars/clippy.toml b/tests/ui-toml/min_ident_chars/clippy.toml new file mode 100644 index 000000000000..0114ca750143 --- /dev/null +++ b/tests/ui-toml/min_ident_chars/clippy.toml @@ -0,0 +1,2 @@ +allowed-idents-below-min-chars = ["Owo", "Uwu", "wha", "t_e", "lse", "_do", "_i_", "put", "her", "_e"] +min-ident-chars-threshold = 3 diff --git a/tests/ui-toml/min_ident_chars/min_ident_chars.rs b/tests/ui-toml/min_ident_chars/min_ident_chars.rs new file mode 100644 index 000000000000..4326c7159c83 --- /dev/null +++ b/tests/ui-toml/min_ident_chars/min_ident_chars.rs @@ -0,0 +1,19 @@ +//@aux-build:extern_types.rs +#![allow(nonstandard_style, unused)] +#![warn(clippy::min_ident_chars)] + +extern crate extern_types; +use extern_types::Aaa; + +struct Owo { + Uwu: u128, + aaa: Aaa, +} + +fn main() { + let wha = 1; + let vvv = 1; + let uuu = 1; + let (mut a, mut b) = (1, 2); + for i in 0..1000 {} +} diff --git a/tests/ui-toml/min_ident_chars/min_ident_chars.stderr b/tests/ui-toml/min_ident_chars/min_ident_chars.stderr new file mode 100644 index 000000000000..d9a27628ddb2 --- /dev/null +++ b/tests/ui-toml/min_ident_chars/min_ident_chars.stderr @@ -0,0 +1,46 @@ +error: this ident is too short (3 <= 3) + --> $DIR/min_ident_chars.rs:6:19 + | +LL | use extern_types::Aaa; + | ^^^ + | + = note: `-D clippy::min-ident-chars` implied by `-D warnings` + +error: this ident is too short (3 <= 3) + --> $DIR/min_ident_chars.rs:10:5 + | +LL | aaa: Aaa, + | ^^^ + +error: this ident is too short (3 <= 3) + --> $DIR/min_ident_chars.rs:15:9 + | +LL | let vvv = 1; + | ^^^ + +error: this ident is too short (3 <= 3) + --> $DIR/min_ident_chars.rs:16:9 + | +LL | let uuu = 1; + | ^^^ + +error: this ident is too short (1 <= 3) + --> $DIR/min_ident_chars.rs:17:14 + | +LL | let (mut a, mut b) = (1, 2); + | ^ + +error: this ident is too short (1 <= 3) + --> $DIR/min_ident_chars.rs:17:21 + | +LL | let (mut a, mut b) = (1, 2); + | ^ + +error: this ident is too short (1 <= 3) + --> $DIR/min_ident_chars.rs:18:9 + | +LL | for i in 0..1000 {} + | ^ + +error: aborting due to 7 previous errors + diff --git a/tests/ui-toml/min_rust_version/min_rust_version.rs b/tests/ui-toml/min_rust_version/min_rust_version.rs index 1e3ec123a3c8..e1dc3f4389c0 100644 --- a/tests/ui-toml/min_rust_version/min_rust_version.rs +++ b/tests/ui-toml/min_rust_version/min_rust_version.rs @@ -41,7 +41,7 @@ fn match_like_matches() { fn match_same_arms() { match (1, 2, 3) { (1, .., 3) => 42, - (.., 3) => 42, //~ ERROR match arms have same body + (.., 3) => 42, _ => 0, }; } @@ -49,7 +49,7 @@ fn match_same_arms() { fn match_same_arms2() { let _ = match Some(42) { Some(_) => 24, - None => 24, //~ ERROR match arms have same body + None => 24, }; } diff --git a/tests/ui-toml/module_inception/clippy.toml b/tests/ui-toml/module_inception/clippy.toml new file mode 100644 index 000000000000..787620d865cc --- /dev/null +++ b/tests/ui-toml/module_inception/clippy.toml @@ -0,0 +1 @@ +allow-private-module-inception = true diff --git a/tests/ui-toml/module_inception/module_inception.rs b/tests/ui-toml/module_inception/module_inception.rs new file mode 100644 index 000000000000..cd495c884a43 --- /dev/null +++ b/tests/ui-toml/module_inception/module_inception.rs @@ -0,0 +1,34 @@ +#![warn(clippy::module_inception)] + +// Lint +pub mod foo2 { + pub mod bar2 { + pub mod bar2 { + pub mod foo2 {} + } + pub mod foo2 {} + } + pub mod foo2 { + pub mod bar2 {} + } +} + +// Don't lint +mod foo { + pub mod bar { + pub mod foo { + pub mod bar {} + } + } + pub mod foo { + pub mod bar {} + } +} + +// No warning. See . +pub mod bar { + #[allow(clippy::module_inception)] + pub mod bar {} +} + +fn main() {} diff --git a/tests/ui-toml/module_inception/module_inception.stderr b/tests/ui-toml/module_inception/module_inception.stderr new file mode 100644 index 000000000000..a5a09c322e13 --- /dev/null +++ b/tests/ui-toml/module_inception/module_inception.stderr @@ -0,0 +1,20 @@ +error: module has the same name as its containing module + --> $DIR/module_inception.rs:6:9 + | +LL | / pub mod bar2 { +LL | | pub mod foo2 {} +LL | | } + | |_________^ + | + = note: `-D clippy::module-inception` implied by `-D warnings` + +error: module has the same name as its containing module + --> $DIR/module_inception.rs:11:5 + | +LL | / pub mod foo2 { +LL | | pub mod bar2 {} +LL | | } + | |_____^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui-toml/nonstandard_macro_braces/auxiliary/proc_macro_derive.rs b/tests/ui-toml/nonstandard_macro_braces/auxiliary/proc_macro_derive.rs index f5761c6afeb3..e7ac05dd3c63 100644 --- a/tests/ui-toml/nonstandard_macro_braces/auxiliary/proc_macro_derive.rs +++ b/tests/ui-toml/nonstandard_macro_braces/auxiliary/proc_macro_derive.rs @@ -1,8 +1,3 @@ -//@compile-flags: --emit=link -//@no-prefer-dynamic - -#![crate_type = "proc-macro"] - extern crate proc_macro; use proc_macro::TokenStream; diff --git a/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.fixed b/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.fixed index e4747bedddb8..054db5d93305 100644 --- a/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.fixed +++ b/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.fixed @@ -1,4 +1,4 @@ -//@aux-build:proc_macro_derive.rs +//@aux-build:proc_macro_derive.rs:proc-macro //@run-rustfix #![warn(clippy::nonstandard_macro_braces)] diff --git a/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs b/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs index 54edded99f41..95d1a2297e53 100644 --- a/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs +++ b/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs @@ -1,4 +1,4 @@ -//@aux-build:proc_macro_derive.rs +//@aux-build:proc_macro_derive.rs:proc-macro //@run-rustfix #![warn(clippy::nonstandard_macro_braces)] diff --git a/tests/ui-toml/suppress_lint_in_const/test.rs b/tests/ui-toml/suppress_lint_in_const/test.rs index 5a2df9f6c5d9..17c1b03d88c6 100644 --- a/tests/ui-toml/suppress_lint_in_const/test.rs +++ b/tests/ui-toml/suppress_lint_in_const/test.rs @@ -3,11 +3,17 @@ // We also check the out_of_bounds_indexing lint here, because it lints similar things and // we want to avoid false positives. #![warn(clippy::out_of_bounds_indexing)] -#![allow(unconditional_panic, clippy::no_effect, clippy::unnecessary_operation)] +#![allow( + unconditional_panic, + clippy::no_effect, + clippy::unnecessary_operation, + clippy::useless_vec +)] const ARR: [i32; 2] = [1, 2]; const REF: &i32 = &ARR[idx()]; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true. const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts. +//~^ ERROR: failed const fn idx() -> usize { 1 @@ -29,6 +35,8 @@ fn main() { x[const { idx4() }]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays. const { &ARR[idx()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true. const { &ARR[idx4()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true. + // + //~^^ ERROR: failed let y = &x; y[0]; // Ok, referencing shouldn't affect this lint. See the issue 6021 diff --git a/tests/ui-toml/suppress_lint_in_const/test.stderr b/tests/ui-toml/suppress_lint_in_const/test.stderr index bc178b7e1319..14e13194427c 100644 --- a/tests/ui-toml/suppress_lint_in_const/test.stderr +++ b/tests/ui-toml/suppress_lint_in_const/test.stderr @@ -1,17 +1,17 @@ error[E0080]: evaluation of `main::{constant#3}` failed - --> $DIR/test.rs:31:14 + --> $DIR/test.rs:37:14 | LL | const { &ARR[idx4()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true. | ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4 note: erroneous constant used - --> $DIR/test.rs:31:5 + --> $DIR/test.rs:37:5 | LL | const { &ARR[idx4()] }; // Ok, should not produce stderr, since `suppress-restriction-lint-in-const` is set true. | ^^^^^^^^^^^^^^^^^^^^^^ error: indexing may panic - --> $DIR/test.rs:22:5 + --> $DIR/test.rs:28:5 | LL | x[index]; | ^^^^^^^^ @@ -20,7 +20,7 @@ LL | x[index]; = note: `-D clippy::indexing-slicing` implied by `-D warnings` error: indexing may panic - --> $DIR/test.rs:38:5 + --> $DIR/test.rs:46:5 | LL | v[0]; | ^^^^ @@ -28,7 +28,7 @@ LL | v[0]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> $DIR/test.rs:39:5 + --> $DIR/test.rs:47:5 | LL | v[10]; | ^^^^^ @@ -36,7 +36,7 @@ LL | v[10]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> $DIR/test.rs:40:5 + --> $DIR/test.rs:48:5 | LL | v[1 << 3]; | ^^^^^^^^^ @@ -44,7 +44,7 @@ LL | v[1 << 3]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> $DIR/test.rs:46:5 + --> $DIR/test.rs:54:5 | LL | v[N]; | ^^^^ @@ -52,7 +52,7 @@ LL | v[N]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> $DIR/test.rs:47:5 + --> $DIR/test.rs:55:5 | LL | v[M]; | ^^^^ @@ -60,7 +60,7 @@ LL | v[M]; = help: consider using `.get(n)` or `.get_mut(n)` instead error[E0080]: evaluation of constant value failed - --> $DIR/test.rs:10:24 + --> $DIR/test.rs:15:24 | LL | const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts. | ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4 diff --git a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs index 8e1a1710a6ce..63fdea710cb6 100644 --- a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs +++ b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs @@ -1,6 +1,8 @@ //@compile-flags: --crate-name conf_disallowed_methods +#![allow(clippy::needless_raw_strings)] #![warn(clippy::disallowed_methods)] +#![allow(clippy::useless_vec)] extern crate futures; extern crate regex; diff --git a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr index 148d1cae51f1..fc137c225d83 100644 --- a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr +++ b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr @@ -1,5 +1,5 @@ error: use of a disallowed method `regex::Regex::new` - --> $DIR/conf_disallowed_methods.rs:33:14 + --> $DIR/conf_disallowed_methods.rs:35:14 | LL | let re = Regex::new(r"ab.*c").unwrap(); | ^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | let re = Regex::new(r"ab.*c").unwrap(); = note: `-D clippy::disallowed-methods` implied by `-D warnings` error: use of a disallowed method `regex::Regex::is_match` - --> $DIR/conf_disallowed_methods.rs:34:5 + --> $DIR/conf_disallowed_methods.rs:36:5 | LL | re.is_match("abc"); | ^^^^^^^^^^^^^^^^^^ @@ -15,73 +15,73 @@ LL | re.is_match("abc"); = note: no matching allowed (from clippy.toml) error: use of a disallowed method `std::iter::Iterator::sum` - --> $DIR/conf_disallowed_methods.rs:37:5 + --> $DIR/conf_disallowed_methods.rs:39:5 | LL | a.iter().sum::(); | ^^^^^^^^^^^^^^^^^^^^^ error: use of a disallowed method `slice::sort_unstable` - --> $DIR/conf_disallowed_methods.rs:39:5 + --> $DIR/conf_disallowed_methods.rs:41:5 | LL | a.sort_unstable(); | ^^^^^^^^^^^^^^^^^ error: use of a disallowed method `f32::clamp` - --> $DIR/conf_disallowed_methods.rs:41:13 + --> $DIR/conf_disallowed_methods.rs:43:13 | LL | let _ = 2.0f32.clamp(3.0f32, 4.0f32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of a disallowed method `regex::Regex::new` - --> $DIR/conf_disallowed_methods.rs:44:61 + --> $DIR/conf_disallowed_methods.rs:46:61 | LL | let indirect: fn(&str) -> Result = Regex::new; | ^^^^^^^^^^ error: use of a disallowed method `f32::clamp` - --> $DIR/conf_disallowed_methods.rs:47:28 + --> $DIR/conf_disallowed_methods.rs:49:28 | LL | let in_call = Box::new(f32::clamp); | ^^^^^^^^^^ error: use of a disallowed method `regex::Regex::new` - --> $DIR/conf_disallowed_methods.rs:48:53 + --> $DIR/conf_disallowed_methods.rs:50:53 | LL | let in_method_call = ["^", "$"].into_iter().map(Regex::new); | ^^^^^^^^^^ error: use of a disallowed method `futures::stream::select_all` - --> $DIR/conf_disallowed_methods.rs:51:31 + --> $DIR/conf_disallowed_methods.rs:53:31 | LL | let same_name_as_module = select_all(vec![empty::<()>()]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of a disallowed method `conf_disallowed_methods::local_fn` - --> $DIR/conf_disallowed_methods.rs:53:5 + --> $DIR/conf_disallowed_methods.rs:55:5 | LL | local_fn(); | ^^^^^^^^^^ error: use of a disallowed method `conf_disallowed_methods::local_mod::f` - --> $DIR/conf_disallowed_methods.rs:54:5 + --> $DIR/conf_disallowed_methods.rs:56:5 | LL | local_mod::f(); | ^^^^^^^^^^^^^^ error: use of a disallowed method `conf_disallowed_methods::Struct::method` - --> $DIR/conf_disallowed_methods.rs:56:5 + --> $DIR/conf_disallowed_methods.rs:58:5 | LL | s.method(); | ^^^^^^^^^^ error: use of a disallowed method `conf_disallowed_methods::Trait::provided_method` - --> $DIR/conf_disallowed_methods.rs:57:5 + --> $DIR/conf_disallowed_methods.rs:59:5 | LL | s.provided_method(); | ^^^^^^^^^^^^^^^^^^^ error: use of a disallowed method `conf_disallowed_methods::Trait::implemented_method` - --> $DIR/conf_disallowed_methods.rs:58:5 + --> $DIR/conf_disallowed_methods.rs:60:5 | LL | s.implemented_method(); | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui-toml/toml_trivially_copy/test.rs b/tests/ui-toml/toml_trivially_copy/test.rs index 179b1266169e..f267a67f40ee 100644 --- a/tests/ui-toml/toml_trivially_copy/test.rs +++ b/tests/ui-toml/toml_trivially_copy/test.rs @@ -1,7 +1,7 @@ //@normalize-stderr-test: "\(\d+ byte\)" -> "(N byte)" //@normalize-stderr-test: "\(limit: \d+ byte\)" -> "(limit: N byte)" -#![deny(clippy::trivially_copy_pass_by_ref)] +#![warn(clippy::trivially_copy_pass_by_ref)] #[derive(Copy, Clone)] struct Foo(u8); diff --git a/tests/ui-toml/toml_trivially_copy/test.stderr b/tests/ui-toml/toml_trivially_copy/test.stderr index b3ef5928e8ea..d2b55eff16db 100644 --- a/tests/ui-toml/toml_trivially_copy/test.stderr +++ b/tests/ui-toml/toml_trivially_copy/test.stderr @@ -4,11 +4,7 @@ error: this argument (N byte) is passed by reference, but would be more efficien LL | fn bad(x: &u16, y: &Foo) {} | ^^^^ help: consider passing by value instead: `u16` | -note: the lint level is defined here - --> $DIR/test.rs:4:9 - | -LL | #![deny(clippy::trivially_copy_pass_by_ref)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `-D clippy::trivially-copy-pass-by-ref` implied by `-D warnings` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) --> $DIR/test.rs:14:20 diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.rs b/tests/ui-toml/toml_unknown_key/conf_unknown_key.rs index 569fd2c3553b..38009627757c 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.rs +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.rs @@ -1,3 +1,3 @@ -//@error-pattern: unknown field `foobar`, expected one of +//@error-in-other-file: unknown field `foobar`, expected one of fn main() {} diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index b6038f031f3c..6ba26e977302 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -1,9 +1,14 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expected one of + accept-comment-above-attributes + accept-comment-above-statement allow-dbg-in-tests allow-expect-in-tests allow-mixed-uninlined-format-args + allow-one-hash-in-raw-strings allow-print-in-tests + allow-private-module-inception allow-unwrap-in-tests + allowed-idents-below-min-chars allowed-scripts arithmetic-side-effects-allowed arithmetic-side-effects-allowed-binary @@ -24,6 +29,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect enforced-import-renames enum-variant-name-threshold enum-variant-size-threshold + excessive-nesting-threshold future-size-threshold ignore-interior-mutability large-error-threshold @@ -34,12 +40,14 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect max-struct-bools max-suggested-slice-pattern-length max-trait-bounds + min-ident-chars-threshold missing-docs-in-crate-items msrv pass-by-value-size-limit semicolon-inside-block-ignore-singleline semicolon-outside-block-ignore-multiline single-char-binding-names-threshold + stack-size-threshold standard-macro-braces suppress-restriction-lint-in-const third-party @@ -54,17 +62,22 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect vec-box-size-threshold verbose-bit-mask-threshold warn-on-all-wildcard-imports - --> $DIR/clippy.toml:2:1 + --> $DIR/$DIR/clippy.toml:2:1 | LL | foobar = 42 | ^^^^^^ error: error reading Clippy's configuration file: unknown field `barfoo`, expected one of + accept-comment-above-attributes + accept-comment-above-statement allow-dbg-in-tests allow-expect-in-tests allow-mixed-uninlined-format-args + allow-one-hash-in-raw-strings allow-print-in-tests + allow-private-module-inception allow-unwrap-in-tests + allowed-idents-below-min-chars allowed-scripts arithmetic-side-effects-allowed arithmetic-side-effects-allowed-binary @@ -85,6 +98,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect enforced-import-renames enum-variant-name-threshold enum-variant-size-threshold + excessive-nesting-threshold future-size-threshold ignore-interior-mutability large-error-threshold @@ -95,12 +109,14 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect max-struct-bools max-suggested-slice-pattern-length max-trait-bounds + min-ident-chars-threshold missing-docs-in-crate-items msrv pass-by-value-size-limit semicolon-inside-block-ignore-singleline semicolon-outside-block-ignore-multiline single-char-binding-names-threshold + stack-size-threshold standard-macro-braces suppress-restriction-lint-in-const third-party @@ -115,7 +131,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect vec-box-size-threshold verbose-bit-mask-threshold warn-on-all-wildcard-imports - --> $DIR/clippy.toml:4:1 + --> $DIR/$DIR/clippy.toml:4:1 | LL | barfoo = 53 | ^^^^^^ diff --git a/tests/ui-toml/undocumented_unsafe_blocks/auxiliary/proc_macro_unsafe.rs b/tests/ui-toml/undocumented_unsafe_blocks/auxiliary/proc_macro_unsafe.rs new file mode 100644 index 000000000000..1c591fc76f3e --- /dev/null +++ b/tests/ui-toml/undocumented_unsafe_blocks/auxiliary/proc_macro_unsafe.rs @@ -0,0 +1,13 @@ +extern crate proc_macro; + +use proc_macro::{Delimiter, Group, Ident, TokenStream, TokenTree}; + +#[proc_macro] +pub fn unsafe_block(input: TokenStream) -> TokenStream { + let span = input.into_iter().next().unwrap().span(); + TokenStream::from_iter([TokenTree::Ident(Ident::new("unsafe", span)), { + let mut group = Group::new(Delimiter::Brace, TokenStream::new()); + group.set_span(span); + TokenTree::Group(group) + }]) +} diff --git a/tests/ui-toml/undocumented_unsafe_blocks/clippy.toml b/tests/ui-toml/undocumented_unsafe_blocks/clippy.toml new file mode 100644 index 000000000000..e6dbb3d37841 --- /dev/null +++ b/tests/ui-toml/undocumented_unsafe_blocks/clippy.toml @@ -0,0 +1,2 @@ +accept-comment-above-statement = true +accept-comment-above-attributes = true diff --git a/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs b/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs new file mode 100644 index 000000000000..33d63670958d --- /dev/null +++ b/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs @@ -0,0 +1,567 @@ +//@aux-build:proc_macro_unsafe.rs:proc-macro + +#![warn(clippy::undocumented_unsafe_blocks, clippy::unnecessary_safety_comment)] +#![allow(deref_nullptr, clippy::let_unit_value, clippy::missing_safety_doc)] +#![feature(lint_reasons)] + +extern crate proc_macro_unsafe; + +// Valid comments + +fn nested_local() { + let _ = { + let _ = { + // SAFETY: + let _ = unsafe {}; + }; + }; +} + +fn deep_nest() { + let _ = { + let _ = { + // SAFETY: + let _ = unsafe {}; + + // Safety: + unsafe {}; + + let _ = { + let _ = { + let _ = { + let _ = { + let _ = { + // Safety: + let _ = unsafe {}; + + // SAFETY: + unsafe {}; + }; + }; + }; + + // Safety: + unsafe {}; + }; + }; + }; + + // Safety: + unsafe {}; + }; + + // SAFETY: + unsafe {}; +} + +fn local_tuple_expression() { + // Safety: + let _ = (42, unsafe {}); +} + +fn line_comment() { + // Safety: + unsafe {} +} + +fn line_comment_newlines() { + // SAFETY: + + unsafe {} +} + +fn line_comment_empty() { + // Safety: + // + // + // + unsafe {} +} + +fn line_comment_with_extras() { + // This is a description + // Safety: + unsafe {} +} + +fn block_comment() { + /* Safety: */ + unsafe {} +} + +fn block_comment_newlines() { + /* SAFETY: */ + + unsafe {} +} + +fn block_comment_with_extras() { + /* This is a description + * SAFETY: + */ + unsafe {} +} + +fn block_comment_terminator_same_line() { + /* This is a description + * Safety: */ + unsafe {} +} + +fn buried_safety() { + // Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor + // incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation + // ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in + // reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint + // occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est + // laborum. Safety: + // Tellus elementum sagittis vitae et leo duis ut diam quam. Sit amet nulla facilisi + // morbi tempus iaculis urna. Amet luctus venenatis lectus magna. At quis risus sed vulputate odio + // ut. Luctus venenatis lectus magna fringilla urna. Tortor id aliquet lectus proin nibh nisl + // condimentum id venenatis. Vulputate dignissim suspendisse in est ante in nibh mauris cursus. + unsafe {} +} + +fn safety_with_prepended_text() { + // This is a test. safety: + unsafe {} +} + +fn local_line_comment() { + // Safety: + let _ = unsafe {}; +} + +fn local_block_comment() { + /* SAFETY: */ + let _ = unsafe {}; +} + +fn comment_array() { + // Safety: + let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; +} + +fn comment_tuple() { + // sAFETY: + let _ = (42, unsafe {}, "test", unsafe {}); +} + +fn comment_unary() { + // SAFETY: + let _ = *unsafe { &42 }; +} + +#[allow(clippy::match_single_binding)] +fn comment_match() { + // SAFETY: + let _ = match unsafe {} { + _ => {}, + }; +} + +fn comment_addr_of() { + // Safety: + let _ = &unsafe {}; +} + +fn comment_repeat() { + // Safety: + let _ = [unsafe {}; 5]; +} + +fn comment_macro_call() { + macro_rules! t { + ($b:expr) => { + $b + }; + } + + t!( + // SAFETY: + unsafe {} + ); +} + +fn comment_macro_def() { + macro_rules! t { + () => { + // Safety: + unsafe {} + }; + } + + t!(); +} + +fn non_ascii_comment() { + // ॐ᧻໒ SaFeTy: ௵∰ + unsafe {}; +} + +fn local_commented_block() { + let _ = + // safety: + unsafe {}; +} + +fn local_nest() { + // safety: + let _ = [(42, unsafe {}, unsafe {}), (52, unsafe {}, unsafe {})]; +} + +fn in_fn_call(x: *const u32) { + fn f(x: u32) {} + + // Safety: reason + f(unsafe { *x }); +} + +fn multi_in_fn_call(x: *const u32) { + fn f(x: u32, y: u32) {} + + // Safety: reason + f(unsafe { *x }, unsafe { *x }); +} + +fn in_multiline_fn_call(x: *const u32) { + fn f(x: u32, y: u32) {} + + f( + // Safety: reason + unsafe { *x }, + 0, + ); +} + +fn in_macro_call(x: *const u32) { + // Safety: reason + println!("{}", unsafe { *x }); +} + +fn in_multiline_macro_call(x: *const u32) { + println!( + "{}", + // Safety: reason + unsafe { *x }, + ); +} + +fn from_proc_macro() { + proc_macro_unsafe::unsafe_block!(token); +} + +fn in_closure(x: *const u32) { + // Safety: reason + let _ = || unsafe { *x }; +} + +// Invalid comments + +#[rustfmt::skip] +fn inline_block_comment() { + /* Safety: */ unsafe {} +} + +fn no_comment() { + unsafe {} +} + +fn no_comment_array() { + let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; +} + +fn no_comment_tuple() { + let _ = (42, unsafe {}, "test", unsafe {}); +} + +fn no_comment_unary() { + let _ = *unsafe { &42 }; +} + +#[allow(clippy::match_single_binding)] +fn no_comment_match() { + let _ = match unsafe {} { + _ => {}, + }; +} + +fn no_comment_addr_of() { + let _ = &unsafe {}; +} + +fn no_comment_repeat() { + let _ = [unsafe {}; 5]; +} + +fn local_no_comment() { + let _ = unsafe {}; +} + +fn no_comment_macro_call() { + macro_rules! t { + ($b:expr) => { + $b + }; + } + + t!(unsafe {}); +} + +fn no_comment_macro_def() { + macro_rules! t { + () => { + unsafe {} + }; + } + + t!(); +} + +fn trailing_comment() { + unsafe {} // SAFETY: +} + +fn internal_comment() { + unsafe { + // SAFETY: + } +} + +fn interference() { + // SAFETY + + let _ = 42; + + unsafe {}; +} + +pub fn print_binary_tree() { + println!("{}", unsafe { String::from_utf8_unchecked(vec![]) }); +} + +mod unsafe_impl_smoke_test { + unsafe trait A {} + + // error: no safety comment + unsafe impl A for () {} + + // Safety: ok + unsafe impl A for (i32) {} + + mod sub_mod { + // error: + unsafe impl B for (u32) {} + unsafe trait B {} + } + + #[rustfmt::skip] + mod sub_mod2 { + // + // SAFETY: ok + // + + unsafe impl B for (u32) {} + unsafe trait B {} + } +} + +mod unsafe_impl_from_macro { + unsafe trait T {} + + // error + macro_rules! no_safety_comment { + ($t:ty) => { + unsafe impl T for $t {} + }; + } + + // ok + no_safety_comment!(()); + + // ok + macro_rules! with_safety_comment { + ($t:ty) => { + // SAFETY: + unsafe impl T for $t {} + }; + } + + // ok + with_safety_comment!((i32)); +} + +mod unsafe_impl_macro_and_not_macro { + unsafe trait T {} + + // error + macro_rules! no_safety_comment { + ($t:ty) => { + unsafe impl T for $t {} + }; + } + + // ok + no_safety_comment!(()); + + // error + unsafe impl T for (i32) {} + + // ok + no_safety_comment!(u32); + + // error + unsafe impl T for (bool) {} +} + +#[rustfmt::skip] +mod unsafe_impl_valid_comment { + unsafe trait SaFety {} + // SaFety: + unsafe impl SaFety for () {} + + unsafe trait MultiLineComment {} + // The following impl is safe + // ... + // Safety: reason + unsafe impl MultiLineComment for () {} + + unsafe trait NoAscii {} + // 安全 SAFETY: 以下のコードは安全です + unsafe impl NoAscii for () {} + + unsafe trait InlineAndPrecedingComment {} + // SAFETY: + /* comment */ unsafe impl InlineAndPrecedingComment for () {} + + unsafe trait BuriedSafety {} + // Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor + // incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation + // ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in + // reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint + // occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est + // laborum. Safety: + // Tellus elementum sagittis vitae et leo duis ut diam quam. Sit amet nulla facilisi + // morbi tempus iaculis urna. Amet luctus venenatis lectus magna. At quis risus sed vulputate odio + // ut. Luctus venenatis lectus magna fringilla urna. Tortor id aliquet lectus proin nibh nisl + // condimentum id venenatis. Vulputate dignissim suspendisse in est ante in nibh mauris cursus. + unsafe impl BuriedSafety for () {} + + unsafe trait MultiLineBlockComment {} + /* This is a description + * Safety: */ + unsafe impl MultiLineBlockComment for () {} +} + +#[rustfmt::skip] +mod unsafe_impl_invalid_comment { + unsafe trait NoComment {} + + unsafe impl NoComment for () {} + + unsafe trait InlineComment {} + + /* SAFETY: */ unsafe impl InlineComment for () {} + + unsafe trait TrailingComment {} + + unsafe impl TrailingComment for () {} // SAFETY: + + unsafe trait Interference {} + // SAFETY: + const BIG_NUMBER: i32 = 1000000; + unsafe impl Interference for () {} +} + +unsafe trait ImplInFn {} + +fn impl_in_fn() { + // error + unsafe impl ImplInFn for () {} + + // SAFETY: ok + unsafe impl ImplInFn for (i32) {} +} + +unsafe trait CrateRoot {} + +// error +unsafe impl CrateRoot for () {} + +// SAFETY: ok +unsafe impl CrateRoot for (i32) {} + +fn issue_9142() { + // SAFETY: ok + let _ = + // we need this comment to avoid rustfmt putting + // it all on one line + unsafe {}; + + // SAFETY: this is more than one level away, so it should warn + let _ = { + if unsafe { true } { + todo!(); + } else { + let bar = unsafe {}; + todo!(); + bar + } + }; +} + +pub unsafe fn a_function_with_a_very_long_name_to_break_the_line() -> u32 { + 1 +} + +pub const unsafe fn a_const_function_with_a_very_long_name_to_break_the_line() -> u32 { + 2 +} + +fn issue_10832() { + // Safety: A safety comment + let _some_variable_with_a_very_long_name_to_break_the_line = + unsafe { a_function_with_a_very_long_name_to_break_the_line() }; + + // Safety: Another safety comment + const _SOME_CONST_WITH_A_VERY_LONG_NAME_TO_BREAK_THE_LINE: u32 = + unsafe { a_const_function_with_a_very_long_name_to_break_the_line() }; + + // Safety: Yet another safety comment + static _SOME_STATIC_WITH_A_VERY_LONG_NAME_TO_BREAK_THE_LINE: u32 = + unsafe { a_const_function_with_a_very_long_name_to_break_the_line() }; +} + +fn issue_8679() { + // SAFETY: + #[allow(unsafe_code)] + unsafe {} + + // SAFETY: + #[expect(unsafe_code, reason = "totally safe")] + unsafe { + *std::ptr::null::() + }; + + // Safety: A safety comment + #[allow(unsafe_code)] + let _some_variable_with_a_very_long_name_to_break_the_line = + unsafe { a_function_with_a_very_long_name_to_break_the_line() }; + + // Safety: Another safety comment + #[allow(unsafe_code)] + const _SOME_CONST_WITH_A_VERY_LONG_NAME_TO_BREAK_THE_LINE: u32 = + unsafe { a_const_function_with_a_very_long_name_to_break_the_line() }; + + // Safety: Yet another safety comment + #[allow(unsafe_code)] + static _SOME_STATIC_WITH_A_VERY_LONG_NAME_TO_BREAK_THE_LINE: u32 = + unsafe { a_const_function_with_a_very_long_name_to_break_the_line() }; + + // SAFETY: + #[allow(unsafe_code)] + // This also works I guess + unsafe {} +} + +fn main() {} diff --git a/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.stderr b/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.stderr new file mode 100644 index 000000000000..9a0fd0593896 --- /dev/null +++ b/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.stderr @@ -0,0 +1,314 @@ +error: unsafe block missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:263:19 + | +LL | /* Safety: */ unsafe {} + | ^^^^^^^^^ + | + = help: consider adding a safety comment on the preceding line + = note: `-D clippy::undocumented-unsafe-blocks` implied by `-D warnings` + +error: unsafe block missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:267:5 + | +LL | unsafe {} + | ^^^^^^^^^ + | + = help: consider adding a safety comment on the preceding line + +error: unsafe block missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:271:14 + | +LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; + | ^^^^^^^^^^^^^ + | + = help: consider adding a safety comment on the preceding line + +error: unsafe block missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:271:29 + | +LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; + | ^^^^^^^^^^^^^ + | + = help: consider adding a safety comment on the preceding line + +error: unsafe block missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:271:48 + | +LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; + | ^^^^^^^^^^^^^ + | + = help: consider adding a safety comment on the preceding line + +error: unsafe block missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:275:18 + | +LL | let _ = (42, unsafe {}, "test", unsafe {}); + | ^^^^^^^^^ + | + = help: consider adding a safety comment on the preceding line + +error: unsafe block missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:275:37 + | +LL | let _ = (42, unsafe {}, "test", unsafe {}); + | ^^^^^^^^^ + | + = help: consider adding a safety comment on the preceding line + +error: unsafe block missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:279:14 + | +LL | let _ = *unsafe { &42 }; + | ^^^^^^^^^^^^^^ + | + = help: consider adding a safety comment on the preceding line + +error: unsafe block missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:284:19 + | +LL | let _ = match unsafe {} { + | ^^^^^^^^^ + | + = help: consider adding a safety comment on the preceding line + +error: unsafe block missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:290:14 + | +LL | let _ = &unsafe {}; + | ^^^^^^^^^ + | + = help: consider adding a safety comment on the preceding line + +error: unsafe block missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:294:14 + | +LL | let _ = [unsafe {}; 5]; + | ^^^^^^^^^ + | + = help: consider adding a safety comment on the preceding line + +error: unsafe block missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:298:13 + | +LL | let _ = unsafe {}; + | ^^^^^^^^^ + | + = help: consider adding a safety comment on the preceding line + +error: unsafe block missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:308:8 + | +LL | t!(unsafe {}); + | ^^^^^^^^^ + | + = help: consider adding a safety comment on the preceding line + +error: unsafe block missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:314:13 + | +LL | unsafe {} + | ^^^^^^^^^ +... +LL | t!(); + | ---- in this macro invocation + | + = help: consider adding a safety comment on the preceding line + = note: this error originates in the macro `t` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: unsafe block missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:322:5 + | +LL | unsafe {} // SAFETY: + | ^^^^^^^^^ + | + = help: consider adding a safety comment on the preceding line + +error: unsafe block missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:326:5 + | +LL | unsafe { + | ^^^^^^^^ + | + = help: consider adding a safety comment on the preceding line + +error: unsafe block missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:336:5 + | +LL | unsafe {}; + | ^^^^^^^^^ + | + = help: consider adding a safety comment on the preceding line + +error: unsafe block missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:340:20 + | +LL | println!("{}", unsafe { String::from_utf8_unchecked(vec![]) }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider adding a safety comment on the preceding line + +error: unsafe impl missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:347:5 + | +LL | unsafe impl A for () {} + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider adding a safety comment on the preceding line + +error: unsafe impl missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:354:9 + | +LL | unsafe impl B for (u32) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider adding a safety comment on the preceding line + +error: unsafe impl missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:375:13 + | +LL | unsafe impl T for $t {} + | ^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | no_safety_comment!(()); + | ---------------------- in this macro invocation + | + = help: consider adding a safety comment on the preceding line + = note: this error originates in the macro `no_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: unsafe impl missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:400:13 + | +LL | unsafe impl T for $t {} + | ^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | no_safety_comment!(()); + | ---------------------- in this macro invocation + | + = help: consider adding a safety comment on the preceding line + = note: this error originates in the macro `no_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: unsafe impl missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:408:5 + | +LL | unsafe impl T for (i32) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider adding a safety comment on the preceding line + +error: unsafe impl missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:400:13 + | +LL | unsafe impl T for $t {} + | ^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | no_safety_comment!(u32); + | ----------------------- in this macro invocation + | + = help: consider adding a safety comment on the preceding line + = note: this error originates in the macro `no_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: unsafe impl missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:414:5 + | +LL | unsafe impl T for (bool) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider adding a safety comment on the preceding line + +error: unsafe impl missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:460:5 + | +LL | unsafe impl NoComment for () {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider adding a safety comment on the preceding line + +error: unsafe impl missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:464:19 + | +LL | /* SAFETY: */ unsafe impl InlineComment for () {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider adding a safety comment on the preceding line + +error: unsafe impl missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:468:5 + | +LL | unsafe impl TrailingComment for () {} // SAFETY: + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider adding a safety comment on the preceding line + +error: constant item has unnecessary safety comment + --> $DIR/undocumented_unsafe_blocks.rs:472:5 + | +LL | const BIG_NUMBER: i32 = 1000000; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider removing the safety comment + --> $DIR/undocumented_unsafe_blocks.rs:471:5 + | +LL | // SAFETY: + | ^^^^^^^^^^ + = note: `-D clippy::unnecessary-safety-comment` implied by `-D warnings` + +error: unsafe impl missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:473:5 + | +LL | unsafe impl Interference for () {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider adding a safety comment on the preceding line + +error: unsafe impl missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:480:5 + | +LL | unsafe impl ImplInFn for () {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider adding a safety comment on the preceding line + +error: unsafe impl missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:489:1 + | +LL | unsafe impl CrateRoot for () {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider adding a safety comment on the preceding line + +error: statement has unnecessary safety comment + --> $DIR/undocumented_unsafe_blocks.rs:502:5 + | +LL | / let _ = { +LL | | if unsafe { true } { +LL | | todo!(); +LL | | } else { +... | +LL | | } +LL | | }; + | |______^ + | +help: consider removing the safety comment + --> $DIR/undocumented_unsafe_blocks.rs:501:5 + | +LL | // SAFETY: this is more than one level away, so it should warn + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unsafe block missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:503:12 + | +LL | if unsafe { true } { + | ^^^^^^^^^^^^^^^ + | + = help: consider adding a safety comment on the preceding line + +error: unsafe block missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:506:23 + | +LL | let bar = unsafe {}; + | ^^^^^^^^^ + | + = help: consider adding a safety comment on the preceding line + +error: aborting due to 35 previous errors + diff --git a/tests/ui-toml/unwrap_used/unwrap_used.rs b/tests/ui-toml/unwrap_used/unwrap_used.rs index 5d3e800caddf..dde1c6d7c37d 100644 --- a/tests/ui-toml/unwrap_used/unwrap_used.rs +++ b/tests/ui-toml/unwrap_used/unwrap_used.rs @@ -1,8 +1,13 @@ //@compile-flags: --test -#![allow(unused_mut, clippy::get_first, clippy::from_iter_instead_of_collect)] +#![allow( + unused_mut, + clippy::get_first, + clippy::from_iter_instead_of_collect, + clippy::useless_vec +)] #![warn(clippy::unwrap_used)] -#![deny(clippy::get_unwrap)] +#![warn(clippy::get_unwrap)] use std::collections::BTreeMap; use std::collections::HashMap; diff --git a/tests/ui-toml/unwrap_used/unwrap_used.stderr b/tests/ui-toml/unwrap_used/unwrap_used.stderr index 8a32750e3c92..eb66a5cf50ba 100644 --- a/tests/ui-toml/unwrap_used/unwrap_used.stderr +++ b/tests/ui-toml/unwrap_used/unwrap_used.stderr @@ -1,17 +1,13 @@ error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:35:17 + --> $DIR/unwrap_used.rs:40:17 | LL | let _ = boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&boxed_slice[1]` | -note: the lint level is defined here - --> $DIR/unwrap_used.rs:5:9 - | -LL | #![deny(clippy::get_unwrap)] - | ^^^^^^^^^^^^^^^^^^ + = note: `-D clippy::get-unwrap` implied by `-D warnings` error: used `unwrap()` on an `Option` value - --> $DIR/unwrap_used.rs:35:17 + --> $DIR/unwrap_used.rs:40:17 | LL | let _ = boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -20,13 +16,13 @@ LL | let _ = boxed_slice.get(1).unwrap(); = note: `-D clippy::unwrap-used` implied by `-D warnings` error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:36:17 + --> $DIR/unwrap_used.rs:41:17 | LL | let _ = some_slice.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_slice[0]` error: used `unwrap()` on an `Option` value - --> $DIR/unwrap_used.rs:36:17 + --> $DIR/unwrap_used.rs:41:17 | LL | let _ = some_slice.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -34,13 +30,13 @@ LL | let _ = some_slice.get(0).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:37:17 + --> $DIR/unwrap_used.rs:42:17 | LL | let _ = some_vec.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vec[0]` error: used `unwrap()` on an `Option` value - --> $DIR/unwrap_used.rs:37:17 + --> $DIR/unwrap_used.rs:42:17 | LL | let _ = some_vec.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -48,13 +44,13 @@ LL | let _ = some_vec.get(0).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a VecDeque. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:38:17 + --> $DIR/unwrap_used.rs:43:17 | LL | let _ = some_vecdeque.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vecdeque[0]` error: used `unwrap()` on an `Option` value - --> $DIR/unwrap_used.rs:38:17 + --> $DIR/unwrap_used.rs:43:17 | LL | let _ = some_vecdeque.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -62,13 +58,13 @@ LL | let _ = some_vecdeque.get(0).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a HashMap. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:39:17 + --> $DIR/unwrap_used.rs:44:17 | LL | let _ = some_hashmap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_hashmap[&1]` error: used `unwrap()` on an `Option` value - --> $DIR/unwrap_used.rs:39:17 + --> $DIR/unwrap_used.rs:44:17 | LL | let _ = some_hashmap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -76,13 +72,13 @@ LL | let _ = some_hashmap.get(&1).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a BTreeMap. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:40:17 + --> $DIR/unwrap_used.rs:45:17 | LL | let _ = some_btreemap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_btreemap[&1]` error: used `unwrap()` on an `Option` value - --> $DIR/unwrap_used.rs:40:17 + --> $DIR/unwrap_used.rs:45:17 | LL | let _ = some_btreemap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -90,13 +86,13 @@ LL | let _ = some_btreemap.get(&1).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:44:21 + --> $DIR/unwrap_used.rs:49:21 | LL | let _: u8 = *boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `boxed_slice[1]` error: used `unwrap()` on an `Option` value - --> $DIR/unwrap_used.rs:44:22 + --> $DIR/unwrap_used.rs:49:22 | LL | let _: u8 = *boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -104,13 +100,13 @@ LL | let _: u8 = *boxed_slice.get(1).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:49:9 + --> $DIR/unwrap_used.rs:54:9 | LL | *boxed_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `boxed_slice[0]` error: used `unwrap()` on an `Option` value - --> $DIR/unwrap_used.rs:49:10 + --> $DIR/unwrap_used.rs:54:10 | LL | *boxed_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -118,13 +114,13 @@ LL | *boxed_slice.get_mut(0).unwrap() = 1; = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:50:9 + --> $DIR/unwrap_used.rs:55:9 | LL | *some_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_slice[0]` error: used `unwrap()` on an `Option` value - --> $DIR/unwrap_used.rs:50:10 + --> $DIR/unwrap_used.rs:55:10 | LL | *some_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -132,13 +128,13 @@ LL | *some_slice.get_mut(0).unwrap() = 1; = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:51:9 + --> $DIR/unwrap_used.rs:56:9 | LL | *some_vec.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0]` error: used `unwrap()` on an `Option` value - --> $DIR/unwrap_used.rs:51:10 + --> $DIR/unwrap_used.rs:56:10 | LL | *some_vec.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -146,13 +142,13 @@ LL | *some_vec.get_mut(0).unwrap() = 1; = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:52:9 + --> $DIR/unwrap_used.rs:57:9 | LL | *some_vecdeque.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vecdeque[0]` error: used `unwrap()` on an `Option` value - --> $DIR/unwrap_used.rs:52:10 + --> $DIR/unwrap_used.rs:57:10 | LL | *some_vecdeque.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -160,13 +156,13 @@ LL | *some_vecdeque.get_mut(0).unwrap() = 1; = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:64:17 + --> $DIR/unwrap_used.rs:69:17 | LL | let _ = some_vec.get(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]` error: used `unwrap()` on an `Option` value - --> $DIR/unwrap_used.rs:64:17 + --> $DIR/unwrap_used.rs:69:17 | LL | let _ = some_vec.get(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -174,13 +170,13 @@ LL | let _ = some_vec.get(0..1).unwrap().to_vec(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:65:17 + --> $DIR/unwrap_used.rs:70:17 | LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]` error: used `unwrap()` on an `Option` value - --> $DIR/unwrap_used.rs:65:17 + --> $DIR/unwrap_used.rs:70:17 | LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -188,13 +184,13 @@ LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:72:13 + --> $DIR/unwrap_used.rs:77:13 | LL | let _ = boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&boxed_slice[1]` error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/unwrap_used.rs:90:17 + --> $DIR/unwrap_used.rs:95:17 | LL | let _ = Box::new([0]).get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&Box::new([0])[1]` diff --git a/tests/ui-toml/update-all-references.sh b/tests/ui-toml/update-all-references.sh index 4391499a1e1f..d42043070261 100755 --- a/tests/ui-toml/update-all-references.sh +++ b/tests/ui-toml/update-all-references.sh @@ -1,3 +1,3 @@ #!/bin/bash -echo "Please use 'cargo dev bless' instead." +echo "Please use 'cargo bless' instead." diff --git a/tests/ui/allow_attributes.fixed b/tests/ui/allow_attributes.fixed index f0936b2608e9..cc95a06817d6 100644 --- a/tests/ui/allow_attributes.fixed +++ b/tests/ui/allow_attributes.fixed @@ -1,9 +1,12 @@ //@run-rustfix +//@aux-build:proc_macros.rs:proc-macro #![allow(unused)] #![warn(clippy::allow_attributes)] #![feature(lint_reasons)] +#![no_main] -fn main() {} +extern crate proc_macros; +use proc_macros::{external, with_span}; // Using clippy::needless_borrow just as a placeholder, it isn't relevant. @@ -20,6 +23,21 @@ struct T4; #[cfg_attr(panic = "unwind", expect(dead_code))] struct CfgT; +fn ignore_external() { + external! { + #[allow(clippy::needless_borrow)] // Should not lint + fn a() {} + } +} + +fn ignore_proc_macro() { + with_span! { + span + #[allow(clippy::needless_borrow)] // Should not lint + fn a() {} + } +} + fn ignore_inner_attr() { #![allow(unused)] // Should not lint } diff --git a/tests/ui/allow_attributes.rs b/tests/ui/allow_attributes.rs index 2fb9e86126e5..2eb6ad304ea4 100644 --- a/tests/ui/allow_attributes.rs +++ b/tests/ui/allow_attributes.rs @@ -1,9 +1,12 @@ //@run-rustfix +//@aux-build:proc_macros.rs:proc-macro #![allow(unused)] #![warn(clippy::allow_attributes)] #![feature(lint_reasons)] +#![no_main] -fn main() {} +extern crate proc_macros; +use proc_macros::{external, with_span}; // Using clippy::needless_borrow just as a placeholder, it isn't relevant. @@ -20,6 +23,21 @@ struct T4; #[cfg_attr(panic = "unwind", allow(dead_code))] struct CfgT; +fn ignore_external() { + external! { + #[allow(clippy::needless_borrow)] // Should not lint + fn a() {} + } +} + +fn ignore_proc_macro() { + with_span! { + span + #[allow(clippy::needless_borrow)] // Should not lint + fn a() {} + } +} + fn ignore_inner_attr() { #![allow(unused)] // Should not lint } diff --git a/tests/ui/allow_attributes.stderr b/tests/ui/allow_attributes.stderr index 681837e9ed77..d17fd86cb866 100644 --- a/tests/ui/allow_attributes.stderr +++ b/tests/ui/allow_attributes.stderr @@ -1,5 +1,5 @@ error: #[allow] attribute found - --> $DIR/allow_attributes.rs:11:3 + --> $DIR/allow_attributes.rs:14:3 | LL | #[allow(dead_code)] | ^^^^^ help: replace it with: `expect` @@ -7,7 +7,7 @@ LL | #[allow(dead_code)] = note: `-D clippy::allow-attributes` implied by `-D warnings` error: #[allow] attribute found - --> $DIR/allow_attributes.rs:20:30 + --> $DIR/allow_attributes.rs:23:30 | LL | #[cfg_attr(panic = "unwind", allow(dead_code))] | ^^^^^ help: replace it with: `expect` diff --git a/tests/ui/allow_attributes_false_positive.rs b/tests/ui/allow_attributes_false_positive.rs deleted file mode 100644 index 5c3407628be2..000000000000 --- a/tests/ui/allow_attributes_false_positive.rs +++ /dev/null @@ -1,5 +0,0 @@ -#![warn(clippy::allow_attributes)] -#![feature(lint_reasons)] -#![crate_type = "proc-macro"] - -fn main() {} diff --git a/tests/ui/allow_attributes_without_reason.rs b/tests/ui/allow_attributes_without_reason.rs index 1a0d4e886576..d223d5642217 100644 --- a/tests/ui/allow_attributes_without_reason.rs +++ b/tests/ui/allow_attributes_without_reason.rs @@ -1,9 +1,15 @@ +//@aux-build:proc_macros.rs:proc-macro #![feature(lint_reasons)] #![deny(clippy::allow_attributes_without_reason)] +#![allow(unfulfilled_lint_expectations)] + +extern crate proc_macros; +use proc_macros::{external, with_span}; // These should trigger the lint #[allow(dead_code)] #[allow(dead_code, deprecated)] +#[expect(dead_code)] // These should be fine #[allow(dead_code, reason = "This should be allowed")] #[warn(dyn_drop, reason = "Warnings can also have reasons")] @@ -11,4 +17,28 @@ #[deny(deref_nullptr)] #[forbid(deref_nullptr)] -fn main() {} +fn main() { + external! { + #[allow(dead_code)] + fn a() {} + } + with_span! { + span + #[allow(dead_code)] + fn b() {} + } +} + +// Make sure this is not triggered on `?` desugaring + +pub fn trigger_fp_option() -> Option<()> { + Some(())?; + None?; + Some(()) +} + +pub fn trigger_fp_result() -> Result<(), &'static str> { + Ok(())?; + Err("asdf")?; + Ok(()) +} diff --git a/tests/ui/allow_attributes_without_reason.stderr b/tests/ui/allow_attributes_without_reason.stderr index 23f17e9a7afb..96f747d0026d 100644 --- a/tests/ui/allow_attributes_without_reason.stderr +++ b/tests/ui/allow_attributes_without_reason.stderr @@ -1,23 +1,39 @@ error: `allow` attribute without specifying a reason - --> $DIR/allow_attributes_without_reason.rs:5:1 + --> $DIR/allow_attributes_without_reason.rs:4:1 | -LL | #[allow(dead_code)] - | ^^^^^^^^^^^^^^^^^^^ +LL | #![allow(unfulfilled_lint_expectations)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: try adding a reason at the end with `, reason = ".."` note: the lint level is defined here - --> $DIR/allow_attributes_without_reason.rs:2:9 + --> $DIR/allow_attributes_without_reason.rs:3:9 | LL | #![deny(clippy::allow_attributes_without_reason)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `allow` attribute without specifying a reason - --> $DIR/allow_attributes_without_reason.rs:6:1 + --> $DIR/allow_attributes_without_reason.rs:10:1 + | +LL | #[allow(dead_code)] + | ^^^^^^^^^^^^^^^^^^^ + | + = help: try adding a reason at the end with `, reason = ".."` + +error: `allow` attribute without specifying a reason + --> $DIR/allow_attributes_without_reason.rs:11:1 | LL | #[allow(dead_code, deprecated)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: try adding a reason at the end with `, reason = ".."` -error: aborting due to 2 previous errors +error: `expect` attribute without specifying a reason + --> $DIR/allow_attributes_without_reason.rs:12:1 + | +LL | #[expect(dead_code)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: try adding a reason at the end with `, reason = ".."` + +error: aborting due to 4 previous errors diff --git a/tests/ui/almost_complete_range.fixed b/tests/ui/almost_complete_range.fixed index 5cd0dcce6f76..50a13f16b445 100644 --- a/tests/ui/almost_complete_range.fixed +++ b/tests/ui/almost_complete_range.fixed @@ -1,6 +1,6 @@ //@run-rustfix //@edition:2018 -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![feature(exclusive_range_pattern)] #![feature(stmt_expr_attributes)] diff --git a/tests/ui/almost_complete_range.rs b/tests/ui/almost_complete_range.rs index db0bfc8afc39..fd8223a2309c 100644 --- a/tests/ui/almost_complete_range.rs +++ b/tests/ui/almost_complete_range.rs @@ -1,6 +1,6 @@ //@run-rustfix //@edition:2018 -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![feature(exclusive_range_pattern)] #![feature(stmt_expr_attributes)] diff --git a/tests/ui/arc_with_non_send_sync.rs b/tests/ui/arc_with_non_send_sync.rs new file mode 100644 index 000000000000..ac786f68c123 --- /dev/null +++ b/tests/ui/arc_with_non_send_sync.rs @@ -0,0 +1,17 @@ +#![warn(clippy::arc_with_non_send_sync)] +#![allow(unused_variables)] +use std::cell::RefCell; +use std::sync::{Arc, Mutex}; + +fn foo(x: T) { + // Should not lint - purposefully ignoring generic args. + let a = Arc::new(x); +} + +fn main() { + // This is safe, as `i32` implements `Send` and `Sync`. + let a = Arc::new(42); + + // This is not safe, as `RefCell` does not implement `Sync`. + let b = Arc::new(RefCell::new(42)); +} diff --git a/tests/ui/arc_with_non_send_sync.stderr b/tests/ui/arc_with_non_send_sync.stderr new file mode 100644 index 000000000000..fc2fc5f93b13 --- /dev/null +++ b/tests/ui/arc_with_non_send_sync.stderr @@ -0,0 +1,11 @@ +error: usage of `Arc` where `T` is not `Send` or `Sync` + --> $DIR/arc_with_non_send_sync.rs:16:13 + | +LL | let b = Arc::new(RefCell::new(42)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using `Rc` instead or wrapping `T` in a std::sync type like `Mutex` + = note: `-D clippy::arc-with-non-send-sync` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/tests/ui/arithmetic_side_effects.rs b/tests/ui/arithmetic_side_effects.rs index f95af1017bcb..4f38e50c81d5 100644 --- a/tests/ui/arithmetic_side_effects.rs +++ b/tests/ui/arithmetic_side_effects.rs @@ -1,4 +1,4 @@ -//@aux-build:proc_macro_derive.rs +//@aux-build:proc_macro_derive.rs:proc-macro #![allow( clippy::assign_op_pattern, @@ -466,4 +466,19 @@ pub fn issue_10767() { &3.5_f32 + &1.3_f32; } +pub fn issue_10792() { + struct One { + a: u32, + } + struct Two { + b: u32, + c: u64, + } + const ONE: One = One { a: 1 }; + const TWO: Two = Two { b: 2, c: 3 }; + let _ = 10 / ONE.a; + let _ = 10 / TWO.b; + let _ = 10 / TWO.c; +} + fn main() {} diff --git a/tests/ui/as_conversions.rs b/tests/ui/as_conversions.rs index 890bf0b0a7eb..427842a51d9b 100644 --- a/tests/ui/as_conversions.rs +++ b/tests/ui/as_conversions.rs @@ -1,10 +1,11 @@ -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![warn(clippy::as_conversions)] -#![allow(clippy::borrow_as_ptr)] +#![allow(clippy::borrow_as_ptr, unused)] extern crate proc_macros; use proc_macros::external; +use proc_macros::with_span; fn main() { let i = 0u32 as u64; @@ -13,3 +14,11 @@ fn main() { external!(0u32 as u64); } + +with_span!( + span + + fn coverting() { + let x = 0u32 as u64; + } +); diff --git a/tests/ui/as_conversions.stderr b/tests/ui/as_conversions.stderr index 54037a649978..ca41d1378aa0 100644 --- a/tests/ui/as_conversions.stderr +++ b/tests/ui/as_conversions.stderr @@ -1,5 +1,5 @@ error: using a potentially dangerous silent `as` conversion - --> $DIR/as_conversions.rs:10:13 + --> $DIR/as_conversions.rs:11:13 | LL | let i = 0u32 as u64; | ^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | let i = 0u32 as u64; = note: `-D clippy::as-conversions` implied by `-D warnings` error: using a potentially dangerous silent `as` conversion - --> $DIR/as_conversions.rs:12:13 + --> $DIR/as_conversions.rs:13:13 | LL | let j = &i as *const u64 as *mut u64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | let j = &i as *const u64 as *mut u64; = help: consider using a safe wrapper for this conversion error: using a potentially dangerous silent `as` conversion - --> $DIR/as_conversions.rs:12:13 + --> $DIR/as_conversions.rs:13:13 | LL | let j = &i as *const u64 as *mut u64; | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/as_ptr_cast_mut.rs b/tests/ui/as_ptr_cast_mut.rs index 0d1d9258433b..7d71947e4281 100644 --- a/tests/ui/as_ptr_cast_mut.rs +++ b/tests/ui/as_ptr_cast_mut.rs @@ -1,6 +1,6 @@ #![allow(unused)] #![warn(clippy::as_ptr_cast_mut)] -#![allow(clippy::wrong_self_convention)] +#![allow(clippy::wrong_self_convention, clippy::unnecessary_cast)] struct MutPtrWrapper(Vec); impl MutPtrWrapper { diff --git a/tests/ui/asm_syntax.rs b/tests/ui/asm_syntax.rs index c93995f939ac..af02e202b17b 100644 --- a/tests/ui/asm_syntax.rs +++ b/tests/ui/asm_syntax.rs @@ -1,5 +1,5 @@ -//@only-x86_64 -//@ignore-aarch64 +//@only-target-x86_64 +//@ignore-target-aarch64 #[warn(clippy::inline_asm_x86_intel_syntax)] mod warn_intel { diff --git a/tests/ui/assertions_on_result_states.fixed b/tests/ui/assertions_on_result_states.fixed index ea8b895664c4..3152bd3cae1a 100644 --- a/tests/ui/assertions_on_result_states.fixed +++ b/tests/ui/assertions_on_result_states.fixed @@ -1,5 +1,6 @@ //@run-rustfix #![warn(clippy::assertions_on_result_states)] +#![allow(clippy::unnecessary_literal_unwrap)] use std::result::Result; diff --git a/tests/ui/assertions_on_result_states.rs b/tests/ui/assertions_on_result_states.rs index 6fc20f859887..42755e935aa4 100644 --- a/tests/ui/assertions_on_result_states.rs +++ b/tests/ui/assertions_on_result_states.rs @@ -1,5 +1,6 @@ //@run-rustfix #![warn(clippy::assertions_on_result_states)] +#![allow(clippy::unnecessary_literal_unwrap)] use std::result::Result; diff --git a/tests/ui/assertions_on_result_states.stderr b/tests/ui/assertions_on_result_states.stderr index 298d63c9c34f..be581030cb67 100644 --- a/tests/ui/assertions_on_result_states.stderr +++ b/tests/ui/assertions_on_result_states.stderr @@ -1,5 +1,5 @@ error: called `assert!` with `Result::is_ok` - --> $DIR/assertions_on_result_states.rs:24:5 + --> $DIR/assertions_on_result_states.rs:25:5 | LL | assert!(r.is_ok()); | ^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap()` @@ -7,37 +7,37 @@ LL | assert!(r.is_ok()); = note: `-D clippy::assertions-on-result-states` implied by `-D warnings` error: called `assert!` with `Result::is_ok` - --> $DIR/assertions_on_result_states.rs:42:5 + --> $DIR/assertions_on_result_states.rs:43:5 | LL | assert!(get_ok().is_ok()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `get_ok().unwrap()` error: called `assert!` with `Result::is_ok` - --> $DIR/assertions_on_result_states.rs:45:5 + --> $DIR/assertions_on_result_states.rs:46:5 | LL | assert!(get_ok_macro!().is_ok()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `get_ok_macro!().unwrap()` error: called `assert!` with `Result::is_ok` - --> $DIR/assertions_on_result_states.rs:58:5 + --> $DIR/assertions_on_result_states.rs:59:5 | LL | assert!(r.is_ok()); | ^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap()` error: called `assert!` with `Result::is_ok` - --> $DIR/assertions_on_result_states.rs:64:9 + --> $DIR/assertions_on_result_states.rs:65:9 | LL | assert!(r.is_ok()); | ^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap()` error: called `assert!` with `Result::is_err` - --> $DIR/assertions_on_result_states.rs:72:5 + --> $DIR/assertions_on_result_states.rs:73:5 | LL | assert!(r.is_err()); | ^^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap_err()` error: called `assert!` with `Result::is_err` - --> $DIR/assertions_on_result_states.rs:82:5 + --> $DIR/assertions_on_result_states.rs:83:5 | LL | assert!(res.is_err()) | ^^^^^^^^^^^^^^^^^^^^^ help: replace with: `res.unwrap_err();` diff --git a/tests/ui/assign_ops.fixed b/tests/ui/assign_ops.fixed index b50682ea00c4..ef45e97d1de1 100644 --- a/tests/ui/assign_ops.fixed +++ b/tests/ui/assign_ops.fixed @@ -2,7 +2,7 @@ use core::num::Wrapping; -#[allow(dead_code, unused_assignments)] +#[allow(dead_code, unused_assignments, clippy::useless_vec)] #[warn(clippy::assign_op_pattern)] fn main() { let mut a = 5; diff --git a/tests/ui/assign_ops.rs b/tests/ui/assign_ops.rs index 780d2d040f12..ae87afc485ed 100644 --- a/tests/ui/assign_ops.rs +++ b/tests/ui/assign_ops.rs @@ -2,7 +2,7 @@ use core::num::Wrapping; -#[allow(dead_code, unused_assignments)] +#[allow(dead_code, unused_assignments, clippy::useless_vec)] #[warn(clippy::assign_op_pattern)] fn main() { let mut a = 5; diff --git a/tests/ui/auxiliary/extern_fake_libc.rs b/tests/ui/auxiliary/extern_fake_libc.rs new file mode 100644 index 000000000000..eb5a5d2b8368 --- /dev/null +++ b/tests/ui/auxiliary/extern_fake_libc.rs @@ -0,0 +1,10 @@ +#![allow(nonstandard_style)] +#![allow(clippy::missing_safety_doc, unused)] + +type pid_t = i32; +pub unsafe fn getpid() -> pid_t { + pid_t::from(0) +} +pub fn getpid_SAFE_TRUTH() -> pid_t { + unsafe { getpid() } +} diff --git a/tests/ui/auxiliary/macro_rules.rs b/tests/ui/auxiliary/macro_rules.rs index e5bb906663c5..6b164967a28e 100644 --- a/tests/ui/auxiliary/macro_rules.rs +++ b/tests/ui/auxiliary/macro_rules.rs @@ -1,7 +1,6 @@ #![allow(dead_code)] //! Used to test that certain lints don't trigger in imported external macros - #[macro_export] macro_rules! try_err { () => { @@ -44,3 +43,10 @@ macro_rules! issue_10421 { b = a; }; } + +#[macro_export] +macro_rules! macro_with_panic { + () => { + panic!() + }; +} diff --git a/tests/ui/auxiliary/macro_use_helper.rs b/tests/ui/auxiliary/macro_use_helper.rs index 7ed8a28dbd93..cab216b51ac7 100644 --- a/tests/ui/auxiliary/macro_use_helper.rs +++ b/tests/ui/auxiliary/macro_use_helper.rs @@ -1,3 +1,5 @@ +//@aux-build:macro_rules.rs + extern crate macro_rules; // STMT diff --git a/tests/ui/auxiliary/proc_macro_attr.rs b/tests/ui/auxiliary/proc_macro_attr.rs index d164dd0e5450..fdfe5fc41812 100644 --- a/tests/ui/auxiliary/proc_macro_attr.rs +++ b/tests/ui/auxiliary/proc_macro_attr.rs @@ -1,7 +1,3 @@ -//@compile-flags: --emit=link -//@no-prefer-dynamic - -#![crate_type = "proc-macro"] #![feature(repr128, proc_macro_hygiene, proc_macro_quote, box_patterns)] #![allow(incomplete_features)] #![allow(clippy::useless_conversion, clippy::uninlined_format_args)] diff --git a/tests/ui/auxiliary/proc_macro_derive.rs b/tests/ui/auxiliary/proc_macro_derive.rs index 5a924ca1830a..37f0ec2b37d8 100644 --- a/tests/ui/auxiliary/proc_macro_derive.rs +++ b/tests/ui/auxiliary/proc_macro_derive.rs @@ -1,7 +1,3 @@ -//@compile-flags: --emit=link -//@no-prefer-dynamic - -#![crate_type = "proc-macro"] #![feature(repr128, proc_macro_quote)] #![allow(incomplete_features)] #![allow(clippy::field_reassign_with_default)] @@ -90,70 +86,58 @@ pub fn extra_lifetime(_input: TokenStream) -> TokenStream { #[allow(unused)] #[proc_macro_derive(ArithmeticDerive)] pub fn arithmetic_derive(_: TokenStream) -> TokenStream { - >::from_iter( - [ - Ident::new("fn", Span::call_site()).into(), - Ident::new("_foo", Span::call_site()).into(), - Group::new(Delimiter::Parenthesis, TokenStream::new()).into(), - Group::new( - Delimiter::Brace, - >::from_iter( - [ - Ident::new("let", Span::call_site()).into(), - Ident::new("mut", Span::call_site()).into(), - Ident::new("_n", Span::call_site()).into(), - Punct::new('=', Spacing::Alone).into(), - Literal::i32_unsuffixed(9).into(), - Punct::new(';', Spacing::Alone).into(), - Ident::new("_n", Span::call_site()).into(), - Punct::new('=', Spacing::Alone).into(), - Literal::i32_unsuffixed(9).into(), - Punct::new('/', Spacing::Alone).into(), - Literal::i32_unsuffixed(2).into(), - Punct::new(';', Spacing::Alone).into(), - Ident::new("_n", Span::call_site()).into(), - Punct::new('=', Spacing::Alone).into(), - Punct::new('-', Spacing::Alone).into(), - Ident::new("_n", Span::call_site()).into(), - Punct::new(';', Spacing::Alone).into(), - ] - .into_iter(), - ), - ) - .into(), - ] - .into_iter(), - ) + >::from_iter([ + Ident::new("fn", Span::call_site()).into(), + Ident::new("_foo", Span::call_site()).into(), + Group::new(Delimiter::Parenthesis, TokenStream::new()).into(), + Group::new( + Delimiter::Brace, + >::from_iter([ + Ident::new("let", Span::call_site()).into(), + Ident::new("mut", Span::call_site()).into(), + Ident::new("_n", Span::call_site()).into(), + Punct::new('=', Spacing::Alone).into(), + Literal::i32_unsuffixed(9).into(), + Punct::new(';', Spacing::Alone).into(), + Ident::new("_n", Span::call_site()).into(), + Punct::new('=', Spacing::Alone).into(), + Literal::i32_unsuffixed(9).into(), + Punct::new('/', Spacing::Alone).into(), + Literal::i32_unsuffixed(2).into(), + Punct::new(';', Spacing::Alone).into(), + Ident::new("_n", Span::call_site()).into(), + Punct::new('=', Spacing::Alone).into(), + Punct::new('-', Spacing::Alone).into(), + Ident::new("_n", Span::call_site()).into(), + Punct::new(';', Spacing::Alone).into(), + ]), + ) + .into(), + ]) } #[allow(unused)] #[proc_macro_derive(ShadowDerive)] pub fn shadow_derive(_: TokenStream) -> TokenStream { - >::from_iter( - [ - Ident::new("fn", Span::call_site()).into(), - Ident::new("_foo", Span::call_site()).into(), - Group::new(Delimiter::Parenthesis, TokenStream::new()).into(), - Group::new( - Delimiter::Brace, - >::from_iter( - [ - Ident::new("let", Span::call_site()).into(), - Ident::new("_x", Span::call_site()).into(), - Punct::new('=', Spacing::Alone).into(), - Literal::i32_unsuffixed(2).into(), - Punct::new(';', Spacing::Alone).into(), - Ident::new("let", Span::call_site()).into(), - Ident::new("_x", Span::call_site()).into(), - Punct::new('=', Spacing::Alone).into(), - Ident::new("_x", Span::call_site()).into(), - Punct::new(';', Spacing::Alone).into(), - ] - .into_iter(), - ), - ) - .into(), - ] - .into_iter(), - ) + >::from_iter([ + Ident::new("fn", Span::call_site()).into(), + Ident::new("_foo", Span::call_site()).into(), + Group::new(Delimiter::Parenthesis, TokenStream::new()).into(), + Group::new( + Delimiter::Brace, + >::from_iter([ + Ident::new("let", Span::call_site()).into(), + Ident::new("_x", Span::call_site()).into(), + Punct::new('=', Spacing::Alone).into(), + Literal::i32_unsuffixed(2).into(), + Punct::new(';', Spacing::Alone).into(), + Ident::new("let", Span::call_site()).into(), + Ident::new("_x", Span::call_site()).into(), + Punct::new('=', Spacing::Alone).into(), + Ident::new("_x", Span::call_site()).into(), + Punct::new(';', Spacing::Alone).into(), + ]), + ) + .into(), + ]) } diff --git a/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs b/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs index f13b76e44b04..79e8eff3aa10 100644 --- a/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs +++ b/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs @@ -1,8 +1,3 @@ -//@compile-flags: --emit=link -//@no-prefer-dynamic - -#![crate_type = "proc-macro"] - extern crate proc_macro; use proc_macro::{token_stream, Delimiter, Group, Ident, Span, TokenStream, TokenTree}; diff --git a/tests/ui/auxiliary/proc_macro_unsafe.rs b/tests/ui/auxiliary/proc_macro_unsafe.rs index c2326678d0d5..1c591fc76f3e 100644 --- a/tests/ui/auxiliary/proc_macro_unsafe.rs +++ b/tests/ui/auxiliary/proc_macro_unsafe.rs @@ -1,8 +1,3 @@ -//@compile-flags: --emit=link -//@no-prefer-dynamic - -#![crate_type = "proc-macro"] - extern crate proc_macro; use proc_macro::{Delimiter, Group, Ident, TokenStream, TokenTree}; diff --git a/tests/ui/auxiliary/proc_macros.rs b/tests/ui/auxiliary/proc_macros.rs index 94f075ed09cc..4d008c8cb59f 100644 --- a/tests/ui/auxiliary/proc_macros.rs +++ b/tests/ui/auxiliary/proc_macros.rs @@ -1,10 +1,6 @@ -//@compile-flags: --emit=link -//@no-prefer-dynamic - -#![crate_type = "proc-macro"] #![feature(let_chains)] #![feature(proc_macro_span)] -#![allow(dead_code)] +#![allow(clippy::needless_if, dead_code)] extern crate proc_macro; diff --git a/tests/ui/blocks_in_if_conditions.fixed b/tests/ui/blocks_in_if_conditions.fixed index a9f18782e58b..2a3867ac8fc0 100644 --- a/tests/ui/blocks_in_if_conditions.fixed +++ b/tests/ui/blocks_in_if_conditions.fixed @@ -1,6 +1,6 @@ //@run-rustfix #![warn(clippy::blocks_in_if_conditions)] -#![allow(unused, clippy::let_and_return)] +#![allow(unused, clippy::let_and_return, clippy::needless_if)] #![warn(clippy::nonminimal_bool)] macro_rules! blocky { diff --git a/tests/ui/blocks_in_if_conditions.rs b/tests/ui/blocks_in_if_conditions.rs index 0a70317c4d40..704d09fbad3d 100644 --- a/tests/ui/blocks_in_if_conditions.rs +++ b/tests/ui/blocks_in_if_conditions.rs @@ -1,6 +1,6 @@ //@run-rustfix #![warn(clippy::blocks_in_if_conditions)] -#![allow(unused, clippy::let_and_return)] +#![allow(unused, clippy::let_and_return, clippy::needless_if)] #![warn(clippy::nonminimal_bool)] macro_rules! blocky { diff --git a/tests/ui/blocks_in_if_conditions_closure.rs b/tests/ui/blocks_in_if_conditions_closure.rs index 169589f6d4e7..d6d085d7fd14 100644 --- a/tests/ui/blocks_in_if_conditions_closure.rs +++ b/tests/ui/blocks_in_if_conditions_closure.rs @@ -1,5 +1,10 @@ #![warn(clippy::blocks_in_if_conditions)] -#![allow(unused, clippy::let_and_return)] +#![allow( + unused, + clippy::let_and_return, + clippy::needless_if, + clippy::unnecessary_literal_unwrap +)] fn predicate bool, T>(pfn: F, val: T) -> bool { pfn(val) diff --git a/tests/ui/blocks_in_if_conditions_closure.stderr b/tests/ui/blocks_in_if_conditions_closure.stderr index 941d604dd5f9..5ac02e7504e8 100644 --- a/tests/ui/blocks_in_if_conditions_closure.stderr +++ b/tests/ui/blocks_in_if_conditions_closure.stderr @@ -1,5 +1,5 @@ error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let` - --> $DIR/blocks_in_if_conditions_closure.rs:18:17 + --> $DIR/blocks_in_if_conditions_closure.rs:23:17 | LL | |x| { | _________________^ @@ -11,7 +11,7 @@ LL | | }, = note: `-D clippy::blocks-in-if-conditions` implied by `-D warnings` error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let` - --> $DIR/blocks_in_if_conditions_closure.rs:27:13 + --> $DIR/blocks_in_if_conditions_closure.rs:32:13 | LL | |x| { | _____________^ diff --git a/tests/ui/bool_comparison.fixed b/tests/ui/bool_comparison.fixed index 670eef6a21d7..d6774c035984 100644 --- a/tests/ui/bool_comparison.fixed +++ b/tests/ui/bool_comparison.fixed @@ -1,5 +1,6 @@ //@run-rustfix +#![allow(clippy::needless_if)] #![warn(clippy::bool_comparison)] fn main() { diff --git a/tests/ui/bool_comparison.rs b/tests/ui/bool_comparison.rs index 72851be635d0..c0483fd73748 100644 --- a/tests/ui/bool_comparison.rs +++ b/tests/ui/bool_comparison.rs @@ -1,5 +1,6 @@ //@run-rustfix +#![allow(clippy::needless_if)] #![warn(clippy::bool_comparison)] fn main() { diff --git a/tests/ui/bool_comparison.stderr b/tests/ui/bool_comparison.stderr index 31522d4a5251..f4dded365fba 100644 --- a/tests/ui/bool_comparison.stderr +++ b/tests/ui/bool_comparison.stderr @@ -1,5 +1,5 @@ error: equality checks against true are unnecessary - --> $DIR/bool_comparison.rs:7:8 + --> $DIR/bool_comparison.rs:8:8 | LL | if x == true { | ^^^^^^^^^ help: try simplifying it as shown: `x` @@ -7,127 +7,127 @@ LL | if x == true { = note: `-D clippy::bool-comparison` implied by `-D warnings` error: equality checks against false can be replaced by a negation - --> $DIR/bool_comparison.rs:12:8 + --> $DIR/bool_comparison.rs:13:8 | LL | if x == false { | ^^^^^^^^^^ help: try simplifying it as shown: `!x` error: equality checks against true are unnecessary - --> $DIR/bool_comparison.rs:17:8 + --> $DIR/bool_comparison.rs:18:8 | LL | if true == x { | ^^^^^^^^^ help: try simplifying it as shown: `x` error: equality checks against false can be replaced by a negation - --> $DIR/bool_comparison.rs:22:8 + --> $DIR/bool_comparison.rs:23:8 | LL | if false == x { | ^^^^^^^^^^ help: try simplifying it as shown: `!x` error: inequality checks against true can be replaced by a negation - --> $DIR/bool_comparison.rs:27:8 + --> $DIR/bool_comparison.rs:28:8 | LL | if x != true { | ^^^^^^^^^ help: try simplifying it as shown: `!x` error: inequality checks against false are unnecessary - --> $DIR/bool_comparison.rs:32:8 + --> $DIR/bool_comparison.rs:33:8 | LL | if x != false { | ^^^^^^^^^^ help: try simplifying it as shown: `x` error: inequality checks against true can be replaced by a negation - --> $DIR/bool_comparison.rs:37:8 + --> $DIR/bool_comparison.rs:38:8 | LL | if true != x { | ^^^^^^^^^ help: try simplifying it as shown: `!x` error: inequality checks against false are unnecessary - --> $DIR/bool_comparison.rs:42:8 + --> $DIR/bool_comparison.rs:43:8 | LL | if false != x { | ^^^^^^^^^^ help: try simplifying it as shown: `x` error: less than comparison against true can be replaced by a negation - --> $DIR/bool_comparison.rs:47:8 + --> $DIR/bool_comparison.rs:48:8 | LL | if x < true { | ^^^^^^^^ help: try simplifying it as shown: `!x` error: greater than checks against false are unnecessary - --> $DIR/bool_comparison.rs:52:8 + --> $DIR/bool_comparison.rs:53:8 | LL | if false < x { | ^^^^^^^^^ help: try simplifying it as shown: `x` error: greater than checks against false are unnecessary - --> $DIR/bool_comparison.rs:57:8 + --> $DIR/bool_comparison.rs:58:8 | LL | if x > false { | ^^^^^^^^^ help: try simplifying it as shown: `x` error: less than comparison against true can be replaced by a negation - --> $DIR/bool_comparison.rs:62:8 + --> $DIR/bool_comparison.rs:63:8 | LL | if true > x { | ^^^^^^^^ help: try simplifying it as shown: `!x` error: order comparisons between booleans can be simplified - --> $DIR/bool_comparison.rs:68:8 + --> $DIR/bool_comparison.rs:69:8 | LL | if x < y { | ^^^^^ help: try simplifying it as shown: `!x & y` error: order comparisons between booleans can be simplified - --> $DIR/bool_comparison.rs:73:8 + --> $DIR/bool_comparison.rs:74:8 | LL | if x > y { | ^^^^^ help: try simplifying it as shown: `x & !y` error: this comparison might be written more concisely - --> $DIR/bool_comparison.rs:121:8 + --> $DIR/bool_comparison.rs:122:8 | LL | if a == !b {}; | ^^^^^^^ help: try simplifying it as shown: `a != b` error: this comparison might be written more concisely - --> $DIR/bool_comparison.rs:122:8 + --> $DIR/bool_comparison.rs:123:8 | LL | if !a == b {}; | ^^^^^^^ help: try simplifying it as shown: `a != b` error: this comparison might be written more concisely - --> $DIR/bool_comparison.rs:126:8 + --> $DIR/bool_comparison.rs:127:8 | LL | if b == !a {}; | ^^^^^^^ help: try simplifying it as shown: `b != a` error: this comparison might be written more concisely - --> $DIR/bool_comparison.rs:127:8 + --> $DIR/bool_comparison.rs:128:8 | LL | if !b == a {}; | ^^^^^^^ help: try simplifying it as shown: `b != a` error: equality checks against false can be replaced by a negation - --> $DIR/bool_comparison.rs:151:8 + --> $DIR/bool_comparison.rs:152:8 | LL | if false == m!(func) {} | ^^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `!m!(func)` error: equality checks against false can be replaced by a negation - --> $DIR/bool_comparison.rs:152:8 + --> $DIR/bool_comparison.rs:153:8 | LL | if m!(func) == false {} | ^^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `!m!(func)` error: equality checks against true are unnecessary - --> $DIR/bool_comparison.rs:153:8 + --> $DIR/bool_comparison.rs:154:8 | LL | if true == m!(func) {} | ^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `m!(func)` error: equality checks against true are unnecessary - --> $DIR/bool_comparison.rs:154:8 + --> $DIR/bool_comparison.rs:155:8 | LL | if m!(func) == true {} | ^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `m!(func)` diff --git a/tests/ui/borrow_as_ptr.fixed b/tests/ui/borrow_as_ptr.fixed index 3f440ce0045a..996cc3650ff0 100644 --- a/tests/ui/borrow_as_ptr.fixed +++ b/tests/ui/borrow_as_ptr.fixed @@ -1,9 +1,18 @@ //@run-rustfix #![warn(clippy::borrow_as_ptr)] +#![allow(clippy::useless_vec)] + +fn a() -> i32 { + 0 +} fn main() { let val = 1; let _p = std::ptr::addr_of!(val); + let _p = &0 as *const i32; + let _p = &a() as *const i32; + let vec = vec![1]; + let _p = &vec.len() as *const usize; let mut val_mut = 1; let _p_mut = std::ptr::addr_of_mut!(val_mut); diff --git a/tests/ui/borrow_as_ptr.rs b/tests/ui/borrow_as_ptr.rs index c1ca9180eef4..5eafaeb2fc30 100644 --- a/tests/ui/borrow_as_ptr.rs +++ b/tests/ui/borrow_as_ptr.rs @@ -1,9 +1,18 @@ //@run-rustfix #![warn(clippy::borrow_as_ptr)] +#![allow(clippy::useless_vec)] + +fn a() -> i32 { + 0 +} fn main() { let val = 1; let _p = &val as *const i32; + let _p = &0 as *const i32; + let _p = &a() as *const i32; + let vec = vec![1]; + let _p = &vec.len() as *const usize; let mut val_mut = 1; let _p_mut = &mut val_mut as *mut i32; diff --git a/tests/ui/borrow_as_ptr.stderr b/tests/ui/borrow_as_ptr.stderr index be1ed7330567..c9990bb6f226 100644 --- a/tests/ui/borrow_as_ptr.stderr +++ b/tests/ui/borrow_as_ptr.stderr @@ -1,5 +1,5 @@ error: borrow as raw pointer - --> $DIR/borrow_as_ptr.rs:6:14 + --> $DIR/borrow_as_ptr.rs:11:14 | LL | let _p = &val as *const i32; | ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::addr_of!(val)` @@ -7,7 +7,7 @@ LL | let _p = &val as *const i32; = note: `-D clippy::borrow-as-ptr` implied by `-D warnings` error: borrow as raw pointer - --> $DIR/borrow_as_ptr.rs:9:18 + --> $DIR/borrow_as_ptr.rs:18:18 | LL | let _p_mut = &mut val_mut as *mut i32; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::addr_of_mut!(val_mut)` diff --git a/tests/ui/borrow_deref_ref.fixed b/tests/ui/borrow_deref_ref.fixed index 755264617920..b951ba04c37f 100644 --- a/tests/ui/borrow_deref_ref.fixed +++ b/tests/ui/borrow_deref_ref.fixed @@ -1,5 +1,5 @@ //@run-rustfix -//@aux-build: proc_macros.rs +//@aux-build: proc_macros.rs:proc-macro #![allow(dead_code, unused_variables)] diff --git a/tests/ui/borrow_deref_ref.rs b/tests/ui/borrow_deref_ref.rs index e319d365f7e7..52980e55fbea 100644 --- a/tests/ui/borrow_deref_ref.rs +++ b/tests/ui/borrow_deref_ref.rs @@ -1,5 +1,5 @@ //@run-rustfix -//@aux-build: proc_macros.rs +//@aux-build: proc_macros.rs:proc-macro #![allow(dead_code, unused_variables)] diff --git a/tests/ui/borrow_interior_mutable_const/enums.rs b/tests/ui/borrow_interior_mutable_const/enums.rs index 29b08ab36430..da940a4cfb50 100644 --- a/tests/ui/borrow_interior_mutable_const/enums.rs +++ b/tests/ui/borrow_interior_mutable_const/enums.rs @@ -1,6 +1,6 @@ //@aux-build:helper.rs -#![warn(clippy::borrow_interior_mutable_const)] +#![deny(clippy::borrow_interior_mutable_const)] #![allow(clippy::declare_interior_mutable_const)] // this file (mostly) replicates its `declare` counterpart. Please see it for more discussions. @@ -19,7 +19,7 @@ const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); const FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; fn borrow_optional_cell() { - let _ = &UNFROZEN_VARIANT; //~ ERROR interior mutability + let _ = &UNFROZEN_VARIANT; //~ ERROR: interior mutability let _ = &FROZEN_VARIANT; } @@ -34,11 +34,11 @@ trait AssocConsts { // This is the "suboptimal behavior" mentioned in `is_value_unfrozen` // caused by a similar reason to unfrozen types without any default values // get linted even if it has frozen variants'. - let _ = &Self::TO_BE_FROZEN_VARIANT; //~ ERROR interior mutable + let _ = &Self::TO_BE_FROZEN_VARIANT; //~ ERROR: interior mutability // The lint ignores default values because an impl of this trait can set // an unfrozen variant to `DEFAULTED_ON_FROZEN_VARIANT` and use the default impl for `function`. - let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT; //~ ERROR interior mutable + let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT; //~ ERROR: interior mutability } } @@ -47,9 +47,9 @@ impl AssocConsts for u64 { const TO_BE_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; fn function() { - let _ = &::TO_BE_UNFROZEN_VARIANT; //~ ERROR interior mutable + let _ = &::TO_BE_UNFROZEN_VARIANT; //~ ERROR: interior mutability let _ = &::TO_BE_FROZEN_VARIANT; - let _ = &Self::DEFAULTED_ON_UNFROZEN_VARIANT; //~ ERROR interior mutable + let _ = &Self::DEFAULTED_ON_UNFROZEN_VARIANT; //~ ERROR: interior mutability let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT; } } @@ -67,11 +67,11 @@ trait AssocTypes { impl AssocTypes for u64 { type ToBeUnfrozen = AtomicUsize; - const TO_BE_UNFROZEN_VARIANT: Option = Some(Self::ToBeUnfrozen::new(4)); //~ ERROR interior mutable + const TO_BE_UNFROZEN_VARIANT: Option = Some(Self::ToBeUnfrozen::new(4)); const TO_BE_FROZEN_VARIANT: Option = None; fn function() { - let _ = &::TO_BE_UNFROZEN_VARIANT; //~ ERROR interior mutable + let _ = &::TO_BE_UNFROZEN_VARIANT; //~ ERROR: interior mutability let _ = &::TO_BE_FROZEN_VARIANT; } } @@ -83,19 +83,19 @@ enum BothOfCellAndGeneric { } impl BothOfCellAndGeneric { - const UNFROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ ERROR interior mutable - const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR interior mutable + const UNFROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); + const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); const FROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Frozen(5); fn function() { - let _ = &Self::UNFROZEN_VARIANT; //~ ERROR interior mutability - let _ = &Self::GENERIC_VARIANT; //~ ERROR interior mutability + let _ = &Self::UNFROZEN_VARIANT; //~ ERROR: interior mutability + let _ = &Self::GENERIC_VARIANT; //~ ERROR: interior mutability let _ = &Self::FROZEN_VARIANT; } } fn main() { // constants defined in foreign crates - let _ = &helper::WRAPPED_PRIVATE_UNFROZEN_VARIANT; //~ ERROR interior mutability + let _ = &helper::WRAPPED_PRIVATE_UNFROZEN_VARIANT; //~ ERROR: interior mutability let _ = &helper::WRAPPED_PRIVATE_FROZEN_VARIANT; } diff --git a/tests/ui/borrow_interior_mutable_const/enums.stderr b/tests/ui/borrow_interior_mutable_const/enums.stderr index b0cab977a038..b753ec92608a 100644 --- a/tests/ui/borrow_interior_mutable_const/enums.stderr +++ b/tests/ui/borrow_interior_mutable_const/enums.stderr @@ -1,16 +1,20 @@ error: a `const` item with interior mutability should not be borrowed --> $DIR/enums.rs:22:14 | -LL | let _ = &UNFROZEN_VARIANT; //~ ERROR interior mutability +LL | let _ = &UNFROZEN_VARIANT; | ^^^^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here - = note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings` +note: the lint level is defined here + --> $DIR/enums.rs:3:9 + | +LL | #![deny(clippy::borrow_interior_mutable_const)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item with interior mutability should not be borrowed --> $DIR/enums.rs:37:18 | -LL | let _ = &Self::TO_BE_FROZEN_VARIANT; //~ ERROR interior mutable +LL | let _ = &Self::TO_BE_FROZEN_VARIANT; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here @@ -18,7 +22,7 @@ LL | let _ = &Self::TO_BE_FROZEN_VARIANT; //~ ERROR interior mutable error: a `const` item with interior mutability should not be borrowed --> $DIR/enums.rs:41:18 | -LL | let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT; //~ ERROR interior mutable +LL | let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here @@ -26,7 +30,7 @@ LL | let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT; //~ ERROR interior muta error: a `const` item with interior mutability should not be borrowed --> $DIR/enums.rs:50:18 | -LL | let _ = &::TO_BE_UNFROZEN_VARIANT; //~ ERROR interior mutable +LL | let _ = &::TO_BE_UNFROZEN_VARIANT; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here @@ -34,7 +38,7 @@ LL | let _ = &::TO_BE_UNFROZEN_VARIANT; //~ ERROR i error: a `const` item with interior mutability should not be borrowed --> $DIR/enums.rs:52:18 | -LL | let _ = &Self::DEFAULTED_ON_UNFROZEN_VARIANT; //~ ERROR interior mutable +LL | let _ = &Self::DEFAULTED_ON_UNFROZEN_VARIANT; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here @@ -42,7 +46,7 @@ LL | let _ = &Self::DEFAULTED_ON_UNFROZEN_VARIANT; //~ ERROR interior mu error: a `const` item with interior mutability should not be borrowed --> $DIR/enums.rs:74:18 | -LL | let _ = &::TO_BE_UNFROZEN_VARIANT; //~ ERROR interior mutable +LL | let _ = &::TO_BE_UNFROZEN_VARIANT; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here @@ -50,7 +54,7 @@ LL | let _ = &::TO_BE_UNFROZEN_VARIANT; //~ ERROR in error: a `const` item with interior mutability should not be borrowed --> $DIR/enums.rs:91:18 | -LL | let _ = &Self::UNFROZEN_VARIANT; //~ ERROR interior mutability +LL | let _ = &Self::UNFROZEN_VARIANT; | ^^^^^^^^^^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here @@ -58,7 +62,7 @@ LL | let _ = &Self::UNFROZEN_VARIANT; //~ ERROR interior mutability error: a `const` item with interior mutability should not be borrowed --> $DIR/enums.rs:92:18 | -LL | let _ = &Self::GENERIC_VARIANT; //~ ERROR interior mutability +LL | let _ = &Self::GENERIC_VARIANT; | ^^^^^^^^^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here @@ -66,7 +70,7 @@ LL | let _ = &Self::GENERIC_VARIANT; //~ ERROR interior mutability error: a `const` item with interior mutability should not be borrowed --> $DIR/enums.rs:99:14 | -LL | let _ = &helper::WRAPPED_PRIVATE_UNFROZEN_VARIANT; //~ ERROR interior mutability +LL | let _ = &helper::WRAPPED_PRIVATE_UNFROZEN_VARIANT; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here diff --git a/tests/ui/borrow_interior_mutable_const/others.rs b/tests/ui/borrow_interior_mutable_const/others.rs index 7c57864245a9..0ea93dd84625 100644 --- a/tests/ui/borrow_interior_mutable_const/others.rs +++ b/tests/ui/borrow_interior_mutable_const/others.rs @@ -1,4 +1,4 @@ -#![warn(clippy::borrow_interior_mutable_const)] +#![deny(clippy::borrow_interior_mutable_const)] #![allow(clippy::declare_interior_mutable_const, clippy::needless_borrow)] #![allow(const_item_mutation)] @@ -51,14 +51,14 @@ impl std::ops::Deref for StaticRef { const CELL_REF: StaticRef<(UnsafeCell,)> = unsafe { StaticRef::new(std::ptr::null()) }; fn main() { - ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability - assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutability + ATOMIC.store(1, Ordering::SeqCst); //~ ERROR: interior mutability + assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR: interior mutability let _once = ONCE_INIT; - let _once_ref = &ONCE_INIT; //~ ERROR interior mutability - let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability - let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability - let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability + let _once_ref = &ONCE_INIT; //~ ERROR: interior mutability + let _once_ref_2 = &&ONCE_INIT; //~ ERROR: interior mutability + let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR: interior mutability + let _once_mut = &mut ONCE_INIT; //~ ERROR: interior mutability let _atomic_into_inner = ATOMIC.into_inner(); // these should be all fine. let _twice = (ONCE_INIT, ONCE_INIT); @@ -69,23 +69,23 @@ fn main() { let _ref_array_once = &[ONCE_INIT, ONCE_INIT][0]; // referencing projection is still bad. - let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability - let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability - let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability - let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability - let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability + let _ = &ATOMIC_TUPLE; //~ ERROR: interior mutability + let _ = &ATOMIC_TUPLE.0; //~ ERROR: interior mutability + let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR: interior mutability + let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR: interior mutability + let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR: interior mutability let _ = &*ATOMIC_TUPLE.1; let _ = &ATOMIC_TUPLE.2; let _ = (&&&&ATOMIC_TUPLE).0; let _ = (&&&&ATOMIC_TUPLE).2; let _ = ATOMIC_TUPLE.0; - let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability + let _ = ATOMIC_TUPLE.0[0]; //~ ERROR: interior mutability let _ = ATOMIC_TUPLE.1.into_iter(); let _ = ATOMIC_TUPLE.2; let _ = &{ ATOMIC_TUPLE }; - CELL.set(2); //~ ERROR interior mutability - assert_eq!(CELL.get(), 6); //~ ERROR interior mutability + CELL.set(2); //~ ERROR: interior mutability + assert_eq!(CELL.get(), 6); //~ ERROR: interior mutability assert_eq!(INTEGER, 8); assert!(STRING.is_empty()); diff --git a/tests/ui/borrow_interior_mutable_const/others.stderr b/tests/ui/borrow_interior_mutable_const/others.stderr index c87ad206c2ae..200e04b8f6be 100644 --- a/tests/ui/borrow_interior_mutable_const/others.stderr +++ b/tests/ui/borrow_interior_mutable_const/others.stderr @@ -1,16 +1,20 @@ error: a `const` item with interior mutability should not be borrowed --> $DIR/others.rs:54:5 | -LL | ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability +LL | ATOMIC.store(1, Ordering::SeqCst); | ^^^^^^ | = help: assign this const to a local or static variable, and use the variable here - = note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings` +note: the lint level is defined here + --> $DIR/others.rs:1:9 + | +LL | #![deny(clippy::borrow_interior_mutable_const)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item with interior mutability should not be borrowed --> $DIR/others.rs:55:16 | -LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutability +LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); | ^^^^^^ | = help: assign this const to a local or static variable, and use the variable here @@ -18,7 +22,7 @@ LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutabi error: a `const` item with interior mutability should not be borrowed --> $DIR/others.rs:58:22 | -LL | let _once_ref = &ONCE_INIT; //~ ERROR interior mutability +LL | let _once_ref = &ONCE_INIT; | ^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here @@ -26,7 +30,7 @@ LL | let _once_ref = &ONCE_INIT; //~ ERROR interior mutability error: a `const` item with interior mutability should not be borrowed --> $DIR/others.rs:59:25 | -LL | let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability +LL | let _once_ref_2 = &&ONCE_INIT; | ^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here @@ -34,7 +38,7 @@ LL | let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability error: a `const` item with interior mutability should not be borrowed --> $DIR/others.rs:60:27 | -LL | let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability +LL | let _once_ref_4 = &&&&ONCE_INIT; | ^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here @@ -42,7 +46,7 @@ LL | let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability error: a `const` item with interior mutability should not be borrowed --> $DIR/others.rs:61:26 | -LL | let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability +LL | let _once_mut = &mut ONCE_INIT; | ^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here @@ -50,7 +54,7 @@ LL | let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability error: a `const` item with interior mutability should not be borrowed --> $DIR/others.rs:72:14 | -LL | let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability +LL | let _ = &ATOMIC_TUPLE; | ^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here @@ -58,7 +62,7 @@ LL | let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability error: a `const` item with interior mutability should not be borrowed --> $DIR/others.rs:73:14 | -LL | let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability +LL | let _ = &ATOMIC_TUPLE.0; | ^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here @@ -66,7 +70,7 @@ LL | let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability error: a `const` item with interior mutability should not be borrowed --> $DIR/others.rs:74:19 | -LL | let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability +LL | let _ = &(&&&&ATOMIC_TUPLE).0; | ^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here @@ -74,7 +78,7 @@ LL | let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability error: a `const` item with interior mutability should not be borrowed --> $DIR/others.rs:75:14 | -LL | let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability +LL | let _ = &ATOMIC_TUPLE.0[0]; | ^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here @@ -82,7 +86,7 @@ LL | let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability error: a `const` item with interior mutability should not be borrowed --> $DIR/others.rs:76:13 | -LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability +LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); | ^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here @@ -90,7 +94,7 @@ LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mu error: a `const` item with interior mutability should not be borrowed --> $DIR/others.rs:82:13 | -LL | let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability +LL | let _ = ATOMIC_TUPLE.0[0]; | ^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here @@ -98,7 +102,7 @@ LL | let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability error: a `const` item with interior mutability should not be borrowed --> $DIR/others.rs:87:5 | -LL | CELL.set(2); //~ ERROR interior mutability +LL | CELL.set(2); | ^^^^ | = help: assign this const to a local or static variable, and use the variable here @@ -106,7 +110,7 @@ LL | CELL.set(2); //~ ERROR interior mutability error: a `const` item with interior mutability should not be borrowed --> $DIR/others.rs:88:16 | -LL | assert_eq!(CELL.get(), 6); //~ ERROR interior mutability +LL | assert_eq!(CELL.get(), 6); | ^^^^ | = help: assign this const to a local or static variable, and use the variable here diff --git a/tests/ui/borrow_interior_mutable_const/traits.rs b/tests/ui/borrow_interior_mutable_const/traits.rs index 06b5d62e8f9a..4da3833cbf5a 100644 --- a/tests/ui/borrow_interior_mutable_const/traits.rs +++ b/tests/ui/borrow_interior_mutable_const/traits.rs @@ -1,4 +1,4 @@ -#![warn(clippy::borrow_interior_mutable_const)] +#![deny(clippy::borrow_interior_mutable_const)] #![allow(clippy::declare_interior_mutable_const)] // this file replicates its `declare` counterpart. Please see it for more discussions. @@ -12,7 +12,7 @@ trait ConcreteTypes { const STRING: String; fn function() { - let _ = &Self::ATOMIC; //~ ERROR interior mutable + let _ = &Self::ATOMIC; //~ ERROR: interior mutability let _ = &Self::STRING; } } @@ -23,7 +23,7 @@ impl ConcreteTypes for u64 { fn function() { // Lint this again since implementers can choose not to borrow it. - let _ = &Self::ATOMIC; //~ ERROR interior mutable + let _ = &Self::ATOMIC; //~ ERROR: interior mutability let _ = &Self::STRING; } } @@ -48,7 +48,7 @@ impl GenericTypes for Vec { fn function() { let _ = &Self::TO_REMAIN_GENERIC; - let _ = &Self::TO_BE_CONCRETE; //~ ERROR interior mutable + let _ = &Self::TO_BE_CONCRETE; //~ ERROR: interior mutability } } @@ -83,8 +83,8 @@ impl AssocTypes for Vec { fn function() { let _ = &Self::TO_BE_FROZEN; - let _ = &Self::TO_BE_UNFROZEN; //~ ERROR interior mutable - let _ = &Self::WRAPPED_TO_BE_UNFROZEN; //~ ERROR interior mutable + let _ = &Self::TO_BE_UNFROZEN; //~ ERROR: interior mutability + let _ = &Self::WRAPPED_TO_BE_UNFROZEN; //~ ERROR: interior mutability let _ = &Self::WRAPPED_TO_BE_GENERIC_PARAM; } } @@ -106,7 +106,7 @@ where fn function() { let _ = &Self::NOT_BOUNDED; - let _ = &Self::BOUNDED; //~ ERROR interior mutable + let _ = &Self::BOUNDED; //~ ERROR: interior mutability } } @@ -119,7 +119,7 @@ where fn function() { let _ = &Self::NOT_BOUNDED; - let _ = &Self::BOUNDED; //~ ERROR interior mutable + let _ = &Self::BOUNDED; //~ ERROR: interior mutability } } @@ -148,8 +148,8 @@ impl SelfType for AtomicUsize { const WRAPPED_SELF: Option = Some(AtomicUsize::new(21)); fn function() { - let _ = &Self::SELF; //~ ERROR interior mutable - let _ = &Self::WRAPPED_SELF; //~ ERROR interior mutable + let _ = &Self::SELF; //~ ERROR: interior mutability + let _ = &Self::WRAPPED_SELF; //~ ERROR: interior mutability } } @@ -159,7 +159,7 @@ trait BothOfCellAndGeneric { fn function() { let _ = &Self::DIRECT; - let _ = &Self::INDIRECT; //~ ERROR interior mutable + let _ = &Self::INDIRECT; //~ ERROR: interior mutability } } @@ -169,7 +169,7 @@ impl BothOfCellAndGeneric for Vec { fn function() { let _ = &Self::DIRECT; - let _ = &Self::INDIRECT; //~ ERROR interior mutable + let _ = &Self::INDIRECT; //~ ERROR: interior mutability } } @@ -188,15 +188,15 @@ where const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); fn function() { - let _ = &Self::ATOMIC; //~ ERROR interior mutable + let _ = &Self::ATOMIC; //~ ERROR: interior mutability let _ = &Self::COW; let _ = &Self::GENERIC_TYPE; let _ = &Self::ASSOC_TYPE; - let _ = &Self::BOUNDED_ASSOC_TYPE; //~ ERROR interior mutable + let _ = &Self::BOUNDED_ASSOC_TYPE; //~ ERROR: interior mutability } } fn main() { - u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability - assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability + u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR: interior mutability + assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR: interior mutability } diff --git a/tests/ui/borrow_interior_mutable_const/traits.stderr b/tests/ui/borrow_interior_mutable_const/traits.stderr index f34ae8814c33..add223acd68c 100644 --- a/tests/ui/borrow_interior_mutable_const/traits.stderr +++ b/tests/ui/borrow_interior_mutable_const/traits.stderr @@ -1,16 +1,20 @@ error: a `const` item with interior mutability should not be borrowed --> $DIR/traits.rs:15:18 | -LL | let _ = &Self::ATOMIC; //~ ERROR interior mutable +LL | let _ = &Self::ATOMIC; | ^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here - = note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings` +note: the lint level is defined here + --> $DIR/traits.rs:1:9 + | +LL | #![deny(clippy::borrow_interior_mutable_const)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item with interior mutability should not be borrowed --> $DIR/traits.rs:26:18 | -LL | let _ = &Self::ATOMIC; //~ ERROR interior mutable +LL | let _ = &Self::ATOMIC; | ^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here @@ -18,7 +22,7 @@ LL | let _ = &Self::ATOMIC; //~ ERROR interior mutable error: a `const` item with interior mutability should not be borrowed --> $DIR/traits.rs:51:18 | -LL | let _ = &Self::TO_BE_CONCRETE; //~ ERROR interior mutable +LL | let _ = &Self::TO_BE_CONCRETE; | ^^^^^^^^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here @@ -26,7 +30,7 @@ LL | let _ = &Self::TO_BE_CONCRETE; //~ ERROR interior mutable error: a `const` item with interior mutability should not be borrowed --> $DIR/traits.rs:86:18 | -LL | let _ = &Self::TO_BE_UNFROZEN; //~ ERROR interior mutable +LL | let _ = &Self::TO_BE_UNFROZEN; | ^^^^^^^^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here @@ -34,7 +38,7 @@ LL | let _ = &Self::TO_BE_UNFROZEN; //~ ERROR interior mutable error: a `const` item with interior mutability should not be borrowed --> $DIR/traits.rs:87:18 | -LL | let _ = &Self::WRAPPED_TO_BE_UNFROZEN; //~ ERROR interior mutable +LL | let _ = &Self::WRAPPED_TO_BE_UNFROZEN; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here @@ -42,7 +46,7 @@ LL | let _ = &Self::WRAPPED_TO_BE_UNFROZEN; //~ ERROR interior mutable error: a `const` item with interior mutability should not be borrowed --> $DIR/traits.rs:109:18 | -LL | let _ = &Self::BOUNDED; //~ ERROR interior mutable +LL | let _ = &Self::BOUNDED; | ^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here @@ -50,7 +54,7 @@ LL | let _ = &Self::BOUNDED; //~ ERROR interior mutable error: a `const` item with interior mutability should not be borrowed --> $DIR/traits.rs:122:18 | -LL | let _ = &Self::BOUNDED; //~ ERROR interior mutable +LL | let _ = &Self::BOUNDED; | ^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here @@ -58,7 +62,7 @@ LL | let _ = &Self::BOUNDED; //~ ERROR interior mutable error: a `const` item with interior mutability should not be borrowed --> $DIR/traits.rs:151:18 | -LL | let _ = &Self::SELF; //~ ERROR interior mutable +LL | let _ = &Self::SELF; | ^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here @@ -66,7 +70,7 @@ LL | let _ = &Self::SELF; //~ ERROR interior mutable error: a `const` item with interior mutability should not be borrowed --> $DIR/traits.rs:152:18 | -LL | let _ = &Self::WRAPPED_SELF; //~ ERROR interior mutable +LL | let _ = &Self::WRAPPED_SELF; | ^^^^^^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here @@ -74,7 +78,7 @@ LL | let _ = &Self::WRAPPED_SELF; //~ ERROR interior mutable error: a `const` item with interior mutability should not be borrowed --> $DIR/traits.rs:162:18 | -LL | let _ = &Self::INDIRECT; //~ ERROR interior mutable +LL | let _ = &Self::INDIRECT; | ^^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here @@ -82,7 +86,7 @@ LL | let _ = &Self::INDIRECT; //~ ERROR interior mutable error: a `const` item with interior mutability should not be borrowed --> $DIR/traits.rs:172:18 | -LL | let _ = &Self::INDIRECT; //~ ERROR interior mutable +LL | let _ = &Self::INDIRECT; | ^^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here @@ -90,7 +94,7 @@ LL | let _ = &Self::INDIRECT; //~ ERROR interior mutable error: a `const` item with interior mutability should not be borrowed --> $DIR/traits.rs:191:18 | -LL | let _ = &Self::ATOMIC; //~ ERROR interior mutable +LL | let _ = &Self::ATOMIC; | ^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here @@ -98,7 +102,7 @@ LL | let _ = &Self::ATOMIC; //~ ERROR interior mutable error: a `const` item with interior mutability should not be borrowed --> $DIR/traits.rs:195:18 | -LL | let _ = &Self::BOUNDED_ASSOC_TYPE; //~ ERROR interior mutable +LL | let _ = &Self::BOUNDED_ASSOC_TYPE; | ^^^^^^^^^^^^^^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here @@ -106,7 +110,7 @@ LL | let _ = &Self::BOUNDED_ASSOC_TYPE; //~ ERROR interior mutable error: a `const` item with interior mutability should not be borrowed --> $DIR/traits.rs:200:5 | -LL | u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability +LL | u64::ATOMIC.store(5, Ordering::SeqCst); | ^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here @@ -114,7 +118,7 @@ LL | u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability error: a `const` item with interior mutability should not be borrowed --> $DIR/traits.rs:201:16 | -LL | assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability +LL | assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); | ^^^^^^^^^^^ | = help: assign this const to a local or static variable, and use the variable here diff --git a/tests/ui/builtin_type_shadow.rs b/tests/ui/builtin_type_shadow.rs index 69b8b6a0e68c..c5addd53434c 100644 --- a/tests/ui/builtin_type_shadow.rs +++ b/tests/ui/builtin_type_shadow.rs @@ -3,7 +3,7 @@ fn foo(a: u32) -> u32 { 42 - // ^ rustc's type error + //~^ ERROR: mismatched types } fn main() {} diff --git a/tests/ui/bytecount.rs b/tests/ui/bytecount.rs index d3ad26921bff..4d168bfeab93 100644 --- a/tests/ui/bytecount.rs +++ b/tests/ui/bytecount.rs @@ -1,4 +1,4 @@ -#![allow(clippy::needless_borrow)] +#![allow(clippy::needless_borrow, clippy::useless_vec)] #[deny(clippy::naive_bytecount)] fn main() { diff --git a/tests/ui/cast.rs b/tests/ui/cast.rs index a86b85706a34..60a0eabf55b0 100644 --- a/tests/ui/cast.rs +++ b/tests/ui/cast.rs @@ -41,6 +41,14 @@ fn main() { 1u32 as i32; 1u64 as i64; 1usize as isize; + 1usize as i8; // should not wrap, usize is never 8 bits + 1usize as i16; // wraps on 16 bit ptr size + 1usize as i32; // wraps on 32 bit ptr size + 1usize as i64; // wraps on 64 bit ptr size + 1u8 as isize; // should not wrap, isize is never 8 bits + 1u16 as isize; // wraps on 16 bit ptr size + 1u32 as isize; // wraps on 32 bit ptr size + 1u64 as isize; // wraps on 64 bit ptr size // Test clippy::cast_sign_loss 1i32 as u32; -1i32 as u32; diff --git a/tests/ui/cast.stderr b/tests/ui/cast.stderr index 65ecf1aa37aa..de29af78ef30 100644 --- a/tests/ui/cast.stderr +++ b/tests/ui/cast.stderr @@ -215,20 +215,110 @@ error: casting `usize` to `isize` may wrap around the value LL | 1usize as isize; | ^^^^^^^^^^^^^^^ -error: casting `i32` to `u32` may lose the sign of the value +error: casting `usize` to `i8` may truncate the value + --> $DIR/cast.rs:44:5 + | +LL | 1usize as i8; // should not wrap, usize is never 8 bits + | ^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | i8::try_from(1usize); // should not wrap, usize is never 8 bits + | ~~~~~~~~~~~~~~~~~~~~ + +error: casting `usize` to `i16` may truncate the value + --> $DIR/cast.rs:45:5 + | +LL | 1usize as i16; // wraps on 16 bit ptr size + | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | i16::try_from(1usize); // wraps on 16 bit ptr size + | ~~~~~~~~~~~~~~~~~~~~~ + +error: casting `usize` to `i16` may wrap around the value on targets with 16-bit wide pointers + --> $DIR/cast.rs:45:5 + | +LL | 1usize as i16; // wraps on 16 bit ptr size + | ^^^^^^^^^^^^^ + | + = note: `usize` and `isize` may be as small as 16 bits on some platforms + = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types + +error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers --> $DIR/cast.rs:46:5 | +LL | 1usize as i32; // wraps on 32 bit ptr size + | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | i32::try_from(1usize); // wraps on 32 bit ptr size + | ~~~~~~~~~~~~~~~~~~~~~ + +error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers + --> $DIR/cast.rs:46:5 + | +LL | 1usize as i32; // wraps on 32 bit ptr size + | ^^^^^^^^^^^^^ + +error: casting `usize` to `i64` may wrap around the value on targets with 64-bit wide pointers + --> $DIR/cast.rs:47:5 + | +LL | 1usize as i64; // wraps on 64 bit ptr size + | ^^^^^^^^^^^^^ + +error: casting `u16` to `isize` may wrap around the value on targets with 16-bit wide pointers + --> $DIR/cast.rs:49:5 + | +LL | 1u16 as isize; // wraps on 16 bit ptr size + | ^^^^^^^^^^^^^ + | + = note: `usize` and `isize` may be as small as 16 bits on some platforms + = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types + +error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers + --> $DIR/cast.rs:50:5 + | +LL | 1u32 as isize; // wraps on 32 bit ptr size + | ^^^^^^^^^^^^^ + +error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers + --> $DIR/cast.rs:51:5 + | +LL | 1u64 as isize; // wraps on 64 bit ptr size + | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | isize::try_from(1u64); // wraps on 64 bit ptr size + | ~~~~~~~~~~~~~~~~~~~~~ + +error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers + --> $DIR/cast.rs:51:5 + | +LL | 1u64 as isize; // wraps on 64 bit ptr size + | ^^^^^^^^^^^^^ + +error: casting `i32` to `u32` may lose the sign of the value + --> $DIR/cast.rs:54:5 + | LL | -1i32 as u32; | ^^^^^^^^^^^^ error: casting `isize` to `usize` may lose the sign of the value - --> $DIR/cast.rs:48:5 + --> $DIR/cast.rs:56:5 | LL | -1isize as usize; | ^^^^^^^^^^^^^^^^ error: casting `i64` to `i8` may truncate the value - --> $DIR/cast.rs:115:5 + --> $DIR/cast.rs:123:5 | LL | (-99999999999i64).min(1) as i8; // should be linted because signed | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -240,7 +330,7 @@ LL | i8::try_from((-99999999999i64).min(1)); // should be linted because sig | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `u8` may truncate the value - --> $DIR/cast.rs:127:5 + --> $DIR/cast.rs:135:5 | LL | 999999u64.clamp(0, 256) as u8; // should still be linted | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -252,7 +342,7 @@ LL | u8::try_from(999999u64.clamp(0, 256)); // should still be linted | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: casting `main::E2` to `u8` may truncate the value - --> $DIR/cast.rs:148:21 + --> $DIR/cast.rs:156:21 | LL | let _ = self as u8; | ^^^^^^^^^^ @@ -264,7 +354,7 @@ LL | let _ = u8::try_from(self); | ~~~~~~~~~~~~~~~~~~ error: casting `main::E2::B` to `u8` will truncate the value - --> $DIR/cast.rs:149:21 + --> $DIR/cast.rs:157:21 | LL | let _ = Self::B as u8; | ^^^^^^^^^^^^^ @@ -272,7 +362,7 @@ LL | let _ = Self::B as u8; = note: `-D clippy::cast-enum-truncation` implied by `-D warnings` error: casting `main::E5` to `i8` may truncate the value - --> $DIR/cast.rs:185:21 + --> $DIR/cast.rs:193:21 | LL | let _ = self as i8; | ^^^^^^^^^^ @@ -284,13 +374,13 @@ LL | let _ = i8::try_from(self); | ~~~~~~~~~~~~~~~~~~ error: casting `main::E5::A` to `i8` will truncate the value - --> $DIR/cast.rs:186:21 + --> $DIR/cast.rs:194:21 | LL | let _ = Self::A as i8; | ^^^^^^^^^^^^^ error: casting `main::E6` to `i16` may truncate the value - --> $DIR/cast.rs:200:21 + --> $DIR/cast.rs:208:21 | LL | let _ = self as i16; | ^^^^^^^^^^^ @@ -302,7 +392,7 @@ LL | let _ = i16::try_from(self); | ~~~~~~~~~~~~~~~~~~~ error: casting `main::E7` to `usize` may truncate the value on targets with 32-bit wide pointers - --> $DIR/cast.rs:215:21 + --> $DIR/cast.rs:223:21 | LL | let _ = self as usize; | ^^^^^^^^^^^^^ @@ -314,7 +404,7 @@ LL | let _ = usize::try_from(self); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `main::E10` to `u16` may truncate the value - --> $DIR/cast.rs:256:21 + --> $DIR/cast.rs:264:21 | LL | let _ = self as u16; | ^^^^^^^^^^^ @@ -326,7 +416,7 @@ LL | let _ = u16::try_from(self); | ~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `u8` may truncate the value - --> $DIR/cast.rs:264:13 + --> $DIR/cast.rs:272:13 | LL | let c = (q >> 16) as u8; | ^^^^^^^^^^^^^^^ @@ -338,7 +428,7 @@ LL | let c = u8::try_from(q >> 16); | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `u8` may truncate the value - --> $DIR/cast.rs:267:13 + --> $DIR/cast.rs:275:13 | LL | let c = (q / 1000) as u8; | ^^^^^^^^^^^^^^^^ @@ -349,5 +439,5 @@ help: ... or use `try_from` and handle the error accordingly LL | let c = u8::try_from(q / 1000); | ~~~~~~~~~~~~~~~~~~~~~~ -error: aborting due to 41 previous errors +error: aborting due to 51 previous errors diff --git a/tests/ui/cast_slice_different_sizes.rs b/tests/ui/cast_slice_different_sizes.rs index b77f01883bf3..27e03ebb7197 100644 --- a/tests/ui/cast_slice_different_sizes.rs +++ b/tests/ui/cast_slice_different_sizes.rs @@ -1,4 +1,4 @@ -#![allow(clippy::let_unit_value)] +#![allow(clippy::let_unit_value, clippy::unnecessary_cast)] fn main() { let x: [i32; 3] = [1_i32, 2, 3]; diff --git a/tests/ui/cfg_features.rs b/tests/ui/cfg_features.rs new file mode 100644 index 000000000000..bc4109c2c896 --- /dev/null +++ b/tests/ui/cfg_features.rs @@ -0,0 +1,12 @@ +#![warn(clippy::maybe_misused_cfg)] + +fn main() { + #[cfg(features = "not-really-a-feature")] + let _ = 1 + 2; + + #[cfg(all(feature = "right", features = "wrong"))] + let _ = 1 + 2; + + #[cfg(all(features = "wrong1", any(feature = "right", features = "wrong2", feature, features)))] + let _ = 1 + 2; +} diff --git a/tests/ui/cfg_features.stderr b/tests/ui/cfg_features.stderr new file mode 100644 index 000000000000..00405985d48c --- /dev/null +++ b/tests/ui/cfg_features.stderr @@ -0,0 +1,28 @@ +error: feature may misspelled as features + --> $DIR/cfg_features.rs:4:11 + | +LL | #[cfg(features = "not-really-a-feature")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `feature = "not-really-a-feature"` + | + = note: `-D clippy::maybe-misused-cfg` implied by `-D warnings` + +error: feature may misspelled as features + --> $DIR/cfg_features.rs:7:34 + | +LL | #[cfg(all(feature = "right", features = "wrong"))] + | ^^^^^^^^^^^^^^^^^^ help: use: `feature = "wrong"` + +error: feature may misspelled as features + --> $DIR/cfg_features.rs:10:15 + | +LL | #[cfg(all(features = "wrong1", any(feature = "right", features = "wrong2", feature, features)))] + | ^^^^^^^^^^^^^^^^^^^ help: use: `feature = "wrong1"` + +error: feature may misspelled as features + --> $DIR/cfg_features.rs:10:59 + | +LL | #[cfg(all(features = "wrong1", any(feature = "right", features = "wrong2", feature, features)))] + | ^^^^^^^^^^^^^^^^^^^ help: use: `feature = "wrong2"` + +error: aborting due to 4 previous errors + diff --git a/tests/ui/checked_unwrap/complex_conditionals.rs b/tests/ui/checked_unwrap/complex_conditionals.rs index ec082c73b44c..16e54a7d969e 100644 --- a/tests/ui/checked_unwrap/complex_conditionals.rs +++ b/tests/ui/checked_unwrap/complex_conditionals.rs @@ -1,5 +1,9 @@ #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] -#![allow(clippy::if_same_then_else, clippy::branches_sharing_code)] +#![allow( + clippy::if_same_then_else, + clippy::branches_sharing_code, + clippy::unnecessary_literal_unwrap +)] fn test_complex_conditions() { let x: Result<(), ()> = Ok(()); diff --git a/tests/ui/checked_unwrap/complex_conditionals.stderr b/tests/ui/checked_unwrap/complex_conditionals.stderr index d44d5072e485..c395c5ba06f2 100644 --- a/tests/ui/checked_unwrap/complex_conditionals.stderr +++ b/tests/ui/checked_unwrap/complex_conditionals.stderr @@ -1,5 +1,5 @@ error: called `unwrap` on `x` after checking its variant with `is_ok` - --> $DIR/complex_conditionals.rs:8:9 + --> $DIR/complex_conditionals.rs:12:9 | LL | if x.is_ok() && y.is_err() { | --------- the check is happening here @@ -14,7 +14,7 @@ LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap_err()` will always panic - --> $DIR/complex_conditionals.rs:9:9 + --> $DIR/complex_conditionals.rs:13:9 | LL | if x.is_ok() && y.is_err() { | --------- because of this check @@ -29,7 +29,7 @@ LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> $DIR/complex_conditionals.rs:10:9 + --> $DIR/complex_conditionals.rs:14:9 | LL | if x.is_ok() && y.is_err() { | ---------- because of this check @@ -38,7 +38,7 @@ LL | y.unwrap(); // will panic | ^^^^^^^^^^ error: called `unwrap_err` on `y` after checking its variant with `is_err` - --> $DIR/complex_conditionals.rs:11:9 + --> $DIR/complex_conditionals.rs:15:9 | LL | if x.is_ok() && y.is_err() { | ---------- the check is happening here @@ -49,7 +49,7 @@ LL | y.unwrap_err(); // unnecessary = help: try using `if let` or `match` error: this call to `unwrap()` will always panic - --> $DIR/complex_conditionals.rs:25:9 + --> $DIR/complex_conditionals.rs:29:9 | LL | if x.is_ok() || y.is_ok() { | --------- because of this check @@ -58,7 +58,7 @@ LL | x.unwrap(); // will panic | ^^^^^^^^^^ error: called `unwrap_err` on `x` after checking its variant with `is_ok` - --> $DIR/complex_conditionals.rs:26:9 + --> $DIR/complex_conditionals.rs:30:9 | LL | if x.is_ok() || y.is_ok() { | --------- the check is happening here @@ -69,7 +69,7 @@ LL | x.unwrap_err(); // unnecessary = help: try using `if let` or `match` error: this call to `unwrap()` will always panic - --> $DIR/complex_conditionals.rs:27:9 + --> $DIR/complex_conditionals.rs:31:9 | LL | if x.is_ok() || y.is_ok() { | --------- because of this check @@ -78,7 +78,7 @@ LL | y.unwrap(); // will panic | ^^^^^^^^^^ error: called `unwrap_err` on `y` after checking its variant with `is_ok` - --> $DIR/complex_conditionals.rs:28:9 + --> $DIR/complex_conditionals.rs:32:9 | LL | if x.is_ok() || y.is_ok() { | --------- the check is happening here @@ -89,7 +89,7 @@ LL | y.unwrap_err(); // unnecessary = help: try using `if let` or `match` error: called `unwrap` on `x` after checking its variant with `is_ok` - --> $DIR/complex_conditionals.rs:32:9 + --> $DIR/complex_conditionals.rs:36:9 | LL | if x.is_ok() && !(y.is_ok() || z.is_err()) { | --------- the check is happening here @@ -99,7 +99,7 @@ LL | x.unwrap(); // unnecessary = help: try using `if let` or `match` error: this call to `unwrap_err()` will always panic - --> $DIR/complex_conditionals.rs:33:9 + --> $DIR/complex_conditionals.rs:37:9 | LL | if x.is_ok() && !(y.is_ok() || z.is_err()) { | --------- because of this check @@ -108,7 +108,7 @@ LL | x.unwrap_err(); // will panic | ^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> $DIR/complex_conditionals.rs:34:9 + --> $DIR/complex_conditionals.rs:38:9 | LL | if x.is_ok() && !(y.is_ok() || z.is_err()) { | --------- because of this check @@ -117,7 +117,7 @@ LL | y.unwrap(); // will panic | ^^^^^^^^^^ error: called `unwrap_err` on `y` after checking its variant with `is_ok` - --> $DIR/complex_conditionals.rs:35:9 + --> $DIR/complex_conditionals.rs:39:9 | LL | if x.is_ok() && !(y.is_ok() || z.is_err()) { | --------- the check is happening here @@ -128,7 +128,7 @@ LL | y.unwrap_err(); // unnecessary = help: try using `if let` or `match` error: called `unwrap` on `z` after checking its variant with `is_err` - --> $DIR/complex_conditionals.rs:36:9 + --> $DIR/complex_conditionals.rs:40:9 | LL | if x.is_ok() && !(y.is_ok() || z.is_err()) { | ---------- the check is happening here @@ -139,7 +139,7 @@ LL | z.unwrap(); // unnecessary = help: try using `if let` or `match` error: this call to `unwrap_err()` will always panic - --> $DIR/complex_conditionals.rs:37:9 + --> $DIR/complex_conditionals.rs:41:9 | LL | if x.is_ok() && !(y.is_ok() || z.is_err()) { | ---------- because of this check @@ -148,7 +148,7 @@ LL | z.unwrap_err(); // will panic | ^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> $DIR/complex_conditionals.rs:45:9 + --> $DIR/complex_conditionals.rs:49:9 | LL | if x.is_ok() || !(y.is_ok() && z.is_err()) { | --------- because of this check @@ -157,7 +157,7 @@ LL | x.unwrap(); // will panic | ^^^^^^^^^^ error: called `unwrap_err` on `x` after checking its variant with `is_ok` - --> $DIR/complex_conditionals.rs:46:9 + --> $DIR/complex_conditionals.rs:50:9 | LL | if x.is_ok() || !(y.is_ok() && z.is_err()) { | --------- the check is happening here @@ -168,7 +168,7 @@ LL | x.unwrap_err(); // unnecessary = help: try using `if let` or `match` error: called `unwrap` on `y` after checking its variant with `is_ok` - --> $DIR/complex_conditionals.rs:47:9 + --> $DIR/complex_conditionals.rs:51:9 | LL | if x.is_ok() || !(y.is_ok() && z.is_err()) { | --------- the check is happening here @@ -179,7 +179,7 @@ LL | y.unwrap(); // unnecessary = help: try using `if let` or `match` error: this call to `unwrap_err()` will always panic - --> $DIR/complex_conditionals.rs:48:9 + --> $DIR/complex_conditionals.rs:52:9 | LL | if x.is_ok() || !(y.is_ok() && z.is_err()) { | --------- because of this check @@ -188,7 +188,7 @@ LL | y.unwrap_err(); // will panic | ^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> $DIR/complex_conditionals.rs:49:9 + --> $DIR/complex_conditionals.rs:53:9 | LL | if x.is_ok() || !(y.is_ok() && z.is_err()) { | ---------- because of this check @@ -197,7 +197,7 @@ LL | z.unwrap(); // will panic | ^^^^^^^^^^ error: called `unwrap_err` on `z` after checking its variant with `is_err` - --> $DIR/complex_conditionals.rs:50:9 + --> $DIR/complex_conditionals.rs:54:9 | LL | if x.is_ok() || !(y.is_ok() && z.is_err()) { | ---------- the check is happening here diff --git a/tests/ui/checked_unwrap/complex_conditionals_nested.rs b/tests/ui/checked_unwrap/complex_conditionals_nested.rs index 043ea4148dc5..e417cf833cbb 100644 --- a/tests/ui/checked_unwrap/complex_conditionals_nested.rs +++ b/tests/ui/checked_unwrap/complex_conditionals_nested.rs @@ -1,5 +1,9 @@ #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] -#![allow(clippy::if_same_then_else, clippy::branches_sharing_code)] +#![allow( + clippy::if_same_then_else, + clippy::branches_sharing_code, + clippy::unnecessary_literal_unwrap +)] fn test_nested() { fn nested() { diff --git a/tests/ui/checked_unwrap/complex_conditionals_nested.stderr b/tests/ui/checked_unwrap/complex_conditionals_nested.stderr index 542ab53300c0..049a69d93bfe 100644 --- a/tests/ui/checked_unwrap/complex_conditionals_nested.stderr +++ b/tests/ui/checked_unwrap/complex_conditionals_nested.stderr @@ -1,5 +1,5 @@ error: called `unwrap` on `x` after checking its variant with `is_some` - --> $DIR/complex_conditionals_nested.rs:8:13 + --> $DIR/complex_conditionals_nested.rs:12:13 | LL | if x.is_some() { | -------------- help: try: `if let Some(..) = x` @@ -13,7 +13,7 @@ LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> $DIR/complex_conditionals_nested.rs:10:13 + --> $DIR/complex_conditionals_nested.rs:14:13 | LL | if x.is_some() { | ----------- because of this check diff --git a/tests/ui/checked_unwrap/simple_conditionals.rs b/tests/ui/checked_unwrap/simple_conditionals.rs index 82dce81979fd..61042bb90d27 100644 --- a/tests/ui/checked_unwrap/simple_conditionals.rs +++ b/tests/ui/checked_unwrap/simple_conditionals.rs @@ -1,6 +1,10 @@ #![feature(lint_reasons)] #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] -#![allow(clippy::if_same_then_else, clippy::branches_sharing_code)] +#![allow( + clippy::if_same_then_else, + clippy::branches_sharing_code, + clippy::unnecessary_literal_unwrap +)] macro_rules! m { ($a:expr) => { diff --git a/tests/ui/checked_unwrap/simple_conditionals.stderr b/tests/ui/checked_unwrap/simple_conditionals.stderr index ef6882742223..93809f6551ad 100644 --- a/tests/ui/checked_unwrap/simple_conditionals.stderr +++ b/tests/ui/checked_unwrap/simple_conditionals.stderr @@ -1,5 +1,5 @@ error: called `unwrap` on `x` after checking its variant with `is_some` - --> $DIR/simple_conditionals.rs:40:9 + --> $DIR/simple_conditionals.rs:44:9 | LL | if x.is_some() { | -------------- help: try: `if let Some(..) = x` @@ -13,7 +13,7 @@ LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `expect` on `x` after checking its variant with `is_some` - --> $DIR/simple_conditionals.rs:41:9 + --> $DIR/simple_conditionals.rs:45:9 | LL | if x.is_some() { | -------------- help: try: `if let Some(..) = x` @@ -22,7 +22,7 @@ LL | x.expect("an error message"); // unnecessary | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> $DIR/simple_conditionals.rs:43:9 + --> $DIR/simple_conditionals.rs:47:9 | LL | if x.is_some() { | ----------- because of this check @@ -37,7 +37,7 @@ LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `expect()` will always panic - --> $DIR/simple_conditionals.rs:44:9 + --> $DIR/simple_conditionals.rs:48:9 | LL | if x.is_some() { | ----------- because of this check @@ -46,7 +46,7 @@ LL | x.expect("an error message"); // will panic | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> $DIR/simple_conditionals.rs:47:9 + --> $DIR/simple_conditionals.rs:51:9 | LL | if x.is_none() { | ----------- because of this check @@ -54,7 +54,7 @@ LL | x.unwrap(); // will panic | ^^^^^^^^^^ error: called `unwrap` on `x` after checking its variant with `is_none` - --> $DIR/simple_conditionals.rs:49:9 + --> $DIR/simple_conditionals.rs:53:9 | LL | if x.is_none() { | -------------- help: try: `if let Some(..) = x` @@ -63,7 +63,7 @@ LL | x.unwrap(); // unnecessary | ^^^^^^^^^^ error: called `unwrap` on `x` after checking its variant with `is_some` - --> $DIR/simple_conditionals.rs:8:13 + --> $DIR/simple_conditionals.rs:12:13 | LL | if $a.is_some() { | --------------- help: try: `if let Some(..) = x` @@ -76,7 +76,7 @@ LL | m!(x); = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) error: called `unwrap` on `x` after checking its variant with `is_ok` - --> $DIR/simple_conditionals.rs:57:9 + --> $DIR/simple_conditionals.rs:61:9 | LL | if x.is_ok() { | ------------ help: try: `if let Ok(..) = x` @@ -84,7 +84,7 @@ LL | x.unwrap(); // unnecessary | ^^^^^^^^^^ error: called `expect` on `x` after checking its variant with `is_ok` - --> $DIR/simple_conditionals.rs:58:9 + --> $DIR/simple_conditionals.rs:62:9 | LL | if x.is_ok() { | ------------ help: try: `if let Ok(..) = x` @@ -93,7 +93,7 @@ LL | x.expect("an error message"); // unnecessary | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap_err()` will always panic - --> $DIR/simple_conditionals.rs:59:9 + --> $DIR/simple_conditionals.rs:63:9 | LL | if x.is_ok() { | --------- because of this check @@ -102,7 +102,7 @@ LL | x.unwrap_err(); // will panic | ^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> $DIR/simple_conditionals.rs:61:9 + --> $DIR/simple_conditionals.rs:65:9 | LL | if x.is_ok() { | --------- because of this check @@ -111,7 +111,7 @@ LL | x.unwrap(); // will panic | ^^^^^^^^^^ error: this call to `expect()` will always panic - --> $DIR/simple_conditionals.rs:62:9 + --> $DIR/simple_conditionals.rs:66:9 | LL | if x.is_ok() { | --------- because of this check @@ -120,7 +120,7 @@ LL | x.expect("an error message"); // will panic | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `unwrap_err` on `x` after checking its variant with `is_ok` - --> $DIR/simple_conditionals.rs:63:9 + --> $DIR/simple_conditionals.rs:67:9 | LL | if x.is_ok() { | ------------ help: try: `if let Err(..) = x` @@ -129,7 +129,7 @@ LL | x.unwrap_err(); // unnecessary | ^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> $DIR/simple_conditionals.rs:66:9 + --> $DIR/simple_conditionals.rs:70:9 | LL | if x.is_err() { | ---------- because of this check @@ -137,7 +137,7 @@ LL | x.unwrap(); // will panic | ^^^^^^^^^^ error: called `unwrap_err` on `x` after checking its variant with `is_err` - --> $DIR/simple_conditionals.rs:67:9 + --> $DIR/simple_conditionals.rs:71:9 | LL | if x.is_err() { | ------------- help: try: `if let Err(..) = x` @@ -146,7 +146,7 @@ LL | x.unwrap_err(); // unnecessary | ^^^^^^^^^^^^^^ error: called `unwrap` on `x` after checking its variant with `is_err` - --> $DIR/simple_conditionals.rs:69:9 + --> $DIR/simple_conditionals.rs:73:9 | LL | if x.is_err() { | ------------- help: try: `if let Ok(..) = x` @@ -155,7 +155,7 @@ LL | x.unwrap(); // unnecessary | ^^^^^^^^^^ error: this call to `unwrap_err()` will always panic - --> $DIR/simple_conditionals.rs:70:9 + --> $DIR/simple_conditionals.rs:74:9 | LL | if x.is_err() { | ---------- because of this check diff --git a/tests/ui/clone_on_copy_impl.rs b/tests/ui/clone_on_copy_impl.rs index 8f9f2a0db8c4..b7c186bef772 100644 --- a/tests/ui/clone_on_copy_impl.rs +++ b/tests/ui/clone_on_copy_impl.rs @@ -1,3 +1,5 @@ +#![allow(clippy::incorrect_clone_impl_on_copy_type)] + use std::fmt; use std::marker::PhantomData; diff --git a/tests/ui/cloned_instead_of_copied.fixed b/tests/ui/cloned_instead_of_copied.fixed index b6e09ab31908..34bd2233440b 100644 --- a/tests/ui/cloned_instead_of_copied.fixed +++ b/tests/ui/cloned_instead_of_copied.fixed @@ -2,6 +2,7 @@ #![warn(clippy::cloned_instead_of_copied)] #![allow(unused)] +#![allow(clippy::useless_vec)] fn main() { // yay diff --git a/tests/ui/cloned_instead_of_copied.rs b/tests/ui/cloned_instead_of_copied.rs index fa9e1a996139..fa8444937b6b 100644 --- a/tests/ui/cloned_instead_of_copied.rs +++ b/tests/ui/cloned_instead_of_copied.rs @@ -2,6 +2,7 @@ #![warn(clippy::cloned_instead_of_copied)] #![allow(unused)] +#![allow(clippy::useless_vec)] fn main() { // yay diff --git a/tests/ui/cloned_instead_of_copied.stderr b/tests/ui/cloned_instead_of_copied.stderr index e0361acd9560..3ce482006e94 100644 --- a/tests/ui/cloned_instead_of_copied.stderr +++ b/tests/ui/cloned_instead_of_copied.stderr @@ -1,5 +1,5 @@ error: used `cloned` where `copied` could be used instead - --> $DIR/cloned_instead_of_copied.rs:8:24 + --> $DIR/cloned_instead_of_copied.rs:9:24 | LL | let _ = [1].iter().cloned(); | ^^^^^^ help: try: `copied` @@ -7,43 +7,43 @@ LL | let _ = [1].iter().cloned(); = note: `-D clippy::cloned-instead-of-copied` implied by `-D warnings` error: used `cloned` where `copied` could be used instead - --> $DIR/cloned_instead_of_copied.rs:9:31 + --> $DIR/cloned_instead_of_copied.rs:10:31 | LL | let _ = vec!["hi"].iter().cloned(); | ^^^^^^ help: try: `copied` error: used `cloned` where `copied` could be used instead - --> $DIR/cloned_instead_of_copied.rs:10:22 + --> $DIR/cloned_instead_of_copied.rs:11:22 | LL | let _ = Some(&1).cloned(); | ^^^^^^ help: try: `copied` error: used `cloned` where `copied` could be used instead - --> $DIR/cloned_instead_of_copied.rs:11:34 + --> $DIR/cloned_instead_of_copied.rs:12:34 | LL | let _ = Box::new([1].iter()).cloned(); | ^^^^^^ help: try: `copied` error: used `cloned` where `copied` could be used instead - --> $DIR/cloned_instead_of_copied.rs:12:32 + --> $DIR/cloned_instead_of_copied.rs:13:32 | LL | let _ = Box::new(Some(&1)).cloned(); | ^^^^^^ help: try: `copied` error: used `cloned` where `copied` could be used instead - --> $DIR/cloned_instead_of_copied.rs:28:22 + --> $DIR/cloned_instead_of_copied.rs:29:22 | LL | let _ = Some(&1).cloned(); // Option::copied needs 1.35 | ^^^^^^ help: try: `copied` error: used `cloned` where `copied` could be used instead - --> $DIR/cloned_instead_of_copied.rs:33:24 + --> $DIR/cloned_instead_of_copied.rs:34:24 | LL | let _ = [1].iter().cloned(); // Iterator::copied needs 1.36 | ^^^^^^ help: try: `copied` error: used `cloned` where `copied` could be used instead - --> $DIR/cloned_instead_of_copied.rs:34:22 + --> $DIR/cloned_instead_of_copied.rs:35:22 | LL | let _ = Some(&1).cloned(); | ^^^^^^ help: try: `copied` diff --git a/tests/ui/cmp_owned/asymmetric_partial_eq.fixed b/tests/ui/cmp_owned/asymmetric_partial_eq.fixed index 3bf3deb9b918..118346348564 100644 --- a/tests/ui/cmp_owned/asymmetric_partial_eq.fixed +++ b/tests/ui/cmp_owned/asymmetric_partial_eq.fixed @@ -1,5 +1,10 @@ //@run-rustfix -#![allow(unused, clippy::redundant_clone, clippy::derive_partial_eq_without_eq)] // See #5700 +#![allow( + unused, + clippy::needless_if, + clippy::redundant_clone, + clippy::derive_partial_eq_without_eq +)] // See #5700 // Define the types in each module to avoid trait impls leaking between modules. macro_rules! impl_types { diff --git a/tests/ui/cmp_owned/asymmetric_partial_eq.rs b/tests/ui/cmp_owned/asymmetric_partial_eq.rs index 10107dc8f86d..3a25d53a5d08 100644 --- a/tests/ui/cmp_owned/asymmetric_partial_eq.rs +++ b/tests/ui/cmp_owned/asymmetric_partial_eq.rs @@ -1,5 +1,10 @@ //@run-rustfix -#![allow(unused, clippy::redundant_clone, clippy::derive_partial_eq_without_eq)] // See #5700 +#![allow( + unused, + clippy::needless_if, + clippy::redundant_clone, + clippy::derive_partial_eq_without_eq +)] // See #5700 // Define the types in each module to avoid trait impls leaking between modules. macro_rules! impl_types { diff --git a/tests/ui/cmp_owned/asymmetric_partial_eq.stderr b/tests/ui/cmp_owned/asymmetric_partial_eq.stderr index 43bf8851fc62..4714a0daaa68 100644 --- a/tests/ui/cmp_owned/asymmetric_partial_eq.stderr +++ b/tests/ui/cmp_owned/asymmetric_partial_eq.stderr @@ -1,5 +1,5 @@ error: this creates an owned instance just for comparison - --> $DIR/asymmetric_partial_eq.rs:42:12 + --> $DIR/asymmetric_partial_eq.rs:47:12 | LL | if borrowed.to_owned() == owned {} | ^^^^^^^^^^^^^^^^^^^ help: try: `borrowed` @@ -7,7 +7,7 @@ LL | if borrowed.to_owned() == owned {} = note: `-D clippy::cmp-owned` implied by `-D warnings` error: this creates an owned instance just for comparison - --> $DIR/asymmetric_partial_eq.rs:43:21 + --> $DIR/asymmetric_partial_eq.rs:48:21 | LL | if owned == borrowed.to_owned() {} | ---------^^^^^^^^^^^^^^^^^^^ @@ -15,13 +15,13 @@ LL | if owned == borrowed.to_owned() {} | help: try: `borrowed == owned` error: this creates an owned instance just for comparison - --> $DIR/asymmetric_partial_eq.rs:61:21 + --> $DIR/asymmetric_partial_eq.rs:66:21 | LL | if owned == borrowed.to_owned() {} | ^^^^^^^^^^^^^^^^^^^ help: try: `borrowed` error: this creates an owned instance just for comparison - --> $DIR/asymmetric_partial_eq.rs:62:12 + --> $DIR/asymmetric_partial_eq.rs:67:12 | LL | if borrowed.to_owned() == owned {} | ^^^^^^^^^^^^^^^^^^^--------- @@ -29,7 +29,7 @@ LL | if borrowed.to_owned() == owned {} | help: try: `owned == borrowed` error: this creates an owned instance just for comparison - --> $DIR/asymmetric_partial_eq.rs:88:20 + --> $DIR/asymmetric_partial_eq.rs:93:20 | LL | if "Hi" == borrowed.to_string() {} | --------^^^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL | if "Hi" == borrowed.to_string() {} | help: try: `borrowed == "Hi"` error: this creates an owned instance just for comparison - --> $DIR/asymmetric_partial_eq.rs:89:12 + --> $DIR/asymmetric_partial_eq.rs:94:12 | LL | if borrowed.to_string() == "Hi" {} | ^^^^^^^^^^^^^^^^^^^^ help: try: `borrowed` diff --git a/tests/ui/cmp_owned/with_suggestion.fixed b/tests/ui/cmp_owned/with_suggestion.fixed index 76f90ab2a9d1..bf1a58588a85 100644 --- a/tests/ui/cmp_owned/with_suggestion.fixed +++ b/tests/ui/cmp_owned/with_suggestion.fixed @@ -31,7 +31,7 @@ struct Foo; impl PartialEq for Foo { // Allow this here, because it emits the lint // without a suggestion. This is tested in - // `tests/ui/cmp_owned/without_suggestion.rs` + // `$DIR/without_suggestion.rs` #[allow(clippy::cmp_owned)] fn eq(&self, other: &Self) -> bool { self.to_owned() == *other diff --git a/tests/ui/cognitive_complexity.stderr b/tests/ui/cognitive_complexity.stderr index 5824631fa83b..d867246301ab 100644 --- a/tests/ui/cognitive_complexity.stderr +++ b/tests/ui/cognitive_complexity.stderr @@ -39,6 +39,14 @@ LL | fn bar() { | = help: you could split it up into multiple smaller functions +error: the function has a cognitive complexity of (2/1) + --> $DIR/cognitive_complexity.rs:178:4 + | +LL | fn dont_warn_on_tests() { + | ^^^^^^^^^^^^^^^^^^ + | + = help: you could split it up into multiple smaller functions + error: the function has a cognitive complexity of (2/1) --> $DIR/cognitive_complexity.rs:186:4 | @@ -151,5 +159,5 @@ LL | pub async fn async_method() { | = help: you could split it up into multiple smaller functions -error: aborting due to 19 previous errors +error: aborting due to 20 previous errors diff --git a/tests/ui/collapsible_else_if.fixed b/tests/ui/collapsible_else_if.fixed index 8302cec45e78..c4116cd8520c 100644 --- a/tests/ui/collapsible_else_if.fixed +++ b/tests/ui/collapsible_else_if.fixed @@ -1,5 +1,5 @@ //@run-rustfix -#![allow(clippy::assertions_on_constants, clippy::equatable_if_let)] +#![allow(clippy::assertions_on_constants, clippy::equatable_if_let, clippy::needless_if)] #[rustfmt::skip] #[warn(clippy::collapsible_if)] diff --git a/tests/ui/collapsible_else_if.rs b/tests/ui/collapsible_else_if.rs index 5913dcf41caf..8f51d0ee508f 100644 --- a/tests/ui/collapsible_else_if.rs +++ b/tests/ui/collapsible_else_if.rs @@ -1,5 +1,5 @@ //@run-rustfix -#![allow(clippy::assertions_on_constants, clippy::equatable_if_let)] +#![allow(clippy::assertions_on_constants, clippy::equatable_if_let, clippy::needless_if)] #[rustfmt::skip] #[warn(clippy::collapsible_if)] diff --git a/tests/ui/collapsible_if.fixed b/tests/ui/collapsible_if.fixed index c6514a559340..e305e1d7a871 100644 --- a/tests/ui/collapsible_if.fixed +++ b/tests/ui/collapsible_if.fixed @@ -2,6 +2,7 @@ #![allow( clippy::assertions_on_constants, clippy::equatable_if_let, + clippy::needless_if, clippy::nonminimal_bool, clippy::eq_op )] diff --git a/tests/ui/collapsible_if.rs b/tests/ui/collapsible_if.rs index 2c85b68df632..7c52959d3b51 100644 --- a/tests/ui/collapsible_if.rs +++ b/tests/ui/collapsible_if.rs @@ -2,6 +2,7 @@ #![allow( clippy::assertions_on_constants, clippy::equatable_if_let, + clippy::needless_if, clippy::nonminimal_bool, clippy::eq_op )] diff --git a/tests/ui/collapsible_if.stderr b/tests/ui/collapsible_if.stderr index c687bae1acc5..4a1a9e8a60ae 100644 --- a/tests/ui/collapsible_if.stderr +++ b/tests/ui/collapsible_if.stderr @@ -1,5 +1,5 @@ error: this `if` statement can be collapsed - --> $DIR/collapsible_if.rs:14:5 + --> $DIR/collapsible_if.rs:15:5 | LL | / if x == "hello" { LL | | if y == "world" { @@ -17,7 +17,7 @@ LL + } | error: this `if` statement can be collapsed - --> $DIR/collapsible_if.rs:20:5 + --> $DIR/collapsible_if.rs:21:5 | LL | / if x == "hello" || x == "world" { LL | | if y == "world" || y == "hello" { @@ -34,7 +34,7 @@ LL + } | error: this `if` statement can be collapsed - --> $DIR/collapsible_if.rs:26:5 + --> $DIR/collapsible_if.rs:27:5 | LL | / if x == "hello" && x == "world" { LL | | if y == "world" || y == "hello" { @@ -51,7 +51,7 @@ LL + } | error: this `if` statement can be collapsed - --> $DIR/collapsible_if.rs:32:5 + --> $DIR/collapsible_if.rs:33:5 | LL | / if x == "hello" || x == "world" { LL | | if y == "world" && y == "hello" { @@ -68,7 +68,7 @@ LL + } | error: this `if` statement can be collapsed - --> $DIR/collapsible_if.rs:38:5 + --> $DIR/collapsible_if.rs:39:5 | LL | / if x == "hello" && x == "world" { LL | | if y == "world" && y == "hello" { @@ -85,7 +85,7 @@ LL + } | error: this `if` statement can be collapsed - --> $DIR/collapsible_if.rs:44:5 + --> $DIR/collapsible_if.rs:45:5 | LL | / if 42 == 1337 { LL | | if 'a' != 'A' { @@ -102,7 +102,7 @@ LL + } | error: this `if` statement can be collapsed - --> $DIR/collapsible_if.rs:100:5 + --> $DIR/collapsible_if.rs:101:5 | LL | / if x == "hello" { LL | | if y == "world" { // Collapsible @@ -119,7 +119,7 @@ LL + } | error: this `if` statement can be collapsed - --> $DIR/collapsible_if.rs:159:5 + --> $DIR/collapsible_if.rs:160:5 | LL | / if matches!(true, true) { LL | | if matches!(true, true) {} @@ -127,7 +127,7 @@ LL | | } | |_____^ help: collapse nested if block: `if matches!(true, true) && matches!(true, true) {}` error: this `if` statement can be collapsed - --> $DIR/collapsible_if.rs:164:5 + --> $DIR/collapsible_if.rs:165:5 | LL | / if matches!(true, true) && truth() { LL | | if matches!(true, true) {} diff --git a/tests/ui/collection_is_never_read.rs b/tests/ui/collection_is_never_read.rs index 2c1a42a72c14..e02c1c57230a 100644 --- a/tests/ui/collection_is_never_read.rs +++ b/tests/ui/collection_is_never_read.rs @@ -1,4 +1,4 @@ -#![allow(unused)] +#![allow(unused, clippy::useless_vec)] #![warn(clippy::collection_is_never_read)] use std::collections::{HashMap, HashSet}; diff --git a/tests/ui/comparison_to_empty.fixed b/tests/ui/comparison_to_empty.fixed index dd2615ab25cf..c92dd509ebb2 100644 --- a/tests/ui/comparison_to_empty.fixed +++ b/tests/ui/comparison_to_empty.fixed @@ -1,6 +1,7 @@ //@run-rustfix #![warn(clippy::comparison_to_empty)] +#![allow(clippy::useless_vec)] fn main() { // Disallow comparisons to empty diff --git a/tests/ui/comparison_to_empty.rs b/tests/ui/comparison_to_empty.rs index 5462784c6ac8..b3489714380a 100644 --- a/tests/ui/comparison_to_empty.rs +++ b/tests/ui/comparison_to_empty.rs @@ -1,6 +1,7 @@ //@run-rustfix #![warn(clippy::comparison_to_empty)] +#![allow(clippy::useless_vec)] fn main() { // Disallow comparisons to empty diff --git a/tests/ui/comparison_to_empty.stderr b/tests/ui/comparison_to_empty.stderr index f69d6bd5255d..cc09b17eb895 100644 --- a/tests/ui/comparison_to_empty.stderr +++ b/tests/ui/comparison_to_empty.stderr @@ -1,5 +1,5 @@ error: comparison to empty slice - --> $DIR/comparison_to_empty.rs:8:13 + --> $DIR/comparison_to_empty.rs:9:13 | LL | let _ = s == ""; | ^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()` @@ -7,19 +7,19 @@ LL | let _ = s == ""; = note: `-D clippy::comparison-to-empty` implied by `-D warnings` error: comparison to empty slice - --> $DIR/comparison_to_empty.rs:9:13 + --> $DIR/comparison_to_empty.rs:10:13 | LL | let _ = s != ""; | ^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!s.is_empty()` error: comparison to empty slice - --> $DIR/comparison_to_empty.rs:12:13 + --> $DIR/comparison_to_empty.rs:13:13 | LL | let _ = v == []; | ^^^^^^^ help: using `is_empty` is clearer and more explicit: `v.is_empty()` error: comparison to empty slice - --> $DIR/comparison_to_empty.rs:13:13 + --> $DIR/comparison_to_empty.rs:14:13 | LL | let _ = v != []; | ^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!v.is_empty()` diff --git a/tests/ui/crashes/auxiliary/proc_macro_crash.rs b/tests/ui/crashes/auxiliary/proc_macro_crash.rs index 66419656a327..5dffddc119aa 100644 --- a/tests/ui/crashes/auxiliary/proc_macro_crash.rs +++ b/tests/ui/crashes/auxiliary/proc_macro_crash.rs @@ -1,13 +1,5 @@ -//@compile-flags: --emit=link -//@no-prefer-dynamic -// ^ compiletest by default builds all aux files as dylibs, but we don't want that for proc-macro -// crates. If we don't set this, compiletest will override the `crate_type` attribute below and -// compile this as dylib. Removing this then causes the test to fail because a `dylib` crate can't -// contain a proc-macro. - #![feature(repr128)] #![allow(incomplete_features)] -#![crate_type = "proc-macro"] extern crate proc_macro; diff --git a/tests/ui/crashes/ice-10148.rs b/tests/ui/crashes/ice-10148.rs index c7f0224820ed..0df22f41374f 100644 --- a/tests/ui/crashes/ice-10148.rs +++ b/tests/ui/crashes/ice-10148.rs @@ -1,4 +1,4 @@ -//@aux-build:../../auxiliary/proc_macros.rs +//@aux-build:../auxiliary/proc_macros.rs:proc-macro extern crate proc_macros; diff --git a/tests/ui/crashes/ice-10645.rs b/tests/ui/crashes/ice-10645.rs index 4d8698d383ba..6e126aff7512 100644 --- a/tests/ui/crashes/ice-10645.rs +++ b/tests/ui/crashes/ice-10645.rs @@ -1,4 +1,4 @@ -// compile-flags: --cap-lints=warn +//@compile-flags: --cap-lints=warn // https://github.com/rust-lang/rust-clippy/issues/10645 #![warn(clippy::future_not_send)] diff --git a/tests/ui/crashes/ice-10645.stderr b/tests/ui/crashes/ice-10645.stderr index fc084e30d7fe..0055fe061e2a 100644 --- a/tests/ui/crashes/ice-10645.stderr +++ b/tests/ui/crashes/ice-10645.stderr @@ -1,4 +1,4 @@ -error: future cannot be sent between threads safely +warning: future cannot be sent between threads safely --> $DIR/ice-10645.rs:5:35 | LL | pub async fn bar<'a, T: 'a>(_: T) {} @@ -12,5 +12,5 @@ LL | pub async fn bar<'a, T: 'a>(_: T) {} = note: `T` doesn't implement `std::marker::Send` = note: `-D clippy::future-not-send` implied by `-D warnings` -error: aborting due to previous error +warning: 1 warning emitted diff --git a/tests/ui/crashes/ice-10912.rs b/tests/ui/crashes/ice-10912.rs new file mode 100644 index 000000000000..69d7f2f395ff --- /dev/null +++ b/tests/ui/crashes/ice-10912.rs @@ -0,0 +1,4 @@ +#![warn(clippy::unreadable_literal)] +fn f2() -> impl Sized { && 3.14159265358979323846E } + +fn main() {} diff --git a/tests/ui/crashes/ice-10912.stderr b/tests/ui/crashes/ice-10912.stderr new file mode 100644 index 000000000000..a74ce731577d --- /dev/null +++ b/tests/ui/crashes/ice-10912.stderr @@ -0,0 +1,16 @@ +error: expected at least one digit in exponent + --> $DIR/ice-10912.rs:2:28 + | +LL | fn f2() -> impl Sized { && 3.14159265358979323846E } + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: long literal lacking separators + --> $DIR/ice-10912.rs:2:28 + | +LL | fn f2() -> impl Sized { && 3.14159265358979323846E } + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider: `3.141_592_653_589_793_238_46` + | + = note: `-D clippy::unreadable-literal` implied by `-D warnings` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/crashes/ice-1782.rs b/tests/ui/crashes/ice-1782.rs index 81af88962a64..19ab03418eed 100644 --- a/tests/ui/crashes/ice-1782.rs +++ b/tests/ui/crashes/ice-1782.rs @@ -1,4 +1,5 @@ #![allow(dead_code, unused_variables)] +#![allow(clippy::unnecessary_cast)] /// Should not trigger an ICE in `SpanlessEq` / `consts::constant` /// diff --git a/tests/ui/crashes/ice-2774.stderr b/tests/ui/crashes/ice-2774.stderr index c5ea0b16d1be..a166ccb3ee8f 100644 --- a/tests/ui/crashes/ice-2774.stderr +++ b/tests/ui/crashes/ice-2774.stderr @@ -1,8 +1,8 @@ error: the following explicit lifetimes could be elided: 'a - --> $DIR/ice-2774.rs:15:1 + --> $DIR/ice-2774.rs:15:28 | LL | pub fn add_barfoos_to_foos<'a>(bars: &HashSet<&'a Bar>) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ | = note: `-D clippy::needless-lifetimes` implied by `-D warnings` help: elide the lifetimes diff --git a/tests/ui/crashes/ice-3462.rs b/tests/ui/crashes/ice-3462.rs index b402052882ad..21cd9d337cdd 100644 --- a/tests/ui/crashes/ice-3462.rs +++ b/tests/ui/crashes/ice-3462.rs @@ -1,5 +1,5 @@ #![warn(clippy::all)] -#![allow(clippy::disallowed_names, clippy::equatable_if_let)] +#![allow(clippy::disallowed_names, clippy::equatable_if_let, clippy::needless_if)] #![allow(unused)] /// Test for https://github.com/rust-lang/rust-clippy/issues/3462 diff --git a/tests/ui/crashes/ice-3741.rs b/tests/ui/crashes/ice-3741.rs index 3106a2e72169..268c5ba0ad0f 100644 --- a/tests/ui/crashes/ice-3741.rs +++ b/tests/ui/crashes/ice-3741.rs @@ -1,4 +1,4 @@ -//@aux-build:proc_macro_crash.rs +//@aux-build:proc_macro_crash.rs:proc-macro #![warn(clippy::suspicious_else_formatting)] diff --git a/tests/ui/crashes/ice-4968.rs b/tests/ui/crashes/ice-4968.rs index ac724ac93e3f..50473868005e 100644 --- a/tests/ui/crashes/ice-4968.rs +++ b/tests/ui/crashes/ice-4968.rs @@ -1,5 +1,3 @@ -//@check-pass - // Test for https://github.com/rust-lang/rust-clippy/issues/4968 #![warn(clippy::unsound_collection_transmute)] diff --git a/tests/ui/crashes/ice-5497.rs b/tests/ui/crashes/ice-5497.rs index 0769bce5fc80..f77f691c1927 100644 --- a/tests/ui/crashes/ice-5497.rs +++ b/tests/ui/crashes/ice-5497.rs @@ -7,5 +7,5 @@ pub trait Foo { impl Foo for Vec { const OOB: i32 = [1][1] + T::OOB; - //~^ ERROR operation will panic + //~^ ERROR: operation will panic } diff --git a/tests/ui/crashes/ice-5579.rs b/tests/ui/crashes/ice-5579.rs index e1842c73f0e3..8ab36bbf93cb 100644 --- a/tests/ui/crashes/ice-5579.rs +++ b/tests/ui/crashes/ice-5579.rs @@ -1,3 +1,5 @@ +#![allow(clippy::unnecessary_literal_unwrap)] + trait IsErr { fn is_err(&self, err: &str) -> bool; } diff --git a/tests/ui/crashes/ice-6250.stderr b/tests/ui/crashes/ice-6250.stderr index db34e6bfa7b2..97390af3e89e 100644 --- a/tests/ui/crashes/ice-6250.stderr +++ b/tests/ui/crashes/ice-6250.stderr @@ -1,9 +1,3 @@ -error[E0601]: `main` function not found in crate `ice_6250` - --> $DIR/ice-6250.rs:16:2 - | -LL | } - | ^ consider adding a `main` function to `$DIR/ice-6250.rs` - error[E0308]: mismatched types --> $DIR/ice-6250.rs:12:14 | @@ -24,7 +18,6 @@ help: consider adding `let` LL | let Some(reference) = cache.data.get(key) { | +++ -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0308, E0601. -For more information about an error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/crashes/ice-6251.stderr b/tests/ui/crashes/ice-6251.stderr index 8da2965c6351..68a5766c90c0 100644 --- a/tests/ui/crashes/ice-6251.stderr +++ b/tests/ui/crashes/ice-6251.stderr @@ -1,9 +1,3 @@ -error[E0601]: `main` function not found in crate `ice_6251` - --> $DIR/ice-6251.rs:6:2 - | -LL | } - | ^ consider adding a `main` function to `$DIR/ice-6251.rs` - error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> $DIR/ice-6251.rs:4:45 | @@ -35,7 +29,7 @@ LL | fn bug() -> impl Iterator { = note: expected type `usize` found closure `[closure@$DIR/ice-6251.rs:4:44: 4:53]` -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0277, E0308, E0601. +Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/crashes/ice-6255.rs b/tests/ui/crashes/ice-6255.rs index ccde6aa2b0f7..b6555ac5c407 100644 --- a/tests/ui/crashes/ice-6255.rs +++ b/tests/ui/crashes/ice-6255.rs @@ -4,7 +4,6 @@ macro_rules! define_other_core { ( ) => { extern crate std as core; - //~^ ERROR macro-expanded `extern crate` items cannot shadow names passed with `--extern` }; } @@ -13,3 +12,4 @@ fn main() { } define_other_core!(); +//~^ ERROR: macro-expanded `extern crate` items cannot shadow names passed with `--extern` diff --git a/tests/ui/crashes/ice-6256.rs b/tests/ui/crashes/ice-6256.rs index f9ee3e058c11..1d336b3cdc0c 100644 --- a/tests/ui/crashes/ice-6256.rs +++ b/tests/ui/crashes/ice-6256.rs @@ -10,6 +10,6 @@ impl dyn TT { #[rustfmt::skip] fn main() { - let f = |x: &dyn TT| x.func(); //[default]~ ERROR: mismatched types - //[nll]~^ ERROR: borrowed data escapes outside of closure + let f = |x: &dyn TT| x.func(); + //~^ ERROR: borrowed data escapes outside of closure } diff --git a/tests/ui/crashes/ice-6256.stderr b/tests/ui/crashes/ice-6256.stderr index 9cfcccf1e3cd..671933157c80 100644 --- a/tests/ui/crashes/ice-6256.stderr +++ b/tests/ui/crashes/ice-6256.stderr @@ -1,7 +1,7 @@ error[E0521]: borrowed data escapes outside of closure --> $DIR/ice-6256.rs:13:26 | -LL | let f = |x: &dyn TT| x.func(); //[default]~ ERROR: mismatched types +LL | let f = |x: &dyn TT| x.func(); | - - ^^^^^^^^ | | | | | | | `x` escapes the closure body here diff --git a/tests/ui/crashes/ice-7169.rs b/tests/ui/crashes/ice-7169.rs index 82095febc194..b203252f0a14 100644 --- a/tests/ui/crashes/ice-7169.rs +++ b/tests/ui/crashes/ice-7169.rs @@ -1,3 +1,5 @@ +#![allow(clippy::needless_if)] + #[derive(Default)] struct A { a: Vec>, diff --git a/tests/ui/crashes/ice-7169.stderr b/tests/ui/crashes/ice-7169.stderr index 5a9cd32380a1..84e0af3f0d0a 100644 --- a/tests/ui/crashes/ice-7169.stderr +++ b/tests/ui/crashes/ice-7169.stderr @@ -1,5 +1,5 @@ error: redundant pattern matching, consider using `is_ok()` - --> $DIR/ice-7169.rs:8:12 + --> $DIR/ice-7169.rs:10:12 | LL | if let Ok(_) = Ok::<_, ()>(A::::default()) {} | -------^^^^^-------------------------------------- help: try this: `if Ok::<_, ()>(A::::default()).is_ok()` diff --git a/tests/ui/crashes/ice-7410.rs b/tests/ui/crashes/ice-7410.rs index a5373cdcae12..a2683b3ce340 100644 --- a/tests/ui/crashes/ice-7410.rs +++ b/tests/ui/crashes/ice-7410.rs @@ -1,6 +1,6 @@ //@compile-flags: -Clink-arg=-nostartfiles -//@ignore-macos -//@ignore-windows +//@ignore-target-apple +//@ignore-target-windows #![feature(lang_items, start, libc)] #![no_std] diff --git a/tests/ui/crashes/ice-96721.rs b/tests/ui/crashes/ice-96721.rs index 4b3fb7640108..ca68ba3d03a5 100644 --- a/tests/ui/crashes/ice-96721.rs +++ b/tests/ui/crashes/ice-96721.rs @@ -4,7 +4,7 @@ macro_rules! foo { }; } -#[path = foo!()] //~ ERROR malformed `path` attribute +#[path = foo!()] //~ ERROR: malformed `path` attribute mod abc {} fn main() {} diff --git a/tests/ui/crashes/ice-96721.stderr b/tests/ui/crashes/ice-96721.stderr index 78c567b8e772..712bd14c685f 100644 --- a/tests/ui/crashes/ice-96721.stderr +++ b/tests/ui/crashes/ice-96721.stderr @@ -1,7 +1,7 @@ error: malformed `path` attribute input --> $DIR/ice-96721.rs:7:1 | -LL | #[path = foo!()] //~ ERROR malformed `path` attribute +LL | #[path = foo!()] | ^^^^^^^^^^^^^^^^ help: must be of the form: `#[path = "file"]` error: aborting due to previous error diff --git a/tests/ui/crashes/needless_lifetimes_impl_trait.stderr b/tests/ui/crashes/needless_lifetimes_impl_trait.stderr index 0b0e0ad2684a..37484f5ebd70 100644 --- a/tests/ui/crashes/needless_lifetimes_impl_trait.stderr +++ b/tests/ui/crashes/needless_lifetimes_impl_trait.stderr @@ -1,8 +1,8 @@ error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes_impl_trait.rs:15:5 + --> $DIR/needless_lifetimes_impl_trait.rs:15:12 | LL | fn baz<'a>(&'a self) -> impl Foo + 'a { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ ^^ | note: the lint level is defined here --> $DIR/needless_lifetimes_impl_trait.rs:1:9 diff --git a/tests/ui/crate_level_checks/entrypoint_recursion.rs b/tests/ui/crate_level_checks/entrypoint_recursion.rs index d6cd594d7c97..aa76688d8010 100644 --- a/tests/ui/crate_level_checks/entrypoint_recursion.rs +++ b/tests/ui/crate_level_checks/entrypoint_recursion.rs @@ -1,4 +1,4 @@ -//@ignore-macos +//@ignore-target-apple #![feature(rustc_attrs)] diff --git a/tests/ui/crate_level_checks/entrypoint_recursion.stderr b/tests/ui/crate_level_checks/entrypoint_recursion.stderr deleted file mode 100644 index 3d79a115cb30..000000000000 --- a/tests/ui/crate_level_checks/entrypoint_recursion.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error: recursing into entrypoint `a` - --> $DIR/entrypoint_recursion.rs:10:5 - | -LL | a(); - | ^ - | - = help: consider using another function for this recursion - = note: `-D clippy::main-recursion` implied by `-D warnings` - -error: aborting due to previous error - diff --git a/tests/ui/crate_level_checks/no_std_main_recursion.rs b/tests/ui/crate_level_checks/no_std_main_recursion.rs index a382135bb695..32eba9695920 100644 --- a/tests/ui/crate_level_checks/no_std_main_recursion.rs +++ b/tests/ui/crate_level_checks/no_std_main_recursion.rs @@ -1,5 +1,5 @@ //@compile-flags: -Clink-arg=-nostartfiles -//@ignore-macos +//@ignore-target-apple #![feature(lang_items, start, libc)] #![no_std] diff --git a/tests/ui/dbg_macro.rs b/tests/ui/dbg_macro.rs index 10788d404816..6c63c098916b 100644 --- a/tests/ui/dbg_macro.rs +++ b/tests/ui/dbg_macro.rs @@ -1,4 +1,3 @@ -//@compile-flags: --test #![warn(clippy::dbg_macro)] fn foo(n: u32) -> u32 { diff --git a/tests/ui/dbg_macro.stderr b/tests/ui/dbg_macro.stderr index 530e76633177..3d2926259590 100644 --- a/tests/ui/dbg_macro.stderr +++ b/tests/ui/dbg_macro.stderr @@ -1,5 +1,5 @@ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:5:22 + --> $DIR/dbg_macro.rs:4:22 | LL | if let Some(n) = dbg!(n.checked_sub(4)) { n } else { n } | ^^^^^^^^^^^^^^^^^^^^^^ @@ -11,7 +11,7 @@ LL | if let Some(n) = n.checked_sub(4) { n } else { n } | ~~~~~~~~~~~~~~~~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:10:8 + --> $DIR/dbg_macro.rs:9:8 | LL | if dbg!(n <= 1) { | ^^^^^^^^^^^^ @@ -22,7 +22,7 @@ LL | if n <= 1 { | ~~~~~~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:11:9 + --> $DIR/dbg_macro.rs:10:9 | LL | dbg!(1) | ^^^^^^^ @@ -33,7 +33,7 @@ LL | 1 | error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:13:9 + --> $DIR/dbg_macro.rs:12:9 | LL | dbg!(n * factorial(n - 1)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -44,7 +44,7 @@ LL | n * factorial(n - 1) | error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:18:5 + --> $DIR/dbg_macro.rs:17:5 | LL | dbg!(42); | ^^^^^^^^ @@ -55,7 +55,7 @@ LL | 42; | ~~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:19:5 + --> $DIR/dbg_macro.rs:18:5 | LL | dbg!(dbg!(dbg!(42))); | ^^^^^^^^^^^^^^^^^^^^ @@ -66,7 +66,7 @@ LL | dbg!(dbg!(42)); | ~~~~~~~~~~~~~~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:20:14 + --> $DIR/dbg_macro.rs:19:14 | LL | foo(3) + dbg!(factorial(4)); | ^^^^^^^^^^^^^^^^^^ @@ -77,7 +77,7 @@ LL | foo(3) + factorial(4); | ~~~~~~~~~~~~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:21:5 + --> $DIR/dbg_macro.rs:20:5 | LL | dbg!(1, 2, dbg!(3, 4)); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -88,7 +88,7 @@ LL | (1, 2, dbg!(3, 4)); | ~~~~~~~~~~~~~~~~~~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:22:5 + --> $DIR/dbg_macro.rs:21:5 | LL | dbg!(1, 2, 3, 4, 5); | ^^^^^^^^^^^^^^^^^^^ @@ -99,7 +99,7 @@ LL | (1, 2, 3, 4, 5); | ~~~~~~~~~~~~~~~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:42:5 + --> $DIR/dbg_macro.rs:41:5 | LL | dbg!(); | ^^^^^^^ @@ -111,7 +111,7 @@ LL + | error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:44:13 + --> $DIR/dbg_macro.rs:43:13 | LL | let _ = dbg!(); | ^^^^^^ @@ -122,7 +122,7 @@ LL | let _ = (); | ~~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:45:9 + --> $DIR/dbg_macro.rs:44:9 | LL | bar(dbg!()); | ^^^^^^ @@ -133,7 +133,7 @@ LL | bar(()); | ~~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:46:10 + --> $DIR/dbg_macro.rs:45:10 | LL | foo!(dbg!()); | ^^^^^^ @@ -144,7 +144,7 @@ LL | foo!(()); | ~~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:47:16 + --> $DIR/dbg_macro.rs:46:16 | LL | foo2!(foo!(dbg!())); | ^^^^^^ @@ -155,7 +155,7 @@ LL | foo2!(foo!(())); | ~~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:68:9 + --> $DIR/dbg_macro.rs:67:9 | LL | dbg!(2); | ^^^^^^^ @@ -166,7 +166,7 @@ LL | 2; | ~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:74:5 + --> $DIR/dbg_macro.rs:73:5 | LL | dbg!(1); | ^^^^^^^ @@ -177,7 +177,7 @@ LL | 1; | ~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:79:5 + --> $DIR/dbg_macro.rs:78:5 | LL | dbg!(1); | ^^^^^^^ @@ -188,7 +188,7 @@ LL | 1; | ~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:85:9 + --> $DIR/dbg_macro.rs:84:9 | LL | dbg!(1); | ^^^^^^^ diff --git a/tests/ui/declare_interior_mutable_const/enums.rs b/tests/ui/declare_interior_mutable_const/enums.rs index f44518694b89..a88bf7b21b8b 100644 --- a/tests/ui/declare_interior_mutable_const/enums.rs +++ b/tests/ui/declare_interior_mutable_const/enums.rs @@ -9,7 +9,7 @@ enum OptionalCell { } // a constant with enums should be linted only when the used variant is unfrozen (#3962). -const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); //~ ERROR interior mutable +const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); //~ ERROR: interior mutable const FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; const fn unfrozen_variant() -> OptionalCell { @@ -20,7 +20,7 @@ const fn frozen_variant() -> OptionalCell { OptionalCell::Frozen } -const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant(); //~ ERROR interior mutable +const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant(); //~ ERROR: interior mutable const FROZEN_VARIANT_FROM_FN: OptionalCell = frozen_variant(); enum NestedInnermost { @@ -43,10 +43,11 @@ struct NestedOutermost { // a constant with enums should be linted according to its value, no matter how structs involve. const NESTED_UNFROZEN_VARIANT: NestedOutermost = NestedOutermost { + //~^ ERROR: interior mutable outer: NestedOuter::NestedInner(NestedInner { inner: NestedInnermost::Unfrozen(AtomicUsize::new(2)), }), -}; //~ ERROR interior mutable +}; const NESTED_FROZEN_VARIANT: NestedOutermost = NestedOutermost { outer: NestedOuter::NestedInner(NestedInner { inner: NestedInnermost::Frozen, @@ -56,11 +57,11 @@ const NESTED_FROZEN_VARIANT: NestedOutermost = NestedOutermost { trait AssocConsts { // When there's no default value, lint it only according to its type. // Further details are on the corresponding code (`NonCopyConst::check_trait_item`). - const TO_BE_UNFROZEN_VARIANT: OptionalCell; //~ ERROR interior mutable - const TO_BE_FROZEN_VARIANT: OptionalCell; //~ ERROR interior mutable + const TO_BE_UNFROZEN_VARIANT: OptionalCell; //~ ERROR: interior mutable + const TO_BE_FROZEN_VARIANT: OptionalCell; //~ ERROR: interior mutable // Lint default values accordingly. - const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); //~ ERROR interior mutable + const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); //~ ERROR: interior mutable const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; } @@ -86,7 +87,7 @@ trait AssocTypes { impl AssocTypes for u64 { type ToBeUnfrozen = AtomicUsize; - const TO_BE_UNFROZEN_VARIANT: Option = Some(Self::ToBeUnfrozen::new(4)); //~ ERROR interior mutable + const TO_BE_UNFROZEN_VARIANT: Option = Some(Self::ToBeUnfrozen::new(4)); //~ ERROR: interior mutable const TO_BE_FROZEN_VARIANT: Option = None; } @@ -98,25 +99,25 @@ enum BothOfCellAndGeneric { } impl BothOfCellAndGeneric { - const UNFROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ ERROR interior mutable + const UNFROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ ERROR: interior mutable // This is a false positive. The argument about this is on `is_value_unfrozen_raw` - const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR interior mutable + const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR: interior mutable const FROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Frozen(5); // This is what is likely to be a false negative when one tries to fix // the `GENERIC_VARIANT` false positive. - const NO_ENUM: Cell<*const T> = Cell::new(std::ptr::null()); //~ ERROR interior mutable + const NO_ENUM: Cell<*const T> = Cell::new(std::ptr::null()); //~ ERROR: interior mutable } // associated types here is basically the same as the one above. trait BothOfCellAndGenericWithAssocType { type AssocType; - const UNFROZEN_VARIANT: BothOfCellAndGeneric = - BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ ERROR interior mutable - const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR interior mutable + const UNFROZEN_VARIANT: BothOfCellAndGeneric = //~ ERROR: interior mutable + BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); + const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR: interior mutable const FROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Frozen(5); } diff --git a/tests/ui/declare_interior_mutable_const/enums.stderr b/tests/ui/declare_interior_mutable_const/enums.stderr index 84198d546157..6070df749ca9 100644 --- a/tests/ui/declare_interior_mutable_const/enums.stderr +++ b/tests/ui/declare_interior_mutable_const/enums.stderr @@ -1,7 +1,7 @@ error: a `const` item should never be interior mutable --> $DIR/enums.rs:12:1 | -LL | const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); //~ ERROR interior mutable +LL | const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | make this a static item (maybe with lazy_static) @@ -11,7 +11,7 @@ LL | const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(tru error: a `const` item should never be interior mutable --> $DIR/enums.rs:23:1 | -LL | const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant(); //~ ERROR interior mutable +LL | const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant(); | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | make this a static item (maybe with lazy_static) @@ -24,65 +24,66 @@ LL | const NESTED_UNFROZEN_VARIANT: NestedOutermost = NestedOutermost { | | | _make this a static item (maybe with lazy_static) | | +LL | | LL | | outer: NestedOuter::NestedInner(NestedInner { LL | | inner: NestedInnermost::Unfrozen(AtomicUsize::new(2)), LL | | }), -LL | | }; //~ ERROR interior mutable +LL | | }; | |__^ -error: a `const` item should never be interior mutable - --> $DIR/enums.rs:59:5 - | -LL | const TO_BE_UNFROZEN_VARIANT: OptionalCell; //~ ERROR interior mutable - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error: a `const` item should never be interior mutable --> $DIR/enums.rs:60:5 | -LL | const TO_BE_FROZEN_VARIANT: OptionalCell; //~ ERROR interior mutable +LL | const TO_BE_UNFROZEN_VARIANT: OptionalCell; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a `const` item should never be interior mutable + --> $DIR/enums.rs:61:5 + | +LL | const TO_BE_FROZEN_VARIANT: OptionalCell; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> $DIR/enums.rs:63:5 + --> $DIR/enums.rs:64:5 | -LL | const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); //~ ERROR interior mutable +LL | const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> $DIR/enums.rs:89:5 + --> $DIR/enums.rs:90:5 | -LL | const TO_BE_UNFROZEN_VARIANT: Option = Some(Self::ToBeUnfrozen::new(4)); //~ ERROR interior mutable +LL | const TO_BE_UNFROZEN_VARIANT: Option = Some(Self::ToBeUnfrozen::new(4)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> $DIR/enums.rs:101:5 + --> $DIR/enums.rs:102:5 | -LL | const UNFROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ ERROR interior mut... +LL | const UNFROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> $DIR/enums.rs:104:5 + --> $DIR/enums.rs:105:5 | -LL | const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR interior mutable +LL | const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> $DIR/enums.rs:110:5 + --> $DIR/enums.rs:111:5 | -LL | const NO_ENUM: Cell<*const T> = Cell::new(std::ptr::null()); //~ ERROR interior mutable +LL | const NO_ENUM: Cell<*const T> = Cell::new(std::ptr::null()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> $DIR/enums.rs:117:5 + --> $DIR/enums.rs:118:5 | LL | / const UNFROZEN_VARIANT: BothOfCellAndGeneric = -LL | | BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ ERROR interior mutable +LL | | BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); | |____________________________________________________________________^ error: a `const` item should never be interior mutable - --> $DIR/enums.rs:119:5 + --> $DIR/enums.rs:120:5 | -LL | const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR interior mu... +LL | const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 12 previous errors diff --git a/tests/ui/declare_interior_mutable_const/others.rs b/tests/ui/declare_interior_mutable_const/others.rs index 896596b56792..1cec2980652c 100644 --- a/tests/ui/declare_interior_mutable_const/others.rs +++ b/tests/ui/declare_interior_mutable_const/others.rs @@ -6,17 +6,17 @@ use std::fmt::Display; use std::sync::atomic::AtomicUsize; use std::sync::Once; -const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR interior mutable -const CELL: Cell = Cell::new(6); //~ ERROR interior mutable +const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR: interior mutable +const CELL: Cell = Cell::new(6); //~ ERROR: interior mutable const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec, u8) = ([ATOMIC], Vec::new(), 7); -//~^ ERROR interior mutable +//~^ ERROR: interior mutable macro_rules! declare_const { ($name:ident: $ty:ty = $e:expr) => { const $name: $ty = $e; }; } -declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable +declare_const!(_ONCE: Once = Once::new()); //~ ERROR: interior mutable // const ATOMIC_REF: &AtomicUsize = &AtomicUsize::new(7); // This will simply trigger E0492. @@ -24,12 +24,12 @@ const INTEGER: u8 = 8; const STRING: String = String::new(); const STR: &str = "012345"; const COW: Cow = Cow::Borrowed("abcdef"); -//^ note: a const item of Cow is used in the `postgres` package. +// note: a const item of Cow is used in the `postgres` package. const NO_ANN: &dyn Display = &70; static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING); -//^ there should be no lints on this line +// there should be no lints on the line above line mod issue_8493 { use std::cell::Cell; @@ -40,7 +40,7 @@ mod issue_8493 { macro_rules! issue_8493 { () => { - const _BAZ: Cell = Cell::new(0); //~ ERROR interior mutable + const _BAZ: Cell = Cell::new(0); static _FOOBAR: () = { thread_local! { static _VAR: Cell = const { Cell::new(0) }; @@ -49,7 +49,7 @@ mod issue_8493 { }; } - issue_8493!(); + issue_8493!(); //~ ERROR: interior mutable } fn main() {} diff --git a/tests/ui/declare_interior_mutable_const/others.stderr b/tests/ui/declare_interior_mutable_const/others.stderr index 1fd6d7322a76..0259f6a4a286 100644 --- a/tests/ui/declare_interior_mutable_const/others.stderr +++ b/tests/ui/declare_interior_mutable_const/others.stderr @@ -1,7 +1,7 @@ error: a `const` item should never be interior mutable --> $DIR/others.rs:9:1 | -LL | const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR interior mutable +LL | const ATOMIC: AtomicUsize = AtomicUsize::new(5); | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | make this a static item (maybe with lazy_static) @@ -11,7 +11,7 @@ LL | const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR interior mutable error: a `const` item should never be interior mutable --> $DIR/others.rs:10:1 | -LL | const CELL: Cell = Cell::new(6); //~ ERROR interior mutable +LL | const CELL: Cell = Cell::new(6); | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | make this a static item (maybe with lazy_static) @@ -30,7 +30,7 @@ error: a `const` item should never be interior mutable LL | const $name: $ty = $e; | ^^^^^^^^^^^^^^^^^^^^^^ ... -LL | declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable +LL | declare_const!(_ONCE: Once = Once::new()); | ----------------------------------------- in this macro invocation | = note: this error originates in the macro `declare_const` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -38,7 +38,7 @@ LL | declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable error: a `const` item should never be interior mutable --> $DIR/others.rs:43:13 | -LL | const _BAZ: Cell = Cell::new(0); //~ ERROR interior mutable +LL | const _BAZ: Cell = Cell::new(0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | issue_8493!(); diff --git a/tests/ui/declare_interior_mutable_const/traits.rs b/tests/ui/declare_interior_mutable_const/traits.rs index 256a336db821..a6ccdd270798 100644 --- a/tests/ui/declare_interior_mutable_const/traits.rs +++ b/tests/ui/declare_interior_mutable_const/traits.rs @@ -12,10 +12,10 @@ macro_rules! declare_const { // a constant whose type is a concrete type should be linted at the definition site. trait ConcreteTypes { - const ATOMIC: AtomicUsize; //~ ERROR interior mutable + const ATOMIC: AtomicUsize; //~ ERROR: interior mutable const INTEGER: u64; const STRING: String; - declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); //~ ERROR interior mutable + declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); //~ ERROR: interior mutable } impl ConcreteTypes for u64 { @@ -40,7 +40,7 @@ trait GenericTypes { impl GenericTypes for u64 { const TO_REMAIN_GENERIC: T = T::DEFAULT; - const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11); //~ ERROR interior mutable + const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11); //~ ERROR: interior mutable } // a helper type used below @@ -65,8 +65,8 @@ impl AssocTypes for Vec { type ToBeGenericParam = T; const TO_BE_FROZEN: Self::ToBeFrozen = 12; - const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); //~ ERROR interior mutable - const WRAPPED_TO_BE_UNFROZEN: Wrapper = Wrapper(AtomicUsize::new(14)); //~ ERROR interior mutable + const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); //~ ERROR: interior mutable + const WRAPPED_TO_BE_UNFROZEN: Wrapper = Wrapper(AtomicUsize::new(14)); //~ ERROR: interior mutable const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper = Wrapper(T::DEFAULT); } @@ -85,7 +85,7 @@ where T: AssocTypesHelper, { const NOT_BOUNDED: T::NotToBeBounded; - const BOUNDED: T::ToBeBounded; //~ ERROR interior mutable + const BOUNDED: T::ToBeBounded; //~ ERROR: interior mutable } impl AssocTypesFromGenericParam for u64 @@ -113,8 +113,8 @@ impl SelfType for u64 { impl SelfType for AtomicUsize { // this (interior mutable `Self` const) exists in `parking_lot`. // `const_trait_impl` will replace it in the future, hopefully. - const SELF: Self = AtomicUsize::new(17); //~ ERROR interior mutable - const WRAPPED_SELF: Option = Some(AtomicUsize::new(21)); //~ ERROR interior mutable + const SELF: Self = AtomicUsize::new(17); //~ ERROR: interior mutable + const WRAPPED_SELF: Option = Some(AtomicUsize::new(21)); //~ ERROR: interior mutable } // Even though a constant contains a generic type, if it also have an interior mutable type, @@ -122,7 +122,7 @@ impl SelfType for AtomicUsize { trait BothOfCellAndGeneric { // this is a false negative in the current implementation. const DIRECT: Cell; - const INDIRECT: Cell<*const T>; //~ ERROR interior mutable + const INDIRECT: Cell<*const T>; //~ ERROR: interior mutable } impl BothOfCellAndGeneric for u64 { @@ -138,13 +138,13 @@ impl Local where T: ConstDefault + AssocTypesHelper, { - const ATOMIC: AtomicUsize = AtomicUsize::new(18); //~ ERROR interior mutable + const ATOMIC: AtomicUsize = AtomicUsize::new(18); //~ ERROR: interior mutable const COW: Cow<'static, str> = Cow::Borrowed("tuvwxy"); const GENERIC_TYPE: T = T::DEFAULT; const ASSOC_TYPE: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED; - const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); //~ ERROR interior mutable + const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); //~ ERROR: interior mutable } fn main() {} diff --git a/tests/ui/declare_interior_mutable_const/traits.stderr b/tests/ui/declare_interior_mutable_const/traits.stderr index 7debe059ff4e..ef62919dfead 100644 --- a/tests/ui/declare_interior_mutable_const/traits.stderr +++ b/tests/ui/declare_interior_mutable_const/traits.stderr @@ -1,7 +1,7 @@ error: a `const` item should never be interior mutable --> $DIR/traits.rs:15:5 | -LL | const ATOMIC: AtomicUsize; //~ ERROR interior mutable +LL | const ATOMIC: AtomicUsize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` @@ -12,7 +12,7 @@ error: a `const` item should never be interior mutable LL | const $name: $ty = $e; | ^^^^^^^^^^^^^^^^^^^^^^ ... -LL | declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); //~ ERROR interior mutable +LL | declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); | ---------------------------------------------------------- in this macro invocation | = note: this error originates in the macro `declare_const` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -20,55 +20,55 @@ LL | declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); //~ ERROR i error: a `const` item should never be interior mutable --> $DIR/traits.rs:43:5 | -LL | const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11); //~ ERROR interior mutable +LL | const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable --> $DIR/traits.rs:68:5 | -LL | const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); //~ ERROR interior mutable +LL | const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable --> $DIR/traits.rs:69:5 | -LL | const WRAPPED_TO_BE_UNFROZEN: Wrapper = Wrapper(AtomicUsize::new(14)); //~ ERROR interior mutable +LL | const WRAPPED_TO_BE_UNFROZEN: Wrapper = Wrapper(AtomicUsize::new(14)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable --> $DIR/traits.rs:88:5 | -LL | const BOUNDED: T::ToBeBounded; //~ ERROR interior mutable +LL | const BOUNDED: T::ToBeBounded; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable --> $DIR/traits.rs:116:5 | -LL | const SELF: Self = AtomicUsize::new(17); //~ ERROR interior mutable +LL | const SELF: Self = AtomicUsize::new(17); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable --> $DIR/traits.rs:117:5 | -LL | const WRAPPED_SELF: Option = Some(AtomicUsize::new(21)); //~ ERROR interior mutable +LL | const WRAPPED_SELF: Option = Some(AtomicUsize::new(21)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable --> $DIR/traits.rs:125:5 | -LL | const INDIRECT: Cell<*const T>; //~ ERROR interior mutable +LL | const INDIRECT: Cell<*const T>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable --> $DIR/traits.rs:141:5 | -LL | const ATOMIC: AtomicUsize = AtomicUsize::new(18); //~ ERROR interior mutable +LL | const ATOMIC: AtomicUsize = AtomicUsize::new(18); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable --> $DIR/traits.rs:147:5 | -LL | const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); //~ ERROR interior mutable +LL | const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 11 previous errors diff --git a/tests/ui/def_id_nocore.rs b/tests/ui/def_id_nocore.rs index f7819068ac5a..da0816830b85 100644 --- a/tests/ui/def_id_nocore.rs +++ b/tests/ui/def_id_nocore.rs @@ -1,4 +1,4 @@ -//@ignore-macos +//@ignore-target-apple #![feature(no_core, lang_items, start)] #![no_core] diff --git a/tests/ui/default_numeric_fallback_f64.fixed b/tests/ui/default_numeric_fallback_f64.fixed index 9520efe6329b..02eb78060130 100644 --- a/tests/ui/default_numeric_fallback_f64.fixed +++ b/tests/ui/default_numeric_fallback_f64.fixed @@ -1,5 +1,5 @@ //@run-rustfix -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![warn(clippy::default_numeric_fallback)] #![allow( diff --git a/tests/ui/default_numeric_fallback_f64.rs b/tests/ui/default_numeric_fallback_f64.rs index cacbdb4a95bf..79a9669833fa 100644 --- a/tests/ui/default_numeric_fallback_f64.rs +++ b/tests/ui/default_numeric_fallback_f64.rs @@ -1,5 +1,5 @@ //@run-rustfix -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![warn(clippy::default_numeric_fallback)] #![allow( diff --git a/tests/ui/default_numeric_fallback_i32.fixed b/tests/ui/default_numeric_fallback_i32.fixed index fbabb8bcf8e3..23272d07eec6 100644 --- a/tests/ui/default_numeric_fallback_i32.fixed +++ b/tests/ui/default_numeric_fallback_i32.fixed @@ -1,5 +1,5 @@ //@run-rustfix -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![feature(lint_reasons)] #![warn(clippy::default_numeric_fallback)] diff --git a/tests/ui/default_numeric_fallback_i32.rs b/tests/ui/default_numeric_fallback_i32.rs index 7bfc390e4bfa..fb149141609d 100644 --- a/tests/ui/default_numeric_fallback_i32.rs +++ b/tests/ui/default_numeric_fallback_i32.rs @@ -1,5 +1,5 @@ //@run-rustfix -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![feature(lint_reasons)] #![warn(clippy::default_numeric_fallback)] diff --git a/tests/ui/default_trait_access.fixed b/tests/ui/default_trait_access.fixed index bf5dca976416..14eb6d572cfa 100644 --- a/tests/ui/default_trait_access.fixed +++ b/tests/ui/default_trait_access.fixed @@ -1,5 +1,5 @@ //@run-rustfix -//@aux-build: proc_macros.rs +//@aux-build: proc_macros.rs:proc-macro #![deny(clippy::default_trait_access)] #![allow(dead_code, unused_imports)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/default_trait_access.rs b/tests/ui/default_trait_access.rs index 5e8e9ce85b1c..aa2ced0a7f03 100644 --- a/tests/ui/default_trait_access.rs +++ b/tests/ui/default_trait_access.rs @@ -1,5 +1,5 @@ //@run-rustfix -//@aux-build: proc_macros.rs +//@aux-build: proc_macros.rs:proc-macro #![deny(clippy::default_trait_access)] #![allow(dead_code, unused_imports)] #![allow(clippy::uninlined_format_args)] diff --git a/tests/ui/deref_addrof.fixed b/tests/ui/deref_addrof.fixed index b27d3bc10028..0ecca1b8ffaa 100644 --- a/tests/ui/deref_addrof.fixed +++ b/tests/ui/deref_addrof.fixed @@ -1,7 +1,7 @@ //@run-rustfix -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro -#![allow(clippy::return_self_not_must_use)] +#![allow(clippy::return_self_not_must_use, clippy::useless_vec)] #![warn(clippy::deref_addrof)] extern crate proc_macros; diff --git a/tests/ui/deref_addrof.rs b/tests/ui/deref_addrof.rs index 825090c7c122..9f91310e61f3 100644 --- a/tests/ui/deref_addrof.rs +++ b/tests/ui/deref_addrof.rs @@ -1,7 +1,7 @@ //@run-rustfix -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro -#![allow(clippy::return_self_not_must_use)] +#![allow(clippy::return_self_not_must_use, clippy::useless_vec)] #![warn(clippy::deref_addrof)] extern crate proc_macros; diff --git a/tests/ui/deref_addrof_macro.rs b/tests/ui/deref_addrof_macro.rs index c7e60f365060..ce4b94a73bd2 100644 --- a/tests/ui/deref_addrof_macro.rs +++ b/tests/ui/deref_addrof_macro.rs @@ -1,4 +1,4 @@ -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![warn(clippy::deref_addrof)] diff --git a/tests/ui/derivable_impls.fixed b/tests/ui/derivable_impls.fixed index aa0efb85c297..a10f3d010707 100644 --- a/tests/ui/derivable_impls.fixed +++ b/tests/ui/derivable_impls.fixed @@ -268,4 +268,25 @@ impl Default for OtherGenericType { } } +mod issue10158 { + pub trait T {} + + #[derive(Default)] + pub struct S {} + impl T for S {} + + pub struct Outer { + pub inner: Box, + } + + impl Default for Outer { + fn default() -> Self { + Outer { + // Box::::default() adjusts to Box + inner: Box::::default(), + } + } + } +} + fn main() {} diff --git a/tests/ui/derivable_impls.rs b/tests/ui/derivable_impls.rs index 8dc999ad5860..18cef1c5be89 100644 --- a/tests/ui/derivable_impls.rs +++ b/tests/ui/derivable_impls.rs @@ -304,4 +304,25 @@ impl Default for OtherGenericType { } } +mod issue10158 { + pub trait T {} + + #[derive(Default)] + pub struct S {} + impl T for S {} + + pub struct Outer { + pub inner: Box, + } + + impl Default for Outer { + fn default() -> Self { + Outer { + // Box::::default() adjusts to Box + inner: Box::::default(), + } + } + } +} + fn main() {} diff --git a/tests/ui/derive.rs b/tests/ui/derive.rs index 6e0ce55f57d9..e01079bc977b 100644 --- a/tests/ui/derive.rs +++ b/tests/ui/derive.rs @@ -1,4 +1,4 @@ -#![allow(dead_code)] +#![allow(clippy::incorrect_clone_impl_on_copy_type, dead_code)] #![warn(clippy::expl_impl_clone_on_copy)] diff --git a/tests/ui/disallowed_names.rs b/tests/ui/disallowed_names.rs index e937c49f3897..5889f04439ff 100644 --- a/tests/ui/disallowed_names.rs +++ b/tests/ui/disallowed_names.rs @@ -1,5 +1,6 @@ #![allow( dead_code, + clippy::needless_if, clippy::similar_names, clippy::single_match, clippy::toplevel_ref_arg, diff --git a/tests/ui/disallowed_names.stderr b/tests/ui/disallowed_names.stderr index 78cb55096ff0..9ab68b641f13 100644 --- a/tests/ui/disallowed_names.stderr +++ b/tests/ui/disallowed_names.stderr @@ -1,5 +1,5 @@ error: use of a disallowed/placeholder name `foo` - --> $DIR/disallowed_names.rs:11:9 + --> $DIR/disallowed_names.rs:12:9 | LL | fn test(foo: ()) {} | ^^^ @@ -7,79 +7,79 @@ LL | fn test(foo: ()) {} = note: `-D clippy::disallowed-names` implied by `-D warnings` error: use of a disallowed/placeholder name `foo` - --> $DIR/disallowed_names.rs:14:9 + --> $DIR/disallowed_names.rs:15:9 | LL | let foo = 42; | ^^^ error: use of a disallowed/placeholder name `baz` - --> $DIR/disallowed_names.rs:15:9 + --> $DIR/disallowed_names.rs:16:9 | LL | let baz = 42; | ^^^ error: use of a disallowed/placeholder name `quux` - --> $DIR/disallowed_names.rs:16:9 + --> $DIR/disallowed_names.rs:17:9 | LL | let quux = 42; | ^^^^ error: use of a disallowed/placeholder name `foo` - --> $DIR/disallowed_names.rs:27:10 + --> $DIR/disallowed_names.rs:28:10 | LL | (foo, Some(baz), quux @ Some(_)) => (), | ^^^ error: use of a disallowed/placeholder name `baz` - --> $DIR/disallowed_names.rs:27:20 + --> $DIR/disallowed_names.rs:28:20 | LL | (foo, Some(baz), quux @ Some(_)) => (), | ^^^ error: use of a disallowed/placeholder name `quux` - --> $DIR/disallowed_names.rs:27:26 + --> $DIR/disallowed_names.rs:28:26 | LL | (foo, Some(baz), quux @ Some(_)) => (), | ^^^^ error: use of a disallowed/placeholder name `foo` - --> $DIR/disallowed_names.rs:32:19 + --> $DIR/disallowed_names.rs:33:19 | LL | fn issue_1647(mut foo: u8) { | ^^^ error: use of a disallowed/placeholder name `baz` - --> $DIR/disallowed_names.rs:33:13 + --> $DIR/disallowed_names.rs:34:13 | LL | let mut baz = 0; | ^^^ error: use of a disallowed/placeholder name `quux` - --> $DIR/disallowed_names.rs:34:21 + --> $DIR/disallowed_names.rs:35:21 | LL | if let Some(mut quux) = Some(42) {} | ^^^^ error: use of a disallowed/placeholder name `baz` - --> $DIR/disallowed_names.rs:38:13 + --> $DIR/disallowed_names.rs:39:13 | LL | let ref baz = 0; | ^^^ error: use of a disallowed/placeholder name `quux` - --> $DIR/disallowed_names.rs:39:21 + --> $DIR/disallowed_names.rs:40:21 | LL | if let Some(ref quux) = Some(42) {} | ^^^^ error: use of a disallowed/placeholder name `baz` - --> $DIR/disallowed_names.rs:43:17 + --> $DIR/disallowed_names.rs:44:17 | LL | let ref mut baz = 0; | ^^^ error: use of a disallowed/placeholder name `quux` - --> $DIR/disallowed_names.rs:44:25 + --> $DIR/disallowed_names.rs:45:25 | LL | if let Some(ref mut quux) = Some(42) {} | ^^^^ diff --git a/tests/ui/diverging_sub_expression.rs b/tests/ui/diverging_sub_expression.rs index e8f992e6dded..9b1619baf0e6 100644 --- a/tests/ui/diverging_sub_expression.rs +++ b/tests/ui/diverging_sub_expression.rs @@ -1,5 +1,6 @@ #![warn(clippy::diverging_sub_expression)] #![allow(clippy::match_same_arms, clippy::overly_complex_bool_expr)] +#![allow(clippy::nonminimal_bool)] #[allow(clippy::empty_loop)] fn diverge() -> ! { loop {} @@ -21,6 +22,7 @@ fn main() { } #[allow(dead_code, unused_variables)] +#[rustfmt::skip] fn foobar() { loop { let x = match 5 { @@ -35,6 +37,20 @@ fn foobar() { 99 => return, _ => true || panic!("boo"), }, + // lint blocks as well + 15 => true || { return; }, + 16 => false || { return; }, + // ... and when it's a single expression + 17 => true || { return }, + 18 => false || { return }, + // ... but not when there's both an expression and a statement + 19 => true || { _ = 1; return }, + 20 => false || { _ = 1; return }, + // ... or multiple statements + 21 => true || { _ = 1; return; }, + 22 => false || { _ = 1; return; }, + 23 => true || { return; true }, + 24 => true || { return; true }, _ => true || break, }; } diff --git a/tests/ui/diverging_sub_expression.stderr b/tests/ui/diverging_sub_expression.stderr index 51a3b0d972e6..243a5cf5369a 100644 --- a/tests/ui/diverging_sub_expression.stderr +++ b/tests/ui/diverging_sub_expression.stderr @@ -1,5 +1,5 @@ error: sub-expression diverges - --> $DIR/diverging_sub_expression.rs:19:10 + --> $DIR/diverging_sub_expression.rs:20:10 | LL | b || diverge(); | ^^^^^^^^^ @@ -7,34 +7,66 @@ LL | b || diverge(); = note: `-D clippy::diverging-sub-expression` implied by `-D warnings` error: sub-expression diverges - --> $DIR/diverging_sub_expression.rs:20:10 + --> $DIR/diverging_sub_expression.rs:21:10 | LL | b || A.foo(); | ^^^^^^^ error: sub-expression diverges - --> $DIR/diverging_sub_expression.rs:29:26 + --> $DIR/diverging_sub_expression.rs:31:26 | LL | 6 => true || return, | ^^^^^^ error: sub-expression diverges - --> $DIR/diverging_sub_expression.rs:30:26 + --> $DIR/diverging_sub_expression.rs:32:26 | LL | 7 => true || continue, | ^^^^^^^^ error: sub-expression diverges - --> $DIR/diverging_sub_expression.rs:33:26 + --> $DIR/diverging_sub_expression.rs:35:26 | LL | 3 => true || diverge(), | ^^^^^^^^^ error: sub-expression diverges - --> $DIR/diverging_sub_expression.rs:38:26 + --> $DIR/diverging_sub_expression.rs:38:30 + | +LL | _ => true || panic!("boo"), + | ^^^^^^^^^^^^^ + | + = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: sub-expression diverges + --> $DIR/diverging_sub_expression.rs:41:29 + | +LL | 15 => true || { return; }, + | ^^^^^^ + +error: sub-expression diverges + --> $DIR/diverging_sub_expression.rs:42:30 + | +LL | 16 => false || { return; }, + | ^^^^^^ + +error: sub-expression diverges + --> $DIR/diverging_sub_expression.rs:44:29 + | +LL | 17 => true || { return }, + | ^^^^^^ + +error: sub-expression diverges + --> $DIR/diverging_sub_expression.rs:45:30 + | +LL | 18 => false || { return }, + | ^^^^^^ + +error: sub-expression diverges + --> $DIR/diverging_sub_expression.rs:54:26 | LL | _ => true || break, | ^^^^^ -error: aborting due to 6 previous errors +error: aborting due to 11 previous errors diff --git a/tests/ui/doc/doc-fixable.fixed b/tests/ui/doc/doc-fixable.fixed index d3aa2816cb6d..14444df4c10e 100644 --- a/tests/ui/doc/doc-fixable.fixed +++ b/tests/ui/doc/doc-fixable.fixed @@ -60,6 +60,7 @@ fn test_units() { /// GitHub GitLab /// IPv4 IPv6 /// ClojureScript CoffeeScript JavaScript PureScript TypeScript +/// WebAssembly /// NaN NaNs /// OAuth GraphQL /// OCaml diff --git a/tests/ui/doc/doc-fixable.rs b/tests/ui/doc/doc-fixable.rs index d1e7d8017d7d..542d33b13a4c 100644 --- a/tests/ui/doc/doc-fixable.rs +++ b/tests/ui/doc/doc-fixable.rs @@ -60,6 +60,7 @@ fn test_units() { /// GitHub GitLab /// IPv4 IPv6 /// ClojureScript CoffeeScript JavaScript PureScript TypeScript +/// WebAssembly /// NaN NaNs /// OAuth GraphQL /// OCaml diff --git a/tests/ui/doc/doc-fixable.stderr b/tests/ui/doc/doc-fixable.stderr index 6c67c903c750..94ef43afc08f 100644 --- a/tests/ui/doc/doc-fixable.stderr +++ b/tests/ui/doc/doc-fixable.stderr @@ -132,7 +132,7 @@ LL | /// `be_sure_we_got_to_the_end_of_it` | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: item in documentation is missing backticks - --> $DIR/doc-fixable.rs:74:5 + --> $DIR/doc-fixable.rs:75:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -143,7 +143,7 @@ LL | /// `be_sure_we_got_to_the_end_of_it` | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: item in documentation is missing backticks - --> $DIR/doc-fixable.rs:91:5 + --> $DIR/doc-fixable.rs:92:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -154,7 +154,7 @@ LL | /// `be_sure_we_got_to_the_end_of_it` | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: item in documentation is missing backticks - --> $DIR/doc-fixable.rs:99:8 + --> $DIR/doc-fixable.rs:100:8 | LL | /// ## CamelCaseThing | ^^^^^^^^^^^^^^ @@ -165,7 +165,7 @@ LL | /// ## `CamelCaseThing` | ~~~~~~~~~~~~~~~~ error: item in documentation is missing backticks - --> $DIR/doc-fixable.rs:102:7 + --> $DIR/doc-fixable.rs:103:7 | LL | /// # CamelCaseThing | ^^^^^^^^^^^^^^ @@ -176,7 +176,7 @@ LL | /// # `CamelCaseThing` | ~~~~~~~~~~~~~~~~ error: item in documentation is missing backticks - --> $DIR/doc-fixable.rs:104:22 + --> $DIR/doc-fixable.rs:105:22 | LL | /// Not a title #897 CamelCaseThing | ^^^^^^^^^^^^^^ @@ -187,7 +187,7 @@ LL | /// Not a title #897 `CamelCaseThing` | ~~~~~~~~~~~~~~~~ error: item in documentation is missing backticks - --> $DIR/doc-fixable.rs:105:5 + --> $DIR/doc-fixable.rs:106:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -198,7 +198,7 @@ LL | /// `be_sure_we_got_to_the_end_of_it` | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: item in documentation is missing backticks - --> $DIR/doc-fixable.rs:112:5 + --> $DIR/doc-fixable.rs:113:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -209,7 +209,7 @@ LL | /// `be_sure_we_got_to_the_end_of_it` | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: item in documentation is missing backticks - --> $DIR/doc-fixable.rs:125:5 + --> $DIR/doc-fixable.rs:126:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -220,7 +220,7 @@ LL | /// `be_sure_we_got_to_the_end_of_it` | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: item in documentation is missing backticks - --> $DIR/doc-fixable.rs:136:43 + --> $DIR/doc-fixable.rs:137:43 | LL | /** E.g., serialization of an empty list: FooBar | ^^^^^^ @@ -231,7 +231,7 @@ LL | /** E.g., serialization of an empty list: `FooBar` | ~~~~~~~~ error: item in documentation is missing backticks - --> $DIR/doc-fixable.rs:141:5 + --> $DIR/doc-fixable.rs:142:5 | LL | And BarQuz too. | ^^^^^^ @@ -242,7 +242,7 @@ LL | And `BarQuz` too. | ~~~~~~~~ error: item in documentation is missing backticks - --> $DIR/doc-fixable.rs:142:1 + --> $DIR/doc-fixable.rs:143:1 | LL | be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -253,7 +253,7 @@ LL | `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> $DIR/doc-fixable.rs:147:43 + --> $DIR/doc-fixable.rs:148:43 | LL | /** E.g., serialization of an empty list: FooBar | ^^^^^^ @@ -264,7 +264,7 @@ LL | /** E.g., serialization of an empty list: `FooBar` | ~~~~~~~~ error: item in documentation is missing backticks - --> $DIR/doc-fixable.rs:152:5 + --> $DIR/doc-fixable.rs:153:5 | LL | And BarQuz too. | ^^^^^^ @@ -275,7 +275,7 @@ LL | And `BarQuz` too. | ~~~~~~~~ error: item in documentation is missing backticks - --> $DIR/doc-fixable.rs:153:1 + --> $DIR/doc-fixable.rs:154:1 | LL | be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -286,7 +286,7 @@ LL | `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> $DIR/doc-fixable.rs:164:5 + --> $DIR/doc-fixable.rs:165:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -297,7 +297,7 @@ LL | /// `be_sure_we_got_to_the_end_of_it` | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: item in documentation is missing backticks - --> $DIR/doc-fixable.rs:183:22 + --> $DIR/doc-fixable.rs:184:22 | LL | /// An iterator over mycrate::Collection's values. | ^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/doc/needless_doctest_main.rs b/tests/ui/doc/needless_doctest_main.rs new file mode 100644 index 000000000000..f1a2c0575ee5 --- /dev/null +++ b/tests/ui/doc/needless_doctest_main.rs @@ -0,0 +1,20 @@ +#![warn(clippy::needless_doctest_main)] +//! issue 10491: +//! ```rust,no_test +//! use std::collections::HashMap; +//! +//! fn main() { +//! let mut m = HashMap::new(); +//! m.insert(1u32, 2u32); +//! } +//! ``` + +/// some description here +/// ```rust,no_test +/// fn main() { +/// foo() +/// } +/// ``` +fn foo() {} + +fn main() {} diff --git a/tests/ui/doc_unsafe.rs b/tests/ui/doc_unsafe.rs index 0c8eac5ccffc..d21b046f167e 100644 --- a/tests/ui/doc_unsafe.rs +++ b/tests/ui/doc_unsafe.rs @@ -1,4 +1,4 @@ -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![allow(clippy::let_unit_value)] diff --git a/tests/ui/double_comparison.fixed b/tests/ui/double_comparison.fixed index c80ff671a5db..f8ca92ef0b34 100644 --- a/tests/ui/double_comparison.fixed +++ b/tests/ui/double_comparison.fixed @@ -1,4 +1,5 @@ //@run-rustfix +#![allow(clippy::needless_if)] fn main() { let x = 1; diff --git a/tests/ui/double_comparison.rs b/tests/ui/double_comparison.rs index bc78694aa680..47ff87bea0ab 100644 --- a/tests/ui/double_comparison.rs +++ b/tests/ui/double_comparison.rs @@ -1,4 +1,5 @@ //@run-rustfix +#![allow(clippy::needless_if)] fn main() { let x = 1; diff --git a/tests/ui/double_comparison.stderr b/tests/ui/double_comparison.stderr index 05ef4e25f7f8..4df1c28ac487 100644 --- a/tests/ui/double_comparison.stderr +++ b/tests/ui/double_comparison.stderr @@ -1,5 +1,5 @@ error: this binary expression can be simplified - --> $DIR/double_comparison.rs:6:8 + --> $DIR/double_comparison.rs:7:8 | LL | if x == y || x < y { | ^^^^^^^^^^^^^^^ help: try: `x <= y` @@ -7,43 +7,43 @@ LL | if x == y || x < y { = note: `-D clippy::double-comparisons` implied by `-D warnings` error: this binary expression can be simplified - --> $DIR/double_comparison.rs:9:8 + --> $DIR/double_comparison.rs:10:8 | LL | if x < y || x == y { | ^^^^^^^^^^^^^^^ help: try: `x <= y` error: this binary expression can be simplified - --> $DIR/double_comparison.rs:12:8 + --> $DIR/double_comparison.rs:13:8 | LL | if x == y || x > y { | ^^^^^^^^^^^^^^^ help: try: `x >= y` error: this binary expression can be simplified - --> $DIR/double_comparison.rs:15:8 + --> $DIR/double_comparison.rs:16:8 | LL | if x > y || x == y { | ^^^^^^^^^^^^^^^ help: try: `x >= y` error: this binary expression can be simplified - --> $DIR/double_comparison.rs:18:8 + --> $DIR/double_comparison.rs:19:8 | LL | if x < y || x > y { | ^^^^^^^^^^^^^^ help: try: `x != y` error: this binary expression can be simplified - --> $DIR/double_comparison.rs:21:8 + --> $DIR/double_comparison.rs:22:8 | LL | if x > y || x < y { | ^^^^^^^^^^^^^^ help: try: `x != y` error: this binary expression can be simplified - --> $DIR/double_comparison.rs:24:8 + --> $DIR/double_comparison.rs:25:8 | LL | if x <= y && x >= y { | ^^^^^^^^^^^^^^^^ help: try: `x == y` error: this binary expression can be simplified - --> $DIR/double_comparison.rs:27:8 + --> $DIR/double_comparison.rs:28:8 | LL | if x >= y && x <= y { | ^^^^^^^^^^^^^^^^ help: try: `x == y` diff --git a/tests/ui/drain_collect.fixed b/tests/ui/drain_collect.fixed new file mode 100644 index 000000000000..11001bd319f3 --- /dev/null +++ b/tests/ui/drain_collect.fixed @@ -0,0 +1,77 @@ +//@run-rustfix + +#![deny(clippy::drain_collect)] +#![allow(dead_code)] + +use std::collections::{BinaryHeap, HashMap, HashSet, VecDeque}; + +fn binaryheap(b: &mut BinaryHeap) -> BinaryHeap { + std::mem::take(b) +} + +fn binaryheap_dont_lint(b: &mut BinaryHeap) -> HashSet { + b.drain().collect() +} + +fn hashmap(b: &mut HashMap) -> HashMap { + std::mem::take(b) +} + +fn hashmap_dont_lint(b: &mut HashMap) -> Vec<(i32, i32)> { + b.drain().collect() +} + +fn hashset(b: &mut HashSet) -> HashSet { + std::mem::take(b) +} + +fn hashset_dont_lint(b: &mut HashSet) -> Vec { + b.drain().collect() +} + +fn vecdeque(b: &mut VecDeque) -> VecDeque { + std::mem::take(b) +} + +fn vecdeque_dont_lint(b: &mut VecDeque) -> HashSet { + b.drain(..).collect() +} + +fn vec(b: &mut Vec) -> Vec { + std::mem::take(b) +} + +fn vec2(b: &mut Vec) -> Vec { + std::mem::take(b) +} + +fn vec3(b: &mut Vec) -> Vec { + std::mem::take(b) +} + +fn vec4(b: &mut Vec) -> Vec { + std::mem::take(b) +} + +fn vec_no_reborrow() -> Vec { + let mut b = vec![1, 2, 3]; + std::mem::take(&mut b) +} + +fn vec_dont_lint(b: &mut Vec) -> HashSet { + b.drain(..).collect() +} + +fn string(b: &mut String) -> String { + std::mem::take(b) +} + +fn string_dont_lint(b: &mut String) -> HashSet { + b.drain(..).collect() +} + +fn not_whole_length(v: &mut Vec) -> Vec { + v.drain(1..).collect() +} + +fn main() {} diff --git a/tests/ui/drain_collect.rs b/tests/ui/drain_collect.rs new file mode 100644 index 000000000000..373a3ca3506d --- /dev/null +++ b/tests/ui/drain_collect.rs @@ -0,0 +1,77 @@ +//@run-rustfix + +#![deny(clippy::drain_collect)] +#![allow(dead_code)] + +use std::collections::{BinaryHeap, HashMap, HashSet, VecDeque}; + +fn binaryheap(b: &mut BinaryHeap) -> BinaryHeap { + b.drain().collect() +} + +fn binaryheap_dont_lint(b: &mut BinaryHeap) -> HashSet { + b.drain().collect() +} + +fn hashmap(b: &mut HashMap) -> HashMap { + b.drain().collect() +} + +fn hashmap_dont_lint(b: &mut HashMap) -> Vec<(i32, i32)> { + b.drain().collect() +} + +fn hashset(b: &mut HashSet) -> HashSet { + b.drain().collect() +} + +fn hashset_dont_lint(b: &mut HashSet) -> Vec { + b.drain().collect() +} + +fn vecdeque(b: &mut VecDeque) -> VecDeque { + b.drain(..).collect() +} + +fn vecdeque_dont_lint(b: &mut VecDeque) -> HashSet { + b.drain(..).collect() +} + +fn vec(b: &mut Vec) -> Vec { + b.drain(..).collect() +} + +fn vec2(b: &mut Vec) -> Vec { + b.drain(0..).collect() +} + +fn vec3(b: &mut Vec) -> Vec { + b.drain(..b.len()).collect() +} + +fn vec4(b: &mut Vec) -> Vec { + b.drain(0..b.len()).collect() +} + +fn vec_no_reborrow() -> Vec { + let mut b = vec![1, 2, 3]; + b.drain(..).collect() +} + +fn vec_dont_lint(b: &mut Vec) -> HashSet { + b.drain(..).collect() +} + +fn string(b: &mut String) -> String { + b.drain(..).collect() +} + +fn string_dont_lint(b: &mut String) -> HashSet { + b.drain(..).collect() +} + +fn not_whole_length(v: &mut Vec) -> Vec { + v.drain(1..).collect() +} + +fn main() {} diff --git a/tests/ui/drain_collect.stderr b/tests/ui/drain_collect.stderr new file mode 100644 index 000000000000..0792f0254cb5 --- /dev/null +++ b/tests/ui/drain_collect.stderr @@ -0,0 +1,68 @@ +error: you seem to be trying to move all elements into a new `BinaryHeap` + --> $DIR/drain_collect.rs:9:5 + | +LL | b.drain().collect() + | ^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` + | +note: the lint level is defined here + --> $DIR/drain_collect.rs:3:9 + | +LL | #![deny(clippy::drain_collect)] + | ^^^^^^^^^^^^^^^^^^^^^ + +error: you seem to be trying to move all elements into a new `HashMap` + --> $DIR/drain_collect.rs:17:5 + | +LL | b.drain().collect() + | ^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` + +error: you seem to be trying to move all elements into a new `HashSet` + --> $DIR/drain_collect.rs:25:5 + | +LL | b.drain().collect() + | ^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` + +error: you seem to be trying to move all elements into a new `Vec` + --> $DIR/drain_collect.rs:33:5 + | +LL | b.drain(..).collect() + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` + +error: you seem to be trying to move all elements into a new `Vec` + --> $DIR/drain_collect.rs:41:5 + | +LL | b.drain(..).collect() + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` + +error: you seem to be trying to move all elements into a new `Vec` + --> $DIR/drain_collect.rs:45:5 + | +LL | b.drain(0..).collect() + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` + +error: you seem to be trying to move all elements into a new `Vec` + --> $DIR/drain_collect.rs:49:5 + | +LL | b.drain(..b.len()).collect() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` + +error: you seem to be trying to move all elements into a new `Vec` + --> $DIR/drain_collect.rs:53:5 + | +LL | b.drain(0..b.len()).collect() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` + +error: you seem to be trying to move all elements into a new `Vec` + --> $DIR/drain_collect.rs:58:5 + | +LL | b.drain(..).collect() + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(&mut b)` + +error: you seem to be trying to move all elements into a new `String` + --> $DIR/drain_collect.rs:66:5 + | +LL | b.drain(..).collect() + | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` + +error: aborting due to 10 previous errors + diff --git a/tests/ui/else_if_without_else.rs b/tests/ui/else_if_without_else.rs index 879b3ac398e4..eb5e2266540c 100644 --- a/tests/ui/else_if_without_else.rs +++ b/tests/ui/else_if_without_else.rs @@ -43,7 +43,7 @@ fn main() { if bla1() { println!("if"); } else if bla2() { - //~ ERROR else if without else + //~^ ERROR: `if` expression with an `else if`, but without a final `else` println!("else if"); } @@ -52,7 +52,7 @@ fn main() { } else if bla2() { println!("else if 1"); } else if bla3() { - //~ ERROR else if without else + //~^ ERROR: `if` expression with an `else if`, but without a final `else` println!("else if 2"); } } diff --git a/tests/ui/else_if_without_else.stderr b/tests/ui/else_if_without_else.stderr index 90ccfb4fad64..11baf75441ae 100644 --- a/tests/ui/else_if_without_else.stderr +++ b/tests/ui/else_if_without_else.stderr @@ -3,7 +3,7 @@ error: `if` expression with an `else if`, but without a final `else` | LL | } else if bla2() { | ____________^ -LL | | //~ ERROR else if without else +LL | | LL | | println!("else if"); LL | | } | |_____^ @@ -16,7 +16,7 @@ error: `if` expression with an `else if`, but without a final `else` | LL | } else if bla3() { | ____________^ -LL | | //~ ERROR else if without else +LL | | LL | | println!("else if 2"); LL | | } | |_____^ diff --git a/tests/ui/empty_line_after_doc_comments.rs b/tests/ui/empty_line_after_doc_comments.rs index e843770f5785..83db2a07d334 100644 --- a/tests/ui/empty_line_after_doc_comments.rs +++ b/tests/ui/empty_line_after_doc_comments.rs @@ -1,4 +1,4 @@ -//@aux-build:proc_macro_attr.rs +//@aux-build:proc_macro_attr.rs:proc-macro #![warn(clippy::empty_line_after_doc_comments)] #![allow(clippy::assertions_on_constants)] #![feature(custom_inner_attributes)] diff --git a/tests/ui/empty_line_after_outer_attribute.rs b/tests/ui/empty_line_after_outer_attribute.rs index 269e66ea0a81..b2d7ddae4274 100644 --- a/tests/ui/empty_line_after_outer_attribute.rs +++ b/tests/ui/empty_line_after_outer_attribute.rs @@ -1,4 +1,4 @@ -//@aux-build:proc_macro_attr.rs +//@aux-build:proc_macro_attr.rs:proc-macro #![warn(clippy::empty_line_after_outer_attr)] #![allow(clippy::assertions_on_constants)] #![feature(custom_inner_attributes)] diff --git a/tests/ui/empty_loop.rs b/tests/ui/empty_loop.rs index 54e8fb4907c0..f1a55415c8d5 100644 --- a/tests/ui/empty_loop.rs +++ b/tests/ui/empty_loop.rs @@ -1,4 +1,4 @@ -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![warn(clippy::empty_loop)] diff --git a/tests/ui/empty_loop_no_std.rs b/tests/ui/empty_loop_no_std.rs index d564b2d24f5c..f9ab443dfd94 100644 --- a/tests/ui/empty_loop_no_std.rs +++ b/tests/ui/empty_loop_no_std.rs @@ -1,5 +1,5 @@ //@compile-flags: -Clink-arg=-nostartfiles -//@ignore-macos +//@ignore-target-apple #![warn(clippy::empty_loop)] #![feature(lang_items, start, libc)] diff --git a/tests/ui/endian_bytes.rs b/tests/ui/endian_bytes.rs new file mode 100644 index 000000000000..6bf014fc8095 --- /dev/null +++ b/tests/ui/endian_bytes.rs @@ -0,0 +1,127 @@ +#![allow(unused)] +#![allow(clippy::diverging_sub_expression)] +#![no_main] + +macro_rules! fn_body { + () => { + 2u8.to_ne_bytes(); + 2i8.to_ne_bytes(); + 2u16.to_ne_bytes(); + 2i16.to_ne_bytes(); + 2u32.to_ne_bytes(); + 2i32.to_ne_bytes(); + 2u64.to_ne_bytes(); + 2i64.to_ne_bytes(); + 2u128.to_ne_bytes(); + 2i128.to_ne_bytes(); + 2.0f32.to_ne_bytes(); + 2.0f64.to_ne_bytes(); + 2usize.to_ne_bytes(); + 2isize.to_ne_bytes(); + u8::from_ne_bytes(todo!()); + i8::from_ne_bytes(todo!()); + u16::from_ne_bytes(todo!()); + i16::from_ne_bytes(todo!()); + u32::from_ne_bytes(todo!()); + i32::from_ne_bytes(todo!()); + u64::from_ne_bytes(todo!()); + i64::from_ne_bytes(todo!()); + u128::from_ne_bytes(todo!()); + i128::from_ne_bytes(todo!()); + usize::from_ne_bytes(todo!()); + isize::from_ne_bytes(todo!()); + f32::from_ne_bytes(todo!()); + f64::from_ne_bytes(todo!()); + + 2u8.to_le_bytes(); + 2i8.to_le_bytes(); + 2u16.to_le_bytes(); + 2i16.to_le_bytes(); + 2u32.to_le_bytes(); + 2i32.to_le_bytes(); + 2u64.to_le_bytes(); + 2i64.to_le_bytes(); + 2u128.to_le_bytes(); + 2i128.to_le_bytes(); + 2.0f32.to_le_bytes(); + 2.0f64.to_le_bytes(); + 2usize.to_le_bytes(); + 2isize.to_le_bytes(); + u8::from_le_bytes(todo!()); + i8::from_le_bytes(todo!()); + u16::from_le_bytes(todo!()); + i16::from_le_bytes(todo!()); + u32::from_le_bytes(todo!()); + i32::from_le_bytes(todo!()); + u64::from_le_bytes(todo!()); + i64::from_le_bytes(todo!()); + u128::from_le_bytes(todo!()); + i128::from_le_bytes(todo!()); + usize::from_le_bytes(todo!()); + isize::from_le_bytes(todo!()); + f32::from_le_bytes(todo!()); + f64::from_le_bytes(todo!()); + }; +} + +// bless breaks if I use fn_body too much (oops) +macro_rules! fn_body_smol { + () => { + 2u8.to_ne_bytes(); + u8::from_ne_bytes(todo!()); + + 2u8.to_le_bytes(); + u8::from_le_bytes(todo!()); + + 2u8.to_be_bytes(); + u8::from_be_bytes(todo!()); + }; +} + +#[rustfmt::skip] +#[warn(clippy::host_endian_bytes)] +fn host() { fn_body!(); } + +#[rustfmt::skip] +#[warn(clippy::little_endian_bytes)] +fn little() { fn_body!(); } + +#[rustfmt::skip] +#[warn(clippy::big_endian_bytes)] +fn big() { fn_body!(); } + +#[rustfmt::skip] +#[warn(clippy::host_endian_bytes)] +#[warn(clippy::big_endian_bytes)] +fn host_encourage_little() { fn_body_smol!(); } + +#[rustfmt::skip] +#[warn(clippy::host_endian_bytes)] +#[warn(clippy::little_endian_bytes)] +fn host_encourage_big() { fn_body_smol!(); } + +#[rustfmt::skip] +#[warn(clippy::host_endian_bytes)] +#[warn(clippy::little_endian_bytes)] +#[warn(clippy::big_endian_bytes)] +fn no_help() { fn_body_smol!(); } + +#[rustfmt::skip] +#[warn(clippy::little_endian_bytes)] +#[warn(clippy::big_endian_bytes)] +fn little_encourage_host() { fn_body_smol!(); } + +#[rustfmt::skip] +#[warn(clippy::host_endian_bytes)] +#[warn(clippy::little_endian_bytes)] +fn little_encourage_big() { fn_body_smol!(); } + +#[rustfmt::skip] +#[warn(clippy::big_endian_bytes)] +#[warn(clippy::little_endian_bytes)] +fn big_encourage_host() { fn_body_smol!(); } + +#[rustfmt::skip] +#[warn(clippy::host_endian_bytes)] +#[warn(clippy::big_endian_bytes)] +fn big_encourage_little() { fn_body_smol!(); } diff --git a/tests/ui/endian_bytes.stderr b/tests/ui/endian_bytes.stderr new file mode 100644 index 000000000000..5e64ea5b5ab8 --- /dev/null +++ b/tests/ui/endian_bytes.stderr @@ -0,0 +1,1031 @@ +error: usage of the `u8::to_ne_bytes` method + --> $DIR/endian_bytes.rs:7:9 + | +LL | 2u8.to_ne_bytes(); + | ^^^^^^^^^^^^^^^^^ +... +LL | fn host() { fn_body!(); } + | ---------- in this macro invocation + | + = help: specify the desired endianness explicitly + = note: `-D clippy::host-endian-bytes` implied by `-D warnings` + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `i8::to_ne_bytes` method + --> $DIR/endian_bytes.rs:8:9 + | +LL | 2i8.to_ne_bytes(); + | ^^^^^^^^^^^^^^^^^ +... +LL | fn host() { fn_body!(); } + | ---------- in this macro invocation + | + = help: specify the desired endianness explicitly + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `u16::to_ne_bytes` method + --> $DIR/endian_bytes.rs:9:9 + | +LL | 2u16.to_ne_bytes(); + | ^^^^^^^^^^^^^^^^^^ +... +LL | fn host() { fn_body!(); } + | ---------- in this macro invocation + | + = help: specify the desired endianness explicitly + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `i16::to_ne_bytes` method + --> $DIR/endian_bytes.rs:10:9 + | +LL | 2i16.to_ne_bytes(); + | ^^^^^^^^^^^^^^^^^^ +... +LL | fn host() { fn_body!(); } + | ---------- in this macro invocation + | + = help: specify the desired endianness explicitly + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `u32::to_ne_bytes` method + --> $DIR/endian_bytes.rs:11:9 + | +LL | 2u32.to_ne_bytes(); + | ^^^^^^^^^^^^^^^^^^ +... +LL | fn host() { fn_body!(); } + | ---------- in this macro invocation + | + = help: specify the desired endianness explicitly + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `i32::to_ne_bytes` method + --> $DIR/endian_bytes.rs:12:9 + | +LL | 2i32.to_ne_bytes(); + | ^^^^^^^^^^^^^^^^^^ +... +LL | fn host() { fn_body!(); } + | ---------- in this macro invocation + | + = help: specify the desired endianness explicitly + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `u64::to_ne_bytes` method + --> $DIR/endian_bytes.rs:13:9 + | +LL | 2u64.to_ne_bytes(); + | ^^^^^^^^^^^^^^^^^^ +... +LL | fn host() { fn_body!(); } + | ---------- in this macro invocation + | + = help: specify the desired endianness explicitly + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `i64::to_ne_bytes` method + --> $DIR/endian_bytes.rs:14:9 + | +LL | 2i64.to_ne_bytes(); + | ^^^^^^^^^^^^^^^^^^ +... +LL | fn host() { fn_body!(); } + | ---------- in this macro invocation + | + = help: specify the desired endianness explicitly + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `u128::to_ne_bytes` method + --> $DIR/endian_bytes.rs:15:9 + | +LL | 2u128.to_ne_bytes(); + | ^^^^^^^^^^^^^^^^^^^ +... +LL | fn host() { fn_body!(); } + | ---------- in this macro invocation + | + = help: specify the desired endianness explicitly + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `i128::to_ne_bytes` method + --> $DIR/endian_bytes.rs:16:9 + | +LL | 2i128.to_ne_bytes(); + | ^^^^^^^^^^^^^^^^^^^ +... +LL | fn host() { fn_body!(); } + | ---------- in this macro invocation + | + = help: specify the desired endianness explicitly + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `f32::to_ne_bytes` method + --> $DIR/endian_bytes.rs:17:9 + | +LL | 2.0f32.to_ne_bytes(); + | ^^^^^^^^^^^^^^^^^^^^ +... +LL | fn host() { fn_body!(); } + | ---------- in this macro invocation + | + = help: specify the desired endianness explicitly + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `f64::to_ne_bytes` method + --> $DIR/endian_bytes.rs:18:9 + | +LL | 2.0f64.to_ne_bytes(); + | ^^^^^^^^^^^^^^^^^^^^ +... +LL | fn host() { fn_body!(); } + | ---------- in this macro invocation + | + = help: specify the desired endianness explicitly + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `usize::to_ne_bytes` method + --> $DIR/endian_bytes.rs:19:9 + | +LL | 2usize.to_ne_bytes(); + | ^^^^^^^^^^^^^^^^^^^^ +... +LL | fn host() { fn_body!(); } + | ---------- in this macro invocation + | + = help: specify the desired endianness explicitly + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `isize::to_ne_bytes` method + --> $DIR/endian_bytes.rs:20:9 + | +LL | 2isize.to_ne_bytes(); + | ^^^^^^^^^^^^^^^^^^^^ +... +LL | fn host() { fn_body!(); } + | ---------- in this macro invocation + | + = help: specify the desired endianness explicitly + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `u8::from_ne_bytes` + --> $DIR/endian_bytes.rs:21:9 + | +LL | u8::from_ne_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn host() { fn_body!(); } + | ---------- in this macro invocation + | + = help: specify the desired endianness explicitly + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `i8::from_ne_bytes` + --> $DIR/endian_bytes.rs:22:9 + | +LL | i8::from_ne_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn host() { fn_body!(); } + | ---------- in this macro invocation + | + = help: specify the desired endianness explicitly + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `u16::from_ne_bytes` + --> $DIR/endian_bytes.rs:23:9 + | +LL | u16::from_ne_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn host() { fn_body!(); } + | ---------- in this macro invocation + | + = help: specify the desired endianness explicitly + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `i16::from_ne_bytes` + --> $DIR/endian_bytes.rs:24:9 + | +LL | i16::from_ne_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn host() { fn_body!(); } + | ---------- in this macro invocation + | + = help: specify the desired endianness explicitly + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `u32::from_ne_bytes` + --> $DIR/endian_bytes.rs:25:9 + | +LL | u32::from_ne_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn host() { fn_body!(); } + | ---------- in this macro invocation + | + = help: specify the desired endianness explicitly + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `i32::from_ne_bytes` + --> $DIR/endian_bytes.rs:26:9 + | +LL | i32::from_ne_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn host() { fn_body!(); } + | ---------- in this macro invocation + | + = help: specify the desired endianness explicitly + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `u64::from_ne_bytes` + --> $DIR/endian_bytes.rs:27:9 + | +LL | u64::from_ne_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn host() { fn_body!(); } + | ---------- in this macro invocation + | + = help: specify the desired endianness explicitly + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `i64::from_ne_bytes` + --> $DIR/endian_bytes.rs:28:9 + | +LL | i64::from_ne_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn host() { fn_body!(); } + | ---------- in this macro invocation + | + = help: specify the desired endianness explicitly + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `u128::from_ne_bytes` + --> $DIR/endian_bytes.rs:29:9 + | +LL | u128::from_ne_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn host() { fn_body!(); } + | ---------- in this macro invocation + | + = help: specify the desired endianness explicitly + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `i128::from_ne_bytes` + --> $DIR/endian_bytes.rs:30:9 + | +LL | i128::from_ne_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn host() { fn_body!(); } + | ---------- in this macro invocation + | + = help: specify the desired endianness explicitly + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `usize::from_ne_bytes` + --> $DIR/endian_bytes.rs:31:9 + | +LL | usize::from_ne_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn host() { fn_body!(); } + | ---------- in this macro invocation + | + = help: specify the desired endianness explicitly + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `isize::from_ne_bytes` + --> $DIR/endian_bytes.rs:32:9 + | +LL | isize::from_ne_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn host() { fn_body!(); } + | ---------- in this macro invocation + | + = help: specify the desired endianness explicitly + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `f32::from_ne_bytes` + --> $DIR/endian_bytes.rs:33:9 + | +LL | f32::from_ne_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn host() { fn_body!(); } + | ---------- in this macro invocation + | + = help: specify the desired endianness explicitly + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `f64::from_ne_bytes` + --> $DIR/endian_bytes.rs:34:9 + | +LL | f64::from_ne_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn host() { fn_body!(); } + | ---------- in this macro invocation + | + = help: specify the desired endianness explicitly + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `u8::to_le_bytes` method + --> $DIR/endian_bytes.rs:36:9 + | +LL | 2u8.to_le_bytes(); + | ^^^^^^^^^^^^^^^^^ +... +LL | fn little() { fn_body!(); } + | ---------- in this macro invocation + | + = help: use the native endianness instead + = note: `-D clippy::little-endian-bytes` implied by `-D warnings` + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `i8::to_le_bytes` method + --> $DIR/endian_bytes.rs:37:9 + | +LL | 2i8.to_le_bytes(); + | ^^^^^^^^^^^^^^^^^ +... +LL | fn little() { fn_body!(); } + | ---------- in this macro invocation + | + = help: use the native endianness instead + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `u16::to_le_bytes` method + --> $DIR/endian_bytes.rs:38:9 + | +LL | 2u16.to_le_bytes(); + | ^^^^^^^^^^^^^^^^^^ +... +LL | fn little() { fn_body!(); } + | ---------- in this macro invocation + | + = help: use the native endianness instead + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `i16::to_le_bytes` method + --> $DIR/endian_bytes.rs:39:9 + | +LL | 2i16.to_le_bytes(); + | ^^^^^^^^^^^^^^^^^^ +... +LL | fn little() { fn_body!(); } + | ---------- in this macro invocation + | + = help: use the native endianness instead + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `u32::to_le_bytes` method + --> $DIR/endian_bytes.rs:40:9 + | +LL | 2u32.to_le_bytes(); + | ^^^^^^^^^^^^^^^^^^ +... +LL | fn little() { fn_body!(); } + | ---------- in this macro invocation + | + = help: use the native endianness instead + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `i32::to_le_bytes` method + --> $DIR/endian_bytes.rs:41:9 + | +LL | 2i32.to_le_bytes(); + | ^^^^^^^^^^^^^^^^^^ +... +LL | fn little() { fn_body!(); } + | ---------- in this macro invocation + | + = help: use the native endianness instead + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `u64::to_le_bytes` method + --> $DIR/endian_bytes.rs:42:9 + | +LL | 2u64.to_le_bytes(); + | ^^^^^^^^^^^^^^^^^^ +... +LL | fn little() { fn_body!(); } + | ---------- in this macro invocation + | + = help: use the native endianness instead + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `i64::to_le_bytes` method + --> $DIR/endian_bytes.rs:43:9 + | +LL | 2i64.to_le_bytes(); + | ^^^^^^^^^^^^^^^^^^ +... +LL | fn little() { fn_body!(); } + | ---------- in this macro invocation + | + = help: use the native endianness instead + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `u128::to_le_bytes` method + --> $DIR/endian_bytes.rs:44:9 + | +LL | 2u128.to_le_bytes(); + | ^^^^^^^^^^^^^^^^^^^ +... +LL | fn little() { fn_body!(); } + | ---------- in this macro invocation + | + = help: use the native endianness instead + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `i128::to_le_bytes` method + --> $DIR/endian_bytes.rs:45:9 + | +LL | 2i128.to_le_bytes(); + | ^^^^^^^^^^^^^^^^^^^ +... +LL | fn little() { fn_body!(); } + | ---------- in this macro invocation + | + = help: use the native endianness instead + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `f32::to_le_bytes` method + --> $DIR/endian_bytes.rs:46:9 + | +LL | 2.0f32.to_le_bytes(); + | ^^^^^^^^^^^^^^^^^^^^ +... +LL | fn little() { fn_body!(); } + | ---------- in this macro invocation + | + = help: use the native endianness instead + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `f64::to_le_bytes` method + --> $DIR/endian_bytes.rs:47:9 + | +LL | 2.0f64.to_le_bytes(); + | ^^^^^^^^^^^^^^^^^^^^ +... +LL | fn little() { fn_body!(); } + | ---------- in this macro invocation + | + = help: use the native endianness instead + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `usize::to_le_bytes` method + --> $DIR/endian_bytes.rs:48:9 + | +LL | 2usize.to_le_bytes(); + | ^^^^^^^^^^^^^^^^^^^^ +... +LL | fn little() { fn_body!(); } + | ---------- in this macro invocation + | + = help: use the native endianness instead + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `isize::to_le_bytes` method + --> $DIR/endian_bytes.rs:49:9 + | +LL | 2isize.to_le_bytes(); + | ^^^^^^^^^^^^^^^^^^^^ +... +LL | fn little() { fn_body!(); } + | ---------- in this macro invocation + | + = help: use the native endianness instead + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `u8::from_le_bytes` + --> $DIR/endian_bytes.rs:50:9 + | +LL | u8::from_le_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn little() { fn_body!(); } + | ---------- in this macro invocation + | + = help: use the native endianness instead + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `i8::from_le_bytes` + --> $DIR/endian_bytes.rs:51:9 + | +LL | i8::from_le_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn little() { fn_body!(); } + | ---------- in this macro invocation + | + = help: use the native endianness instead + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `u16::from_le_bytes` + --> $DIR/endian_bytes.rs:52:9 + | +LL | u16::from_le_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn little() { fn_body!(); } + | ---------- in this macro invocation + | + = help: use the native endianness instead + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `i16::from_le_bytes` + --> $DIR/endian_bytes.rs:53:9 + | +LL | i16::from_le_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn little() { fn_body!(); } + | ---------- in this macro invocation + | + = help: use the native endianness instead + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `u32::from_le_bytes` + --> $DIR/endian_bytes.rs:54:9 + | +LL | u32::from_le_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn little() { fn_body!(); } + | ---------- in this macro invocation + | + = help: use the native endianness instead + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `i32::from_le_bytes` + --> $DIR/endian_bytes.rs:55:9 + | +LL | i32::from_le_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn little() { fn_body!(); } + | ---------- in this macro invocation + | + = help: use the native endianness instead + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `u64::from_le_bytes` + --> $DIR/endian_bytes.rs:56:9 + | +LL | u64::from_le_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn little() { fn_body!(); } + | ---------- in this macro invocation + | + = help: use the native endianness instead + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `i64::from_le_bytes` + --> $DIR/endian_bytes.rs:57:9 + | +LL | i64::from_le_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn little() { fn_body!(); } + | ---------- in this macro invocation + | + = help: use the native endianness instead + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `u128::from_le_bytes` + --> $DIR/endian_bytes.rs:58:9 + | +LL | u128::from_le_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn little() { fn_body!(); } + | ---------- in this macro invocation + | + = help: use the native endianness instead + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `i128::from_le_bytes` + --> $DIR/endian_bytes.rs:59:9 + | +LL | i128::from_le_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn little() { fn_body!(); } + | ---------- in this macro invocation + | + = help: use the native endianness instead + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `usize::from_le_bytes` + --> $DIR/endian_bytes.rs:60:9 + | +LL | usize::from_le_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn little() { fn_body!(); } + | ---------- in this macro invocation + | + = help: use the native endianness instead + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `isize::from_le_bytes` + --> $DIR/endian_bytes.rs:61:9 + | +LL | isize::from_le_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn little() { fn_body!(); } + | ---------- in this macro invocation + | + = help: use the native endianness instead + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `f32::from_le_bytes` + --> $DIR/endian_bytes.rs:62:9 + | +LL | f32::from_le_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn little() { fn_body!(); } + | ---------- in this macro invocation + | + = help: use the native endianness instead + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `f64::from_le_bytes` + --> $DIR/endian_bytes.rs:63:9 + | +LL | f64::from_le_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn little() { fn_body!(); } + | ---------- in this macro invocation + | + = help: use the native endianness instead + = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `u8::to_ne_bytes` method + --> $DIR/endian_bytes.rs:70:9 + | +LL | 2u8.to_ne_bytes(); + | ^^^^^^^^^^^^^^^^^ +... +LL | fn host_encourage_little() { fn_body_smol!(); } + | --------------- in this macro invocation + | + = help: use `u8::to_le_bytes` instead + = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `u8::from_ne_bytes` + --> $DIR/endian_bytes.rs:71:9 + | +LL | u8::from_ne_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn host_encourage_little() { fn_body_smol!(); } + | --------------- in this macro invocation + | + = help: use `u8::from_le_bytes` instead + = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `u8::to_be_bytes` method + --> $DIR/endian_bytes.rs:76:9 + | +LL | 2u8.to_be_bytes(); + | ^^^^^^^^^^^^^^^^^ +... +LL | fn host_encourage_little() { fn_body_smol!(); } + | --------------- in this macro invocation + | + = help: use `u8::to_le_bytes` instead + = note: `-D clippy::big-endian-bytes` implied by `-D warnings` + = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `u8::from_be_bytes` + --> $DIR/endian_bytes.rs:77:9 + | +LL | u8::from_be_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn host_encourage_little() { fn_body_smol!(); } + | --------------- in this macro invocation + | + = help: use `u8::from_le_bytes` instead + = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `u8::to_ne_bytes` method + --> $DIR/endian_bytes.rs:70:9 + | +LL | 2u8.to_ne_bytes(); + | ^^^^^^^^^^^^^^^^^ +... +LL | fn host_encourage_big() { fn_body_smol!(); } + | --------------- in this macro invocation + | + = help: use `u8::to_be_bytes` instead + = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `u8::from_ne_bytes` + --> $DIR/endian_bytes.rs:71:9 + | +LL | u8::from_ne_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn host_encourage_big() { fn_body_smol!(); } + | --------------- in this macro invocation + | + = help: use `u8::from_be_bytes` instead + = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `u8::to_le_bytes` method + --> $DIR/endian_bytes.rs:73:9 + | +LL | 2u8.to_le_bytes(); + | ^^^^^^^^^^^^^^^^^ +... +LL | fn host_encourage_big() { fn_body_smol!(); } + | --------------- in this macro invocation + | + = help: use `u8::to_be_bytes` instead + = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `u8::from_le_bytes` + --> $DIR/endian_bytes.rs:74:9 + | +LL | u8::from_le_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn host_encourage_big() { fn_body_smol!(); } + | --------------- in this macro invocation + | + = help: use `u8::from_be_bytes` instead + = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `u8::to_ne_bytes` method + --> $DIR/endian_bytes.rs:70:9 + | +LL | 2u8.to_ne_bytes(); + | ^^^^^^^^^^^^^^^^^ +... +LL | fn no_help() { fn_body_smol!(); } + | --------------- in this macro invocation + | + = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `u8::from_ne_bytes` + --> $DIR/endian_bytes.rs:71:9 + | +LL | u8::from_ne_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn no_help() { fn_body_smol!(); } + | --------------- in this macro invocation + | + = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `u8::to_le_bytes` method + --> $DIR/endian_bytes.rs:73:9 + | +LL | 2u8.to_le_bytes(); + | ^^^^^^^^^^^^^^^^^ +... +LL | fn no_help() { fn_body_smol!(); } + | --------------- in this macro invocation + | + = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `u8::from_le_bytes` + --> $DIR/endian_bytes.rs:74:9 + | +LL | u8::from_le_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn no_help() { fn_body_smol!(); } + | --------------- in this macro invocation + | + = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `u8::to_be_bytes` method + --> $DIR/endian_bytes.rs:76:9 + | +LL | 2u8.to_be_bytes(); + | ^^^^^^^^^^^^^^^^^ +... +LL | fn no_help() { fn_body_smol!(); } + | --------------- in this macro invocation + | + = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `u8::from_be_bytes` + --> $DIR/endian_bytes.rs:77:9 + | +LL | u8::from_be_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn no_help() { fn_body_smol!(); } + | --------------- in this macro invocation + | + = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `u8::to_le_bytes` method + --> $DIR/endian_bytes.rs:73:9 + | +LL | 2u8.to_le_bytes(); + | ^^^^^^^^^^^^^^^^^ +... +LL | fn little_encourage_host() { fn_body_smol!(); } + | --------------- in this macro invocation + | + = help: use the native endianness instead + = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `u8::from_le_bytes` + --> $DIR/endian_bytes.rs:74:9 + | +LL | u8::from_le_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn little_encourage_host() { fn_body_smol!(); } + | --------------- in this macro invocation + | + = help: use the native endianness instead + = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `u8::to_be_bytes` method + --> $DIR/endian_bytes.rs:76:9 + | +LL | 2u8.to_be_bytes(); + | ^^^^^^^^^^^^^^^^^ +... +LL | fn little_encourage_host() { fn_body_smol!(); } + | --------------- in this macro invocation + | + = help: use the native endianness instead + = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `u8::from_be_bytes` + --> $DIR/endian_bytes.rs:77:9 + | +LL | u8::from_be_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn little_encourage_host() { fn_body_smol!(); } + | --------------- in this macro invocation + | + = help: use the native endianness instead + = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `u8::to_ne_bytes` method + --> $DIR/endian_bytes.rs:70:9 + | +LL | 2u8.to_ne_bytes(); + | ^^^^^^^^^^^^^^^^^ +... +LL | fn little_encourage_big() { fn_body_smol!(); } + | --------------- in this macro invocation + | + = help: use `u8::to_be_bytes` instead + = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `u8::from_ne_bytes` + --> $DIR/endian_bytes.rs:71:9 + | +LL | u8::from_ne_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn little_encourage_big() { fn_body_smol!(); } + | --------------- in this macro invocation + | + = help: use `u8::from_be_bytes` instead + = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `u8::to_le_bytes` method + --> $DIR/endian_bytes.rs:73:9 + | +LL | 2u8.to_le_bytes(); + | ^^^^^^^^^^^^^^^^^ +... +LL | fn little_encourage_big() { fn_body_smol!(); } + | --------------- in this macro invocation + | + = help: use `u8::to_be_bytes` instead + = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `u8::from_le_bytes` + --> $DIR/endian_bytes.rs:74:9 + | +LL | u8::from_le_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn little_encourage_big() { fn_body_smol!(); } + | --------------- in this macro invocation + | + = help: use `u8::from_be_bytes` instead + = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `u8::to_le_bytes` method + --> $DIR/endian_bytes.rs:73:9 + | +LL | 2u8.to_le_bytes(); + | ^^^^^^^^^^^^^^^^^ +... +LL | fn big_encourage_host() { fn_body_smol!(); } + | --------------- in this macro invocation + | + = help: use the native endianness instead + = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `u8::from_le_bytes` + --> $DIR/endian_bytes.rs:74:9 + | +LL | u8::from_le_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn big_encourage_host() { fn_body_smol!(); } + | --------------- in this macro invocation + | + = help: use the native endianness instead + = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `u8::to_be_bytes` method + --> $DIR/endian_bytes.rs:76:9 + | +LL | 2u8.to_be_bytes(); + | ^^^^^^^^^^^^^^^^^ +... +LL | fn big_encourage_host() { fn_body_smol!(); } + | --------------- in this macro invocation + | + = help: use the native endianness instead + = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `u8::from_be_bytes` + --> $DIR/endian_bytes.rs:77:9 + | +LL | u8::from_be_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn big_encourage_host() { fn_body_smol!(); } + | --------------- in this macro invocation + | + = help: use the native endianness instead + = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `u8::to_ne_bytes` method + --> $DIR/endian_bytes.rs:70:9 + | +LL | 2u8.to_ne_bytes(); + | ^^^^^^^^^^^^^^^^^ +... +LL | fn big_encourage_little() { fn_body_smol!(); } + | --------------- in this macro invocation + | + = help: use `u8::to_le_bytes` instead + = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `u8::from_ne_bytes` + --> $DIR/endian_bytes.rs:71:9 + | +LL | u8::from_ne_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn big_encourage_little() { fn_body_smol!(); } + | --------------- in this macro invocation + | + = help: use `u8::from_le_bytes` instead + = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the `u8::to_be_bytes` method + --> $DIR/endian_bytes.rs:76:9 + | +LL | 2u8.to_be_bytes(); + | ^^^^^^^^^^^^^^^^^ +... +LL | fn big_encourage_little() { fn_body_smol!(); } + | --------------- in this macro invocation + | + = help: use `u8::to_le_bytes` instead + = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: usage of the function `u8::from_be_bytes` + --> $DIR/endian_bytes.rs:77:9 + | +LL | u8::from_be_bytes(todo!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | fn big_encourage_little() { fn_body_smol!(); } + | --------------- in this macro invocation + | + = help: use `u8::from_le_bytes` instead + = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 86 previous errors + diff --git a/tests/ui/enum_clike_unportable_variant.rs b/tests/ui/enum_clike_unportable_variant.rs index f17556ea9070..abe42a2305f5 100644 --- a/tests/ui/enum_clike_unportable_variant.rs +++ b/tests/ui/enum_clike_unportable_variant.rs @@ -1,4 +1,4 @@ -//@ignore-x86 +//@ignore-target-x86 #![warn(clippy::enum_clike_unportable_variant)] #![allow(unused, non_upper_case_globals)] diff --git a/tests/ui/eprint_with_newline.rs b/tests/ui/eprint_with_newline.rs index de5e121be877..8389806c838e 100644 --- a/tests/ui/eprint_with_newline.rs +++ b/tests/ui/eprint_with_newline.rs @@ -44,7 +44,7 @@ fn main() { // Don't warn on CRLF (#4208) eprint!("\r\n"); eprint!("foo\r\n"); - eprint!("\\r\n"); //~ ERROR + eprint!("\\r\n"); eprint!("foo\rbar\n"); // Ignore expanded format strings diff --git a/tests/ui/eprint_with_newline.stderr b/tests/ui/eprint_with_newline.stderr index 0eefb9f0ca97..0a6bdf15df8e 100644 --- a/tests/ui/eprint_with_newline.stderr +++ b/tests/ui/eprint_with_newline.stderr @@ -62,13 +62,13 @@ LL + eprintln!(); error: using `eprint!()` with a format string that ends in a single newline --> $DIR/eprint_with_newline.rs:28:5 | -LL | eprint!("//n"); // should fail +LL | eprint!("///n"); // should fail | ^^^^^^^^^^^^^^^ | help: use `eprintln!` instead | -LL - eprint!("//n"); // should fail -LL + eprintln!("/"); // should fail +LL - eprint!("///n"); // should fail +LL + eprintln!("//"); // should fail | error: using `eprint!()` with a format string that ends in a single newline @@ -104,13 +104,13 @@ LL ~ error: using `eprint!()` with a format string that ends in a single newline --> $DIR/eprint_with_newline.rs:47:5 | -LL | eprint!("/r/n"); //~ ERROR +LL | eprint!("//r/n"); | ^^^^^^^^^^^^^^^^ | help: use `eprintln!` instead | -LL - eprint!("/r/n"); //~ ERROR -LL + eprintln!("/r"); //~ ERROR +LL - eprint!("//r/n"); +LL + eprintln!("//r"); | error: aborting due to 9 previous errors diff --git a/tests/ui/eq_op.rs b/tests/ui/eq_op.rs index cdd33ebe582f..e973e5ba2fb1 100644 --- a/tests/ui/eq_op.rs +++ b/tests/ui/eq_op.rs @@ -1,5 +1,3 @@ -//@compile-flags: --test - #![warn(clippy::eq_op)] #![allow(clippy::double_parens, clippy::identity_op, clippy::nonminimal_bool)] #![allow(clippy::suspicious_xor_used_as_pow)] @@ -12,6 +10,8 @@ fn main() { let _ = false != false; let _ = 1.5 < 1.5; let _ = 1u64 >= 1u64; + let x = f32::NAN; + let _ = x != x; // casts, methods, parentheses let _ = (1u32 as u64) & (1u32 as u64); diff --git a/tests/ui/eq_op.stderr b/tests/ui/eq_op.stderr index d365ab27edc2..c7fa253bdca2 100644 --- a/tests/ui/eq_op.stderr +++ b/tests/ui/eq_op.stderr @@ -1,5 +1,5 @@ error: equal expressions as operands to `==` - --> $DIR/eq_op.rs:9:13 + --> $DIR/eq_op.rs:7:13 | LL | let _ = 1 == 1; | ^^^^^^ @@ -7,29 +7,37 @@ LL | let _ = 1 == 1; = note: `-D clippy::eq-op` implied by `-D warnings` error: equal expressions as operands to `==` - --> $DIR/eq_op.rs:10:13 + --> $DIR/eq_op.rs:8:13 | LL | let _ = "no" == "no"; | ^^^^^^^^^^^^ error: equal expressions as operands to `!=` - --> $DIR/eq_op.rs:12:13 + --> $DIR/eq_op.rs:10:13 | LL | let _ = false != false; | ^^^^^^^^^^^^^^ error: equal expressions as operands to `<` - --> $DIR/eq_op.rs:13:13 + --> $DIR/eq_op.rs:11:13 | LL | let _ = 1.5 < 1.5; | ^^^^^^^^^ error: equal expressions as operands to `>=` - --> $DIR/eq_op.rs:14:13 + --> $DIR/eq_op.rs:12:13 | LL | let _ = 1u64 >= 1u64; | ^^^^^^^^^^^^ +error: equal expressions as operands to `!=` + --> $DIR/eq_op.rs:14:13 + | +LL | let _ = x != x; + | ^^^^^^ + | + = note: if you intended to check if the operand is NaN, use `.is_nan()` instead + error: equal expressions as operands to `&` --> $DIR/eq_op.rs:17:13 | @@ -168,5 +176,5 @@ error: equal expressions as operands to `==` LL | (n1.inner.0).0 == (n1.inner.0).0 && (n1.inner.1).0 == (n2.inner.1).0 && (n1.inner.2).0 == (n2.inner.2).0 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 28 previous errors +error: aborting due to 29 previous errors diff --git a/tests/ui/eq_op_macros.rs b/tests/ui/eq_op_macros.rs index 6b5b31a1a2ef..482406772289 100644 --- a/tests/ui/eq_op_macros.rs +++ b/tests/ui/eq_op_macros.rs @@ -1,4 +1,5 @@ #![warn(clippy::eq_op)] +#![allow(clippy::useless_vec)] // lint also in macro definition macro_rules! assert_in_macro_def { diff --git a/tests/ui/eq_op_macros.stderr b/tests/ui/eq_op_macros.stderr index cd9f1826e59b..cb9b0c01862b 100644 --- a/tests/ui/eq_op_macros.stderr +++ b/tests/ui/eq_op_macros.stderr @@ -1,5 +1,5 @@ error: identical args used in this `assert_eq!` macro call - --> $DIR/eq_op_macros.rs:7:20 + --> $DIR/eq_op_macros.rs:8:20 | LL | assert_eq!(a, a); | ^^^^ @@ -11,7 +11,7 @@ LL | assert_in_macro_def!(); = note: this error originates in the macro `assert_in_macro_def` (in Nightly builds, run with -Z macro-backtrace for more info) error: identical args used in this `assert_ne!` macro call - --> $DIR/eq_op_macros.rs:8:20 + --> $DIR/eq_op_macros.rs:9:20 | LL | assert_ne!(a, a); | ^^^^ @@ -22,7 +22,7 @@ LL | assert_in_macro_def!(); = note: this error originates in the macro `assert_in_macro_def` (in Nightly builds, run with -Z macro-backtrace for more info) error: identical args used in this `debug_assert_eq!` macro call - --> $DIR/eq_op_macros.rs:9:26 + --> $DIR/eq_op_macros.rs:10:26 | LL | debug_assert_eq!(a, a); | ^^^^ @@ -33,7 +33,7 @@ LL | assert_in_macro_def!(); = note: this error originates in the macro `assert_in_macro_def` (in Nightly builds, run with -Z macro-backtrace for more info) error: identical args used in this `debug_assert_ne!` macro call - --> $DIR/eq_op_macros.rs:10:26 + --> $DIR/eq_op_macros.rs:11:26 | LL | debug_assert_ne!(a, a); | ^^^^ @@ -44,49 +44,49 @@ LL | assert_in_macro_def!(); = note: this error originates in the macro `assert_in_macro_def` (in Nightly builds, run with -Z macro-backtrace for more info) error: identical args used in this `assert_eq!` macro call - --> $DIR/eq_op_macros.rs:22:16 + --> $DIR/eq_op_macros.rs:23:16 | LL | assert_eq!(a, a); | ^^^^ error: identical args used in this `assert_eq!` macro call - --> $DIR/eq_op_macros.rs:23:16 + --> $DIR/eq_op_macros.rs:24:16 | LL | assert_eq!(a + 1, a + 1); | ^^^^^^^^^^^^ error: identical args used in this `assert_ne!` macro call - --> $DIR/eq_op_macros.rs:30:16 + --> $DIR/eq_op_macros.rs:31:16 | LL | assert_ne!(a, a); | ^^^^ error: identical args used in this `assert_ne!` macro call - --> $DIR/eq_op_macros.rs:31:16 + --> $DIR/eq_op_macros.rs:32:16 | LL | assert_ne!(a + 1, a + 1); | ^^^^^^^^^^^^ error: identical args used in this `debug_assert_eq!` macro call - --> $DIR/eq_op_macros.rs:38:22 + --> $DIR/eq_op_macros.rs:39:22 | LL | debug_assert_eq!(a, a); | ^^^^ error: identical args used in this `debug_assert_eq!` macro call - --> $DIR/eq_op_macros.rs:39:22 + --> $DIR/eq_op_macros.rs:40:22 | LL | debug_assert_eq!(a + 1, a + 1); | ^^^^^^^^^^^^ error: identical args used in this `debug_assert_ne!` macro call - --> $DIR/eq_op_macros.rs:46:22 + --> $DIR/eq_op_macros.rs:47:22 | LL | debug_assert_ne!(a, a); | ^^^^ error: identical args used in this `debug_assert_ne!` macro call - --> $DIR/eq_op_macros.rs:47:22 + --> $DIR/eq_op_macros.rs:48:22 | LL | debug_assert_ne!(a + 1, a + 1); | ^^^^^^^^^^^^ diff --git a/tests/ui/equatable_if_let.fixed b/tests/ui/equatable_if_let.fixed index 53e62760bef4..6cc070fb5526 100644 --- a/tests/ui/equatable_if_let.fixed +++ b/tests/ui/equatable_if_let.fixed @@ -1,7 +1,12 @@ //@run-rustfix -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro -#![allow(unused_variables, dead_code, clippy::derive_partial_eq_without_eq)] +#![allow( + unused_variables, + dead_code, + clippy::derive_partial_eq_without_eq, + clippy::needless_if +)] #![warn(clippy::equatable_if_let)] extern crate proc_macros; diff --git a/tests/ui/equatable_if_let.rs b/tests/ui/equatable_if_let.rs index 55918a5bb119..f00a129bef1a 100644 --- a/tests/ui/equatable_if_let.rs +++ b/tests/ui/equatable_if_let.rs @@ -1,7 +1,12 @@ //@run-rustfix -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro -#![allow(unused_variables, dead_code, clippy::derive_partial_eq_without_eq)] +#![allow( + unused_variables, + dead_code, + clippy::derive_partial_eq_without_eq, + clippy::needless_if +)] #![warn(clippy::equatable_if_let)] extern crate proc_macros; diff --git a/tests/ui/equatable_if_let.stderr b/tests/ui/equatable_if_let.stderr index a72d87bb7ba9..649495dded7d 100644 --- a/tests/ui/equatable_if_let.stderr +++ b/tests/ui/equatable_if_let.stderr @@ -1,5 +1,5 @@ error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:60:8 + --> $DIR/equatable_if_let.rs:65:8 | LL | if let 2 = a {} | ^^^^^^^^^ help: try: `a == 2` @@ -7,79 +7,79 @@ LL | if let 2 = a {} = note: `-D clippy::equatable-if-let` implied by `-D warnings` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:61:8 + --> $DIR/equatable_if_let.rs:66:8 | LL | if let Ordering::Greater = a.cmp(&b) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.cmp(&b) == Ordering::Greater` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:62:8 + --> $DIR/equatable_if_let.rs:67:8 | LL | if let Some(2) = c {} | ^^^^^^^^^^^^^^^ help: try: `c == Some(2)` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:63:8 + --> $DIR/equatable_if_let.rs:68:8 | LL | if let Struct { a: 2, b: false } = d {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `d == (Struct { a: 2, b: false })` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:64:8 + --> $DIR/equatable_if_let.rs:69:8 | LL | if let Enum::TupleVariant(32, 64) = e {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == Enum::TupleVariant(32, 64)` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:65:8 + --> $DIR/equatable_if_let.rs:70:8 | LL | if let Enum::RecordVariant { a: 64, b: 32 } = e {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == (Enum::RecordVariant { a: 64, b: 32 })` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:66:8 + --> $DIR/equatable_if_let.rs:71:8 | LL | if let Enum::UnitVariant = e {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == Enum::UnitVariant` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:67:8 + --> $DIR/equatable_if_let.rs:72:8 | LL | if let (Enum::UnitVariant, &Struct { a: 2, b: false }) = (e, &d) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(e, &d) == (Enum::UnitVariant, &Struct { a: 2, b: false })` error: this pattern matching can be expressed using `matches!` - --> $DIR/equatable_if_let.rs:76:8 + --> $DIR/equatable_if_let.rs:81:8 | LL | if let NotPartialEq::A = f {} | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(f, NotPartialEq::A)` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:77:8 + --> $DIR/equatable_if_let.rs:82:8 | LL | if let NotStructuralEq::A = g {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `g == NotStructuralEq::A` error: this pattern matching can be expressed using `matches!` - --> $DIR/equatable_if_let.rs:78:8 + --> $DIR/equatable_if_let.rs:83:8 | LL | if let Some(NotPartialEq::A) = Some(f) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(Some(f), Some(NotPartialEq::A))` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:79:8 + --> $DIR/equatable_if_let.rs:84:8 | LL | if let Some(NotStructuralEq::A) = Some(g) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(g) == Some(NotStructuralEq::A)` error: this pattern matching can be expressed using `matches!` - --> $DIR/equatable_if_let.rs:80:8 + --> $DIR/equatable_if_let.rs:85:8 | LL | if let NoPartialEqStruct { a: 2, b: false } = h {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(h, NoPartialEqStruct { a: 2, b: false })` error: this pattern matching can be expressed using equality - --> $DIR/equatable_if_let.rs:82:8 + --> $DIR/equatable_if_let.rs:87:8 | LL | if let inline!("abc") = "abc" { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"abc" == inline!("abc")` diff --git a/tests/ui/err_expect.fixed b/tests/ui/err_expect.fixed index 6ade6f546891..46e2816da522 100644 --- a/tests/ui/err_expect.fixed +++ b/tests/ui/err_expect.fixed @@ -1,6 +1,6 @@ //@run-rustfix -#![allow(unused)] +#![allow(unused, clippy::unnecessary_literal_unwrap)] struct MyTypeNonDebug; diff --git a/tests/ui/err_expect.rs b/tests/ui/err_expect.rs index a93fb59493fe..b9446034d50a 100644 --- a/tests/ui/err_expect.rs +++ b/tests/ui/err_expect.rs @@ -1,6 +1,6 @@ //@run-rustfix -#![allow(unused)] +#![allow(unused, clippy::unnecessary_literal_unwrap)] struct MyTypeNonDebug; diff --git a/tests/ui/eta.fixed b/tests/ui/eta.fixed index b1baf462c0f8..bf44bcb564ec 100644 --- a/tests/ui/eta.fixed +++ b/tests/ui/eta.fixed @@ -7,7 +7,8 @@ clippy::no_effect, clippy::option_map_unit_fn, clippy::redundant_closure_call, - clippy::uninlined_format_args + clippy::uninlined_format_args, + clippy::useless_vec )] use std::path::{Path, PathBuf}; @@ -46,6 +47,12 @@ fn main() { // issue #7224 let _: Option> = Some(0).map(|_| vec![]); + + // issue #10684 + fn test(x: impl Fn(usize, usize) -> T) -> T { + x(1, 2) + } + test(|start, end| start..=end); } trait TestTrait { diff --git a/tests/ui/eta.rs b/tests/ui/eta.rs index e113c3d6cd6b..b2af4bf09537 100644 --- a/tests/ui/eta.rs +++ b/tests/ui/eta.rs @@ -7,7 +7,8 @@ clippy::no_effect, clippy::option_map_unit_fn, clippy::redundant_closure_call, - clippy::uninlined_format_args + clippy::uninlined_format_args, + clippy::useless_vec )] use std::path::{Path, PathBuf}; @@ -46,6 +47,12 @@ fn main() { // issue #7224 let _: Option> = Some(0).map(|_| vec![]); + + // issue #10684 + fn test(x: impl Fn(usize, usize) -> T) -> T { + x(1, 2) + } + test(|start, end| start..=end); } trait TestTrait { diff --git a/tests/ui/eta.stderr b/tests/ui/eta.stderr index a521fb868607..0ac0b901df44 100644 --- a/tests/ui/eta.stderr +++ b/tests/ui/eta.stderr @@ -1,5 +1,5 @@ error: redundant closure - --> $DIR/eta.rs:28:27 + --> $DIR/eta.rs:29:27 | LL | let a = Some(1u8).map(|a| foo(a)); | ^^^^^^^^^^ help: replace the closure with the function itself: `foo` @@ -7,31 +7,31 @@ LL | let a = Some(1u8).map(|a| foo(a)); = note: `-D clippy::redundant-closure` implied by `-D warnings` error: redundant closure - --> $DIR/eta.rs:32:40 + --> $DIR/eta.rs:33:40 | LL | let _: Option> = true.then(|| vec![]); // special case vec! | ^^^^^^^^^ help: replace the closure with `Vec::new`: `std::vec::Vec::new` error: redundant closure - --> $DIR/eta.rs:33:35 + --> $DIR/eta.rs:34:35 | LL | let d = Some(1u8).map(|a| foo((|b| foo2(b))(a))); //is adjusted? | ^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo2` error: redundant closure - --> $DIR/eta.rs:34:26 + --> $DIR/eta.rs:35:26 | LL | all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted | ^^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `below` error: redundant closure - --> $DIR/eta.rs:41:27 + --> $DIR/eta.rs:42:27 | LL | let e = Some(1u8).map(|a| generic(a)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `generic` error: redundant closure - --> $DIR/eta.rs:87:51 + --> $DIR/eta.rs:94:51 | LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo()); | ^^^^^^^^^^^ help: replace the closure with the method itself: `TestStruct::foo` @@ -39,121 +39,121 @@ LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo()); = note: `-D clippy::redundant-closure-for-method-calls` implied by `-D warnings` error: redundant closure - --> $DIR/eta.rs:88:51 + --> $DIR/eta.rs:95:51 | LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo()); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `TestTrait::trait_foo` error: redundant closure - --> $DIR/eta.rs:90:42 + --> $DIR/eta.rs:97:42 | LL | let e = Some(&mut vec![1, 2, 3]).map(|v| v.clear()); | ^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::vec::Vec::clear` error: redundant closure - --> $DIR/eta.rs:94:29 + --> $DIR/eta.rs:101:29 | LL | let e = Some("str").map(|s| s.to_string()); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::string::ToString::to_string` error: redundant closure - --> $DIR/eta.rs:95:27 + --> $DIR/eta.rs:102:27 | LL | let e = Some('a').map(|s| s.to_uppercase()); | ^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_uppercase` error: redundant closure - --> $DIR/eta.rs:97:65 + --> $DIR/eta.rs:104:65 | LL | let e: std::vec::Vec = vec!['a', 'b', 'c'].iter().map(|c| c.to_ascii_uppercase()).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_ascii_uppercase` error: redundant closure - --> $DIR/eta.rs:160:22 + --> $DIR/eta.rs:167:22 | LL | requires_fn_once(|| x()); | ^^^^^^ help: replace the closure with the function itself: `x` error: redundant closure - --> $DIR/eta.rs:167:27 + --> $DIR/eta.rs:174:27 | LL | let a = Some(1u8).map(|a| foo_ptr(a)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo_ptr` error: redundant closure - --> $DIR/eta.rs:172:27 + --> $DIR/eta.rs:179:27 | LL | let a = Some(1u8).map(|a| closure(a)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `closure` error: redundant closure - --> $DIR/eta.rs:204:28 + --> $DIR/eta.rs:211:28 | LL | x.into_iter().for_each(|x| add_to_res(x)); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res` error: redundant closure - --> $DIR/eta.rs:205:28 + --> $DIR/eta.rs:212:28 | LL | y.into_iter().for_each(|x| add_to_res(x)); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res` error: redundant closure - --> $DIR/eta.rs:206:28 + --> $DIR/eta.rs:213:28 | LL | z.into_iter().for_each(|x| add_to_res(x)); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `add_to_res` error: redundant closure - --> $DIR/eta.rs:213:21 + --> $DIR/eta.rs:220:21 | LL | Some(1).map(|n| closure(n)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut closure` error: redundant closure - --> $DIR/eta.rs:217:21 + --> $DIR/eta.rs:224:21 | LL | Some(1).map(|n| in_loop(n)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `in_loop` error: redundant closure - --> $DIR/eta.rs:310:18 + --> $DIR/eta.rs:317:18 | LL | takes_fn_mut(|| f()); | ^^^^^^ help: replace the closure with the function itself: `&mut f` error: redundant closure - --> $DIR/eta.rs:313:19 + --> $DIR/eta.rs:320:19 | LL | takes_fn_once(|| f()); | ^^^^^^ help: replace the closure with the function itself: `&mut f` error: redundant closure - --> $DIR/eta.rs:317:26 + --> $DIR/eta.rs:324:26 | LL | move || takes_fn_mut(|| f_used_once()) | ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut f_used_once` error: redundant closure - --> $DIR/eta.rs:329:19 + --> $DIR/eta.rs:336:19 | LL | array_opt.map(|a| a.as_slice()); | ^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<[u8; 3]>::as_slice` error: redundant closure - --> $DIR/eta.rs:332:19 + --> $DIR/eta.rs:339:19 | LL | slice_opt.map(|s| s.len()); | ^^^^^^^^^^^ help: replace the closure with the method itself: `<[u8]>::len` error: redundant closure - --> $DIR/eta.rs:335:17 + --> $DIR/eta.rs:342:17 | LL | ptr_opt.map(|p| p.is_null()); | ^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<*const usize>::is_null` error: redundant closure - --> $DIR/eta.rs:339:17 + --> $DIR/eta.rs:346:17 | LL | dyn_opt.map(|d| d.method_on_dyn()); | ^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `::method_on_dyn` diff --git a/tests/ui/excessive_precision.fixed b/tests/ui/excessive_precision.fixed index 0a07957386c2..7bb4da453c1c 100644 --- a/tests/ui/excessive_precision.fixed +++ b/tests/ui/excessive_precision.fixed @@ -1,6 +1,12 @@ //@run-rustfix #![warn(clippy::excessive_precision)] -#![allow(dead_code, unused_variables, clippy::print_literal)] +#![allow( + dead_code, + overflowing_literals, + unused_variables, + clippy::print_literal, + clippy::useless_vec +)] fn main() { // Consts @@ -66,4 +72,11 @@ fn main() { // issue #7745 let _ = 0_f64; + + // issue #9910 + const INF1: f32 = 1.0e+33f32; + const INF2: f64 = 1.0e+3300f64; + const NEG_INF1: f32 = -1.0e+33f32; + const NEG_INF2: f64 = -1.0e+3300f64; + const NEG_INF3: f32 = -3.40282357e+38_f32; } diff --git a/tests/ui/excessive_precision.rs b/tests/ui/excessive_precision.rs index 62a832caa67b..e8d6ab6870a4 100644 --- a/tests/ui/excessive_precision.rs +++ b/tests/ui/excessive_precision.rs @@ -1,6 +1,12 @@ //@run-rustfix #![warn(clippy::excessive_precision)] -#![allow(dead_code, unused_variables, clippy::print_literal)] +#![allow( + dead_code, + overflowing_literals, + unused_variables, + clippy::print_literal, + clippy::useless_vec +)] fn main() { // Consts @@ -66,4 +72,11 @@ fn main() { // issue #7745 let _ = 1.000_000_000_000_001e-324_f64; + + // issue #9910 + const INF1: f32 = 1.0e+33f32; + const INF2: f64 = 1.0e+3300f64; + const NEG_INF1: f32 = -1.0e+33f32; + const NEG_INF2: f64 = -1.0e+3300f64; + const NEG_INF3: f32 = -3.40282357e+38_f32; } diff --git a/tests/ui/excessive_precision.stderr b/tests/ui/excessive_precision.stderr index 42d9d4de193c..348ad183d7d7 100644 --- a/tests/ui/excessive_precision.stderr +++ b/tests/ui/excessive_precision.stderr @@ -1,5 +1,5 @@ error: float has excessive precision - --> $DIR/excessive_precision.rs:15:26 + --> $DIR/excessive_precision.rs:21:26 | LL | const BAD32_1: f32 = 0.123_456_789_f32; | ^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_79_f32` @@ -7,85 +7,85 @@ LL | const BAD32_1: f32 = 0.123_456_789_f32; = note: `-D clippy::excessive-precision` implied by `-D warnings` error: float has excessive precision - --> $DIR/excessive_precision.rs:16:26 + --> $DIR/excessive_precision.rs:22:26 | LL | const BAD32_2: f32 = 0.123_456_789; | ^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_79` error: float has excessive precision - --> $DIR/excessive_precision.rs:17:26 + --> $DIR/excessive_precision.rs:23:26 | LL | const BAD32_3: f32 = 0.100_000_000_000_1; | ^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.1` error: float has excessive precision - --> $DIR/excessive_precision.rs:18:29 + --> $DIR/excessive_precision.rs:24:29 | LL | const BAD32_EDGE: f32 = 1.000_000_9; | ^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.000_001` error: float has excessive precision - --> $DIR/excessive_precision.rs:22:26 + --> $DIR/excessive_precision.rs:28:26 | LL | const BAD64_3: f64 = 0.100_000_000_000_000_000_1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.1` error: float has excessive precision - --> $DIR/excessive_precision.rs:25:22 + --> $DIR/excessive_precision.rs:31:22 | LL | println!("{:?}", 8.888_888_888_888_888_888_888); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `8.888_888_888_888_89` error: float has excessive precision - --> $DIR/excessive_precision.rs:36:22 + --> $DIR/excessive_precision.rs:42:22 | LL | let bad32: f32 = 1.123_456_789; | ^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8` error: float has excessive precision - --> $DIR/excessive_precision.rs:37:26 + --> $DIR/excessive_precision.rs:43:26 | LL | let bad32_suf: f32 = 1.123_456_789_f32; | ^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8_f32` error: float has excessive precision - --> $DIR/excessive_precision.rs:38:21 + --> $DIR/excessive_precision.rs:44:21 | LL | let bad32_inf = 1.123_456_789_f32; | ^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8_f32` error: float has excessive precision - --> $DIR/excessive_precision.rs:48:36 + --> $DIR/excessive_precision.rs:54:36 | LL | let bad_vec32: Vec = vec![0.123_456_789]; | ^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_79` error: float has excessive precision - --> $DIR/excessive_precision.rs:49:36 + --> $DIR/excessive_precision.rs:55:36 | LL | let bad_vec64: Vec = vec![0.123_456_789_123_456_789]; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_123_456_78` error: float has excessive precision - --> $DIR/excessive_precision.rs:53:24 + --> $DIR/excessive_precision.rs:59:24 | LL | let bad_e32: f32 = 1.123_456_788_888e-10; | ^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8e-10` error: float has excessive precision - --> $DIR/excessive_precision.rs:56:27 + --> $DIR/excessive_precision.rs:62:27 | LL | let bad_bige32: f32 = 1.123_456_788_888E-10; | ^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8E-10` error: float has excessive precision - --> $DIR/excessive_precision.rs:65:13 + --> $DIR/excessive_precision.rs:71:13 | LL | let _ = 2.225_073_858_507_201_1e-308_f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `2.225_073_858_507_201e-308_f64` error: float has excessive precision - --> $DIR/excessive_precision.rs:68:13 + --> $DIR/excessive_precision.rs:74:13 | LL | let _ = 1.000_000_000_000_001e-324_f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0_f64` diff --git a/tests/ui/expect.rs b/tests/ui/expect.rs index d742595e14d4..1588579bb0f2 100644 --- a/tests/ui/expect.rs +++ b/tests/ui/expect.rs @@ -1,4 +1,5 @@ #![warn(clippy::expect_used)] +#![allow(clippy::unnecessary_literal_unwrap)] fn expect_option() { let opt = Some(0); diff --git a/tests/ui/expect.stderr b/tests/ui/expect.stderr index c08e0dbbf744..be340340d477 100644 --- a/tests/ui/expect.stderr +++ b/tests/ui/expect.stderr @@ -1,5 +1,5 @@ error: used `expect()` on an `Option` value - --> $DIR/expect.rs:5:13 + --> $DIR/expect.rs:6:13 | LL | let _ = opt.expect(""); | ^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | let _ = opt.expect(""); = note: `-D clippy::expect-used` implied by `-D warnings` error: used `expect()` on a `Result` value - --> $DIR/expect.rs:10:13 + --> $DIR/expect.rs:11:13 | LL | let _ = res.expect(""); | ^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | let _ = res.expect(""); = help: if this value is an `Err`, it will panic error: used `expect_err()` on a `Result` value - --> $DIR/expect.rs:11:13 + --> $DIR/expect.rs:12:13 | LL | let _ = res.expect_err(""); | ^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/expect_fun_call.fixed b/tests/ui/expect_fun_call.fixed index 8e97054fb6bc..73c6c97de84b 100644 --- a/tests/ui/expect_fun_call.fixed +++ b/tests/ui/expect_fun_call.fixed @@ -1,6 +1,10 @@ //@run-rustfix #![warn(clippy::expect_fun_call)] -#![allow(clippy::to_string_in_format_args, clippy::uninlined_format_args)] +#![allow( + clippy::to_string_in_format_args, + clippy::uninlined_format_args, + clippy::unnecessary_literal_unwrap +)] /// Checks implementation of the `EXPECT_FUN_CALL` lint diff --git a/tests/ui/expect_fun_call.rs b/tests/ui/expect_fun_call.rs index 31e6bcc7ff64..a786138631c8 100644 --- a/tests/ui/expect_fun_call.rs +++ b/tests/ui/expect_fun_call.rs @@ -1,6 +1,10 @@ //@run-rustfix #![warn(clippy::expect_fun_call)] -#![allow(clippy::to_string_in_format_args, clippy::uninlined_format_args)] +#![allow( + clippy::to_string_in_format_args, + clippy::uninlined_format_args, + clippy::unnecessary_literal_unwrap +)] /// Checks implementation of the `EXPECT_FUN_CALL` lint diff --git a/tests/ui/expect_fun_call.stderr b/tests/ui/expect_fun_call.stderr index cb55e32aee02..36fb0e5de156 100644 --- a/tests/ui/expect_fun_call.stderr +++ b/tests/ui/expect_fun_call.stderr @@ -1,5 +1,5 @@ error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:34:26 + --> $DIR/expect_fun_call.rs:38:26 | LL | with_none_and_format.expect(&format!("Error {}: fake error", error_code)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))` @@ -7,85 +7,85 @@ LL | with_none_and_format.expect(&format!("Error {}: fake error", error_code = note: `-D clippy::expect-fun-call` implied by `-D warnings` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:37:26 + --> $DIR/expect_fun_call.rs:41:26 | LL | with_none_and_as_str.expect(format!("Error {}: fake error", error_code).as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:40:37 + --> $DIR/expect_fun_call.rs:44:37 | LL | with_none_and_format_with_macro.expect(format!("Error {}: fake error", one!()).as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", one!()))` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:50:25 + --> $DIR/expect_fun_call.rs:54:25 | LL | with_err_and_format.expect(&format!("Error {}: fake error", error_code)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:53:25 + --> $DIR/expect_fun_call.rs:57:25 | LL | with_err_and_as_str.expect(format!("Error {}: fake error", error_code).as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:65:17 + --> $DIR/expect_fun_call.rs:69:17 | LL | Some("foo").expect(format!("{} {}", 1, 2).as_ref()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{} {}", 1, 2))` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:86:21 + --> $DIR/expect_fun_call.rs:90:21 | LL | Some("foo").expect(&get_string()); | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_string()) })` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:87:21 + --> $DIR/expect_fun_call.rs:91:21 | LL | Some("foo").expect(get_string().as_ref()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_string()) })` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:88:21 + --> $DIR/expect_fun_call.rs:92:21 | LL | Some("foo").expect(get_string().as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_string()) })` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:90:21 + --> $DIR/expect_fun_call.rs:94:21 | LL | Some("foo").expect(get_static_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_static_str()) })` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:91:21 + --> $DIR/expect_fun_call.rs:95:21 | LL | Some("foo").expect(get_non_static_str(&0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_non_static_str(&0).to_string()) })` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:95:16 + --> $DIR/expect_fun_call.rs:99:16 | LL | Some(true).expect(&format!("key {}, {}", 1, 2)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("key {}, {}", 1, 2))` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:101:17 + --> $DIR/expect_fun_call.rs:105:17 | LL | opt_ref.expect(&format!("{:?}", opt_ref)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{:?}", opt_ref))` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:105:20 + --> $DIR/expect_fun_call.rs:109:20 | LL | format_capture.expect(&format!("{error_code}")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{error_code}"))` error: use of `expect` followed by a function call - --> $DIR/expect_fun_call.rs:108:30 + --> $DIR/expect_fun_call.rs:112:30 | LL | format_capture_and_value.expect(&format!("{error_code}, {}", 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{error_code}, {}", 1))` diff --git a/tests/ui/expect_tool_lint_rfc_2383.rs b/tests/ui/expect_tool_lint_rfc_2383.rs index 0415e33b3fa1..2460f33434d1 100644 --- a/tests/ui/expect_tool_lint_rfc_2383.rs +++ b/tests/ui/expect_tool_lint_rfc_2383.rs @@ -1,4 +1,3 @@ -// check-pass #![feature(lint_reasons)] //! This file tests the `#[expect]` attribute implementation for tool lints. The same //! file is used to test clippy and rustdoc. Any changes to this file should be synced @@ -12,6 +11,7 @@ //! This test can't cover every lint from Clippy, rustdoc and potentially other //! tools that will be developed. This therefore only tests a small subset of lints #![expect(rustdoc::missing_crate_level_docs)] +#![allow(clippy::needless_if)] mod rustc_ok { //! See diff --git a/tests/ui/explicit_counter_loop.rs b/tests/ui/explicit_counter_loop.rs index 46565a97f005..e02b8f62b3dd 100644 --- a/tests/ui/explicit_counter_loop.rs +++ b/tests/ui/explicit_counter_loop.rs @@ -1,5 +1,5 @@ #![warn(clippy::explicit_counter_loop)] -#![allow(clippy::uninlined_format_args)] +#![allow(clippy::uninlined_format_args, clippy::useless_vec)] fn main() { let mut vec = vec![1, 2, 3, 4]; @@ -23,6 +23,54 @@ fn main() { for _v in vec { _index += 1; } + + let vec = [1, 2, 3, 4]; + // Potential false positives + let mut _index = 0; + _index = 1; + for _v in &vec { + _index += 1 + } + + let mut _index = 0; + _index += 1; + for _v in &vec { + _index += 1 + } + + let mut _index = 0; + for _v in &vec { + _index = 1; + _index += 1 + } + + let mut _index = 0; + for _v in &vec { + let mut _index = 0; + _index += 1 + } + + let mut _index = 0; + for _v in &vec { + _index += 1; + _index = 0; + } + + let mut _index = 0; + if true { + _index = 1 + }; + for _v in &vec { + _index += 1 + } + + let mut _index = 1; + if false { + _index = 0 + }; + for _v in &vec { + _index += 1 + } } mod issue_1219 { diff --git a/tests/ui/explicit_counter_loop.stderr b/tests/ui/explicit_counter_loop.stderr index d3f3c626bbdf..0677e4d78c8b 100644 --- a/tests/ui/explicit_counter_loop.stderr +++ b/tests/ui/explicit_counter_loop.stderr @@ -25,31 +25,31 @@ LL | for _v in vec { | ^^^^^^^^^^^^^ help: consider using: `for (_index, _v) in vec.into_iter().enumerate()` error: the variable `count` is used as a loop counter - --> $DIR/explicit_counter_loop.rs:62:9 + --> $DIR/explicit_counter_loop.rs:110:9 | LL | for ch in text.chars() { | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `for (count, ch) in text.chars().enumerate()` error: the variable `count` is used as a loop counter - --> $DIR/explicit_counter_loop.rs:73:9 + --> $DIR/explicit_counter_loop.rs:121:9 | LL | for ch in text.chars() { | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `for (count, ch) in text.chars().enumerate()` error: the variable `count` is used as a loop counter - --> $DIR/explicit_counter_loop.rs:131:9 + --> $DIR/explicit_counter_loop.rs:179:9 | LL | for _i in 3..10 { | ^^^^^^^^^^^^^^^ help: consider using: `for (count, _i) in (3..10).enumerate()` error: the variable `idx_usize` is used as a loop counter - --> $DIR/explicit_counter_loop.rs:171:9 + --> $DIR/explicit_counter_loop.rs:219:9 | LL | for _item in slice { | ^^^^^^^^^^^^^^^^^^ help: consider using: `for (idx_usize, _item) in slice.iter().enumerate()` error: the variable `idx_u32` is used as a loop counter - --> $DIR/explicit_counter_loop.rs:183:9 + --> $DIR/explicit_counter_loop.rs:231:9 | LL | for _item in slice { | ^^^^^^^^^^^^^^^^^^ help: consider using: `for (idx_u32, _item) in (0_u32..).zip(slice.iter())` diff --git a/tests/ui/explicit_deref_methods.fixed b/tests/ui/explicit_deref_methods.fixed index 60482c66da7c..4d72b58cdf86 100644 --- a/tests/ui/explicit_deref_methods.fixed +++ b/tests/ui/explicit_deref_methods.fixed @@ -1,12 +1,14 @@ //@run-rustfix #![warn(clippy::explicit_deref_methods)] -#![allow(unused_variables)] +#![allow(unused_variables, unused_must_use)] #![allow( clippy::borrow_deref_ref, suspicious_double_ref_op, clippy::explicit_auto_deref, clippy::needless_borrow, - clippy::uninlined_format_args + clippy::no_effect, + clippy::uninlined_format_args, + clippy::unnecessary_literal_unwrap )] use std::ops::{Deref, DerefMut}; @@ -28,6 +30,22 @@ impl Deref for CustomVec { } } +struct Aaa; + +impl Deref for Aaa { + type Target = (); + + fn deref(&self) -> &Self::Target { + todo!(); + } +} + +impl DerefMut for Aaa { + fn deref_mut(&mut self) -> &mut Self::Target { + todo!(); + } +} + fn main() { let a: &mut String = &mut String::from("foo"); @@ -58,6 +76,17 @@ fn main() { let opt_a = Some(a.clone()); let b = &*opt_a.unwrap(); + // make sure `Aaa::deref` instead of `aaa.deref()` is not linted, as well as fully qualified + // syntax + + Aaa::deref(&Aaa); + Aaa::deref_mut(&mut Aaa); + ::deref(&Aaa); + ::deref_mut(&mut Aaa); + let mut aaa = Aaa; + Aaa::deref(&aaa); + Aaa::deref_mut(&mut aaa); + // following should not require linting let cv = CustomVec(vec![0, 42]); diff --git a/tests/ui/explicit_deref_methods.rs b/tests/ui/explicit_deref_methods.rs index e3613e216bb2..fcd945de3386 100644 --- a/tests/ui/explicit_deref_methods.rs +++ b/tests/ui/explicit_deref_methods.rs @@ -1,12 +1,14 @@ //@run-rustfix #![warn(clippy::explicit_deref_methods)] -#![allow(unused_variables)] +#![allow(unused_variables, unused_must_use)] #![allow( clippy::borrow_deref_ref, suspicious_double_ref_op, clippy::explicit_auto_deref, clippy::needless_borrow, - clippy::uninlined_format_args + clippy::no_effect, + clippy::uninlined_format_args, + clippy::unnecessary_literal_unwrap )] use std::ops::{Deref, DerefMut}; @@ -28,6 +30,22 @@ impl Deref for CustomVec { } } +struct Aaa; + +impl Deref for Aaa { + type Target = (); + + fn deref(&self) -> &Self::Target { + todo!(); + } +} + +impl DerefMut for Aaa { + fn deref_mut(&mut self) -> &mut Self::Target { + todo!(); + } +} + fn main() { let a: &mut String = &mut String::from("foo"); @@ -58,6 +76,17 @@ fn main() { let opt_a = Some(a.clone()); let b = opt_a.unwrap().deref(); + // make sure `Aaa::deref` instead of `aaa.deref()` is not linted, as well as fully qualified + // syntax + + Aaa::deref(&Aaa); + Aaa::deref_mut(&mut Aaa); + ::deref(&Aaa); + ::deref_mut(&mut Aaa); + let mut aaa = Aaa; + Aaa::deref(&aaa); + Aaa::deref_mut(&mut aaa); + // following should not require linting let cv = CustomVec(vec![0, 42]); diff --git a/tests/ui/explicit_deref_methods.stderr b/tests/ui/explicit_deref_methods.stderr index 4b10ed1377b0..d025035b7894 100644 --- a/tests/ui/explicit_deref_methods.stderr +++ b/tests/ui/explicit_deref_methods.stderr @@ -1,5 +1,5 @@ error: explicit `deref` method call - --> $DIR/explicit_deref_methods.rs:36:19 + --> $DIR/explicit_deref_methods.rs:54:19 | LL | let b: &str = a.deref(); | ^^^^^^^^^ help: try this: `&*a` @@ -7,67 +7,67 @@ LL | let b: &str = a.deref(); = note: `-D clippy::explicit-deref-methods` implied by `-D warnings` error: explicit `deref_mut` method call - --> $DIR/explicit_deref_methods.rs:38:23 + --> $DIR/explicit_deref_methods.rs:56:23 | LL | let b: &mut str = a.deref_mut(); | ^^^^^^^^^^^^^ help: try this: `&mut **a` error: explicit `deref` method call - --> $DIR/explicit_deref_methods.rs:41:39 + --> $DIR/explicit_deref_methods.rs:59:39 | LL | let b: String = format!("{}, {}", a.deref(), a.deref()); | ^^^^^^^^^ help: try this: `&*a` error: explicit `deref` method call - --> $DIR/explicit_deref_methods.rs:41:50 + --> $DIR/explicit_deref_methods.rs:59:50 | LL | let b: String = format!("{}, {}", a.deref(), a.deref()); | ^^^^^^^^^ help: try this: `&*a` error: explicit `deref` method call - --> $DIR/explicit_deref_methods.rs:43:20 + --> $DIR/explicit_deref_methods.rs:61:20 | LL | println!("{}", a.deref()); | ^^^^^^^^^ help: try this: `&*a` error: explicit `deref` method call - --> $DIR/explicit_deref_methods.rs:46:11 + --> $DIR/explicit_deref_methods.rs:64:11 | LL | match a.deref() { | ^^^^^^^^^ help: try this: `&*a` error: explicit `deref` method call - --> $DIR/explicit_deref_methods.rs:50:28 + --> $DIR/explicit_deref_methods.rs:68:28 | LL | let b: String = concat(a.deref()); | ^^^^^^^^^ help: try this: `&*a` error: explicit `deref` method call - --> $DIR/explicit_deref_methods.rs:52:13 + --> $DIR/explicit_deref_methods.rs:70:13 | LL | let b = just_return(a).deref(); | ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `just_return(a)` error: explicit `deref` method call - --> $DIR/explicit_deref_methods.rs:54:28 + --> $DIR/explicit_deref_methods.rs:72:28 | LL | let b: String = concat(just_return(a).deref()); | ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `just_return(a)` error: explicit `deref` method call - --> $DIR/explicit_deref_methods.rs:56:19 + --> $DIR/explicit_deref_methods.rs:74:19 | LL | let b: &str = a.deref().deref(); | ^^^^^^^^^^^^^^^^^ help: try this: `&**a` error: explicit `deref` method call - --> $DIR/explicit_deref_methods.rs:59:13 + --> $DIR/explicit_deref_methods.rs:77:13 | LL | let b = opt_a.unwrap().deref(); | ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&*opt_a.unwrap()` error: explicit `deref` method call - --> $DIR/explicit_deref_methods.rs:85:31 + --> $DIR/explicit_deref_methods.rs:114:31 | LL | let b: &str = expr_deref!(a.deref()); | ^^^^^^^^^ help: try this: `&*a` diff --git a/tests/ui/explicit_into_iter_loop.fixed b/tests/ui/explicit_into_iter_loop.fixed new file mode 100644 index 000000000000..dcef63403114 --- /dev/null +++ b/tests/ui/explicit_into_iter_loop.fixed @@ -0,0 +1,69 @@ +//@run-rustfix +#![warn(clippy::explicit_into_iter_loop)] + +fn main() { + // Issue #4958 + fn _takes_iterator(iterator: &T) + where + for<'a> &'a T: IntoIterator, + { + for _ in iterator {} + } + + struct T; + impl IntoIterator for &T { + type Item = (); + type IntoIter = std::vec::IntoIter; + fn into_iter(self) -> Self::IntoIter { + unimplemented!() + } + } + + let mut t = T; + for _ in &t {} + + let r = &t; + for _ in r {} + + // No suggestion for this. + // We'd have to suggest `for _ in *rr {}` which is less clear. + let rr = &&t; + for _ in rr.into_iter() {} + + let mr = &mut t; + for _ in &*mr {} + + struct U; + impl IntoIterator for &mut U { + type Item = (); + type IntoIter = std::vec::IntoIter; + fn into_iter(self) -> Self::IntoIter { + unimplemented!() + } + } + + let mut u = U; + for _ in &mut u {} + + let mr = &mut u; + for _ in &mut *mr {} + + // Issue #6900 + struct S; + impl S { + #[allow(clippy::should_implement_trait)] + pub fn into_iter(self) -> I { + unimplemented!() + } + } + + struct I(T); + impl Iterator for I { + type Item = T; + fn next(&mut self) -> Option { + unimplemented!() + } + } + + for _ in S.into_iter::() {} +} diff --git a/tests/ui/explicit_into_iter_loop.rs b/tests/ui/explicit_into_iter_loop.rs new file mode 100644 index 000000000000..bc048ed302bf --- /dev/null +++ b/tests/ui/explicit_into_iter_loop.rs @@ -0,0 +1,69 @@ +//@run-rustfix +#![warn(clippy::explicit_into_iter_loop)] + +fn main() { + // Issue #4958 + fn _takes_iterator(iterator: &T) + where + for<'a> &'a T: IntoIterator, + { + for _ in iterator.into_iter() {} + } + + struct T; + impl IntoIterator for &T { + type Item = (); + type IntoIter = std::vec::IntoIter; + fn into_iter(self) -> Self::IntoIter { + unimplemented!() + } + } + + let mut t = T; + for _ in t.into_iter() {} + + let r = &t; + for _ in r.into_iter() {} + + // No suggestion for this. + // We'd have to suggest `for _ in *rr {}` which is less clear. + let rr = &&t; + for _ in rr.into_iter() {} + + let mr = &mut t; + for _ in mr.into_iter() {} + + struct U; + impl IntoIterator for &mut U { + type Item = (); + type IntoIter = std::vec::IntoIter; + fn into_iter(self) -> Self::IntoIter { + unimplemented!() + } + } + + let mut u = U; + for _ in u.into_iter() {} + + let mr = &mut u; + for _ in mr.into_iter() {} + + // Issue #6900 + struct S; + impl S { + #[allow(clippy::should_implement_trait)] + pub fn into_iter(self) -> I { + unimplemented!() + } + } + + struct I(T); + impl Iterator for I { + type Item = T; + fn next(&mut self) -> Option { + unimplemented!() + } + } + + for _ in S.into_iter::() {} +} diff --git a/tests/ui/explicit_into_iter_loop.stderr b/tests/ui/explicit_into_iter_loop.stderr new file mode 100644 index 000000000000..fa89b884fa0f --- /dev/null +++ b/tests/ui/explicit_into_iter_loop.stderr @@ -0,0 +1,40 @@ +error: it is more concise to loop over containers instead of using explicit iteration methods + --> $DIR/explicit_into_iter_loop.rs:10:18 + | +LL | for _ in iterator.into_iter() {} + | ^^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `iterator` + | + = note: `-D clippy::explicit-into-iter-loop` implied by `-D warnings` + +error: it is more concise to loop over containers instead of using explicit iteration methods + --> $DIR/explicit_into_iter_loop.rs:23:14 + | +LL | for _ in t.into_iter() {} + | ^^^^^^^^^^^^^ help: to write this more concisely, try: `&t` + +error: it is more concise to loop over containers instead of using explicit iteration methods + --> $DIR/explicit_into_iter_loop.rs:26:14 + | +LL | for _ in r.into_iter() {} + | ^^^^^^^^^^^^^ help: to write this more concisely, try: `r` + +error: it is more concise to loop over containers instead of using explicit iteration methods + --> $DIR/explicit_into_iter_loop.rs:34:14 + | +LL | for _ in mr.into_iter() {} + | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&*mr` + +error: it is more concise to loop over containers instead of using explicit iteration methods + --> $DIR/explicit_into_iter_loop.rs:46:14 + | +LL | for _ in u.into_iter() {} + | ^^^^^^^^^^^^^ help: to write this more concisely, try: `&mut u` + +error: it is more concise to loop over containers instead of using explicit iteration methods + --> $DIR/explicit_into_iter_loop.rs:49:14 + | +LL | for _ in mr.into_iter() {} + | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&mut *mr` + +error: aborting due to 6 previous errors + diff --git a/tests/ui/explicit_iter_loop.fixed b/tests/ui/explicit_iter_loop.fixed new file mode 100644 index 000000000000..746ef813c048 --- /dev/null +++ b/tests/ui/explicit_iter_loop.fixed @@ -0,0 +1,154 @@ +//@run-rustfix +#![deny(clippy::explicit_iter_loop)] +#![allow( + clippy::linkedlist, + clippy::similar_names, + clippy::needless_borrow, + clippy::deref_addrof, + dead_code +)] + +use core::slice; +use std::collections::*; + +fn main() { + let mut vec = vec![1, 2, 3, 4]; + + for _ in &vec {} + for _ in &mut vec {} + + let rvec = &vec; + for _ in rvec {} + + let rmvec = &mut vec; + for _ in &*rmvec {} + for _ in &mut *rmvec {} + + for _ in &vec {} // these are fine + for _ in &mut vec {} // these are fine + + for _ in &[1, 2, 3] {} + + for _ in &*(&mut [1, 2, 3]) {} + + for _ in &[0; 32] {} + for _ in &[0; 33] {} + + let ll: LinkedList<()> = LinkedList::new(); + for _ in &ll {} + let rll = ≪ + for _ in rll {} + + let vd: VecDeque<()> = VecDeque::new(); + for _ in &vd {} + let rvd = &vd; + for _ in rvd {} + + let bh: BinaryHeap<()> = BinaryHeap::new(); + for _ in &bh {} + + let hm: HashMap<(), ()> = HashMap::new(); + for _ in &hm {} + + let bt: BTreeMap<(), ()> = BTreeMap::new(); + for _ in &bt {} + + let hs: HashSet<()> = HashSet::new(); + for _ in &hs {} + + let bs: BTreeSet<()> = BTreeSet::new(); + for _ in &bs {} + + struct NoIntoIter(); + impl NoIntoIter { + fn iter(&self) -> slice::Iter { + unimplemented!() + } + + fn iter_mut(&mut self) -> slice::IterMut { + unimplemented!() + } + } + let mut x = NoIntoIter(); + for _ in x.iter() {} // no error + for _ in x.iter_mut() {} // no error + + struct IntoIterDiffTy; + impl IntoIterator for &'_ IntoIterDiffTy { + type Item = &'static (); + type IntoIter = core::slice::Iter<'static, ()>; + fn into_iter(self) -> Self::IntoIter { + unimplemented!() + } + } + impl IntoIterDiffTy { + fn iter(&self) -> core::slice::Iter<'static, i32> { + unimplemented!() + } + } + let x = IntoIterDiffTy; + for _ in x.iter() {} + + struct IntoIterDiffSig; + impl IntoIterator for &'_ IntoIterDiffSig { + type Item = &'static (); + type IntoIter = core::slice::Iter<'static, ()>; + fn into_iter(self) -> Self::IntoIter { + unimplemented!() + } + } + impl IntoIterDiffSig { + fn iter(&self, _: u32) -> core::slice::Iter<'static, ()> { + unimplemented!() + } + } + let x = IntoIterDiffSig; + for _ in x.iter(0) {} + + struct IntoIterDiffLt<'a>(&'a ()); + impl<'a> IntoIterator for &'a IntoIterDiffLt<'_> { + type Item = &'a (); + type IntoIter = core::slice::Iter<'a, ()>; + fn into_iter(self) -> Self::IntoIter { + unimplemented!() + } + } + impl<'a> IntoIterDiffLt<'a> { + fn iter(&self) -> core::slice::Iter<'a, ()> { + unimplemented!() + } + } + let x = IntoIterDiffLt(&()); + for _ in x.iter() {} + + struct CustomType; + impl<'a> IntoIterator for &'a CustomType { + type Item = &'a u32; + type IntoIter = core::slice::Iter<'a, u32>; + fn into_iter(self) -> Self::IntoIter { + unimplemented!() + } + } + impl<'a> IntoIterator for &'a mut CustomType { + type Item = &'a mut u32; + type IntoIter = core::slice::IterMut<'a, u32>; + fn into_iter(self) -> Self::IntoIter { + unimplemented!() + } + } + impl CustomType { + fn iter(&self) -> <&'_ Self as IntoIterator>::IntoIter { + panic!() + } + + fn iter_mut(&mut self) -> core::slice::IterMut<'_, u32> { + panic!() + } + } + let mut x = CustomType; + for _ in &x {} + for _ in &mut x {} + + let r = &x; + for _ in r {} +} diff --git a/tests/ui/explicit_iter_loop.rs b/tests/ui/explicit_iter_loop.rs new file mode 100644 index 000000000000..fba230ee0eea --- /dev/null +++ b/tests/ui/explicit_iter_loop.rs @@ -0,0 +1,154 @@ +//@run-rustfix +#![deny(clippy::explicit_iter_loop)] +#![allow( + clippy::linkedlist, + clippy::similar_names, + clippy::needless_borrow, + clippy::deref_addrof, + dead_code +)] + +use core::slice; +use std::collections::*; + +fn main() { + let mut vec = vec![1, 2, 3, 4]; + + for _ in vec.iter() {} + for _ in vec.iter_mut() {} + + let rvec = &vec; + for _ in rvec.iter() {} + + let rmvec = &mut vec; + for _ in rmvec.iter() {} + for _ in rmvec.iter_mut() {} + + for _ in &vec {} // these are fine + for _ in &mut vec {} // these are fine + + for _ in [1, 2, 3].iter() {} + + for _ in (&mut [1, 2, 3]).iter() {} + + for _ in [0; 32].iter() {} + for _ in [0; 33].iter() {} + + let ll: LinkedList<()> = LinkedList::new(); + for _ in ll.iter() {} + let rll = ≪ + for _ in rll.iter() {} + + let vd: VecDeque<()> = VecDeque::new(); + for _ in vd.iter() {} + let rvd = &vd; + for _ in rvd.iter() {} + + let bh: BinaryHeap<()> = BinaryHeap::new(); + for _ in bh.iter() {} + + let hm: HashMap<(), ()> = HashMap::new(); + for _ in hm.iter() {} + + let bt: BTreeMap<(), ()> = BTreeMap::new(); + for _ in bt.iter() {} + + let hs: HashSet<()> = HashSet::new(); + for _ in hs.iter() {} + + let bs: BTreeSet<()> = BTreeSet::new(); + for _ in bs.iter() {} + + struct NoIntoIter(); + impl NoIntoIter { + fn iter(&self) -> slice::Iter { + unimplemented!() + } + + fn iter_mut(&mut self) -> slice::IterMut { + unimplemented!() + } + } + let mut x = NoIntoIter(); + for _ in x.iter() {} // no error + for _ in x.iter_mut() {} // no error + + struct IntoIterDiffTy; + impl IntoIterator for &'_ IntoIterDiffTy { + type Item = &'static (); + type IntoIter = core::slice::Iter<'static, ()>; + fn into_iter(self) -> Self::IntoIter { + unimplemented!() + } + } + impl IntoIterDiffTy { + fn iter(&self) -> core::slice::Iter<'static, i32> { + unimplemented!() + } + } + let x = IntoIterDiffTy; + for _ in x.iter() {} + + struct IntoIterDiffSig; + impl IntoIterator for &'_ IntoIterDiffSig { + type Item = &'static (); + type IntoIter = core::slice::Iter<'static, ()>; + fn into_iter(self) -> Self::IntoIter { + unimplemented!() + } + } + impl IntoIterDiffSig { + fn iter(&self, _: u32) -> core::slice::Iter<'static, ()> { + unimplemented!() + } + } + let x = IntoIterDiffSig; + for _ in x.iter(0) {} + + struct IntoIterDiffLt<'a>(&'a ()); + impl<'a> IntoIterator for &'a IntoIterDiffLt<'_> { + type Item = &'a (); + type IntoIter = core::slice::Iter<'a, ()>; + fn into_iter(self) -> Self::IntoIter { + unimplemented!() + } + } + impl<'a> IntoIterDiffLt<'a> { + fn iter(&self) -> core::slice::Iter<'a, ()> { + unimplemented!() + } + } + let x = IntoIterDiffLt(&()); + for _ in x.iter() {} + + struct CustomType; + impl<'a> IntoIterator for &'a CustomType { + type Item = &'a u32; + type IntoIter = core::slice::Iter<'a, u32>; + fn into_iter(self) -> Self::IntoIter { + unimplemented!() + } + } + impl<'a> IntoIterator for &'a mut CustomType { + type Item = &'a mut u32; + type IntoIter = core::slice::IterMut<'a, u32>; + fn into_iter(self) -> Self::IntoIter { + unimplemented!() + } + } + impl CustomType { + fn iter(&self) -> <&'_ Self as IntoIterator>::IntoIter { + panic!() + } + + fn iter_mut(&mut self) -> core::slice::IterMut<'_, u32> { + panic!() + } + } + let mut x = CustomType; + for _ in x.iter() {} + for _ in x.iter_mut() {} + + let r = &x; + for _ in r.iter() {} +} diff --git a/tests/ui/explicit_iter_loop.stderr b/tests/ui/explicit_iter_loop.stderr new file mode 100644 index 000000000000..94a264dcea8d --- /dev/null +++ b/tests/ui/explicit_iter_loop.stderr @@ -0,0 +1,142 @@ +error: it is more concise to loop over references to containers instead of using explicit iteration methods + --> $DIR/explicit_iter_loop.rs:17:14 + | +LL | for _ in vec.iter() {} + | ^^^^^^^^^^ help: to write this more concisely, try: `&vec` + | +note: the lint level is defined here + --> $DIR/explicit_iter_loop.rs:2:9 + | +LL | #![deny(clippy::explicit_iter_loop)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: it is more concise to loop over references to containers instead of using explicit iteration methods + --> $DIR/explicit_iter_loop.rs:18:14 + | +LL | for _ in vec.iter_mut() {} + | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&mut vec` + +error: it is more concise to loop over references to containers instead of using explicit iteration methods + --> $DIR/explicit_iter_loop.rs:21:14 + | +LL | for _ in rvec.iter() {} + | ^^^^^^^^^^^ help: to write this more concisely, try: `rvec` + +error: it is more concise to loop over references to containers instead of using explicit iteration methods + --> $DIR/explicit_iter_loop.rs:24:14 + | +LL | for _ in rmvec.iter() {} + | ^^^^^^^^^^^^ help: to write this more concisely, try: `&*rmvec` + +error: it is more concise to loop over references to containers instead of using explicit iteration methods + --> $DIR/explicit_iter_loop.rs:25:14 + | +LL | for _ in rmvec.iter_mut() {} + | ^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `&mut *rmvec` + +error: it is more concise to loop over references to containers instead of using explicit iteration methods + --> $DIR/explicit_iter_loop.rs:30:14 + | +LL | for _ in [1, 2, 3].iter() {} + | ^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[1, 2, 3]` + +error: it is more concise to loop over references to containers instead of using explicit iteration methods + --> $DIR/explicit_iter_loop.rs:32:14 + | +LL | for _ in (&mut [1, 2, 3]).iter() {} + | ^^^^^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `&*(&mut [1, 2, 3])` + +error: the method `iter` doesn't need a mutable reference + --> $DIR/explicit_iter_loop.rs:32:14 + | +LL | for _ in (&mut [1, 2, 3]).iter() {} + | ^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::unnecessary-mut-passed` implied by `-D warnings` + +error: it is more concise to loop over references to containers instead of using explicit iteration methods + --> $DIR/explicit_iter_loop.rs:34:14 + | +LL | for _ in [0; 32].iter() {} + | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[0; 32]` + +error: it is more concise to loop over references to containers instead of using explicit iteration methods + --> $DIR/explicit_iter_loop.rs:35:14 + | +LL | for _ in [0; 33].iter() {} + | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[0; 33]` + +error: it is more concise to loop over references to containers instead of using explicit iteration methods + --> $DIR/explicit_iter_loop.rs:38:14 + | +LL | for _ in ll.iter() {} + | ^^^^^^^^^ help: to write this more concisely, try: `&ll` + +error: it is more concise to loop over references to containers instead of using explicit iteration methods + --> $DIR/explicit_iter_loop.rs:40:14 + | +LL | for _ in rll.iter() {} + | ^^^^^^^^^^ help: to write this more concisely, try: `rll` + +error: it is more concise to loop over references to containers instead of using explicit iteration methods + --> $DIR/explicit_iter_loop.rs:43:14 + | +LL | for _ in vd.iter() {} + | ^^^^^^^^^ help: to write this more concisely, try: `&vd` + +error: it is more concise to loop over references to containers instead of using explicit iteration methods + --> $DIR/explicit_iter_loop.rs:45:14 + | +LL | for _ in rvd.iter() {} + | ^^^^^^^^^^ help: to write this more concisely, try: `rvd` + +error: it is more concise to loop over references to containers instead of using explicit iteration methods + --> $DIR/explicit_iter_loop.rs:48:14 + | +LL | for _ in bh.iter() {} + | ^^^^^^^^^ help: to write this more concisely, try: `&bh` + +error: it is more concise to loop over references to containers instead of using explicit iteration methods + --> $DIR/explicit_iter_loop.rs:51:14 + | +LL | for _ in hm.iter() {} + | ^^^^^^^^^ help: to write this more concisely, try: `&hm` + +error: it is more concise to loop over references to containers instead of using explicit iteration methods + --> $DIR/explicit_iter_loop.rs:54:14 + | +LL | for _ in bt.iter() {} + | ^^^^^^^^^ help: to write this more concisely, try: `&bt` + +error: it is more concise to loop over references to containers instead of using explicit iteration methods + --> $DIR/explicit_iter_loop.rs:57:14 + | +LL | for _ in hs.iter() {} + | ^^^^^^^^^ help: to write this more concisely, try: `&hs` + +error: it is more concise to loop over references to containers instead of using explicit iteration methods + --> $DIR/explicit_iter_loop.rs:60:14 + | +LL | for _ in bs.iter() {} + | ^^^^^^^^^ help: to write this more concisely, try: `&bs` + +error: it is more concise to loop over references to containers instead of using explicit iteration methods + --> $DIR/explicit_iter_loop.rs:149:14 + | +LL | for _ in x.iter() {} + | ^^^^^^^^ help: to write this more concisely, try: `&x` + +error: it is more concise to loop over references to containers instead of using explicit iteration methods + --> $DIR/explicit_iter_loop.rs:150:14 + | +LL | for _ in x.iter_mut() {} + | ^^^^^^^^^^^^ help: to write this more concisely, try: `&mut x` + +error: it is more concise to loop over references to containers instead of using explicit iteration methods + --> $DIR/explicit_iter_loop.rs:153:14 + | +LL | for _ in r.iter() {} + | ^^^^^^^^ help: to write this more concisely, try: `r` + +error: aborting due to 22 previous errors + diff --git a/tests/ui/extra_unused_lifetimes.rs b/tests/ui/extra_unused_lifetimes.rs index cdfaf8d3afea..50abe89da893 100644 --- a/tests/ui/extra_unused_lifetimes.rs +++ b/tests/ui/extra_unused_lifetimes.rs @@ -1,4 +1,4 @@ -//@aux-build:proc_macro_derive.rs +//@aux-build:proc_macro_derive.rs:proc-macro #![allow( unused, diff --git a/tests/ui/extra_unused_type_parameters.fixed b/tests/ui/extra_unused_type_parameters.fixed index adcd1f6d4076..8420df6634d9 100644 --- a/tests/ui/extra_unused_type_parameters.fixed +++ b/tests/ui/extra_unused_type_parameters.fixed @@ -1,8 +1,12 @@ //@run-rustfix +//@aux-build:proc_macros.rs:proc-macro #![allow(unused, clippy::needless_lifetimes)] #![warn(clippy::extra_unused_type_parameters)] +extern crate proc_macros; +use proc_macros::with_span; + fn unused_ty(x: u8) { unimplemented!() } @@ -102,4 +106,12 @@ mod issue10319 { } } +with_span!( + span + + fn should_not_lint(x: u8) { + unimplemented!() + } +); + fn main() {} diff --git a/tests/ui/extra_unused_type_parameters.rs b/tests/ui/extra_unused_type_parameters.rs index c4c5227ac918..f63535d7ae6e 100644 --- a/tests/ui/extra_unused_type_parameters.rs +++ b/tests/ui/extra_unused_type_parameters.rs @@ -1,8 +1,12 @@ //@run-rustfix +//@aux-build:proc_macros.rs:proc-macro #![allow(unused, clippy::needless_lifetimes)] #![warn(clippy::extra_unused_type_parameters)] +extern crate proc_macros; +use proc_macros::with_span; + fn unused_ty(x: u8) { unimplemented!() } @@ -102,4 +106,12 @@ mod issue10319 { } } +with_span!( + span + + fn should_not_lint(x: u8) { + unimplemented!() + } +); + fn main() {} diff --git a/tests/ui/extra_unused_type_parameters.stderr b/tests/ui/extra_unused_type_parameters.stderr index c042a5a2290e..b5277d49861c 100644 --- a/tests/ui/extra_unused_type_parameters.stderr +++ b/tests/ui/extra_unused_type_parameters.stderr @@ -1,5 +1,5 @@ error: type parameter `T` goes unused in function definition - --> $DIR/extra_unused_type_parameters.rs:6:13 + --> $DIR/extra_unused_type_parameters.rs:10:13 | LL | fn unused_ty(x: u8) { | ^^^ help: consider removing the parameter @@ -7,19 +7,19 @@ LL | fn unused_ty(x: u8) { = note: `-D clippy::extra-unused-type-parameters` implied by `-D warnings` error: type parameters go unused in function definition: T, U - --> $DIR/extra_unused_type_parameters.rs:10:16 + --> $DIR/extra_unused_type_parameters.rs:14:16 | LL | fn unused_multi(x: u8) { | ^^^^^^ help: consider removing the parameters error: type parameter `T` goes unused in function definition - --> $DIR/extra_unused_type_parameters.rs:14:21 + --> $DIR/extra_unused_type_parameters.rs:18:21 | LL | fn unused_with_lt<'a, T>(x: &'a u8) { | ^^^ help: consider removing the parameter error: type parameters go unused in function definition: T, V - --> $DIR/extra_unused_type_parameters.rs:26:19 + --> $DIR/extra_unused_type_parameters.rs:30:19 | LL | fn unused_bounded(x: U) { | ^^^^^^^^^^^^ ^^^^^^^^^^^^ @@ -31,7 +31,7 @@ LL + fn unused_bounded(x: U) { | error: type parameters go unused in function definition: A, D, E - --> $DIR/extra_unused_type_parameters.rs:30:16 + --> $DIR/extra_unused_type_parameters.rs:34:16 | LL | fn some_unused, E>(b: B, c: C) { | ^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -43,19 +43,19 @@ LL + fn some_unused(b: B, c: C) { | error: type parameter `T` goes unused in function definition - --> $DIR/extra_unused_type_parameters.rs:55:22 + --> $DIR/extra_unused_type_parameters.rs:59:22 | LL | fn unused_ty_impl(&self) { | ^^^ help: consider removing the parameter error: type parameters go unused in function definition: A, B - --> $DIR/extra_unused_type_parameters.rs:77:17 + --> $DIR/extra_unused_type_parameters.rs:81:17 | LL | fn unused_opaque(dummy: impl Default) { | ^^^^^^ help: consider removing the parameters error: type parameter `U` goes unused in function definition - --> $DIR/extra_unused_type_parameters.rs:90:56 + --> $DIR/extra_unused_type_parameters.rs:94:56 | LL | fn unused_with_priv_trait_bound() { | ^^^ help: consider removing the parameter diff --git a/tests/ui/field_reassign_with_default.rs b/tests/ui/field_reassign_with_default.rs index 2045b1eebcd7..d6df114b8d26 100644 --- a/tests/ui/field_reassign_with_default.rs +++ b/tests/ui/field_reassign_with_default.rs @@ -1,5 +1,5 @@ -//@aux-build:proc_macro_derive.rs -//@aux-build:proc_macros.rs +//@aux-build:proc_macro_derive.rs:proc-macro +//@aux-build:proc_macros.rs:proc-macro #![warn(clippy::field_reassign_with_default)] diff --git a/tests/ui/filetype_is_file.rs b/tests/ui/filetype_is_file.rs index 5de8fe8cdd7b..d3ad36e40b53 100644 --- a/tests/ui/filetype_is_file.rs +++ b/tests/ui/filetype_is_file.rs @@ -1,3 +1,4 @@ +#![allow(clippy::needless_if)] #![warn(clippy::filetype_is_file)] fn main() -> std::io::Result<()> { diff --git a/tests/ui/filetype_is_file.stderr b/tests/ui/filetype_is_file.stderr index e51a90d6cfd2..36142deb3092 100644 --- a/tests/ui/filetype_is_file.stderr +++ b/tests/ui/filetype_is_file.stderr @@ -1,5 +1,5 @@ error: `FileType::is_file()` only covers regular files - --> $DIR/filetype_is_file.rs:8:8 + --> $DIR/filetype_is_file.rs:9:8 | LL | if fs::metadata("foo.txt")?.file_type().is_file() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | if fs::metadata("foo.txt")?.file_type().is_file() { = note: `-D clippy::filetype-is-file` implied by `-D warnings` error: `!FileType::is_file()` only denies regular files - --> $DIR/filetype_is_file.rs:13:8 + --> $DIR/filetype_is_file.rs:14:8 | LL | if !fs::metadata("foo.txt")?.file_type().is_file() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | if !fs::metadata("foo.txt")?.file_type().is_file() { = help: use `FileType::is_dir()` instead error: `FileType::is_file()` only covers regular files - --> $DIR/filetype_is_file.rs:18:9 + --> $DIR/filetype_is_file.rs:19:9 | LL | if !fs::metadata("foo.txt")?.file_type().is_file().bitor(true) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/find_map.rs b/tests/ui/find_map.rs index 88d3b0e74900..bbd395d50ef2 100644 --- a/tests/ui/find_map.rs +++ b/tests/ui/find_map.rs @@ -1,4 +1,5 @@ #![warn(clippy::all, clippy::pedantic)] +#![allow(clippy::useless_vec)] #[derive(Debug, Copy, Clone)] enum Flavor { diff --git a/tests/ui/fn_null_check.rs b/tests/ui/fn_null_check.rs index df5bc8420d57..dfdea100c8fd 100644 --- a/tests/ui/fn_null_check.rs +++ b/tests/ui/fn_null_check.rs @@ -1,6 +1,7 @@ #![allow(unused)] #![warn(clippy::fn_null_check)] #![allow(clippy::cmp_null)] +#![allow(clippy::needless_if)] #![allow(clippy::ptr_eq)] #![allow(clippy::zero_ptr)] diff --git a/tests/ui/fn_null_check.stderr b/tests/ui/fn_null_check.stderr index 660dd3239792..5b9f48a961ca 100644 --- a/tests/ui/fn_null_check.stderr +++ b/tests/ui/fn_null_check.stderr @@ -1,5 +1,5 @@ error: function pointer assumed to be nullable, even though it isn't - --> $DIR/fn_null_check.rs:13:8 + --> $DIR/fn_null_check.rs:14:8 | LL | if (fn_ptr as *mut ()).is_null() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | if (fn_ptr as *mut ()).is_null() {} = note: `-D clippy::fn-null-check` implied by `-D warnings` error: function pointer assumed to be nullable, even though it isn't - --> $DIR/fn_null_check.rs:14:8 + --> $DIR/fn_null_check.rs:15:8 | LL | if (fn_ptr as *const u8).is_null() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | if (fn_ptr as *const u8).is_null() {} = help: try wrapping your function pointer type in `Option` instead, and using `is_none` to check for null pointer value error: function pointer assumed to be nullable, even though it isn't - --> $DIR/fn_null_check.rs:15:8 + --> $DIR/fn_null_check.rs:16:8 | LL | if (fn_ptr as *const ()) == std::ptr::null() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | if (fn_ptr as *const ()) == std::ptr::null() {} = help: try wrapping your function pointer type in `Option` instead, and using `is_none` to check for null pointer value error: function pointer assumed to be nullable, even though it isn't - --> $DIR/fn_null_check.rs:16:8 + --> $DIR/fn_null_check.rs:17:8 | LL | if (fn_ptr as *const ()) == (0 as *const ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | if (fn_ptr as *const ()) == (0 as *const ()) {} = help: try wrapping your function pointer type in `Option` instead, and using `is_none` to check for null pointer value error: function pointer assumed to be nullable, even though it isn't - --> $DIR/fn_null_check.rs:17:8 + --> $DIR/fn_null_check.rs:18:8 | LL | if (fn_ptr as *const ()) == ZPTR {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/for_loop_fixable.fixed b/tests/ui/for_loop_fixable.fixed deleted file mode 100644 index f578c98da153..000000000000 --- a/tests/ui/for_loop_fixable.fixed +++ /dev/null @@ -1,309 +0,0 @@ -//@run-rustfix -#![allow(dead_code, unused)] -#![allow(clippy::uninlined_format_args)] - -use std::collections::*; - -#[warn(clippy::all)] -struct Unrelated(Vec); -impl Unrelated { - fn next(&self) -> std::slice::Iter { - self.0.iter() - } - - fn iter(&self) -> std::slice::Iter { - self.0.iter() - } -} - -#[warn( - clippy::needless_range_loop, - clippy::explicit_iter_loop, - clippy::explicit_into_iter_loop, - clippy::iter_next_loop, - clippy::for_kv_map -)] -#[allow( - clippy::linkedlist, - clippy::unnecessary_mut_passed, - clippy::similar_names, - clippy::needless_borrow -)] -#[allow(unused_variables)] -fn main() { - let mut vec = vec![1, 2, 3, 4]; - - // See #601 - for i in 0..10 { - // no error, id_col does not exist outside the loop - let mut id_col = vec![0f64; 10]; - id_col[i] = 1f64; - } - - for _v in &vec {} - - for _v in &mut vec {} - - let out_vec = vec![1, 2, 3]; - for _v in out_vec {} - - for _v in &vec {} // these are fine - for _v in &mut vec {} // these are fine - - for _v in &[1, 2, 3] {} - - for _v in (&mut [1, 2, 3]).iter() {} // no error - - for _v in &[0; 32] {} - - for _v in [0; 33].iter() {} // no error - - let ll: LinkedList<()> = LinkedList::new(); - for _v in &ll {} - - let vd: VecDeque<()> = VecDeque::new(); - for _v in &vd {} - - let bh: BinaryHeap<()> = BinaryHeap::new(); - for _v in &bh {} - - let hm: HashMap<(), ()> = HashMap::new(); - for _v in &hm {} - - let bt: BTreeMap<(), ()> = BTreeMap::new(); - for _v in &bt {} - - let hs: HashSet<()> = HashSet::new(); - for _v in &hs {} - - let bs: BTreeSet<()> = BTreeSet::new(); - for _v in &bs {} - - let u = Unrelated(vec![]); - for _v in u.next() {} // no error - for _v in u.iter() {} // no error - - let mut out = vec![]; - vec.iter().cloned().map(|x| out.push(x)).collect::>(); - let _y = vec.iter().cloned().map(|x| out.push(x)).collect::>(); // this is fine - - // Loop with explicit counter variable - - // Potential false positives - let mut _index = 0; - _index = 1; - for _v in &vec { - _index += 1 - } - - let mut _index = 0; - _index += 1; - for _v in &vec { - _index += 1 - } - - let mut _index = 0; - if true { - _index = 1 - } - for _v in &vec { - _index += 1 - } - - let mut _index = 0; - let mut _index = 1; - for _v in &vec { - _index += 1 - } - - let mut _index = 0; - for _v in &vec { - _index += 1; - _index += 1 - } - - let mut _index = 0; - for _v in &vec { - _index *= 2; - _index += 1 - } - - let mut _index = 0; - for _v in &vec { - _index = 1; - _index += 1 - } - - let mut _index = 0; - - for _v in &vec { - let mut _index = 0; - _index += 1 - } - - let mut _index = 0; - for _v in &vec { - _index += 1; - _index = 0; - } - - let mut _index = 0; - for _v in &vec { - for _x in 0..1 { - _index += 1; - } - _index += 1 - } - - let mut _index = 0; - for x in &vec { - if *x == 1 { - _index += 1 - } - } - - let mut _index = 0; - if true { - _index = 1 - }; - for _v in &vec { - _index += 1 - } - - let mut _index = 1; - if false { - _index = 0 - }; - for _v in &vec { - _index += 1 - } - - let mut index = 0; - { - let mut _x = &mut index; - } - for _v in &vec { - _index += 1 - } - - let mut index = 0; - for _v in &vec { - index += 1 - } - println!("index: {}", index); - - fn f(_: &T, _: &T) -> bool { - unimplemented!() - } - fn g(_: &mut [T], _: usize, _: usize) { - unimplemented!() - } - for i in 1..vec.len() { - if f(&vec[i - 1], &vec[i]) { - g(&mut vec, i - 1, i); - } - } - - for mid in 1..vec.len() { - let (_, _) = vec.split_at(mid); - } -} - -fn partition(v: &mut [T]) -> usize { - let pivot = v.len() - 1; - let mut i = 0; - for j in 0..pivot { - if v[j] <= v[pivot] { - v.swap(i, j); - i += 1; - } - } - v.swap(i, pivot); - i -} - -#[warn(clippy::needless_range_loop)] -pub fn manual_copy_same_destination(dst: &mut [i32], d: usize, s: usize) { - // Same source and destination - don't trigger lint - for i in 0..dst.len() { - dst[d + i] = dst[s + i]; - } -} - -mod issue_2496 { - pub trait Handle { - fn new_for_index(index: usize) -> Self; - fn index(&self) -> usize; - } - - pub fn test() -> H { - for x in 0..5 { - let next_handle = H::new_for_index(x); - println!("{}", next_handle.index()); - } - unimplemented!() - } -} - -// explicit_into_iter_loop bad suggestions -#[warn(clippy::explicit_into_iter_loop, clippy::explicit_iter_loop)] -mod issue_4958 { - fn takes_iterator(iterator: &T) - where - for<'a> &'a T: IntoIterator, - { - for i in iterator { - println!("{}", i); - } - } - - struct T; - impl IntoIterator for &T { - type Item = (); - type IntoIter = std::vec::IntoIter; - fn into_iter(self) -> Self::IntoIter { - vec![].into_iter() - } - } - - fn more_tests() { - let t = T; - let r = &t; - let rr = &&t; - - // This case is handled by `explicit_iter_loop`. No idea why. - for _ in &t {} - - for _ in r {} - - // No suggestion for this. - // We'd have to suggest `for _ in *rr {}` which is less clear. - for _ in rr.into_iter() {} - } -} - -// explicit_into_iter_loop -#[warn(clippy::explicit_into_iter_loop)] -mod issue_6900 { - struct S; - impl S { - #[allow(clippy::should_implement_trait)] - pub fn into_iter(self) -> I { - unimplemented!() - } - } - - struct I(T); - impl Iterator for I { - type Item = T; - fn next(&mut self) -> Option { - unimplemented!() - } - } - - fn f() { - for _ in S.into_iter::() { - unimplemented!() - } - } -} diff --git a/tests/ui/for_loop_fixable.rs b/tests/ui/for_loop_fixable.rs deleted file mode 100644 index 42bc6de0c7dd..000000000000 --- a/tests/ui/for_loop_fixable.rs +++ /dev/null @@ -1,309 +0,0 @@ -//@run-rustfix -#![allow(dead_code, unused)] -#![allow(clippy::uninlined_format_args)] - -use std::collections::*; - -#[warn(clippy::all)] -struct Unrelated(Vec); -impl Unrelated { - fn next(&self) -> std::slice::Iter { - self.0.iter() - } - - fn iter(&self) -> std::slice::Iter { - self.0.iter() - } -} - -#[warn( - clippy::needless_range_loop, - clippy::explicit_iter_loop, - clippy::explicit_into_iter_loop, - clippy::iter_next_loop, - clippy::for_kv_map -)] -#[allow( - clippy::linkedlist, - clippy::unnecessary_mut_passed, - clippy::similar_names, - clippy::needless_borrow -)] -#[allow(unused_variables)] -fn main() { - let mut vec = vec![1, 2, 3, 4]; - - // See #601 - for i in 0..10 { - // no error, id_col does not exist outside the loop - let mut id_col = vec![0f64; 10]; - id_col[i] = 1f64; - } - - for _v in vec.iter() {} - - for _v in vec.iter_mut() {} - - let out_vec = vec![1, 2, 3]; - for _v in out_vec.into_iter() {} - - for _v in &vec {} // these are fine - for _v in &mut vec {} // these are fine - - for _v in [1, 2, 3].iter() {} - - for _v in (&mut [1, 2, 3]).iter() {} // no error - - for _v in [0; 32].iter() {} - - for _v in [0; 33].iter() {} // no error - - let ll: LinkedList<()> = LinkedList::new(); - for _v in ll.iter() {} - - let vd: VecDeque<()> = VecDeque::new(); - for _v in vd.iter() {} - - let bh: BinaryHeap<()> = BinaryHeap::new(); - for _v in bh.iter() {} - - let hm: HashMap<(), ()> = HashMap::new(); - for _v in hm.iter() {} - - let bt: BTreeMap<(), ()> = BTreeMap::new(); - for _v in bt.iter() {} - - let hs: HashSet<()> = HashSet::new(); - for _v in hs.iter() {} - - let bs: BTreeSet<()> = BTreeSet::new(); - for _v in bs.iter() {} - - let u = Unrelated(vec![]); - for _v in u.next() {} // no error - for _v in u.iter() {} // no error - - let mut out = vec![]; - vec.iter().cloned().map(|x| out.push(x)).collect::>(); - let _y = vec.iter().cloned().map(|x| out.push(x)).collect::>(); // this is fine - - // Loop with explicit counter variable - - // Potential false positives - let mut _index = 0; - _index = 1; - for _v in &vec { - _index += 1 - } - - let mut _index = 0; - _index += 1; - for _v in &vec { - _index += 1 - } - - let mut _index = 0; - if true { - _index = 1 - } - for _v in &vec { - _index += 1 - } - - let mut _index = 0; - let mut _index = 1; - for _v in &vec { - _index += 1 - } - - let mut _index = 0; - for _v in &vec { - _index += 1; - _index += 1 - } - - let mut _index = 0; - for _v in &vec { - _index *= 2; - _index += 1 - } - - let mut _index = 0; - for _v in &vec { - _index = 1; - _index += 1 - } - - let mut _index = 0; - - for _v in &vec { - let mut _index = 0; - _index += 1 - } - - let mut _index = 0; - for _v in &vec { - _index += 1; - _index = 0; - } - - let mut _index = 0; - for _v in &vec { - for _x in 0..1 { - _index += 1; - } - _index += 1 - } - - let mut _index = 0; - for x in &vec { - if *x == 1 { - _index += 1 - } - } - - let mut _index = 0; - if true { - _index = 1 - }; - for _v in &vec { - _index += 1 - } - - let mut _index = 1; - if false { - _index = 0 - }; - for _v in &vec { - _index += 1 - } - - let mut index = 0; - { - let mut _x = &mut index; - } - for _v in &vec { - _index += 1 - } - - let mut index = 0; - for _v in &vec { - index += 1 - } - println!("index: {}", index); - - fn f(_: &T, _: &T) -> bool { - unimplemented!() - } - fn g(_: &mut [T], _: usize, _: usize) { - unimplemented!() - } - for i in 1..vec.len() { - if f(&vec[i - 1], &vec[i]) { - g(&mut vec, i - 1, i); - } - } - - for mid in 1..vec.len() { - let (_, _) = vec.split_at(mid); - } -} - -fn partition(v: &mut [T]) -> usize { - let pivot = v.len() - 1; - let mut i = 0; - for j in 0..pivot { - if v[j] <= v[pivot] { - v.swap(i, j); - i += 1; - } - } - v.swap(i, pivot); - i -} - -#[warn(clippy::needless_range_loop)] -pub fn manual_copy_same_destination(dst: &mut [i32], d: usize, s: usize) { - // Same source and destination - don't trigger lint - for i in 0..dst.len() { - dst[d + i] = dst[s + i]; - } -} - -mod issue_2496 { - pub trait Handle { - fn new_for_index(index: usize) -> Self; - fn index(&self) -> usize; - } - - pub fn test() -> H { - for x in 0..5 { - let next_handle = H::new_for_index(x); - println!("{}", next_handle.index()); - } - unimplemented!() - } -} - -// explicit_into_iter_loop bad suggestions -#[warn(clippy::explicit_into_iter_loop, clippy::explicit_iter_loop)] -mod issue_4958 { - fn takes_iterator(iterator: &T) - where - for<'a> &'a T: IntoIterator, - { - for i in iterator.into_iter() { - println!("{}", i); - } - } - - struct T; - impl IntoIterator for &T { - type Item = (); - type IntoIter = std::vec::IntoIter; - fn into_iter(self) -> Self::IntoIter { - vec![].into_iter() - } - } - - fn more_tests() { - let t = T; - let r = &t; - let rr = &&t; - - // This case is handled by `explicit_iter_loop`. No idea why. - for _ in t.into_iter() {} - - for _ in r.into_iter() {} - - // No suggestion for this. - // We'd have to suggest `for _ in *rr {}` which is less clear. - for _ in rr.into_iter() {} - } -} - -// explicit_into_iter_loop -#[warn(clippy::explicit_into_iter_loop)] -mod issue_6900 { - struct S; - impl S { - #[allow(clippy::should_implement_trait)] - pub fn into_iter(self) -> I { - unimplemented!() - } - } - - struct I(T); - impl Iterator for I { - type Item = T; - fn next(&mut self) -> Option { - unimplemented!() - } - } - - fn f() { - for _ in S.into_iter::() { - unimplemented!() - } - } -} diff --git a/tests/ui/for_loop_fixable.stderr b/tests/ui/for_loop_fixable.stderr deleted file mode 100644 index ddfe66d675f9..000000000000 --- a/tests/ui/for_loop_fixable.stderr +++ /dev/null @@ -1,96 +0,0 @@ -error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:43:15 - | -LL | for _v in vec.iter() {} - | ^^^^^^^^^^ help: to write this more concisely, try: `&vec` - | - = note: `-D clippy::explicit-iter-loop` implied by `-D warnings` - -error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:45:15 - | -LL | for _v in vec.iter_mut() {} - | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&mut vec` - -error: it is more concise to loop over containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:48:15 - | -LL | for _v in out_vec.into_iter() {} - | ^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `out_vec` - | - = note: `-D clippy::explicit-into-iter-loop` implied by `-D warnings` - -error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:53:15 - | -LL | for _v in [1, 2, 3].iter() {} - | ^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[1, 2, 3]` - -error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:57:15 - | -LL | for _v in [0; 32].iter() {} - | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[0; 32]` - -error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:62:15 - | -LL | for _v in ll.iter() {} - | ^^^^^^^^^ help: to write this more concisely, try: `&ll` - -error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:65:15 - | -LL | for _v in vd.iter() {} - | ^^^^^^^^^ help: to write this more concisely, try: `&vd` - -error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:68:15 - | -LL | for _v in bh.iter() {} - | ^^^^^^^^^ help: to write this more concisely, try: `&bh` - -error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:71:15 - | -LL | for _v in hm.iter() {} - | ^^^^^^^^^ help: to write this more concisely, try: `&hm` - -error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:74:15 - | -LL | for _v in bt.iter() {} - | ^^^^^^^^^ help: to write this more concisely, try: `&bt` - -error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:77:15 - | -LL | for _v in hs.iter() {} - | ^^^^^^^^^ help: to write this more concisely, try: `&hs` - -error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:80:15 - | -LL | for _v in bs.iter() {} - | ^^^^^^^^^ help: to write this more concisely, try: `&bs` - -error: it is more concise to loop over containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:255:18 - | -LL | for i in iterator.into_iter() { - | ^^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `iterator` - -error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:275:18 - | -LL | for _ in t.into_iter() {} - | ^^^^^^^^^^^^^ help: to write this more concisely, try: `&t` - -error: it is more concise to loop over containers instead of using explicit iteration methods - --> $DIR/for_loop_fixable.rs:277:18 - | -LL | for _ in r.into_iter() {} - | ^^^^^^^^^^^^^ help: to write this more concisely, try: `r` - -error: aborting due to 15 previous errors - diff --git a/tests/ui/for_loop_unfixable.rs b/tests/ui/for_loop_unfixable.rs deleted file mode 100644 index 55fb3788a8b1..000000000000 --- a/tests/ui/for_loop_unfixable.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Tests from for_loop.rs that don't have suggestions - -#[warn( - clippy::needless_range_loop, - clippy::explicit_iter_loop, - clippy::explicit_into_iter_loop, - clippy::iter_next_loop, - clippy::for_kv_map -)] -#[allow(clippy::linkedlist, clippy::unnecessary_mut_passed, clippy::similar_names)] -#[allow(for_loops_over_fallibles)] -fn main() { - let vec = vec![1, 2, 3, 4]; - - for _v in vec.iter().next() {} -} diff --git a/tests/ui/for_loop_unfixable.stderr b/tests/ui/for_loop_unfixable.stderr deleted file mode 100644 index 50a86eaa68f7..000000000000 --- a/tests/ui/for_loop_unfixable.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: you are iterating over `Iterator::next()` which is an Option; this will compile but is probably not what you want - --> $DIR/for_loop_unfixable.rs:15:15 - | -LL | for _v in vec.iter().next() {} - | ^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::iter-next-loop` implied by `-D warnings` - -error: aborting due to previous error - diff --git a/tests/ui/format.fixed b/tests/ui/format.fixed index 9288956f5130..2e24e07ea268 100644 --- a/tests/ui/format.fixed +++ b/tests/ui/format.fixed @@ -6,7 +6,9 @@ clippy::redundant_clone, clippy::to_string_in_format_args, clippy::needless_borrow, - clippy::uninlined_format_args + clippy::uninlined_format_args, + clippy::needless_raw_string_hashes, + clippy::useless_vec )] struct Foo(pub String); diff --git a/tests/ui/format.rs b/tests/ui/format.rs index b2b817e0f4c4..0e64a310b01e 100644 --- a/tests/ui/format.rs +++ b/tests/ui/format.rs @@ -6,7 +6,9 @@ clippy::redundant_clone, clippy::to_string_in_format_args, clippy::needless_borrow, - clippy::uninlined_format_args + clippy::uninlined_format_args, + clippy::needless_raw_string_hashes, + clippy::useless_vec )] struct Foo(pub String); diff --git a/tests/ui/format.stderr b/tests/ui/format.stderr index 0ef0ac655d39..78a11a3354f6 100644 --- a/tests/ui/format.stderr +++ b/tests/ui/format.stderr @@ -1,5 +1,5 @@ error: useless use of `format!` - --> $DIR/format.rs:19:5 + --> $DIR/format.rs:21:5 | LL | format!("foo"); | ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()` @@ -7,19 +7,19 @@ LL | format!("foo"); = note: `-D clippy::useless-format` implied by `-D warnings` error: useless use of `format!` - --> $DIR/format.rs:20:5 + --> $DIR/format.rs:22:5 | LL | format!("{{}}"); | ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{}".to_string()` error: useless use of `format!` - --> $DIR/format.rs:21:5 + --> $DIR/format.rs:23:5 | LL | format!("{{}} abc {{}}"); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{} abc {}".to_string()` error: useless use of `format!` - --> $DIR/format.rs:22:5 + --> $DIR/format.rs:24:5 | LL | / format!( LL | | r##"foo {{}} @@ -34,67 +34,67 @@ LL ~ " bar"##.to_string(); | error: useless use of `format!` - --> $DIR/format.rs:27:13 + --> $DIR/format.rs:29:13 | LL | let _ = format!(""); | ^^^^^^^^^^^ help: consider using `String::new()`: `String::new()` error: useless use of `format!` - --> $DIR/format.rs:29:5 + --> $DIR/format.rs:31:5 | LL | format!("{}", "foo"); | ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()` error: useless use of `format!` - --> $DIR/format.rs:37:5 + --> $DIR/format.rs:39:5 | LL | format!("{}", arg); | ^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()` error: useless use of `format!` - --> $DIR/format.rs:67:5 + --> $DIR/format.rs:69:5 | LL | format!("{}", 42.to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `42.to_string()` error: useless use of `format!` - --> $DIR/format.rs:69:5 + --> $DIR/format.rs:71:5 | LL | format!("{}", x.display().to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.display().to_string()` error: useless use of `format!` - --> $DIR/format.rs:73:18 + --> $DIR/format.rs:75:18 | LL | let _ = Some(format!("{}", a + "bar")); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `a + "bar"` error: useless use of `format!` - --> $DIR/format.rs:77:22 + --> $DIR/format.rs:79:22 | LL | let _s: String = format!("{}", &*v.join("/n")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `(&*v.join("/n")).to_string()` error: useless use of `format!` - --> $DIR/format.rs:83:13 + --> $DIR/format.rs:85:13 | LL | let _ = format!("{x}"); | ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()` error: useless use of `format!` - --> $DIR/format.rs:85:13 + --> $DIR/format.rs:87:13 | LL | let _ = format!("{y}", y = x); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()` error: useless use of `format!` - --> $DIR/format.rs:89:13 + --> $DIR/format.rs:91:13 | LL | let _ = format!("{abc}"); | ^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `abc.to_string()` error: useless use of `format!` - --> $DIR/format.rs:91:13 + --> $DIR/format.rs:93:13 | LL | let _ = format!("{xx}"); | ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `xx.to_string()` diff --git a/tests/ui/format_push_string.rs b/tests/ui/format_push_string.rs index 4db13d650eb1..89423ffe1cf8 100644 --- a/tests/ui/format_push_string.rs +++ b/tests/ui/format_push_string.rs @@ -5,3 +5,32 @@ fn main() { string += &format!("{:?}", 1234); string.push_str(&format!("{:?}", 5678)); } + +mod issue9493 { + pub fn u8vec_to_hex(vector: &Vec, upper: bool) -> String { + let mut hex = String::with_capacity(vector.len() * 2); + for byte in vector { + hex += &(if upper { + format!("{byte:02X}") + } else { + format!("{byte:02x}") + }); + } + hex + } + + pub fn other_cases() { + let mut s = String::new(); + // if let + s += &(if let Some(_a) = Some(1234) { + format!("{}", 1234) + } else { + format!("{}", 1234) + }); + // match + s += &(match Some(1234) { + Some(_) => format!("{}", 1234), + None => format!("{}", 1234), + }); + } +} diff --git a/tests/ui/format_push_string.stderr b/tests/ui/format_push_string.stderr index d7be9a5f206c..76762c4a1d1f 100644 --- a/tests/ui/format_push_string.stderr +++ b/tests/ui/format_push_string.stderr @@ -15,5 +15,40 @@ LL | string.push_str(&format!("{:?}", 5678)); | = help: consider using `write!` to avoid the extra allocation -error: aborting due to 2 previous errors +error: `format!(..)` appended to existing `String` + --> $DIR/format_push_string.rs:13:13 + | +LL | / hex += &(if upper { +LL | | format!("{byte:02X}") +LL | | } else { +LL | | format!("{byte:02x}") +LL | | }); + | |______________^ + | + = help: consider using `write!` to avoid the extra allocation + +error: `format!(..)` appended to existing `String` + --> $DIR/format_push_string.rs:25:9 + | +LL | / s += &(if let Some(_a) = Some(1234) { +LL | | format!("{}", 1234) +LL | | } else { +LL | | format!("{}", 1234) +LL | | }); + | |__________^ + | + = help: consider using `write!` to avoid the extra allocation + +error: `format!(..)` appended to existing `String` + --> $DIR/format_push_string.rs:31:9 + | +LL | / s += &(match Some(1234) { +LL | | Some(_) => format!("{}", 1234), +LL | | None => format!("{}", 1234), +LL | | }); + | |__________^ + | + = help: consider using `write!` to avoid the extra allocation + +error: aborting due to 5 previous errors diff --git a/tests/ui/from_iter_instead_of_collect.fixed b/tests/ui/from_iter_instead_of_collect.fixed index 915ff4fb079d..1671987cb673 100644 --- a/tests/ui/from_iter_instead_of_collect.fixed +++ b/tests/ui/from_iter_instead_of_collect.fixed @@ -2,6 +2,7 @@ #![warn(clippy::from_iter_instead_of_collect)] #![allow(unused_imports, unused_tuple_struct_fields)] +#![allow(clippy::useless_vec)] use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque}; diff --git a/tests/ui/from_iter_instead_of_collect.rs b/tests/ui/from_iter_instead_of_collect.rs index e926f8c529df..48509b32f109 100644 --- a/tests/ui/from_iter_instead_of_collect.rs +++ b/tests/ui/from_iter_instead_of_collect.rs @@ -2,6 +2,7 @@ #![warn(clippy::from_iter_instead_of_collect)] #![allow(unused_imports, unused_tuple_struct_fields)] +#![allow(clippy::useless_vec)] use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque}; diff --git a/tests/ui/from_iter_instead_of_collect.stderr b/tests/ui/from_iter_instead_of_collect.stderr index 8aa3c3c01f81..8f08ac8c3ff4 100644 --- a/tests/ui/from_iter_instead_of_collect.stderr +++ b/tests/ui/from_iter_instead_of_collect.stderr @@ -1,5 +1,5 @@ error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:18:9 + --> $DIR/from_iter_instead_of_collect.rs:19:9 | LL | >::from_iter(iter.into_iter().copied()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter.into_iter().copied().collect::()` @@ -7,85 +7,85 @@ LL | >::from_iter(iter.into_iter().copied()) = note: `-D clippy::from-iter-instead-of-collect` implied by `-D warnings` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:24:13 + --> $DIR/from_iter_instead_of_collect.rs:25:13 | LL | let _ = Vec::from_iter(iter_expr); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter_expr.collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:26:13 + --> $DIR/from_iter_instead_of_collect.rs:27:13 | LL | let _ = HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `vec![5, 5, 5, 5].iter().enumerate().collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:31:19 + --> $DIR/from_iter_instead_of_collect.rs:32:19 | LL | assert_eq!(a, Vec::from_iter(0..3)); | ^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:32:19 + --> $DIR/from_iter_instead_of_collect.rs:33:19 | LL | assert_eq!(a, Vec::::from_iter(0..3)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:34:17 + --> $DIR/from_iter_instead_of_collect.rs:35:17 | LL | let mut b = VecDeque::from_iter(0..3); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:37:17 + --> $DIR/from_iter_instead_of_collect.rs:38:17 | LL | let mut b = VecDeque::::from_iter(0..3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:42:21 + --> $DIR/from_iter_instead_of_collect.rs:43:21 | LL | let mut b = collections::VecDeque::::from_iter(0..3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:47:14 + --> $DIR/from_iter_instead_of_collect.rs:48:14 | LL | let bm = BTreeMap::from_iter(values.iter().cloned()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `values.iter().cloned().collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:48:19 + --> $DIR/from_iter_instead_of_collect.rs:49:19 | LL | let mut bar = BTreeMap::from_iter(bm.range(0..2)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `bm.range(0..2).collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:51:19 + --> $DIR/from_iter_instead_of_collect.rs:52:19 | LL | let mut bts = BTreeSet::from_iter(0..3); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:55:17 + --> $DIR/from_iter_instead_of_collect.rs:56:17 | LL | let _ = collections::BTreeSet::from_iter(0..3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:56:17 + --> $DIR/from_iter_instead_of_collect.rs:57:17 | LL | let _ = collections::BTreeSet::::from_iter(0..3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:59:15 + --> $DIR/from_iter_instead_of_collect.rs:60:15 | LL | for _i in Vec::from_iter([1, 2, 3].iter()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `[1, 2, 3].iter().collect::>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:60:15 + --> $DIR/from_iter_instead_of_collect.rs:61:15 | LL | for _i in Vec::<&i32>::from_iter([1, 2, 3].iter()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `[1, 2, 3].iter().collect::>()` diff --git a/tests/ui/from_over_into.fixed b/tests/ui/from_over_into.fixed index 204019130ede..d96b68a9159a 100644 --- a/tests/ui/from_over_into.fixed +++ b/tests/ui/from_over_into.fixed @@ -60,6 +60,15 @@ impl From for A { } } +struct PathInExpansion; + +impl From for String { + fn from(val: PathInExpansion) -> Self { + // non self/Self paths in expansions are fine + panic!() + } +} + #[clippy::msrv = "1.40"] fn msrv_1_40() { struct FromOverInto(Vec); diff --git a/tests/ui/from_over_into.rs b/tests/ui/from_over_into.rs index 46e02847e308..da8fe04f4760 100644 --- a/tests/ui/from_over_into.rs +++ b/tests/ui/from_over_into.rs @@ -60,6 +60,15 @@ impl From for A { } } +struct PathInExpansion; + +impl Into for PathInExpansion { + fn into(self) -> String { + // non self/Self paths in expansions are fine + panic!() + } +} + #[clippy::msrv = "1.40"] fn msrv_1_40() { struct FromOverInto(Vec); diff --git a/tests/ui/from_over_into.stderr b/tests/ui/from_over_into.stderr index 6039f86fe670..498b00de5adb 100644 --- a/tests/ui/from_over_into.stderr +++ b/tests/ui/from_over_into.stderr @@ -59,7 +59,21 @@ LL ~ val.0 | error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true - --> $DIR/from_over_into.rs:78:5 + --> $DIR/from_over_into.rs:65:1 + | +LL | impl Into for PathInExpansion { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `impl From for Foreign` is allowed by the orphan rules, for more information see + https://doc.rust-lang.org/reference/items/implementations.html#trait-implementation-coherence +help: replace the `Into` implementation with `From` + | +LL ~ impl From for String { +LL ~ fn from(val: PathInExpansion) -> Self { + | + +error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true + --> $DIR/from_over_into.rs:87:5 | LL | impl Into> for Vec { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -71,5 +85,5 @@ LL ~ fn from(val: Vec) -> Self { LL ~ FromOverInto(val) | -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors diff --git a/tests/ui/from_over_into_unfixable.rs b/tests/ui/from_over_into_unfixable.rs index 3b280b7488ae..c769e38eb33a 100644 --- a/tests/ui/from_over_into_unfixable.rs +++ b/tests/ui/from_over_into_unfixable.rs @@ -3,14 +3,14 @@ struct InMacro(String); macro_rules! in_macro { - ($e:ident) => { - $e + () => { + Self::new() }; } impl Into for String { fn into(self) -> InMacro { - InMacro(in_macro!(self)) + InMacro(in_macro!()) } } @@ -32,4 +32,14 @@ impl Into for ContainsVal { } } +pub struct Lval(T); + +pub struct Rval(T); + +impl Into> for Lval { + fn into(self) -> Rval { + Rval(self) + } +} + fn main() {} diff --git a/tests/ui/from_over_into_unfixable.stderr b/tests/ui/from_over_into_unfixable.stderr index 251f1d84e74e..2ab9b9d6b17c 100644 --- a/tests/ui/from_over_into_unfixable.stderr +++ b/tests/ui/from_over_into_unfixable.stderr @@ -25,5 +25,13 @@ LL | impl Into for ContainsVal { https://doc.rust-lang.org/reference/items/implementations.html#trait-implementation-coherence = help: replace the `Into` implementation with `From` -error: aborting due to 3 previous errors +error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true + --> $DIR/from_over_into_unfixable.rs:39:1 + | +LL | impl Into> for Lval { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: replace the `Into` implementation with `From>` + +error: aborting due to 4 previous errors diff --git a/tests/ui/from_raw_with_void_ptr.rs b/tests/ui/from_raw_with_void_ptr.rs index 8484da2415ab..95ef6425fad9 100644 --- a/tests/ui/from_raw_with_void_ptr.rs +++ b/tests/ui/from_raw_with_void_ptr.rs @@ -1,4 +1,5 @@ #![warn(clippy::from_raw_with_void_ptr)] +#![allow(clippy::unnecessary_cast)] use std::ffi::c_void; use std::rc::Rc; diff --git a/tests/ui/from_raw_with_void_ptr.stderr b/tests/ui/from_raw_with_void_ptr.stderr index 96e4af12ba38..1963d08014b1 100644 --- a/tests/ui/from_raw_with_void_ptr.stderr +++ b/tests/ui/from_raw_with_void_ptr.stderr @@ -1,60 +1,60 @@ error: creating a `Box` from a void raw pointer - --> $DIR/from_raw_with_void_ptr.rs:10:22 + --> $DIR/from_raw_with_void_ptr.rs:11:22 | LL | let _ = unsafe { Box::from_raw(ptr) }; | ^^^^^^^^^^^^^^^^^^ | help: cast this to a pointer of the appropriate type - --> $DIR/from_raw_with_void_ptr.rs:10:36 + --> $DIR/from_raw_with_void_ptr.rs:11:36 | LL | let _ = unsafe { Box::from_raw(ptr) }; | ^^^ = note: `-D clippy::from-raw-with-void-ptr` implied by `-D warnings` error: creating a `Rc` from a void raw pointer - --> $DIR/from_raw_with_void_ptr.rs:21:22 + --> $DIR/from_raw_with_void_ptr.rs:22:22 | LL | let _ = unsafe { Rc::from_raw(ptr) }; | ^^^^^^^^^^^^^^^^^ | help: cast this to a pointer of the appropriate type - --> $DIR/from_raw_with_void_ptr.rs:21:35 + --> $DIR/from_raw_with_void_ptr.rs:22:35 | LL | let _ = unsafe { Rc::from_raw(ptr) }; | ^^^ error: creating a `Arc` from a void raw pointer - --> $DIR/from_raw_with_void_ptr.rs:25:22 + --> $DIR/from_raw_with_void_ptr.rs:26:22 | LL | let _ = unsafe { Arc::from_raw(ptr) }; | ^^^^^^^^^^^^^^^^^^ | help: cast this to a pointer of the appropriate type - --> $DIR/from_raw_with_void_ptr.rs:25:36 + --> $DIR/from_raw_with_void_ptr.rs:26:36 | LL | let _ = unsafe { Arc::from_raw(ptr) }; | ^^^ error: creating a `Weak` from a void raw pointer - --> $DIR/from_raw_with_void_ptr.rs:29:22 + --> $DIR/from_raw_with_void_ptr.rs:30:22 | LL | let _ = unsafe { std::rc::Weak::from_raw(ptr) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: cast this to a pointer of the appropriate type - --> $DIR/from_raw_with_void_ptr.rs:29:46 + --> $DIR/from_raw_with_void_ptr.rs:30:46 | LL | let _ = unsafe { std::rc::Weak::from_raw(ptr) }; | ^^^ error: creating a `Weak` from a void raw pointer - --> $DIR/from_raw_with_void_ptr.rs:33:22 + --> $DIR/from_raw_with_void_ptr.rs:34:22 | LL | let _ = unsafe { std::sync::Weak::from_raw(ptr) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: cast this to a pointer of the appropriate type - --> $DIR/from_raw_with_void_ptr.rs:33:48 + --> $DIR/from_raw_with_void_ptr.rs:34:48 | LL | let _ = unsafe { std::sync::Weak::from_raw(ptr) }; | ^^^ diff --git a/tests/ui/get_first.fixed b/tests/ui/get_first.fixed index ef132b796117..a29c0918a6dd 100644 --- a/tests/ui/get_first.fixed +++ b/tests/ui/get_first.fixed @@ -1,5 +1,6 @@ //@run-rustfix #![warn(clippy::get_first)] +#![allow(clippy::useless_vec)] use std::collections::BTreeMap; use std::collections::HashMap; use std::collections::VecDeque; diff --git a/tests/ui/get_first.rs b/tests/ui/get_first.rs index 4d8722356144..2062f3ec23a0 100644 --- a/tests/ui/get_first.rs +++ b/tests/ui/get_first.rs @@ -1,5 +1,6 @@ //@run-rustfix #![warn(clippy::get_first)] +#![allow(clippy::useless_vec)] use std::collections::BTreeMap; use std::collections::HashMap; use std::collections::VecDeque; diff --git a/tests/ui/get_first.stderr b/tests/ui/get_first.stderr index 466beff9c92d..4e267ba9a3b4 100644 --- a/tests/ui/get_first.stderr +++ b/tests/ui/get_first.stderr @@ -1,5 +1,5 @@ error: accessing first element with `x.get(0)` - --> $DIR/get_first.rs:19:13 + --> $DIR/get_first.rs:20:13 | LL | let _ = x.get(0); // Use x.first() | ^^^^^^^^ help: try: `x.first()` @@ -7,13 +7,13 @@ LL | let _ = x.get(0); // Use x.first() = note: `-D clippy::get-first` implied by `-D warnings` error: accessing first element with `y.get(0)` - --> $DIR/get_first.rs:24:13 + --> $DIR/get_first.rs:25:13 | LL | let _ = y.get(0); // Use y.first() | ^^^^^^^^ help: try: `y.first()` error: accessing first element with `z.get(0)` - --> $DIR/get_first.rs:29:13 + --> $DIR/get_first.rs:30:13 | LL | let _ = z.get(0); // Use z.first() | ^^^^^^^^ help: try: `z.first()` diff --git a/tests/ui/get_last_with_len.fixed b/tests/ui/get_last_with_len.fixed index a58dfda79885..01a83e5bf343 100644 --- a/tests/ui/get_last_with_len.fixed +++ b/tests/ui/get_last_with_len.fixed @@ -1,7 +1,7 @@ //@run-rustfix #![warn(clippy::get_last_with_len)] -#![allow(unused)] +#![allow(unused, clippy::useless_vec)] use std::collections::VecDeque; diff --git a/tests/ui/get_last_with_len.rs b/tests/ui/get_last_with_len.rs index d626656c78f9..d82484b46d3f 100644 --- a/tests/ui/get_last_with_len.rs +++ b/tests/ui/get_last_with_len.rs @@ -1,7 +1,7 @@ //@run-rustfix #![warn(clippy::get_last_with_len)] -#![allow(unused)] +#![allow(unused, clippy::useless_vec)] use std::collections::VecDeque; diff --git a/tests/ui/get_unwrap.fixed b/tests/ui/get_unwrap.fixed index 4950c47ddeb8..56ee37f02d26 100644 --- a/tests/ui/get_unwrap.fixed +++ b/tests/ui/get_unwrap.fixed @@ -1,6 +1,11 @@ //@run-rustfix -#![allow(unused_mut, clippy::from_iter_instead_of_collect, clippy::get_first)] +#![allow( + unused_mut, + clippy::from_iter_instead_of_collect, + clippy::get_first, + clippy::useless_vec +)] #![warn(clippy::unwrap_used)] #![deny(clippy::get_unwrap)] @@ -65,3 +70,42 @@ fn main() { let _ = some_vec[0..1].to_vec(); } } +mod issue9909 { + #![allow(clippy::identity_op, clippy::unwrap_used, dead_code)] + + fn reduced() { + let f = &[1, 2, 3]; + + // include a borrow in the suggestion, even if the argument is not just a numeric literal + let _x: &i32 = &f[1 + 2]; + + // don't include a borrow here + let _x = f[1 + 2].to_string(); + + // don't include a borrow here + let _x = f[1 + 2].abs(); + } + + // original code: + fn linidx(row: usize, col: usize) -> usize { + row * 1 + col * 3 + } + + fn main_() { + let mut mat = [1.0f32, 5.0, 9.0, 2.0, 6.0, 10.0, 3.0, 7.0, 11.0, 4.0, 8.0, 12.0]; + + for i in 0..2 { + for j in i + 1..3 { + if mat[linidx(j, 3)] > mat[linidx(i, 3)] { + for k in 0..4 { + let (x, rest) = mat.split_at_mut(linidx(i, k) + 1); + let a = x.last_mut().unwrap(); + let b = &mut rest[linidx(j, k) - linidx(i, k) - 1]; + ::std::mem::swap(a, b); + } + } + } + } + assert_eq!([9.0, 5.0, 1.0, 10.0, 6.0, 2.0, 11.0, 7.0, 3.0, 12.0, 8.0, 4.0], mat); + } +} diff --git a/tests/ui/get_unwrap.rs b/tests/ui/get_unwrap.rs index 6b1e8edb7bd2..af3a619adc5e 100644 --- a/tests/ui/get_unwrap.rs +++ b/tests/ui/get_unwrap.rs @@ -1,6 +1,11 @@ //@run-rustfix -#![allow(unused_mut, clippy::from_iter_instead_of_collect, clippy::get_first)] +#![allow( + unused_mut, + clippy::from_iter_instead_of_collect, + clippy::get_first, + clippy::useless_vec +)] #![warn(clippy::unwrap_used)] #![deny(clippy::get_unwrap)] @@ -65,3 +70,42 @@ fn main() { let _ = some_vec.get_mut(0..1).unwrap().to_vec(); } } +mod issue9909 { + #![allow(clippy::identity_op, clippy::unwrap_used, dead_code)] + + fn reduced() { + let f = &[1, 2, 3]; + + // include a borrow in the suggestion, even if the argument is not just a numeric literal + let _x: &i32 = f.get(1 + 2).unwrap(); + + // don't include a borrow here + let _x = f.get(1 + 2).unwrap().to_string(); + + // don't include a borrow here + let _x = f.get(1 + 2).unwrap().abs(); + } + + // original code: + fn linidx(row: usize, col: usize) -> usize { + row * 1 + col * 3 + } + + fn main_() { + let mut mat = [1.0f32, 5.0, 9.0, 2.0, 6.0, 10.0, 3.0, 7.0, 11.0, 4.0, 8.0, 12.0]; + + for i in 0..2 { + for j in i + 1..3 { + if mat[linidx(j, 3)] > mat[linidx(i, 3)] { + for k in 0..4 { + let (x, rest) = mat.split_at_mut(linidx(i, k) + 1); + let a = x.last_mut().unwrap(); + let b = rest.get_mut(linidx(j, k) - linidx(i, k) - 1).unwrap(); + ::std::mem::swap(a, b); + } + } + } + } + assert_eq!([9.0, 5.0, 1.0, 10.0, 6.0, 2.0, 11.0, 7.0, 3.0, 12.0, 8.0, 4.0], mat); + } +} diff --git a/tests/ui/get_unwrap.stderr b/tests/ui/get_unwrap.stderr index 6dee4d5b4b62..fd961420dc41 100644 --- a/tests/ui/get_unwrap.stderr +++ b/tests/ui/get_unwrap.stderr @@ -1,17 +1,17 @@ error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:35:17 + --> $DIR/get_unwrap.rs:40:17 | LL | let _ = boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&boxed_slice[1]` | note: the lint level is defined here - --> $DIR/get_unwrap.rs:5:9 + --> $DIR/get_unwrap.rs:10:9 | LL | #![deny(clippy::get_unwrap)] | ^^^^^^^^^^^^^^^^^^ error: used `unwrap()` on an `Option` value - --> $DIR/get_unwrap.rs:35:17 + --> $DIR/get_unwrap.rs:40:17 | LL | let _ = boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -20,13 +20,13 @@ LL | let _ = boxed_slice.get(1).unwrap(); = note: `-D clippy::unwrap-used` implied by `-D warnings` error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:36:17 + --> $DIR/get_unwrap.rs:41:17 | LL | let _ = some_slice.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_slice[0]` error: used `unwrap()` on an `Option` value - --> $DIR/get_unwrap.rs:36:17 + --> $DIR/get_unwrap.rs:41:17 | LL | let _ = some_slice.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -34,13 +34,13 @@ LL | let _ = some_slice.get(0).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:37:17 + --> $DIR/get_unwrap.rs:42:17 | LL | let _ = some_vec.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vec[0]` error: used `unwrap()` on an `Option` value - --> $DIR/get_unwrap.rs:37:17 + --> $DIR/get_unwrap.rs:42:17 | LL | let _ = some_vec.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -48,13 +48,13 @@ LL | let _ = some_vec.get(0).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a VecDeque. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:38:17 + --> $DIR/get_unwrap.rs:43:17 | LL | let _ = some_vecdeque.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vecdeque[0]` error: used `unwrap()` on an `Option` value - --> $DIR/get_unwrap.rs:38:17 + --> $DIR/get_unwrap.rs:43:17 | LL | let _ = some_vecdeque.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -62,13 +62,13 @@ LL | let _ = some_vecdeque.get(0).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a HashMap. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:39:17 + --> $DIR/get_unwrap.rs:44:17 | LL | let _ = some_hashmap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_hashmap[&1]` error: used `unwrap()` on an `Option` value - --> $DIR/get_unwrap.rs:39:17 + --> $DIR/get_unwrap.rs:44:17 | LL | let _ = some_hashmap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -76,13 +76,13 @@ LL | let _ = some_hashmap.get(&1).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a BTreeMap. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:40:17 + --> $DIR/get_unwrap.rs:45:17 | LL | let _ = some_btreemap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_btreemap[&1]` error: used `unwrap()` on an `Option` value - --> $DIR/get_unwrap.rs:40:17 + --> $DIR/get_unwrap.rs:45:17 | LL | let _ = some_btreemap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -90,13 +90,13 @@ LL | let _ = some_btreemap.get(&1).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:44:21 + --> $DIR/get_unwrap.rs:49:21 | LL | let _: u8 = *boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `boxed_slice[1]` error: used `unwrap()` on an `Option` value - --> $DIR/get_unwrap.rs:44:22 + --> $DIR/get_unwrap.rs:49:22 | LL | let _: u8 = *boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -104,13 +104,13 @@ LL | let _: u8 = *boxed_slice.get(1).unwrap(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:49:9 + --> $DIR/get_unwrap.rs:54:9 | LL | *boxed_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `boxed_slice[0]` error: used `unwrap()` on an `Option` value - --> $DIR/get_unwrap.rs:49:10 + --> $DIR/get_unwrap.rs:54:10 | LL | *boxed_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -118,13 +118,13 @@ LL | *boxed_slice.get_mut(0).unwrap() = 1; = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:50:9 + --> $DIR/get_unwrap.rs:55:9 | LL | *some_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_slice[0]` error: used `unwrap()` on an `Option` value - --> $DIR/get_unwrap.rs:50:10 + --> $DIR/get_unwrap.rs:55:10 | LL | *some_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -132,13 +132,13 @@ LL | *some_slice.get_mut(0).unwrap() = 1; = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:51:9 + --> $DIR/get_unwrap.rs:56:9 | LL | *some_vec.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0]` error: used `unwrap()` on an `Option` value - --> $DIR/get_unwrap.rs:51:10 + --> $DIR/get_unwrap.rs:56:10 | LL | *some_vec.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -146,13 +146,13 @@ LL | *some_vec.get_mut(0).unwrap() = 1; = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:52:9 + --> $DIR/get_unwrap.rs:57:9 | LL | *some_vecdeque.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vecdeque[0]` error: used `unwrap()` on an `Option` value - --> $DIR/get_unwrap.rs:52:10 + --> $DIR/get_unwrap.rs:57:10 | LL | *some_vecdeque.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -160,13 +160,13 @@ LL | *some_vecdeque.get_mut(0).unwrap() = 1; = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:64:17 + --> $DIR/get_unwrap.rs:69:17 | LL | let _ = some_vec.get(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]` error: used `unwrap()` on an `Option` value - --> $DIR/get_unwrap.rs:64:17 + --> $DIR/get_unwrap.rs:69:17 | LL | let _ = some_vec.get(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -174,18 +174,42 @@ LL | let _ = some_vec.get(0..1).unwrap().to_vec(); = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise - --> $DIR/get_unwrap.rs:65:17 + --> $DIR/get_unwrap.rs:70:17 | LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]` error: used `unwrap()` on an `Option` value - --> $DIR/get_unwrap.rs:65:17 + --> $DIR/get_unwrap.rs:70:17 | LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message -error: aborting due to 26 previous errors +error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise + --> $DIR/get_unwrap.rs:80:24 + | +LL | let _x: &i32 = f.get(1 + 2).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `&f[1 + 2]` + +error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise + --> $DIR/get_unwrap.rs:83:18 + | +LL | let _x = f.get(1 + 2).unwrap().to_string(); + | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `f[1 + 2]` + +error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise + --> $DIR/get_unwrap.rs:86:18 + | +LL | let _x = f.get(1 + 2).unwrap().abs(); + | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `f[1 + 2]` + +error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise + --> $DIR/get_unwrap.rs:103:33 + | +LL | let b = rest.get_mut(linidx(j, k) - linidx(i, k) - 1).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&mut rest[linidx(j, k) - linidx(i, k) - 1]` + +error: aborting due to 30 previous errors diff --git a/tests/ui/if_same_then_else.rs b/tests/ui/if_same_then_else.rs index 07d2002eb27f..dad4543f84c0 100644 --- a/tests/ui/if_same_then_else.rs +++ b/tests/ui/if_same_then_else.rs @@ -21,6 +21,7 @@ fn foo() -> bool { fn if_same_then_else() { if true { + //~^ ERROR: this `if` has identical blocks Foo { bar: 42 }; 0..10; ..; @@ -29,7 +30,6 @@ fn if_same_then_else() { 0..=10; foo(); } else { - //~ ERROR same body as `if` block Foo { bar: 42 }; 0..10; ..; @@ -65,16 +65,16 @@ fn if_same_then_else() { } let _ = if true { + //~^ ERROR: this `if` has identical blocks 0.0 } else { - //~ ERROR same body as `if` block 0.0 }; let _ = if true { + //~^ ERROR: this `if` has identical blocks -0.0 } else { - //~ ERROR same body as `if` block -0.0 }; @@ -88,13 +88,14 @@ fn if_same_then_else() { } let _ = if true { + //~^ ERROR: this `if` has identical blocks 42 } else { - //~ ERROR same body as `if` block 42 }; if true { + //~^ ERROR: this `if` has identical blocks let bar = if true { 42 } else { 43 }; while foo() { @@ -102,7 +103,6 @@ fn if_same_then_else() { } bar + 1; } else { - //~ ERROR same body as `if` block let bar = if true { 42 } else { 43 }; while foo() { diff --git a/tests/ui/if_same_then_else.stderr b/tests/ui/if_same_then_else.stderr index fb23b81d36d7..a34fc565590b 100644 --- a/tests/ui/if_same_then_else.stderr +++ b/tests/ui/if_same_then_else.stderr @@ -3,22 +3,22 @@ error: this `if` has identical blocks | LL | if true { | _____________^ +LL | | LL | | Foo { bar: 42 }; LL | | 0..10; -LL | | ..; ... | LL | | foo(); LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else.rs:31:12 + --> $DIR/if_same_then_else.rs:32:12 | LL | } else { | ____________^ -LL | | //~ ERROR same body as `if` block LL | | Foo { bar: 42 }; LL | | 0..10; +LL | | ..; ... | LL | | foo(); LL | | } @@ -30,16 +30,16 @@ error: this `if` has identical blocks | LL | let _ = if true { | _____________________^ +LL | | LL | | 0.0 LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else.rs:69:12 + --> $DIR/if_same_then_else.rs:70:12 | LL | } else { | ____________^ -LL | | //~ ERROR same body as `if` block LL | | 0.0 LL | | }; | |_____^ @@ -49,16 +49,16 @@ error: this `if` has identical blocks | LL | let _ = if true { | _____________________^ +LL | | LL | | -0.0 LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else.rs:76:12 + --> $DIR/if_same_then_else.rs:77:12 | LL | } else { | ____________^ -LL | | //~ ERROR same body as `if` block LL | | -0.0 LL | | }; | |_____^ @@ -68,16 +68,16 @@ error: this `if` has identical blocks | LL | let _ = if true { | _____________________^ +LL | | LL | | 42 LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else.rs:92:12 + --> $DIR/if_same_then_else.rs:93:12 | LL | } else { | ____________^ -LL | | //~ ERROR same body as `if` block LL | | 42 LL | | }; | |_____^ @@ -87,22 +87,22 @@ error: this `if` has identical blocks | LL | if true { | _____________^ +LL | | LL | | let bar = if true { 42 } else { 43 }; LL | | -LL | | while foo() { ... | LL | | bar + 1; LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else.rs:104:12 + --> $DIR/if_same_then_else.rs:105:12 | LL | } else { | ____________^ -LL | | //~ ERROR same body as `if` block LL | | let bar = if true { 42 } else { 43 }; LL | | +LL | | while foo() { ... | LL | | bar + 1; LL | | } diff --git a/tests/ui/if_same_then_else2.rs b/tests/ui/if_same_then_else2.rs index 58167f4446db..0b171f21d0cc 100644 --- a/tests/ui/if_same_then_else2.rs +++ b/tests/ui/if_same_then_else2.rs @@ -5,6 +5,7 @@ clippy::equatable_if_let, clippy::collapsible_if, clippy::ifs_same_cond, + clippy::needless_if, clippy::needless_return, clippy::single_element_loop, clippy::branches_sharing_code @@ -12,6 +13,7 @@ fn if_same_then_else2() -> Result<&'static str, ()> { if true { + //~^ ERROR: this `if` has identical blocks for _ in &[42] { let foo: &Option<_> = &Some::(42); if foo.is_some() { @@ -21,7 +23,6 @@ fn if_same_then_else2() -> Result<&'static str, ()> { } } } else { - //~ ERROR same body as `if` block for _ in &[42] { let bar: &Option<_> = &Some::(42); if bar.is_some() { @@ -33,16 +34,16 @@ fn if_same_then_else2() -> Result<&'static str, ()> { } if true { + //~^ ERROR: this `if` has identical blocks if let Some(a) = Some(42) {} } else { - //~ ERROR same body as `if` block if let Some(a) = Some(42) {} } if true { + //~^ ERROR: this `if` has identical blocks if let (1, .., 3) = (1, 2, 3) {} } else { - //~ ERROR same body as `if` block if let (1, .., 3) = (1, 2, 3) {} } @@ -90,16 +91,16 @@ fn if_same_then_else2() -> Result<&'static str, ()> { // Same NaNs let _ = if true { + //~^ ERROR: this `if` has identical blocks f32::NAN } else { - //~ ERROR same body as `if` block f32::NAN }; if true { + //~^ ERROR: this `if` has identical blocks Ok("foo")?; } else { - //~ ERROR same body as `if` block Ok("foo")?; } @@ -121,6 +122,7 @@ fn if_same_then_else2() -> Result<&'static str, ()> { let foo = "bar"; return Ok(&foo[0..]); } else if true { + //~^ ERROR: this `if` has identical blocks let foo = ""; return Ok(&foo[0..]); } else { diff --git a/tests/ui/if_same_then_else2.stderr b/tests/ui/if_same_then_else2.stderr index 704cfd9669ac..56e5f3e45b22 100644 --- a/tests/ui/if_same_then_else2.stderr +++ b/tests/ui/if_same_then_else2.stderr @@ -1,24 +1,24 @@ error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:14:13 + --> $DIR/if_same_then_else2.rs:15:13 | LL | if true { | _____________^ +LL | | LL | | for _ in &[42] { LL | | let foo: &Option<_> = &Some::(42); -LL | | if foo.is_some() { ... | LL | | } LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:23:12 + --> $DIR/if_same_then_else2.rs:25:12 | LL | } else { | ____________^ -LL | | //~ ERROR same body as `if` block LL | | for _ in &[42] { LL | | let bar: &Option<_> = &Some::(42); +LL | | if bar.is_some() { ... | LL | | } LL | | } @@ -26,93 +26,94 @@ LL | | } = note: `-D clippy::if-same-then-else` implied by `-D warnings` error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:35:13 + --> $DIR/if_same_then_else2.rs:36:13 | LL | if true { | _____________^ +LL | | LL | | if let Some(a) = Some(42) {} LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:37:12 + --> $DIR/if_same_then_else2.rs:39:12 | LL | } else { | ____________^ -LL | | //~ ERROR same body as `if` block LL | | if let Some(a) = Some(42) {} LL | | } | |_____^ error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:42:13 + --> $DIR/if_same_then_else2.rs:43:13 | LL | if true { | _____________^ +LL | | LL | | if let (1, .., 3) = (1, 2, 3) {} LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:44:12 + --> $DIR/if_same_then_else2.rs:46:12 | LL | } else { | ____________^ -LL | | //~ ERROR same body as `if` block LL | | if let (1, .., 3) = (1, 2, 3) {} LL | | } | |_____^ error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:92:21 + --> $DIR/if_same_then_else2.rs:93:21 | LL | let _ = if true { | _____________________^ +LL | | LL | | f32::NAN LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:94:12 + --> $DIR/if_same_then_else2.rs:96:12 | LL | } else { | ____________^ -LL | | //~ ERROR same body as `if` block LL | | f32::NAN LL | | }; | |_____^ error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:99:13 + --> $DIR/if_same_then_else2.rs:100:13 | LL | if true { | _____________^ +LL | | LL | | Ok("foo")?; LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:101:12 + --> $DIR/if_same_then_else2.rs:103:12 | LL | } else { | ____________^ -LL | | //~ ERROR same body as `if` block LL | | Ok("foo")?; LL | | } | |_____^ error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:123:20 + --> $DIR/if_same_then_else2.rs:124:20 | LL | } else if true { | ____________________^ +LL | | LL | | let foo = ""; LL | | return Ok(&foo[0..]); LL | | } else { | |_____^ | note: same as this - --> $DIR/if_same_then_else2.rs:126:12 + --> $DIR/if_same_then_else2.rs:128:12 | LL | } else { | ____________^ diff --git a/tests/ui/ifs_same_cond.rs b/tests/ui/ifs_same_cond.rs index f62da157d1b9..5c338e3c5c8f 100644 --- a/tests/ui/ifs_same_cond.rs +++ b/tests/ui/ifs_same_cond.rs @@ -1,5 +1,10 @@ #![warn(clippy::ifs_same_cond)] -#![allow(clippy::if_same_then_else, clippy::comparison_chain, clippy::needless_else)] // all empty blocks +#![allow( + clippy::if_same_then_else, + clippy::comparison_chain, + clippy::needless_if, + clippy::needless_else +)] // all empty blocks fn ifs_same_cond() { let a = 0; @@ -7,18 +12,18 @@ fn ifs_same_cond() { if b { } else if b { - //~ ERROR ifs same condition + //~^ ERROR: this `if` has the same condition as a previous `if` } if a == 1 { } else if a == 1 { - //~ ERROR ifs same condition + //~^ ERROR: this `if` has the same condition as a previous `if` } if 2 * a == 1 { } else if 2 * a == 2 { } else if 2 * a == 1 { - //~ ERROR ifs same condition + //~^ ERROR: this `if` has the same condition as a previous `if` } else if a == 1 { } @@ -47,6 +52,7 @@ fn issue10272() { let a = String::from("ha"); if a.contains("ah") { } else if a.contains("ah") { + //~^ ERROR: this `if` has the same condition as a previous `if` // Trigger this lint } else if a.contains("ha") { } else if a == "wow" { diff --git a/tests/ui/ifs_same_cond.stderr b/tests/ui/ifs_same_cond.stderr index 9519f6904cb1..8d70934476cb 100644 --- a/tests/ui/ifs_same_cond.stderr +++ b/tests/ui/ifs_same_cond.stderr @@ -1,48 +1,48 @@ error: this `if` has the same condition as a previous `if` - --> $DIR/ifs_same_cond.rs:9:15 + --> $DIR/ifs_same_cond.rs:14:15 | LL | } else if b { | ^ | note: same as this - --> $DIR/ifs_same_cond.rs:8:8 + --> $DIR/ifs_same_cond.rs:13:8 | LL | if b { | ^ = note: `-D clippy::ifs-same-cond` implied by `-D warnings` error: this `if` has the same condition as a previous `if` - --> $DIR/ifs_same_cond.rs:14:15 + --> $DIR/ifs_same_cond.rs:19:15 | LL | } else if a == 1 { | ^^^^^^ | note: same as this - --> $DIR/ifs_same_cond.rs:13:8 + --> $DIR/ifs_same_cond.rs:18:8 | LL | if a == 1 { | ^^^^^^ error: this `if` has the same condition as a previous `if` - --> $DIR/ifs_same_cond.rs:20:15 + --> $DIR/ifs_same_cond.rs:25:15 | LL | } else if 2 * a == 1 { | ^^^^^^^^^^ | note: same as this - --> $DIR/ifs_same_cond.rs:18:8 + --> $DIR/ifs_same_cond.rs:23:8 | LL | if 2 * a == 1 { | ^^^^^^^^^^ error: this `if` has the same condition as a previous `if` - --> $DIR/ifs_same_cond.rs:49:15 + --> $DIR/ifs_same_cond.rs:54:15 | LL | } else if a.contains("ah") { | ^^^^^^^^^^^^^^^^ | note: same as this - --> $DIR/ifs_same_cond.rs:48:8 + --> $DIR/ifs_same_cond.rs:53:8 | LL | if a.contains("ah") { | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/implicit_hasher.rs b/tests/ui/implicit_hasher.rs index ca7c12213728..7ed7bf94a4b3 100644 --- a/tests/ui/implicit_hasher.rs +++ b/tests/ui/implicit_hasher.rs @@ -1,4 +1,4 @@ -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![deny(clippy::implicit_hasher)] #![allow(unused)] diff --git a/tests/ui/inconsistent_struct_constructor.fixed b/tests/ui/inconsistent_struct_constructor.fixed index 620d45e6828c..d84346e8789d 100644 --- a/tests/ui/inconsistent_struct_constructor.fixed +++ b/tests/ui/inconsistent_struct_constructor.fixed @@ -1,5 +1,5 @@ //@run-rustfix -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![warn(clippy::inconsistent_struct_constructor)] #![allow(clippy::redundant_field_names)] diff --git a/tests/ui/inconsistent_struct_constructor.rs b/tests/ui/inconsistent_struct_constructor.rs index 10ffadcb2ba9..87fba7448e3a 100644 --- a/tests/ui/inconsistent_struct_constructor.rs +++ b/tests/ui/inconsistent_struct_constructor.rs @@ -1,5 +1,5 @@ //@run-rustfix -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![warn(clippy::inconsistent_struct_constructor)] #![allow(clippy::redundant_field_names)] diff --git a/tests/ui/incorrect_clone_impl_on_copy_type.fixed b/tests/ui/incorrect_clone_impl_on_copy_type.fixed new file mode 100644 index 000000000000..ac482dcda1ee --- /dev/null +++ b/tests/ui/incorrect_clone_impl_on_copy_type.fixed @@ -0,0 +1,97 @@ +//@run-rustfix +#![allow(clippy::clone_on_copy, unused)] +#![no_main] + +// lint + +struct A(u32); + +impl Clone for A { + fn clone(&self) -> Self { *self } + + +} + +impl Copy for A {} + +// do not lint + +struct B(u32); + +impl Clone for B { + fn clone(&self) -> Self { + *self + } +} + +impl Copy for B {} + +// do not lint derived (clone's implementation is `*self` here anyway) + +#[derive(Clone, Copy)] +struct C(u32); + +// do not lint derived (fr this time) + +struct D(u32); + +#[automatically_derived] +impl Clone for D { + fn clone(&self) -> Self { + Self(self.0) + } + + fn clone_from(&mut self, source: &Self) { + source.clone(); + *self = source.clone(); + } +} + +impl Copy for D {} + +// do not lint if clone is not manually implemented + +struct E(u32); + +#[automatically_derived] +impl Clone for E { + fn clone(&self) -> Self { + Self(self.0) + } + + fn clone_from(&mut self, source: &Self) { + source.clone(); + *self = source.clone(); + } +} + +impl Copy for E {} + +// lint since clone is not derived + +#[derive(Copy)] +struct F(u32); + +impl Clone for F { + fn clone(&self) -> Self { *self } + + +} + +// do not lint since copy has more restrictive bounds + +#[derive(Eq, PartialEq)] +struct Uwu(A); + +impl Clone for Uwu
{ + fn clone(&self) -> Self { + Self(self.0) + } + + fn clone_from(&mut self, source: &Self) { + source.clone(); + *self = source.clone(); + } +} + +impl Copy for Uwu {} diff --git a/tests/ui/incorrect_clone_impl_on_copy_type.rs b/tests/ui/incorrect_clone_impl_on_copy_type.rs new file mode 100644 index 000000000000..00775874ff58 --- /dev/null +++ b/tests/ui/incorrect_clone_impl_on_copy_type.rs @@ -0,0 +1,107 @@ +//@run-rustfix +#![allow(clippy::clone_on_copy, unused)] +#![no_main] + +// lint + +struct A(u32); + +impl Clone for A { + fn clone(&self) -> Self { + Self(self.0) + } + + fn clone_from(&mut self, source: &Self) { + source.clone(); + *self = source.clone(); + } +} + +impl Copy for A {} + +// do not lint + +struct B(u32); + +impl Clone for B { + fn clone(&self) -> Self { + *self + } +} + +impl Copy for B {} + +// do not lint derived (clone's implementation is `*self` here anyway) + +#[derive(Clone, Copy)] +struct C(u32); + +// do not lint derived (fr this time) + +struct D(u32); + +#[automatically_derived] +impl Clone for D { + fn clone(&self) -> Self { + Self(self.0) + } + + fn clone_from(&mut self, source: &Self) { + source.clone(); + *self = source.clone(); + } +} + +impl Copy for D {} + +// do not lint if clone is not manually implemented + +struct E(u32); + +#[automatically_derived] +impl Clone for E { + fn clone(&self) -> Self { + Self(self.0) + } + + fn clone_from(&mut self, source: &Self) { + source.clone(); + *self = source.clone(); + } +} + +impl Copy for E {} + +// lint since clone is not derived + +#[derive(Copy)] +struct F(u32); + +impl Clone for F { + fn clone(&self) -> Self { + Self(self.0) + } + + fn clone_from(&mut self, source: &Self) { + source.clone(); + *self = source.clone(); + } +} + +// do not lint since copy has more restrictive bounds + +#[derive(Eq, PartialEq)] +struct Uwu(A); + +impl Clone for Uwu { + fn clone(&self) -> Self { + Self(self.0) + } + + fn clone_from(&mut self, source: &Self) { + source.clone(); + *self = source.clone(); + } +} + +impl Copy for Uwu {} diff --git a/tests/ui/incorrect_clone_impl_on_copy_type.stderr b/tests/ui/incorrect_clone_impl_on_copy_type.stderr new file mode 100644 index 000000000000..0021841aa860 --- /dev/null +++ b/tests/ui/incorrect_clone_impl_on_copy_type.stderr @@ -0,0 +1,40 @@ +error: incorrect implementation of `clone` on a `Copy` type + --> $DIR/incorrect_clone_impl_on_copy_type.rs:10:29 + | +LL | fn clone(&self) -> Self { + | _____________________________^ +LL | | Self(self.0) +LL | | } + | |_____^ help: change this to: `{ *self }` + | + = note: `#[deny(clippy::incorrect_clone_impl_on_copy_type)]` on by default + +error: incorrect implementation of `clone_from` on a `Copy` type + --> $DIR/incorrect_clone_impl_on_copy_type.rs:14:5 + | +LL | / fn clone_from(&mut self, source: &Self) { +LL | | source.clone(); +LL | | *self = source.clone(); +LL | | } + | |_____^ help: remove this + +error: incorrect implementation of `clone` on a `Copy` type + --> $DIR/incorrect_clone_impl_on_copy_type.rs:81:29 + | +LL | fn clone(&self) -> Self { + | _____________________________^ +LL | | Self(self.0) +LL | | } + | |_____^ help: change this to: `{ *self }` + +error: incorrect implementation of `clone_from` on a `Copy` type + --> $DIR/incorrect_clone_impl_on_copy_type.rs:85:5 + | +LL | / fn clone_from(&mut self, source: &Self) { +LL | | source.clone(); +LL | | *self = source.clone(); +LL | | } + | |_____^ help: remove this + +error: aborting due to 4 previous errors + diff --git a/tests/ui/indexing_slicing_index.rs b/tests/ui/indexing_slicing_index.rs index 26abc9edb5e4..16f9e47e8532 100644 --- a/tests/ui/indexing_slicing_index.rs +++ b/tests/ui/indexing_slicing_index.rs @@ -3,7 +3,12 @@ // We also check the out_of_bounds_indexing lint here, because it lints similar things and // we want to avoid false positives. #![warn(clippy::out_of_bounds_indexing)] -#![allow(unconditional_panic, clippy::no_effect, clippy::unnecessary_operation)] +#![allow( + unconditional_panic, + clippy::no_effect, + clippy::unnecessary_operation, + clippy::useless_vec +)] const ARR: [i32; 2] = [1, 2]; const REF: &i32 = &ARR[idx()]; // This should be linted, since `suppress-restriction-lint-in-const` default is false. diff --git a/tests/ui/indexing_slicing_index.stderr b/tests/ui/indexing_slicing_index.stderr index 8fd77913a3fd..f4357c1d592d 100644 --- a/tests/ui/indexing_slicing_index.stderr +++ b/tests/ui/indexing_slicing_index.stderr @@ -1,5 +1,5 @@ error: indexing may panic - --> $DIR/indexing_slicing_index.rs:9:20 + --> $DIR/indexing_slicing_index.rs:14:20 | LL | const REF: &i32 = &ARR[idx()]; // This should be linted, since `suppress-restriction-lint-in-const` default is false. | ^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | const REF: &i32 = &ARR[idx()]; // This should be linted, since `suppress-re = note: `-D clippy::indexing-slicing` implied by `-D warnings` error: indexing may panic - --> $DIR/indexing_slicing_index.rs:10:24 + --> $DIR/indexing_slicing_index.rs:15:24 | LL | const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts. | ^^^^^^^^^^^ @@ -18,19 +18,19 @@ LL | const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts. = note: the suggestion might not be applicable in constant blocks error[E0080]: evaluation of `main::{constant#3}` failed - --> $DIR/indexing_slicing_index.rs:31:14 + --> $DIR/indexing_slicing_index.rs:36:14 | LL | const { &ARR[idx4()] }; // This should be linted, since `suppress-restriction-lint-in-const` default is false. | ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4 note: erroneous constant used - --> $DIR/indexing_slicing_index.rs:31:5 + --> $DIR/indexing_slicing_index.rs:36:5 | LL | const { &ARR[idx4()] }; // This should be linted, since `suppress-restriction-lint-in-const` default is false. | ^^^^^^^^^^^^^^^^^^^^^^ error: indexing may panic - --> $DIR/indexing_slicing_index.rs:22:5 + --> $DIR/indexing_slicing_index.rs:27:5 | LL | x[index]; | ^^^^^^^^ @@ -38,7 +38,7 @@ LL | x[index]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> $DIR/indexing_slicing_index.rs:30:14 + --> $DIR/indexing_slicing_index.rs:35:14 | LL | const { &ARR[idx()] }; // This should be linted, since `suppress-restriction-lint-in-const` default is false. | ^^^^^^^^^^ @@ -47,7 +47,7 @@ LL | const { &ARR[idx()] }; // This should be linted, since `suppress-restri = note: the suggestion might not be applicable in constant blocks error: indexing may panic - --> $DIR/indexing_slicing_index.rs:31:14 + --> $DIR/indexing_slicing_index.rs:36:14 | LL | const { &ARR[idx4()] }; // This should be linted, since `suppress-restriction-lint-in-const` default is false. | ^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | const { &ARR[idx4()] }; // This should be linted, since `suppress-restr = note: the suggestion might not be applicable in constant blocks error: indexing may panic - --> $DIR/indexing_slicing_index.rs:38:5 + --> $DIR/indexing_slicing_index.rs:43:5 | LL | v[0]; | ^^^^ @@ -64,7 +64,7 @@ LL | v[0]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> $DIR/indexing_slicing_index.rs:39:5 + --> $DIR/indexing_slicing_index.rs:44:5 | LL | v[10]; | ^^^^^ @@ -72,7 +72,7 @@ LL | v[10]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> $DIR/indexing_slicing_index.rs:40:5 + --> $DIR/indexing_slicing_index.rs:45:5 | LL | v[1 << 3]; | ^^^^^^^^^ @@ -80,7 +80,7 @@ LL | v[1 << 3]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> $DIR/indexing_slicing_index.rs:46:5 + --> $DIR/indexing_slicing_index.rs:51:5 | LL | v[N]; | ^^^^ @@ -88,7 +88,7 @@ LL | v[N]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> $DIR/indexing_slicing_index.rs:47:5 + --> $DIR/indexing_slicing_index.rs:52:5 | LL | v[M]; | ^^^^ @@ -96,7 +96,7 @@ LL | v[M]; = help: consider using `.get(n)` or `.get_mut(n)` instead error[E0080]: evaluation of constant value failed - --> $DIR/indexing_slicing_index.rs:10:24 + --> $DIR/indexing_slicing_index.rs:15:24 | LL | const REF_ERR: &i32 = &ARR[idx4()]; // Ok, let rustc handle const contexts. | ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4 diff --git a/tests/ui/indexing_slicing_slice.rs b/tests/ui/indexing_slicing_slice.rs index 7b107db39f02..939b6ac36bde 100644 --- a/tests/ui/indexing_slicing_slice.rs +++ b/tests/ui/indexing_slicing_slice.rs @@ -2,7 +2,7 @@ // We also check the out_of_bounds_indexing lint here, because it lints similar things and // we want to avoid false positives. #![warn(clippy::out_of_bounds_indexing)] -#![allow(clippy::no_effect, clippy::unnecessary_operation)] +#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::useless_vec)] fn main() { let x = [1, 2, 3, 4]; diff --git a/tests/ui/into_iter_on_ref.fixed b/tests/ui/into_iter_on_ref.fixed index 9f550acb1577..af197e33fd83 100644 --- a/tests/ui/into_iter_on_ref.fixed +++ b/tests/ui/into_iter_on_ref.fixed @@ -11,35 +11,35 @@ fn main() { for _ in &vec![X, X] {} let _ = vec![1, 2, 3].into_iter(); - let _ = (&vec![1, 2, 3]).iter(); //~ WARN equivalent to .iter() - let _ = vec![1, 2, 3].into_boxed_slice().iter(); //~ WARN equivalent to .iter() - let _ = std::rc::Rc::from(&[X][..]).iter(); //~ WARN equivalent to .iter() - let _ = std::sync::Arc::from(&[X][..]).iter(); //~ WARN equivalent to .iter() + let _ = (&vec![1, 2, 3]).iter(); //~ ERROR: equivalent to `.iter() + let _ = vec![1, 2, 3].into_boxed_slice().iter(); //~ ERROR: equivalent to `.iter() + let _ = std::rc::Rc::from(&[X][..]).iter(); //~ ERROR: equivalent to `.iter() + let _ = std::sync::Arc::from(&[X][..]).iter(); //~ ERROR: equivalent to `.iter() - let _ = (&&&&&&&[1, 2, 3]).iter(); //~ ERROR equivalent to .iter() - let _ = (&&&&mut &&&[1, 2, 3]).iter(); //~ ERROR equivalent to .iter() - let _ = (&mut &mut &mut [1, 2, 3]).iter_mut(); //~ ERROR equivalent to .iter_mut() + let _ = (&&&&&&&[1, 2, 3]).iter(); //~ ERROR: equivalent to `.iter() + let _ = (&&&&mut &&&[1, 2, 3]).iter(); //~ ERROR: equivalent to `.iter() + let _ = (&mut &mut &mut [1, 2, 3]).iter_mut(); //~ ERROR: equivalent to `.iter_mut() - let _ = (&Some(4)).iter(); //~ WARN equivalent to .iter() - let _ = (&mut Some(5)).iter_mut(); //~ WARN equivalent to .iter_mut() - let _ = (&Ok::<_, i32>(6)).iter(); //~ WARN equivalent to .iter() - let _ = (&mut Err::(7)).iter_mut(); //~ WARN equivalent to .iter_mut() - let _ = (&Vec::::new()).iter(); //~ WARN equivalent to .iter() - let _ = (&mut Vec::::new()).iter_mut(); //~ WARN equivalent to .iter_mut() - let _ = (&BTreeMap::::new()).iter(); //~ WARN equivalent to .iter() - let _ = (&mut BTreeMap::::new()).iter_mut(); //~ WARN equivalent to .iter_mut() - let _ = (&VecDeque::::new()).iter(); //~ WARN equivalent to .iter() - let _ = (&mut VecDeque::::new()).iter_mut(); //~ WARN equivalent to .iter_mut() - let _ = (&LinkedList::::new()).iter(); //~ WARN equivalent to .iter() - let _ = (&mut LinkedList::::new()).iter_mut(); //~ WARN equivalent to .iter_mut() - let _ = (&HashMap::::new()).iter(); //~ WARN equivalent to .iter() - let _ = (&mut HashMap::::new()).iter_mut(); //~ WARN equivalent to .iter_mut() + let _ = (&Some(4)).iter(); //~ ERROR: equivalent to `.iter() + let _ = (&mut Some(5)).iter_mut(); //~ ERROR: equivalent to `.iter_mut() + let _ = (&Ok::<_, i32>(6)).iter(); //~ ERROR: equivalent to `.iter() + let _ = (&mut Err::(7)).iter_mut(); //~ ERROR: equivalent to `.iter_mut() + let _ = (&Vec::::new()).iter(); //~ ERROR: equivalent to `.iter() + let _ = (&mut Vec::::new()).iter_mut(); //~ ERROR: equivalent to `.iter_mut() + let _ = (&BTreeMap::::new()).iter(); //~ ERROR: equivalent to `.iter() + let _ = (&mut BTreeMap::::new()).iter_mut(); //~ ERROR: equivalent to `.iter_mut() + let _ = (&VecDeque::::new()).iter(); //~ ERROR: equivalent to `.iter() + let _ = (&mut VecDeque::::new()).iter_mut(); //~ ERROR: equivalent to `.iter_mut() + let _ = (&LinkedList::::new()).iter(); //~ ERROR: equivalent to `.iter() + let _ = (&mut LinkedList::::new()).iter_mut(); //~ ERROR: equivalent to `.iter_mut() + let _ = (&HashMap::::new()).iter(); //~ ERROR: equivalent to `.iter() + let _ = (&mut HashMap::::new()).iter_mut(); //~ ERROR: equivalent to `.iter_mut() - let _ = (&BTreeSet::::new()).iter(); //~ WARN equivalent to .iter() - let _ = (&BinaryHeap::::new()).iter(); //~ WARN equivalent to .iter() - let _ = (&HashSet::::new()).iter(); //~ WARN equivalent to .iter() - let _ = std::path::Path::new("12/34").iter(); //~ WARN equivalent to .iter() - let _ = std::path::PathBuf::from("12/34").iter(); //~ ERROR equivalent to .iter() + let _ = (&BTreeSet::::new()).iter(); //~ ERROR: equivalent to `.iter() + let _ = (&BinaryHeap::::new()).iter(); //~ ERROR: equivalent to `.iter() + let _ = (&HashSet::::new()).iter(); //~ ERROR: equivalent to `.iter() + let _ = std::path::Path::new("12/34").iter(); //~ ERROR: equivalent to `.iter() + let _ = std::path::PathBuf::from("12/34").iter(); //~ ERROR: equivalent to `.iter() - let _ = (&[1, 2, 3]).iter().next(); //~ WARN equivalent to .iter() + let _ = (&[1, 2, 3]).iter().next(); //~ ERROR: equivalent to `.iter() } diff --git a/tests/ui/into_iter_on_ref.rs b/tests/ui/into_iter_on_ref.rs index 3381ae04dcec..3ac13d7dd3e1 100644 --- a/tests/ui/into_iter_on_ref.rs +++ b/tests/ui/into_iter_on_ref.rs @@ -11,35 +11,35 @@ fn main() { for _ in &vec![X, X] {} let _ = vec![1, 2, 3].into_iter(); - let _ = (&vec![1, 2, 3]).into_iter(); //~ WARN equivalent to .iter() - let _ = vec![1, 2, 3].into_boxed_slice().into_iter(); //~ WARN equivalent to .iter() - let _ = std::rc::Rc::from(&[X][..]).into_iter(); //~ WARN equivalent to .iter() - let _ = std::sync::Arc::from(&[X][..]).into_iter(); //~ WARN equivalent to .iter() + let _ = (&vec![1, 2, 3]).into_iter(); //~ ERROR: equivalent to `.iter() + let _ = vec![1, 2, 3].into_boxed_slice().into_iter(); //~ ERROR: equivalent to `.iter() + let _ = std::rc::Rc::from(&[X][..]).into_iter(); //~ ERROR: equivalent to `.iter() + let _ = std::sync::Arc::from(&[X][..]).into_iter(); //~ ERROR: equivalent to `.iter() - let _ = (&&&&&&&[1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter() - let _ = (&&&&mut &&&[1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter() - let _ = (&mut &mut &mut [1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter_mut() + let _ = (&&&&&&&[1, 2, 3]).into_iter(); //~ ERROR: equivalent to `.iter() + let _ = (&&&&mut &&&[1, 2, 3]).into_iter(); //~ ERROR: equivalent to `.iter() + let _ = (&mut &mut &mut [1, 2, 3]).into_iter(); //~ ERROR: equivalent to `.iter_mut() - let _ = (&Some(4)).into_iter(); //~ WARN equivalent to .iter() - let _ = (&mut Some(5)).into_iter(); //~ WARN equivalent to .iter_mut() - let _ = (&Ok::<_, i32>(6)).into_iter(); //~ WARN equivalent to .iter() - let _ = (&mut Err::(7)).into_iter(); //~ WARN equivalent to .iter_mut() - let _ = (&Vec::::new()).into_iter(); //~ WARN equivalent to .iter() - let _ = (&mut Vec::::new()).into_iter(); //~ WARN equivalent to .iter_mut() - let _ = (&BTreeMap::::new()).into_iter(); //~ WARN equivalent to .iter() - let _ = (&mut BTreeMap::::new()).into_iter(); //~ WARN equivalent to .iter_mut() - let _ = (&VecDeque::::new()).into_iter(); //~ WARN equivalent to .iter() - let _ = (&mut VecDeque::::new()).into_iter(); //~ WARN equivalent to .iter_mut() - let _ = (&LinkedList::::new()).into_iter(); //~ WARN equivalent to .iter() - let _ = (&mut LinkedList::::new()).into_iter(); //~ WARN equivalent to .iter_mut() - let _ = (&HashMap::::new()).into_iter(); //~ WARN equivalent to .iter() - let _ = (&mut HashMap::::new()).into_iter(); //~ WARN equivalent to .iter_mut() + let _ = (&Some(4)).into_iter(); //~ ERROR: equivalent to `.iter() + let _ = (&mut Some(5)).into_iter(); //~ ERROR: equivalent to `.iter_mut() + let _ = (&Ok::<_, i32>(6)).into_iter(); //~ ERROR: equivalent to `.iter() + let _ = (&mut Err::(7)).into_iter(); //~ ERROR: equivalent to `.iter_mut() + let _ = (&Vec::::new()).into_iter(); //~ ERROR: equivalent to `.iter() + let _ = (&mut Vec::::new()).into_iter(); //~ ERROR: equivalent to `.iter_mut() + let _ = (&BTreeMap::::new()).into_iter(); //~ ERROR: equivalent to `.iter() + let _ = (&mut BTreeMap::::new()).into_iter(); //~ ERROR: equivalent to `.iter_mut() + let _ = (&VecDeque::::new()).into_iter(); //~ ERROR: equivalent to `.iter() + let _ = (&mut VecDeque::::new()).into_iter(); //~ ERROR: equivalent to `.iter_mut() + let _ = (&LinkedList::::new()).into_iter(); //~ ERROR: equivalent to `.iter() + let _ = (&mut LinkedList::::new()).into_iter(); //~ ERROR: equivalent to `.iter_mut() + let _ = (&HashMap::::new()).into_iter(); //~ ERROR: equivalent to `.iter() + let _ = (&mut HashMap::::new()).into_iter(); //~ ERROR: equivalent to `.iter_mut() - let _ = (&BTreeSet::::new()).into_iter(); //~ WARN equivalent to .iter() - let _ = (&BinaryHeap::::new()).into_iter(); //~ WARN equivalent to .iter() - let _ = (&HashSet::::new()).into_iter(); //~ WARN equivalent to .iter() - let _ = std::path::Path::new("12/34").into_iter(); //~ WARN equivalent to .iter() - let _ = std::path::PathBuf::from("12/34").into_iter(); //~ ERROR equivalent to .iter() + let _ = (&BTreeSet::::new()).into_iter(); //~ ERROR: equivalent to `.iter() + let _ = (&BinaryHeap::::new()).into_iter(); //~ ERROR: equivalent to `.iter() + let _ = (&HashSet::::new()).into_iter(); //~ ERROR: equivalent to `.iter() + let _ = std::path::Path::new("12/34").into_iter(); //~ ERROR: equivalent to `.iter() + let _ = std::path::PathBuf::from("12/34").into_iter(); //~ ERROR: equivalent to `.iter() - let _ = (&[1, 2, 3]).into_iter().next(); //~ WARN equivalent to .iter() + let _ = (&[1, 2, 3]).into_iter().next(); //~ ERROR: equivalent to `.iter() } diff --git a/tests/ui/into_iter_on_ref.stderr b/tests/ui/into_iter_on_ref.stderr index 28003b365bbd..06014a93f8c1 100644 --- a/tests/ui/into_iter_on_ref.stderr +++ b/tests/ui/into_iter_on_ref.stderr @@ -1,7 +1,7 @@ error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Vec` --> $DIR/into_iter_on_ref.rs:14:30 | -LL | let _ = (&vec![1, 2, 3]).into_iter(); //~ WARN equivalent to .iter() +LL | let _ = (&vec![1, 2, 3]).into_iter(); | ^^^^^^^^^ help: call directly: `iter` | = note: `-D clippy::into-iter-on-ref` implied by `-D warnings` @@ -9,157 +9,157 @@ LL | let _ = (&vec![1, 2, 3]).into_iter(); //~ WARN equivalent to .iter() error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `slice` --> $DIR/into_iter_on_ref.rs:15:46 | -LL | let _ = vec![1, 2, 3].into_boxed_slice().into_iter(); //~ WARN equivalent to .iter() +LL | let _ = vec![1, 2, 3].into_boxed_slice().into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `slice` --> $DIR/into_iter_on_ref.rs:16:41 | -LL | let _ = std::rc::Rc::from(&[X][..]).into_iter(); //~ WARN equivalent to .iter() +LL | let _ = std::rc::Rc::from(&[X][..]).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `slice` --> $DIR/into_iter_on_ref.rs:17:44 | -LL | let _ = std::sync::Arc::from(&[X][..]).into_iter(); //~ WARN equivalent to .iter() +LL | let _ = std::sync::Arc::from(&[X][..]).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `array` --> $DIR/into_iter_on_ref.rs:19:32 | -LL | let _ = (&&&&&&&[1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter() +LL | let _ = (&&&&&&&[1, 2, 3]).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `array` --> $DIR/into_iter_on_ref.rs:20:36 | -LL | let _ = (&&&&mut &&&[1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter() +LL | let _ = (&&&&mut &&&[1, 2, 3]).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `array` --> $DIR/into_iter_on_ref.rs:21:40 | -LL | let _ = (&mut &mut &mut [1, 2, 3]).into_iter(); //~ ERROR equivalent to .iter_mut() +LL | let _ = (&mut &mut &mut [1, 2, 3]).into_iter(); | ^^^^^^^^^ help: call directly: `iter_mut` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Option` --> $DIR/into_iter_on_ref.rs:23:24 | -LL | let _ = (&Some(4)).into_iter(); //~ WARN equivalent to .iter() +LL | let _ = (&Some(4)).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `Option` --> $DIR/into_iter_on_ref.rs:24:28 | -LL | let _ = (&mut Some(5)).into_iter(); //~ WARN equivalent to .iter_mut() +LL | let _ = (&mut Some(5)).into_iter(); | ^^^^^^^^^ help: call directly: `iter_mut` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Result` --> $DIR/into_iter_on_ref.rs:25:32 | -LL | let _ = (&Ok::<_, i32>(6)).into_iter(); //~ WARN equivalent to .iter() +LL | let _ = (&Ok::<_, i32>(6)).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `Result` --> $DIR/into_iter_on_ref.rs:26:37 | -LL | let _ = (&mut Err::(7)).into_iter(); //~ WARN equivalent to .iter_mut() +LL | let _ = (&mut Err::(7)).into_iter(); | ^^^^^^^^^ help: call directly: `iter_mut` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Vec` --> $DIR/into_iter_on_ref.rs:27:34 | -LL | let _ = (&Vec::::new()).into_iter(); //~ WARN equivalent to .iter() +LL | let _ = (&Vec::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `Vec` --> $DIR/into_iter_on_ref.rs:28:38 | -LL | let _ = (&mut Vec::::new()).into_iter(); //~ WARN equivalent to .iter_mut() +LL | let _ = (&mut Vec::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter_mut` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `BTreeMap` --> $DIR/into_iter_on_ref.rs:29:44 | -LL | let _ = (&BTreeMap::::new()).into_iter(); //~ WARN equivalent to .iter() +LL | let _ = (&BTreeMap::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `BTreeMap` --> $DIR/into_iter_on_ref.rs:30:48 | -LL | let _ = (&mut BTreeMap::::new()).into_iter(); //~ WARN equivalent to .iter_mut() +LL | let _ = (&mut BTreeMap::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter_mut` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `VecDeque` --> $DIR/into_iter_on_ref.rs:31:39 | -LL | let _ = (&VecDeque::::new()).into_iter(); //~ WARN equivalent to .iter() +LL | let _ = (&VecDeque::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `VecDeque` --> $DIR/into_iter_on_ref.rs:32:43 | -LL | let _ = (&mut VecDeque::::new()).into_iter(); //~ WARN equivalent to .iter_mut() +LL | let _ = (&mut VecDeque::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter_mut` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `LinkedList` --> $DIR/into_iter_on_ref.rs:33:41 | -LL | let _ = (&LinkedList::::new()).into_iter(); //~ WARN equivalent to .iter() +LL | let _ = (&LinkedList::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `LinkedList` --> $DIR/into_iter_on_ref.rs:34:45 | -LL | let _ = (&mut LinkedList::::new()).into_iter(); //~ WARN equivalent to .iter_mut() +LL | let _ = (&mut LinkedList::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter_mut` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `HashMap` --> $DIR/into_iter_on_ref.rs:35:43 | -LL | let _ = (&HashMap::::new()).into_iter(); //~ WARN equivalent to .iter() +LL | let _ = (&HashMap::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `HashMap` --> $DIR/into_iter_on_ref.rs:36:47 | -LL | let _ = (&mut HashMap::::new()).into_iter(); //~ WARN equivalent to .iter_mut() +LL | let _ = (&mut HashMap::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter_mut` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `BTreeSet` --> $DIR/into_iter_on_ref.rs:38:39 | -LL | let _ = (&BTreeSet::::new()).into_iter(); //~ WARN equivalent to .iter() +LL | let _ = (&BTreeSet::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `BinaryHeap` --> $DIR/into_iter_on_ref.rs:39:41 | -LL | let _ = (&BinaryHeap::::new()).into_iter(); //~ WARN equivalent to .iter() +LL | let _ = (&BinaryHeap::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `HashSet` --> $DIR/into_iter_on_ref.rs:40:38 | -LL | let _ = (&HashSet::::new()).into_iter(); //~ WARN equivalent to .iter() +LL | let _ = (&HashSet::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Path` --> $DIR/into_iter_on_ref.rs:41:43 | -LL | let _ = std::path::Path::new("12/34").into_iter(); //~ WARN equivalent to .iter() +LL | let _ = std::path::Path::new("12/34").into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `PathBuf` --> $DIR/into_iter_on_ref.rs:42:47 | -LL | let _ = std::path::PathBuf::from("12/34").into_iter(); //~ ERROR equivalent to .iter() +LL | let _ = std::path::PathBuf::from("12/34").into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `array` --> $DIR/into_iter_on_ref.rs:44:26 | -LL | let _ = (&[1, 2, 3]).into_iter().next(); //~ WARN equivalent to .iter() +LL | let _ = (&[1, 2, 3]).into_iter().next(); | ^^^^^^^^^ help: call directly: `iter` error: aborting due to 27 previous errors diff --git a/tests/ui/issue-3145.rs b/tests/ui/issue-3145.rs index 586d13647d15..0b07de1144ce 100644 --- a/tests/ui/issue-3145.rs +++ b/tests/ui/issue-3145.rs @@ -1,3 +1,3 @@ fn main() { - println!("{}" a); //~ERROR expected `,`, found `a` + println!("{}" a); //~ERROR: expected `,`, found `a` } diff --git a/tests/ui/issue-3145.stderr b/tests/ui/issue-3145.stderr index a35032aa150d..d7c2c88a2047 100644 --- a/tests/ui/issue-3145.stderr +++ b/tests/ui/issue-3145.stderr @@ -1,7 +1,7 @@ error: expected `,`, found `a` --> $DIR/issue-3145.rs:2:19 | -LL | println!("{}" a); //~ERROR expected `,`, found `a` +LL | println!("{}" a); | ^ expected `,` error: aborting due to previous error diff --git a/tests/ui/issue_4266.stderr b/tests/ui/issue_4266.stderr index fd553aa4538a..5b60646ef21d 100644 --- a/tests/ui/issue_4266.stderr +++ b/tests/ui/issue_4266.stderr @@ -1,16 +1,16 @@ error: the following explicit lifetimes could be elided: 'a - --> $DIR/issue_4266.rs:4:1 + --> $DIR/issue_4266.rs:4:16 | LL | async fn sink1<'a>(_: &'a str) {} // lint - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ | = note: `-D clippy::needless-lifetimes` implied by `-D warnings` error: the following explicit lifetimes could be elided: 'a - --> $DIR/issue_4266.rs:8:1 + --> $DIR/issue_4266.rs:8:21 | LL | async fn one_to_one<'a>(s: &'a str) -> &'a str { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ error: methods called `new` usually take no `self` --> $DIR/issue_4266.rs:28:22 diff --git a/tests/ui/items_after_test_module/block_module.stderr b/tests/ui/items_after_test_module/block_module.stderr index 597f1b9510c5..1b6257471618 100644 --- a/tests/ui/items_after_test_module/block_module.stderr +++ b/tests/ui/items_after_test_module/block_module.stderr @@ -1,17 +1,2 @@ -error: items were found after the testing module - --> $DIR/block_module.rs:13:1 - | -LL | / mod tests { -LL | | #[test] -LL | | fn hi() {} -LL | | } -... | -LL | | () => {}; -LL | | } - | |_^ - | - = help: move the items to before the testing module was defined - = note: `-D clippy::items-after-test-module` implied by `-D warnings` - -error: aborting due to previous error +error: Option 'test' given more than once diff --git a/tests/ui/iter_cloned_collect.fixed b/tests/ui/iter_cloned_collect.fixed index 88f08bb991b8..2baea06f84ba 100644 --- a/tests/ui/iter_cloned_collect.fixed +++ b/tests/ui/iter_cloned_collect.fixed @@ -1,6 +1,7 @@ //@run-rustfix #![allow(unused)] +#![allow(clippy::useless_vec)] use std::collections::HashSet; use std::collections::VecDeque; diff --git a/tests/ui/iter_cloned_collect.rs b/tests/ui/iter_cloned_collect.rs index d3438b7f51a2..9eac94eb8d97 100644 --- a/tests/ui/iter_cloned_collect.rs +++ b/tests/ui/iter_cloned_collect.rs @@ -1,6 +1,7 @@ //@run-rustfix #![allow(unused)] +#![allow(clippy::useless_vec)] use std::collections::HashSet; use std::collections::VecDeque; diff --git a/tests/ui/iter_cloned_collect.stderr b/tests/ui/iter_cloned_collect.stderr index b2cc497bf433..b38cf547dc5f 100644 --- a/tests/ui/iter_cloned_collect.stderr +++ b/tests/ui/iter_cloned_collect.stderr @@ -1,5 +1,5 @@ error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable - --> $DIR/iter_cloned_collect.rs:10:27 + --> $DIR/iter_cloned_collect.rs:11:27 | LL | let v2: Vec = v.iter().cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()` @@ -7,13 +7,13 @@ LL | let v2: Vec = v.iter().cloned().collect(); = note: `-D clippy::iter-cloned-collect` implied by `-D warnings` error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable - --> $DIR/iter_cloned_collect.rs:15:38 + --> $DIR/iter_cloned_collect.rs:16:38 | LL | let _: Vec = vec![1, 2, 3].iter().cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()` error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable - --> $DIR/iter_cloned_collect.rs:20:24 + --> $DIR/iter_cloned_collect.rs:21:24 | LL | .to_bytes() | ________________________^ @@ -23,13 +23,13 @@ LL | | .collect(); | |______________________^ help: try: `.to_vec()` error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable - --> $DIR/iter_cloned_collect.rs:28:24 + --> $DIR/iter_cloned_collect.rs:29:24 | LL | let _: Vec<_> = arr.iter().cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()` error: called `iter().copied().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable - --> $DIR/iter_cloned_collect.rs:31:26 + --> $DIR/iter_cloned_collect.rs:32:26 | LL | let _: Vec = v.iter().copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()` diff --git a/tests/ui/iter_count.fixed b/tests/ui/iter_count.fixed index 4367a12f820d..b6208201409f 100644 --- a/tests/ui/iter_count.fixed +++ b/tests/ui/iter_count.fixed @@ -7,7 +7,8 @@ array_into_iter, unused_mut, clippy::into_iter_on_ref, - clippy::unnecessary_operation + clippy::unnecessary_operation, + clippy::useless_vec )] extern crate option_helpers; diff --git a/tests/ui/iter_count.rs b/tests/ui/iter_count.rs index 8c7543cf03b3..fb2161312098 100644 --- a/tests/ui/iter_count.rs +++ b/tests/ui/iter_count.rs @@ -7,7 +7,8 @@ array_into_iter, unused_mut, clippy::into_iter_on_ref, - clippy::unnecessary_operation + clippy::unnecessary_operation, + clippy::useless_vec )] extern crate option_helpers; diff --git a/tests/ui/iter_count.stderr b/tests/ui/iter_count.stderr index 2e3d7fc35de9..f9aee0b7846d 100644 --- a/tests/ui/iter_count.stderr +++ b/tests/ui/iter_count.stderr @@ -1,5 +1,5 @@ error: called `.iter().count()` on a `slice` - --> $DIR/iter_count.rs:54:6 + --> $DIR/iter_count.rs:55:6 | LL | &vec[..].iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec[..].len()` @@ -7,145 +7,145 @@ LL | &vec[..].iter().count(); = note: `-D clippy::iter-count` implied by `-D warnings` error: called `.iter().count()` on a `Vec` - --> $DIR/iter_count.rs:55:5 + --> $DIR/iter_count.rs:56:5 | LL | vec.iter().count(); | ^^^^^^^^^^^^^^^^^^ help: try: `vec.len()` error: called `.iter().count()` on a `slice` - --> $DIR/iter_count.rs:56:5 + --> $DIR/iter_count.rs:57:5 | LL | boxed_slice.iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice.len()` error: called `.iter().count()` on a `VecDeque` - --> $DIR/iter_count.rs:57:5 + --> $DIR/iter_count.rs:58:5 | LL | vec_deque.iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec_deque.len()` error: called `.iter().count()` on a `HashSet` - --> $DIR/iter_count.rs:58:5 + --> $DIR/iter_count.rs:59:5 | LL | hash_set.iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_set.len()` error: called `.iter().count()` on a `HashMap` - --> $DIR/iter_count.rs:59:5 + --> $DIR/iter_count.rs:60:5 | LL | hash_map.iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.len()` error: called `.iter().count()` on a `BTreeMap` - --> $DIR/iter_count.rs:60:5 + --> $DIR/iter_count.rs:61:5 | LL | b_tree_map.iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b_tree_map.len()` error: called `.iter().count()` on a `BTreeSet` - --> $DIR/iter_count.rs:61:5 + --> $DIR/iter_count.rs:62:5 | LL | b_tree_set.iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b_tree_set.len()` error: called `.iter().count()` on a `LinkedList` - --> $DIR/iter_count.rs:62:5 + --> $DIR/iter_count.rs:63:5 | LL | linked_list.iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `linked_list.len()` error: called `.iter().count()` on a `BinaryHeap` - --> $DIR/iter_count.rs:63:5 + --> $DIR/iter_count.rs:64:5 | LL | binary_heap.iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `binary_heap.len()` error: called `.iter_mut().count()` on a `Vec` - --> $DIR/iter_count.rs:65:5 + --> $DIR/iter_count.rs:66:5 | LL | vec.iter_mut().count(); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.len()` error: called `.iter_mut().count()` on a `slice` - --> $DIR/iter_count.rs:66:6 + --> $DIR/iter_count.rs:67:6 | LL | &vec[..].iter_mut().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec[..].len()` error: called `.iter_mut().count()` on a `VecDeque` - --> $DIR/iter_count.rs:67:5 + --> $DIR/iter_count.rs:68:5 | LL | vec_deque.iter_mut().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec_deque.len()` error: called `.iter_mut().count()` on a `HashMap` - --> $DIR/iter_count.rs:68:5 + --> $DIR/iter_count.rs:69:5 | LL | hash_map.iter_mut().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.len()` error: called `.iter_mut().count()` on a `BTreeMap` - --> $DIR/iter_count.rs:69:5 + --> $DIR/iter_count.rs:70:5 | LL | b_tree_map.iter_mut().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b_tree_map.len()` error: called `.iter_mut().count()` on a `LinkedList` - --> $DIR/iter_count.rs:70:5 + --> $DIR/iter_count.rs:71:5 | LL | linked_list.iter_mut().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `linked_list.len()` error: called `.into_iter().count()` on a `slice` - --> $DIR/iter_count.rs:72:6 + --> $DIR/iter_count.rs:73:6 | LL | &vec[..].into_iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec[..].len()` error: called `.into_iter().count()` on a `Vec` - --> $DIR/iter_count.rs:73:5 + --> $DIR/iter_count.rs:74:5 | LL | vec.into_iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.len()` error: called `.into_iter().count()` on a `VecDeque` - --> $DIR/iter_count.rs:74:5 + --> $DIR/iter_count.rs:75:5 | LL | vec_deque.into_iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec_deque.len()` error: called `.into_iter().count()` on a `HashSet` - --> $DIR/iter_count.rs:75:5 + --> $DIR/iter_count.rs:76:5 | LL | hash_set.into_iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_set.len()` error: called `.into_iter().count()` on a `HashMap` - --> $DIR/iter_count.rs:76:5 + --> $DIR/iter_count.rs:77:5 | LL | hash_map.into_iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.len()` error: called `.into_iter().count()` on a `BTreeMap` - --> $DIR/iter_count.rs:77:5 + --> $DIR/iter_count.rs:78:5 | LL | b_tree_map.into_iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b_tree_map.len()` error: called `.into_iter().count()` on a `BTreeSet` - --> $DIR/iter_count.rs:78:5 + --> $DIR/iter_count.rs:79:5 | LL | b_tree_set.into_iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b_tree_set.len()` error: called `.into_iter().count()` on a `LinkedList` - --> $DIR/iter_count.rs:79:5 + --> $DIR/iter_count.rs:80:5 | LL | linked_list.into_iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `linked_list.len()` error: called `.into_iter().count()` on a `BinaryHeap` - --> $DIR/iter_count.rs:80:5 + --> $DIR/iter_count.rs:81:5 | LL | binary_heap.into_iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `binary_heap.len()` diff --git a/tests/ui/iter_next_loop.rs b/tests/ui/iter_next_loop.rs new file mode 100644 index 000000000000..548b799de44e --- /dev/null +++ b/tests/ui/iter_next_loop.rs @@ -0,0 +1,16 @@ +#![allow(dead_code, unused, for_loops_over_fallibles)] +#![warn(clippy::iter_next_loop)] + +fn main() { + let x = [1, 2, 3, 4]; + for _ in vec.iter().next() {} + + struct Unrelated(&'static [u8]); + impl Unrelated { + fn next(&self) -> std::slice::Iter { + self.0.iter() + } + } + let u = Unrelated(&[0]); + for _v in u.next() {} // no error +} diff --git a/tests/ui/iter_next_loop.stderr b/tests/ui/iter_next_loop.stderr new file mode 100644 index 000000000000..5bba0e635bba --- /dev/null +++ b/tests/ui/iter_next_loop.stderr @@ -0,0 +1,9 @@ +error[E0423]: expected value, found macro `vec` + --> $DIR/iter_next_loop.rs:6:14 + | +LL | for _ in vec.iter().next() {} + | ^^^ not a value + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0423`. diff --git a/tests/ui/iter_next_slice.fixed b/tests/ui/iter_next_slice.fixed index d862abc34e0b..702edccdbad0 100644 --- a/tests/ui/iter_next_slice.fixed +++ b/tests/ui/iter_next_slice.fixed @@ -1,5 +1,6 @@ //@run-rustfix #![warn(clippy::iter_next_slice)] +#![allow(clippy::useless_vec)] fn main() { // test code goes here diff --git a/tests/ui/iter_next_slice.rs b/tests/ui/iter_next_slice.rs index da6fc46e4287..30bfc72de179 100644 --- a/tests/ui/iter_next_slice.rs +++ b/tests/ui/iter_next_slice.rs @@ -1,5 +1,6 @@ //@run-rustfix #![warn(clippy::iter_next_slice)] +#![allow(clippy::useless_vec)] fn main() { // test code goes here diff --git a/tests/ui/iter_next_slice.stderr b/tests/ui/iter_next_slice.stderr index d8b89061ff89..0db8201a1325 100644 --- a/tests/ui/iter_next_slice.stderr +++ b/tests/ui/iter_next_slice.stderr @@ -1,5 +1,5 @@ error: using `.iter().next()` on an array - --> $DIR/iter_next_slice.rs:9:13 + --> $DIR/iter_next_slice.rs:10:13 | LL | let _ = s.iter().next(); | ^^^^^^^^^^^^^^^ help: try calling: `s.first()` @@ -7,19 +7,19 @@ LL | let _ = s.iter().next(); = note: `-D clippy::iter-next-slice` implied by `-D warnings` error: using `.iter().next()` on a Slice without end index - --> $DIR/iter_next_slice.rs:12:13 + --> $DIR/iter_next_slice.rs:13:13 | LL | let _ = s[2..].iter().next(); | ^^^^^^^^^^^^^^^^^^^^ help: try calling: `s.get(2)` error: using `.iter().next()` on a Slice without end index - --> $DIR/iter_next_slice.rs:15:13 + --> $DIR/iter_next_slice.rs:16:13 | LL | let _ = v[5..].iter().next(); | ^^^^^^^^^^^^^^^^^^^^ help: try calling: `v.get(5)` error: using `.iter().next()` on an array - --> $DIR/iter_next_slice.rs:18:13 + --> $DIR/iter_next_slice.rs:19:13 | LL | let _ = v.iter().next(); | ^^^^^^^^^^^^^^^ help: try calling: `v.first()` diff --git a/tests/ui/iter_nth.rs b/tests/ui/iter_nth.rs index e7fb97d4fbc8..7c567bb81d88 100644 --- a/tests/ui/iter_nth.rs +++ b/tests/ui/iter_nth.rs @@ -1,6 +1,7 @@ //@aux-build:option_helpers.rs #![warn(clippy::iter_nth)] +#![allow(clippy::useless_vec)] #[macro_use] extern crate option_helpers; diff --git a/tests/ui/iter_nth.stderr b/tests/ui/iter_nth.stderr index a0fe353bcf75..24be814548a2 100644 --- a/tests/ui/iter_nth.stderr +++ b/tests/ui/iter_nth.stderr @@ -1,5 +1,5 @@ -error: called `.iter().nth()` on a Vec - --> $DIR/iter_nth.rs:33:23 +error: called `.iter().nth()` on a `Vec` + --> $DIR/iter_nth.rs:34:23 | LL | let bad_vec = some_vec.iter().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | let bad_vec = some_vec.iter().nth(3); = note: `-D clippy::iter-nth` implied by `-D warnings` error: called `.iter().nth()` on a slice - --> $DIR/iter_nth.rs:34:26 + --> $DIR/iter_nth.rs:35:26 | LL | let bad_slice = &some_vec[..].iter().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,23 +16,23 @@ LL | let bad_slice = &some_vec[..].iter().nth(3); = help: calling `.get()` is both faster and more readable error: called `.iter().nth()` on a slice - --> $DIR/iter_nth.rs:35:31 + --> $DIR/iter_nth.rs:36:31 | LL | let bad_boxed_slice = boxed_slice.iter().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: calling `.get()` is both faster and more readable -error: called `.iter().nth()` on a VecDeque - --> $DIR/iter_nth.rs:36:29 +error: called `.iter().nth()` on a `VecDeque` + --> $DIR/iter_nth.rs:37:29 | LL | let bad_vec_deque = some_vec_deque.iter().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: calling `.get()` is both faster and more readable -error: called `.iter_mut().nth()` on a Vec - --> $DIR/iter_nth.rs:41:23 +error: called `.iter_mut().nth()` on a `Vec` + --> $DIR/iter_nth.rs:42:23 | LL | let bad_vec = some_vec.iter_mut().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -40,15 +40,15 @@ LL | let bad_vec = some_vec.iter_mut().nth(3); = help: calling `.get_mut()` is both faster and more readable error: called `.iter_mut().nth()` on a slice - --> $DIR/iter_nth.rs:44:26 + --> $DIR/iter_nth.rs:45:26 | LL | let bad_slice = &some_vec[..].iter_mut().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: calling `.get_mut()` is both faster and more readable -error: called `.iter_mut().nth()` on a VecDeque - --> $DIR/iter_nth.rs:47:29 +error: called `.iter_mut().nth()` on a `VecDeque` + --> $DIR/iter_nth.rs:48:29 | LL | let bad_vec_deque = some_vec_deque.iter_mut().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/iter_nth_zero.fixed b/tests/ui/iter_nth_zero.fixed index 587b0d1d366a..91f4a7ba0d2f 100644 --- a/tests/ui/iter_nth_zero.fixed +++ b/tests/ui/iter_nth_zero.fixed @@ -29,3 +29,18 @@ fn main() { let mut iter2 = s3.iter(); let _unwrapped = iter2.next().unwrap(); } + +struct Issue9820; + +impl Iterator for Issue9820 { + type Item = (); + + fn nth(&mut self, _n: usize) -> Option { + todo!() + } + + // Don't lint in implementations of `next`, as calling `next` in `next` is incorrect + fn next(&mut self) -> Option { + self.nth(0) + } +} diff --git a/tests/ui/iter_nth_zero.rs b/tests/ui/iter_nth_zero.rs index 93b576ec56fe..160a895bb7b4 100644 --- a/tests/ui/iter_nth_zero.rs +++ b/tests/ui/iter_nth_zero.rs @@ -29,3 +29,18 @@ fn main() { let mut iter2 = s3.iter(); let _unwrapped = iter2.nth(0).unwrap(); } + +struct Issue9820; + +impl Iterator for Issue9820 { + type Item = (); + + fn nth(&mut self, _n: usize) -> Option { + todo!() + } + + // Don't lint in implementations of `next`, as calling `next` in `next` is incorrect + fn next(&mut self) -> Option { + self.nth(0) + } +} diff --git a/tests/ui/iter_overeager_cloned.fixed b/tests/ui/iter_overeager_cloned.fixed index bf576e9cbfb3..2874513c049b 100644 --- a/tests/ui/iter_overeager_cloned.fixed +++ b/tests/ui/iter_overeager_cloned.fixed @@ -1,6 +1,6 @@ //@run-rustfix #![warn(clippy::iter_overeager_cloned, clippy::redundant_clone, clippy::filter_next)] -#![allow(dead_code, clippy::let_unit_value)] +#![allow(dead_code, clippy::let_unit_value, clippy::useless_vec)] fn main() { let vec = vec!["1".to_string(), "2".to_string(), "3".to_string()]; diff --git a/tests/ui/iter_overeager_cloned.rs b/tests/ui/iter_overeager_cloned.rs index df42d88eff00..26f39734a512 100644 --- a/tests/ui/iter_overeager_cloned.rs +++ b/tests/ui/iter_overeager_cloned.rs @@ -1,6 +1,6 @@ //@run-rustfix #![warn(clippy::iter_overeager_cloned, clippy::redundant_clone, clippy::filter_next)] -#![allow(dead_code, clippy::let_unit_value)] +#![allow(dead_code, clippy::let_unit_value, clippy::useless_vec)] fn main() { let vec = vec!["1".to_string(), "2".to_string(), "3".to_string()]; diff --git a/tests/ui/iter_skip_next.fixed b/tests/ui/iter_skip_next.fixed index 8f2cefc43043..b888d965e8d7 100644 --- a/tests/ui/iter_skip_next.fixed +++ b/tests/ui/iter_skip_next.fixed @@ -4,6 +4,7 @@ #![warn(clippy::iter_skip_next)] #![allow(clippy::disallowed_names)] #![allow(clippy::iter_nth)] +#![allow(clippy::useless_vec)] #![allow(unused_mut, dead_code)] extern crate option_helpers; diff --git a/tests/ui/iter_skip_next.rs b/tests/ui/iter_skip_next.rs index 71d83384f3a0..e44efdebc471 100644 --- a/tests/ui/iter_skip_next.rs +++ b/tests/ui/iter_skip_next.rs @@ -4,6 +4,7 @@ #![warn(clippy::iter_skip_next)] #![allow(clippy::disallowed_names)] #![allow(clippy::iter_nth)] +#![allow(clippy::useless_vec)] #![allow(unused_mut, dead_code)] extern crate option_helpers; diff --git a/tests/ui/iter_skip_next.stderr b/tests/ui/iter_skip_next.stderr index ca6970b27f16..4ee26e088ce3 100644 --- a/tests/ui/iter_skip_next.stderr +++ b/tests/ui/iter_skip_next.stderr @@ -1,5 +1,5 @@ error: called `skip(..).next()` on an iterator - --> $DIR/iter_skip_next.rs:16:28 + --> $DIR/iter_skip_next.rs:17:28 | LL | let _ = some_vec.iter().skip(42).next(); | ^^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(42)` @@ -7,37 +7,37 @@ LL | let _ = some_vec.iter().skip(42).next(); = note: `-D clippy::iter-skip-next` implied by `-D warnings` error: called `skip(..).next()` on an iterator - --> $DIR/iter_skip_next.rs:17:36 + --> $DIR/iter_skip_next.rs:18:36 | LL | let _ = some_vec.iter().cycle().skip(42).next(); | ^^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(42)` error: called `skip(..).next()` on an iterator - --> $DIR/iter_skip_next.rs:18:20 + --> $DIR/iter_skip_next.rs:19:20 | LL | let _ = (1..10).skip(10).next(); | ^^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(10)` error: called `skip(..).next()` on an iterator - --> $DIR/iter_skip_next.rs:19:33 + --> $DIR/iter_skip_next.rs:20:33 | LL | let _ = &some_vec[..].iter().skip(3).next(); | ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(3)` error: called `skip(..).next()` on an iterator - --> $DIR/iter_skip_next.rs:27:26 + --> $DIR/iter_skip_next.rs:28:26 | LL | let _: Vec<&str> = sp.skip(1).next().unwrap().split(' ').collect(); | ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)` error: called `skip(..).next()` on an iterator - --> $DIR/iter_skip_next.rs:29:29 + --> $DIR/iter_skip_next.rs:30:29 | LL | let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect(); | ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)` error: called `skip(..).next()` on an iterator - --> $DIR/iter_skip_next.rs:35:29 + --> $DIR/iter_skip_next.rs:36:29 | LL | let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect(); | ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)` diff --git a/tests/ui/iter_with_drain.fixed b/tests/ui/iter_with_drain.fixed index 24a95c4d0fee..7a8c67701010 100644 --- a/tests/ui/iter_with_drain.fixed +++ b/tests/ui/iter_with_drain.fixed @@ -2,7 +2,7 @@ // will emits unused mut warnings after fixing #![allow(unused_mut)] // will emits needless collect warnings after fixing -#![allow(clippy::needless_collect)] +#![allow(clippy::needless_collect, clippy::drain_collect)] #![warn(clippy::iter_with_drain)] use std::collections::{BinaryHeap, HashMap, HashSet, VecDeque}; diff --git a/tests/ui/iter_with_drain.rs b/tests/ui/iter_with_drain.rs index a118c981ee3f..cf3a935c349a 100644 --- a/tests/ui/iter_with_drain.rs +++ b/tests/ui/iter_with_drain.rs @@ -2,7 +2,7 @@ // will emits unused mut warnings after fixing #![allow(unused_mut)] // will emits needless collect warnings after fixing -#![allow(clippy::needless_collect)] +#![allow(clippy::needless_collect, clippy::drain_collect)] #![warn(clippy::iter_with_drain)] use std::collections::{BinaryHeap, HashMap, HashSet, VecDeque}; diff --git a/tests/ui/iterator_step_by_zero.rs b/tests/ui/iterator_step_by_zero.rs index 13d1cfd42818..33ec78e9a416 100644 --- a/tests/ui/iterator_step_by_zero.rs +++ b/tests/ui/iterator_step_by_zero.rs @@ -1,3 +1,4 @@ +#![allow(clippy::useless_vec)] #[warn(clippy::iterator_step_by_zero)] fn main() { let _ = vec!["A", "B", "B"].iter().step_by(0); diff --git a/tests/ui/iterator_step_by_zero.stderr b/tests/ui/iterator_step_by_zero.stderr index d792aea11dfa..b470e2ed2eab 100644 --- a/tests/ui/iterator_step_by_zero.stderr +++ b/tests/ui/iterator_step_by_zero.stderr @@ -1,5 +1,5 @@ error: `Iterator::step_by(0)` will panic at runtime - --> $DIR/iterator_step_by_zero.rs:3:13 + --> $DIR/iterator_step_by_zero.rs:4:13 | LL | let _ = vec!["A", "B", "B"].iter().step_by(0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,37 +7,37 @@ LL | let _ = vec!["A", "B", "B"].iter().step_by(0); = note: `-D clippy::iterator-step-by-zero` implied by `-D warnings` error: `Iterator::step_by(0)` will panic at runtime - --> $DIR/iterator_step_by_zero.rs:4:13 + --> $DIR/iterator_step_by_zero.rs:5:13 | LL | let _ = "XXX".chars().step_by(0); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: `Iterator::step_by(0)` will panic at runtime - --> $DIR/iterator_step_by_zero.rs:5:13 + --> $DIR/iterator_step_by_zero.rs:6:13 | LL | let _ = (0..1).step_by(0); | ^^^^^^^^^^^^^^^^^ error: `Iterator::step_by(0)` will panic at runtime - --> $DIR/iterator_step_by_zero.rs:14:13 + --> $DIR/iterator_step_by_zero.rs:15:13 | LL | let _ = (1..).step_by(0); | ^^^^^^^^^^^^^^^^ error: `Iterator::step_by(0)` will panic at runtime - --> $DIR/iterator_step_by_zero.rs:15:13 + --> $DIR/iterator_step_by_zero.rs:16:13 | LL | let _ = (1..=2).step_by(0); | ^^^^^^^^^^^^^^^^^^ error: `Iterator::step_by(0)` will panic at runtime - --> $DIR/iterator_step_by_zero.rs:18:13 + --> $DIR/iterator_step_by_zero.rs:19:13 | LL | let _ = x.step_by(0); | ^^^^^^^^^^^^ error: `Iterator::step_by(0)` will panic at runtime - --> $DIR/iterator_step_by_zero.rs:22:13 + --> $DIR/iterator_step_by_zero.rs:23:13 | LL | let _ = v1.iter().step_by(2 / 3); | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/large_enum_variant.rs b/tests/ui/large_enum_variant.rs index ea8bc5b4aca1..e677cc9a7b95 100644 --- a/tests/ui/large_enum_variant.rs +++ b/tests/ui/large_enum_variant.rs @@ -1,4 +1,4 @@ -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![allow(dead_code)] #![allow(unused_variables)] diff --git a/tests/ui/large_futures.rs b/tests/ui/large_futures.rs index 4a8ba995da55..e0f6b3d9d3b4 100644 --- a/tests/ui/large_futures.rs +++ b/tests/ui/large_futures.rs @@ -1,5 +1,6 @@ #![feature(generators)] #![warn(clippy::large_futures)] +#![allow(clippy::never_loop)] #![allow(clippy::future_not_send)] #![allow(clippy::manual_async_fn)] diff --git a/tests/ui/large_futures.stderr b/tests/ui/large_futures.stderr index 67e0fceff6ef..5bcf054884e4 100644 --- a/tests/ui/large_futures.stderr +++ b/tests/ui/large_futures.stderr @@ -1,5 +1,5 @@ error: large future with a size of 16385 bytes - --> $DIR/large_futures.rs:10:9 + --> $DIR/large_futures.rs:11:9 | LL | big_fut([0u8; 1024 * 16]).await; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(big_fut([0u8; 1024 * 16]))` @@ -7,37 +7,37 @@ LL | big_fut([0u8; 1024 * 16]).await; = note: `-D clippy::large-futures` implied by `-D warnings` error: large future with a size of 16386 bytes - --> $DIR/large_futures.rs:12:5 + --> $DIR/large_futures.rs:13:5 | LL | f.await | ^ help: consider `Box::pin` on it: `Box::pin(f)` error: large future with a size of 16387 bytes - --> $DIR/large_futures.rs:16:9 + --> $DIR/large_futures.rs:17:9 | LL | wait().await; | ^^^^^^ help: consider `Box::pin` on it: `Box::pin(wait())` error: large future with a size of 16387 bytes - --> $DIR/large_futures.rs:20:13 + --> $DIR/large_futures.rs:21:13 | LL | wait().await; | ^^^^^^ help: consider `Box::pin` on it: `Box::pin(wait())` error: large future with a size of 65540 bytes - --> $DIR/large_futures.rs:27:5 + --> $DIR/large_futures.rs:28:5 | LL | foo().await; | ^^^^^ help: consider `Box::pin` on it: `Box::pin(foo())` error: large future with a size of 49159 bytes - --> $DIR/large_futures.rs:28:5 + --> $DIR/large_futures.rs:29:5 | LL | calls_fut(fut).await; | ^^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(calls_fut(fut))` error: large future with a size of 65540 bytes - --> $DIR/large_futures.rs:40:5 + --> $DIR/large_futures.rs:41:5 | LL | / async { LL | | let x = [0i32; 1024 * 16]; @@ -56,7 +56,7 @@ LL + }) | error: large future with a size of 65540 bytes - --> $DIR/large_futures.rs:51:13 + --> $DIR/large_futures.rs:52:13 | LL | / async { LL | | let x = [0i32; 1024 * 16]; diff --git a/tests/ui/large_stack_frames.rs b/tests/ui/large_stack_frames.rs new file mode 100644 index 000000000000..cd9d0c8a67a8 --- /dev/null +++ b/tests/ui/large_stack_frames.rs @@ -0,0 +1,44 @@ +#![allow(unused, incomplete_features)] +#![warn(clippy::large_stack_frames)] +#![feature(unsized_locals)] + +use std::hint::black_box; + +fn generic() { + let x = T::default(); + black_box(&x); +} + +fn unsized_local() { + let x: dyn std::fmt::Display = *(Box::new(1) as Box); + black_box(&x); +} + +struct ArrayDefault([u8; N]); + +impl Default for ArrayDefault { + fn default() -> Self { + Self([0; N]) + } +} + +fn many_small_arrays() { + let x = [0u8; 500_000]; + let x2 = [0u8; 500_000]; + let x3 = [0u8; 500_000]; + let x4 = [0u8; 500_000]; + let x5 = [0u8; 500_000]; + black_box((&x, &x2, &x3, &x4, &x5)); +} + +fn large_return_value() -> ArrayDefault<1_000_000> { + Default::default() +} + +fn large_fn_arg(x: ArrayDefault<1_000_000>) { + black_box(&x); +} + +fn main() { + generic::>(); +} diff --git a/tests/ui/large_stack_frames.stderr b/tests/ui/large_stack_frames.stderr new file mode 100644 index 000000000000..d57df8596fe5 --- /dev/null +++ b/tests/ui/large_stack_frames.stderr @@ -0,0 +1,37 @@ +error: this function allocates a large amount of stack space + --> $DIR/large_stack_frames.rs:25:1 + | +LL | / fn many_small_arrays() { +LL | | let x = [0u8; 500_000]; +LL | | let x2 = [0u8; 500_000]; +LL | | let x3 = [0u8; 500_000]; +... | +LL | | black_box((&x, &x2, &x3, &x4, &x5)); +LL | | } + | |_^ + | + = note: allocating large amounts of stack space can overflow the stack + = note: `-D clippy::large-stack-frames` implied by `-D warnings` + +error: this function allocates a large amount of stack space + --> $DIR/large_stack_frames.rs:34:1 + | +LL | / fn large_return_value() -> ArrayDefault<1_000_000> { +LL | | Default::default() +LL | | } + | |_^ + | + = note: allocating large amounts of stack space can overflow the stack + +error: this function allocates a large amount of stack space + --> $DIR/large_stack_frames.rs:38:1 + | +LL | / fn large_fn_arg(x: ArrayDefault<1_000_000>) { +LL | | black_box(&x); +LL | | } + | |_^ + | + = note: allocating large amounts of stack space can overflow the stack + +error: aborting due to 3 previous errors + diff --git a/tests/ui/len_zero.fixed b/tests/ui/len_zero.fixed index 2c22abd7e4b1..fafee6a0d41d 100644 --- a/tests/ui/len_zero.fixed +++ b/tests/ui/len_zero.fixed @@ -1,7 +1,7 @@ //@run-rustfix #![warn(clippy::len_zero)] -#![allow(dead_code, unused, clippy::len_without_is_empty)] +#![allow(dead_code, unused, clippy::needless_if, clippy::len_without_is_empty)] extern crate core; use core::ops::Deref; diff --git a/tests/ui/len_zero.rs b/tests/ui/len_zero.rs index a011ff976448..6a9006c47799 100644 --- a/tests/ui/len_zero.rs +++ b/tests/ui/len_zero.rs @@ -1,7 +1,7 @@ //@run-rustfix #![warn(clippy::len_zero)] -#![allow(dead_code, unused, clippy::len_without_is_empty)] +#![allow(dead_code, unused, clippy::needless_if, clippy::len_without_is_empty)] extern crate core; use core::ops::Deref; diff --git a/tests/ui/let_underscore_untyped.rs b/tests/ui/let_underscore_untyped.rs index 2c313ff35d59..431d83778e34 100644 --- a/tests/ui/let_underscore_untyped.rs +++ b/tests/ui/let_underscore_untyped.rs @@ -1,4 +1,4 @@ -//@aux-build: proc_macros.rs +//@aux-build: proc_macros.rs:proc-macro #![allow(unused)] #![warn(clippy::let_underscore_untyped)] diff --git a/tests/ui/let_with_type_underscore.rs b/tests/ui/let_with_type_underscore.rs index 7c1835e8cd18..8214176cfd57 100644 --- a/tests/ui/let_with_type_underscore.rs +++ b/tests/ui/let_with_type_underscore.rs @@ -1,19 +1,42 @@ +//@aux-build: proc_macros.rs:proc-macro #![allow(unused)] #![warn(clippy::let_with_type_underscore)] -#![allow(clippy::let_unit_value)] +#![allow(clippy::let_unit_value, clippy::needless_late_init)] + +extern crate proc_macros; fn func() -> &'static str { "" } +#[rustfmt::skip] fn main() { // Will lint let x: _ = 1; let _: _ = 2; let x: _ = func(); + let x: _; + x = (); let x = 1; // Will not lint, Rust infers this to an integer before Clippy let x = func(); let x: Vec<_> = Vec::::new(); let x: [_; 1] = [1]; + let x : _ = 1; + + // Do not lint from procedural macros + proc_macros::with_span! { + span + let x: _ = (); + // Late initialization + let x: _; + x = (); + // Ensure weird formatting will not break it (hopefully) + let x : _ = 1; + let x +: _ = 1; + let x : + _; + x = (); + }; } diff --git a/tests/ui/let_with_type_underscore.stderr b/tests/ui/let_with_type_underscore.stderr index 16bf83c708fe..a749552c7fac 100644 --- a/tests/ui/let_with_type_underscore.stderr +++ b/tests/ui/let_with_type_underscore.stderr @@ -1,39 +1,63 @@ error: variable declared with type underscore - --> $DIR/let_with_type_underscore.rs:11:5 + --> $DIR/let_with_type_underscore.rs:15:5 | LL | let x: _ = 1; | ^^^^^^^^^^^^^ | help: remove the explicit type `_` declaration - --> $DIR/let_with_type_underscore.rs:11:10 + --> $DIR/let_with_type_underscore.rs:15:10 | LL | let x: _ = 1; | ^^^ = note: `-D clippy::let-with-type-underscore` implied by `-D warnings` error: variable declared with type underscore - --> $DIR/let_with_type_underscore.rs:12:5 + --> $DIR/let_with_type_underscore.rs:16:5 | LL | let _: _ = 2; | ^^^^^^^^^^^^^ | help: remove the explicit type `_` declaration - --> $DIR/let_with_type_underscore.rs:12:10 + --> $DIR/let_with_type_underscore.rs:16:10 | LL | let _: _ = 2; | ^^^ error: variable declared with type underscore - --> $DIR/let_with_type_underscore.rs:13:5 + --> $DIR/let_with_type_underscore.rs:17:5 | LL | let x: _ = func(); | ^^^^^^^^^^^^^^^^^^ | help: remove the explicit type `_` declaration - --> $DIR/let_with_type_underscore.rs:13:10 + --> $DIR/let_with_type_underscore.rs:17:10 | LL | let x: _ = func(); | ^^^ -error: aborting due to 3 previous errors +error: variable declared with type underscore + --> $DIR/let_with_type_underscore.rs:18:5 + | +LL | let x: _; + | ^^^^^^^^^ + | +help: remove the explicit type `_` declaration + --> $DIR/let_with_type_underscore.rs:18:10 + | +LL | let x: _; + | ^^^ + +error: variable declared with type underscore + --> $DIR/let_with_type_underscore.rs:25:5 + | +LL | let x : _ = 1; + | ^^^^^^^^^^^^^^ + | +help: remove the explicit type `_` declaration + --> $DIR/let_with_type_underscore.rs:25:10 + | +LL | let x : _ = 1; + | ^^^^ + +error: aborting due to 5 previous errors diff --git a/tests/ui/lossy_float_literal.fixed b/tests/ui/lossy_float_literal.fixed index a20885756103..e19f4980cd70 100644 --- a/tests/ui/lossy_float_literal.fixed +++ b/tests/ui/lossy_float_literal.fixed @@ -1,5 +1,6 @@ //@run-rustfix #![warn(clippy::lossy_float_literal)] +#![allow(overflowing_literals, unused)] fn main() { // Lossy whole-number float literals @@ -32,4 +33,7 @@ fn main() { let _: f64 = 1e99; let _: f64 = 1E99; let _: f32 = 0.1; + + const INF1: f32 = 1000000000000000000000000000000000f32; + const NEG_INF1: f32 = -340282357000000000000000000000000000001_f32; } diff --git a/tests/ui/lossy_float_literal.rs b/tests/ui/lossy_float_literal.rs index 1a75f214c856..a2a1cfb317e1 100644 --- a/tests/ui/lossy_float_literal.rs +++ b/tests/ui/lossy_float_literal.rs @@ -1,5 +1,6 @@ //@run-rustfix #![warn(clippy::lossy_float_literal)] +#![allow(overflowing_literals, unused)] fn main() { // Lossy whole-number float literals @@ -32,4 +33,7 @@ fn main() { let _: f64 = 1e99; let _: f64 = 1E99; let _: f32 = 0.1; + + const INF1: f32 = 1000000000000000000000000000000000f32; + const NEG_INF1: f32 = -340282357000000000000000000000000000001_f32; } diff --git a/tests/ui/lossy_float_literal.stderr b/tests/ui/lossy_float_literal.stderr index d2193c0c8195..2d72b16430c4 100644 --- a/tests/ui/lossy_float_literal.stderr +++ b/tests/ui/lossy_float_literal.stderr @@ -1,5 +1,5 @@ error: literal cannot be represented as the underlying type without loss of precision - --> $DIR/lossy_float_literal.rs:6:18 + --> $DIR/lossy_float_literal.rs:7:18 | LL | let _: f32 = 16_777_217.0; | ^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_216.0` @@ -7,61 +7,61 @@ LL | let _: f32 = 16_777_217.0; = note: `-D clippy::lossy-float-literal` implied by `-D warnings` error: literal cannot be represented as the underlying type without loss of precision - --> $DIR/lossy_float_literal.rs:7:18 + --> $DIR/lossy_float_literal.rs:8:18 | LL | let _: f32 = 16_777_219.0; | ^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220.0` error: literal cannot be represented as the underlying type without loss of precision - --> $DIR/lossy_float_literal.rs:8:18 + --> $DIR/lossy_float_literal.rs:9:18 | LL | let _: f32 = 16_777_219.; | ^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220.0` error: literal cannot be represented as the underlying type without loss of precision - --> $DIR/lossy_float_literal.rs:9:18 + --> $DIR/lossy_float_literal.rs:10:18 | LL | let _: f32 = 16_777_219.000; | ^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220.0` error: literal cannot be represented as the underlying type without loss of precision - --> $DIR/lossy_float_literal.rs:10:13 + --> $DIR/lossy_float_literal.rs:11:13 | LL | let _ = 16_777_219f32; | ^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220_f32` error: literal cannot be represented as the underlying type without loss of precision - --> $DIR/lossy_float_literal.rs:11:19 + --> $DIR/lossy_float_literal.rs:12:19 | LL | let _: f32 = -16_777_219.0; | ^^^^^^^^^^^^ help: consider changing the type or replacing it with: `16_777_220.0` error: literal cannot be represented as the underlying type without loss of precision - --> $DIR/lossy_float_literal.rs:12:18 + --> $DIR/lossy_float_literal.rs:13:18 | LL | let _: f64 = 9_007_199_254_740_993.0; | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992.0` error: literal cannot be represented as the underlying type without loss of precision - --> $DIR/lossy_float_literal.rs:13:18 + --> $DIR/lossy_float_literal.rs:14:18 | LL | let _: f64 = 9_007_199_254_740_993.; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992.0` error: literal cannot be represented as the underlying type without loss of precision - --> $DIR/lossy_float_literal.rs:14:18 + --> $DIR/lossy_float_literal.rs:15:18 | LL | let _: f64 = 9_007_199_254_740_993.00; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992.0` error: literal cannot be represented as the underlying type without loss of precision - --> $DIR/lossy_float_literal.rs:15:13 + --> $DIR/lossy_float_literal.rs:16:13 | LL | let _ = 9_007_199_254_740_993f64; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992_f64` error: literal cannot be represented as the underlying type without loss of precision - --> $DIR/lossy_float_literal.rs:16:19 + --> $DIR/lossy_float_literal.rs:17:19 | LL | let _: f64 = -9_007_199_254_740_993.0; | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or replacing it with: `9_007_199_254_740_992.0` diff --git a/tests/ui/macro_use_imports.fixed b/tests/ui/macro_use_imports.fixed index b4dabe3cae5d..53b6a0250f99 100644 --- a/tests/ui/macro_use_imports.fixed +++ b/tests/ui/macro_use_imports.fixed @@ -1,6 +1,6 @@ //@aux-build:macro_rules.rs //@aux-build:macro_use_helper.rs -//@aux-build:proc_macro_derive.rs +//@aux-build:proc_macro_derive.rs:proc-macro //@run-rustfix //@ignore-32bit diff --git a/tests/ui/macro_use_imports.rs b/tests/ui/macro_use_imports.rs index 925a2c61f8d2..a40fa389895a 100644 --- a/tests/ui/macro_use_imports.rs +++ b/tests/ui/macro_use_imports.rs @@ -1,6 +1,6 @@ //@aux-build:macro_rules.rs //@aux-build:macro_use_helper.rs -//@aux-build:proc_macro_derive.rs +//@aux-build:proc_macro_derive.rs:proc-macro //@run-rustfix //@ignore-32bit diff --git a/tests/ui/macro_use_imports.stderr b/tests/ui/macro_use_imports.stderr index 6fd338cef868..67a833e85e04 100644 --- a/tests/ui/macro_use_imports.stderr +++ b/tests/ui/macro_use_imports.stderr @@ -1,17 +1,11 @@ error: `macro_use` attributes are no longer needed in the Rust 2018 edition - --> $DIR/macro_use_imports.rs:25:5 + --> $DIR/macro_use_imports.rs:19:5 | LL | #[macro_use] - | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;` + | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro};` | = note: `-D clippy::macro-use-imports` implied by `-D warnings` -error: `macro_use` attributes are no longer needed in the Rust 2018 edition - --> $DIR/macro_use_imports.rs:21:5 - | -LL | #[macro_use] - | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;` - error: `macro_use` attributes are no longer needed in the Rust 2018 edition --> $DIR/macro_use_imports.rs:23:5 | @@ -19,10 +13,16 @@ LL | #[macro_use] | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::mut_mut, inner::try_err};` error: `macro_use` attributes are no longer needed in the Rust 2018 edition - --> $DIR/macro_use_imports.rs:19:5 + --> $DIR/macro_use_imports.rs:25:5 | LL | #[macro_use] - | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro};` + | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;` + +error: `macro_use` attributes are no longer needed in the Rust 2018 edition + --> $DIR/macro_use_imports.rs:21:5 + | +LL | #[macro_use] + | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;` error: aborting due to 4 previous errors diff --git a/tests/ui/macro_use_imports_expect.rs b/tests/ui/macro_use_imports_expect.rs index b9677851b92d..3971aadbef85 100644 --- a/tests/ui/macro_use_imports_expect.rs +++ b/tests/ui/macro_use_imports_expect.rs @@ -1,6 +1,6 @@ //@aux-build:macro_rules.rs //@aux-build:macro_use_helper.rs -//@aux-build:proc_macro_derive.rs +//@aux-build:proc_macro_derive.rs:proc-macro //@ignore-32bit #![feature(lint_reasons)] diff --git a/tests/ui/manual_assert.edition2018.fixed b/tests/ui/manual_assert.edition2018.fixed index ab9b375dc03d..d8dde0236eae 100644 --- a/tests/ui/manual_assert.edition2018.fixed +++ b/tests/ui/manual_assert.edition2018.fixed @@ -5,7 +5,7 @@ #![warn(clippy::manual_assert)] #![allow(dead_code, unused_doc_comments)] -#![allow(clippy::nonminimal_bool, clippy::uninlined_format_args)] +#![allow(clippy::nonminimal_bool, clippy::uninlined_format_args, clippy::useless_vec)] macro_rules! one { () => { diff --git a/tests/ui/manual_assert.edition2021.fixed b/tests/ui/manual_assert.edition2021.fixed index ab9b375dc03d..d8dde0236eae 100644 --- a/tests/ui/manual_assert.edition2021.fixed +++ b/tests/ui/manual_assert.edition2021.fixed @@ -5,7 +5,7 @@ #![warn(clippy::manual_assert)] #![allow(dead_code, unused_doc_comments)] -#![allow(clippy::nonminimal_bool, clippy::uninlined_format_args)] +#![allow(clippy::nonminimal_bool, clippy::uninlined_format_args, clippy::useless_vec)] macro_rules! one { () => { diff --git a/tests/ui/manual_assert.rs b/tests/ui/manual_assert.rs index eac52d1b5de5..0f87d6e2d2c9 100644 --- a/tests/ui/manual_assert.rs +++ b/tests/ui/manual_assert.rs @@ -5,7 +5,7 @@ #![warn(clippy::manual_assert)] #![allow(dead_code, unused_doc_comments)] -#![allow(clippy::nonminimal_bool, clippy::uninlined_format_args)] +#![allow(clippy::nonminimal_bool, clippy::uninlined_format_args, clippy::useless_vec)] macro_rules! one { () => { diff --git a/tests/ui/manual_async_fn.fixed b/tests/ui/manual_async_fn.fixed index e458f0d254f6..e609b4b1bdb0 100644 --- a/tests/ui/manual_async_fn.fixed +++ b/tests/ui/manual_async_fn.fixed @@ -1,6 +1,6 @@ //@run-rustfix #![warn(clippy::manual_async_fn)] -#![allow(unused)] +#![allow(clippy::needless_pub_self, unused)] use std::future::Future; diff --git a/tests/ui/manual_async_fn.rs b/tests/ui/manual_async_fn.rs index dd5ca1c9b5b7..6c1a9edaa110 100644 --- a/tests/ui/manual_async_fn.rs +++ b/tests/ui/manual_async_fn.rs @@ -1,6 +1,6 @@ //@run-rustfix #![warn(clippy::manual_async_fn)] -#![allow(unused)] +#![allow(clippy::needless_pub_self, unused)] use std::future::Future; diff --git a/tests/ui/manual_filter.fixed b/tests/ui/manual_filter.fixed index 755caa664d59..5e3b12e510b8 100644 --- a/tests/ui/manual_filter.fixed +++ b/tests/ui/manual_filter.fixed @@ -1,7 +1,7 @@ //@run-rustfix #![warn(clippy::manual_filter)] -#![allow(unused_variables, dead_code)] +#![allow(unused_variables, dead_code, clippy::useless_vec)] fn main() { Some(0).filter(|&x| x <= 0); diff --git a/tests/ui/manual_filter.rs b/tests/ui/manual_filter.rs index faccfe9db12a..b81604b0372b 100644 --- a/tests/ui/manual_filter.rs +++ b/tests/ui/manual_filter.rs @@ -1,7 +1,7 @@ //@run-rustfix #![warn(clippy::manual_filter)] -#![allow(unused_variables, dead_code)] +#![allow(unused_variables, dead_code, clippy::useless_vec)] fn main() { match Some(0) { diff --git a/tests/ui/manual_filter_map.fixed b/tests/ui/manual_filter_map.fixed index 831323089e7f..9dd376df2b48 100644 --- a/tests/ui/manual_filter_map.fixed +++ b/tests/ui/manual_filter_map.fixed @@ -2,6 +2,7 @@ #![allow(dead_code)] #![warn(clippy::manual_filter_map)] #![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure +#![allow(clippy::useless_vec)] fn main() { // is_some(), unwrap() diff --git a/tests/ui/manual_filter_map.rs b/tests/ui/manual_filter_map.rs index 2692303d3138..6dd1e066aebd 100644 --- a/tests/ui/manual_filter_map.rs +++ b/tests/ui/manual_filter_map.rs @@ -2,6 +2,7 @@ #![allow(dead_code)] #![warn(clippy::manual_filter_map)] #![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure +#![allow(clippy::useless_vec)] fn main() { // is_some(), unwrap() diff --git a/tests/ui/manual_filter_map.stderr b/tests/ui/manual_filter_map.stderr index 6e5bbe8f2aaf..882468b0f5f1 100644 --- a/tests/ui/manual_filter_map.stderr +++ b/tests/ui/manual_filter_map.stderr @@ -1,5 +1,5 @@ error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:8:19 + --> $DIR/manual_filter_map.rs:9:19 | LL | let _ = (0..).filter(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_opt(a))` @@ -7,19 +7,19 @@ LL | let _ = (0..).filter(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap = note: `-D clippy::manual-filter-map` implied by `-D warnings` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:11:19 + --> $DIR/manual_filter_map.rs:12:19 | LL | let _ = (0..).filter(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_opt(a))` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:14:19 + --> $DIR/manual_filter_map.rs:15:19 | LL | let _ = (0..).filter(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_res(a).ok())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:17:10 + --> $DIR/manual_filter_map.rs:18:10 | LL | .filter(|&x| to_ref(to_opt(x)).is_some()) | __________^ @@ -27,7 +27,7 @@ LL | | .map(|y| to_ref(to_opt(y)).unwrap()); | |____________________________________________^ help: try: `filter_map(|y| *to_ref(to_opt(y)))` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:20:10 + --> $DIR/manual_filter_map.rs:21:10 | LL | .filter(|x| to_ref(to_opt(*x)).is_some()) | __________^ @@ -35,7 +35,7 @@ LL | | .map(|y| to_ref(to_opt(y)).unwrap()); | |____________________________________________^ help: try: `filter_map(|y| *to_ref(to_opt(y)))` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:24:10 + --> $DIR/manual_filter_map.rs:25:10 | LL | .filter(|&x| to_ref(to_res(x)).is_ok()) | __________^ @@ -43,7 +43,7 @@ LL | | .map(|y| to_ref(to_res(y)).unwrap()); | |____________________________________________^ help: try: `filter_map(|y| to_ref(to_res(y)).ok())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:27:10 + --> $DIR/manual_filter_map.rs:28:10 | LL | .filter(|x| to_ref(to_res(*x)).is_ok()) | __________^ @@ -51,7 +51,7 @@ LL | | .map(|y| to_ref(to_res(y)).unwrap()); | |____________________________________________^ help: try: `filter_map(|y| to_ref(to_res(y)).ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_filter_map.rs:33:27 + --> $DIR/manual_filter_map.rs:34:27 | LL | iter::>().find(|x| x.is_some()).map(|x| x.cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned())` @@ -59,67 +59,67 @@ LL | iter::>().find(|x| x.is_some()).map(|x| x.cloned().unwrap() = note: `-D clippy::manual-find-map` implied by `-D warnings` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_filter_map.rs:34:28 + --> $DIR/manual_filter_map.rs:35:28 | LL | iter::<&Option<&u8>>().find(|x| x.is_some()).map(|x| x.cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_filter_map.rs:35:31 + --> $DIR/manual_filter_map.rs:36:31 | LL | iter::<&Option>().find(|x| x.is_some()).map(|x| x.as_deref().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.as_deref())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_filter_map.rs:36:31 + --> $DIR/manual_filter_map.rs:37:31 | LL | iter::>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_filter_map.rs:38:30 + --> $DIR/manual_filter_map.rs:39:30 | LL | iter::>().find(|x| x.is_ok()).map(|x| x.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_filter_map.rs:39:31 + --> $DIR/manual_filter_map.rs:40:31 | LL | iter::<&Result>().find(|x| x.is_ok()).map(|x| x.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_filter_map.rs:40:32 + --> $DIR/manual_filter_map.rs:41:32 | LL | iter::<&&Result>().find(|x| x.is_ok()).map(|x| x.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_filter_map.rs:41:31 + --> $DIR/manual_filter_map.rs:42:31 | LL | iter::>().find(|x| x.is_ok()).map(|x| x.cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_filter_map.rs:42:32 + --> $DIR/manual_filter_map.rs:43:32 | LL | iter::<&Result<&u8, ()>>().find(|x| x.is_ok()).map(|x| x.cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_filter_map.rs:43:35 + --> $DIR/manual_filter_map.rs:44:35 | LL | iter::<&Result>().find(|x| x.is_ok()).map(|x| x.as_deref().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.as_deref().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_filter_map.rs:44:35 + --> $DIR/manual_filter_map.rs:45:35 | LL | iter::>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned().ok())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:92:10 + --> $DIR/manual_filter_map.rs:93:10 | LL | .filter(|f| f.option_field.is_some()) | __________^ @@ -127,7 +127,7 @@ LL | | .map(|f| f.option_field.clone().unwrap()); | |_________________________________________________^ help: try: `filter_map(|f| f.option_field.clone())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:97:10 + --> $DIR/manual_filter_map.rs:98:10 | LL | .filter(|f| f.ref_field.is_some()) | __________^ @@ -135,7 +135,7 @@ LL | | .map(|f| f.ref_field.cloned().unwrap()); | |_______________________________________________^ help: try: `filter_map(|f| f.ref_field.cloned())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:102:10 + --> $DIR/manual_filter_map.rs:103:10 | LL | .filter(|f| f.ref_field.is_some()) | __________^ @@ -143,7 +143,7 @@ LL | | .map(|f| f.ref_field.copied().unwrap()); | |_______________________________________________^ help: try: `filter_map(|f| f.ref_field.copied())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:107:10 + --> $DIR/manual_filter_map.rs:108:10 | LL | .filter(|f| f.result_field.is_ok()) | __________^ @@ -151,7 +151,7 @@ LL | | .map(|f| f.result_field.clone().unwrap()); | |_________________________________________________^ help: try: `filter_map(|f| f.result_field.clone().ok())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:112:10 + --> $DIR/manual_filter_map.rs:113:10 | LL | .filter(|f| f.result_field.is_ok()) | __________^ @@ -159,7 +159,7 @@ LL | | .map(|f| f.result_field.as_ref().unwrap()); | |__________________________________________________^ help: try: `filter_map(|f| f.result_field.as_ref().ok())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:117:10 + --> $DIR/manual_filter_map.rs:118:10 | LL | .filter(|f| f.result_field.is_ok()) | __________^ @@ -167,7 +167,7 @@ LL | | .map(|f| f.result_field.as_deref().unwrap()); | |____________________________________________________^ help: try: `filter_map(|f| f.result_field.as_deref().ok())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:122:10 + --> $DIR/manual_filter_map.rs:123:10 | LL | .filter(|f| f.result_field.is_ok()) | __________^ @@ -175,7 +175,7 @@ LL | | .map(|f| f.result_field.as_mut().unwrap()); | |__________________________________________________^ help: try: `filter_map(|f| f.result_field.as_mut().ok())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:127:10 + --> $DIR/manual_filter_map.rs:128:10 | LL | .filter(|f| f.result_field.is_ok()) | __________^ @@ -183,7 +183,7 @@ LL | | .map(|f| f.result_field.as_deref_mut().unwrap()); | |________________________________________________________^ help: try: `filter_map(|f| f.result_field.as_deref_mut().ok())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> $DIR/manual_filter_map.rs:132:10 + --> $DIR/manual_filter_map.rs:133:10 | LL | .filter(|f| f.result_field.is_ok()) | __________^ diff --git a/tests/ui/manual_find_map.fixed b/tests/ui/manual_find_map.fixed index 554613a30a9e..0c8eebf04b5c 100644 --- a/tests/ui/manual_find_map.fixed +++ b/tests/ui/manual_find_map.fixed @@ -2,6 +2,7 @@ #![allow(dead_code)] #![warn(clippy::manual_find_map)] #![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure +#![allow(clippy::useless_vec)] fn main() { // is_some(), unwrap() diff --git a/tests/ui/manual_find_map.rs b/tests/ui/manual_find_map.rs index d6245758f9d0..b2feb48a839b 100644 --- a/tests/ui/manual_find_map.rs +++ b/tests/ui/manual_find_map.rs @@ -2,6 +2,7 @@ #![allow(dead_code)] #![warn(clippy::manual_find_map)] #![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure +#![allow(clippy::useless_vec)] fn main() { // is_some(), unwrap() diff --git a/tests/ui/manual_find_map.stderr b/tests/ui/manual_find_map.stderr index c1ac499f7c60..693a06bb5590 100644 --- a/tests/ui/manual_find_map.stderr +++ b/tests/ui/manual_find_map.stderr @@ -1,5 +1,5 @@ error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:8:19 + --> $DIR/manual_find_map.rs:9:19 | LL | let _ = (0..).find(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|a| to_opt(a))` @@ -7,19 +7,19 @@ LL | let _ = (0..).find(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap() = note: `-D clippy::manual-find-map` implied by `-D warnings` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:11:19 + --> $DIR/manual_find_map.rs:12:19 | LL | let _ = (0..).find(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|a| to_opt(a))` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:14:19 + --> $DIR/manual_find_map.rs:15:19 | LL | let _ = (0..).find(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|a| to_res(a).ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:17:10 + --> $DIR/manual_find_map.rs:18:10 | LL | .find(|&x| to_ref(to_opt(x)).is_some()) | __________^ @@ -27,7 +27,7 @@ LL | | .map(|y| to_ref(to_opt(y)).unwrap()); | |____________________________________________^ help: try: `find_map(|y| *to_ref(to_opt(y)))` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:20:10 + --> $DIR/manual_find_map.rs:21:10 | LL | .find(|x| to_ref(to_opt(*x)).is_some()) | __________^ @@ -35,7 +35,7 @@ LL | | .map(|y| to_ref(to_opt(y)).unwrap()); | |____________________________________________^ help: try: `find_map(|y| *to_ref(to_opt(y)))` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:24:10 + --> $DIR/manual_find_map.rs:25:10 | LL | .find(|&x| to_ref(to_res(x)).is_ok()) | __________^ @@ -43,7 +43,7 @@ LL | | .map(|y| to_ref(to_res(y)).unwrap()); | |____________________________________________^ help: try: `find_map(|y| to_ref(to_res(y)).ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:27:10 + --> $DIR/manual_find_map.rs:28:10 | LL | .find(|x| to_ref(to_res(*x)).is_ok()) | __________^ @@ -51,91 +51,91 @@ LL | | .map(|y| to_ref(to_res(y)).unwrap()); | |____________________________________________^ help: try: `find_map(|y| to_ref(to_res(y)).ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:33:26 + --> $DIR/manual_find_map.rs:34:26 | LL | iter::>().find(|x| x.is_some()).map(|x| x.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x)` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:34:27 + --> $DIR/manual_find_map.rs:35:27 | LL | iter::<&Option>().find(|x| x.is_some()).map(|x| x.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| *x)` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:35:28 + --> $DIR/manual_find_map.rs:36:28 | LL | iter::<&&Option>().find(|x| x.is_some()).map(|x| x.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| **x)` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:36:27 + --> $DIR/manual_find_map.rs:37:27 | LL | iter::>().find(|x| x.is_some()).map(|x| x.cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:37:28 + --> $DIR/manual_find_map.rs:38:28 | LL | iter::<&Option<&u8>>().find(|x| x.is_some()).map(|x| x.cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:38:31 + --> $DIR/manual_find_map.rs:39:31 | LL | iter::<&Option>().find(|x| x.is_some()).map(|x| x.as_deref().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.as_deref())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:39:31 + --> $DIR/manual_find_map.rs:40:31 | LL | iter::>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:41:30 + --> $DIR/manual_find_map.rs:42:30 | LL | iter::>().find(|x| x.is_ok()).map(|x| x.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:42:31 + --> $DIR/manual_find_map.rs:43:31 | LL | iter::<&Result>().find(|x| x.is_ok()).map(|x| x.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:43:32 + --> $DIR/manual_find_map.rs:44:32 | LL | iter::<&&Result>().find(|x| x.is_ok()).map(|x| x.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:44:31 + --> $DIR/manual_find_map.rs:45:31 | LL | iter::>().find(|x| x.is_ok()).map(|x| x.cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:45:32 + --> $DIR/manual_find_map.rs:46:32 | LL | iter::<&Result<&u8, ()>>().find(|x| x.is_ok()).map(|x| x.cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:46:35 + --> $DIR/manual_find_map.rs:47:35 | LL | iter::<&Result>().find(|x| x.is_ok()).map(|x| x.as_deref().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.as_deref().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:47:35 + --> $DIR/manual_find_map.rs:48:35 | LL | iter::>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:95:10 + --> $DIR/manual_find_map.rs:96:10 | LL | .find(|f| f.option_field.is_some()) | __________^ @@ -143,7 +143,7 @@ LL | | .map(|f| f.option_field.clone().unwrap()); | |_________________________________________________^ help: try: `find_map(|f| f.option_field.clone())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:100:10 + --> $DIR/manual_find_map.rs:101:10 | LL | .find(|f| f.ref_field.is_some()) | __________^ @@ -151,7 +151,7 @@ LL | | .map(|f| f.ref_field.cloned().unwrap()); | |_______________________________________________^ help: try: `find_map(|f| f.ref_field.cloned())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:105:10 + --> $DIR/manual_find_map.rs:106:10 | LL | .find(|f| f.ref_field.is_some()) | __________^ @@ -159,7 +159,7 @@ LL | | .map(|f| f.ref_field.copied().unwrap()); | |_______________________________________________^ help: try: `find_map(|f| f.ref_field.copied())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:110:10 + --> $DIR/manual_find_map.rs:111:10 | LL | .find(|f| f.result_field.is_ok()) | __________^ @@ -167,7 +167,7 @@ LL | | .map(|f| f.result_field.clone().unwrap()); | |_________________________________________________^ help: try: `find_map(|f| f.result_field.clone().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:115:10 + --> $DIR/manual_find_map.rs:116:10 | LL | .find(|f| f.result_field.is_ok()) | __________^ @@ -175,7 +175,7 @@ LL | | .map(|f| f.result_field.as_ref().unwrap()); | |__________________________________________________^ help: try: `find_map(|f| f.result_field.as_ref().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:120:10 + --> $DIR/manual_find_map.rs:121:10 | LL | .find(|f| f.result_field.is_ok()) | __________^ @@ -183,7 +183,7 @@ LL | | .map(|f| f.result_field.as_deref().unwrap()); | |____________________________________________________^ help: try: `find_map(|f| f.result_field.as_deref().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:125:10 + --> $DIR/manual_find_map.rs:126:10 | LL | .find(|f| f.result_field.is_ok()) | __________^ @@ -191,7 +191,7 @@ LL | | .map(|f| f.result_field.as_mut().unwrap()); | |__________________________________________________^ help: try: `find_map(|f| f.result_field.as_mut().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:130:10 + --> $DIR/manual_find_map.rs:131:10 | LL | .find(|f| f.result_field.is_ok()) | __________^ @@ -199,7 +199,7 @@ LL | | .map(|f| f.result_field.as_deref_mut().unwrap()); | |________________________________________________________^ help: try: `find_map(|f| f.result_field.as_deref_mut().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> $DIR/manual_find_map.rs:135:10 + --> $DIR/manual_find_map.rs:136:10 | LL | .find(|f| f.result_field.is_ok()) | __________^ diff --git a/tests/ui/manual_let_else.rs b/tests/ui/manual_let_else.rs index 351ea0e4f509..46241afec947 100644 --- a/tests/ui/manual_let_else.rs +++ b/tests/ui/manual_let_else.rs @@ -4,7 +4,8 @@ clippy::unused_unit, clippy::let_unit_value, clippy::match_single_binding, - clippy::never_loop + clippy::never_loop, + clippy::needless_if )] #![warn(clippy::manual_let_else)] @@ -127,8 +128,8 @@ fn fire() { return; }; - // Tuples supported for the identity block and pattern - let v = if let (Some(v_some), w_some) = (g(), 0) { + // Tuples supported with multiple bindings + let (w, S { v }) = if let (Some(v_some), w_some) = (g().map(|_| S { v: 0 }), 0) { (w_some, v_some) } else { return; @@ -160,6 +161,30 @@ fn fire() { }; // dot dot works let v = if let Variant::A(.., a) = e() { a } else { return }; + + // () is preserved: a bit of an edge case but make sure it stays around + let w = if let (Some(v), ()) = (g(), ()) { v } else { return }; + + // Tuple structs work + let w = if let Some(S { v: x }) = Some(S { v: 0 }) { + x + } else { + return; + }; + + // Field init shorthand is suggested + let v = if let Some(S { v: x }) = Some(S { v: 0 }) { + x + } else { + return; + }; + + // Multi-field structs also work + let (x, S { v }, w) = if let Some(U { v, w, x }) = None::>> { + (x, v, w) + } else { + return; + }; } fn not_fire() { @@ -284,4 +309,23 @@ fn not_fire() { }; 1 }; + + // This would require creation of a suggestion of the form + // let v @ (Some(_), _) = (...) else { return }; + // Which is too advanced for our code, so we just bail. + let v = if let (Some(v_some), w_some) = (g(), 0) { + (w_some, v_some) + } else { + return; + }; +} + +struct S { + v: T, +} + +struct U { + v: T, + w: T, + x: T, } diff --git a/tests/ui/manual_let_else.stderr b/tests/ui/manual_let_else.stderr index 0e8767971347..1eada4f992ec 100644 --- a/tests/ui/manual_let_else.stderr +++ b/tests/ui/manual_let_else.stderr @@ -1,5 +1,5 @@ error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:24:5 + --> $DIR/manual_let_else.rs:25:5 | LL | let v = if let Some(v_some) = g() { v_some } else { return }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { return };` @@ -7,7 +7,7 @@ LL | let v = if let Some(v_some) = g() { v_some } else { return }; = note: `-D clippy::manual-let-else` implied by `-D warnings` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:25:5 + --> $DIR/manual_let_else.rs:26:5 | LL | / let v = if let Some(v_some) = g() { LL | | v_some @@ -24,7 +24,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:31:5 + --> $DIR/manual_let_else.rs:32:5 | LL | / let v = if let Some(v) = g() { LL | | // Blocks around the identity should have no impact @@ -45,25 +45,25 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:44:9 + --> $DIR/manual_let_else.rs:45:9 | LL | let v = if let Some(v_some) = g() { v_some } else { continue }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { continue };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:45:9 + --> $DIR/manual_let_else.rs:46:9 | LL | let v = if let Some(v_some) = g() { v_some } else { break }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { break };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:49:5 + --> $DIR/manual_let_else.rs:50:5 | LL | let v = if let Some(v_some) = g() { v_some } else { panic!() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { panic!() };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:52:5 + --> $DIR/manual_let_else.rs:53:5 | LL | / let v = if let Some(v_some) = g() { LL | | v_some @@ -80,7 +80,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:59:5 + --> $DIR/manual_let_else.rs:60:5 | LL | / let v = if let Some(v_some) = g() { LL | | v_some @@ -97,7 +97,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:66:5 + --> $DIR/manual_let_else.rs:67:5 | LL | / let v = if let Some(v_some) = g() { LL | | v_some @@ -116,7 +116,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:76:5 + --> $DIR/manual_let_else.rs:77:5 | LL | / let v = if let Some(v_some) = g() { LL | | v_some @@ -138,13 +138,13 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:86:5 + --> $DIR/manual_let_else.rs:87:5 | LL | let v = if let Some(v_some) = g() { v_some } else { if panic!() {} }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { if panic!() {} };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:89:5 + --> $DIR/manual_let_else.rs:90:5 | LL | / let v = if let Some(v_some) = g() { LL | | v_some @@ -165,7 +165,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:98:5 + --> $DIR/manual_let_else.rs:99:5 | LL | / let v = if let Some(v_some) = g() { LL | | v_some @@ -186,7 +186,7 @@ LL + } }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:107:5 + --> $DIR/manual_let_else.rs:108:5 | LL | / let v = if let Some(v_some) = g() { LL | | v_some @@ -215,7 +215,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:124:5 + --> $DIR/manual_let_else.rs:125:5 | LL | / let (v, w) = if let Some(v_some) = g().map(|v| (v, 42)) { LL | | v_some @@ -232,9 +232,9 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:131:5 + --> $DIR/manual_let_else.rs:132:5 | -LL | / let v = if let (Some(v_some), w_some) = (g(), 0) { +LL | / let (w, S { v }) = if let (Some(v_some), w_some) = (g().map(|_| S { v: 0 }), 0) { LL | | (w_some, v_some) LL | | } else { LL | | return; @@ -243,13 +243,13 @@ LL | | }; | help: consider writing | -LL ~ let (Some(v_some), w_some) = (g(), 0) else { +LL ~ let (Some(S { v }), w) = (g().map(|_| S { v: 0 }), 0) else { LL + return; LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:140:13 + --> $DIR/manual_let_else.rs:141:13 | LL | let $n = if let Some(v) = $e { v } else { return }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some($n) = g() else { return };` @@ -260,19 +260,19 @@ LL | create_binding_if_some!(w, g()); = note: this error originates in the macro `create_binding_if_some` (in Nightly builds, run with -Z macro-backtrace for more info) error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:149:5 + --> $DIR/manual_let_else.rs:150:5 | LL | let v = if let Variant::A(a, 0) = e() { a } else { return }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::A(v, 0) = e() else { return };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:152:5 + --> $DIR/manual_let_else.rs:153:5 | LL | let mut v = if let Variant::B(b) = e() { b } else { return }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::B(mut v) = e() else { return };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:156:5 + --> $DIR/manual_let_else.rs:157:5 | LL | / let v = if let Ok(Some(Variant::B(b))) | Err(Some(Variant::A(b, _))) = nested { LL | | b @@ -289,13 +289,70 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:162:5 + --> $DIR/manual_let_else.rs:163:5 | LL | let v = if let Variant::A(.., a) = e() { a } else { return }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::A(.., v) = e() else { return };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:272:5 + --> $DIR/manual_let_else.rs:166:5 + | +LL | let w = if let (Some(v), ()) = (g(), ()) { v } else { return }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let (Some(w), ()) = (g(), ()) else { return };` + +error: this could be rewritten as `let...else` + --> $DIR/manual_let_else.rs:169:5 + | +LL | / let w = if let Some(S { v: x }) = Some(S { v: 0 }) { +LL | | x +LL | | } else { +LL | | return; +LL | | }; + | |______^ + | +help: consider writing + | +LL ~ let Some(S { v: w }) = Some(S { v: 0 }) else { +LL + return; +LL + }; + | + +error: this could be rewritten as `let...else` + --> $DIR/manual_let_else.rs:176:5 + | +LL | / let v = if let Some(S { v: x }) = Some(S { v: 0 }) { +LL | | x +LL | | } else { +LL | | return; +LL | | }; + | |______^ + | +help: consider writing + | +LL ~ let Some(S { v }) = Some(S { v: 0 }) else { +LL + return; +LL + }; + | + +error: this could be rewritten as `let...else` + --> $DIR/manual_let_else.rs:183:5 + | +LL | / let (x, S { v }, w) = if let Some(U { v, w, x }) = None::>> { +LL | | (x, v, w) +LL | | } else { +LL | | return; +LL | | }; + | |______^ + | +help: consider writing + | +LL ~ let Some(U { v: S { v }, w, x }) = None::>> else { +LL + return; +LL + }; + | + +error: this could be rewritten as `let...else` + --> $DIR/manual_let_else.rs:297:5 | LL | / let _ = match ff { LL | | Some(value) => value, @@ -303,5 +360,5 @@ LL | | _ => macro_call!(), LL | | }; | |______^ help: consider writing: `let Some(_) = ff else { macro_call!() };` -error: aborting due to 22 previous errors +error: aborting due to 26 previous errors diff --git a/tests/ui/manual_let_else_match.rs b/tests/ui/manual_let_else_match.rs index dfca3b023cd5..73ff69eec4ed 100644 --- a/tests/ui/manual_let_else_match.rs +++ b/tests/ui/manual_let_else_match.rs @@ -1,5 +1,9 @@ #![allow(unused_braces, unused_variables, dead_code)] -#![allow(clippy::collapsible_else_if, clippy::let_unit_value)] +#![allow( + clippy::collapsible_else_if, + clippy::let_unit_value, + clippy::redundant_at_rest_pattern +)] #![warn(clippy::manual_let_else)] // Ensure that we don't conflict with match -> if let lints #![warn(clippy::single_match_else, clippy::single_match)] @@ -72,6 +76,11 @@ fn fire() { _ => return, }; + let _value = match Some(build_enum()) { + Some(Variant::Bar(v) | Variant::Baz(v)) => v, + _ => return, + }; + let data = [1_u8, 2, 3, 4, 0, 0, 0, 0]; let data = match data.as_slice() { [data @ .., 0, 0, 0, 0] | [data @ .., 0, 0] | [data @ .., 0] => data, diff --git a/tests/ui/manual_let_else_match.stderr b/tests/ui/manual_let_else_match.stderr index 13ed35bc1d5d..3fd9a637605b 100644 --- a/tests/ui/manual_let_else_match.stderr +++ b/tests/ui/manual_let_else_match.stderr @@ -1,5 +1,5 @@ error: this could be rewritten as `let...else` - --> $DIR/manual_let_else_match.rs:32:5 + --> $DIR/manual_let_else_match.rs:36:5 | LL | / let v = match g() { LL | | Some(v_some) => v_some, @@ -10,7 +10,7 @@ LL | | }; = note: `-D clippy::manual-let-else` implied by `-D warnings` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else_match.rs:37:5 + --> $DIR/manual_let_else_match.rs:41:5 | LL | / let v = match g() { LL | | Some(v_some) => v_some, @@ -19,7 +19,7 @@ LL | | }; | |______^ help: consider writing: `let Some(v) = g() else { return };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else_match.rs:44:9 + --> $DIR/manual_let_else_match.rs:48:9 | LL | / let v = match h() { LL | | (Some(v), None) | (None, Some(v)) => v, @@ -28,7 +28,7 @@ LL | | }; | |__________^ help: consider writing: `let ((Some(v), None) | (None, Some(v))) = h() else { continue };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else_match.rs:49:9 + --> $DIR/manual_let_else_match.rs:53:9 | LL | / let v = match build_enum() { LL | | Variant::Bar(v) | Variant::Baz(v) => v, @@ -37,7 +37,7 @@ LL | | }; | |__________^ help: consider writing: `let (Variant::Bar(v) | Variant::Baz(v)) = build_enum() else { continue };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else_match.rs:57:5 + --> $DIR/manual_let_else_match.rs:61:5 | LL | / let v = match f() { LL | | Ok(v) => v, @@ -46,7 +46,7 @@ LL | | }; | |______^ help: consider writing: `let Ok(v) = f() else { return };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else_match.rs:63:5 + --> $DIR/manual_let_else_match.rs:67:5 | LL | / let v = match f().map_err(|_| ()) { LL | | Ok(v) => v, @@ -55,7 +55,7 @@ LL | | }; | |______^ help: consider writing: `let Ok(v) = f().map_err(|_| ()) else { return };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else_match.rs:70:5 + --> $DIR/manual_let_else_match.rs:74:5 | LL | / let _value = match f { LL | | Variant::Bar(v) | Variant::Baz(v) => v, @@ -64,7 +64,16 @@ LL | | }; | |______^ help: consider writing: `let (Variant::Bar(_value) | Variant::Baz(_value)) = f else { return };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else_match.rs:76:5 + --> $DIR/manual_let_else_match.rs:79:5 + | +LL | / let _value = match Some(build_enum()) { +LL | | Some(Variant::Bar(v) | Variant::Baz(v)) => v, +LL | | _ => return, +LL | | }; + | |______^ help: consider writing: `let Some(Variant::Bar(_value) | Variant::Baz(_value)) = Some(build_enum()) else { return };` + +error: this could be rewritten as `let...else` + --> $DIR/manual_let_else_match.rs:85:5 | LL | / let data = match data.as_slice() { LL | | [data @ .., 0, 0, 0, 0] | [data @ .., 0, 0] | [data @ .., 0] => data, @@ -72,5 +81,5 @@ LL | | _ => return, LL | | }; | |______^ help: consider writing: `let ([data @ .., 0, 0, 0, 0] | [data @ .., 0, 0] | [data @ .., 0]) = data.as_slice() else { return };` -error: aborting due to 8 previous errors +error: aborting due to 9 previous errors diff --git a/tests/ui/manual_memcpy/without_loop_counters.rs b/tests/ui/manual_memcpy/without_loop_counters.rs index ea0535d076b8..4d5c70f19a06 100644 --- a/tests/ui/manual_memcpy/without_loop_counters.rs +++ b/tests/ui/manual_memcpy/without_loop_counters.rs @@ -1,4 +1,5 @@ #![warn(clippy::needless_range_loop, clippy::manual_memcpy)] +#![allow(clippy::useless_vec)] const LOOP_OFFSET: usize = 5000; diff --git a/tests/ui/manual_memcpy/without_loop_counters.stderr b/tests/ui/manual_memcpy/without_loop_counters.stderr index c163ae061dfc..1c6a7d5c04e0 100644 --- a/tests/ui/manual_memcpy/without_loop_counters.stderr +++ b/tests/ui/manual_memcpy/without_loop_counters.stderr @@ -1,5 +1,5 @@ error: it looks like you're manually copying between slices - --> $DIR/without_loop_counters.rs:7:5 + --> $DIR/without_loop_counters.rs:8:5 | LL | / for i in 0..src.len() { LL | | dst[i] = src[i]; @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::manual-memcpy` implied by `-D warnings` error: it looks like you're manually copying between slices - --> $DIR/without_loop_counters.rs:12:5 + --> $DIR/without_loop_counters.rs:13:5 | LL | / for i in 0..src.len() { LL | | dst[i + 10] = src[i]; @@ -17,7 +17,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst[10..(src.len() + 10)].copy_from_slice(&src[..]);` error: it looks like you're manually copying between slices - --> $DIR/without_loop_counters.rs:17:5 + --> $DIR/without_loop_counters.rs:18:5 | LL | / for i in 0..src.len() { LL | | dst[i] = src[i + 10]; @@ -25,7 +25,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst[..src.len()].copy_from_slice(&src[10..(src.len() + 10)]);` error: it looks like you're manually copying between slices - --> $DIR/without_loop_counters.rs:22:5 + --> $DIR/without_loop_counters.rs:23:5 | LL | / for i in 11..src.len() { LL | | dst[i] = src[i - 10]; @@ -33,7 +33,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst[11..src.len()].copy_from_slice(&src[(11 - 10)..(src.len() - 10)]);` error: it looks like you're manually copying between slices - --> $DIR/without_loop_counters.rs:27:5 + --> $DIR/without_loop_counters.rs:28:5 | LL | / for i in 0..dst.len() { LL | | dst[i] = src[i]; @@ -41,7 +41,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst.copy_from_slice(&src[..dst.len()]);` error: it looks like you're manually copying between slices - --> $DIR/without_loop_counters.rs:40:5 + --> $DIR/without_loop_counters.rs:41:5 | LL | / for i in 10..256 { LL | | dst[i] = src[i - 5]; @@ -56,7 +56,7 @@ LL + dst2[(10 + 500)..(256 + 500)].copy_from_slice(&src[10..256]); | error: it looks like you're manually copying between slices - --> $DIR/without_loop_counters.rs:52:5 + --> $DIR/without_loop_counters.rs:53:5 | LL | / for i in 10..LOOP_OFFSET { LL | | dst[i + LOOP_OFFSET] = src[i - some_var]; @@ -64,7 +64,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst[(10 + LOOP_OFFSET)..(LOOP_OFFSET + LOOP_OFFSET)].copy_from_slice(&src[(10 - some_var)..(LOOP_OFFSET - some_var)]);` error: it looks like you're manually copying between slices - --> $DIR/without_loop_counters.rs:65:5 + --> $DIR/without_loop_counters.rs:66:5 | LL | / for i in 0..src_vec.len() { LL | | dst_vec[i] = src_vec[i]; @@ -72,7 +72,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst_vec[..src_vec.len()].copy_from_slice(&src_vec[..]);` error: it looks like you're manually copying between slices - --> $DIR/without_loop_counters.rs:94:5 + --> $DIR/without_loop_counters.rs:95:5 | LL | / for i in from..from + src.len() { LL | | dst[i] = src[i - from]; @@ -80,7 +80,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst[from..(from + src.len())].copy_from_slice(&src[..(from + src.len() - from)]);` error: it looks like you're manually copying between slices - --> $DIR/without_loop_counters.rs:98:5 + --> $DIR/without_loop_counters.rs:99:5 | LL | / for i in from..from + 3 { LL | | dst[i] = src[i - from]; @@ -88,7 +88,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst[from..(from + 3)].copy_from_slice(&src[..(from + 3 - from)]);` error: it looks like you're manually copying between slices - --> $DIR/without_loop_counters.rs:103:5 + --> $DIR/without_loop_counters.rs:104:5 | LL | / for i in 0..5 { LL | | dst[i - 0] = src[i]; @@ -96,7 +96,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst[..5].copy_from_slice(&src[..5]);` error: it looks like you're manually copying between slices - --> $DIR/without_loop_counters.rs:108:5 + --> $DIR/without_loop_counters.rs:109:5 | LL | / for i in 0..0 { LL | | dst[i] = src[i]; @@ -104,7 +104,7 @@ LL | | } | |_____^ help: try replacing the loop by: `dst[..0].copy_from_slice(&src[..0]);` error: it looks like you're manually copying between slices - --> $DIR/without_loop_counters.rs:131:5 + --> $DIR/without_loop_counters.rs:132:5 | LL | / for i in 0..src.len() { LL | | dst[i] = src[i].clone(); diff --git a/tests/ui/manual_range_patterns.fixed b/tests/ui/manual_range_patterns.fixed new file mode 100644 index 000000000000..9eee8f371874 --- /dev/null +++ b/tests/ui/manual_range_patterns.fixed @@ -0,0 +1,35 @@ +//@run-rustfix + +#![allow(unused)] +#![warn(clippy::manual_range_patterns)] +#![feature(exclusive_range_pattern)] + +fn main() { + let f = 6; + + let _ = matches!(f, 1..=10); + let _ = matches!(f, 1..=10); + let _ = matches!(f, 4 | 2 | 3 | 1 | 5 | 6 | 9 | 8 | 10); // 7 is missing + let _ = matches!(f, | 4); + let _ = matches!(f, 4 | 5); + let _ = matches!(f, 1 | 2147483647); + let _ = matches!(f, 0 | 2147483647); + let _ = matches!(f, -2147483647 | 2147483647); + let _ = matches!(f, 1 | (2..=4)); + let _ = matches!(f, 1 | (2..4)); + let _ = matches!(f, 1..=48324729); + let _ = matches!(f, 0..=48324730); + let _ = matches!(f, 0..=3); + #[allow(clippy::match_like_matches_macro)] + let _ = match f { + 1..=10 => true, + _ => false, + }; + + macro_rules! mac { + ($e:expr) => { + matches!($e, 1..=10) + }; + } + mac!(f); +} diff --git a/tests/ui/manual_range_patterns.rs b/tests/ui/manual_range_patterns.rs new file mode 100644 index 000000000000..10743a7d04c6 --- /dev/null +++ b/tests/ui/manual_range_patterns.rs @@ -0,0 +1,35 @@ +//@run-rustfix + +#![allow(unused)] +#![warn(clippy::manual_range_patterns)] +#![feature(exclusive_range_pattern)] + +fn main() { + let f = 6; + + let _ = matches!(f, 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10); + let _ = matches!(f, 4 | 2 | 3 | 1 | 5 | 6 | 9 | 7 | 8 | 10); + let _ = matches!(f, 4 | 2 | 3 | 1 | 5 | 6 | 9 | 8 | 10); // 7 is missing + let _ = matches!(f, | 4); + let _ = matches!(f, 4 | 5); + let _ = matches!(f, 1 | 2147483647); + let _ = matches!(f, 0 | 2147483647); + let _ = matches!(f, -2147483647 | 2147483647); + let _ = matches!(f, 1 | (2..=4)); + let _ = matches!(f, 1 | (2..4)); + let _ = matches!(f, (1..=10) | (2..=13) | (14..=48324728) | 48324729); + let _ = matches!(f, 0 | (1..=10) | 48324730 | (2..=13) | (14..=48324728) | 48324729); + let _ = matches!(f, 0..=1 | 0..=2 | 0..=3); + #[allow(clippy::match_like_matches_macro)] + let _ = match f { + 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 => true, + _ => false, + }; + + macro_rules! mac { + ($e:expr) => { + matches!($e, 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10) + }; + } + mac!(f); +} diff --git a/tests/ui/manual_range_patterns.stderr b/tests/ui/manual_range_patterns.stderr new file mode 100644 index 000000000000..bc9e33501645 --- /dev/null +++ b/tests/ui/manual_range_patterns.stderr @@ -0,0 +1,51 @@ +error: this OR pattern can be rewritten using a range + --> $DIR/manual_range_patterns.rs:10:25 + | +LL | let _ = matches!(f, 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1..=10` + | + = note: `-D clippy::manual-range-patterns` implied by `-D warnings` + +error: this OR pattern can be rewritten using a range + --> $DIR/manual_range_patterns.rs:11:25 + | +LL | let _ = matches!(f, 4 | 2 | 3 | 1 | 5 | 6 | 9 | 7 | 8 | 10); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1..=10` + +error: this OR pattern can be rewritten using a range + --> $DIR/manual_range_patterns.rs:20:25 + | +LL | let _ = matches!(f, (1..=10) | (2..=13) | (14..=48324728) | 48324729); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1..=48324729` + +error: this OR pattern can be rewritten using a range + --> $DIR/manual_range_patterns.rs:21:25 + | +LL | let _ = matches!(f, 0 | (1..=10) | 48324730 | (2..=13) | (14..=48324728) | 48324729); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `0..=48324730` + +error: this OR pattern can be rewritten using a range + --> $DIR/manual_range_patterns.rs:22:25 + | +LL | let _ = matches!(f, 0..=1 | 0..=2 | 0..=3); + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `0..=3` + +error: this OR pattern can be rewritten using a range + --> $DIR/manual_range_patterns.rs:25:9 + | +LL | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 => true, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1..=10` + +error: this OR pattern can be rewritten using a range + --> $DIR/manual_range_patterns.rs:31:26 + | +LL | matches!($e, 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1..=10` +... +LL | mac!(f); + | ------- in this macro invocation + | + = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 7 previous errors + diff --git a/tests/ui/manual_rem_euclid.fixed b/tests/ui/manual_rem_euclid.fixed index f2e44e56f020..594a76897bbe 100644 --- a/tests/ui/manual_rem_euclid.fixed +++ b/tests/ui/manual_rem_euclid.fixed @@ -1,5 +1,5 @@ //@run-rustfix -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![warn(clippy::manual_rem_euclid)] #![allow(clippy::let_with_type_underscore)] diff --git a/tests/ui/manual_rem_euclid.rs b/tests/ui/manual_rem_euclid.rs index b2329c33a47d..d5f98e71517e 100644 --- a/tests/ui/manual_rem_euclid.rs +++ b/tests/ui/manual_rem_euclid.rs @@ -1,5 +1,5 @@ //@run-rustfix -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![warn(clippy::manual_rem_euclid)] #![allow(clippy::let_with_type_underscore)] diff --git a/tests/ui/manual_slice_size_calculation.fixed b/tests/ui/manual_slice_size_calculation.fixed index ac85bd8d3aca..5b9629f4bc10 100644 --- a/tests/ui/manual_slice_size_calculation.fixed +++ b/tests/ui/manual_slice_size_calculation.fixed @@ -1,5 +1,5 @@ //@run-rustfix -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![allow(unused)] #![warn(clippy::manual_slice_size_calculation)] diff --git a/tests/ui/manual_slice_size_calculation.rs b/tests/ui/manual_slice_size_calculation.rs index 1f824b12bc26..297887a9cfc8 100644 --- a/tests/ui/manual_slice_size_calculation.rs +++ b/tests/ui/manual_slice_size_calculation.rs @@ -1,5 +1,5 @@ //@run-rustfix -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![allow(unused)] #![warn(clippy::manual_slice_size_calculation)] diff --git a/tests/ui/manual_try_fold.rs b/tests/ui/manual_try_fold.rs new file mode 100644 index 000000000000..4521e9fa1a50 --- /dev/null +++ b/tests/ui/manual_try_fold.rs @@ -0,0 +1,100 @@ +//@aux-build:proc_macros.rs:proc-macro +#![allow(clippy::unnecessary_fold, unused)] +#![warn(clippy::manual_try_fold)] +#![feature(try_trait_v2)] + +use std::ops::ControlFlow; +use std::ops::FromResidual; +use std::ops::Try; + +#[macro_use] +extern crate proc_macros; + +// Test custom `Try` with more than 1 argument +struct NotOption(i32, i32); + +impl FromResidual for NotOption { + fn from_residual(_: R) -> Self { + todo!() + } +} + +impl Try for NotOption { + type Output = (); + type Residual = (); + + fn from_output(_: Self::Output) -> Self { + todo!() + } + + fn branch(self) -> ControlFlow { + todo!() + } +} + +// Test custom `Try` with only 1 argument +#[derive(Default)] +struct NotOptionButWorse(i32); + +impl FromResidual for NotOptionButWorse { + fn from_residual(_: R) -> Self { + todo!() + } +} + +impl Try for NotOptionButWorse { + type Output = (); + type Residual = (); + + fn from_output(_: Self::Output) -> Self { + todo!() + } + + fn branch(self) -> ControlFlow { + todo!() + } +} + +fn main() { + [1, 2, 3] + .iter() + .fold(Some(0i32), |sum, i| sum?.checked_add(*i)) + .unwrap(); + [1, 2, 3] + .iter() + .fold(NotOption(0i32, 0i32), |sum, i| NotOption(0i32, 0i32)); + [1, 2, 3] + .iter() + .fold(NotOptionButWorse(0i32), |sum, i| NotOptionButWorse(0i32)); + // Do not lint + [1, 2, 3].iter().try_fold(0i32, |sum, i| sum.checked_add(*i)).unwrap(); + [1, 2, 3].iter().fold(0i32, |sum, i| sum + i); + [1, 2, 3] + .iter() + .fold(NotOptionButWorse::default(), |sum, i| NotOptionButWorse::default()); + external! { + [1, 2, 3].iter().fold(Some(0i32), |sum, i| sum?.checked_add(*i)).unwrap(); + [1, 2, 3].iter().try_fold(0i32, |sum, i| sum.checked_add(*i)).unwrap(); + } + with_span! { + span + [1, 2, 3].iter().fold(Some(0i32), |sum, i| sum?.checked_add(*i)).unwrap(); + [1, 2, 3].iter().try_fold(0i32, |sum, i| sum.checked_add(*i)).unwrap(); + } +} + +#[clippy::msrv = "1.26.0"] +fn msrv_too_low() { + [1, 2, 3] + .iter() + .fold(Some(0i32), |sum, i| sum?.checked_add(*i)) + .unwrap(); +} + +#[clippy::msrv = "1.27.0"] +fn msrv_juust_right() { + [1, 2, 3] + .iter() + .fold(Some(0i32), |sum, i| sum?.checked_add(*i)) + .unwrap(); +} diff --git a/tests/ui/manual_try_fold.stderr b/tests/ui/manual_try_fold.stderr new file mode 100644 index 000000000000..a0cf5b3b5fc8 --- /dev/null +++ b/tests/ui/manual_try_fold.stderr @@ -0,0 +1,28 @@ +error: usage of `Iterator::fold` on a type that implements `Try` + --> $DIR/manual_try_fold.rs:61:10 + | +LL | .fold(Some(0i32), |sum, i| sum?.checked_add(*i)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `try_fold` instead: `try_fold(0i32, |sum, i| ...)` + | + = note: `-D clippy::manual-try-fold` implied by `-D warnings` + +error: usage of `Iterator::fold` on a type that implements `Try` + --> $DIR/manual_try_fold.rs:65:10 + | +LL | .fold(NotOption(0i32, 0i32), |sum, i| NotOption(0i32, 0i32)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `try_fold` instead: `try_fold(..., |sum, i| ...)` + +error: usage of `Iterator::fold` on a type that implements `Try` + --> $DIR/manual_try_fold.rs:68:10 + | +LL | .fold(NotOptionButWorse(0i32), |sum, i| NotOptionButWorse(0i32)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `try_fold` instead: `try_fold(0i32, |sum, i| ...)` + +error: usage of `Iterator::fold` on a type that implements `Try` + --> $DIR/manual_try_fold.rs:98:10 + | +LL | .fold(Some(0i32), |sum, i| sum?.checked_add(*i)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `try_fold` instead: `try_fold(0i32, |sum, i| ...)` + +error: aborting due to 4 previous errors + diff --git a/tests/ui/manual_unwrap_or.fixed b/tests/ui/manual_unwrap_or.fixed index c17634bffe30..20560b87c1a5 100644 --- a/tests/ui/manual_unwrap_or.fixed +++ b/tests/ui/manual_unwrap_or.fixed @@ -1,6 +1,6 @@ //@run-rustfix #![allow(dead_code)] -#![allow(unused_variables, clippy::unnecessary_wraps)] +#![allow(unused_variables, clippy::unnecessary_wraps, clippy::unnecessary_literal_unwrap)] fn option_unwrap_or() { // int case diff --git a/tests/ui/manual_unwrap_or.rs b/tests/ui/manual_unwrap_or.rs index 6d49a6949fa9..5dbc57565bff 100644 --- a/tests/ui/manual_unwrap_or.rs +++ b/tests/ui/manual_unwrap_or.rs @@ -1,6 +1,6 @@ //@run-rustfix #![allow(dead_code)] -#![allow(unused_variables, clippy::unnecessary_wraps)] +#![allow(unused_variables, clippy::unnecessary_wraps, clippy::unnecessary_literal_unwrap)] fn option_unwrap_or() { // int case diff --git a/tests/ui/map_clone.fixed b/tests/ui/map_clone.fixed index d7474f357191..50c0eb1a8108 100644 --- a/tests/ui/map_clone.fixed +++ b/tests/ui/map_clone.fixed @@ -4,7 +4,8 @@ clippy::clone_on_copy, clippy::iter_cloned_collect, clippy::many_single_char_names, - clippy::redundant_clone + clippy::redundant_clone, + clippy::useless_vec )] fn main() { diff --git a/tests/ui/map_clone.rs b/tests/ui/map_clone.rs index 74978ae8006d..91a084f2844d 100644 --- a/tests/ui/map_clone.rs +++ b/tests/ui/map_clone.rs @@ -4,7 +4,8 @@ clippy::clone_on_copy, clippy::iter_cloned_collect, clippy::many_single_char_names, - clippy::redundant_clone + clippy::redundant_clone, + clippy::useless_vec )] fn main() { diff --git a/tests/ui/map_clone.stderr b/tests/ui/map_clone.stderr index d84a5bf8d4de..d768af1f48c9 100644 --- a/tests/ui/map_clone.stderr +++ b/tests/ui/map_clone.stderr @@ -1,5 +1,5 @@ error: you are using an explicit closure for copying elements - --> $DIR/map_clone.rs:11:22 + --> $DIR/map_clone.rs:12:22 | LL | let _: Vec = vec![5_i8; 6].iter().map(|x| *x).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `vec![5_i8; 6].iter().copied()` @@ -7,31 +7,31 @@ LL | let _: Vec = vec![5_i8; 6].iter().map(|x| *x).collect(); = note: `-D clippy::map-clone` implied by `-D warnings` error: you are using an explicit closure for cloning elements - --> $DIR/map_clone.rs:12:26 + --> $DIR/map_clone.rs:13:26 | LL | let _: Vec = vec![String::new()].iter().map(|x| x.clone()).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `vec![String::new()].iter().cloned()` error: you are using an explicit closure for copying elements - --> $DIR/map_clone.rs:13:23 + --> $DIR/map_clone.rs:14:23 | LL | let _: Vec = vec![42, 43].iter().map(|&x| x).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `vec![42, 43].iter().copied()` error: you are using an explicit closure for copying elements - --> $DIR/map_clone.rs:15:26 + --> $DIR/map_clone.rs:16:26 | LL | let _: Option = Some(&16).map(|b| *b); | ^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `Some(&16).copied()` error: you are using an explicit closure for copying elements - --> $DIR/map_clone.rs:16:25 + --> $DIR/map_clone.rs:17:25 | LL | let _: Option = Some(&1).map(|x| x.clone()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `Some(&1).copied()` error: you are needlessly cloning iterator elements - --> $DIR/map_clone.rs:27:29 + --> $DIR/map_clone.rs:28:29 | LL | let _ = std::env::args().map(|v| v.clone()); | ^^^^^^^^^^^^^^^^^^^ help: remove the `map` call diff --git a/tests/ui/map_unwrap_or.rs b/tests/ui/map_unwrap_or.rs index cb25d8567aa0..bb36cb2c598b 100644 --- a/tests/ui/map_unwrap_or.rs +++ b/tests/ui/map_unwrap_or.rs @@ -56,6 +56,10 @@ fn option_methods() { .unwrap_or_else(|| 0 ); + + // Check for `map(f).unwrap_or(false)` use. + let _ = opt.map(|x| x > 5).unwrap_or(false); + } #[rustfmt::skip] @@ -94,3 +98,46 @@ fn msrv_1_41() { let _ = res.map(|x| x + 1).unwrap_or_else(|_e| 0); } + +#[clippy::msrv = "1.69"] +fn msrv_1_69() { + let opt: Option = Some(1); + + let _ = opt.map(|x| x > 5).unwrap_or(false); +} + +#[clippy::msrv = "1.70"] +fn msrv_1_70() { + let opt: Option = Some(1); + + let _ = opt.map(|x| x > 5).unwrap_or(false); +} + +mod issue_10579 { + // Different variations of the same issue. + fn v1() { + let x = vec![1, 2, 3, 0]; + let y = x.strip_suffix(&[0]).map(|s| s.to_vec()).unwrap_or(x); + println!("{y:?}"); + } + fn v2() { + let x = vec![1, 2, 3, 0]; + let y = Some(()).map(|_| x.to_vec()).unwrap_or(x); + println!("{y:?}"); + } + fn v3() { + let x = vec![1, 2, 3, 0]; + let xref = &x; + let y = Some(()).map(|_| xref.to_vec()).unwrap_or(x); + println!("{y:?}"); + } + fn v4() { + struct VecInStruct { + v: Vec, + } + let s = VecInStruct { v: vec![1, 2, 3, 0] }; + + let y = Some(()).map(|_| s.v.clone()).unwrap_or(s.v); + println!("{y:?}"); + } +} diff --git a/tests/ui/map_unwrap_or.stderr b/tests/ui/map_unwrap_or.stderr index 41781b050fa2..9f4a4a9ae6bf 100644 --- a/tests/ui/map_unwrap_or.stderr +++ b/tests/ui/map_unwrap_or.stderr @@ -126,8 +126,20 @@ LL | | 0 LL | | ); | |_________^ +error: called `map().unwrap_or(false)` on an `Option` value. This can be done more directly by calling `is_some_and()` instead + --> $DIR/map_unwrap_or.rs:61:13 + | +LL | let _ = opt.map(|x| x > 5).unwrap_or(false); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `is_some_and()` instead + | +LL - let _ = opt.map(|x| x > 5).unwrap_or(false); +LL + let _ = opt.is_some_and(|x| x > 5); + | + error: called `map().unwrap_or_else()` on a `Result` value. This can be done more directly by calling `.map_or_else(, )` instead - --> $DIR/map_unwrap_or.rs:67:13 + --> $DIR/map_unwrap_or.rs:71:13 | LL | let _ = res.map(|x| { | _____________^ @@ -137,7 +149,7 @@ LL | | ).unwrap_or_else(|_e| 0); | |____________________________^ error: called `map().unwrap_or_else()` on a `Result` value. This can be done more directly by calling `.map_or_else(, )` instead - --> $DIR/map_unwrap_or.rs:71:13 + --> $DIR/map_unwrap_or.rs:75:13 | LL | let _ = res.map(|x| x + 1) | _____________^ @@ -147,10 +159,34 @@ LL | | }); | |__________^ error: called `map().unwrap_or_else()` on a `Result` value. This can be done more directly by calling `.map_or_else(, )` instead - --> $DIR/map_unwrap_or.rs:95:13 + --> $DIR/map_unwrap_or.rs:99:13 | LL | let _ = res.map(|x| x + 1).unwrap_or_else(|_e| 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `res.map_or_else(|_e| 0, |x| x + 1)` -error: aborting due to 12 previous errors +error: called `map().unwrap_or()` on an `Option` value. This can be done more directly by calling `map_or(, )` instead + --> $DIR/map_unwrap_or.rs:106:13 + | +LL | let _ = opt.map(|x| x > 5).unwrap_or(false); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `map_or(, )` instead + | +LL - let _ = opt.map(|x| x > 5).unwrap_or(false); +LL + let _ = opt.map_or(false, |x| x > 5); + | + +error: called `map().unwrap_or(false)` on an `Option` value. This can be done more directly by calling `is_some_and()` instead + --> $DIR/map_unwrap_or.rs:113:13 + | +LL | let _ = opt.map(|x| x > 5).unwrap_or(false); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `is_some_and()` instead + | +LL - let _ = opt.map(|x| x > 5).unwrap_or(false); +LL + let _ = opt.is_some_and(|x| x > 5); + | + +error: aborting due to 15 previous errors diff --git a/tests/ui/match_on_vec_items.rs b/tests/ui/match_on_vec_items.rs index 30415e3b94dc..cf9c279cd2f1 100644 --- a/tests/ui/match_on_vec_items.rs +++ b/tests/ui/match_on_vec_items.rs @@ -1,4 +1,5 @@ #![warn(clippy::match_on_vec_items)] +#![allow(clippy::redundant_at_rest_pattern, clippy::useless_vec)] fn match_with_wildcard() { let arr = vec![0, 1, 2, 3]; diff --git a/tests/ui/match_on_vec_items.stderr b/tests/ui/match_on_vec_items.stderr index 49446d715abe..9b1f052867e0 100644 --- a/tests/ui/match_on_vec_items.stderr +++ b/tests/ui/match_on_vec_items.stderr @@ -1,5 +1,5 @@ error: indexing into a vector may panic - --> $DIR/match_on_vec_items.rs:9:11 + --> $DIR/match_on_vec_items.rs:10:11 | LL | match arr[idx] { | ^^^^^^^^ help: try this: `arr.get(idx)` @@ -7,43 +7,43 @@ LL | match arr[idx] { = note: `-D clippy::match-on-vec-items` implied by `-D warnings` error: indexing into a vector may panic - --> $DIR/match_on_vec_items.rs:16:11 + --> $DIR/match_on_vec_items.rs:17:11 | LL | match arr[range] { | ^^^^^^^^^^ help: try this: `arr.get(range)` error: indexing into a vector may panic - --> $DIR/match_on_vec_items.rs:29:11 + --> $DIR/match_on_vec_items.rs:30:11 | LL | match arr[idx] { | ^^^^^^^^ help: try this: `arr.get(idx)` error: indexing into a vector may panic - --> $DIR/match_on_vec_items.rs:36:11 + --> $DIR/match_on_vec_items.rs:37:11 | LL | match arr[range] { | ^^^^^^^^^^ help: try this: `arr.get(range)` error: indexing into a vector may panic - --> $DIR/match_on_vec_items.rs:49:11 + --> $DIR/match_on_vec_items.rs:50:11 | LL | match arr[idx] { | ^^^^^^^^ help: try this: `arr.get(idx)` error: indexing into a vector may panic - --> $DIR/match_on_vec_items.rs:56:11 + --> $DIR/match_on_vec_items.rs:57:11 | LL | match arr[range] { | ^^^^^^^^^^ help: try this: `arr.get(range)` error: indexing into a vector may panic - --> $DIR/match_on_vec_items.rs:69:11 + --> $DIR/match_on_vec_items.rs:70:11 | LL | match arr[idx] { | ^^^^^^^^ help: try this: `arr.get(idx)` error: indexing into a vector may panic - --> $DIR/match_on_vec_items.rs:76:11 + --> $DIR/match_on_vec_items.rs:77:11 | LL | match arr[range] { | ^^^^^^^^^^ help: try this: `arr.get(range)` diff --git a/tests/ui/match_overlapping_arm.rs b/tests/ui/match_overlapping_arm.rs index b4097fa96045..b78c1fd06d44 100644 --- a/tests/ui/match_overlapping_arm.rs +++ b/tests/ui/match_overlapping_arm.rs @@ -1,7 +1,7 @@ #![feature(exclusive_range_pattern)] #![warn(clippy::match_overlapping_arm)] #![allow(clippy::redundant_pattern_matching)] -#![allow(clippy::if_same_then_else, clippy::equatable_if_let)] +#![allow(clippy::if_same_then_else, clippy::equatable_if_let, clippy::needless_if)] /// Tests for match_overlapping_arm diff --git a/tests/ui/match_same_arms.rs b/tests/ui/match_same_arms.rs index 3914b45464c7..fad6a7db988c 100644 --- a/tests/ui/match_same_arms.rs +++ b/tests/ui/match_same_arms.rs @@ -8,29 +8,30 @@ pub enum Abc { fn match_same_arms() { let _ = match Abc::A { - Abc::A => 0, + Abc::A => 0, //~ ERROR: this match arm has an identical body to the `_` wildcard arm Abc::B => 1, - _ => 0, //~ ERROR match arms have same body + _ => 0, }; match (1, 2, 3) { - (1, .., 3) => 42, - (.., 3) => 42, //~ ERROR match arms have same body + (1, .., 3) => 42, //~ ERROR: this match arm has an identical body to another arm + (.., 3) => 42, _ => 0, }; let _ = match 42 { 42 => 1, - 51 => 1, //~ ERROR match arms have same body - 41 => 2, - 52 => 2, //~ ERROR match arms have same body + 51 => 1, //~ ERROR: this match arm has an identical body to another arm + 41 => 2, //~ ERROR: this match arm has an identical body to another arm + 52 => 2, _ => 0, }; let _ = match 42 { 1 => 2, - 2 => 2, //~ ERROR 2nd matched arms have same body - 3 => 2, //~ ERROR 3rd matched arms have same body + 2 => 2, //~ ERROR: this match arm has an identical body to another arm + //~^ ERROR: this match arm has an identical body to another arm + 3 => 2, //~ ERROR: this match arm has an identical body to another arm 4 => 3, _ => 0, }; @@ -48,6 +49,7 @@ mod issue4244 { match self { CommandInfo::BuiltIn { name, .. } => name.to_string(), CommandInfo::External { name, .. } => name.to_string(), + //~^ ERROR: this match arm has an identical body to another arm } } } diff --git a/tests/ui/match_same_arms.stderr b/tests/ui/match_same_arms.stderr index db85b5964e84..88b9a20a3726 100644 --- a/tests/ui/match_same_arms.stderr +++ b/tests/ui/match_same_arms.stderr @@ -8,7 +8,7 @@ LL | Abc::A => 0, note: `_` wildcard arm here --> $DIR/match_same_arms.rs:13:9 | -LL | _ => 0, //~ ERROR match arms have same body +LL | _ => 0, | ^^^^^^ = note: `-D clippy::match-same-arms` implied by `-D warnings` @@ -24,13 +24,13 @@ LL | (1, .., 3) => 42, note: other arm here --> $DIR/match_same_arms.rs:18:9 | -LL | (.., 3) => 42, //~ ERROR match arms have same body +LL | (.., 3) => 42, | ^^^^^^^^^^^^^ error: this match arm has an identical body to another arm --> $DIR/match_same_arms.rs:24:9 | -LL | 51 => 1, //~ ERROR match arms have same body +LL | 51 => 1, | --^^^^^ | | | help: try merging the arm patterns: `51 | 42` @@ -54,13 +54,13 @@ LL | 41 => 2, note: other arm here --> $DIR/match_same_arms.rs:26:9 | -LL | 52 => 2, //~ ERROR match arms have same body +LL | 52 => 2, | ^^^^^^^ error: this match arm has an identical body to another arm --> $DIR/match_same_arms.rs:32:9 | -LL | 2 => 2, //~ ERROR 2nd matched arms have same body +LL | 2 => 2, | -^^^^^ | | | help: try merging the arm patterns: `2 | 1` @@ -73,9 +73,9 @@ LL | 1 => 2, | ^^^^^^ error: this match arm has an identical body to another arm - --> $DIR/match_same_arms.rs:33:9 + --> $DIR/match_same_arms.rs:34:9 | -LL | 3 => 2, //~ ERROR 3rd matched arms have same body +LL | 3 => 2, | -^^^^^ | | | help: try merging the arm patterns: `3 | 1` @@ -90,20 +90,20 @@ LL | 1 => 2, error: this match arm has an identical body to another arm --> $DIR/match_same_arms.rs:32:9 | -LL | 2 => 2, //~ ERROR 2nd matched arms have same body +LL | 2 => 2, | -^^^^^ | | | help: try merging the arm patterns: `2 | 3` | = help: or try changing either arm body note: other arm here - --> $DIR/match_same_arms.rs:33:9 + --> $DIR/match_same_arms.rs:34:9 | -LL | 3 => 2, //~ ERROR 3rd matched arms have same body +LL | 3 => 2, | ^^^^^^ error: this match arm has an identical body to another arm - --> $DIR/match_same_arms.rs:50:17 + --> $DIR/match_same_arms.rs:51:17 | LL | CommandInfo::External { name, .. } => name.to_string(), | ----------------------------------^^^^^^^^^^^^^^^^^^^^ @@ -112,7 +112,7 @@ LL | CommandInfo::External { name, .. } => name.to_string(), | = help: or try changing either arm body note: other arm here - --> $DIR/match_same_arms.rs:49:17 + --> $DIR/match_same_arms.rs:50:17 | LL | CommandInfo::BuiltIn { name, .. } => name.to_string(), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/match_same_arms2.rs b/tests/ui/match_same_arms2.rs index 60b2975be045..b1b9a6ae3e8a 100644 --- a/tests/ui/match_same_arms2.rs +++ b/tests/ui/match_same_arms2.rs @@ -13,6 +13,7 @@ fn foo() -> bool { fn match_same_arms() { let _ = match 42 { 42 => { + //~^ ERROR: this match arm has an identical body to the `_` wildcard arm foo(); let mut a = 42 + [23].len() as i32; if true { @@ -22,7 +23,6 @@ fn match_same_arms() { a }, _ => { - //~ ERROR match arms have same body foo(); let mut a = 42 + [23].len() as i32; if true { @@ -35,13 +35,13 @@ fn match_same_arms() { let _ = match 42 { 42 => foo(), - 51 => foo(), //~ ERROR match arms have same body + 51 => foo(), //~ ERROR: this match arm has an identical body to another arm _ => true, }; let _ = match Some(42) { Some(_) => 24, - None => 24, //~ ERROR match arms have same body + None => 24, //~ ERROR: this match arm has an identical body to another arm }; let _ = match Some(42) { @@ -63,13 +63,13 @@ fn match_same_arms() { match (Some(42), Some(42)) { (Some(a), None) => bar(a), - (None, Some(a)) => bar(a), //~ ERROR match arms have same body + (None, Some(a)) => bar(a), //~ ERROR: this match arm has an identical body to another arm _ => (), } match (Some(42), Some(42)) { - (Some(a), ..) => bar(a), - (.., Some(a)) => bar(a), //~ ERROR match arms have same body + (Some(a), ..) => bar(a), //~ ERROR: this match arm has an identical body to another arm + (.., Some(a)) => bar(a), _ => (), } @@ -102,7 +102,7 @@ fn match_same_arms() { } match (x, Some(1i32)) { - (Ok(x), Some(_)) => println!("ok {}", x), + (Ok(x), Some(_)) => println!("ok {}", x), //~ ERROR: this match arm has an identical body to another arm (Ok(_), Some(x)) => println!("ok {}", x), _ => println!("err"), } @@ -118,7 +118,7 @@ fn match_same_arms() { match x { Ok(_tmp) => println!("ok"), Ok(3) => println!("ok"), - Ok(_) => println!("ok"), + Ok(_) => println!("ok"), //~ ERROR: this match arm has an identical body to another arm Err(_) => { unreachable!(); }, @@ -146,6 +146,7 @@ fn match_same_arms() { empty!(0); }, 1 => { + //~^ ERROR: this match arm has an identical body to another arm empty!(0); }, x => { @@ -195,7 +196,7 @@ fn main() { // Suggest moving `Foo::Z(_)` up. let _ = match Foo::X(0) { - Foo::X(0) => 1, + Foo::X(0) => 1, //~ ERROR: this match arm has an identical body to another arm Foo::X(_) | Foo::Y(_) => 2, Foo::Z(_) => 1, _ => 0, @@ -205,7 +206,7 @@ fn main() { let _ = match Foo::X(0) { Foo::X(0) => 1, Foo::Y(_) | Foo::Z(0) => 2, - Foo::Z(_) => 1, + Foo::Z(_) => 1, //~ ERROR: this match arm has an identical body to another arm _ => 0, }; @@ -228,7 +229,7 @@ fn main() { Some(Bar { x: 0, y: 5, .. }) => 1, Some(Bar { y: 10, z: 0, .. }) => 2, None => 50, - Some(Bar { y: 0, x: 5, .. }) => 1, + Some(Bar { y: 0, x: 5, .. }) => 1, //~ ERROR: this match arm has an identical body to another arm _ => 200, }; diff --git a/tests/ui/match_same_arms2.stderr b/tests/ui/match_same_arms2.stderr index 8fb461bd2866..7f0c70745ac0 100644 --- a/tests/ui/match_same_arms2.stderr +++ b/tests/ui/match_same_arms2.stderr @@ -2,9 +2,9 @@ error: this match arm has an identical body to the `_` wildcard arm --> $DIR/match_same_arms2.rs:15:9 | LL | / 42 => { +LL | | LL | | foo(); LL | | let mut a = 42 + [23].len() as i32; -LL | | if true { ... | LL | | a LL | | }, @@ -12,12 +12,12 @@ LL | | }, | = help: or try changing either arm body note: `_` wildcard arm here - --> $DIR/match_same_arms2.rs:24:9 + --> $DIR/match_same_arms2.rs:25:9 | LL | / _ => { -LL | | //~ ERROR match arms have same body LL | | foo(); LL | | let mut a = 42 + [23].len() as i32; +LL | | if true { ... | LL | | a LL | | }, @@ -27,7 +27,7 @@ LL | | }, error: this match arm has an identical body to another arm --> $DIR/match_same_arms2.rs:38:9 | -LL | 51 => foo(), //~ ERROR match arms have same body +LL | 51 => foo(), | --^^^^^^^^^ | | | help: try merging the arm patterns: `51 | 42` @@ -42,7 +42,7 @@ LL | 42 => foo(), error: this match arm has an identical body to another arm --> $DIR/match_same_arms2.rs:44:9 | -LL | None => 24, //~ ERROR match arms have same body +LL | None => 24, | ----^^^^^^ | | | help: try merging the arm patterns: `None | Some(_)` @@ -57,7 +57,7 @@ LL | Some(_) => 24, error: this match arm has an identical body to another arm --> $DIR/match_same_arms2.rs:66:9 | -LL | (None, Some(a)) => bar(a), //~ ERROR match arms have same body +LL | (None, Some(a)) => bar(a), | ---------------^^^^^^^^^^ | | | help: try merging the arm patterns: `(None, Some(a)) | (Some(a), None)` @@ -81,7 +81,7 @@ LL | (Some(a), ..) => bar(a), note: other arm here --> $DIR/match_same_arms2.rs:72:9 | -LL | (.., Some(a)) => bar(a), //~ ERROR match arms have same body +LL | (.., Some(a)) => bar(a), | ^^^^^^^^^^^^^^^^^^^^^^^ error: this match arm has an identical body to another arm @@ -121,6 +121,7 @@ LL | 1 => { | ^ help: try merging the arm patterns: `1 | 0` | _________| | | +LL | | LL | | empty!(0); LL | | }, | |_________^ @@ -135,7 +136,7 @@ LL | | }, | |_________^ error: match expression looks like `matches!` macro - --> $DIR/match_same_arms2.rs:166:16 + --> $DIR/match_same_arms2.rs:167:16 | LL | let _ans = match x { | ________________^ @@ -148,7 +149,7 @@ LL | | }; = note: `-D clippy::match-like-matches-macro` implied by `-D warnings` error: this match arm has an identical body to another arm - --> $DIR/match_same_arms2.rs:198:9 + --> $DIR/match_same_arms2.rs:199:9 | LL | Foo::X(0) => 1, | ---------^^^^^ @@ -157,13 +158,13 @@ LL | Foo::X(0) => 1, | = help: or try changing either arm body note: other arm here - --> $DIR/match_same_arms2.rs:200:9 + --> $DIR/match_same_arms2.rs:201:9 | LL | Foo::Z(_) => 1, | ^^^^^^^^^^^^^^ error: this match arm has an identical body to another arm - --> $DIR/match_same_arms2.rs:208:9 + --> $DIR/match_same_arms2.rs:209:9 | LL | Foo::Z(_) => 1, | ---------^^^^^ @@ -172,13 +173,13 @@ LL | Foo::Z(_) => 1, | = help: or try changing either arm body note: other arm here - --> $DIR/match_same_arms2.rs:206:9 + --> $DIR/match_same_arms2.rs:207:9 | LL | Foo::X(0) => 1, | ^^^^^^^^^^^^^^ error: this match arm has an identical body to another arm - --> $DIR/match_same_arms2.rs:231:9 + --> $DIR/match_same_arms2.rs:232:9 | LL | Some(Bar { y: 0, x: 5, .. }) => 1, | ----------------------------^^^^^ @@ -187,13 +188,13 @@ LL | Some(Bar { y: 0, x: 5, .. }) => 1, | = help: or try changing either arm body note: other arm here - --> $DIR/match_same_arms2.rs:228:9 + --> $DIR/match_same_arms2.rs:229:9 | LL | Some(Bar { x: 0, y: 5, .. }) => 1, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this match arm has an identical body to another arm - --> $DIR/match_same_arms2.rs:245:9 + --> $DIR/match_same_arms2.rs:246:9 | LL | 1 => cfg!(not_enable), | -^^^^^^^^^^^^^^^^^^^^ @@ -202,7 +203,7 @@ LL | 1 => cfg!(not_enable), | = help: or try changing either arm body note: other arm here - --> $DIR/match_same_arms2.rs:244:9 + --> $DIR/match_same_arms2.rs:245:9 | LL | 0 => cfg!(not_enable), | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/match_same_arms_non_exhaustive.rs b/tests/ui/match_same_arms_non_exhaustive.rs new file mode 100644 index 000000000000..07421173a338 --- /dev/null +++ b/tests/ui/match_same_arms_non_exhaustive.rs @@ -0,0 +1,58 @@ +#![feature(non_exhaustive_omitted_patterns_lint)] +#![warn(clippy::match_same_arms)] +#![no_main] + +use std::sync::atomic::Ordering; // #[non_exhaustive] enum + +pub fn f(x: Ordering) { + match x { + Ordering::Relaxed => println!("relaxed"), + Ordering::Release => println!("release"), + Ordering::Acquire => println!("acquire"), + Ordering::AcqRel | Ordering::SeqCst => panic!(), + #[deny(non_exhaustive_omitted_patterns)] + _ => panic!(), + } +} + +mod f { + #![deny(non_exhaustive_omitted_patterns)] + + use super::*; + + pub fn f(x: Ordering) { + match x { + Ordering::Relaxed => println!("relaxed"), + Ordering::Release => println!("release"), + Ordering::Acquire => println!("acquire"), + Ordering::AcqRel | Ordering::SeqCst => panic!(), + _ => panic!(), + } + } +} + +// Below should still lint + +pub fn g(x: Ordering) { + match x { + Ordering::Relaxed => println!("relaxed"), + Ordering::Release => println!("release"), + Ordering::Acquire => println!("acquire"), + Ordering::AcqRel | Ordering::SeqCst => panic!(), + _ => panic!(), + } +} + +mod g { + use super::*; + + pub fn g(x: Ordering) { + match x { + Ordering::Relaxed => println!("relaxed"), + Ordering::Release => println!("release"), + Ordering::Acquire => println!("acquire"), + Ordering::AcqRel | Ordering::SeqCst => panic!(), + _ => panic!(), + } + } +} diff --git a/tests/ui/match_same_arms_non_exhaustive.stderr b/tests/ui/match_same_arms_non_exhaustive.stderr new file mode 100644 index 000000000000..088f7d5c0624 --- /dev/null +++ b/tests/ui/match_same_arms_non_exhaustive.stderr @@ -0,0 +1,29 @@ +error: this match arm has an identical body to the `_` wildcard arm + --> $DIR/match_same_arms_non_exhaustive.rs:41:9 + | +LL | Ordering::AcqRel | Ordering::SeqCst => panic!(), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try removing the arm + | + = help: or try changing either arm body +note: `_` wildcard arm here + --> $DIR/match_same_arms_non_exhaustive.rs:42:9 + | +LL | _ => panic!(), + | ^^^^^^^^^^^^^ + = note: `-D clippy::match-same-arms` implied by `-D warnings` + +error: this match arm has an identical body to the `_` wildcard arm + --> $DIR/match_same_arms_non_exhaustive.rs:54:13 + | +LL | Ordering::AcqRel | Ordering::SeqCst => panic!(), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try removing the arm + | + = help: or try changing either arm body +note: `_` wildcard arm here + --> $DIR/match_same_arms_non_exhaustive.rs:55:13 + | +LL | _ => panic!(), + | ^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/match_single_binding.fixed b/tests/ui/match_single_binding.fixed index 7c29bb08e64d..f59ff456bf29 100644 --- a/tests/ui/match_single_binding.fixed +++ b/tests/ui/match_single_binding.fixed @@ -5,7 +5,8 @@ clippy::let_unit_value, clippy::no_effect, clippy::toplevel_ref_arg, - clippy::uninlined_format_args + clippy::uninlined_format_args, + clippy::useless_vec )] struct Point { diff --git a/tests/ui/match_single_binding.rs b/tests/ui/match_single_binding.rs index c068d5e17c33..e293bc33c8a9 100644 --- a/tests/ui/match_single_binding.rs +++ b/tests/ui/match_single_binding.rs @@ -5,7 +5,8 @@ clippy::let_unit_value, clippy::no_effect, clippy::toplevel_ref_arg, - clippy::uninlined_format_args + clippy::uninlined_format_args, + clippy::useless_vec )] struct Point { diff --git a/tests/ui/match_single_binding.stderr b/tests/ui/match_single_binding.stderr index 9d16af76c6af..8998786de7ea 100644 --- a/tests/ui/match_single_binding.stderr +++ b/tests/ui/match_single_binding.stderr @@ -1,5 +1,5 @@ error: this match could be written as a `let` statement - --> $DIR/match_single_binding.rs:33:5 + --> $DIR/match_single_binding.rs:34:5 | LL | / match (a, b, c) { LL | | (x, y, z) => { @@ -18,7 +18,7 @@ LL + } | error: this match could be written as a `let` statement - --> $DIR/match_single_binding.rs:39:5 + --> $DIR/match_single_binding.rs:40:5 | LL | / match (a, b, c) { LL | | (x, y, z) => println!("{} {} {}", x, y, z), @@ -32,7 +32,7 @@ LL + println!("{} {} {}", x, y, z); | error: this match could be replaced by its body itself - --> $DIR/match_single_binding.rs:56:5 + --> $DIR/match_single_binding.rs:57:5 | LL | / match a { LL | | _ => println!("whatever"), @@ -40,7 +40,7 @@ LL | | } | |_____^ help: consider using the match body instead: `println!("whatever");` error: this match could be replaced by its body itself - --> $DIR/match_single_binding.rs:60:5 + --> $DIR/match_single_binding.rs:61:5 | LL | / match a { LL | | _ => { @@ -59,7 +59,7 @@ LL + } | error: this match could be replaced by its body itself - --> $DIR/match_single_binding.rs:67:5 + --> $DIR/match_single_binding.rs:68:5 | LL | / match a { LL | | _ => { @@ -81,7 +81,7 @@ LL + } | error: this match could be written as a `let` statement - --> $DIR/match_single_binding.rs:77:5 + --> $DIR/match_single_binding.rs:78:5 | LL | / match p { LL | | Point { x, y } => println!("Coords: ({}, {})", x, y), @@ -95,7 +95,7 @@ LL + println!("Coords: ({}, {})", x, y); | error: this match could be written as a `let` statement - --> $DIR/match_single_binding.rs:81:5 + --> $DIR/match_single_binding.rs:82:5 | LL | / match p { LL | | Point { x: x1, y: y1 } => println!("Coords: ({}, {})", x1, y1), @@ -109,7 +109,7 @@ LL + println!("Coords: ({}, {})", x1, y1); | error: this match could be written as a `let` statement - --> $DIR/match_single_binding.rs:86:5 + --> $DIR/match_single_binding.rs:87:5 | LL | / match x { LL | | ref r => println!("Got a reference to {}", r), @@ -123,7 +123,7 @@ LL + println!("Got a reference to {}", r); | error: this match could be written as a `let` statement - --> $DIR/match_single_binding.rs:91:5 + --> $DIR/match_single_binding.rs:92:5 | LL | / match x { LL | | ref mut mr => println!("Got a mutable reference to {}", mr), @@ -137,7 +137,7 @@ LL + println!("Got a mutable reference to {}", mr); | error: this match could be written as a `let` statement - --> $DIR/match_single_binding.rs:95:5 + --> $DIR/match_single_binding.rs:96:5 | LL | / let product = match coords() { LL | | Point { x, y } => x * y, @@ -151,7 +151,7 @@ LL + let product = x * y; | error: this match could be written as a `let` statement - --> $DIR/match_single_binding.rs:103:18 + --> $DIR/match_single_binding.rs:104:18 | LL | .map(|i| match i.unwrap() { | __________________^ @@ -168,7 +168,7 @@ LL ~ }) | error: this match could be replaced by its body itself - --> $DIR/match_single_binding.rs:129:5 + --> $DIR/match_single_binding.rs:130:5 | LL | / match x { LL | | // => @@ -177,7 +177,7 @@ LL | | } | |_____^ help: consider using the match body instead: `println!("Not an array index start")` error: this assignment could be simplified - --> $DIR/match_single_binding.rs:138:5 + --> $DIR/match_single_binding.rs:139:5 | LL | / val = match val.split_at(idx) { LL | | (pre, suf) => { @@ -197,7 +197,7 @@ LL ~ }; | error: this match could be replaced by its scrutinee and body - --> $DIR/match_single_binding.rs:151:16 + --> $DIR/match_single_binding.rs:152:16 | LL | let _ = || match side_effects() { | ________________^ @@ -214,7 +214,7 @@ LL ~ }; | error: this match could be written as a `let` statement - --> $DIR/match_single_binding.rs:157:5 + --> $DIR/match_single_binding.rs:158:5 | LL | / match r { LL | | x => match x { @@ -239,7 +239,7 @@ LL ~ }; | error: this match could be replaced by its body itself - --> $DIR/match_single_binding.rs:170:5 + --> $DIR/match_single_binding.rs:171:5 | LL | / match 1 { LL | | _ => (), @@ -247,7 +247,7 @@ LL | | } | |_____^ help: consider using the match body instead: `();` error: this match could be replaced by its body itself - --> $DIR/match_single_binding.rs:174:13 + --> $DIR/match_single_binding.rs:175:13 | LL | let a = match 1 { | _____________^ @@ -256,7 +256,7 @@ LL | | }; | |_____^ help: consider using the match body instead: `()` error: this match could be replaced by its body itself - --> $DIR/match_single_binding.rs:178:5 + --> $DIR/match_single_binding.rs:179:5 | LL | / match 1 { LL | | _ => side_effects(), @@ -264,7 +264,7 @@ LL | | } | |_____^ help: consider using the match body instead: `side_effects();` error: this match could be replaced by its body itself - --> $DIR/match_single_binding.rs:182:13 + --> $DIR/match_single_binding.rs:183:13 | LL | let b = match 1 { | _____________^ @@ -273,7 +273,7 @@ LL | | }; | |_____^ help: consider using the match body instead: `side_effects()` error: this match could be replaced by its body itself - --> $DIR/match_single_binding.rs:186:5 + --> $DIR/match_single_binding.rs:187:5 | LL | / match 1 { LL | | _ => println!("1"), @@ -281,7 +281,7 @@ LL | | } | |_____^ help: consider using the match body instead: `println!("1");` error: this match could be replaced by its body itself - --> $DIR/match_single_binding.rs:190:13 + --> $DIR/match_single_binding.rs:191:13 | LL | let c = match 1 { | _____________^ @@ -290,7 +290,7 @@ LL | | }; | |_____^ help: consider using the match body instead: `println!("1")` error: this match could be replaced by its body itself - --> $DIR/match_single_binding.rs:195:9 + --> $DIR/match_single_binding.rs:196:9 | LL | / match 1 { LL | | _ => (), @@ -298,7 +298,7 @@ LL | | }, | |_________^ help: consider using the match body instead: `()` error: this match could be replaced by its body itself - --> $DIR/match_single_binding.rs:198:9 + --> $DIR/match_single_binding.rs:199:9 | LL | / match 1 { LL | | _ => side_effects(), @@ -306,7 +306,7 @@ LL | | }, | |_________^ help: consider using the match body instead: `side_effects()` error: this match could be replaced by its body itself - --> $DIR/match_single_binding.rs:201:9 + --> $DIR/match_single_binding.rs:202:9 | LL | / match 1 { LL | | _ => println!("1"), diff --git a/tests/ui/mem_forget.rs b/tests/ui/mem_forget.rs index edb9d87d032e..b6c8d9e53d80 100644 --- a/tests/ui/mem_forget.rs +++ b/tests/ui/mem_forget.rs @@ -19,5 +19,8 @@ fn main() { let eight: Vec = vec![8]; forgetSomething(eight); + let string = String::new(); + std::mem::forget(string); + std::mem::forget(7); } diff --git a/tests/ui/mem_forget.stderr b/tests/ui/mem_forget.stderr index a90d8b1655dc..8004b2aa8db7 100644 --- a/tests/ui/mem_forget.stderr +++ b/tests/ui/mem_forget.stderr @@ -4,6 +4,7 @@ error: usage of `mem::forget` on `Drop` type LL | memstuff::forget(six); | ^^^^^^^^^^^^^^^^^^^^^ | + = note: argument has type `std::sync::Arc` = note: `-D clippy::mem-forget` implied by `-D warnings` error: usage of `mem::forget` on `Drop` type @@ -11,12 +12,24 @@ error: usage of `mem::forget` on `Drop` type | LL | std::mem::forget(seven); | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: argument has type `std::rc::Rc` error: usage of `mem::forget` on `Drop` type --> $DIR/mem_forget.rs:20:5 | LL | forgetSomething(eight); | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: argument has type `std::vec::Vec` -error: aborting due to 3 previous errors +error: usage of `mem::forget` on type with `Drop` fields + --> $DIR/mem_forget.rs:23:5 + | +LL | std::mem::forget(string); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: argument has type `std::string::String` + +error: aborting due to 4 previous errors diff --git a/tests/ui/mem_replace_macro.rs b/tests/ui/mem_replace_macro.rs index 132873858b7c..e53342f2ed36 100644 --- a/tests/ui/mem_replace_macro.rs +++ b/tests/ui/mem_replace_macro.rs @@ -1,4 +1,4 @@ -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![warn(clippy::mem_replace_with_default)] extern crate proc_macros; diff --git a/tests/ui/methods.rs b/tests/ui/methods.rs index e0e2cac30a28..589eab5cdfc5 100644 --- a/tests/ui/methods.rs +++ b/tests/ui/methods.rs @@ -18,6 +18,7 @@ clippy::wrong_self_convention, clippy::unused_async, clippy::unused_self, + clippy::useless_vec, unused )] diff --git a/tests/ui/methods.stderr b/tests/ui/methods.stderr index 4643e09e2702..73ec48643e06 100644 --- a/tests/ui/methods.stderr +++ b/tests/ui/methods.stderr @@ -1,5 +1,5 @@ error: methods called `new` usually return `Self` - --> $DIR/methods.rs:105:5 + --> $DIR/methods.rs:106:5 | LL | / fn new() -> i32 { LL | | 0 @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::new-ret-no-self` implied by `-D warnings` error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead - --> $DIR/methods.rs:126:13 + --> $DIR/methods.rs:127:13 | LL | let _ = v.iter().filter(|&x| { | _____________^ diff --git a/tests/ui/methods_fixable.fixed b/tests/ui/methods_fixable.fixed index dcbed5a4d997..ce5d19a8b6e8 100644 --- a/tests/ui/methods_fixable.fixed +++ b/tests/ui/methods_fixable.fixed @@ -1,6 +1,7 @@ //@run-rustfix #![warn(clippy::filter_next)] +#![allow(clippy::useless_vec)] /// Checks implementation of `FILTER_NEXT` lint. fn main() { diff --git a/tests/ui/methods_fixable.rs b/tests/ui/methods_fixable.rs index 3a976d235276..0615817ec925 100644 --- a/tests/ui/methods_fixable.rs +++ b/tests/ui/methods_fixable.rs @@ -1,6 +1,7 @@ //@run-rustfix #![warn(clippy::filter_next)] +#![allow(clippy::useless_vec)] /// Checks implementation of `FILTER_NEXT` lint. fn main() { diff --git a/tests/ui/methods_fixable.stderr b/tests/ui/methods_fixable.stderr index 852f48e32d67..187714c75fb9 100644 --- a/tests/ui/methods_fixable.stderr +++ b/tests/ui/methods_fixable.stderr @@ -1,5 +1,5 @@ error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead - --> $DIR/methods_fixable.rs:10:13 + --> $DIR/methods_fixable.rs:11:13 | LL | let _ = v.iter().filter(|&x| *x < 0).next(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `v.iter().find(|&x| *x < 0)` diff --git a/tests/ui/min_ident_chars.rs b/tests/ui/min_ident_chars.rs new file mode 100644 index 000000000000..b5b9e66aa7a0 --- /dev/null +++ b/tests/ui/min_ident_chars.rs @@ -0,0 +1,84 @@ +//@aux-build:proc_macros.rs:proc-macro +#![allow(irrefutable_let_patterns, nonstandard_style, unused)] +#![warn(clippy::min_ident_chars)] + +extern crate proc_macros; +use proc_macros::external; +use proc_macros::with_span; + +struct A { + a: u32, + i: u32, + A: u32, + I: u32, +} + +struct B(u32); + +struct O { + o: u32, +} + +struct i; + +enum C { + D, + E, + F, + j, +} + +struct Vec4 { + x: u32, + y: u32, + z: u32, + w: u32, +} + +struct AA(T, E); + +fn main() { + // Allowed idents + let w = 1; + // Ok, not this one + // let i = 1; + let j = 1; + let n = 1; + let z = 1; + let y = 1; + let z = 1; + // Implicitly disallowed idents + let h = 1; + let e = 2; + let l = 3; + let l = 4; + let o = 6; + // 2 len does not lint + let hi = 0; + // Lint + let (h, o, w) = (1, 2, 3); + for (a, (r, e)) in (0..1000).enumerate().enumerate() {} + let you = Vec4 { x: 1, y: 2, z: 3, w: 4 }; + while let (d, o, _i, n, g) = (true, true, false, false, true) {} + let today = true; + // Ideally this wouldn't lint, but this would (likely) require global analysis, outta scope + // of this lint regardless + let o = 1; + let o = O { o }; + + for j in 0..1000 {} + for _ in 0..10 {} + + // Do not lint code from external macros + external! { for j in 0..1000 {} } + // Do not lint code from procedural macros + with_span! { + span + for j in 0..1000 {} + } +} + +fn b() {} +fn wrong_pythagoras(a: f32, b: f32) -> f32 { + a * a + a * b +} diff --git a/tests/ui/min_ident_chars.stderr b/tests/ui/min_ident_chars.stderr new file mode 100644 index 000000000000..66a63f657565 --- /dev/null +++ b/tests/ui/min_ident_chars.stderr @@ -0,0 +1,178 @@ +error: this ident consists of a single char + --> $DIR/min_ident_chars.rs:9:8 + | +LL | struct A { + | ^ + | + = note: `-D clippy::min-ident-chars` implied by `-D warnings` + +error: this ident consists of a single char + --> $DIR/min_ident_chars.rs:10:5 + | +LL | a: u32, + | ^ + +error: this ident consists of a single char + --> $DIR/min_ident_chars.rs:12:5 + | +LL | A: u32, + | ^ + +error: this ident consists of a single char + --> $DIR/min_ident_chars.rs:13:5 + | +LL | I: u32, + | ^ + +error: this ident consists of a single char + --> $DIR/min_ident_chars.rs:16:8 + | +LL | struct B(u32); + | ^ + +error: this ident consists of a single char + --> $DIR/min_ident_chars.rs:18:8 + | +LL | struct O { + | ^ + +error: this ident consists of a single char + --> $DIR/min_ident_chars.rs:19:5 + | +LL | o: u32, + | ^ + +error: this ident consists of a single char + --> $DIR/min_ident_chars.rs:24:6 + | +LL | enum C { + | ^ + +error: this ident consists of a single char + --> $DIR/min_ident_chars.rs:25:5 + | +LL | D, + | ^ + +error: this ident consists of a single char + --> $DIR/min_ident_chars.rs:26:5 + | +LL | E, + | ^ + +error: this ident consists of a single char + --> $DIR/min_ident_chars.rs:27:5 + | +LL | F, + | ^ + +error: this ident consists of a single char + --> $DIR/min_ident_chars.rs:51:9 + | +LL | let h = 1; + | ^ + +error: this ident consists of a single char + --> $DIR/min_ident_chars.rs:52:9 + | +LL | let e = 2; + | ^ + +error: this ident consists of a single char + --> $DIR/min_ident_chars.rs:53:9 + | +LL | let l = 3; + | ^ + +error: this ident consists of a single char + --> $DIR/min_ident_chars.rs:54:9 + | +LL | let l = 4; + | ^ + +error: this ident consists of a single char + --> $DIR/min_ident_chars.rs:55:9 + | +LL | let o = 6; + | ^ + +error: this ident consists of a single char + --> $DIR/min_ident_chars.rs:59:10 + | +LL | let (h, o, w) = (1, 2, 3); + | ^ + +error: this ident consists of a single char + --> $DIR/min_ident_chars.rs:59:13 + | +LL | let (h, o, w) = (1, 2, 3); + | ^ + +error: this ident consists of a single char + --> $DIR/min_ident_chars.rs:60:10 + | +LL | for (a, (r, e)) in (0..1000).enumerate().enumerate() {} + | ^ + +error: this ident consists of a single char + --> $DIR/min_ident_chars.rs:60:14 + | +LL | for (a, (r, e)) in (0..1000).enumerate().enumerate() {} + | ^ + +error: this ident consists of a single char + --> $DIR/min_ident_chars.rs:60:17 + | +LL | for (a, (r, e)) in (0..1000).enumerate().enumerate() {} + | ^ + +error: this ident consists of a single char + --> $DIR/min_ident_chars.rs:62:16 + | +LL | while let (d, o, _i, n, g) = (true, true, false, false, true) {} + | ^ + +error: this ident consists of a single char + --> $DIR/min_ident_chars.rs:62:19 + | +LL | while let (d, o, _i, n, g) = (true, true, false, false, true) {} + | ^ + +error: this ident consists of a single char + --> $DIR/min_ident_chars.rs:62:29 + | +LL | while let (d, o, _i, n, g) = (true, true, false, false, true) {} + | ^ + +error: this ident consists of a single char + --> $DIR/min_ident_chars.rs:66:9 + | +LL | let o = 1; + | ^ + +error: this ident consists of a single char + --> $DIR/min_ident_chars.rs:67:9 + | +LL | let o = O { o }; + | ^ + +error: this ident consists of a single char + --> $DIR/min_ident_chars.rs:81:4 + | +LL | fn b() {} + | ^ + +error: this ident consists of a single char + --> $DIR/min_ident_chars.rs:82:21 + | +LL | fn wrong_pythagoras(a: f32, b: f32) -> f32 { + | ^ + +error: this ident consists of a single char + --> $DIR/min_ident_chars.rs:82:29 + | +LL | fn wrong_pythagoras(a: f32, b: f32) -> f32 { + | ^ + +error: aborting due to 29 previous errors + diff --git a/tests/ui/missing_assert_message.rs b/tests/ui/missing_assert_message.rs index 89404ca88271..af1358f61b5c 100644 --- a/tests/ui/missing_assert_message.rs +++ b/tests/ui/missing_assert_message.rs @@ -7,8 +7,6 @@ macro_rules! bar { }; } -fn main() {} - // Should trigger warning fn asserts_without_message() { assert!(foo()); @@ -66,9 +64,14 @@ fn asserts_without_message_but_inside_a_test_function() { debug_assert_ne!(foo(), foo()); } +fn foo() -> bool { + true +} + // Should not trigger warning #[cfg(test)] mod tests { + use super::foo; fn asserts_without_message_but_inside_a_test_module() { assert!(foo()); assert_eq!(foo(), foo()); @@ -78,7 +81,3 @@ mod tests { debug_assert_ne!(foo(), foo()); } } - -fn foo() -> bool { - true -} diff --git a/tests/ui/missing_assert_message.stderr b/tests/ui/missing_assert_message.stderr index ecd038012779..33a5c1f8e052 100644 --- a/tests/ui/missing_assert_message.stderr +++ b/tests/ui/missing_assert_message.stderr @@ -1,5 +1,5 @@ error: assert without any message - --> $DIR/missing_assert_message.rs:14:5 + --> $DIR/missing_assert_message.rs:12:5 | LL | assert!(foo()); | ^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | assert!(foo()); = note: `-D clippy::missing-assert-message` implied by `-D warnings` error: assert without any message - --> $DIR/missing_assert_message.rs:15:5 + --> $DIR/missing_assert_message.rs:13:5 | LL | assert_eq!(foo(), foo()); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | assert_eq!(foo(), foo()); = help: consider describing why the failing assert is problematic error: assert without any message - --> $DIR/missing_assert_message.rs:16:5 + --> $DIR/missing_assert_message.rs:14:5 | LL | assert_ne!(foo(), foo()); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | assert_ne!(foo(), foo()); = help: consider describing why the failing assert is problematic error: assert without any message - --> $DIR/missing_assert_message.rs:17:5 + --> $DIR/missing_assert_message.rs:15:5 | LL | debug_assert!(foo()); | ^^^^^^^^^^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | debug_assert!(foo()); = help: consider describing why the failing assert is problematic error: assert without any message - --> $DIR/missing_assert_message.rs:18:5 + --> $DIR/missing_assert_message.rs:16:5 | LL | debug_assert_eq!(foo(), foo()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | debug_assert_eq!(foo(), foo()); = help: consider describing why the failing assert is problematic error: assert without any message - --> $DIR/missing_assert_message.rs:19:5 + --> $DIR/missing_assert_message.rs:17:5 | LL | debug_assert_ne!(foo(), foo()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL | debug_assert_ne!(foo(), foo()); = help: consider describing why the failing assert is problematic error: assert without any message - --> $DIR/missing_assert_message.rs:24:5 + --> $DIR/missing_assert_message.rs:22:5 | LL | assert!(bar!(true)); | ^^^^^^^^^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | assert!(bar!(true)); = help: consider describing why the failing assert is problematic error: assert without any message - --> $DIR/missing_assert_message.rs:25:5 + --> $DIR/missing_assert_message.rs:23:5 | LL | assert!(bar!(true, false)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | assert!(bar!(true, false)); = help: consider describing why the failing assert is problematic error: assert without any message - --> $DIR/missing_assert_message.rs:26:5 + --> $DIR/missing_assert_message.rs:24:5 | LL | assert_eq!(bar!(true), foo()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | assert_eq!(bar!(true), foo()); = help: consider describing why the failing assert is problematic error: assert without any message - --> $DIR/missing_assert_message.rs:27:5 + --> $DIR/missing_assert_message.rs:25:5 | LL | assert_ne!(bar!(true, true), bar!(true)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -80,7 +80,7 @@ LL | assert_ne!(bar!(true, true), bar!(true)); = help: consider describing why the failing assert is problematic error: assert without any message - --> $DIR/missing_assert_message.rs:32:5 + --> $DIR/missing_assert_message.rs:30:5 | LL | assert!(foo(),); | ^^^^^^^^^^^^^^^ @@ -88,7 +88,7 @@ LL | assert!(foo(),); = help: consider describing why the failing assert is problematic error: assert without any message - --> $DIR/missing_assert_message.rs:33:5 + --> $DIR/missing_assert_message.rs:31:5 | LL | assert_eq!(foo(), foo(),); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -96,7 +96,7 @@ LL | assert_eq!(foo(), foo(),); = help: consider describing why the failing assert is problematic error: assert without any message - --> $DIR/missing_assert_message.rs:34:5 + --> $DIR/missing_assert_message.rs:32:5 | LL | assert_ne!(foo(), foo(),); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -104,7 +104,7 @@ LL | assert_ne!(foo(), foo(),); = help: consider describing why the failing assert is problematic error: assert without any message - --> $DIR/missing_assert_message.rs:35:5 + --> $DIR/missing_assert_message.rs:33:5 | LL | debug_assert!(foo(),); | ^^^^^^^^^^^^^^^^^^^^^ @@ -112,7 +112,7 @@ LL | debug_assert!(foo(),); = help: consider describing why the failing assert is problematic error: assert without any message - --> $DIR/missing_assert_message.rs:36:5 + --> $DIR/missing_assert_message.rs:34:5 | LL | debug_assert_eq!(foo(), foo(),); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -120,7 +120,7 @@ LL | debug_assert_eq!(foo(), foo(),); = help: consider describing why the failing assert is problematic error: assert without any message - --> $DIR/missing_assert_message.rs:37:5 + --> $DIR/missing_assert_message.rs:35:5 | LL | debug_assert_ne!(foo(), foo(),); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/missing_const_for_fn/cant_be_const.rs b/tests/ui/missing_const_for_fn/cant_be_const.rs index 5db73a7b8ead..06e053524798 100644 --- a/tests/ui/missing_const_for_fn/cant_be_const.rs +++ b/tests/ui/missing_const_for_fn/cant_be_const.rs @@ -3,7 +3,7 @@ //! The .stderr output of this test should be empty. Otherwise it's a bug somewhere. //@aux-build:helper.rs -//@aux-build:../../auxiliary/proc_macros.rs +//@aux-build:../auxiliary/proc_macros.rs:proc-macro #![warn(clippy::missing_const_for_fn)] #![feature(start)] @@ -13,7 +13,7 @@ extern crate proc_macros; use proc_macros::with_span; -struct Game; +struct Game; // You just lost. // This should not be linted because it's already const const fn already_const() -> i32 { @@ -44,7 +44,6 @@ static Y: u32 = 0; // refer to a static variable fn get_y() -> u32 { Y - //~^ ERROR E0013 } // Don't lint entrypoint functions @@ -126,3 +125,43 @@ with_span! { span fn dont_check_in_proc_macro() {} } + +// Do not lint `String` has `Vec`, which cannot be dropped in const contexts +fn a(this: String) {} + +enum A { + F(String), + N, +} + +// Same here. +fn b(this: A) {} + +// Minimized version of `a`. +fn c(this: Vec) {} + +struct F(A); + +// Do not lint +fn f(this: F) {} + +// Do not lint +fn g(this: T) {} + +struct Issue10617(String); + +impl Issue10617 { + // Do not lint + pub fn name(self) -> String { + self.0 + } +} + +union U { + f: u32, +} + +// Do not lint because accessing union fields from const functions is unstable +fn h(u: U) -> u32 { + unsafe { u.f } +} diff --git a/tests/ui/missing_const_for_fn/could_be_const.rs b/tests/ui/missing_const_for_fn/could_be_const.rs index 0246c8622ed3..b1980b1b523f 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.rs +++ b/tests/ui/missing_const_for_fn/could_be_const.rs @@ -1,5 +1,7 @@ #![warn(clippy::missing_const_for_fn)] #![allow(incomplete_features, clippy::let_and_return)] +#![feature(const_mut_refs)] +#![feature(const_trait_impl)] use std::mem::transmute; @@ -87,3 +89,14 @@ fn msrv_1_46() -> i32 { // Should not be const fn main() {} + +struct D; + +impl const Drop for D { + fn drop(&mut self) { + todo!(); + } +} + +// Lint this, since it can be dropped in const contexts +fn d(this: D) {} diff --git a/tests/ui/missing_const_for_fn/could_be_const.stderr b/tests/ui/missing_const_for_fn/could_be_const.stderr index 955e1ed26340..7be2cc0ca930 100644 --- a/tests/ui/missing_const_for_fn/could_be_const.stderr +++ b/tests/ui/missing_const_for_fn/could_be_const.stderr @@ -1,5 +1,5 @@ error: this could be a `const fn` - --> $DIR/could_be_const.rs:12:5 + --> $DIR/could_be_const.rs:14:5 | LL | / pub fn new() -> Self { LL | | Self { guess: 42 } @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::missing-const-for-fn` implied by `-D warnings` error: this could be a `const fn` - --> $DIR/could_be_const.rs:16:5 + --> $DIR/could_be_const.rs:18:5 | LL | / fn const_generic_params<'a, T, const N: usize>(&self, b: &'a [T; N]) -> &'a [T; N] { LL | | b @@ -17,7 +17,7 @@ LL | | } | |_____^ error: this could be a `const fn` - --> $DIR/could_be_const.rs:22:1 + --> $DIR/could_be_const.rs:24:1 | LL | / fn one() -> i32 { LL | | 1 @@ -25,7 +25,7 @@ LL | | } | |_^ error: this could be a `const fn` - --> $DIR/could_be_const.rs:27:1 + --> $DIR/could_be_const.rs:29:1 | LL | / fn two() -> i32 { LL | | let abc = 2; @@ -34,7 +34,7 @@ LL | | } | |_^ error: this could be a `const fn` - --> $DIR/could_be_const.rs:33:1 + --> $DIR/could_be_const.rs:35:1 | LL | / fn string() -> String { LL | | String::new() @@ -42,7 +42,7 @@ LL | | } | |_^ error: this could be a `const fn` - --> $DIR/could_be_const.rs:38:1 + --> $DIR/could_be_const.rs:40:1 | LL | / unsafe fn four() -> i32 { LL | | 4 @@ -50,7 +50,7 @@ LL | | } | |_^ error: this could be a `const fn` - --> $DIR/could_be_const.rs:43:1 + --> $DIR/could_be_const.rs:45:1 | LL | / fn generic(t: T) -> T { LL | | t @@ -58,7 +58,7 @@ LL | | } | |_^ error: this could be a `const fn` - --> $DIR/could_be_const.rs:51:1 + --> $DIR/could_be_const.rs:53:1 | LL | / fn generic_arr(t: [T; 1]) -> T { LL | | t[0] @@ -66,7 +66,7 @@ LL | | } | |_^ error: this could be a `const fn` - --> $DIR/could_be_const.rs:64:9 + --> $DIR/could_be_const.rs:66:9 | LL | / pub fn b(self, a: &A) -> B { LL | | B @@ -74,7 +74,7 @@ LL | | } | |_________^ error: this could be a `const fn` - --> $DIR/could_be_const.rs:73:5 + --> $DIR/could_be_const.rs:75:5 | LL | / fn const_fn_stabilized_before_msrv(byte: u8) { LL | | byte.is_ascii_digit(); @@ -82,12 +82,18 @@ LL | | } | |_____^ error: this could be a `const fn` - --> $DIR/could_be_const.rs:84:1 + --> $DIR/could_be_const.rs:86:1 | LL | / fn msrv_1_46() -> i32 { LL | | 46 LL | | } | |_^ -error: aborting due to 11 previous errors +error: this could be a `const fn` + --> $DIR/could_be_const.rs:102:1 + | +LL | fn d(this: D) {} + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 12 previous errors diff --git a/tests/ui/missing_doc.rs b/tests/ui/missing_doc.rs index bf587e774f74..cff1706a8426 100644 --- a/tests/ui/missing_doc.rs +++ b/tests/ui/missing_doc.rs @@ -1,5 +1,5 @@ //@needs-asm-support -//@aux-build: proc_macros.rs +//@aux-build: proc_macros.rs:proc-macro #![warn(clippy::missing_docs_in_private_items)] // When denying at the crate level, be sure to not get random warnings from the diff --git a/tests/ui/missing_doc_impl.rs b/tests/ui/missing_doc_impl.rs index 520ddbe16b82..2d45132f968e 100644 --- a/tests/ui/missing_doc_impl.rs +++ b/tests/ui/missing_doc_impl.rs @@ -1,4 +1,4 @@ -//@aux-build: proc_macros.rs +//@aux-build: proc_macros.rs:proc-macro #![warn(clippy::missing_docs_in_private_items)] #![allow(dead_code)] diff --git a/tests/ui/missing_inline_proc_macro.rs b/tests/ui/missing_inline_proc_macro.rs index 3c68fb905f12..e47a198c6aea 100644 --- a/tests/ui/missing_inline_proc_macro.rs +++ b/tests/ui/missing_inline_proc_macro.rs @@ -1,5 +1,4 @@ #![warn(clippy::missing_inline_in_public_items)] -#![crate_type = "proc-macro"] extern crate proc_macro; diff --git a/tests/ui/missing_panics_doc.rs b/tests/ui/missing_panics_doc.rs index 7dc44529206d..0e1533fc1ab1 100644 --- a/tests/ui/missing_panics_doc.rs +++ b/tests/ui/missing_panics_doc.rs @@ -1,5 +1,12 @@ +//@aux-build:macro_rules.rs #![warn(clippy::missing_panics_doc)] -#![allow(clippy::option_map_unit_fn)] +#![allow(clippy::option_map_unit_fn, clippy::unnecessary_literal_unwrap)] + +#[macro_use] +extern crate macro_rules; + +use macro_rules::macro_with_panic; + fn main() {} /// This needs to be documented @@ -13,11 +20,6 @@ pub fn panic() { panic!("This function panics") } -/// This needs to be documented -pub fn todo() { - todo!() -} - /// This needs to be documented pub fn inner_body(opt: Option) { opt.map(|x| { @@ -76,15 +78,6 @@ pub fn inner_body_documented(opt: Option) { }); } -/// This is documented -/// -/// # Panics -/// -/// We still need to do this part -pub fn todo_documented() { - todo!() -} - /// This is documented /// /// # Panics @@ -114,6 +107,11 @@ pub fn assert_ne_documented() { assert_ne!(x, 0); } +/// `todo!()` is fine +pub fn todo() { + todo!() +} + /// This is okay because it is private fn unwrap_private() { let result = Err("Hi"); @@ -125,11 +123,6 @@ fn panic_private() { panic!("This function panics") } -/// This is okay because it is private -fn todo_private() { - todo!() -} - /// This is okay because it is private fn inner_body_private(opt: Option) { opt.map(|x| { @@ -151,3 +144,50 @@ pub fn debug_assertions() { debug_assert_eq!(1, 2); debug_assert_ne!(1, 2); } + +// all function must be triggered the lint. +// `pub` is required, because the lint does not consider unreachable items +pub mod issue10240 { + pub fn option_unwrap(v: &[T]) -> &T { + let o: Option<&T> = v.last(); + o.unwrap() + } + + pub fn option_expect(v: &[T]) -> &T { + let o: Option<&T> = v.last(); + o.expect("passed an empty thing") + } + + pub fn result_unwrap(v: &[T]) -> &T { + let res: Result<&T, &str> = v.last().ok_or("oh noes"); + res.unwrap() + } + + pub fn result_expect(v: &[T]) -> &T { + let res: Result<&T, &str> = v.last().ok_or("oh noes"); + res.expect("passed an empty thing") + } + + pub fn last_unwrap(v: &[u32]) -> u32 { + *v.last().unwrap() + } + + pub fn last_expect(v: &[u32]) -> u32 { + *v.last().expect("passed an empty thing") + } +} + +fn from_external_macro_should_not_lint() { + macro_with_panic!() +} + +macro_rules! some_macro_that_panics { + () => { + panic!() + }; +} + +fn from_declared_macro_should_lint_at_macrosite() { + // Not here. + some_macro_that_panics!() +} diff --git a/tests/ui/missing_panics_doc.stderr b/tests/ui/missing_panics_doc.stderr index 183c262ce0b5..3dbe2dfbd88f 100644 --- a/tests/ui/missing_panics_doc.stderr +++ b/tests/ui/missing_panics_doc.stderr @@ -1,87 +1,147 @@ error: docs for function which may panic missing `# Panics` section - --> $DIR/missing_panics_doc.rs:6:1 + --> $DIR/missing_panics_doc.rs:13:1 | LL | pub fn unwrap() { | ^^^^^^^^^^^^^^^ | note: first possible panic found here - --> $DIR/missing_panics_doc.rs:8:5 + --> $DIR/missing_panics_doc.rs:15:5 | LL | result.unwrap() | ^^^^^^^^^^^^^^^ = note: `-D clippy::missing-panics-doc` implied by `-D warnings` error: docs for function which may panic missing `# Panics` section - --> $DIR/missing_panics_doc.rs:12:1 + --> $DIR/missing_panics_doc.rs:19:1 | LL | pub fn panic() { | ^^^^^^^^^^^^^^ | note: first possible panic found here - --> $DIR/missing_panics_doc.rs:13:5 + --> $DIR/missing_panics_doc.rs:20:5 | LL | panic!("This function panics") | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: docs for function which may panic missing `# Panics` section - --> $DIR/missing_panics_doc.rs:17:1 - | -LL | pub fn todo() { - | ^^^^^^^^^^^^^ - | -note: first possible panic found here - --> $DIR/missing_panics_doc.rs:18:5 - | -LL | todo!() - | ^^^^^^^ - -error: docs for function which may panic missing `# Panics` section - --> $DIR/missing_panics_doc.rs:22:1 + --> $DIR/missing_panics_doc.rs:24:1 | LL | pub fn inner_body(opt: Option) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: first possible panic found here - --> $DIR/missing_panics_doc.rs:25:13 + --> $DIR/missing_panics_doc.rs:27:13 | LL | panic!() | ^^^^^^^^ error: docs for function which may panic missing `# Panics` section - --> $DIR/missing_panics_doc.rs:31:1 + --> $DIR/missing_panics_doc.rs:33:1 | LL | pub fn unreachable_and_panic() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: first possible panic found here - --> $DIR/missing_panics_doc.rs:32:39 + --> $DIR/missing_panics_doc.rs:34:39 | LL | if true { unreachable!() } else { panic!() } | ^^^^^^^^ error: docs for function which may panic missing `# Panics` section - --> $DIR/missing_panics_doc.rs:36:1 + --> $DIR/missing_panics_doc.rs:38:1 | LL | pub fn assert_eq() { | ^^^^^^^^^^^^^^^^^^ | note: first possible panic found here - --> $DIR/missing_panics_doc.rs:38:5 + --> $DIR/missing_panics_doc.rs:40:5 | LL | assert_eq!(x, 0); | ^^^^^^^^^^^^^^^^ error: docs for function which may panic missing `# Panics` section - --> $DIR/missing_panics_doc.rs:42:1 + --> $DIR/missing_panics_doc.rs:44:1 | LL | pub fn assert_ne() { | ^^^^^^^^^^^^^^^^^^ | note: first possible panic found here - --> $DIR/missing_panics_doc.rs:44:5 + --> $DIR/missing_panics_doc.rs:46:5 | LL | assert_ne!(x, 0); | ^^^^^^^^^^^^^^^^ -error: aborting due to 7 previous errors +error: docs for function which may panic missing `# Panics` section + --> $DIR/missing_panics_doc.rs:151:5 + | +LL | pub fn option_unwrap(v: &[T]) -> &T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: first possible panic found here + --> $DIR/missing_panics_doc.rs:153:9 + | +LL | o.unwrap() + | ^^^^^^^^^^ + +error: docs for function which may panic missing `# Panics` section + --> $DIR/missing_panics_doc.rs:156:5 + | +LL | pub fn option_expect(v: &[T]) -> &T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: first possible panic found here + --> $DIR/missing_panics_doc.rs:158:9 + | +LL | o.expect("passed an empty thing") + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: docs for function which may panic missing `# Panics` section + --> $DIR/missing_panics_doc.rs:161:5 + | +LL | pub fn result_unwrap(v: &[T]) -> &T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: first possible panic found here + --> $DIR/missing_panics_doc.rs:163:9 + | +LL | res.unwrap() + | ^^^^^^^^^^^^ + +error: docs for function which may panic missing `# Panics` section + --> $DIR/missing_panics_doc.rs:166:5 + | +LL | pub fn result_expect(v: &[T]) -> &T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: first possible panic found here + --> $DIR/missing_panics_doc.rs:168:9 + | +LL | res.expect("passed an empty thing") + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: docs for function which may panic missing `# Panics` section + --> $DIR/missing_panics_doc.rs:171:5 + | +LL | pub fn last_unwrap(v: &[u32]) -> u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: first possible panic found here + --> $DIR/missing_panics_doc.rs:172:10 + | +LL | *v.last().unwrap() + | ^^^^^^^^^^^^^^^^^ + +error: docs for function which may panic missing `# Panics` section + --> $DIR/missing_panics_doc.rs:175:5 + | +LL | pub fn last_expect(v: &[u32]) -> u32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: first possible panic found here + --> $DIR/missing_panics_doc.rs:176:10 + | +LL | *v.last().expect("passed an empty thing") + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 12 previous errors diff --git a/tests/ui/mistyped_literal_suffix.fixed b/tests/ui/mistyped_literal_suffix.fixed index 62cfeafdc49f..9c2ffcb02ea1 100644 --- a/tests/ui/mistyped_literal_suffix.fixed +++ b/tests/ui/mistyped_literal_suffix.fixed @@ -1,5 +1,5 @@ //@run-rustfix -//@aux-build: proc_macros.rs +//@aux-build: proc_macros.rs:proc-macro #![allow( dead_code, diff --git a/tests/ui/mistyped_literal_suffix.rs b/tests/ui/mistyped_literal_suffix.rs index f83b7c3dbda5..a0a1e96a775d 100644 --- a/tests/ui/mistyped_literal_suffix.rs +++ b/tests/ui/mistyped_literal_suffix.rs @@ -1,5 +1,5 @@ //@run-rustfix -//@aux-build: proc_macros.rs +//@aux-build: proc_macros.rs:proc-macro #![allow( dead_code, diff --git a/tests/ui/module_inception.rs b/tests/ui/module_inception.rs index a23aba9164a5..802c3ec39b64 100644 --- a/tests/ui/module_inception.rs +++ b/tests/ui/module_inception.rs @@ -1,5 +1,17 @@ #![warn(clippy::module_inception)] +pub mod foo2 { + pub mod bar2 { + pub mod bar2 { + pub mod foo2 {} + } + pub mod foo2 {} + } + pub mod foo2 { + pub mod bar2 {} + } +} + mod foo { mod bar { mod bar { diff --git a/tests/ui/module_inception.stderr b/tests/ui/module_inception.stderr index 77564dce9eb4..ebb8e296f464 100644 --- a/tests/ui/module_inception.stderr +++ b/tests/ui/module_inception.stderr @@ -1,8 +1,8 @@ error: module has the same name as its containing module --> $DIR/module_inception.rs:5:9 | -LL | / mod bar { -LL | | mod foo {} +LL | / pub mod bar2 { +LL | | pub mod foo2 {} LL | | } | |_________^ | @@ -11,10 +11,26 @@ LL | | } error: module has the same name as its containing module --> $DIR/module_inception.rs:10:5 | +LL | / pub mod foo2 { +LL | | pub mod bar2 {} +LL | | } + | |_____^ + +error: module has the same name as its containing module + --> $DIR/module_inception.rs:17:9 + | +LL | / mod bar { +LL | | mod foo {} +LL | | } + | |_________^ + +error: module has the same name as its containing module + --> $DIR/module_inception.rs:22:5 + | LL | / mod foo { LL | | mod bar {} LL | | } | |_____^ -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors diff --git a/tests/ui/multiple_unsafe_ops_per_block.rs b/tests/ui/multiple_unsafe_ops_per_block.rs index 4ef6f0ca92f2..23ad36bb4730 100644 --- a/tests/ui/multiple_unsafe_ops_per_block.rs +++ b/tests/ui/multiple_unsafe_ops_per_block.rs @@ -1,4 +1,4 @@ -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![allow(unused)] #![allow(deref_nullptr)] #![allow(clippy::unnecessary_operation)] diff --git a/tests/ui/must_use_unit.fixed b/tests/ui/must_use_unit.fixed index 4f7cf4e56d15..c460fd7c6b0d 100644 --- a/tests/ui/must_use_unit.fixed +++ b/tests/ui/must_use_unit.fixed @@ -1,5 +1,5 @@ //@run-rustfix -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![warn(clippy::must_use_unit)] #![allow(clippy::unused_unit)] diff --git a/tests/ui/must_use_unit.rs b/tests/ui/must_use_unit.rs index 3a814ce16859..fe95624f7996 100644 --- a/tests/ui/must_use_unit.rs +++ b/tests/ui/must_use_unit.rs @@ -1,5 +1,5 @@ //@run-rustfix -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![warn(clippy::must_use_unit)] #![allow(clippy::unused_unit)] diff --git a/tests/ui/mut_mut.rs b/tests/ui/mut_mut.rs index d838098de113..b72134283677 100644 --- a/tests/ui/mut_mut.rs +++ b/tests/ui/mut_mut.rs @@ -1,4 +1,4 @@ -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![warn(clippy::mut_mut)] #![allow(unused)] #![allow(clippy::no_effect, clippy::uninlined_format_args, clippy::unnecessary_operation)] diff --git a/tests/ui/needless_arbitrary_self_type_unfixable.rs b/tests/ui/needless_arbitrary_self_type_unfixable.rs index 00871f9f450c..876f16a3854d 100644 --- a/tests/ui/needless_arbitrary_self_type_unfixable.rs +++ b/tests/ui/needless_arbitrary_self_type_unfixable.rs @@ -1,4 +1,4 @@ -//@aux-build:proc_macro_attr.rs +//@aux-build:proc_macro_attr.rs:proc-macro #![warn(clippy::needless_arbitrary_self_type)] diff --git a/tests/ui/needless_bool/fixable.fixed b/tests/ui/needless_bool/fixable.fixed index bf1911881c8a..7d0e556528fa 100644 --- a/tests/ui/needless_bool/fixable.fixed +++ b/tests/ui/needless_bool/fixable.fixed @@ -7,6 +7,7 @@ clippy::no_effect, clippy::if_same_then_else, clippy::equatable_if_let, + clippy::needless_if, clippy::needless_return, clippy::self_named_constructors )] diff --git a/tests/ui/needless_bool/fixable.rs b/tests/ui/needless_bool/fixable.rs index a6c465d4fbd1..88bfe8af7337 100644 --- a/tests/ui/needless_bool/fixable.rs +++ b/tests/ui/needless_bool/fixable.rs @@ -7,6 +7,7 @@ clippy::no_effect, clippy::if_same_then_else, clippy::equatable_if_let, + clippy::needless_if, clippy::needless_return, clippy::self_named_constructors )] diff --git a/tests/ui/needless_bool/fixable.stderr b/tests/ui/needless_bool/fixable.stderr index fa906374fb3b..1476aea439ff 100644 --- a/tests/ui/needless_bool/fixable.stderr +++ b/tests/ui/needless_bool/fixable.stderr @@ -1,5 +1,5 @@ error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:41:5 + --> $DIR/fixable.rs:42:5 | LL | / if x { LL | | true @@ -11,7 +11,7 @@ LL | | }; = note: `-D clippy::needless-bool` implied by `-D warnings` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:46:5 + --> $DIR/fixable.rs:47:5 | LL | / if x { LL | | false @@ -21,7 +21,7 @@ LL | | }; | |_____^ help: you can reduce it to: `!x` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:51:5 + --> $DIR/fixable.rs:52:5 | LL | / if x && y { LL | | false @@ -31,7 +31,7 @@ LL | | }; | |_____^ help: you can reduce it to: `!(x && y)` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:59:5 + --> $DIR/fixable.rs:60:5 | LL | / if a == b { LL | | false @@ -41,7 +41,7 @@ LL | | }; | |_____^ help: you can reduce it to: `a != b` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:64:5 + --> $DIR/fixable.rs:65:5 | LL | / if a != b { LL | | false @@ -51,7 +51,7 @@ LL | | }; | |_____^ help: you can reduce it to: `a == b` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:69:5 + --> $DIR/fixable.rs:70:5 | LL | / if a < b { LL | | false @@ -61,7 +61,7 @@ LL | | }; | |_____^ help: you can reduce it to: `a >= b` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:74:5 + --> $DIR/fixable.rs:75:5 | LL | / if a <= b { LL | | false @@ -71,7 +71,7 @@ LL | | }; | |_____^ help: you can reduce it to: `a > b` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:79:5 + --> $DIR/fixable.rs:80:5 | LL | / if a > b { LL | | false @@ -81,7 +81,7 @@ LL | | }; | |_____^ help: you can reduce it to: `a <= b` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:84:5 + --> $DIR/fixable.rs:85:5 | LL | / if a >= b { LL | | false @@ -91,7 +91,7 @@ LL | | }; | |_____^ help: you can reduce it to: `a < b` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:112:5 + --> $DIR/fixable.rs:113:5 | LL | / if x { LL | | return true; @@ -101,7 +101,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return x` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:120:5 + --> $DIR/fixable.rs:121:5 | LL | / if x { LL | | return false; @@ -111,7 +111,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return !x` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:128:5 + --> $DIR/fixable.rs:129:5 | LL | / if x && y { LL | | return true; @@ -121,7 +121,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return x && y` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:136:5 + --> $DIR/fixable.rs:137:5 | LL | / if x && y { LL | | return false; @@ -131,7 +131,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return !(x && y)` error: equality checks against true are unnecessary - --> $DIR/fixable.rs:144:8 + --> $DIR/fixable.rs:145:8 | LL | if x == true {}; | ^^^^^^^^^ help: try simplifying it as shown: `x` @@ -139,25 +139,25 @@ LL | if x == true {}; = note: `-D clippy::bool-comparison` implied by `-D warnings` error: equality checks against false can be replaced by a negation - --> $DIR/fixable.rs:148:8 + --> $DIR/fixable.rs:149:8 | LL | if x == false {}; | ^^^^^^^^^^ help: try simplifying it as shown: `!x` error: equality checks against true are unnecessary - --> $DIR/fixable.rs:158:8 + --> $DIR/fixable.rs:159:8 | LL | if x == true {}; | ^^^^^^^^^ help: try simplifying it as shown: `x` error: equality checks against false can be replaced by a negation - --> $DIR/fixable.rs:159:8 + --> $DIR/fixable.rs:160:8 | LL | if x == false {}; | ^^^^^^^^^^ help: try simplifying it as shown: `!x` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:168:12 + --> $DIR/fixable.rs:169:12 | LL | } else if returns_bool() { | ____________^ @@ -168,7 +168,7 @@ LL | | }; | |_____^ help: you can reduce it to: `{ !returns_bool() }` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:181:5 + --> $DIR/fixable.rs:182:5 | LL | / if unsafe { no(4) } & 1 != 0 { LL | | true @@ -178,13 +178,13 @@ LL | | }; | |_____^ help: you can reduce it to: `(unsafe { no(4) } & 1 != 0)` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:186:30 + --> $DIR/fixable.rs:187:30 | LL | let _brackets_unneeded = if unsafe { no(4) } & 1 != 0 { true } else { false }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `unsafe { no(4) } & 1 != 0` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:189:9 + --> $DIR/fixable.rs:190:9 | LL | if unsafe { no(4) } & 1 != 0 { true } else { false } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `(unsafe { no(4) } & 1 != 0)` diff --git a/tests/ui/needless_borrow.fixed b/tests/ui/needless_borrow.fixed index 425e6eb6200e..80cdb4e472d4 100644 --- a/tests/ui/needless_borrow.fixed +++ b/tests/ui/needless_borrow.fixed @@ -4,7 +4,8 @@ unused, clippy::uninlined_format_args, clippy::unnecessary_mut_passed, - clippy::unnecessary_to_owned + clippy::unnecessary_to_owned, + clippy::unnecessary_literal_unwrap )] #![warn(clippy::needless_borrow)] diff --git a/tests/ui/needless_borrow.rs b/tests/ui/needless_borrow.rs index 3f7fa4a9d7dc..99f735127eb8 100644 --- a/tests/ui/needless_borrow.rs +++ b/tests/ui/needless_borrow.rs @@ -4,7 +4,8 @@ unused, clippy::uninlined_format_args, clippy::unnecessary_mut_passed, - clippy::unnecessary_to_owned + clippy::unnecessary_to_owned, + clippy::unnecessary_literal_unwrap )] #![warn(clippy::needless_borrow)] diff --git a/tests/ui/needless_borrow.stderr b/tests/ui/needless_borrow.stderr index d26c317124b8..f85b4fb46a65 100644 --- a/tests/ui/needless_borrow.stderr +++ b/tests/ui/needless_borrow.stderr @@ -1,5 +1,5 @@ error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:15:15 + --> $DIR/needless_borrow.rs:16:15 | LL | let _ = x(&&a); // warn | ^^^ help: change this to: `&a` @@ -7,211 +7,211 @@ LL | let _ = x(&&a); // warn = note: `-D clippy::needless-borrow` implied by `-D warnings` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:19:13 + --> $DIR/needless_borrow.rs:20:13 | LL | mut_ref(&mut &mut b); // warn | ^^^^^^^^^^^ help: change this to: `&mut b` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:31:13 + --> $DIR/needless_borrow.rs:32:13 | LL | &&a | ^^^ help: change this to: `&a` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:33:15 + --> $DIR/needless_borrow.rs:34:15 | LL | 46 => &&a, | ^^^ help: change this to: `&a` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:39:27 + --> $DIR/needless_borrow.rs:40:27 | LL | break &ref_a; | ^^^^^^ help: change this to: `ref_a` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:46:15 + --> $DIR/needless_borrow.rs:47:15 | LL | let _ = x(&&&a); | ^^^^ help: change this to: `&a` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:47:15 + --> $DIR/needless_borrow.rs:48:15 | LL | let _ = x(&mut &&a); | ^^^^^^^^ help: change this to: `&a` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:48:15 + --> $DIR/needless_borrow.rs:49:15 | LL | let _ = x(&&&mut b); | ^^^^^^^^ help: change this to: `&mut b` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:49:15 + --> $DIR/needless_borrow.rs:50:15 | LL | let _ = x(&&ref_a); | ^^^^^^^ help: change this to: `ref_a` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:52:11 + --> $DIR/needless_borrow.rs:53:11 | LL | x(&b); | ^^ help: change this to: `b` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:59:13 + --> $DIR/needless_borrow.rs:60:13 | LL | mut_ref(&mut x); | ^^^^^^ help: change this to: `x` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:60:13 + --> $DIR/needless_borrow.rs:61:13 | LL | mut_ref(&mut &mut x); | ^^^^^^^^^^^ help: change this to: `x` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:61:23 + --> $DIR/needless_borrow.rs:62:23 | LL | let y: &mut i32 = &mut x; | ^^^^^^ help: change this to: `x` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:62:23 + --> $DIR/needless_borrow.rs:63:23 | LL | let y: &mut i32 = &mut &mut x; | ^^^^^^^^^^^ help: change this to: `x` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:71:14 + --> $DIR/needless_borrow.rs:72:14 | LL | 0 => &mut x, | ^^^^^^ help: change this to: `x` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:77:14 + --> $DIR/needless_borrow.rs:78:14 | LL | 0 => &mut x, | ^^^^^^ help: change this to: `x` error: this expression borrows a value the compiler would automatically borrow - --> $DIR/needless_borrow.rs:89:13 + --> $DIR/needless_borrow.rs:90:13 | LL | let _ = (&x).0; | ^^^^ help: change this to: `x` error: this expression borrows a value the compiler would automatically borrow - --> $DIR/needless_borrow.rs:91:22 + --> $DIR/needless_borrow.rs:92:22 | LL | let _ = unsafe { (&*x).0 }; | ^^^^^ help: change this to: `(*x)` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:101:5 + --> $DIR/needless_borrow.rs:102:5 | LL | (&&()).foo(); | ^^^^^^ help: change this to: `(&())` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:110:5 + --> $DIR/needless_borrow.rs:111:5 | LL | (&&5).foo(); | ^^^^^ help: change this to: `(&5)` error: the borrowed expression implements the required traits - --> $DIR/needless_borrow.rs:135:51 + --> $DIR/needless_borrow.rs:136:51 | LL | let _ = std::process::Command::new("ls").args(&["-a", "-l"]).status().unwrap(); | ^^^^^^^^^^^^^ help: change this to: `["-a", "-l"]` error: the borrowed expression implements the required traits - --> $DIR/needless_borrow.rs:136:44 + --> $DIR/needless_borrow.rs:137:44 | LL | let _ = std::path::Path::new(".").join(&&"."); | ^^^^^ help: change this to: `"."` error: the borrowed expression implements the required traits - --> $DIR/needless_borrow.rs:137:23 + --> $DIR/needless_borrow.rs:138:23 | LL | deref_target_is_x(&X); | ^^ help: change this to: `X` error: the borrowed expression implements the required traits - --> $DIR/needless_borrow.rs:138:26 + --> $DIR/needless_borrow.rs:139:26 | LL | multiple_constraints(&[[""]]); | ^^^^^^^ help: change this to: `[[""]]` error: the borrowed expression implements the required traits - --> $DIR/needless_borrow.rs:139:45 + --> $DIR/needless_borrow.rs:140:45 | LL | multiple_constraints_normalizes_to_same(&X, X); | ^^ help: change this to: `X` error: this expression creates a reference which is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:140:32 + --> $DIR/needless_borrow.rs:141:32 | LL | let _ = Some("").unwrap_or(&""); | ^^^ help: change this to: `""` error: the borrowed expression implements the required traits - --> $DIR/needless_borrow.rs:141:33 + --> $DIR/needless_borrow.rs:142:33 | LL | let _ = std::fs::write("x", &"".to_string()); | ^^^^^^^^^^^^^^^ help: change this to: `"".to_string()` error: this expression borrows a value the compiler would automatically borrow - --> $DIR/needless_borrow.rs:190:13 + --> $DIR/needless_borrow.rs:191:13 | LL | (&self.f)() | ^^^^^^^^^ help: change this to: `(self.f)` error: this expression borrows a value the compiler would automatically borrow - --> $DIR/needless_borrow.rs:199:13 + --> $DIR/needless_borrow.rs:200:13 | LL | (&mut self.f)() | ^^^^^^^^^^^^^ help: change this to: `(self.f)` error: the borrowed expression implements the required traits - --> $DIR/needless_borrow.rs:283:20 + --> $DIR/needless_borrow.rs:284:20 | LL | takes_iter(&mut x) | ^^^^^^ help: change this to: `x` error: the borrowed expression implements the required traits - --> $DIR/needless_borrow.rs:297:55 + --> $DIR/needless_borrow.rs:298:55 | LL | let _ = std::process::Command::new("ls").args(&["-a", "-l"]).status().unwrap(); | ^^^^^^^^^^^^^ help: change this to: `["-a", "-l"]` error: the borrowed expression implements the required traits - --> $DIR/needless_borrow.rs:335:37 + --> $DIR/needless_borrow.rs:336:37 | LL | let _ = std::fs::write("x", &arg); | ^^^^ help: change this to: `arg` error: the borrowed expression implements the required traits - --> $DIR/needless_borrow.rs:336:37 + --> $DIR/needless_borrow.rs:337:37 | LL | let _ = std::fs::write("x", &loc); | ^^^^ help: change this to: `loc` error: the borrowed expression implements the required traits - --> $DIR/needless_borrow.rs:354:15 + --> $DIR/needless_borrow.rs:355:15 | LL | debug(&x); | ^^ help: change this to: `x` error: the borrowed expression implements the required traits - --> $DIR/needless_borrow.rs:363:15 + --> $DIR/needless_borrow.rs:364:15 | LL | use_x(&x); | ^^ help: change this to: `x` error: the borrowed expression implements the required traits - --> $DIR/needless_borrow.rs:457:13 + --> $DIR/needless_borrow.rs:458:13 | LL | foo(&a); | ^^ help: change this to: `a` diff --git a/tests/ui/needless_borrowed_ref.fixed b/tests/ui/needless_borrowed_ref.fixed index 6663520da8a1..59a38425b068 100644 --- a/tests/ui/needless_borrowed_ref.fixed +++ b/tests/ui/needless_borrowed_ref.fixed @@ -5,7 +5,8 @@ unused, irrefutable_let_patterns, non_shorthand_field_patterns, - clippy::needless_borrow + clippy::needless_borrow, + clippy::needless_if )] fn main() {} diff --git a/tests/ui/needless_borrowed_ref.rs b/tests/ui/needless_borrowed_ref.rs index 6c8efd2ce180..e48b19cb19db 100644 --- a/tests/ui/needless_borrowed_ref.rs +++ b/tests/ui/needless_borrowed_ref.rs @@ -5,7 +5,8 @@ unused, irrefutable_let_patterns, non_shorthand_field_patterns, - clippy::needless_borrow + clippy::needless_borrow, + clippy::needless_if )] fn main() {} diff --git a/tests/ui/needless_borrowed_ref.stderr b/tests/ui/needless_borrowed_ref.stderr index 8d0f0c258dd2..35497a01ec22 100644 --- a/tests/ui/needless_borrowed_ref.stderr +++ b/tests/ui/needless_borrowed_ref.stderr @@ -1,5 +1,5 @@ error: this pattern takes a reference on something that is being dereferenced - --> $DIR/needless_borrowed_ref.rs:31:34 + --> $DIR/needless_borrowed_ref.rs:32:34 | LL | let _ = v.iter_mut().filter(|&ref a| a.is_empty()); | ^^^^^^ @@ -12,7 +12,7 @@ LL + let _ = v.iter_mut().filter(|a| a.is_empty()); | error: this pattern takes a reference on something that is being dereferenced - --> $DIR/needless_borrowed_ref.rs:35:17 + --> $DIR/needless_borrowed_ref.rs:36:17 | LL | if let Some(&ref v) = thingy {} | ^^^^^^ @@ -24,7 +24,7 @@ LL + if let Some(v) = thingy {} | error: this pattern takes a reference on something that is being dereferenced - --> $DIR/needless_borrowed_ref.rs:37:14 + --> $DIR/needless_borrowed_ref.rs:38:14 | LL | if let &[&ref a, ref b] = slice_of_refs {} | ^^^^^^ @@ -36,7 +36,7 @@ LL + if let &[a, ref b] = slice_of_refs {} | error: dereferencing a slice pattern where every element takes a reference - --> $DIR/needless_borrowed_ref.rs:39:9 + --> $DIR/needless_borrowed_ref.rs:40:9 | LL | let &[ref a, ..] = &array; | ^^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL + let [a, ..] = &array; | error: dereferencing a slice pattern where every element takes a reference - --> $DIR/needless_borrowed_ref.rs:40:9 + --> $DIR/needless_borrowed_ref.rs:41:9 | LL | let &[ref a, ref b, ..] = &array; | ^^^^^^^^^^^^^^^^^^^ @@ -60,7 +60,7 @@ LL + let [a, b, ..] = &array; | error: dereferencing a slice pattern where every element takes a reference - --> $DIR/needless_borrowed_ref.rs:42:12 + --> $DIR/needless_borrowed_ref.rs:43:12 | LL | if let &[ref a, ref b] = slice {} | ^^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL + if let [a, b] = slice {} | error: dereferencing a slice pattern where every element takes a reference - --> $DIR/needless_borrowed_ref.rs:43:12 + --> $DIR/needless_borrowed_ref.rs:44:12 | LL | if let &[ref a, ref b] = &vec[..] {} | ^^^^^^^^^^^^^^^ @@ -84,7 +84,7 @@ LL + if let [a, b] = &vec[..] {} | error: dereferencing a slice pattern where every element takes a reference - --> $DIR/needless_borrowed_ref.rs:45:12 + --> $DIR/needless_borrowed_ref.rs:46:12 | LL | if let &[ref a, ref b, ..] = slice {} | ^^^^^^^^^^^^^^^^^^^ @@ -96,7 +96,7 @@ LL + if let [a, b, ..] = slice {} | error: dereferencing a slice pattern where every element takes a reference - --> $DIR/needless_borrowed_ref.rs:46:12 + --> $DIR/needless_borrowed_ref.rs:47:12 | LL | if let &[ref a, .., ref b] = slice {} | ^^^^^^^^^^^^^^^^^^^ @@ -108,7 +108,7 @@ LL + if let [a, .., b] = slice {} | error: dereferencing a slice pattern where every element takes a reference - --> $DIR/needless_borrowed_ref.rs:47:12 + --> $DIR/needless_borrowed_ref.rs:48:12 | LL | if let &[.., ref a, ref b] = slice {} | ^^^^^^^^^^^^^^^^^^^ @@ -120,7 +120,7 @@ LL + if let [.., a, b] = slice {} | error: dereferencing a slice pattern where every element takes a reference - --> $DIR/needless_borrowed_ref.rs:49:12 + --> $DIR/needless_borrowed_ref.rs:50:12 | LL | if let &[ref a, _] = slice {} | ^^^^^^^^^^^ @@ -132,7 +132,7 @@ LL + if let [a, _] = slice {} | error: dereferencing a tuple pattern where every element takes a reference - --> $DIR/needless_borrowed_ref.rs:51:12 + --> $DIR/needless_borrowed_ref.rs:52:12 | LL | if let &(ref a, ref b, ref c) = &tuple {} | ^^^^^^^^^^^^^^^^^^^^^^ @@ -144,7 +144,7 @@ LL + if let (a, b, c) = &tuple {} | error: dereferencing a tuple pattern where every element takes a reference - --> $DIR/needless_borrowed_ref.rs:52:12 + --> $DIR/needless_borrowed_ref.rs:53:12 | LL | if let &(ref a, _, ref c) = &tuple {} | ^^^^^^^^^^^^^^^^^^ @@ -156,7 +156,7 @@ LL + if let (a, _, c) = &tuple {} | error: dereferencing a tuple pattern where every element takes a reference - --> $DIR/needless_borrowed_ref.rs:53:12 + --> $DIR/needless_borrowed_ref.rs:54:12 | LL | if let &(ref a, ..) = &tuple {} | ^^^^^^^^^^^^ @@ -168,7 +168,7 @@ LL + if let (a, ..) = &tuple {} | error: dereferencing a tuple pattern where every element takes a reference - --> $DIR/needless_borrowed_ref.rs:55:12 + --> $DIR/needless_borrowed_ref.rs:56:12 | LL | if let &TupleStruct(ref a, ..) = &tuple_struct {} | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -180,7 +180,7 @@ LL + if let TupleStruct(a, ..) = &tuple_struct {} | error: dereferencing a struct pattern where every field's pattern takes a reference - --> $DIR/needless_borrowed_ref.rs:57:12 + --> $DIR/needless_borrowed_ref.rs:58:12 | LL | if let &Struct { | ____________^ @@ -199,7 +199,7 @@ LL ~ c: renamed, | error: dereferencing a struct pattern where every field's pattern takes a reference - --> $DIR/needless_borrowed_ref.rs:64:12 + --> $DIR/needless_borrowed_ref.rs:65:12 | LL | if let &Struct { ref a, b: _, .. } = &s {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/needless_collect.fixed b/tests/ui/needless_collect.fixed index b7e80af50154..0f0aaad17b45 100644 --- a/tests/ui/needless_collect.fixed +++ b/tests/ui/needless_collect.fixed @@ -1,6 +1,6 @@ //@run-rustfix -#![allow(unused, clippy::suspicious_map, clippy::iter_count)] +#![allow(unused, clippy::needless_if, clippy::suspicious_map, clippy::iter_count)] use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList}; @@ -70,6 +70,11 @@ fn main() { bar((0..10).collect::>(), (0..10)); baz((0..10), (), ('a'..='z')) } + + let values = [1, 2, 3, 4]; + let mut out = vec![]; + values.iter().cloned().map(|x| out.push(x)).collect::>(); + let _y = values.iter().cloned().map(|x| out.push(x)).collect::>(); // this is fine } fn foo(_: impl IntoIterator) {} diff --git a/tests/ui/needless_collect.rs b/tests/ui/needless_collect.rs index 680b6fa5b55f..4f48f24b17b8 100644 --- a/tests/ui/needless_collect.rs +++ b/tests/ui/needless_collect.rs @@ -1,6 +1,6 @@ //@run-rustfix -#![allow(unused, clippy::suspicious_map, clippy::iter_count)] +#![allow(unused, clippy::needless_if, clippy::suspicious_map, clippy::iter_count)] use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList}; @@ -70,6 +70,11 @@ fn main() { bar((0..10).collect::>(), (0..10).collect::>()); baz((0..10), (), ('a'..='z').collect::>()) } + + let values = [1, 2, 3, 4]; + let mut out = vec![]; + values.iter().cloned().map(|x| out.push(x)).collect::>(); + let _y = values.iter().cloned().map(|x| out.push(x)).collect::>(); // this is fine } fn foo(_: impl IntoIterator) {} diff --git a/tests/ui/needless_collect_indirect.rs b/tests/ui/needless_collect_indirect.rs index fe4209e99b2f..d3d856c2c659 100644 --- a/tests/ui/needless_collect_indirect.rs +++ b/tests/ui/needless_collect_indirect.rs @@ -1,4 +1,5 @@ -#![allow(clippy::uninlined_format_args)] +#![allow(clippy::uninlined_format_args, clippy::useless_vec)] +#![allow(clippy::needless_if, clippy::uninlined_format_args)] #![warn(clippy::needless_collect)] use std::collections::{BinaryHeap, HashMap, HashSet, LinkedList, VecDeque}; diff --git a/tests/ui/needless_collect_indirect.stderr b/tests/ui/needless_collect_indirect.stderr index 790d725907f3..8f84c5596889 100644 --- a/tests/ui/needless_collect_indirect.stderr +++ b/tests/ui/needless_collect_indirect.stderr @@ -1,5 +1,5 @@ error: avoid using `collect()` when not needed - --> $DIR/needless_collect_indirect.rs:8:39 + --> $DIR/needless_collect_indirect.rs:9:39 | LL | let indirect_iter = sample.iter().collect::>(); | ^^^^^^^ @@ -14,7 +14,7 @@ LL ~ sample.iter().map(|x| (x, x + 1)).collect::>(); | error: avoid using `collect()` when not needed - --> $DIR/needless_collect_indirect.rs:10:38 + --> $DIR/needless_collect_indirect.rs:11:38 | LL | let indirect_len = sample.iter().collect::>(); | ^^^^^^^ @@ -28,7 +28,7 @@ LL ~ sample.iter().count(); | error: avoid using `collect()` when not needed - --> $DIR/needless_collect_indirect.rs:12:40 + --> $DIR/needless_collect_indirect.rs:13:40 | LL | let indirect_empty = sample.iter().collect::>(); | ^^^^^^^ @@ -42,7 +42,7 @@ LL ~ sample.iter().next().is_none(); | error: avoid using `collect()` when not needed - --> $DIR/needless_collect_indirect.rs:14:43 + --> $DIR/needless_collect_indirect.rs:15:43 | LL | let indirect_contains = sample.iter().collect::>(); | ^^^^^^^ @@ -56,7 +56,7 @@ LL ~ sample.iter().any(|x| x == &5); | error: avoid using `collect()` when not needed - --> $DIR/needless_collect_indirect.rs:26:48 + --> $DIR/needless_collect_indirect.rs:27:48 | LL | let non_copy_contains = sample.into_iter().collect::>(); | ^^^^^^^ @@ -70,7 +70,7 @@ LL ~ sample.into_iter().any(|x| x == a); | error: avoid using `collect()` when not needed - --> $DIR/needless_collect_indirect.rs:55:51 + --> $DIR/needless_collect_indirect.rs:56:51 | LL | let buffer: Vec<&str> = string.split('/').collect(); | ^^^^^^^ @@ -84,7 +84,7 @@ LL ~ string.split('/').count() | error: avoid using `collect()` when not needed - --> $DIR/needless_collect_indirect.rs:60:55 + --> $DIR/needless_collect_indirect.rs:61:55 | LL | let indirect_len: VecDeque<_> = sample.iter().collect(); | ^^^^^^^ @@ -98,7 +98,7 @@ LL ~ sample.iter().count() | error: avoid using `collect()` when not needed - --> $DIR/needless_collect_indirect.rs:65:57 + --> $DIR/needless_collect_indirect.rs:66:57 | LL | let indirect_len: LinkedList<_> = sample.iter().collect(); | ^^^^^^^ @@ -112,7 +112,7 @@ LL ~ sample.iter().count() | error: avoid using `collect()` when not needed - --> $DIR/needless_collect_indirect.rs:70:57 + --> $DIR/needless_collect_indirect.rs:71:57 | LL | let indirect_len: BinaryHeap<_> = sample.iter().collect(); | ^^^^^^^ @@ -126,7 +126,7 @@ LL ~ sample.iter().count() | error: avoid using `collect()` when not needed - --> $DIR/needless_collect_indirect.rs:130:59 + --> $DIR/needless_collect_indirect.rs:131:59 | LL | let y: Vec = vec.iter().map(|k| k * k).collect(); | ^^^^^^^ @@ -143,7 +143,7 @@ LL ~ vec.iter().map(|k| k * k).any(|x| x == i); | error: avoid using `collect()` when not needed - --> $DIR/needless_collect_indirect.rs:155:59 + --> $DIR/needless_collect_indirect.rs:156:59 | LL | let y: Vec = vec.iter().map(|k| k * k).collect(); | ^^^^^^^ @@ -160,7 +160,7 @@ LL ~ vec.iter().map(|k| k * k).any(|x| x == n); | error: avoid using `collect()` when not needed - --> $DIR/needless_collect_indirect.rs:184:63 + --> $DIR/needless_collect_indirect.rs:185:63 | LL | let y: Vec = vec.iter().map(|k| k * k).collect(); | ^^^^^^^ @@ -177,7 +177,7 @@ LL ~ vec.iter().map(|k| k * k).any(|x| x == n); | error: avoid using `collect()` when not needed - --> $DIR/needless_collect_indirect.rs:220:59 + --> $DIR/needless_collect_indirect.rs:221:59 | LL | let y: Vec = vec.iter().map(|k| k * k).collect(); | ^^^^^^^ @@ -195,7 +195,7 @@ LL ~ vec.iter().map(|k| k * k).any(|x| x == n); | error: avoid using `collect()` when not needed - --> $DIR/needless_collect_indirect.rs:245:26 + --> $DIR/needless_collect_indirect.rs:246:26 | LL | let w = v.iter().collect::>(); | ^^^^^^^ @@ -211,7 +211,7 @@ LL ~ for _ in 0..v.iter().count() { | error: avoid using `collect()` when not needed - --> $DIR/needless_collect_indirect.rs:267:30 + --> $DIR/needless_collect_indirect.rs:268:30 | LL | let mut w = v.iter().collect::>(); | ^^^^^^^ @@ -227,7 +227,7 @@ LL ~ while 1 == v.iter().count() { | error: avoid using `collect()` when not needed - --> $DIR/needless_collect_indirect.rs:289:30 + --> $DIR/needless_collect_indirect.rs:290:30 | LL | let mut w = v.iter().collect::>(); | ^^^^^^^ diff --git a/tests/ui/needless_if.fixed b/tests/ui/needless_if.fixed new file mode 100644 index 000000000000..5e6e140c2db3 --- /dev/null +++ b/tests/ui/needless_if.fixed @@ -0,0 +1,93 @@ +//@run-rustfix +//@aux-build:proc_macros.rs:proc-macro +#![feature(let_chains)] +#![allow( + clippy::blocks_in_if_conditions, + clippy::if_same_then_else, + clippy::ifs_same_cond, + clippy::let_unit_value, + clippy::needless_else, + clippy::no_effect, + clippy::nonminimal_bool, + clippy::short_circuit_statement, + clippy::unnecessary_operation, + unused +)] +#![warn(clippy::needless_if)] + +extern crate proc_macros; +use proc_macros::external; +use proc_macros::with_span; + +fn maybe_side_effect() -> bool { + true +} + +fn main() { + // Lint + + // Do not remove the condition + maybe_side_effect(); + // Do not lint + if (true) { + } else { + } + ({ + return; + }); + // Do not lint if `else if` is present + if (true) { + } else if (true) { + } + // Do not lint `if let` or let chains + if let true = true {} + if let true = true && true {} + if true && let true = true {} + // Can lint nested `if let`s + ({ + if let true = true && true { true } else { false } + } && true); + external! { if (true) {} } + with_span! { + span + if (true) {} + } + + if true { + // comment + } + + if true { + #[cfg(any())] + foo; + } + + macro_rules! empty_expansion { + () => {}; + } + + if true { + empty_expansion!(); + } + + macro_rules! empty_repetition { + ($($t:tt)*) => { + if true { + $($t)* + } + } + } + + empty_repetition!(); + + // Must be placed into an expression context to not be interpreted as a block + ({ maybe_side_effect() }); + // Would be a block followed by `&&true` - a double reference to `true` + ({ maybe_side_effect() } && true); + + // Don't leave trailing attributes + #[allow(unused)] + true; + + let () = if maybe_side_effect() {}; +} diff --git a/tests/ui/needless_if.rs b/tests/ui/needless_if.rs new file mode 100644 index 000000000000..eb28ce73be8f --- /dev/null +++ b/tests/ui/needless_if.rs @@ -0,0 +1,94 @@ +//@run-rustfix +//@aux-build:proc_macros.rs:proc-macro +#![feature(let_chains)] +#![allow( + clippy::blocks_in_if_conditions, + clippy::if_same_then_else, + clippy::ifs_same_cond, + clippy::let_unit_value, + clippy::needless_else, + clippy::no_effect, + clippy::nonminimal_bool, + clippy::short_circuit_statement, + clippy::unnecessary_operation, + unused +)] +#![warn(clippy::needless_if)] + +extern crate proc_macros; +use proc_macros::external; +use proc_macros::with_span; + +fn maybe_side_effect() -> bool { + true +} + +fn main() { + // Lint + if (true) {} + // Do not remove the condition + if maybe_side_effect() {} + // Do not lint + if (true) { + } else { + } + if { + return; + } {} + // Do not lint if `else if` is present + if (true) { + } else if (true) { + } + // Do not lint `if let` or let chains + if let true = true {} + if let true = true && true {} + if true && let true = true {} + // Can lint nested `if let`s + if { + if let true = true && true { true } else { false } + } && true + {} + external! { if (true) {} } + with_span! { + span + if (true) {} + } + + if true { + // comment + } + + if true { + #[cfg(any())] + foo; + } + + macro_rules! empty_expansion { + () => {}; + } + + if true { + empty_expansion!(); + } + + macro_rules! empty_repetition { + ($($t:tt)*) => { + if true { + $($t)* + } + } + } + + empty_repetition!(); + + // Must be placed into an expression context to not be interpreted as a block + if { maybe_side_effect() } {} + // Would be a block followed by `&&true` - a double reference to `true` + if { maybe_side_effect() } && true {} + + // Don't leave trailing attributes + #[allow(unused)] + if true {} + + let () = if maybe_side_effect() {}; +} diff --git a/tests/ui/needless_if.stderr b/tests/ui/needless_if.stderr new file mode 100644 index 000000000000..5cb42c36921d --- /dev/null +++ b/tests/ui/needless_if.stderr @@ -0,0 +1,65 @@ +error: this `if` branch is empty + --> $DIR/needless_if.rs:28:5 + | +LL | if (true) {} + | ^^^^^^^^^^^^ help: you can remove it + | + = note: `-D clippy::needless-if` implied by `-D warnings` + +error: this `if` branch is empty + --> $DIR/needless_if.rs:30:5 + | +LL | if maybe_side_effect() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `maybe_side_effect();` + +error: this `if` branch is empty + --> $DIR/needless_if.rs:35:5 + | +LL | / if { +LL | | return; +LL | | } {} + | |________^ + | +help: you can remove it + | +LL ~ ({ +LL + return; +LL + }); + | + +error: this `if` branch is empty + --> $DIR/needless_if.rs:47:5 + | +LL | / if { +LL | | if let true = true && true { true } else { false } +LL | | } && true +LL | | {} + | |______^ + | +help: you can remove it + | +LL ~ ({ +LL + if let true = true && true { true } else { false } +LL + } && true); + | + +error: this `if` branch is empty + --> $DIR/needless_if.rs:85:5 + | +LL | if { maybe_side_effect() } {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `({ maybe_side_effect() });` + +error: this `if` branch is empty + --> $DIR/needless_if.rs:87:5 + | +LL | if { maybe_side_effect() } && true {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `({ maybe_side_effect() } && true);` + +error: this `if` branch is empty + --> $DIR/needless_if.rs:91:5 + | +LL | if true {} + | ^^^^^^^^^^ help: you can remove it: `true;` + +error: aborting due to 7 previous errors + diff --git a/tests/ui/needless_late_init.fixed b/tests/ui/needless_late_init.fixed index 92f7b3f777a1..933dd8bed2a2 100644 --- a/tests/ui/needless_late_init.fixed +++ b/tests/ui/needless_late_init.fixed @@ -1,5 +1,5 @@ //@run-rustfix -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![feature(let_chains)] #![allow(unused)] #![allow( @@ -8,7 +8,8 @@ clippy::let_and_return, clippy::let_unit_value, clippy::nonminimal_bool, - clippy::uninlined_format_args + clippy::uninlined_format_args, + clippy::useless_vec )] extern crate proc_macros; diff --git a/tests/ui/needless_late_init.rs b/tests/ui/needless_late_init.rs index be378c42f95d..ba3a04e0825e 100644 --- a/tests/ui/needless_late_init.rs +++ b/tests/ui/needless_late_init.rs @@ -1,5 +1,5 @@ //@run-rustfix -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![feature(let_chains)] #![allow(unused)] #![allow( @@ -8,7 +8,8 @@ clippy::let_and_return, clippy::let_unit_value, clippy::nonminimal_bool, - clippy::uninlined_format_args + clippy::uninlined_format_args, + clippy::useless_vec )] extern crate proc_macros; diff --git a/tests/ui/needless_late_init.stderr b/tests/ui/needless_late_init.stderr index eff782f8bf10..78ba8e11c575 100644 --- a/tests/ui/needless_late_init.stderr +++ b/tests/ui/needless_late_init.stderr @@ -1,5 +1,5 @@ error: unneeded late initialization - --> $DIR/needless_late_init.rs:27:5 + --> $DIR/needless_late_init.rs:28:5 | LL | let a; | ^^^^^^ created here @@ -13,7 +13,7 @@ LL | let a = "zero"; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:30:5 + --> $DIR/needless_late_init.rs:31:5 | LL | let b; | ^^^^^^ created here @@ -27,7 +27,7 @@ LL | let b = 1; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:31:5 + --> $DIR/needless_late_init.rs:32:5 | LL | let c; | ^^^^^^ created here @@ -41,7 +41,7 @@ LL | let c = 2; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:35:5 + --> $DIR/needless_late_init.rs:36:5 | LL | let d: usize; | ^^^^^^^^^^^^^ created here @@ -54,7 +54,7 @@ LL | let d: usize = 1; | ~~~~~~~~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:38:5 + --> $DIR/needless_late_init.rs:39:5 | LL | let e; | ^^^^^^ created here @@ -67,7 +67,7 @@ LL | let e = format!("{}", d); | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:43:5 + --> $DIR/needless_late_init.rs:44:5 | LL | let a; | ^^^^^^ @@ -88,7 +88,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:52:5 + --> $DIR/needless_late_init.rs:53:5 | LL | let b; | ^^^^^^ @@ -109,7 +109,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:59:5 + --> $DIR/needless_late_init.rs:60:5 | LL | let d; | ^^^^^^ @@ -130,7 +130,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:67:5 + --> $DIR/needless_late_init.rs:68:5 | LL | let e; | ^^^^^^ @@ -151,7 +151,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:74:5 + --> $DIR/needless_late_init.rs:75:5 | LL | let f; | ^^^^^^ @@ -167,7 +167,7 @@ LL + 1 => "three", | error: unneeded late initialization - --> $DIR/needless_late_init.rs:80:5 + --> $DIR/needless_late_init.rs:81:5 | LL | let g: usize; | ^^^^^^^^^^^^^ @@ -187,7 +187,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:88:5 + --> $DIR/needless_late_init.rs:89:5 | LL | let x; | ^^^^^^ created here @@ -201,7 +201,7 @@ LL | let x = 1; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:92:5 + --> $DIR/needless_late_init.rs:93:5 | LL | let x; | ^^^^^^ created here @@ -215,7 +215,7 @@ LL | let x = SignificantDrop; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:96:5 + --> $DIR/needless_late_init.rs:97:5 | LL | let x; | ^^^^^^ created here @@ -229,7 +229,7 @@ LL | let x = SignificantDrop; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:115:5 + --> $DIR/needless_late_init.rs:116:5 | LL | let a; | ^^^^^^ @@ -250,7 +250,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:132:5 + --> $DIR/needless_late_init.rs:133:5 | LL | let a; | ^^^^^^ diff --git a/tests/ui/needless_lifetimes.fixed b/tests/ui/needless_lifetimes.fixed index 7b99042f7449..302a3f9edbec 100644 --- a/tests/ui/needless_lifetimes.fixed +++ b/tests/ui/needless_lifetimes.fixed @@ -1,5 +1,5 @@ //@run-rustfix -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![warn(clippy::needless_lifetimes)] #![allow( diff --git a/tests/ui/needless_lifetimes.rs b/tests/ui/needless_lifetimes.rs index 6fcf1efc2ee6..b15477c92e81 100644 --- a/tests/ui/needless_lifetimes.rs +++ b/tests/ui/needless_lifetimes.rs @@ -1,5 +1,5 @@ //@run-rustfix -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![warn(clippy::needless_lifetimes)] #![allow( diff --git a/tests/ui/needless_lifetimes.stderr b/tests/ui/needless_lifetimes.stderr index 86acc4e00469..0da67b600a3f 100644 --- a/tests/ui/needless_lifetimes.stderr +++ b/tests/ui/needless_lifetimes.stderr @@ -1,8 +1,8 @@ error: the following explicit lifetimes could be elided: 'a, 'b - --> $DIR/needless_lifetimes.rs:18:1 + --> $DIR/needless_lifetimes.rs:18:23 | LL | fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ ^^ ^^ | = note: `-D clippy::needless-lifetimes` implied by `-D warnings` help: elide the lifetimes @@ -12,10 +12,10 @@ LL + fn distinct_lifetimes(_x: &u8, _y: &u8, _z: u8) {} | error: the following explicit lifetimes could be elided: 'a, 'b - --> $DIR/needless_lifetimes.rs:20:1 + --> $DIR/needless_lifetimes.rs:20:24 | LL | fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ ^^ ^^ | help: elide the lifetimes | @@ -24,10 +24,10 @@ LL + fn distinct_and_static(_x: &u8, _y: &u8, _z: &'static u8) {} | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:30:1 + --> $DIR/needless_lifetimes.rs:30:15 | LL | fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ ^^ | help: elide the lifetimes | @@ -36,10 +36,10 @@ LL + fn in_and_out(x: &u8, _y: u8) -> &u8 { | error: the following explicit lifetimes could be elided: 'b - --> $DIR/needless_lifetimes.rs:42:1 + --> $DIR/needless_lifetimes.rs:42:31 | LL | fn multiple_in_and_out_2a<'a, 'b>(x: &'a u8, _y: &'b u8) -> &'a u8 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ | help: elide the lifetimes | @@ -48,10 +48,10 @@ LL + fn multiple_in_and_out_2a<'a>(x: &'a u8, _y: &u8) -> &'a u8 { | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:49:1 + --> $DIR/needless_lifetimes.rs:49:27 | LL | fn multiple_in_and_out_2b<'a, 'b>(_x: &'a u8, y: &'b u8) -> &'b u8 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ | help: elide the lifetimes | @@ -60,10 +60,10 @@ LL + fn multiple_in_and_out_2b<'b>(_x: &u8, y: &'b u8) -> &'b u8 { | error: the following explicit lifetimes could be elided: 'b - --> $DIR/needless_lifetimes.rs:66:1 + --> $DIR/needless_lifetimes.rs:66:26 | LL | fn deep_reference_1a<'a, 'b>(x: &'a u8, _y: &'b u8) -> Result<&'a u8, ()> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ | help: elide the lifetimes | @@ -72,10 +72,10 @@ LL + fn deep_reference_1a<'a>(x: &'a u8, _y: &u8) -> Result<&'a u8, ()> { | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:73:1 + --> $DIR/needless_lifetimes.rs:73:22 | LL | fn deep_reference_1b<'a, 'b>(_x: &'a u8, y: &'b u8) -> Result<&'b u8, ()> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ | help: elide the lifetimes | @@ -84,10 +84,10 @@ LL + fn deep_reference_1b<'b>(_x: &u8, y: &'b u8) -> Result<&'b u8, ()> { | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:82:1 + --> $DIR/needless_lifetimes.rs:82:21 | LL | fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ ^^ | help: elide the lifetimes | @@ -96,10 +96,10 @@ LL + fn deep_reference_3(x: &u8, _y: u8) -> Result<&u8, ()> { | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:87:1 + --> $DIR/needless_lifetimes.rs:87:28 | LL | fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ ^^ | help: elide the lifetimes | @@ -108,10 +108,10 @@ LL + fn where_clause_without_lt(x: &u8, _y: u8) -> Result<&u8, ()> | error: the following explicit lifetimes could be elided: 'a, 'b - --> $DIR/needless_lifetimes.rs:99:1 + --> $DIR/needless_lifetimes.rs:99:21 | LL | fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ ^^ ^^ | help: elide the lifetimes | @@ -120,10 +120,10 @@ LL + fn lifetime_param_2(_x: Ref<'_>, _y: &u8) {} | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:123:1 + --> $DIR/needless_lifetimes.rs:123:15 | LL | fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I> - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ ^^ | help: elide the lifetimes | @@ -132,10 +132,10 @@ LL + fn fn_bound_2(_m: Lt<'_, I>, _f: F) -> Lt<'_, I> | error: the following explicit lifetimes could be elided: 's - --> $DIR/needless_lifetimes.rs:153:5 + --> $DIR/needless_lifetimes.rs:153:21 | LL | fn self_and_out<'s>(&'s self) -> &'s u8 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ ^^ | help: elide the lifetimes | @@ -144,10 +144,10 @@ LL + fn self_and_out(&self) -> &u8 { | error: the following explicit lifetimes could be elided: 't - --> $DIR/needless_lifetimes.rs:160:5 + --> $DIR/needless_lifetimes.rs:160:30 | LL | fn self_and_in_out_1<'s, 't>(&'s self, _x: &'t u8) -> &'s u8 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ | help: elide the lifetimes | @@ -156,10 +156,10 @@ LL + fn self_and_in_out_1<'s>(&'s self, _x: &u8) -> &'s u8 { | error: the following explicit lifetimes could be elided: 's - --> $DIR/needless_lifetimes.rs:167:5 + --> $DIR/needless_lifetimes.rs:167:26 | LL | fn self_and_in_out_2<'s, 't>(&'s self, x: &'t u8) -> &'t u8 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ | help: elide the lifetimes | @@ -168,10 +168,10 @@ LL + fn self_and_in_out_2<'t>(&self, x: &'t u8) -> &'t u8 { | error: the following explicit lifetimes could be elided: 's, 't - --> $DIR/needless_lifetimes.rs:171:5 + --> $DIR/needless_lifetimes.rs:171:29 | LL | fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ ^^ ^^ | help: elide the lifetimes | @@ -180,10 +180,10 @@ LL + fn distinct_self_and_in(&self, _x: &u8) {} | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:190:1 + --> $DIR/needless_lifetimes.rs:190:19 | LL | fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ ^^ | help: elide the lifetimes | @@ -192,10 +192,10 @@ LL + fn struct_with_lt(_foo: Foo<'_>) -> &str { | error: the following explicit lifetimes could be elided: 'b - --> $DIR/needless_lifetimes.rs:208:1 + --> $DIR/needless_lifetimes.rs:208:25 | LL | fn struct_with_lt4a<'a, 'b>(_foo: &'a Foo<'b>) -> &'a str { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ | help: elide the lifetimes | @@ -204,10 +204,10 @@ LL + fn struct_with_lt4a<'a>(_foo: &'a Foo<'_>) -> &'a str { | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:216:1 + --> $DIR/needless_lifetimes.rs:216:21 | LL | fn struct_with_lt4b<'a, 'b>(_foo: &'a Foo<'b>) -> &'b str { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ | help: elide the lifetimes | @@ -216,10 +216,10 @@ LL + fn struct_with_lt4b<'b>(_foo: &Foo<'b>) -> &'b str { | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:231:1 + --> $DIR/needless_lifetimes.rs:231:22 | LL | fn trait_obj_elided2<'a>(_arg: &'a dyn Drop) -> &'a str { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ ^^ | help: elide the lifetimes | @@ -228,10 +228,10 @@ LL + fn trait_obj_elided2(_arg: &dyn Drop) -> &str { | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:237:1 + --> $DIR/needless_lifetimes.rs:237:18 | LL | fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ ^^ | help: elide the lifetimes | @@ -240,10 +240,10 @@ LL + fn alias_with_lt(_foo: FooAlias<'_>) -> &str { | error: the following explicit lifetimes could be elided: 'b - --> $DIR/needless_lifetimes.rs:255:1 + --> $DIR/needless_lifetimes.rs:255:24 | LL | fn alias_with_lt4a<'a, 'b>(_foo: &'a FooAlias<'b>) -> &'a str { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ | help: elide the lifetimes | @@ -252,10 +252,10 @@ LL + fn alias_with_lt4a<'a>(_foo: &'a FooAlias<'_>) -> &'a str { | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:263:1 + --> $DIR/needless_lifetimes.rs:263:20 | LL | fn alias_with_lt4b<'a, 'b>(_foo: &'a FooAlias<'b>) -> &'b str { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ | help: elide the lifetimes | @@ -264,10 +264,10 @@ LL + fn alias_with_lt4b<'b>(_foo: &FooAlias<'b>) -> &'b str { | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:267:1 + --> $DIR/needless_lifetimes.rs:267:30 | LL | fn named_input_elided_output<'a>(_arg: &'a str) -> &str { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ ^ | help: elide the lifetimes | @@ -276,10 +276,10 @@ LL + fn named_input_elided_output(_arg: &str) -> &str { | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:275:1 + --> $DIR/needless_lifetimes.rs:275:19 | LL | fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ | help: elide the lifetimes | @@ -288,10 +288,10 @@ LL + fn trait_bound_ok>(_: &u8, _: T) { | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:311:1 + --> $DIR/needless_lifetimes.rs:311:24 | LL | fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ ^^ | help: elide the lifetimes | @@ -300,10 +300,10 @@ LL + fn out_return_type_lts(e: &str) -> Cow<'_> { | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:318:9 + --> $DIR/needless_lifetimes.rs:318:24 | LL | fn needless_lt<'a>(x: &'a u8) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ | help: elide the lifetimes | @@ -312,10 +312,10 @@ LL + fn needless_lt(x: &u8) {} | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:322:9 + --> $DIR/needless_lifetimes.rs:322:24 | LL | fn needless_lt<'a>(_x: &'a u8) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ | help: elide the lifetimes | @@ -324,10 +324,10 @@ LL + fn needless_lt(_x: &u8) {} | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:335:9 + --> $DIR/needless_lifetimes.rs:335:16 | LL | fn baz<'a>(&'a self) -> impl Foo + 'a { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ ^^ | help: elide the lifetimes | @@ -336,10 +336,10 @@ LL + fn baz(&self) -> impl Foo + '_ { | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:367:5 + --> $DIR/needless_lifetimes.rs:367:55 | LL | fn impl_trait_elidable_nested_anonymous_lifetimes<'a>(i: &'a i32, f: impl Fn(&i32) -> &i32) -> &'a i32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ ^^ | help: elide the lifetimes | @@ -348,10 +348,10 @@ LL + fn impl_trait_elidable_nested_anonymous_lifetimes(i: &i32, f: impl Fn(& | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:376:5 + --> $DIR/needless_lifetimes.rs:376:26 | LL | fn generics_elidable<'a, T: Fn(&i32) -> &i32>(i: &'a i32, f: T) -> &'a i32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ ^^ | help: elide the lifetimes | @@ -360,10 +360,10 @@ LL + fn generics_elidable &i32>(i: &i32, f: T) -> &i32 { | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:388:5 + --> $DIR/needless_lifetimes.rs:388:32 | LL | fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ ^^ | help: elide the lifetimes | @@ -372,10 +372,10 @@ LL + fn where_clause_elidadable(i: &i32, f: T) -> &i32 | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:403:5 + --> $DIR/needless_lifetimes.rs:403:28 | LL | fn pointer_fn_elidable<'a>(i: &'a i32, f: fn(&i32) -> &i32) -> &'a i32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ ^^ | help: elide the lifetimes | @@ -384,10 +384,10 @@ LL + fn pointer_fn_elidable(i: &i32, f: fn(&i32) -> &i32) -> &i32 { | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:416:5 + --> $DIR/needless_lifetimes.rs:416:28 | LL | fn nested_fn_pointer_3<'a>(_: &'a i32) -> fn(fn(&i32) -> &i32) -> i32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ | help: elide the lifetimes | @@ -396,10 +396,10 @@ LL + fn nested_fn_pointer_3(_: &i32) -> fn(fn(&i32) -> &i32) -> i32 { | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:419:5 + --> $DIR/needless_lifetimes.rs:419:28 | LL | fn nested_fn_pointer_4<'a>(_: &'a i32) -> impl Fn(fn(&i32)) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ | help: elide the lifetimes | @@ -408,10 +408,10 @@ LL + fn nested_fn_pointer_4(_: &i32) -> impl Fn(fn(&i32)) { | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:441:9 + --> $DIR/needless_lifetimes.rs:441:21 | LL | fn implicit<'a>(&'a self) -> &'a () { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ ^^ | help: elide the lifetimes | @@ -420,10 +420,10 @@ LL + fn implicit(&self) -> &() { | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:444:9 + --> $DIR/needless_lifetimes.rs:444:25 | LL | fn implicit_mut<'a>(&'a mut self) -> &'a () { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ ^^ | help: elide the lifetimes | @@ -432,10 +432,10 @@ LL + fn implicit_mut(&mut self) -> &() { | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:455:9 + --> $DIR/needless_lifetimes.rs:455:31 | LL | fn lifetime_elsewhere<'a>(self: Box, here: &'a ()) -> &'a () { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ ^^ | help: elide the lifetimes | @@ -444,10 +444,10 @@ LL + fn lifetime_elsewhere(self: Box, here: &()) -> &() { | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:461:9 + --> $DIR/needless_lifetimes.rs:461:21 | LL | fn implicit<'a>(&'a self) -> &'a (); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ ^^ | help: elide the lifetimes | @@ -456,10 +456,10 @@ LL + fn implicit(&self) -> &(); | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:462:9 + --> $DIR/needless_lifetimes.rs:462:30 | LL | fn implicit_provided<'a>(&'a self) -> &'a () { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ ^^ | help: elide the lifetimes | @@ -468,10 +468,10 @@ LL + fn implicit_provided(&self) -> &() { | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:471:9 + --> $DIR/needless_lifetimes.rs:471:31 | LL | fn lifetime_elsewhere<'a>(self: Box, here: &'a ()) -> &'a (); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ ^^ | help: elide the lifetimes | @@ -480,10 +480,10 @@ LL + fn lifetime_elsewhere(self: Box, here: &()) -> &(); | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:472:9 + --> $DIR/needless_lifetimes.rs:472:40 | LL | fn lifetime_elsewhere_provided<'a>(self: Box, here: &'a ()) -> &'a () { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ ^^ | help: elide the lifetimes | @@ -492,10 +492,10 @@ LL + fn lifetime_elsewhere_provided(self: Box, here: &()) -> &() { | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:481:5 + --> $DIR/needless_lifetimes.rs:481:12 | LL | fn foo<'a>(x: &'a u8, y: &'_ u8) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ | help: elide the lifetimes | @@ -504,10 +504,10 @@ LL + fn foo(x: &u8, y: &'_ u8) {} | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:483:5 + --> $DIR/needless_lifetimes.rs:483:12 | LL | fn bar<'a>(x: &'a u8, y: &'_ u8, z: &'_ u8) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ | help: elide the lifetimes | @@ -516,10 +516,10 @@ LL + fn bar(x: &u8, y: &'_ u8, z: &'_ u8) {} | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:490:5 + --> $DIR/needless_lifetimes.rs:490:18 | LL | fn one_input<'a>(x: &'a u8) -> &'a u8 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ ^^ | help: elide the lifetimes | @@ -528,10 +528,10 @@ LL + fn one_input(x: &u8) -> &u8 { | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:495:5 + --> $DIR/needless_lifetimes.rs:495:42 | LL | fn multiple_inputs_output_not_elided<'a, 'b>(x: &'a u8, y: &'b u8, z: &'b u8) -> &'b u8 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ | help: elide the lifetimes | @@ -540,10 +540,10 @@ LL + fn multiple_inputs_output_not_elided<'b>(x: &u8, y: &'b u8, z: &'b u8) | error: the following explicit lifetimes could be elided: 'a - --> $DIR/needless_lifetimes.rs:511:9 + --> $DIR/needless_lifetimes.rs:511:22 | LL | fn one_input<'a>(x: &'a u8) -> &'a u8 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ ^^ ^^ | = note: this error originates in the macro `__inline_mac_mod_in_macro` (in Nightly builds, run with -Z macro-backtrace for more info) help: elide the lifetimes diff --git a/tests/ui/needless_option_as_deref.fixed b/tests/ui/needless_option_as_deref.fixed index 70015fccf9ee..ec981ad97e3d 100644 --- a/tests/ui/needless_option_as_deref.fixed +++ b/tests/ui/needless_option_as_deref.fixed @@ -2,6 +2,7 @@ #![allow(unused)] #![warn(clippy::needless_option_as_deref)] +#![allow(clippy::useless_vec)] fn main() { // should lint diff --git a/tests/ui/needless_option_as_deref.rs b/tests/ui/needless_option_as_deref.rs index e2e35360cb36..6360874f6236 100644 --- a/tests/ui/needless_option_as_deref.rs +++ b/tests/ui/needless_option_as_deref.rs @@ -2,6 +2,7 @@ #![allow(unused)] #![warn(clippy::needless_option_as_deref)] +#![allow(clippy::useless_vec)] fn main() { // should lint diff --git a/tests/ui/needless_option_as_deref.stderr b/tests/ui/needless_option_as_deref.stderr index bc07db5b38ed..20d28a968c91 100644 --- a/tests/ui/needless_option_as_deref.stderr +++ b/tests/ui/needless_option_as_deref.stderr @@ -1,5 +1,5 @@ error: derefed type is same as origin - --> $DIR/needless_option_as_deref.rs:8:29 + --> $DIR/needless_option_as_deref.rs:9:29 | LL | let _: Option<&usize> = Some(&1).as_deref(); | ^^^^^^^^^^^^^^^^^^^ help: try this: `Some(&1)` @@ -7,13 +7,13 @@ LL | let _: Option<&usize> = Some(&1).as_deref(); = note: `-D clippy::needless-option-as-deref` implied by `-D warnings` error: derefed type is same as origin - --> $DIR/needless_option_as_deref.rs:9:33 + --> $DIR/needless_option_as_deref.rs:10:33 | LL | let _: Option<&mut usize> = Some(&mut 1).as_deref_mut(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `Some(&mut 1)` error: derefed type is same as origin - --> $DIR/needless_option_as_deref.rs:13:13 + --> $DIR/needless_option_as_deref.rs:14:13 | LL | let _ = x.as_deref_mut(); | ^^^^^^^^^^^^^^^^ help: try this: `x` diff --git a/tests/ui/needless_pass_by_value_proc_macro.rs b/tests/ui/needless_pass_by_value_proc_macro.rs index 78a0e92d1797..c603163c145f 100644 --- a/tests/ui/needless_pass_by_value_proc_macro.rs +++ b/tests/ui/needless_pass_by_value_proc_macro.rs @@ -1,4 +1,3 @@ -#![crate_type = "proc-macro"] #![warn(clippy::needless_pass_by_value)] extern crate proc_macro; diff --git a/tests/ui/needless_pub_self.fixed b/tests/ui/needless_pub_self.fixed new file mode 100644 index 000000000000..672b4c318a8d --- /dev/null +++ b/tests/ui/needless_pub_self.fixed @@ -0,0 +1,33 @@ +//@run-rustfix +//@aux-build:proc_macros.rs:proc-macro +#![feature(custom_inner_attributes)] +#![allow(unused)] +#![warn(clippy::needless_pub_self)] +#![no_main] +#![rustfmt::skip] // rustfmt will remove `in`, understandable + // but very annoying for our purposes! + +#[macro_use] +extern crate proc_macros; + + fn a() {} + fn b() {} + +pub fn c() {} +mod a { + pub(in super) fn d() {} + pub(super) fn e() {} + fn f() {} +} + +external! { + pub(self) fn g() {} + pub(in self) fn h() {} +} +with_span! { + span + pub(self) fn i() {} + pub(in self) fn j() {} +} + +// not really anything more to test. just a really simple lint overall diff --git a/tests/ui/needless_pub_self.rs b/tests/ui/needless_pub_self.rs new file mode 100644 index 000000000000..5ac1edf8e990 --- /dev/null +++ b/tests/ui/needless_pub_self.rs @@ -0,0 +1,33 @@ +//@run-rustfix +//@aux-build:proc_macros.rs:proc-macro +#![feature(custom_inner_attributes)] +#![allow(unused)] +#![warn(clippy::needless_pub_self)] +#![no_main] +#![rustfmt::skip] // rustfmt will remove `in`, understandable + // but very annoying for our purposes! + +#[macro_use] +extern crate proc_macros; + +pub(self) fn a() {} +pub(in self) fn b() {} + +pub fn c() {} +mod a { + pub(in super) fn d() {} + pub(super) fn e() {} + pub(self) fn f() {} +} + +external! { + pub(self) fn g() {} + pub(in self) fn h() {} +} +with_span! { + span + pub(self) fn i() {} + pub(in self) fn j() {} +} + +// not really anything more to test. just a really simple lint overall diff --git a/tests/ui/needless_pub_self.stderr b/tests/ui/needless_pub_self.stderr new file mode 100644 index 000000000000..3aa2feb5ecd8 --- /dev/null +++ b/tests/ui/needless_pub_self.stderr @@ -0,0 +1,22 @@ +error: unnecessary `pub(self)` + --> $DIR/needless_pub_self.rs:13:1 + | +LL | pub(self) fn a() {} + | ^^^^^^^^^ help: remove it + | + = note: `-D clippy::needless-pub-self` implied by `-D warnings` + +error: unnecessary `pub(in self)` + --> $DIR/needless_pub_self.rs:14:1 + | +LL | pub(in self) fn b() {} + | ^^^^^^^^^^^^ help: remove it + +error: unnecessary `pub(self)` + --> $DIR/needless_pub_self.rs:20:5 + | +LL | pub(self) fn f() {} + | ^^^^^^^^^ help: remove it + +error: aborting due to 3 previous errors + diff --git a/tests/ui/needless_range_loop.rs b/tests/ui/needless_range_loop.rs index 921801138a9b..a16ef5a5bca9 100644 --- a/tests/ui/needless_range_loop.rs +++ b/tests/ui/needless_range_loop.rs @@ -1,5 +1,9 @@ #![warn(clippy::needless_range_loop)] -#![allow(clippy::uninlined_format_args)] +#![allow( + clippy::uninlined_format_args, + clippy::unnecessary_literal_unwrap, + clippy::useless_vec +)] static STATIC: [usize; 4] = [0, 1, 8, 16]; const CONST: [usize; 4] = [0, 1, 8, 16]; @@ -82,6 +86,29 @@ fn main() { for i in 0..2 { println!("{}", test[i]); } + + // See #601 + for i in 0..10 { + // no error, id_col does not exist outside the loop + let mut id_col = [0f64; 10]; + id_col[i] = 1f64; + } + + fn f(_: &T, _: &T) -> bool { + unimplemented!() + } + fn g(_: &mut [T], _: usize, _: usize) { + unimplemented!() + } + for i in 1..vec.len() { + if f(&vec[i - 1], &vec[i]) { + g(&mut vec, i - 1, i); + } + } + + for mid in 1..vec.len() { + let (_, _) = vec.split_at(mid); + } } struct Test { @@ -94,3 +121,38 @@ impl std::ops::Index for Test { &self.inner[index] } } + +fn partition(v: &mut [T]) -> usize { + let pivot = v.len() - 1; + let mut i = 0; + for j in 0..pivot { + if v[j] <= v[pivot] { + v.swap(i, j); + i += 1; + } + } + v.swap(i, pivot); + i +} + +pub fn manual_copy_same_destination(dst: &mut [i32], d: usize, s: usize) { + // Same source and destination - don't trigger lint + for i in 0..dst.len() { + dst[d + i] = dst[s + i]; + } +} + +mod issue_2496 { + pub trait Handle { + fn new_for_index(index: usize) -> Self; + fn index(&self) -> usize; + } + + pub fn test() -> H { + for x in 0..5 { + let next_handle = H::new_for_index(x); + println!("{}", next_handle.index()); + } + unimplemented!() + } +} diff --git a/tests/ui/needless_range_loop.stderr b/tests/ui/needless_range_loop.stderr index cffa19bec3a6..8ca6b880ceae 100644 --- a/tests/ui/needless_range_loop.stderr +++ b/tests/ui/needless_range_loop.stderr @@ -1,5 +1,5 @@ error: the loop variable `i` is only used to index `vec` - --> $DIR/needless_range_loop.rs:11:14 + --> $DIR/needless_range_loop.rs:15:14 | LL | for i in 0..vec.len() { | ^^^^^^^^^^^^ @@ -11,7 +11,7 @@ LL | for in &vec { | ~~~~~~ ~~~~ error: the loop variable `i` is only used to index `vec` - --> $DIR/needless_range_loop.rs:20:14 + --> $DIR/needless_range_loop.rs:24:14 | LL | for i in 0..vec.len() { | ^^^^^^^^^^^^ @@ -22,7 +22,7 @@ LL | for in &vec { | ~~~~~~ ~~~~ error: the loop variable `j` is only used to index `STATIC` - --> $DIR/needless_range_loop.rs:25:14 + --> $DIR/needless_range_loop.rs:29:14 | LL | for j in 0..4 { | ^^^^ @@ -33,7 +33,7 @@ LL | for in &STATIC { | ~~~~~~ ~~~~~~~ error: the loop variable `j` is only used to index `CONST` - --> $DIR/needless_range_loop.rs:29:14 + --> $DIR/needless_range_loop.rs:33:14 | LL | for j in 0..4 { | ^^^^ @@ -44,7 +44,7 @@ LL | for in &CONST { | ~~~~~~ ~~~~~~ error: the loop variable `i` is used to index `vec` - --> $DIR/needless_range_loop.rs:33:14 + --> $DIR/needless_range_loop.rs:37:14 | LL | for i in 0..vec.len() { | ^^^^^^^^^^^^ @@ -55,7 +55,7 @@ LL | for (i, ) in vec.iter().enumerate() { | ~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~ error: the loop variable `i` is only used to index `vec2` - --> $DIR/needless_range_loop.rs:41:14 + --> $DIR/needless_range_loop.rs:45:14 | LL | for i in 0..vec.len() { | ^^^^^^^^^^^^ @@ -66,7 +66,7 @@ LL | for in vec2.iter().take(vec.len()) { | ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: the loop variable `i` is only used to index `vec` - --> $DIR/needless_range_loop.rs:45:14 + --> $DIR/needless_range_loop.rs:49:14 | LL | for i in 5..vec.len() { | ^^^^^^^^^^^^ @@ -77,7 +77,7 @@ LL | for in vec.iter().skip(5) { | ~~~~~~ ~~~~~~~~~~~~~~~~~~ error: the loop variable `i` is only used to index `vec` - --> $DIR/needless_range_loop.rs:49:14 + --> $DIR/needless_range_loop.rs:53:14 | LL | for i in 0..MAX_LEN { | ^^^^^^^^^^ @@ -88,7 +88,7 @@ LL | for in vec.iter().take(MAX_LEN) { | ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~ error: the loop variable `i` is only used to index `vec` - --> $DIR/needless_range_loop.rs:53:14 + --> $DIR/needless_range_loop.rs:57:14 | LL | for i in 0..=MAX_LEN { | ^^^^^^^^^^^ @@ -99,7 +99,7 @@ LL | for in vec.iter().take(MAX_LEN + 1) { | ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: the loop variable `i` is only used to index `vec` - --> $DIR/needless_range_loop.rs:57:14 + --> $DIR/needless_range_loop.rs:61:14 | LL | for i in 5..10 { | ^^^^^ @@ -110,7 +110,7 @@ LL | for in vec.iter().take(10).skip(5) { | ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: the loop variable `i` is only used to index `vec` - --> $DIR/needless_range_loop.rs:61:14 + --> $DIR/needless_range_loop.rs:65:14 | LL | for i in 5..=10 { | ^^^^^^ @@ -121,7 +121,7 @@ LL | for in vec.iter().take(10 + 1).skip(5) { | ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: the loop variable `i` is used to index `vec` - --> $DIR/needless_range_loop.rs:65:14 + --> $DIR/needless_range_loop.rs:69:14 | LL | for i in 5..vec.len() { | ^^^^^^^^^^^^ @@ -132,7 +132,7 @@ LL | for (i, ) in vec.iter().enumerate().skip(5) { | ~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: the loop variable `i` is used to index `vec` - --> $DIR/needless_range_loop.rs:69:14 + --> $DIR/needless_range_loop.rs:73:14 | LL | for i in 5..10 { | ^^^^^ @@ -143,7 +143,7 @@ LL | for (i, ) in vec.iter().enumerate().take(10).skip(5) { | ~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: the loop variable `i` is used to index `vec` - --> $DIR/needless_range_loop.rs:74:14 + --> $DIR/needless_range_loop.rs:78:14 | LL | for i in 0..vec.len() { | ^^^^^^^^^^^^ diff --git a/tests/ui/needless_range_loop2.rs b/tests/ui/needless_range_loop2.rs index 7633316e0f87..516d99a3532a 100644 --- a/tests/ui/needless_range_loop2.rs +++ b/tests/ui/needless_range_loop2.rs @@ -1,4 +1,5 @@ #![warn(clippy::needless_range_loop)] +#![allow(clippy::useless_vec)] fn calc_idx(i: usize) -> usize { (i + i + 20) % 4 diff --git a/tests/ui/needless_range_loop2.stderr b/tests/ui/needless_range_loop2.stderr index 1e6ec5e667aa..8c4f5d954a97 100644 --- a/tests/ui/needless_range_loop2.stderr +++ b/tests/ui/needless_range_loop2.stderr @@ -1,5 +1,5 @@ error: the loop variable `i` is only used to index `ns` - --> $DIR/needless_range_loop2.rs:10:14 + --> $DIR/needless_range_loop2.rs:11:14 | LL | for i in 3..10 { | ^^^^^ @@ -11,7 +11,7 @@ LL | for in ns.iter().take(10).skip(3) { | ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~ error: the loop variable `i` is only used to index `ms` - --> $DIR/needless_range_loop2.rs:31:14 + --> $DIR/needless_range_loop2.rs:32:14 | LL | for i in 0..ms.len() { | ^^^^^^^^^^^ @@ -22,7 +22,7 @@ LL | for in &mut ms { | ~~~~~~ ~~~~~~~ error: the loop variable `i` is only used to index `ms` - --> $DIR/needless_range_loop2.rs:37:14 + --> $DIR/needless_range_loop2.rs:38:14 | LL | for i in 0..ms.len() { | ^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | for in &mut ms { | ~~~~~~ ~~~~~~~ error: the loop variable `i` is only used to index `vec` - --> $DIR/needless_range_loop2.rs:61:14 + --> $DIR/needless_range_loop2.rs:62:14 | LL | for i in x..x + 4 { | ^^^^^^^^ @@ -44,7 +44,7 @@ LL | for in vec.iter_mut().skip(x).take(4) { | ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: the loop variable `i` is only used to index `vec` - --> $DIR/needless_range_loop2.rs:68:14 + --> $DIR/needless_range_loop2.rs:69:14 | LL | for i in x..=x + 4 { | ^^^^^^^^^ @@ -55,7 +55,7 @@ LL | for in vec.iter_mut().skip(x).take(4 + 1) { | ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: the loop variable `i` is only used to index `arr` - --> $DIR/needless_range_loop2.rs:74:14 + --> $DIR/needless_range_loop2.rs:75:14 | LL | for i in 0..3 { | ^^^^ @@ -66,7 +66,7 @@ LL | for in &arr { | ~~~~~~ ~~~~ error: the loop variable `i` is only used to index `arr` - --> $DIR/needless_range_loop2.rs:78:14 + --> $DIR/needless_range_loop2.rs:79:14 | LL | for i in 0..2 { | ^^^^ @@ -77,7 +77,7 @@ LL | for in arr.iter().take(2) { | ~~~~~~ ~~~~~~~~~~~~~~~~~~ error: the loop variable `i` is only used to index `arr` - --> $DIR/needless_range_loop2.rs:82:14 + --> $DIR/needless_range_loop2.rs:83:14 | LL | for i in 1..3 { | ^^^^ diff --git a/tests/ui/needless_raw_string.fixed b/tests/ui/needless_raw_string.fixed new file mode 100644 index 000000000000..6438e46977bb --- /dev/null +++ b/tests/ui/needless_raw_string.fixed @@ -0,0 +1,16 @@ +//@run-rustfix +#![allow(clippy::needless_raw_string_hashes, clippy::no_effect, unused)] +#![warn(clippy::needless_raw_strings)] +#![feature(c_str_literals)] + +fn main() { + "aaa"; + r#""aaa""#; + r#"\s"#; + b"aaa"; + br#""aaa""#; + br#"\s"#; + c"aaa"; + cr#""aaa""#; + cr#"\s"#; +} diff --git a/tests/ui/needless_raw_string.rs b/tests/ui/needless_raw_string.rs new file mode 100644 index 000000000000..f7ddc68265ed --- /dev/null +++ b/tests/ui/needless_raw_string.rs @@ -0,0 +1,16 @@ +//@run-rustfix +#![allow(clippy::needless_raw_string_hashes, clippy::no_effect, unused)] +#![warn(clippy::needless_raw_strings)] +#![feature(c_str_literals)] + +fn main() { + r#"aaa"#; + r#""aaa""#; + r#"\s"#; + br#"aaa"#; + br#""aaa""#; + br#"\s"#; + cr#"aaa"#; + cr#""aaa""#; + cr#"\s"#; +} diff --git a/tests/ui/needless_raw_string.stderr b/tests/ui/needless_raw_string.stderr new file mode 100644 index 000000000000..0179978b7b08 --- /dev/null +++ b/tests/ui/needless_raw_string.stderr @@ -0,0 +1,22 @@ +error: unnecessary raw string literal + --> $DIR/needless_raw_string.rs:7:5 + | +LL | r#"aaa"#; + | ^^^^^^^^ help: try: `"aaa"` + | + = note: `-D clippy::needless-raw-strings` implied by `-D warnings` + +error: unnecessary raw string literal + --> $DIR/needless_raw_string.rs:10:5 + | +LL | br#"aaa"#; + | ^^^^^^^^^ help: try: `b"aaa"` + +error: unnecessary raw string literal + --> $DIR/needless_raw_string.rs:13:5 + | +LL | cr#"aaa"#; + | ^^^^^^^^^ help: try: `c"aaa"` + +error: aborting due to 3 previous errors + diff --git a/tests/ui/needless_raw_string_hashes.fixed b/tests/ui/needless_raw_string_hashes.fixed new file mode 100644 index 000000000000..e4d7d8fb017a --- /dev/null +++ b/tests/ui/needless_raw_string_hashes.fixed @@ -0,0 +1,19 @@ +//@run-rustfix +#![allow(clippy::no_effect, unused)] +#![warn(clippy::needless_raw_string_hashes)] +#![feature(c_str_literals)] + +fn main() { + r#"aaa"#; + r#"Hello "world"!"#; + r####" "### "## "# "####; + r###" "aa" "# "## "###; + br#"aaa"#; + br#"Hello "world"!"#; + br####" "### "## "# "####; + br###" "aa" "# "## "###; + cr#"aaa"#; + cr#"Hello "world"!"#; + cr####" "### "## "# "####; + cr###" "aa" "# "## "###; +} diff --git a/tests/ui/needless_raw_string_hashes.rs b/tests/ui/needless_raw_string_hashes.rs new file mode 100644 index 000000000000..e2d85c52e78c --- /dev/null +++ b/tests/ui/needless_raw_string_hashes.rs @@ -0,0 +1,19 @@ +//@run-rustfix +#![allow(clippy::no_effect, unused)] +#![warn(clippy::needless_raw_string_hashes)] +#![feature(c_str_literals)] + +fn main() { + r#"aaa"#; + r##"Hello "world"!"##; + r######" "### "## "# "######; + r######" "aa" "# "## "######; + br#"aaa"#; + br##"Hello "world"!"##; + br######" "### "## "# "######; + br######" "aa" "# "## "######; + cr#"aaa"#; + cr##"Hello "world"!"##; + cr######" "### "## "# "######; + cr######" "aa" "# "## "######; +} diff --git a/tests/ui/needless_raw_string_hashes.stderr b/tests/ui/needless_raw_string_hashes.stderr new file mode 100644 index 000000000000..dff47a2d0421 --- /dev/null +++ b/tests/ui/needless_raw_string_hashes.stderr @@ -0,0 +1,58 @@ +error: unnecessary hashes around raw string literal + --> $DIR/needless_raw_string_hashes.rs:8:5 + | +LL | r##"Hello "world"!"##; + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `r#"Hello "world"!"#` + | + = note: `-D clippy::needless-raw-string-hashes` implied by `-D warnings` + +error: unnecessary hashes around raw string literal + --> $DIR/needless_raw_string_hashes.rs:9:5 + | +LL | r######" "### "## "# "######; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `r####" "### "## "# "####` + +error: unnecessary hashes around raw string literal + --> $DIR/needless_raw_string_hashes.rs:10:5 + | +LL | r######" "aa" "# "## "######; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `r###" "aa" "# "## "###` + +error: unnecessary hashes around raw string literal + --> $DIR/needless_raw_string_hashes.rs:12:5 + | +LL | br##"Hello "world"!"##; + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `br#"Hello "world"!"#` + +error: unnecessary hashes around raw string literal + --> $DIR/needless_raw_string_hashes.rs:13:5 + | +LL | br######" "### "## "# "######; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `br####" "### "## "# "####` + +error: unnecessary hashes around raw string literal + --> $DIR/needless_raw_string_hashes.rs:14:5 + | +LL | br######" "aa" "# "## "######; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `br###" "aa" "# "## "###` + +error: unnecessary hashes around raw string literal + --> $DIR/needless_raw_string_hashes.rs:16:5 + | +LL | cr##"Hello "world"!"##; + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `cr#"Hello "world"!"#` + +error: unnecessary hashes around raw string literal + --> $DIR/needless_raw_string_hashes.rs:17:5 + | +LL | cr######" "### "## "# "######; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cr####" "### "## "# "####` + +error: unnecessary hashes around raw string literal + --> $DIR/needless_raw_string_hashes.rs:18:5 + | +LL | cr######" "aa" "# "## "######; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cr###" "aa" "# "## "###` + +error: aborting due to 9 previous errors + diff --git a/tests/ui/never_loop.rs b/tests/ui/never_loop.rs index 29821ff96fc0..eb179f30e75e 100644 --- a/tests/ui/never_loop.rs +++ b/tests/ui/never_loop.rs @@ -1,4 +1,6 @@ +#![feature(inline_const)] #![allow( + clippy::eq_op, clippy::single_match, unused_assignments, unused_variables, @@ -295,6 +297,42 @@ pub fn test24() { } } +// Do not lint, we can evaluate `true` to always succeed thus can short-circuit before the `return` +pub fn test25() { + loop { + 'label: { + if const { true } { + break 'label; + } + return; + } + } +} + +pub fn test26() { + loop { + 'label: { + if 1 == 1 { + break 'label; + } + return; + } + } +} + +pub fn test27() { + loop { + 'label: { + let x = true; + // Lints because we cannot prove it's always `true` + if x { + break 'label; + } + return; + } + } +} + fn main() { test1(); test2(); diff --git a/tests/ui/never_loop.stderr b/tests/ui/never_loop.stderr index 704d448644e2..0446c09cd5bc 100644 --- a/tests/ui/never_loop.stderr +++ b/tests/ui/never_loop.stderr @@ -1,5 +1,5 @@ error: this loop never actually loops - --> $DIR/never_loop.rs:10:5 + --> $DIR/never_loop.rs:12:5 | LL | / loop { LL | | // clippy::never_loop @@ -13,7 +13,7 @@ LL | | } = note: `#[deny(clippy::never_loop)]` on by default error: this loop never actually loops - --> $DIR/never_loop.rs:32:5 + --> $DIR/never_loop.rs:34:5 | LL | / loop { LL | | // never loops @@ -23,7 +23,7 @@ LL | | } | |_____^ error: this loop never actually loops - --> $DIR/never_loop.rs:52:5 + --> $DIR/never_loop.rs:54:5 | LL | / loop { LL | | // never loops @@ -35,7 +35,7 @@ LL | | } | |_____^ error: this loop never actually loops - --> $DIR/never_loop.rs:54:9 + --> $DIR/never_loop.rs:56:9 | LL | / while i == 0 { LL | | // never loops @@ -44,7 +44,7 @@ LL | | } | |_________^ error: this loop never actually loops - --> $DIR/never_loop.rs:66:9 + --> $DIR/never_loop.rs:68:9 | LL | / loop { LL | | // never loops @@ -56,7 +56,7 @@ LL | | } | |_________^ error: this loop never actually loops - --> $DIR/never_loop.rs:102:5 + --> $DIR/never_loop.rs:104:5 | LL | / while let Some(y) = x { LL | | // never loops @@ -65,7 +65,7 @@ LL | | } | |_____^ error: this loop never actually loops - --> $DIR/never_loop.rs:109:5 + --> $DIR/never_loop.rs:111:5 | LL | / for x in 0..10 { LL | | // never loops @@ -82,7 +82,7 @@ LL | if let Some(x) = (0..10).next() { | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: this loop never actually loops - --> $DIR/never_loop.rs:157:5 + --> $DIR/never_loop.rs:159:5 | LL | / 'outer: while a { LL | | // never loops @@ -94,7 +94,7 @@ LL | | } | |_____^ error: this loop never actually loops - --> $DIR/never_loop.rs:172:9 + --> $DIR/never_loop.rs:174:9 | LL | / while false { LL | | break 'label; @@ -102,7 +102,7 @@ LL | | } | |_________^ error: this loop never actually loops - --> $DIR/never_loop.rs:223:13 + --> $DIR/never_loop.rs:225:13 | LL | let _ = loop { | _____________^ @@ -115,7 +115,7 @@ LL | | }; | |_____^ error: this loop never actually loops - --> $DIR/never_loop.rs:244:5 + --> $DIR/never_loop.rs:246:5 | LL | / 'a: loop { LL | | 'b: { @@ -126,8 +126,16 @@ LL | | } LL | | } | |_____^ +error: sub-expression diverges + --> $DIR/never_loop.rs:249:17 + | +LL | break 'a; + | ^^^^^^^^ + | + = note: `-D clippy::diverging-sub-expression` implied by `-D warnings` + error: this loop never actually loops - --> $DIR/never_loop.rs:278:13 + --> $DIR/never_loop.rs:280:13 | LL | / for _ in 0..20 { LL | | break 'block; @@ -139,5 +147,17 @@ help: if you need the first element of the iterator, try writing LL | if let Some(_) = (0..20).next() { | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -error: aborting due to 12 previous errors +error: this loop never actually loops + --> $DIR/never_loop.rs:324:5 + | +LL | / loop { +LL | | 'label: { +LL | | let x = true; +LL | | // Lints because we cannot prove it's always `true` +... | +LL | | } +LL | | } + | |_____^ + +error: aborting due to 14 previous errors diff --git a/tests/ui/no_effect.rs b/tests/ui/no_effect.rs index 1e42e1fbabfe..6a726941be89 100644 --- a/tests/ui/no_effect.rs +++ b/tests/ui/no_effect.rs @@ -5,7 +5,8 @@ clippy::deref_addrof, clippy::redundant_field_names, clippy::uninlined_format_args, - clippy::unnecessary_struct_initialization + clippy::unnecessary_struct_initialization, + clippy::useless_vec )] struct Unit; diff --git a/tests/ui/no_effect.stderr b/tests/ui/no_effect.stderr index f10f2bcf2a8a..64edfc32504e 100644 --- a/tests/ui/no_effect.stderr +++ b/tests/ui/no_effect.stderr @@ -1,5 +1,5 @@ error: statement with no effect - --> $DIR/no_effect.rs:97:5 + --> $DIR/no_effect.rs:98:5 | LL | 0; | ^^ @@ -7,151 +7,151 @@ LL | 0; = note: `-D clippy::no-effect` implied by `-D warnings` error: statement with no effect - --> $DIR/no_effect.rs:98:5 + --> $DIR/no_effect.rs:99:5 | LL | s2; | ^^^ error: statement with no effect - --> $DIR/no_effect.rs:99:5 + --> $DIR/no_effect.rs:100:5 | LL | Unit; | ^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:100:5 + --> $DIR/no_effect.rs:101:5 | LL | Tuple(0); | ^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:101:5 + --> $DIR/no_effect.rs:102:5 | LL | Struct { field: 0 }; | ^^^^^^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:102:5 + --> $DIR/no_effect.rs:103:5 | LL | Struct { ..s }; | ^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:103:5 + --> $DIR/no_effect.rs:104:5 | LL | Union { a: 0 }; | ^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:104:5 + --> $DIR/no_effect.rs:105:5 | LL | Enum::Tuple(0); | ^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:105:5 + --> $DIR/no_effect.rs:106:5 | LL | Enum::Struct { field: 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:106:5 + --> $DIR/no_effect.rs:107:5 | LL | 5 + 6; | ^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:107:5 + --> $DIR/no_effect.rs:108:5 | LL | *&42; | ^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:108:5 + --> $DIR/no_effect.rs:109:5 | LL | &6; | ^^^ error: statement with no effect - --> $DIR/no_effect.rs:109:5 + --> $DIR/no_effect.rs:110:5 | LL | (5, 6, 7); | ^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:110:5 + --> $DIR/no_effect.rs:111:5 | LL | ..; | ^^^ error: statement with no effect - --> $DIR/no_effect.rs:111:5 + --> $DIR/no_effect.rs:112:5 | LL | 5..; | ^^^^ error: statement with no effect - --> $DIR/no_effect.rs:112:5 + --> $DIR/no_effect.rs:113:5 | LL | ..5; | ^^^^ error: statement with no effect - --> $DIR/no_effect.rs:113:5 + --> $DIR/no_effect.rs:114:5 | LL | 5..6; | ^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:114:5 + --> $DIR/no_effect.rs:115:5 | LL | 5..=6; | ^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:115:5 + --> $DIR/no_effect.rs:116:5 | LL | [42, 55]; | ^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:116:5 + --> $DIR/no_effect.rs:117:5 | LL | [42, 55][1]; | ^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:117:5 + --> $DIR/no_effect.rs:118:5 | LL | (42, 55).1; | ^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:118:5 + --> $DIR/no_effect.rs:119:5 | LL | [42; 55]; | ^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:119:5 + --> $DIR/no_effect.rs:120:5 | LL | [42; 55][13]; | ^^^^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:121:5 + --> $DIR/no_effect.rs:122:5 | LL | || x += 5; | ^^^^^^^^^^ error: statement with no effect - --> $DIR/no_effect.rs:123:5 + --> $DIR/no_effect.rs:124:5 | LL | FooString { s: s }; | ^^^^^^^^^^^^^^^^^^^ error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:124:5 + --> $DIR/no_effect.rs:125:5 | LL | let _unused = 1; | ^^^^^^^^^^^^^^^^ @@ -159,19 +159,19 @@ LL | let _unused = 1; = note: `-D clippy::no-effect-underscore-binding` implied by `-D warnings` error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:125:5 + --> $DIR/no_effect.rs:126:5 | LL | let _penguin = || println!("Some helpful closure"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:126:5 + --> $DIR/no_effect.rs:127:5 | LL | let _duck = Struct { field: 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: binding to `_` prefixed variable with no side-effect - --> $DIR/no_effect.rs:127:5 + --> $DIR/no_effect.rs:128:5 | LL | let _cat = [2, 4, 6, 8][2]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/no_effect_return.rs b/tests/ui/no_effect_return.rs new file mode 100644 index 000000000000..231dd063ad89 --- /dev/null +++ b/tests/ui/no_effect_return.rs @@ -0,0 +1,81 @@ +#![allow(clippy::unused_unit, dead_code, unused)] +#![no_main] + +use std::ops::ControlFlow; + +fn a() -> u32 { + { + 0u32; + } + 0 +} + +async fn b() -> u32 { + { + 0u32; + } + 0 +} + +type C = i32; +async fn c() -> C { + { + 0i32 as C; + } + 0 +} + +fn d() -> u128 { + { + // not last stmt + 0u128; + println!("lol"); + } + 0 +} + +fn e() -> u32 { + { + // mismatched types + 0u16; + } + 0 +} + +fn f() -> [u16; 1] { + { + [1u16]; + } + [1] +} + +fn g() -> ControlFlow<()> { + { + ControlFlow::Break::<()>(()); + } + ControlFlow::Continue(()) +} + +fn h() -> Vec { + { + // function call, so this won't trigger `no_effect`. not an issue with this change, but the + // lint itself (but also not really.) + vec![0u16]; + } + vec![] +} + +fn i() -> () { + { + (); + } + () +} + +fn j() { + { + // does not suggest on function without explicit return type + (); + } + () +} diff --git a/tests/ui/no_effect_return.stderr b/tests/ui/no_effect_return.stderr new file mode 100644 index 000000000000..779900e18590 --- /dev/null +++ b/tests/ui/no_effect_return.stderr @@ -0,0 +1,70 @@ +error: statement with no effect + --> $DIR/no_effect_return.rs:8:9 + | +LL | 0u32; + | -^^^^ + | | + | help: did you mean to return it?: `return` + | + = note: `-D clippy::no-effect` implied by `-D warnings` + +error: statement with no effect + --> $DIR/no_effect_return.rs:15:9 + | +LL | 0u32; + | -^^^^ + | | + | help: did you mean to return it?: `return` + +error: statement with no effect + --> $DIR/no_effect_return.rs:23:9 + | +LL | 0i32 as C; + | -^^^^^^^^^ + | | + | help: did you mean to return it?: `return` + +error: statement with no effect + --> $DIR/no_effect_return.rs:31:9 + | +LL | 0u128; + | ^^^^^^ + +error: statement with no effect + --> $DIR/no_effect_return.rs:40:9 + | +LL | 0u16; + | ^^^^^ + +error: statement with no effect + --> $DIR/no_effect_return.rs:47:9 + | +LL | [1u16]; + | -^^^^^^ + | | + | help: did you mean to return it?: `return` + +error: statement with no effect + --> $DIR/no_effect_return.rs:54:9 + | +LL | ControlFlow::Break::<()>(()); + | -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: did you mean to return it?: `return` + +error: statement with no effect + --> $DIR/no_effect_return.rs:70:9 + | +LL | (); + | -^^ + | | + | help: did you mean to return it?: `return` + +error: statement with no effect + --> $DIR/no_effect_return.rs:78:9 + | +LL | (); + | ^^^ + +error: aborting due to 9 previous errors + diff --git a/tests/ui/non_expressive_names.rs b/tests/ui/non_expressive_names.rs index 583096ac054a..987a4775ef07 100644 --- a/tests/ui/non_expressive_names.rs +++ b/tests/ui/non_expressive_names.rs @@ -25,9 +25,9 @@ impl MaybeInst { } fn underscores_and_numbers() { - let _1 = 1; //~ERROR Consider a more descriptive name - let ____1 = 1; //~ERROR Consider a more descriptive name - let __1___2 = 12; //~ERROR Consider a more descriptive name + let _1 = 1; //~ERROR: consider choosing a more descriptive name + let ____1 = 1; //~ERROR: consider choosing a more descriptive name + let __1___2 = 12; //~ERROR: consider choosing a more descriptive name let _1_ok = 1; } @@ -48,9 +48,9 @@ struct Bar; impl Bar { fn bar() { - let _1 = 1; - let ____1 = 1; - let __1___2 = 12; + let _1 = 1; //~ERROR: consider choosing a more descriptive name + let ____1 = 1; //~ERROR: consider choosing a more descriptive name + let __1___2 = 12; //~ERROR: consider choosing a more descriptive name let _1_ok = 1; } } diff --git a/tests/ui/non_expressive_names.stderr b/tests/ui/non_expressive_names.stderr index 116d5da8729c..b62748d4989d 100644 --- a/tests/ui/non_expressive_names.stderr +++ b/tests/ui/non_expressive_names.stderr @@ -1,7 +1,7 @@ error: consider choosing a more descriptive name --> $DIR/non_expressive_names.rs:28:9 | -LL | let _1 = 1; //~ERROR Consider a more descriptive name +LL | let _1 = 1; | ^^ | = note: `-D clippy::just-underscores-and-digits` implied by `-D warnings` @@ -9,13 +9,13 @@ LL | let _1 = 1; //~ERROR Consider a more descriptive name error: consider choosing a more descriptive name --> $DIR/non_expressive_names.rs:29:9 | -LL | let ____1 = 1; //~ERROR Consider a more descriptive name +LL | let ____1 = 1; | ^^^^^ error: consider choosing a more descriptive name --> $DIR/non_expressive_names.rs:30:9 | -LL | let __1___2 = 12; //~ERROR Consider a more descriptive name +LL | let __1___2 = 12; | ^^^^^^^ error: consider choosing a more descriptive name diff --git a/tests/ui/non_octal_unix_permissions.fixed b/tests/ui/non_octal_unix_permissions.fixed index 89d127528347..5d0da8dce670 100644 --- a/tests/ui/non_octal_unix_permissions.fixed +++ b/tests/ui/non_octal_unix_permissions.fixed @@ -1,4 +1,4 @@ -//@ignore-windows +//@ignore-target-windows //@run-rustfix #![warn(clippy::non_octal_unix_permissions)] use std::fs::{DirBuilder, File, OpenOptions, Permissions}; diff --git a/tests/ui/non_octal_unix_permissions.rs b/tests/ui/non_octal_unix_permissions.rs index 1b3a322d7265..04a3643050e6 100644 --- a/tests/ui/non_octal_unix_permissions.rs +++ b/tests/ui/non_octal_unix_permissions.rs @@ -1,4 +1,4 @@ -//@ignore-windows +//@ignore-target-windows //@run-rustfix #![warn(clippy::non_octal_unix_permissions)] use std::fs::{DirBuilder, File, OpenOptions, Permissions}; diff --git a/tests/ui/nonminimal_bool.rs b/tests/ui/nonminimal_bool.rs index fec6b7713eef..e4aa0937b977 100644 --- a/tests/ui/nonminimal_bool.rs +++ b/tests/ui/nonminimal_bool.rs @@ -1,6 +1,7 @@ #![feature(lint_reasons)] -#![allow(unused, clippy::diverging_sub_expression)] +#![allow(unused, clippy::diverging_sub_expression, clippy::needless_if)] #![warn(clippy::nonminimal_bool)] +#![allow(clippy::useless_vec)] fn main() { let a: bool = unimplemented!(); diff --git a/tests/ui/nonminimal_bool.stderr b/tests/ui/nonminimal_bool.stderr index 91b5805aa97a..e2e4d6477c9f 100644 --- a/tests/ui/nonminimal_bool.stderr +++ b/tests/ui/nonminimal_bool.stderr @@ -1,5 +1,5 @@ error: this boolean expression can be simplified - --> $DIR/nonminimal_bool.rs:11:13 + --> $DIR/nonminimal_bool.rs:12:13 | LL | let _ = !true; | ^^^^^ help: try: `false` @@ -7,43 +7,43 @@ LL | let _ = !true; = note: `-D clippy::nonminimal-bool` implied by `-D warnings` error: this boolean expression can be simplified - --> $DIR/nonminimal_bool.rs:12:13 + --> $DIR/nonminimal_bool.rs:13:13 | LL | let _ = !false; | ^^^^^^ help: try: `true` error: this boolean expression can be simplified - --> $DIR/nonminimal_bool.rs:13:13 + --> $DIR/nonminimal_bool.rs:14:13 | LL | let _ = !!a; | ^^^ help: try: `a` error: this boolean expression can be simplified - --> $DIR/nonminimal_bool.rs:14:13 + --> $DIR/nonminimal_bool.rs:15:13 | LL | let _ = false || a; | ^^^^^^^^^^ help: try: `a` error: this boolean expression can be simplified - --> $DIR/nonminimal_bool.rs:18:13 + --> $DIR/nonminimal_bool.rs:19:13 | LL | let _ = !(!a && b); | ^^^^^^^^^^ help: try: `a || !b` error: this boolean expression can be simplified - --> $DIR/nonminimal_bool.rs:19:13 + --> $DIR/nonminimal_bool.rs:20:13 | LL | let _ = !(!a || b); | ^^^^^^^^^^ help: try: `a && !b` error: this boolean expression can be simplified - --> $DIR/nonminimal_bool.rs:20:13 + --> $DIR/nonminimal_bool.rs:21:13 | LL | let _ = !a && !(b && c); | ^^^^^^^^^^^^^^^ help: try: `!(a || b && c)` error: this boolean expression can be simplified - --> $DIR/nonminimal_bool.rs:28:13 + --> $DIR/nonminimal_bool.rs:29:13 | LL | let _ = a == b && c == 5 && a == b; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | let _ = a == b && c == 5; | ~~~~~~~~~~~~~~~~ error: this boolean expression can be simplified - --> $DIR/nonminimal_bool.rs:29:13 + --> $DIR/nonminimal_bool.rs:30:13 | LL | let _ = a == b || c == 5 || a == b; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -69,7 +69,7 @@ LL | let _ = a == b || c == 5; | ~~~~~~~~~~~~~~~~ error: this boolean expression can be simplified - --> $DIR/nonminimal_bool.rs:30:13 + --> $DIR/nonminimal_bool.rs:31:13 | LL | let _ = a == b && c == 5 && b == a; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -82,7 +82,7 @@ LL | let _ = a == b && c == 5; | ~~~~~~~~~~~~~~~~ error: this boolean expression can be simplified - --> $DIR/nonminimal_bool.rs:31:13 + --> $DIR/nonminimal_bool.rs:32:13 | LL | let _ = a != b || !(a != b || c == d); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -95,7 +95,7 @@ LL | let _ = a != b || c != d; | ~~~~~~~~~~~~~~~~ error: this boolean expression can be simplified - --> $DIR/nonminimal_bool.rs:32:13 + --> $DIR/nonminimal_bool.rs:33:13 | LL | let _ = a != b && !(a != b && c == d); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -108,7 +108,7 @@ LL | let _ = a != b && c != d; | ~~~~~~~~~~~~~~~~ error: this boolean expression can be simplified - --> $DIR/nonminimal_bool.rs:62:8 + --> $DIR/nonminimal_bool.rs:63:8 | LL | if matches!(true, true) && true { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(true, true)` diff --git a/tests/ui/nonminimal_bool_methods.fixed b/tests/ui/nonminimal_bool_methods.fixed index 05802a2c865f..294f2aa48f1c 100644 --- a/tests/ui/nonminimal_bool_methods.fixed +++ b/tests/ui/nonminimal_bool_methods.fixed @@ -1,5 +1,5 @@ //@run-rustfix -#![allow(unused, clippy::diverging_sub_expression)] +#![allow(unused, clippy::diverging_sub_expression, clippy::needless_if)] #![warn(clippy::nonminimal_bool)] fn methods_with_negation() { diff --git a/tests/ui/nonminimal_bool_methods.rs b/tests/ui/nonminimal_bool_methods.rs index cd5b576fa07e..a165368ab17d 100644 --- a/tests/ui/nonminimal_bool_methods.rs +++ b/tests/ui/nonminimal_bool_methods.rs @@ -1,5 +1,5 @@ //@run-rustfix -#![allow(unused, clippy::diverging_sub_expression)] +#![allow(unused, clippy::diverging_sub_expression, clippy::needless_if)] #![warn(clippy::nonminimal_bool)] fn methods_with_negation() { diff --git a/tests/ui/octal_escapes.stderr b/tests/ui/octal_escapes.stderr index aa362e96321b..63fdfe486e81 100644 --- a/tests/ui/octal_escapes.stderr +++ b/tests/ui/octal_escapes.stderr @@ -34,17 +34,17 @@ LL | let _bad2 = b"/x0033[0m"; error: octal-looking escape in string literal --> $DIR/octal_escapes.rs:6:17 | -LL | let _bad3 = "//033[0m"; +LL | let _bad3 = "///033[0m"; | ^^^^^^^^^^^ | = help: octal escapes are not supported, `/0` is always a null character help: if an octal escape was intended, use the hexadecimal representation instead | -LL | let _bad3 = "//x1b[0m"; +LL | let _bad3 = "///x1b[0m"; | ~~~~~~~~~~~ help: if the null character is intended, disambiguate using | -LL | let _bad3 = "//x0033[0m"; +LL | let _bad3 = "///x0033[0m"; | ~~~~~~~~~~~~~ error: octal-looking escape in string literal diff --git a/tests/ui/ok_expect.rs b/tests/ui/ok_expect.rs index ff68d38c73bf..2047ee689d95 100644 --- a/tests/ui/ok_expect.rs +++ b/tests/ui/ok_expect.rs @@ -1,3 +1,5 @@ +#![allow(clippy::unnecessary_literal_unwrap)] + use std::io; struct MyError(()); // doesn't implement Debug diff --git a/tests/ui/ok_expect.stderr b/tests/ui/ok_expect.stderr index 6c40adbb53dc..ab9df26ebc37 100644 --- a/tests/ui/ok_expect.stderr +++ b/tests/ui/ok_expect.stderr @@ -1,5 +1,5 @@ error: called `ok().expect()` on a `Result` value - --> $DIR/ok_expect.rs:14:5 + --> $DIR/ok_expect.rs:16:5 | LL | res.ok().expect("disaster!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | res.ok().expect("disaster!"); = note: `-D clippy::ok-expect` implied by `-D warnings` error: called `ok().expect()` on a `Result` value - --> $DIR/ok_expect.rs:20:5 + --> $DIR/ok_expect.rs:22:5 | LL | res3.ok().expect("whoof"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | res3.ok().expect("whoof"); = help: you can call `expect()` directly on the `Result` error: called `ok().expect()` on a `Result` value - --> $DIR/ok_expect.rs:22:5 + --> $DIR/ok_expect.rs:24:5 | LL | res4.ok().expect("argh"); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | res4.ok().expect("argh"); = help: you can call `expect()` directly on the `Result` error: called `ok().expect()` on a `Result` value - --> $DIR/ok_expect.rs:24:5 + --> $DIR/ok_expect.rs:26:5 | LL | res5.ok().expect("oops"); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | res5.ok().expect("oops"); = help: you can call `expect()` directly on the `Result` error: called `ok().expect()` on a `Result` value - --> $DIR/ok_expect.rs:26:5 + --> $DIR/ok_expect.rs:28:5 | LL | res6.ok().expect("meh"); | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/option_as_ref_deref.fixed b/tests/ui/option_as_ref_deref.fixed index e1c0fa3f7fd3..4d1a6a1ab98d 100644 --- a/tests/ui/option_as_ref_deref.fixed +++ b/tests/ui/option_as_ref_deref.fixed @@ -1,6 +1,6 @@ //@run-rustfix -#![allow(unused, clippy::redundant_clone)] +#![allow(unused, clippy::redundant_clone, clippy::useless_vec)] #![warn(clippy::option_as_ref_deref)] use std::ffi::{CString, OsString}; diff --git a/tests/ui/option_as_ref_deref.rs b/tests/ui/option_as_ref_deref.rs index 6f4917fd149c..66d5a1250360 100644 --- a/tests/ui/option_as_ref_deref.rs +++ b/tests/ui/option_as_ref_deref.rs @@ -1,6 +1,6 @@ //@run-rustfix -#![allow(unused, clippy::redundant_clone)] +#![allow(unused, clippy::redundant_clone, clippy::useless_vec)] #![warn(clippy::option_as_ref_deref)] use std::ffi::{CString, OsString}; diff --git a/tests/ui/option_env_unwrap.rs b/tests/ui/option_env_unwrap.rs index ee1fe3f1fc0f..65a1b467f811 100644 --- a/tests/ui/option_env_unwrap.rs +++ b/tests/ui/option_env_unwrap.rs @@ -1,4 +1,4 @@ -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![warn(clippy::option_env_unwrap)] #![allow(clippy::map_flatten)] diff --git a/tests/ui/option_if_let_else.fixed b/tests/ui/option_if_let_else.fixed index 2b8ce5477cc6..8e59e4375d2e 100644 --- a/tests/ui/option_if_let_else.fixed +++ b/tests/ui/option_if_let_else.fixed @@ -208,3 +208,19 @@ fn issue9742() -> Option<&'static str> { _ => None, } } + +mod issue10729 { + #![allow(clippy::unit_arg, dead_code)] + + pub fn reproduce(initial: &Option) { + // 👇 needs `.as_ref()` because initial is an `&Option<_>` + initial.as_ref().map_or({}, |value| do_something(value)) + } + + pub fn reproduce2(initial: &mut Option) { + initial.as_mut().map_or({}, |value| do_something2(value)) + } + + fn do_something(_value: &str) {} + fn do_something2(_value: &mut str) {} +} diff --git a/tests/ui/option_if_let_else.rs b/tests/ui/option_if_let_else.rs index cfbec8cb27da..e72edf2a8e31 100644 --- a/tests/ui/option_if_let_else.rs +++ b/tests/ui/option_if_let_else.rs @@ -249,3 +249,25 @@ fn issue9742() -> Option<&'static str> { _ => None, } } + +mod issue10729 { + #![allow(clippy::unit_arg, dead_code)] + + pub fn reproduce(initial: &Option) { + // 👇 needs `.as_ref()` because initial is an `&Option<_>` + match initial { + Some(value) => do_something(value), + None => {}, + } + } + + pub fn reproduce2(initial: &mut Option) { + match initial { + Some(value) => do_something2(value), + None => {}, + } + } + + fn do_something(_value: &str) {} + fn do_something2(_value: &mut str) {} +} diff --git a/tests/ui/option_if_let_else.stderr b/tests/ui/option_if_let_else.stderr index 91d52fc79b81..aa2da2174003 100644 --- a/tests/ui/option_if_let_else.stderr +++ b/tests/ui/option_if_let_else.stderr @@ -271,5 +271,23 @@ error: use Option::map_or instead of an if let/else LL | let _ = if let Ok(a) = res { a + 1 } else { 5 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `res.map_or(5, |a| a + 1)` -error: aborting due to 21 previous errors +error: use Option::map_or instead of an if let/else + --> $DIR/option_if_let_else.rs:258:9 + | +LL | / match initial { +LL | | Some(value) => do_something(value), +LL | | None => {}, +LL | | } + | |_________^ help: try: `initial.as_ref().map_or({}, |value| do_something(value))` + +error: use Option::map_or instead of an if let/else + --> $DIR/option_if_let_else.rs:265:9 + | +LL | / match initial { +LL | | Some(value) => do_something2(value), +LL | | None => {}, +LL | | } + | |_________^ help: try: `initial.as_mut().map_or({}, |value| do_something2(value))` + +error: aborting due to 23 previous errors diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index f723a55f77f8..703debb7a26a 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -1,7 +1,13 @@ //@run-rustfix #![warn(clippy::or_fun_call)] #![allow(dead_code)] -#![allow(clippy::borrow_as_ptr, clippy::uninlined_format_args, clippy::unnecessary_wraps)] +#![allow( + clippy::borrow_as_ptr, + clippy::uninlined_format_args, + clippy::unnecessary_wraps, + clippy::unnecessary_literal_unwrap, + clippy::useless_vec +)] use std::collections::BTreeMap; use std::collections::HashMap; diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs index 61ef6e27f322..bb86fe0d45fa 100644 --- a/tests/ui/or_fun_call.rs +++ b/tests/ui/or_fun_call.rs @@ -1,7 +1,13 @@ //@run-rustfix #![warn(clippy::or_fun_call)] #![allow(dead_code)] -#![allow(clippy::borrow_as_ptr, clippy::uninlined_format_args, clippy::unnecessary_wraps)] +#![allow( + clippy::borrow_as_ptr, + clippy::uninlined_format_args, + clippy::unnecessary_wraps, + clippy::unnecessary_literal_unwrap, + clippy::useless_vec +)] use std::collections::BTreeMap; use std::collections::HashMap; diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr index ba3001db7a5f..0b5c686bec0d 100644 --- a/tests/ui/or_fun_call.stderr +++ b/tests/ui/or_fun_call.stderr @@ -1,5 +1,5 @@ error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:48:22 + --> $DIR/or_fun_call.rs:54:22 | LL | with_constructor.unwrap_or(make()); | ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(make)` @@ -7,163 +7,163 @@ LL | with_constructor.unwrap_or(make()); = note: `-D clippy::or-fun-call` implied by `-D warnings` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:51:14 + --> $DIR/or_fun_call.rs:57:14 | LL | with_new.unwrap_or(Vec::new()); | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:54:21 + --> $DIR/or_fun_call.rs:60:21 | LL | with_const_args.unwrap_or(Vec::with_capacity(12)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| Vec::with_capacity(12))` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:57:14 + --> $DIR/or_fun_call.rs:63:14 | LL | with_err.unwrap_or(make()); | ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| make())` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:60:19 + --> $DIR/or_fun_call.rs:66:19 | LL | with_err_args.unwrap_or(Vec::with_capacity(12)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| Vec::with_capacity(12))` error: use of `unwrap_or` followed by a call to `default` - --> $DIR/or_fun_call.rs:63:24 + --> $DIR/or_fun_call.rs:69:24 | LL | with_default_trait.unwrap_or(Default::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` error: use of `unwrap_or` followed by a call to `default` - --> $DIR/or_fun_call.rs:66:23 + --> $DIR/or_fun_call.rs:72:23 | LL | with_default_type.unwrap_or(u64::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:69:18 + --> $DIR/or_fun_call.rs:75:18 | LL | self_default.unwrap_or(::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(::default)` error: use of `unwrap_or` followed by a call to `default` - --> $DIR/or_fun_call.rs:72:18 + --> $DIR/or_fun_call.rs:78:18 | LL | real_default.unwrap_or(::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:75:14 + --> $DIR/or_fun_call.rs:81:14 | LL | with_vec.unwrap_or(vec![]); | ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:78:21 + --> $DIR/or_fun_call.rs:84:21 | LL | without_default.unwrap_or(Foo::new()); | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(Foo::new)` error: use of `or_insert` followed by a call to `new` - --> $DIR/or_fun_call.rs:81:19 + --> $DIR/or_fun_call.rs:87:19 | LL | map.entry(42).or_insert(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_default()` error: use of `or_insert` followed by a call to `new` - --> $DIR/or_fun_call.rs:84:23 + --> $DIR/or_fun_call.rs:90:23 | LL | map_vec.entry(42).or_insert(vec![]); | ^^^^^^^^^^^^^^^^^ help: try this: `or_default()` error: use of `or_insert` followed by a call to `new` - --> $DIR/or_fun_call.rs:87:21 + --> $DIR/or_fun_call.rs:93:21 | LL | btree.entry(42).or_insert(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_default()` error: use of `or_insert` followed by a call to `new` - --> $DIR/or_fun_call.rs:90:25 + --> $DIR/or_fun_call.rs:96:25 | LL | btree_vec.entry(42).or_insert(vec![]); | ^^^^^^^^^^^^^^^^^ help: try this: `or_default()` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:93:21 + --> $DIR/or_fun_call.rs:99:21 | LL | let _ = stringy.unwrap_or(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:101:21 + --> $DIR/or_fun_call.rs:107:21 | LL | let _ = Some(1).unwrap_or(map[&1]); | ^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| map[&1])` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:103:21 + --> $DIR/or_fun_call.rs:109:21 | LL | let _ = Some(1).unwrap_or(map[&1]); | ^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| map[&1])` error: use of `or` followed by a function call - --> $DIR/or_fun_call.rs:127:35 + --> $DIR/or_fun_call.rs:133:35 | LL | let _ = Some("a".to_string()).or(Some("b".to_string())); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some("b".to_string()))` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:166:14 + --> $DIR/or_fun_call.rs:172:14 | LL | None.unwrap_or(ptr_to_ref(s)); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| ptr_to_ref(s))` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:172:14 + --> $DIR/or_fun_call.rs:178:14 | LL | None.unwrap_or(unsafe { ptr_to_ref(s) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:174:14 + --> $DIR/or_fun_call.rs:180:14 | LL | None.unwrap_or( unsafe { ptr_to_ref(s) } ); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:188:14 + --> $DIR/or_fun_call.rs:194:14 | LL | .unwrap_or(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:201:14 + --> $DIR/or_fun_call.rs:207:14 | LL | .unwrap_or(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:213:14 + --> $DIR/or_fun_call.rs:219:14 | LL | .unwrap_or(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:224:10 + --> $DIR/or_fun_call.rs:230:10 | LL | .unwrap_or(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` error: use of `map_or` followed by a function call - --> $DIR/or_fun_call.rs:249:25 + --> $DIR/or_fun_call.rs:255:25 | LL | let _ = Some(4).map_or(g(), |v| v); | ^^^^^^^^^^^^^^^^^^ help: try this: `map_or_else(g, |v| v)` error: use of `map_or` followed by a function call - --> $DIR/or_fun_call.rs:250:25 + --> $DIR/or_fun_call.rs:256:25 | LL | let _ = Some(4).map_or(g(), f); | ^^^^^^^^^^^^^^ help: try this: `map_or_else(g, f)` diff --git a/tests/ui/or_then_unwrap.fixed b/tests/ui/or_then_unwrap.fixed index 40badac4424a..773dfc3c5d14 100644 --- a/tests/ui/or_then_unwrap.fixed +++ b/tests/ui/or_then_unwrap.fixed @@ -1,7 +1,7 @@ //@run-rustfix #![warn(clippy::or_then_unwrap)] -#![allow(clippy::map_identity, clippy::let_unit_value)] +#![allow(clippy::map_identity, clippy::let_unit_value, clippy::unnecessary_literal_unwrap)] struct SomeStruct; impl SomeStruct { diff --git a/tests/ui/or_then_unwrap.rs b/tests/ui/or_then_unwrap.rs index 76c9942fe6c1..5867e014878e 100644 --- a/tests/ui/or_then_unwrap.rs +++ b/tests/ui/or_then_unwrap.rs @@ -1,7 +1,7 @@ //@run-rustfix #![warn(clippy::or_then_unwrap)] -#![allow(clippy::map_identity, clippy::let_unit_value)] +#![allow(clippy::map_identity, clippy::let_unit_value, clippy::unnecessary_literal_unwrap)] struct SomeStruct; impl SomeStruct { diff --git a/tests/ui/overflow_check_conditional.rs b/tests/ui/overflow_check_conditional.rs index e1e30114081e..14a6b98d07d1 100644 --- a/tests/ui/overflow_check_conditional.rs +++ b/tests/ui/overflow_check_conditional.rs @@ -1,4 +1,5 @@ #![warn(clippy::overflow_check_conditional)] +#![allow(clippy::needless_if)] fn test(a: u32, b: u32, c: u32) { if a + b < a {} diff --git a/tests/ui/overflow_check_conditional.stderr b/tests/ui/overflow_check_conditional.stderr index 92d1d8ef911e..3ec2298f828a 100644 --- a/tests/ui/overflow_check_conditional.stderr +++ b/tests/ui/overflow_check_conditional.stderr @@ -1,5 +1,5 @@ error: you are trying to use classic C overflow conditions that will fail in Rust - --> $DIR/overflow_check_conditional.rs:4:8 + --> $DIR/overflow_check_conditional.rs:5:8 | LL | if a + b < a {} | ^^^^^^^^^ @@ -7,43 +7,43 @@ LL | if a + b < a {} = note: `-D clippy::overflow-check-conditional` implied by `-D warnings` error: you are trying to use classic C overflow conditions that will fail in Rust - --> $DIR/overflow_check_conditional.rs:5:8 + --> $DIR/overflow_check_conditional.rs:6:8 | LL | if a > a + b {} | ^^^^^^^^^ error: you are trying to use classic C overflow conditions that will fail in Rust - --> $DIR/overflow_check_conditional.rs:6:8 + --> $DIR/overflow_check_conditional.rs:7:8 | LL | if a + b < b {} | ^^^^^^^^^ error: you are trying to use classic C overflow conditions that will fail in Rust - --> $DIR/overflow_check_conditional.rs:7:8 + --> $DIR/overflow_check_conditional.rs:8:8 | LL | if b > a + b {} | ^^^^^^^^^ error: you are trying to use classic C underflow conditions that will fail in Rust - --> $DIR/overflow_check_conditional.rs:8:8 + --> $DIR/overflow_check_conditional.rs:9:8 | LL | if a - b > b {} | ^^^^^^^^^ error: you are trying to use classic C underflow conditions that will fail in Rust - --> $DIR/overflow_check_conditional.rs:9:8 + --> $DIR/overflow_check_conditional.rs:10:8 | LL | if b < a - b {} | ^^^^^^^^^ error: you are trying to use classic C underflow conditions that will fail in Rust - --> $DIR/overflow_check_conditional.rs:10:8 + --> $DIR/overflow_check_conditional.rs:11:8 | LL | if a - b > a {} | ^^^^^^^^^ error: you are trying to use classic C underflow conditions that will fail in Rust - --> $DIR/overflow_check_conditional.rs:11:8 + --> $DIR/overflow_check_conditional.rs:12:8 | LL | if a < a - b {} | ^^^^^^^^^ diff --git a/tests/ui/partialeq_to_none.fixed b/tests/ui/partialeq_to_none.fixed index 2df87a26d6d1..95e184b1de6c 100644 --- a/tests/ui/partialeq_to_none.fixed +++ b/tests/ui/partialeq_to_none.fixed @@ -1,6 +1,6 @@ //@run-rustfix #![warn(clippy::partialeq_to_none)] -#![allow(clippy::eq_op)] +#![allow(clippy::eq_op, clippy::needless_if)] struct Foobar; diff --git a/tests/ui/partialeq_to_none.rs b/tests/ui/partialeq_to_none.rs index df6233b9afd6..4fa50dcc11b6 100644 --- a/tests/ui/partialeq_to_none.rs +++ b/tests/ui/partialeq_to_none.rs @@ -1,6 +1,6 @@ //@run-rustfix #![warn(clippy::partialeq_to_none)] -#![allow(clippy::eq_op)] +#![allow(clippy::eq_op, clippy::needless_if)] struct Foobar; diff --git a/tests/ui/patterns.fixed b/tests/ui/patterns.fixed index a1da47d84fd5..714143e75869 100644 --- a/tests/ui/patterns.fixed +++ b/tests/ui/patterns.fixed @@ -1,8 +1,12 @@ //@run-rustfix +//@aux-build:proc_macros.rs:proc-macro #![warn(clippy::all)] #![allow(unused)] #![allow(clippy::uninlined_format_args)] +#[macro_use] +extern crate proc_macros; + fn main() { let v = Some(true); let s = [0, 1, 2, 3, 4]; @@ -34,4 +38,11 @@ fn main() { ref x => println!("vec: {:?}", x), ref y if y == &vec![0] => (), } + external! { + let v = Some(true); + match v { + Some(x) => (), + y @ _ => (), + } + } } diff --git a/tests/ui/patterns.rs b/tests/ui/patterns.rs index 399066b813e3..153e26407017 100644 --- a/tests/ui/patterns.rs +++ b/tests/ui/patterns.rs @@ -1,8 +1,12 @@ //@run-rustfix +//@aux-build:proc_macros.rs:proc-macro #![warn(clippy::all)] #![allow(unused)] #![allow(clippy::uninlined_format_args)] +#[macro_use] +extern crate proc_macros; + fn main() { let v = Some(true); let s = [0, 1, 2, 3, 4]; @@ -34,4 +38,11 @@ fn main() { ref x @ _ => println!("vec: {:?}", x), ref y if y == &vec![0] => (), } + external! { + let v = Some(true); + match v { + Some(x) => (), + y @ _ => (), + } + } } diff --git a/tests/ui/patterns.stderr b/tests/ui/patterns.stderr index 2c46b4eb593e..276330d21c42 100644 --- a/tests/ui/patterns.stderr +++ b/tests/ui/patterns.stderr @@ -1,5 +1,5 @@ error: the `y @ _` pattern can be written as just `y` - --> $DIR/patterns.rs:11:9 + --> $DIR/patterns.rs:15:9 | LL | y @ _ => (), | ^^^^^ help: try: `y` @@ -7,13 +7,13 @@ LL | y @ _ => (), = note: `-D clippy::redundant-pattern` implied by `-D warnings` error: the `x @ _` pattern can be written as just `x` - --> $DIR/patterns.rs:26:9 + --> $DIR/patterns.rs:30:9 | LL | ref mut x @ _ => { | ^^^^^^^^^^^^^ help: try: `ref mut x` error: the `x @ _` pattern can be written as just `x` - --> $DIR/patterns.rs:34:9 + --> $DIR/patterns.rs:38:9 | LL | ref x @ _ => println!("vec: {:?}", x), | ^^^^^^^^^ help: try: `ref x` diff --git a/tests/ui/print_with_newline.fixed b/tests/ui/print_with_newline.fixed new file mode 100644 index 000000000000..6098dea39911 --- /dev/null +++ b/tests/ui/print_with_newline.fixed @@ -0,0 +1,58 @@ +// FIXME: Ideally these suggestions would be fixed via rustfix. Blocked by rust-lang/rust#53934 +//@run-rustfix + +#![allow(clippy::print_literal)] +#![warn(clippy::print_with_newline)] + +fn main() { + println!("Hello"); + println!("Hello {}", "world"); + println!("Hello {} {}", "world", "#2"); + println!("{}", 1265); + println!(); + + // these are all fine + print!(""); + print!("Hello"); + println!("Hello"); + println!("Hello\n"); + println!("Hello {}\n", "world"); + print!("Issue\n{}", 1265); + print!("{}", 1265); + print!("\n{}", 1275); + print!("\n\n"); + print!("like eof\n\n"); + print!("Hello {} {}\n\n", "world", "#2"); + println!("\ndon't\nwarn\nfor\nmultiple\nnewlines\n"); // #3126 + println!("\nbla\n\n"); // #3126 + + // Escaping + print!("\\n"); // #3514 + println!("\\"); // should fail + print!("\\\\n"); + + // Raw strings + print!(r"\n"); // #3778 + + // Literal newlines should also fail + println!( + + ); + println!( + + ); + + // Don't warn on CRLF (#4208) + print!("\r\n"); + print!("foo\r\n"); + println!("\\r"); // should fail + print!("foo\rbar\n"); + + // Ignore expanded format strings + macro_rules! newline { + () => { + "\n" + }; + } + print!(newline!()); +} diff --git a/tests/ui/print_with_newline.rs b/tests/ui/print_with_newline.rs index ff79ca75ffaa..d9c7acc27480 100644 --- a/tests/ui/print_with_newline.rs +++ b/tests/ui/print_with_newline.rs @@ -47,7 +47,7 @@ fn main() { // Don't warn on CRLF (#4208) print!("\r\n"); print!("foo\r\n"); - print!("\\r\n"); //~ ERROR + print!("\\r\n"); // should fail print!("foo\rbar\n"); // Ignore expanded format strings diff --git a/tests/ui/print_with_newline.stderr b/tests/ui/print_with_newline.stderr index b9f5675faec7..b97711e777dd 100644 --- a/tests/ui/print_with_newline.stderr +++ b/tests/ui/print_with_newline.stderr @@ -62,13 +62,13 @@ LL + println!(); error: using `print!()` with a format string that ends in a single newline --> $DIR/print_with_newline.rs:31:5 | -LL | print!("//n"); // should fail +LL | print!("///n"); // should fail | ^^^^^^^^^^^^^^ | help: use `println!` instead | -LL - print!("//n"); // should fail -LL + println!("/"); // should fail +LL - print!("///n"); // should fail +LL + println!("//"); // should fail | error: using `print!()` with a format string that ends in a single newline @@ -104,13 +104,13 @@ LL ~ error: using `print!()` with a format string that ends in a single newline --> $DIR/print_with_newline.rs:50:5 | -LL | print!("/r/n"); //~ ERROR +LL | print!("//r/n"); // should fail | ^^^^^^^^^^^^^^^ | help: use `println!` instead | -LL - print!("/r/n"); //~ ERROR -LL + println!("/r"); //~ ERROR +LL - print!("//r/n"); // should fail +LL + println!("//r"); // should fail | error: aborting due to 9 previous errors diff --git a/tests/ui/proc_macro.rs b/tests/ui/proc_macro.rs index 59914b8b8f62..b77874034d0b 100644 --- a/tests/ui/proc_macro.rs +++ b/tests/ui/proc_macro.rs @@ -1,5 +1,4 @@ //! Check that we correctly lint procedural macros. -#![crate_type = "proc-macro"] extern crate proc_macro; diff --git a/tests/ui/proc_macro.stderr b/tests/ui/proc_macro.stderr index c795f6ad0d25..d912b5027551 100644 --- a/tests/ui/proc_macro.stderr +++ b/tests/ui/proc_macro.stderr @@ -1,5 +1,5 @@ error: approximate value of `f{32, 64}::consts::PI` found - --> $DIR/proc_macro.rs:10:14 + --> $DIR/proc_macro.rs:9:14 | LL | let _x = 3.14; | ^^^^ diff --git a/tests/ui/ptr_arg.rs b/tests/ui/ptr_arg.rs index 5f54101ca15a..709f74ee6aa2 100644 --- a/tests/ui/ptr_arg.rs +++ b/tests/ui/ptr_arg.rs @@ -1,5 +1,10 @@ #![feature(lint_reasons)] -#![allow(unused, clippy::many_single_char_names, clippy::redundant_clone)] +#![allow( + unused, + clippy::many_single_char_names, + clippy::needless_lifetimes, + clippy::redundant_clone +)] #![warn(clippy::ptr_arg)] use std::borrow::Cow; @@ -235,3 +240,29 @@ fn dyn_trait(a: &mut Vec, b: &mut String, c: &mut PathBuf) { takes_dyn(b); takes_dyn(c); } + +mod issue_9218 { + use std::borrow::Cow; + + fn cow_non_elided_lifetime<'a>(input: &Cow<'a, str>) -> &'a str { + todo!() + } + + // This one has an anonymous lifetime so it's not okay + fn cow_elided_lifetime<'a>(input: &'a Cow) -> &'a str { + todo!() + } + + // These two's return types don't use use 'a so it's not okay + fn cow_bad_ret_ty_1<'a>(input: &'a Cow<'a, str>) -> &'static str { + todo!() + } + fn cow_bad_ret_ty_2<'a, 'b>(input: &'a Cow<'a, str>) -> &'b str { + todo!() + } + + // Inferred to be `&'a str`, afaik. + fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &str { + todo!() + } +} diff --git a/tests/ui/ptr_arg.stderr b/tests/ui/ptr_arg.stderr index 6b4de98ce88c..d663b070b9cf 100644 --- a/tests/ui/ptr_arg.stderr +++ b/tests/ui/ptr_arg.stderr @@ -1,5 +1,5 @@ error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:8:14 + --> $DIR/ptr_arg.rs:13:14 | LL | fn do_vec(x: &Vec) { | ^^^^^^^^^ help: change this to: `&[i64]` @@ -7,43 +7,43 @@ LL | fn do_vec(x: &Vec) { = note: `-D clippy::ptr-arg` implied by `-D warnings` error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:12:18 + --> $DIR/ptr_arg.rs:17:18 | LL | fn do_vec_mut(x: &mut Vec) { | ^^^^^^^^^^^^^ help: change this to: `&mut [i64]` error: writing `&String` instead of `&str` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:16:14 + --> $DIR/ptr_arg.rs:21:14 | LL | fn do_str(x: &String) { | ^^^^^^^ help: change this to: `&str` error: writing `&mut String` instead of `&mut str` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:20:18 + --> $DIR/ptr_arg.rs:25:18 | LL | fn do_str_mut(x: &mut String) { | ^^^^^^^^^^^ help: change this to: `&mut str` error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:24:15 + --> $DIR/ptr_arg.rs:29:15 | LL | fn do_path(x: &PathBuf) { | ^^^^^^^^ help: change this to: `&Path` error: writing `&mut PathBuf` instead of `&mut Path` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:28:19 + --> $DIR/ptr_arg.rs:33:19 | LL | fn do_path_mut(x: &mut PathBuf) { | ^^^^^^^^^^^^ help: change this to: `&mut Path` error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:36:18 + --> $DIR/ptr_arg.rs:41:18 | LL | fn do_vec(x: &Vec); | ^^^^^^^^^ help: change this to: `&[i64]` error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:49:14 + --> $DIR/ptr_arg.rs:54:14 | LL | fn cloned(x: &Vec) -> Vec { | ^^^^^^^^ @@ -60,7 +60,7 @@ LL ~ x.to_owned() | error: writing `&String` instead of `&str` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:58:18 + --> $DIR/ptr_arg.rs:63:18 | LL | fn str_cloned(x: &String) -> String { | ^^^^^^^ @@ -76,7 +76,7 @@ LL ~ x.to_owned() | error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:66:19 + --> $DIR/ptr_arg.rs:71:19 | LL | fn path_cloned(x: &PathBuf) -> PathBuf { | ^^^^^^^^ @@ -92,7 +92,7 @@ LL ~ x.to_path_buf() | error: writing `&String` instead of `&str` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:74:44 + --> $DIR/ptr_arg.rs:79:44 | LL | fn false_positive_capacity(x: &Vec, y: &String) { | ^^^^^^^ @@ -106,19 +106,19 @@ LL ~ let c = y; | error: using a reference to `Cow` is not recommended - --> $DIR/ptr_arg.rs:88:25 + --> $DIR/ptr_arg.rs:93:25 | LL | fn test_cow_with_ref(c: &Cow<[i32]>) {} | ^^^^^^^^^^^ help: change this to: `&[i32]` error: writing `&String` instead of `&str` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:117:66 + --> $DIR/ptr_arg.rs:122:66 | LL | fn some_allowed(#[allow(clippy::ptr_arg)] _v: &Vec, _s: &String) {} | ^^^^^^^ help: change this to: `&str` error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:146:21 + --> $DIR/ptr_arg.rs:151:21 | LL | fn foo_vec(vec: &Vec) { | ^^^^^^^^ @@ -131,7 +131,7 @@ LL ~ let _ = vec.to_owned().clone(); | error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:151:23 + --> $DIR/ptr_arg.rs:156:23 | LL | fn foo_path(path: &PathBuf) { | ^^^^^^^^ @@ -144,7 +144,7 @@ LL ~ let _ = path.to_path_buf().clone(); | error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:156:21 + --> $DIR/ptr_arg.rs:161:21 | LL | fn foo_str(str: &PathBuf) { | ^^^^^^^^ @@ -157,28 +157,46 @@ LL ~ let _ = str.to_path_buf().clone(); | error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:162:29 + --> $DIR/ptr_arg.rs:167:29 | LL | fn mut_vec_slice_methods(v: &mut Vec) { | ^^^^^^^^^^^^^ help: change this to: `&mut [u32]` error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:224:17 + --> $DIR/ptr_arg.rs:229:17 | LL | fn dyn_trait(a: &mut Vec, b: &mut String, c: &mut PathBuf) { | ^^^^^^^^^^^^^ help: change this to: `&mut [u32]` error: writing `&mut String` instead of `&mut str` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:224:35 + --> $DIR/ptr_arg.rs:229:35 | LL | fn dyn_trait(a: &mut Vec, b: &mut String, c: &mut PathBuf) { | ^^^^^^^^^^^ help: change this to: `&mut str` error: writing `&mut PathBuf` instead of `&mut Path` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:224:51 + --> $DIR/ptr_arg.rs:229:51 | LL | fn dyn_trait(a: &mut Vec, b: &mut String, c: &mut PathBuf) { | ^^^^^^^^^^^^ help: change this to: `&mut Path` -error: aborting due to 20 previous errors +error: using a reference to `Cow` is not recommended + --> $DIR/ptr_arg.rs:252:39 + | +LL | fn cow_elided_lifetime<'a>(input: &'a Cow) -> &'a str { + | ^^^^^^^^^^^^ help: change this to: `&str` + +error: using a reference to `Cow` is not recommended + --> $DIR/ptr_arg.rs:257:36 + | +LL | fn cow_bad_ret_ty_1<'a>(input: &'a Cow<'a, str>) -> &'static str { + | ^^^^^^^^^^^^^^^^ help: change this to: `&str` + +error: using a reference to `Cow` is not recommended + --> $DIR/ptr_arg.rs:260:40 + | +LL | fn cow_bad_ret_ty_2<'a, 'b>(input: &'a Cow<'a, str>) -> &'b str { + | ^^^^^^^^^^^^^^^^ help: change this to: `&str` + +error: aborting due to 23 previous errors diff --git a/tests/ui/ptr_as_ptr.fixed b/tests/ui/ptr_as_ptr.fixed index 2c2567d67cd9..26a64c861cf4 100644 --- a/tests/ui/ptr_as_ptr.fixed +++ b/tests/ui/ptr_as_ptr.fixed @@ -1,5 +1,5 @@ //@run-rustfix -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![warn(clippy::ptr_as_ptr)] diff --git a/tests/ui/ptr_as_ptr.rs b/tests/ui/ptr_as_ptr.rs index 6000e5c08acb..ea40d4947331 100644 --- a/tests/ui/ptr_as_ptr.rs +++ b/tests/ui/ptr_as_ptr.rs @@ -1,5 +1,5 @@ //@run-rustfix -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![warn(clippy::ptr_as_ptr)] diff --git a/tests/ui/ptr_cast_constness.fixed b/tests/ui/ptr_cast_constness.fixed index 24de573d0838..1ef1809d1530 100644 --- a/tests/ui/ptr_cast_constness.fixed +++ b/tests/ui/ptr_cast_constness.fixed @@ -1,18 +1,25 @@ //@run-rustfix -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![warn(clippy::ptr_cast_constness)] +#![allow(clippy::transmute_ptr_to_ref, clippy::unnecessary_cast, unused)] extern crate proc_macros; use proc_macros::{external, inline_macros}; +unsafe fn ptr_to_ref(p: *const T, om: *mut U) { + let _: &mut T = std::mem::transmute(p.cast_mut()); + let _ = &mut *p.cast_mut(); + let _: &T = &*(om as *const T); +} + #[inline_macros] fn main() { let ptr: *const u32 = &42_u32; let mut_ptr: *mut u32 = &mut 42_u32; - let _ = ptr as *const i32; - let _ = mut_ptr as *mut i32; + let _ = ptr as *const u32; + let _ = mut_ptr as *mut u32; // Make sure the lint can handle the difference in their operator precedences. unsafe { @@ -29,10 +36,10 @@ fn main() { let _ = ptr_of_array as *const dyn std::fmt::Debug; // Make sure the lint is triggered inside a macro - let _ = inline!($ptr as *const i32); + let _ = inline!($ptr as *const u32); // Do not lint inside macros from external crates - let _ = external!($ptr as *const i32); + let _ = external!($ptr as *const u32); } #[clippy::msrv = "1.64"] @@ -41,8 +48,8 @@ fn _msrv_1_64() { let mut_ptr: *mut u32 = &mut 42_u32; // `pointer::cast_const` and `pointer::cast_mut` were stabilized in 1.65. Do not lint this - let _ = ptr as *mut i32; - let _ = mut_ptr as *const i32; + let _ = ptr as *mut u32; + let _ = mut_ptr as *const u32; } #[clippy::msrv = "1.65"] diff --git a/tests/ui/ptr_cast_constness.rs b/tests/ui/ptr_cast_constness.rs index 63d973a9fca8..2c15cd429daf 100644 --- a/tests/ui/ptr_cast_constness.rs +++ b/tests/ui/ptr_cast_constness.rs @@ -1,27 +1,34 @@ //@run-rustfix -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![warn(clippy::ptr_cast_constness)] +#![allow(clippy::transmute_ptr_to_ref, clippy::unnecessary_cast, unused)] extern crate proc_macros; use proc_macros::{external, inline_macros}; +unsafe fn ptr_to_ref(p: *const T, om: *mut U) { + let _: &mut T = std::mem::transmute(p as *mut T); + let _ = &mut *(p as *mut T); + let _: &T = &*(om as *const T); +} + #[inline_macros] fn main() { let ptr: *const u32 = &42_u32; let mut_ptr: *mut u32 = &mut 42_u32; - let _ = ptr as *const i32; - let _ = mut_ptr as *mut i32; + let _ = ptr as *const u32; + let _ = mut_ptr as *mut u32; // Make sure the lint can handle the difference in their operator precedences. unsafe { let ptr_ptr: *const *const u32 = &ptr; - let _ = *ptr_ptr as *mut i32; + let _ = *ptr_ptr as *mut u32; } - let _ = ptr as *mut i32; - let _ = mut_ptr as *const i32; + let _ = ptr as *mut u32; + let _ = mut_ptr as *const u32; // Lint this, since pointer::cast_mut and pointer::cast_const have ?Sized let ptr_of_array: *const [u32; 4] = &[1, 2, 3, 4]; @@ -29,10 +36,10 @@ fn main() { let _ = ptr_of_array as *const dyn std::fmt::Debug; // Make sure the lint is triggered inside a macro - let _ = inline!($ptr as *const i32); + let _ = inline!($ptr as *const u32); // Do not lint inside macros from external crates - let _ = external!($ptr as *const i32); + let _ = external!($ptr as *const u32); } #[clippy::msrv = "1.64"] @@ -41,8 +48,8 @@ fn _msrv_1_64() { let mut_ptr: *mut u32 = &mut 42_u32; // `pointer::cast_const` and `pointer::cast_mut` were stabilized in 1.65. Do not lint this - let _ = ptr as *mut i32; - let _ = mut_ptr as *const i32; + let _ = ptr as *mut u32; + let _ = mut_ptr as *const u32; } #[clippy::msrv = "1.65"] @@ -50,6 +57,6 @@ fn _msrv_1_65() { let ptr: *const u32 = &42_u32; let mut_ptr: *mut u32 = &mut 42_u32; - let _ = ptr as *mut i32; - let _ = mut_ptr as *const i32; + let _ = ptr as *mut u32; + let _ = mut_ptr as *const u32; } diff --git a/tests/ui/ptr_cast_constness.stderr b/tests/ui/ptr_cast_constness.stderr index 43816c87c190..0c3ff863685b 100644 --- a/tests/ui/ptr_cast_constness.stderr +++ b/tests/ui/ptr_cast_constness.stderr @@ -1,34 +1,46 @@ -error: `as` casting between raw pointers while changing its constness - --> $DIR/ptr_cast_constness.rs:20:17 +error: `as` casting between raw pointers while changing only its constness + --> $DIR/ptr_cast_constness.rs:11:41 | -LL | let _ = *ptr_ptr as *mut i32; - | ^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `(*ptr_ptr).cast_mut()` +LL | let _: &mut T = std::mem::transmute(p as *mut T); + | ^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `p.cast_mut()` | = note: `-D clippy::ptr-cast-constness` implied by `-D warnings` -error: `as` casting between raw pointers while changing its constness - --> $DIR/ptr_cast_constness.rs:23:13 +error: `as` casting between raw pointers while changing only its constness + --> $DIR/ptr_cast_constness.rs:12:19 | -LL | let _ = ptr as *mut i32; +LL | let _ = &mut *(p as *mut T); + | ^^^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `p.cast_mut()` + +error: `as` casting between raw pointers while changing only its constness + --> $DIR/ptr_cast_constness.rs:27:17 + | +LL | let _ = *ptr_ptr as *mut u32; + | ^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `(*ptr_ptr).cast_mut()` + +error: `as` casting between raw pointers while changing only its constness + --> $DIR/ptr_cast_constness.rs:30:13 + | +LL | let _ = ptr as *mut u32; | ^^^^^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `ptr.cast_mut()` -error: `as` casting between raw pointers while changing its constness - --> $DIR/ptr_cast_constness.rs:24:13 +error: `as` casting between raw pointers while changing only its constness + --> $DIR/ptr_cast_constness.rs:31:13 | -LL | let _ = mut_ptr as *const i32; +LL | let _ = mut_ptr as *const u32; | ^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast_const`, a safer alternative: `mut_ptr.cast_const()` -error: `as` casting between raw pointers while changing its constness - --> $DIR/ptr_cast_constness.rs:53:13 +error: `as` casting between raw pointers while changing only its constness + --> $DIR/ptr_cast_constness.rs:60:13 | -LL | let _ = ptr as *mut i32; +LL | let _ = ptr as *mut u32; | ^^^^^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `ptr.cast_mut()` -error: `as` casting between raw pointers while changing its constness - --> $DIR/ptr_cast_constness.rs:54:13 +error: `as` casting between raw pointers while changing only its constness + --> $DIR/ptr_cast_constness.rs:61:13 | -LL | let _ = mut_ptr as *const i32; +LL | let _ = mut_ptr as *const u32; | ^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast_const`, a safer alternative: `mut_ptr.cast_const()` -error: aborting due to 5 previous errors +error: aborting due to 7 previous errors diff --git a/tests/ui/ptr_offset_with_cast.fixed b/tests/ui/ptr_offset_with_cast.fixed index f69bc131898f..6ffa401d7617 100644 --- a/tests/ui/ptr_offset_with_cast.fixed +++ b/tests/ui/ptr_offset_with_cast.fixed @@ -1,5 +1,5 @@ //@run-rustfix -#![allow(clippy::unnecessary_cast)] +#![allow(clippy::unnecessary_cast, clippy::useless_vec)] fn main() { let vec = vec![b'a', b'b', b'c']; diff --git a/tests/ui/ptr_offset_with_cast.rs b/tests/ui/ptr_offset_with_cast.rs index eae36c27729e..de1f86cb855c 100644 --- a/tests/ui/ptr_offset_with_cast.rs +++ b/tests/ui/ptr_offset_with_cast.rs @@ -1,5 +1,5 @@ //@run-rustfix -#![allow(clippy::unnecessary_cast)] +#![allow(clippy::unnecessary_cast, clippy::useless_vec)] fn main() { let vec = vec![b'a', b'b', b'c']; diff --git a/tests/ui/pub_with_shorthand.fixed b/tests/ui/pub_with_shorthand.fixed new file mode 100644 index 000000000000..a774faa0a673 --- /dev/null +++ b/tests/ui/pub_with_shorthand.fixed @@ -0,0 +1,38 @@ +//@run-rustfix +//@aux-build:proc_macros.rs:proc-macro +#![feature(custom_inner_attributes)] +#![allow(clippy::needless_pub_self, unused)] +#![warn(clippy::pub_with_shorthand)] +#![no_main] +#![rustfmt::skip] // rustfmt will remove `in`, understandable + // but very annoying for our purposes! + +#[macro_use] +extern crate proc_macros; + +pub(in self) fn a() {} +pub(in self) fn b() {} + +pub fn c() {} +mod a { + pub(in super) fn d() {} + pub(in super) fn e() {} + pub(in self) fn f() {} + pub(in crate) fn k() {} + pub(in crate) fn m() {} + mod b { + pub(in crate::a) fn l() {} + } +} + +external! { + pub(self) fn g() {} + pub(in self) fn h() {} +} +with_span! { + span + pub(self) fn i() {} + pub(in self) fn j() {} +} + +// not really anything more to test. just a really simple lint overall diff --git a/tests/ui/pub_with_shorthand.rs b/tests/ui/pub_with_shorthand.rs new file mode 100644 index 000000000000..4a4bbc18728e --- /dev/null +++ b/tests/ui/pub_with_shorthand.rs @@ -0,0 +1,38 @@ +//@run-rustfix +//@aux-build:proc_macros.rs:proc-macro +#![feature(custom_inner_attributes)] +#![allow(clippy::needless_pub_self, unused)] +#![warn(clippy::pub_with_shorthand)] +#![no_main] +#![rustfmt::skip] // rustfmt will remove `in`, understandable + // but very annoying for our purposes! + +#[macro_use] +extern crate proc_macros; + +pub(self) fn a() {} +pub(in self) fn b() {} + +pub fn c() {} +mod a { + pub(in super) fn d() {} + pub(super) fn e() {} + pub(self) fn f() {} + pub(crate) fn k() {} + pub(in crate) fn m() {} + mod b { + pub(in crate::a) fn l() {} + } +} + +external! { + pub(self) fn g() {} + pub(in self) fn h() {} +} +with_span! { + span + pub(self) fn i() {} + pub(in self) fn j() {} +} + +// not really anything more to test. just a really simple lint overall diff --git a/tests/ui/pub_with_shorthand.stderr b/tests/ui/pub_with_shorthand.stderr new file mode 100644 index 000000000000..323b5a23b247 --- /dev/null +++ b/tests/ui/pub_with_shorthand.stderr @@ -0,0 +1,28 @@ +error: usage of `pub` without `in` + --> $DIR/pub_with_shorthand.rs:13:1 + | +LL | pub(self) fn a() {} + | ^^^^^^^^^ help: add it: `pub(in self)` + | + = note: `-D clippy::pub-with-shorthand` implied by `-D warnings` + +error: usage of `pub` without `in` + --> $DIR/pub_with_shorthand.rs:19:5 + | +LL | pub(super) fn e() {} + | ^^^^^^^^^^ help: add it: `pub(in super)` + +error: usage of `pub` without `in` + --> $DIR/pub_with_shorthand.rs:20:5 + | +LL | pub(self) fn f() {} + | ^^^^^^^^^ help: add it: `pub(in self)` + +error: usage of `pub` without `in` + --> $DIR/pub_with_shorthand.rs:21:5 + | +LL | pub(crate) fn k() {} + | ^^^^^^^^^^ help: add it: `pub(in crate)` + +error: aborting due to 4 previous errors + diff --git a/tests/ui/pub_without_shorthand.fixed b/tests/ui/pub_without_shorthand.fixed new file mode 100644 index 000000000000..fdb49ac4d906 --- /dev/null +++ b/tests/ui/pub_without_shorthand.fixed @@ -0,0 +1,38 @@ +//@run-rustfix +//@aux-build:proc_macros.rs:proc-macro +#![feature(custom_inner_attributes)] +#![allow(clippy::needless_pub_self, unused)] +#![warn(clippy::pub_without_shorthand)] +#![no_main] +#![rustfmt::skip] // rustfmt will remove `in`, understandable + // but very annoying for our purposes! + +#[macro_use] +extern crate proc_macros; + +pub(self) fn a() {} +pub(self) fn b() {} + +pub fn c() {} +mod a { + pub(super) fn d() {} + pub(super) fn e() {} + pub(self) fn f() {} + pub(crate) fn k() {} + pub(crate) fn m() {} + mod b { + pub(in crate::a) fn l() {} + } +} + +external! { + pub(self) fn g() {} + pub(in self) fn h() {} +} +with_span! { + span + pub(self) fn i() {} + pub(in self) fn j() {} +} + +// not really anything more to test. just a really simple lint overall diff --git a/tests/ui/pub_without_shorthand.rs b/tests/ui/pub_without_shorthand.rs new file mode 100644 index 000000000000..1f2ef7ece391 --- /dev/null +++ b/tests/ui/pub_without_shorthand.rs @@ -0,0 +1,38 @@ +//@run-rustfix +//@aux-build:proc_macros.rs:proc-macro +#![feature(custom_inner_attributes)] +#![allow(clippy::needless_pub_self, unused)] +#![warn(clippy::pub_without_shorthand)] +#![no_main] +#![rustfmt::skip] // rustfmt will remove `in`, understandable + // but very annoying for our purposes! + +#[macro_use] +extern crate proc_macros; + +pub(self) fn a() {} +pub(in self) fn b() {} + +pub fn c() {} +mod a { + pub(in super) fn d() {} + pub(super) fn e() {} + pub(self) fn f() {} + pub(crate) fn k() {} + pub(in crate) fn m() {} + mod b { + pub(in crate::a) fn l() {} + } +} + +external! { + pub(self) fn g() {} + pub(in self) fn h() {} +} +with_span! { + span + pub(self) fn i() {} + pub(in self) fn j() {} +} + +// not really anything more to test. just a really simple lint overall diff --git a/tests/ui/pub_without_shorthand.stderr b/tests/ui/pub_without_shorthand.stderr new file mode 100644 index 000000000000..a18c9bf89344 --- /dev/null +++ b/tests/ui/pub_without_shorthand.stderr @@ -0,0 +1,22 @@ +error: usage of `pub` with `in` + --> $DIR/pub_without_shorthand.rs:14:1 + | +LL | pub(in self) fn b() {} + | ^^^^^^^^^^^^ help: remove it: `pub(self)` + | + = note: `-D clippy::pub-without-shorthand` implied by `-D warnings` + +error: usage of `pub` with `in` + --> $DIR/pub_without_shorthand.rs:18:5 + | +LL | pub(in super) fn d() {} + | ^^^^^^^^^^^^^ help: remove it: `pub(super)` + +error: usage of `pub` with `in` + --> $DIR/pub_without_shorthand.rs:22:5 + | +LL | pub(in crate) fn m() {} + | ^^^^^^^^^^^^^ help: remove it: `pub(crate)` + +error: aborting due to 3 previous errors + diff --git a/tests/ui/question_mark.fixed b/tests/ui/question_mark.fixed index 7f1660f31fa5..2d8920ccc42f 100644 --- a/tests/ui/question_mark.fixed +++ b/tests/ui/question_mark.fixed @@ -1,4 +1,5 @@ //@run-rustfix +#![feature(try_blocks)] #![allow(unreachable_code)] #![allow(dead_code)] #![allow(clippy::unnecessary_wraps)] @@ -227,6 +228,27 @@ fn pattern() -> Result<(), PatternedError> { fn main() {} +// `?` is not the same as `return None;` if inside of a try block +fn issue8628(a: Option) -> Option { + let b: Option = try { + if a.is_none() { + return None; + } + 32 + }; + b.or(Some(128)) +} + +fn issue6828_nested_body() -> Option { + try { + fn f2(a: Option) -> Option { + a?; + Some(32) + } + 123 + } +} + // should not lint, `?` operator not available in const context const fn issue9175(option: Option<()>) -> Option<()> { if option.is_none() { diff --git a/tests/ui/question_mark.rs b/tests/ui/question_mark.rs index a90eae50ed45..69451c17ee7a 100644 --- a/tests/ui/question_mark.rs +++ b/tests/ui/question_mark.rs @@ -1,4 +1,5 @@ //@run-rustfix +#![feature(try_blocks)] #![allow(unreachable_code)] #![allow(dead_code)] #![allow(clippy::unnecessary_wraps)] @@ -263,6 +264,31 @@ fn pattern() -> Result<(), PatternedError> { fn main() {} +// `?` is not the same as `return None;` if inside of a try block +fn issue8628(a: Option) -> Option { + let b: Option = try { + if a.is_none() { + return None; + } + 32 + }; + b.or(Some(128)) +} + +fn issue6828_nested_body() -> Option { + try { + fn f2(a: Option) -> Option { + if a.is_none() { + return None; + // do lint here, the outer `try` is not relevant here + // https://github.com/rust-lang/rust-clippy/pull/11001#issuecomment-1610636867 + } + Some(32) + } + 123 + } +} + // should not lint, `?` operator not available in const context const fn issue9175(option: Option<()>) -> Option<()> { if option.is_none() { diff --git a/tests/ui/question_mark.stderr b/tests/ui/question_mark.stderr index 23172d7e535d..2cfd75863081 100644 --- a/tests/ui/question_mark.stderr +++ b/tests/ui/question_mark.stderr @@ -1,5 +1,5 @@ error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:7:5 + --> $DIR/question_mark.rs:8:5 | LL | / if a.is_none() { LL | | return None; @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::question-mark` implied by `-D warnings` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:52:9 + --> $DIR/question_mark.rs:53:9 | LL | / if (self.opt).is_none() { LL | | return None; @@ -17,7 +17,7 @@ LL | | } | |_________^ help: replace it with: `(self.opt)?;` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:56:9 + --> $DIR/question_mark.rs:57:9 | LL | / if self.opt.is_none() { LL | | return None @@ -25,7 +25,7 @@ LL | | } | |_________^ help: replace it with: `self.opt?;` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:60:17 + --> $DIR/question_mark.rs:61:17 | LL | let _ = if self.opt.is_none() { | _________________^ @@ -36,7 +36,7 @@ LL | | }; | |_________^ help: replace it with: `Some(self.opt?)` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:66:17 + --> $DIR/question_mark.rs:67:17 | LL | let _ = if let Some(x) = self.opt { | _________________^ @@ -47,7 +47,7 @@ LL | | }; | |_________^ help: replace it with: `self.opt?` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:83:9 + --> $DIR/question_mark.rs:84:9 | LL | / if self.opt.is_none() { LL | | return None; @@ -55,7 +55,7 @@ LL | | } | |_________^ help: replace it with: `self.opt.as_ref()?;` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:91:9 + --> $DIR/question_mark.rs:92:9 | LL | / if self.opt.is_none() { LL | | return None; @@ -63,7 +63,7 @@ LL | | } | |_________^ help: replace it with: `self.opt.as_ref()?;` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:99:9 + --> $DIR/question_mark.rs:100:9 | LL | / if self.opt.is_none() { LL | | return None; @@ -71,7 +71,7 @@ LL | | } | |_________^ help: replace it with: `self.opt.as_ref()?;` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:106:26 + --> $DIR/question_mark.rs:107:26 | LL | let v: &Vec<_> = if let Some(ref v) = self.opt { | __________________________^ @@ -82,7 +82,7 @@ LL | | }; | |_________^ help: replace it with: `self.opt.as_ref()?` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:116:17 + --> $DIR/question_mark.rs:117:17 | LL | let v = if let Some(v) = self.opt { | _________________^ @@ -93,7 +93,7 @@ LL | | }; | |_________^ help: replace it with: `self.opt?` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:131:5 + --> $DIR/question_mark.rs:132:5 | LL | / if f().is_none() { LL | | return None; @@ -101,13 +101,13 @@ LL | | } | |_____^ help: replace it with: `f()?;` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:143:13 + --> $DIR/question_mark.rs:144: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 - --> $DIR/question_mark.rs:145:5 + --> $DIR/question_mark.rs:146:5 | LL | / if x.is_err() { LL | | return x; @@ -115,7 +115,7 @@ LL | | } | |_____^ help: replace it with: `x?;` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:196:5 + --> $DIR/question_mark.rs:197:5 | LL | / if let Err(err) = func_returning_result() { LL | | return Err(err); @@ -123,12 +123,22 @@ LL | | } | |_____^ help: replace it with: `func_returning_result()?;` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:203:5 + --> $DIR/question_mark.rs:204:5 | LL | / if let Err(err) = func_returning_result() { LL | | return Err(err); LL | | } | |_____^ help: replace it with: `func_returning_result()?;` -error: aborting due to 15 previous errors +error: this block may be rewritten with the `?` operator + --> $DIR/question_mark.rs:281:13 + | +LL | / if a.is_none() { +LL | | return None; +LL | | // do lint here, the outer `try` is not relevant here +LL | | // https://github.com/rust-lang/rust-clippy/pull/11001#issuecomment-1610636867 +LL | | } + | |_____________^ help: replace it with: `a?;` + +error: aborting due to 16 previous errors diff --git a/tests/ui/range.rs b/tests/ui/range.rs index 628282509c1a..46edf0921bf2 100644 --- a/tests/ui/range.rs +++ b/tests/ui/range.rs @@ -1,3 +1,4 @@ +#![allow(clippy::useless_vec)] #[warn(clippy::range_zip_with_len)] fn main() { let v1 = vec![1, 2, 3]; diff --git a/tests/ui/range.stderr b/tests/ui/range.stderr index dcb5061371f8..ac83b67fde3a 100644 --- a/tests/ui/range.stderr +++ b/tests/ui/range.stderr @@ -1,5 +1,5 @@ error: it is more idiomatic to use `v1.iter().enumerate()` - --> $DIR/range.rs:5:14 + --> $DIR/range.rs:6:14 | LL | let _x = v1.iter().zip(0..v1.len()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/rc_clone_in_vec_init/arc.rs b/tests/ui/rc_clone_in_vec_init/arc.rs index 384060e6eae5..53fcbf3c49b4 100644 --- a/tests/ui/rc_clone_in_vec_init/arc.rs +++ b/tests/ui/rc_clone_in_vec_init/arc.rs @@ -1,4 +1,5 @@ #![warn(clippy::rc_clone_in_vec_init)] +#![allow(clippy::useless_vec)] use std::sync::{Arc, Mutex}; fn main() {} diff --git a/tests/ui/rc_clone_in_vec_init/arc.stderr b/tests/ui/rc_clone_in_vec_init/arc.stderr index 7814f5b54036..a8fd28b84b3a 100644 --- a/tests/ui/rc_clone_in_vec_init/arc.stderr +++ b/tests/ui/rc_clone_in_vec_init/arc.stderr @@ -1,5 +1,5 @@ error: initializing a reference-counted pointer in `vec![elem; len]` - --> $DIR/arc.rs:7:13 + --> $DIR/arc.rs:8:13 | LL | let v = vec![Arc::new("x".to_string()); 2]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL ~ }; | error: initializing a reference-counted pointer in `vec![elem; len]` - --> $DIR/arc.rs:15:21 + --> $DIR/arc.rs:16:21 | LL | let v = vec![Arc::new("x".to_string()); 2]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -46,7 +46,7 @@ LL ~ }; | error: initializing a reference-counted pointer in `vec![elem; len]` - --> $DIR/arc.rs:21:13 + --> $DIR/arc.rs:22:13 | LL | let v = vec![ | _____________^ @@ -76,7 +76,7 @@ LL ~ }; | error: initializing a reference-counted pointer in `vec![elem; len]` - --> $DIR/arc.rs:30:14 + --> $DIR/arc.rs:31:14 | LL | let v1 = vec![ | ______________^ diff --git a/tests/ui/rc_clone_in_vec_init/rc.rs b/tests/ui/rc_clone_in_vec_init/rc.rs index 0394457fe170..88ea39bf9083 100644 --- a/tests/ui/rc_clone_in_vec_init/rc.rs +++ b/tests/ui/rc_clone_in_vec_init/rc.rs @@ -1,4 +1,5 @@ #![warn(clippy::rc_clone_in_vec_init)] +#![allow(clippy::useless_vec)] use std::rc::Rc; use std::sync::Mutex; diff --git a/tests/ui/rc_clone_in_vec_init/rc.stderr b/tests/ui/rc_clone_in_vec_init/rc.stderr index 80deb7cb9f24..eab464800ca9 100644 --- a/tests/ui/rc_clone_in_vec_init/rc.stderr +++ b/tests/ui/rc_clone_in_vec_init/rc.stderr @@ -1,5 +1,5 @@ error: initializing a reference-counted pointer in `vec![elem; len]` - --> $DIR/rc.rs:8:13 + --> $DIR/rc.rs:9:13 | LL | let v = vec![Rc::new("x".to_string()); 2]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL ~ }; | error: initializing a reference-counted pointer in `vec![elem; len]` - --> $DIR/rc.rs:16:21 + --> $DIR/rc.rs:17:21 | LL | let v = vec![Rc::new("x".to_string()); 2]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -46,7 +46,7 @@ LL ~ }; | error: initializing a reference-counted pointer in `vec![elem; len]` - --> $DIR/rc.rs:22:13 + --> $DIR/rc.rs:23:13 | LL | let v = vec![ | _____________^ @@ -76,7 +76,7 @@ LL ~ }; | error: initializing a reference-counted pointer in `vec![elem; len]` - --> $DIR/rc.rs:31:14 + --> $DIR/rc.rs:32:14 | LL | let v1 = vec![ | ______________^ diff --git a/tests/ui/rc_clone_in_vec_init/weak.rs b/tests/ui/rc_clone_in_vec_init/weak.rs index 693c9b553c56..03142165057d 100644 --- a/tests/ui/rc_clone_in_vec_init/weak.rs +++ b/tests/ui/rc_clone_in_vec_init/weak.rs @@ -1,4 +1,5 @@ #![warn(clippy::rc_clone_in_vec_init)] +#![allow(clippy::useless_vec)] use std::rc::{Rc, Weak as UnSyncWeak}; use std::sync::{Arc, Mutex, Weak as SyncWeak}; diff --git a/tests/ui/rc_clone_in_vec_init/weak.stderr b/tests/ui/rc_clone_in_vec_init/weak.stderr index 789e14a302f6..1f7a849b1808 100644 --- a/tests/ui/rc_clone_in_vec_init/weak.stderr +++ b/tests/ui/rc_clone_in_vec_init/weak.stderr @@ -1,5 +1,5 @@ error: initializing a reference-counted pointer in `vec![elem; len]` - --> $DIR/weak.rs:8:13 + --> $DIR/weak.rs:9:13 | LL | let v = vec![SyncWeak::::new(); 2]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL ~ }; | error: initializing a reference-counted pointer in `vec![elem; len]` - --> $DIR/weak.rs:9:14 + --> $DIR/weak.rs:10:14 | LL | let v2 = vec![UnSyncWeak::::new(); 2]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -46,7 +46,7 @@ LL ~ }; | error: initializing a reference-counted pointer in `vec![elem; len]` - --> $DIR/weak.rs:11:13 + --> $DIR/weak.rs:12:13 | LL | let v = vec![Rc::downgrade(&Rc::new("x".to_string())); 2]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -69,7 +69,7 @@ LL ~ }; | error: initializing a reference-counted pointer in `vec![elem; len]` - --> $DIR/weak.rs:12:13 + --> $DIR/weak.rs:13:13 | LL | let v = vec![Arc::downgrade(&Arc::new("x".to_string())); 2]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -92,7 +92,7 @@ LL ~ }; | error: initializing a reference-counted pointer in `vec![elem; len]` - --> $DIR/weak.rs:20:21 + --> $DIR/weak.rs:21:21 | LL | let v = vec![Arc::downgrade(&Arc::new("x".to_string())); 2]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -115,7 +115,7 @@ LL ~ }; | error: initializing a reference-counted pointer in `vec![elem; len]` - --> $DIR/weak.rs:21:22 + --> $DIR/weak.rs:22:22 | LL | let v2 = vec![Rc::downgrade(&Rc::new("x".to_string())); 2]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -138,7 +138,7 @@ LL ~ }; | error: initializing a reference-counted pointer in `vec![elem; len]` - --> $DIR/weak.rs:27:13 + --> $DIR/weak.rs:28:13 | LL | let v = vec![ | _____________^ @@ -168,7 +168,7 @@ LL ~ }; | error: initializing a reference-counted pointer in `vec![elem; len]` - --> $DIR/weak.rs:36:14 + --> $DIR/weak.rs:37:14 | LL | let v1 = vec![ | ______________^ diff --git a/tests/ui/redundant_at_rest_pattern.fixed b/tests/ui/redundant_at_rest_pattern.fixed new file mode 100644 index 000000000000..080cf13b5dac --- /dev/null +++ b/tests/ui/redundant_at_rest_pattern.fixed @@ -0,0 +1,27 @@ +//@run-rustfix +//@aux-build:proc_macros.rs:proc-macro +#![allow(irrefutable_let_patterns, unused)] +#![warn(clippy::redundant_at_rest_pattern)] + +#[macro_use] +extern crate proc_macros; + +fn main() { + if let a = [()] {} + if let ref a = [()] {} + if let mut a = [()] {} + if let ref mut a = [()] {} + let v = vec![()]; + if let a = &*v {} + let s = &[()]; + if let a = s {} + // Don't lint + if let [..] = &*v {} + if let [a] = &*v {} + if let [()] = &*v {} + if let [first, rest @ ..] = &*v {} + if let a = [()] {} + external! { + if let [a @ ..] = [()] {} + } +} diff --git a/tests/ui/redundant_at_rest_pattern.rs b/tests/ui/redundant_at_rest_pattern.rs new file mode 100644 index 000000000000..a8a802829564 --- /dev/null +++ b/tests/ui/redundant_at_rest_pattern.rs @@ -0,0 +1,27 @@ +//@run-rustfix +//@aux-build:proc_macros.rs:proc-macro +#![allow(irrefutable_let_patterns, unused)] +#![warn(clippy::redundant_at_rest_pattern)] + +#[macro_use] +extern crate proc_macros; + +fn main() { + if let [a @ ..] = [()] {} + if let [ref a @ ..] = [()] {} + if let [mut a @ ..] = [()] {} + if let [ref mut a @ ..] = [()] {} + let v = vec![()]; + if let [a @ ..] = &*v {} + let s = &[()]; + if let [a @ ..] = s {} + // Don't lint + if let [..] = &*v {} + if let [a] = &*v {} + if let [()] = &*v {} + if let [first, rest @ ..] = &*v {} + if let a = [()] {} + external! { + if let [a @ ..] = [()] {} + } +} diff --git a/tests/ui/redundant_at_rest_pattern.stderr b/tests/ui/redundant_at_rest_pattern.stderr new file mode 100644 index 000000000000..e2a4d9ffd57c --- /dev/null +++ b/tests/ui/redundant_at_rest_pattern.stderr @@ -0,0 +1,40 @@ +error: using a rest pattern to bind an entire slice to a local + --> $DIR/redundant_at_rest_pattern.rs:10:12 + | +LL | if let [a @ ..] = [()] {} + | ^^^^^^^^ help: this is better represented with just the binding: `a` + | + = note: `-D clippy::redundant-at-rest-pattern` implied by `-D warnings` + +error: using a rest pattern to bind an entire slice to a local + --> $DIR/redundant_at_rest_pattern.rs:11:12 + | +LL | if let [ref a @ ..] = [()] {} + | ^^^^^^^^^^^^ help: this is better represented with just the binding: `ref a` + +error: using a rest pattern to bind an entire slice to a local + --> $DIR/redundant_at_rest_pattern.rs:12:12 + | +LL | if let [mut a @ ..] = [()] {} + | ^^^^^^^^^^^^ help: this is better represented with just the binding: `mut a` + +error: using a rest pattern to bind an entire slice to a local + --> $DIR/redundant_at_rest_pattern.rs:13:12 + | +LL | if let [ref mut a @ ..] = [()] {} + | ^^^^^^^^^^^^^^^^ help: this is better represented with just the binding: `ref mut a` + +error: using a rest pattern to bind an entire slice to a local + --> $DIR/redundant_at_rest_pattern.rs:15:12 + | +LL | if let [a @ ..] = &*v {} + | ^^^^^^^^ help: this is better represented with just the binding: `a` + +error: using a rest pattern to bind an entire slice to a local + --> $DIR/redundant_at_rest_pattern.rs:17:12 + | +LL | if let [a @ ..] = s {} + | ^^^^^^^^ help: this is better represented with just the binding: `a` + +error: aborting due to 6 previous errors + diff --git a/tests/ui/redundant_clone.fixed b/tests/ui/redundant_clone.fixed index 8bebb5183bc1..5037c08ebd5f 100644 --- a/tests/ui/redundant_clone.fixed +++ b/tests/ui/redundant_clone.fixed @@ -1,7 +1,13 @@ //@run-rustfix // rustfix-only-machine-applicable #![feature(lint_reasons)] -#![allow(clippy::drop_non_drop, clippy::implicit_clone, clippy::uninlined_format_args)] +#![warn(clippy::redundant_clone)] +#![allow( + clippy::drop_non_drop, + clippy::implicit_clone, + clippy::uninlined_format_args, + clippy::unnecessary_literal_unwrap +)] use std::ffi::OsString; use std::path::Path; diff --git a/tests/ui/redundant_clone.rs b/tests/ui/redundant_clone.rs index b4bd5d16b1a6..501898bf113c 100644 --- a/tests/ui/redundant_clone.rs +++ b/tests/ui/redundant_clone.rs @@ -1,7 +1,13 @@ //@run-rustfix // rustfix-only-machine-applicable #![feature(lint_reasons)] -#![allow(clippy::drop_non_drop, clippy::implicit_clone, clippy::uninlined_format_args)] +#![warn(clippy::redundant_clone)] +#![allow( + clippy::drop_non_drop, + clippy::implicit_clone, + clippy::uninlined_format_args, + clippy::unnecessary_literal_unwrap +)] use std::ffi::OsString; use std::path::Path; diff --git a/tests/ui/redundant_clone.stderr b/tests/ui/redundant_clone.stderr index 782590034d05..8660c0e1f6a0 100644 --- a/tests/ui/redundant_clone.stderr +++ b/tests/ui/redundant_clone.stderr @@ -1,180 +1,180 @@ error: redundant clone - --> $DIR/redundant_clone.rs:10:42 + --> $DIR/redundant_clone.rs:16:42 | LL | let _s = ["lorem", "ipsum"].join(" ").to_string(); | ^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:10:14 + --> $DIR/redundant_clone.rs:16:14 | LL | let _s = ["lorem", "ipsum"].join(" ").to_string(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: `-D clippy::redundant-clone` implied by `-D warnings` error: redundant clone - --> $DIR/redundant_clone.rs:13:15 + --> $DIR/redundant_clone.rs:19:15 | LL | let _s = s.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:13:14 + --> $DIR/redundant_clone.rs:19:14 | LL | let _s = s.clone(); | ^ error: redundant clone - --> $DIR/redundant_clone.rs:16:15 + --> $DIR/redundant_clone.rs:22:15 | LL | let _s = s.to_string(); | ^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:16:14 + --> $DIR/redundant_clone.rs:22:14 | LL | let _s = s.to_string(); | ^ error: redundant clone - --> $DIR/redundant_clone.rs:19:15 + --> $DIR/redundant_clone.rs:25:15 | LL | let _s = s.to_owned(); | ^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:19:14 + --> $DIR/redundant_clone.rs:25:14 | LL | let _s = s.to_owned(); | ^ error: redundant clone - --> $DIR/redundant_clone.rs:21:42 + --> $DIR/redundant_clone.rs:27:42 | LL | let _s = Path::new("/a/b/").join("c").to_owned(); | ^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:21:14 + --> $DIR/redundant_clone.rs:27:14 | LL | let _s = Path::new("/a/b/").join("c").to_owned(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant clone - --> $DIR/redundant_clone.rs:23:42 + --> $DIR/redundant_clone.rs:29:42 | LL | let _s = Path::new("/a/b/").join("c").to_path_buf(); | ^^^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:23:14 + --> $DIR/redundant_clone.rs:29:14 | LL | let _s = Path::new("/a/b/").join("c").to_path_buf(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant clone - --> $DIR/redundant_clone.rs:25:29 + --> $DIR/redundant_clone.rs:31:29 | LL | let _s = OsString::new().to_owned(); | ^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:25:14 + --> $DIR/redundant_clone.rs:31:14 | LL | let _s = OsString::new().to_owned(); | ^^^^^^^^^^^^^^^ error: redundant clone - --> $DIR/redundant_clone.rs:27:29 + --> $DIR/redundant_clone.rs:33:29 | LL | let _s = OsString::new().to_os_string(); | ^^^^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:27:14 + --> $DIR/redundant_clone.rs:33:14 | LL | let _s = OsString::new().to_os_string(); | ^^^^^^^^^^^^^^^ error: redundant clone - --> $DIR/redundant_clone.rs:38:19 + --> $DIR/redundant_clone.rs:44:19 | LL | let _t = tup.0.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:38:14 + --> $DIR/redundant_clone.rs:44:14 | LL | let _t = tup.0.clone(); | ^^^^^ error: redundant clone - --> $DIR/redundant_clone.rs:70:25 + --> $DIR/redundant_clone.rs:76:25 | LL | if b { (a.clone(), a.clone()) } else { (Alpha, a) } | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:70:24 + --> $DIR/redundant_clone.rs:76:24 | LL | if b { (a.clone(), a.clone()) } else { (Alpha, a) } | ^ error: redundant clone - --> $DIR/redundant_clone.rs:127:15 + --> $DIR/redundant_clone.rs:133:15 | LL | let _s = s.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:127:14 + --> $DIR/redundant_clone.rs:133:14 | LL | let _s = s.clone(); | ^ error: redundant clone - --> $DIR/redundant_clone.rs:128:15 + --> $DIR/redundant_clone.rs:134:15 | LL | let _t = t.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:128:14 + --> $DIR/redundant_clone.rs:134:14 | LL | let _t = t.clone(); | ^ error: redundant clone - --> $DIR/redundant_clone.rs:138:19 + --> $DIR/redundant_clone.rs:144:19 | LL | let _f = f.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:138:18 + --> $DIR/redundant_clone.rs:144:18 | LL | let _f = f.clone(); | ^ error: redundant clone - --> $DIR/redundant_clone.rs:150:14 + --> $DIR/redundant_clone.rs:156:14 | LL | let y = x.clone().join("matthias"); | ^^^^^^^^ help: remove this | note: cloned value is neither consumed nor mutated - --> $DIR/redundant_clone.rs:150:13 + --> $DIR/redundant_clone.rs:156:13 | LL | let y = x.clone().join("matthias"); | ^^^^^^^^^ error: redundant clone - --> $DIR/redundant_clone.rs:204:11 + --> $DIR/redundant_clone.rs:210:11 | LL | foo(&x.clone(), move || { | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:204:10 + --> $DIR/redundant_clone.rs:210:10 | LL | foo(&x.clone(), move || { | ^ diff --git a/tests/ui/redundant_closure_call_fixable.fixed b/tests/ui/redundant_closure_call_fixable.fixed index 61aed2733fef..f3669a669ea1 100644 --- a/tests/ui/redundant_closure_call_fixable.fixed +++ b/tests/ui/redundant_closure_call_fixable.fixed @@ -3,6 +3,7 @@ #![feature(async_closure)] #![warn(clippy::redundant_closure_call)] #![allow(clippy::redundant_async_block)] +#![allow(clippy::type_complexity)] #![allow(unused)] async fn something() -> u32 { @@ -38,4 +39,50 @@ fn main() { }; } m2!(); + issue9956(); +} + +fn issue9956() { + assert_eq!(43, 42); + + // ... and some more interesting cases I've found while implementing the fix + + // not actually immediately calling the closure: + let a = (|| 42); + dbg!(a()); + + // immediately calling it inside of a macro + dbg!(42); + + // immediately calling only one closure, so we can't remove the other ones + let a = (|| || 123); + dbg!(a()()); + + // nested async closures + let a = async { 1 }; + let h = async { a.await }; + + // macro expansion tests + macro_rules! echo { + ($e:expr) => { + $e + }; + } + let a = 1; + assert_eq!(a, 1); + let a = 123; + assert_eq!(a, 123); + + // chaining calls, but not closures + fn x() -> fn() -> fn() -> fn() -> i32 { + || || || 42 + } + let _ = x()()()(); + + fn bar() -> fn(i32, i32) { + foo + } + fn foo(_: i32, _: i32) {} + bar()(42, 5); + foo(42, 5); } diff --git a/tests/ui/redundant_closure_call_fixable.rs b/tests/ui/redundant_closure_call_fixable.rs index 56b286635391..db8c7f80df48 100644 --- a/tests/ui/redundant_closure_call_fixable.rs +++ b/tests/ui/redundant_closure_call_fixable.rs @@ -3,6 +3,7 @@ #![feature(async_closure)] #![warn(clippy::redundant_closure_call)] #![allow(clippy::redundant_async_block)] +#![allow(clippy::type_complexity)] #![allow(unused)] async fn something() -> u32 { @@ -38,4 +39,50 @@ fn main() { }; } m2!(); + issue9956(); +} + +fn issue9956() { + assert_eq!((|| || 43)()(), 42); + + // ... and some more interesting cases I've found while implementing the fix + + // not actually immediately calling the closure: + let a = (|| 42); + dbg!(a()); + + // immediately calling it inside of a macro + dbg!((|| 42)()); + + // immediately calling only one closure, so we can't remove the other ones + let a = (|| || || 123)(); + dbg!(a()()); + + // nested async closures + let a = (|| || || || async || 1)()()()()(); + let h = async { a.await }; + + // macro expansion tests + macro_rules! echo { + ($e:expr) => { + $e + }; + } + let a = (|| echo!(|| echo!(|| 1)))()()(); + assert_eq!(a, 1); + let a = (|| echo!((|| 123)))()(); + assert_eq!(a, 123); + + // chaining calls, but not closures + fn x() -> fn() -> fn() -> fn() -> i32 { + || || || 42 + } + let _ = x()()()(); + + fn bar() -> fn(i32, i32) { + foo + } + fn foo(_: i32, _: i32) {} + bar()((|| || 42)()(), 5); + foo((|| || 42)()(), 5); } diff --git a/tests/ui/redundant_closure_call_fixable.stderr b/tests/ui/redundant_closure_call_fixable.stderr index 8a1f0771659b..618f5e071d6b 100644 --- a/tests/ui/redundant_closure_call_fixable.stderr +++ b/tests/ui/redundant_closure_call_fixable.stderr @@ -1,5 +1,5 @@ error: try not to call a closure in the expression where it is declared - --> $DIR/redundant_closure_call_fixable.rs:17:13 + --> $DIR/redundant_closure_call_fixable.rs:18:13 | LL | let a = (|| 42)(); | ^^^^^^^^^ help: try doing something like: `42` @@ -7,7 +7,7 @@ LL | let a = (|| 42)(); = note: `-D clippy::redundant-closure-call` implied by `-D warnings` error: try not to call a closure in the expression where it is declared - --> $DIR/redundant_closure_call_fixable.rs:18:13 + --> $DIR/redundant_closure_call_fixable.rs:19:13 | LL | let b = (async || { | _____________^ @@ -27,7 +27,7 @@ LL ~ }; | error: try not to call a closure in the expression where it is declared - --> $DIR/redundant_closure_call_fixable.rs:23:13 + --> $DIR/redundant_closure_call_fixable.rs:24:13 | LL | let c = (|| { | _____________^ @@ -47,13 +47,13 @@ LL ~ }; | error: try not to call a closure in the expression where it is declared - --> $DIR/redundant_closure_call_fixable.rs:28:13 + --> $DIR/redundant_closure_call_fixable.rs:29:13 | LL | let d = (async || something().await)(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `async { something().await }` error: try not to call a closure in the expression where it is declared - --> $DIR/redundant_closure_call_fixable.rs:37:13 + --> $DIR/redundant_closure_call_fixable.rs:38:13 | LL | (|| m!())() | ^^^^^^^^^^^ help: try doing something like: `m!()` @@ -64,7 +64,7 @@ LL | m2!(); = note: this error originates in the macro `m2` (in Nightly builds, run with -Z macro-backtrace for more info) error: try not to call a closure in the expression where it is declared - --> $DIR/redundant_closure_call_fixable.rs:32:13 + --> $DIR/redundant_closure_call_fixable.rs:33:13 | LL | (|| 0)() | ^^^^^^^^ help: try doing something like: `0` @@ -74,5 +74,53 @@ LL | m2!(); | = note: this error originates in the macro `m` which comes from the expansion of the macro `m2` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 6 previous errors +error: try not to call a closure in the expression where it is declared + --> $DIR/redundant_closure_call_fixable.rs:46:16 + | +LL | assert_eq!((|| || 43)()(), 42); + | ^^^^^^^^^^^^^^ help: try doing something like: `43` + +error: try not to call a closure in the expression where it is declared + --> $DIR/redundant_closure_call_fixable.rs:55:10 + | +LL | dbg!((|| 42)()); + | ^^^^^^^^^ help: try doing something like: `42` + +error: try not to call a closure in the expression where it is declared + --> $DIR/redundant_closure_call_fixable.rs:58:13 + | +LL | let a = (|| || || 123)(); + | ^^^^^^^^^^^^^^^^ help: try doing something like: `(|| || 123)` + +error: try not to call a closure in the expression where it is declared + --> $DIR/redundant_closure_call_fixable.rs:62:13 + | +LL | let a = (|| || || || async || 1)()()()()(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `async { 1 }` + +error: try not to call a closure in the expression where it is declared + --> $DIR/redundant_closure_call_fixable.rs:71:13 + | +LL | let a = (|| echo!(|| echo!(|| 1)))()()(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `1` + +error: try not to call a closure in the expression where it is declared + --> $DIR/redundant_closure_call_fixable.rs:73:13 + | +LL | let a = (|| echo!((|| 123)))()(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `123` + +error: try not to call a closure in the expression where it is declared + --> $DIR/redundant_closure_call_fixable.rs:86:11 + | +LL | bar()((|| || 42)()(), 5); + | ^^^^^^^^^^^^^^ help: try doing something like: `42` + +error: try not to call a closure in the expression where it is declared + --> $DIR/redundant_closure_call_fixable.rs:87:9 + | +LL | foo((|| || 42)()(), 5); + | ^^^^^^^^^^^^^^ help: try doing something like: `42` + +error: aborting due to 14 previous errors diff --git a/tests/ui/redundant_pattern_matching_drop_order.fixed b/tests/ui/redundant_pattern_matching_drop_order.fixed index 481c9b263fbb..d1134de5ab47 100644 --- a/tests/ui/redundant_pattern_matching_drop_order.fixed +++ b/tests/ui/redundant_pattern_matching_drop_order.fixed @@ -2,7 +2,12 @@ // Issue #5746 #![warn(clippy::redundant_pattern_matching)] -#![allow(clippy::if_same_then_else, clippy::equatable_if_let, clippy::needless_else)] +#![allow( + clippy::if_same_then_else, + clippy::equatable_if_let, + clippy::needless_if, + clippy::needless_else +)] use std::task::Poll::{Pending, Ready}; fn main() { diff --git a/tests/ui/redundant_pattern_matching_drop_order.rs b/tests/ui/redundant_pattern_matching_drop_order.rs index 86e46d41e65a..d144086e791a 100644 --- a/tests/ui/redundant_pattern_matching_drop_order.rs +++ b/tests/ui/redundant_pattern_matching_drop_order.rs @@ -2,7 +2,12 @@ // Issue #5746 #![warn(clippy::redundant_pattern_matching)] -#![allow(clippy::if_same_then_else, clippy::equatable_if_let, clippy::needless_else)] +#![allow( + clippy::if_same_then_else, + clippy::equatable_if_let, + clippy::needless_if, + clippy::needless_else +)] use std::task::Poll::{Pending, Ready}; fn main() { diff --git a/tests/ui/redundant_pattern_matching_drop_order.stderr b/tests/ui/redundant_pattern_matching_drop_order.stderr index 23f08103f358..e9ea3f2e6886 100644 --- a/tests/ui/redundant_pattern_matching_drop_order.stderr +++ b/tests/ui/redundant_pattern_matching_drop_order.stderr @@ -1,5 +1,5 @@ error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_drop_order.rs:12:12 + --> $DIR/redundant_pattern_matching_drop_order.rs:17:12 | LL | if let Ok(_) = m.lock() {} | -------^^^^^----------- help: try this: `if m.lock().is_ok()` @@ -9,7 +9,7 @@ LL | if let Ok(_) = m.lock() {} = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_drop_order.rs:13:12 + --> $DIR/redundant_pattern_matching_drop_order.rs:18:12 | LL | if let Err(_) = Err::<(), _>(m.lock().unwrap().0) {} | -------^^^^^^------------------------------------ help: try this: `if Err::<(), _>(m.lock().unwrap().0).is_err()` @@ -18,7 +18,7 @@ LL | if let Err(_) = Err::<(), _>(m.lock().unwrap().0) {} = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_drop_order.rs:16:16 + --> $DIR/redundant_pattern_matching_drop_order.rs:21:16 | LL | if let Ok(_) = Ok::<_, std::sync::MutexGuard<()>>(()) {} | -------^^^^^----------------------------------------- help: try this: `if Ok::<_, std::sync::MutexGuard<()>>(()).is_ok()` @@ -27,7 +27,7 @@ LL | if let Ok(_) = Ok::<_, std::sync::MutexGuard<()>>(()) {} = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_drop_order.rs:18:12 + --> $DIR/redundant_pattern_matching_drop_order.rs:23:12 | LL | if let Ok(_) = Ok::<_, std::sync::MutexGuard<()>>(()) { | -------^^^^^----------------------------------------- help: try this: `if Ok::<_, std::sync::MutexGuard<()>>(()).is_ok()` @@ -36,31 +36,31 @@ LL | if let Ok(_) = Ok::<_, std::sync::MutexGuard<()>>(()) { = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_drop_order.rs:21:12 + --> $DIR/redundant_pattern_matching_drop_order.rs:26:12 | LL | if let Ok(_) = Ok::<_, std::sync::MutexGuard<()>>(()) {} | -------^^^^^----------------------------------------- help: try this: `if Ok::<_, std::sync::MutexGuard<()>>(()).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_drop_order.rs:22:12 + --> $DIR/redundant_pattern_matching_drop_order.rs:27:12 | LL | if let Err(_) = Err::, _>(()) {} | -------^^^^^^------------------------------------------ help: try this: `if Err::, _>(()).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_drop_order.rs:24:12 + --> $DIR/redundant_pattern_matching_drop_order.rs:29:12 | LL | if let Ok(_) = Ok::<_, ()>(String::new()) {} | -------^^^^^----------------------------- help: try this: `if Ok::<_, ()>(String::new()).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_drop_order.rs:25:12 + --> $DIR/redundant_pattern_matching_drop_order.rs:30:12 | LL | if let Err(_) = Err::<(), _>((String::new(), ())) {} | -------^^^^^^------------------------------------ help: try this: `if Err::<(), _>((String::new(), ())).is_err()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_drop_order.rs:28:12 + --> $DIR/redundant_pattern_matching_drop_order.rs:33:12 | LL | if let Some(_) = Some(m.lock()) {} | -------^^^^^^^----------------- help: try this: `if Some(m.lock()).is_some()` @@ -69,7 +69,7 @@ LL | if let Some(_) = Some(m.lock()) {} = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_drop_order.rs:29:12 + --> $DIR/redundant_pattern_matching_drop_order.rs:34:12 | LL | if let Some(_) = Some(m.lock().unwrap().0) {} | -------^^^^^^^---------------------------- help: try this: `if Some(m.lock().unwrap().0).is_some()` @@ -78,7 +78,7 @@ LL | if let Some(_) = Some(m.lock().unwrap().0) {} = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_drop_order.rs:32:16 + --> $DIR/redundant_pattern_matching_drop_order.rs:37:16 | LL | if let None = None::> {} | -------^^^^------------------------------------ help: try this: `if None::>.is_none()` @@ -87,7 +87,7 @@ LL | if let None = None::> {} = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_drop_order.rs:34:12 + --> $DIR/redundant_pattern_matching_drop_order.rs:39:12 | LL | if let None = None::> { | -------^^^^------------------------------------ help: try this: `if None::>.is_none()` @@ -96,25 +96,25 @@ LL | if let None = None::> { = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_drop_order.rs:38:12 + --> $DIR/redundant_pattern_matching_drop_order.rs:43:12 | LL | if let None = None::> {} | -------^^^^------------------------------------ help: try this: `if None::>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_drop_order.rs:40:12 + --> $DIR/redundant_pattern_matching_drop_order.rs:45:12 | LL | if let Some(_) = Some(String::new()) {} | -------^^^^^^^---------------------- help: try this: `if Some(String::new()).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_drop_order.rs:41:12 + --> $DIR/redundant_pattern_matching_drop_order.rs:46:12 | LL | if let Some(_) = Some((String::new(), ())) {} | -------^^^^^^^---------------------------- help: try this: `if Some((String::new(), ())).is_some()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_drop_order.rs:44:12 + --> $DIR/redundant_pattern_matching_drop_order.rs:49:12 | LL | if let Ready(_) = Ready(m.lock()) {} | -------^^^^^^^^------------------ help: try this: `if Ready(m.lock()).is_ready()` @@ -123,7 +123,7 @@ LL | if let Ready(_) = Ready(m.lock()) {} = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_drop_order.rs:45:12 + --> $DIR/redundant_pattern_matching_drop_order.rs:50:12 | LL | if let Ready(_) = Ready(m.lock().unwrap().0) {} | -------^^^^^^^^----------------------------- help: try this: `if Ready(m.lock().unwrap().0).is_ready()` @@ -132,7 +132,7 @@ LL | if let Ready(_) = Ready(m.lock().unwrap().0) {} = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_drop_order.rs:48:16 + --> $DIR/redundant_pattern_matching_drop_order.rs:53:16 | LL | if let Pending = Pending::> {} | -------^^^^^^^--------------------------------------- help: try this: `if Pending::>.is_pending()` @@ -141,7 +141,7 @@ LL | if let Pending = Pending::> {} = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_drop_order.rs:50:12 + --> $DIR/redundant_pattern_matching_drop_order.rs:55:12 | LL | if let Pending = Pending::> { | -------^^^^^^^--------------------------------------- help: try this: `if Pending::>.is_pending()` @@ -150,19 +150,19 @@ LL | if let Pending = Pending::> { = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_drop_order.rs:54:12 + --> $DIR/redundant_pattern_matching_drop_order.rs:59:12 | LL | if let Pending = Pending::> {} | -------^^^^^^^--------------------------------------- help: try this: `if Pending::>.is_pending()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_drop_order.rs:56:12 + --> $DIR/redundant_pattern_matching_drop_order.rs:61:12 | LL | if let Ready(_) = Ready(String::new()) {} | -------^^^^^^^^----------------------- help: try this: `if Ready(String::new()).is_ready()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_drop_order.rs:57:12 + --> $DIR/redundant_pattern_matching_drop_order.rs:62:12 | LL | if let Ready(_) = Ready((String::new(), ())) {} | -------^^^^^^^^----------------------------- help: try this: `if Ready((String::new(), ())).is_ready()` diff --git a/tests/ui/redundant_pattern_matching_ipaddr.fixed b/tests/ui/redundant_pattern_matching_ipaddr.fixed index a9faf12cd5a1..75ed143446c9 100644 --- a/tests/ui/redundant_pattern_matching_ipaddr.fixed +++ b/tests/ui/redundant_pattern_matching_ipaddr.fixed @@ -4,6 +4,7 @@ #![allow( clippy::match_like_matches_macro, clippy::needless_bool, + clippy::needless_if, clippy::uninlined_format_args )] diff --git a/tests/ui/redundant_pattern_matching_ipaddr.rs b/tests/ui/redundant_pattern_matching_ipaddr.rs index 574671d03d1c..9ac77409f791 100644 --- a/tests/ui/redundant_pattern_matching_ipaddr.rs +++ b/tests/ui/redundant_pattern_matching_ipaddr.rs @@ -4,6 +4,7 @@ #![allow( clippy::match_like_matches_macro, clippy::needless_bool, + clippy::needless_if, clippy::uninlined_format_args )] diff --git a/tests/ui/redundant_pattern_matching_ipaddr.stderr b/tests/ui/redundant_pattern_matching_ipaddr.stderr index 536b589de54c..6d1fb2964632 100644 --- a/tests/ui/redundant_pattern_matching_ipaddr.stderr +++ b/tests/ui/redundant_pattern_matching_ipaddr.stderr @@ -1,5 +1,5 @@ error: redundant pattern matching, consider using `is_ipv4()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:17:12 + --> $DIR/redundant_pattern_matching_ipaddr.rs:18:12 | LL | if let V4(_) = &ipaddr {} | -------^^^^^---------- help: try this: `if ipaddr.is_ipv4()` @@ -7,31 +7,31 @@ LL | if let V4(_) = &ipaddr {} = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` error: redundant pattern matching, consider using `is_ipv4()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:19:12 + --> $DIR/redundant_pattern_matching_ipaddr.rs:20:12 | LL | if let V4(_) = V4(Ipv4Addr::LOCALHOST) {} | -------^^^^^-------------------------- help: try this: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:21:12 + --> $DIR/redundant_pattern_matching_ipaddr.rs:22:12 | LL | if let V6(_) = V6(Ipv6Addr::LOCALHOST) {} | -------^^^^^-------------------------- help: try this: `if V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:23:15 + --> $DIR/redundant_pattern_matching_ipaddr.rs:24:15 | LL | while let V4(_) = V4(Ipv4Addr::LOCALHOST) {} | ----------^^^^^-------------------------- help: try this: `while V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:25:15 + --> $DIR/redundant_pattern_matching_ipaddr.rs:26:15 | LL | while let V6(_) = V6(Ipv6Addr::LOCALHOST) {} | ----------^^^^^-------------------------- help: try this: `while V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:35:5 + --> $DIR/redundant_pattern_matching_ipaddr.rs:36:5 | LL | / match V4(Ipv4Addr::LOCALHOST) { LL | | V4(_) => true, @@ -40,7 +40,7 @@ LL | | }; | |_____^ help: try this: `V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:40:5 + --> $DIR/redundant_pattern_matching_ipaddr.rs:41:5 | LL | / match V4(Ipv4Addr::LOCALHOST) { LL | | V4(_) => false, @@ -49,7 +49,7 @@ LL | | }; | |_____^ help: try this: `V4(Ipv4Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv6()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:45:5 + --> $DIR/redundant_pattern_matching_ipaddr.rs:46:5 | LL | / match V6(Ipv6Addr::LOCALHOST) { LL | | V4(_) => false, @@ -58,7 +58,7 @@ LL | | }; | |_____^ help: try this: `V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:50:5 + --> $DIR/redundant_pattern_matching_ipaddr.rs:51:5 | LL | / match V6(Ipv6Addr::LOCALHOST) { LL | | V4(_) => true, @@ -67,49 +67,49 @@ LL | | }; | |_____^ help: try this: `V6(Ipv6Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv4()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:55:20 + --> $DIR/redundant_pattern_matching_ipaddr.rs:56:20 | LL | let _ = if let V4(_) = V4(Ipv4Addr::LOCALHOST) { | -------^^^^^-------------------------- help: try this: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv4()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:63:20 + --> $DIR/redundant_pattern_matching_ipaddr.rs:64:20 | LL | let _ = if let V4(_) = gen_ipaddr() { | -------^^^^^--------------- help: try this: `if gen_ipaddr().is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:65:19 + --> $DIR/redundant_pattern_matching_ipaddr.rs:66:19 | LL | } else if let V6(_) = gen_ipaddr() { | -------^^^^^--------------- help: try this: `if gen_ipaddr().is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:77:12 + --> $DIR/redundant_pattern_matching_ipaddr.rs:78:12 | LL | if let V4(_) = V4(Ipv4Addr::LOCALHOST) {} | -------^^^^^-------------------------- help: try this: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:79:12 + --> $DIR/redundant_pattern_matching_ipaddr.rs:80:12 | LL | if let V6(_) = V6(Ipv6Addr::LOCALHOST) {} | -------^^^^^-------------------------- help: try this: `if V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:81:15 + --> $DIR/redundant_pattern_matching_ipaddr.rs:82:15 | LL | while let V4(_) = V4(Ipv4Addr::LOCALHOST) {} | ----------^^^^^-------------------------- help: try this: `while V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:83:15 + --> $DIR/redundant_pattern_matching_ipaddr.rs:84:15 | LL | while let V6(_) = V6(Ipv6Addr::LOCALHOST) {} | ----------^^^^^-------------------------- help: try this: `while V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:85:5 + --> $DIR/redundant_pattern_matching_ipaddr.rs:86:5 | LL | / match V4(Ipv4Addr::LOCALHOST) { LL | | V4(_) => true, @@ -118,7 +118,7 @@ LL | | }; | |_____^ help: try this: `V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` - --> $DIR/redundant_pattern_matching_ipaddr.rs:90:5 + --> $DIR/redundant_pattern_matching_ipaddr.rs:91:5 | LL | / match V6(Ipv6Addr::LOCALHOST) { LL | | V4(_) => false, diff --git a/tests/ui/redundant_pattern_matching_option.fixed b/tests/ui/redundant_pattern_matching_option.fixed index dae931541d45..a63ba5809e4b 100644 --- a/tests/ui/redundant_pattern_matching_option.fixed +++ b/tests/ui/redundant_pattern_matching_option.fixed @@ -5,6 +5,7 @@ #![allow( unused_must_use, clippy::needless_bool, + clippy::needless_if, clippy::match_like_matches_macro, clippy::equatable_if_let, clippy::if_same_then_else diff --git a/tests/ui/redundant_pattern_matching_option.rs b/tests/ui/redundant_pattern_matching_option.rs index 3f2fa3f53ce9..631f9091672d 100644 --- a/tests/ui/redundant_pattern_matching_option.rs +++ b/tests/ui/redundant_pattern_matching_option.rs @@ -5,6 +5,7 @@ #![allow( unused_must_use, clippy::needless_bool, + clippy::needless_if, clippy::match_like_matches_macro, clippy::equatable_if_let, clippy::if_same_then_else diff --git a/tests/ui/redundant_pattern_matching_option.stderr b/tests/ui/redundant_pattern_matching_option.stderr index 93760ce97a8f..717b603c496e 100644 --- a/tests/ui/redundant_pattern_matching_option.stderr +++ b/tests/ui/redundant_pattern_matching_option.stderr @@ -1,5 +1,5 @@ error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:14:12 + --> $DIR/redundant_pattern_matching_option.rs:15:12 | LL | if let None = None::<()> {} | -------^^^^------------- help: try this: `if None::<()>.is_none()` @@ -7,43 +7,43 @@ LL | if let None = None::<()> {} = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:16:12 + --> $DIR/redundant_pattern_matching_option.rs:17:12 | LL | if let Some(_) = Some(42) {} | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:18:12 + --> $DIR/redundant_pattern_matching_option.rs:19:12 | LL | if let Some(_) = Some(42) { | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:24:15 + --> $DIR/redundant_pattern_matching_option.rs:25:15 | LL | while let Some(_) = Some(42) {} | ----------^^^^^^^----------- help: try this: `while Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:26:15 + --> $DIR/redundant_pattern_matching_option.rs:27:15 | LL | while let None = Some(42) {} | ----------^^^^----------- help: try this: `while Some(42).is_none()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:28:15 + --> $DIR/redundant_pattern_matching_option.rs:29:15 | LL | while let None = None::<()> {} | ----------^^^^------------- help: try this: `while None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:31:15 + --> $DIR/redundant_pattern_matching_option.rs:32:15 | LL | while let Some(_) = v.pop() { | ----------^^^^^^^---------- help: try this: `while v.pop().is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:39:5 + --> $DIR/redundant_pattern_matching_option.rs:40:5 | LL | / match Some(42) { LL | | Some(_) => true, @@ -52,7 +52,7 @@ LL | | }; | |_____^ help: try this: `Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:44:5 + --> $DIR/redundant_pattern_matching_option.rs:45:5 | LL | / match None::<()> { LL | | Some(_) => false, @@ -61,7 +61,7 @@ LL | | }; | |_____^ help: try this: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:49:13 + --> $DIR/redundant_pattern_matching_option.rs:50:13 | LL | let _ = match None::<()> { | _____________^ @@ -71,55 +71,55 @@ LL | | }; | |_____^ help: try this: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:55:20 + --> $DIR/redundant_pattern_matching_option.rs:56:20 | LL | let _ = if let Some(_) = opt { true } else { false }; | -------^^^^^^^------ help: try this: `if opt.is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:61:20 + --> $DIR/redundant_pattern_matching_option.rs:62:20 | LL | let _ = if let Some(_) = gen_opt() { | -------^^^^^^^------------ help: try this: `if gen_opt().is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:63:19 + --> $DIR/redundant_pattern_matching_option.rs:64:19 | LL | } else if let None = gen_opt() { | -------^^^^------------ help: try this: `if gen_opt().is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:69:12 + --> $DIR/redundant_pattern_matching_option.rs:70:12 | LL | if let Some(..) = gen_opt() {} | -------^^^^^^^^------------ help: try this: `if gen_opt().is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:84:12 + --> $DIR/redundant_pattern_matching_option.rs:85:12 | LL | if let Some(_) = Some(42) {} | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:86:12 + --> $DIR/redundant_pattern_matching_option.rs:87:12 | LL | if let None = None::<()> {} | -------^^^^------------- help: try this: `if None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:88:15 + --> $DIR/redundant_pattern_matching_option.rs:89:15 | LL | while let Some(_) = Some(42) {} | ----------^^^^^^^----------- help: try this: `while Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:90:15 + --> $DIR/redundant_pattern_matching_option.rs:91:15 | LL | while let None = None::<()> {} | ----------^^^^------------- help: try this: `while None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:92:5 + --> $DIR/redundant_pattern_matching_option.rs:93:5 | LL | / match Some(42) { LL | | Some(_) => true, @@ -128,7 +128,7 @@ LL | | }; | |_____^ help: try this: `Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:97:5 + --> $DIR/redundant_pattern_matching_option.rs:98:5 | LL | / match None::<()> { LL | | Some(_) => false, @@ -137,19 +137,19 @@ LL | | }; | |_____^ help: try this: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:105:12 + --> $DIR/redundant_pattern_matching_option.rs:106:12 | LL | if let None = *(&None::<()>) {} | -------^^^^----------------- help: try this: `if (&None::<()>).is_none()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:106:12 + --> $DIR/redundant_pattern_matching_option.rs:107:12 | LL | if let None = *&None::<()> {} | -------^^^^--------------- help: try this: `if (&None::<()>).is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:112:5 + --> $DIR/redundant_pattern_matching_option.rs:113:5 | LL | / match x { LL | | Some(_) => true, @@ -158,7 +158,7 @@ LL | | }; | |_____^ help: try this: `x.is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:117:5 + --> $DIR/redundant_pattern_matching_option.rs:118:5 | LL | / match x { LL | | None => true, @@ -167,7 +167,7 @@ LL | | }; | |_____^ help: try this: `x.is_none()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:122:5 + --> $DIR/redundant_pattern_matching_option.rs:123:5 | LL | / match x { LL | | Some(_) => false, @@ -176,7 +176,7 @@ LL | | }; | |_____^ help: try this: `x.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:127:5 + --> $DIR/redundant_pattern_matching_option.rs:128:5 | LL | / match x { LL | | None => false, @@ -185,13 +185,13 @@ LL | | }; | |_____^ help: try this: `x.is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:142:13 + --> $DIR/redundant_pattern_matching_option.rs:143:13 | LL | let _ = matches!(x, Some(_)); | ^^^^^^^^^^^^^^^^^^^^ help: try this: `x.is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:144:13 + --> $DIR/redundant_pattern_matching_option.rs:145:13 | LL | let _ = matches!(x, None); | ^^^^^^^^^^^^^^^^^ help: try this: `x.is_none()` diff --git a/tests/ui/redundant_pattern_matching_poll.fixed b/tests/ui/redundant_pattern_matching_poll.fixed index bf3e692202c3..f739deaf58ea 100644 --- a/tests/ui/redundant_pattern_matching_poll.fixed +++ b/tests/ui/redundant_pattern_matching_poll.fixed @@ -5,6 +5,7 @@ #![allow( unused_must_use, clippy::needless_bool, + clippy::needless_if, clippy::match_like_matches_macro, clippy::equatable_if_let, clippy::if_same_then_else diff --git a/tests/ui/redundant_pattern_matching_poll.rs b/tests/ui/redundant_pattern_matching_poll.rs index 892a21d9d298..88dde02b38b7 100644 --- a/tests/ui/redundant_pattern_matching_poll.rs +++ b/tests/ui/redundant_pattern_matching_poll.rs @@ -5,6 +5,7 @@ #![allow( unused_must_use, clippy::needless_bool, + clippy::needless_if, clippy::match_like_matches_macro, clippy::equatable_if_let, clippy::if_same_then_else diff --git a/tests/ui/redundant_pattern_matching_poll.stderr b/tests/ui/redundant_pattern_matching_poll.stderr index 1b480f3157f7..b89fde35fcfa 100644 --- a/tests/ui/redundant_pattern_matching_poll.stderr +++ b/tests/ui/redundant_pattern_matching_poll.stderr @@ -1,5 +1,5 @@ error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:16:12 + --> $DIR/redundant_pattern_matching_poll.rs:17:12 | LL | if let Pending = Pending::<()> {} | -------^^^^^^^---------------- help: try this: `if Pending::<()>.is_pending()` @@ -7,37 +7,37 @@ LL | if let Pending = Pending::<()> {} = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:18:12 + --> $DIR/redundant_pattern_matching_poll.rs:19:12 | LL | if let Ready(_) = Ready(42) {} | -------^^^^^^^^------------ help: try this: `if Ready(42).is_ready()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:20:12 + --> $DIR/redundant_pattern_matching_poll.rs:21:12 | LL | if let Ready(_) = Ready(42) { | -------^^^^^^^^------------ help: try this: `if Ready(42).is_ready()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:26:15 + --> $DIR/redundant_pattern_matching_poll.rs:27:15 | LL | while let Ready(_) = Ready(42) {} | ----------^^^^^^^^------------ help: try this: `while Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:28:15 + --> $DIR/redundant_pattern_matching_poll.rs:29:15 | LL | while let Pending = Ready(42) {} | ----------^^^^^^^------------ help: try this: `while Ready(42).is_pending()` error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:30:15 + --> $DIR/redundant_pattern_matching_poll.rs:31:15 | LL | while let Pending = Pending::<()> {} | ----------^^^^^^^---------------- help: try this: `while Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:36:5 + --> $DIR/redundant_pattern_matching_poll.rs:37:5 | LL | / match Ready(42) { LL | | Ready(_) => true, @@ -46,7 +46,7 @@ LL | | }; | |_____^ help: try this: `Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:41:5 + --> $DIR/redundant_pattern_matching_poll.rs:42:5 | LL | / match Pending::<()> { LL | | Ready(_) => false, @@ -55,7 +55,7 @@ LL | | }; | |_____^ help: try this: `Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:46:13 + --> $DIR/redundant_pattern_matching_poll.rs:47:13 | LL | let _ = match Pending::<()> { | _____________^ @@ -65,49 +65,49 @@ LL | | }; | |_____^ help: try this: `Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:52:20 + --> $DIR/redundant_pattern_matching_poll.rs:53:20 | LL | let _ = if let Ready(_) = poll { true } else { false }; | -------^^^^^^^^------- help: try this: `if poll.is_ready()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:56:20 + --> $DIR/redundant_pattern_matching_poll.rs:57:20 | LL | let _ = if let Ready(_) = gen_poll() { | -------^^^^^^^^------------- help: try this: `if gen_poll().is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:58:19 + --> $DIR/redundant_pattern_matching_poll.rs:59:19 | LL | } else if let Pending = gen_poll() { | -------^^^^^^^------------- help: try this: `if gen_poll().is_pending()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:74:12 + --> $DIR/redundant_pattern_matching_poll.rs:75:12 | LL | if let Ready(_) = Ready(42) {} | -------^^^^^^^^------------ help: try this: `if Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:76:12 + --> $DIR/redundant_pattern_matching_poll.rs:77:12 | LL | if let Pending = Pending::<()> {} | -------^^^^^^^---------------- help: try this: `if Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:78:15 + --> $DIR/redundant_pattern_matching_poll.rs:79:15 | LL | while let Ready(_) = Ready(42) {} | ----------^^^^^^^^------------ help: try this: `while Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:80:15 + --> $DIR/redundant_pattern_matching_poll.rs:81:15 | LL | while let Pending = Pending::<()> {} | ----------^^^^^^^---------------- help: try this: `while Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_ready()` - --> $DIR/redundant_pattern_matching_poll.rs:82:5 + --> $DIR/redundant_pattern_matching_poll.rs:83:5 | LL | / match Ready(42) { LL | | Ready(_) => true, @@ -116,7 +116,7 @@ LL | | }; | |_____^ help: try this: `Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> $DIR/redundant_pattern_matching_poll.rs:87:5 + --> $DIR/redundant_pattern_matching_poll.rs:88:5 | LL | / match Pending::<()> { LL | | Ready(_) => false, diff --git a/tests/ui/redundant_pattern_matching_result.fixed b/tests/ui/redundant_pattern_matching_result.fixed index d77a2af76164..343e0d04340d 100644 --- a/tests/ui/redundant_pattern_matching_result.fixed +++ b/tests/ui/redundant_pattern_matching_result.fixed @@ -6,6 +6,7 @@ clippy::if_same_then_else, clippy::match_like_matches_macro, clippy::needless_bool, + clippy::needless_if, clippy::uninlined_format_args, clippy::unnecessary_wraps )] diff --git a/tests/ui/redundant_pattern_matching_result.rs b/tests/ui/redundant_pattern_matching_result.rs index aa884ac6bb1e..4d64eafe590c 100644 --- a/tests/ui/redundant_pattern_matching_result.rs +++ b/tests/ui/redundant_pattern_matching_result.rs @@ -6,6 +6,7 @@ clippy::if_same_then_else, clippy::match_like_matches_macro, clippy::needless_bool, + clippy::needless_if, clippy::uninlined_format_args, clippy::unnecessary_wraps )] diff --git a/tests/ui/redundant_pattern_matching_result.stderr b/tests/ui/redundant_pattern_matching_result.stderr index b462f7f41b9c..f6ce666bb4ff 100644 --- a/tests/ui/redundant_pattern_matching_result.stderr +++ b/tests/ui/redundant_pattern_matching_result.stderr @@ -1,5 +1,5 @@ error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_result.rs:15:12 + --> $DIR/redundant_pattern_matching_result.rs:16:12 | LL | if let Ok(_) = &result {} | -------^^^^^---------- help: try this: `if result.is_ok()` @@ -7,31 +7,31 @@ LL | if let Ok(_) = &result {} = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_result.rs:17:12 + --> $DIR/redundant_pattern_matching_result.rs:18:12 | LL | if let Ok(_) = Ok::(42) {} | -------^^^^^--------------------- help: try this: `if Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_result.rs:19:12 + --> $DIR/redundant_pattern_matching_result.rs:20:12 | LL | if let Err(_) = Err::(42) {} | -------^^^^^^---------------------- help: try this: `if Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_result.rs:21:15 + --> $DIR/redundant_pattern_matching_result.rs:22:15 | LL | while let Ok(_) = Ok::(10) {} | ----------^^^^^--------------------- help: try this: `while Ok::(10).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_result.rs:23:15 + --> $DIR/redundant_pattern_matching_result.rs:24:15 | LL | while let Err(_) = Ok::(10) {} | ----------^^^^^^--------------------- help: try this: `while Ok::(10).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_result.rs:33:5 + --> $DIR/redundant_pattern_matching_result.rs:34:5 | LL | / match Ok::(42) { LL | | Ok(_) => true, @@ -40,7 +40,7 @@ LL | | }; | |_____^ help: try this: `Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_result.rs:38:5 + --> $DIR/redundant_pattern_matching_result.rs:39:5 | LL | / match Ok::(42) { LL | | Ok(_) => false, @@ -49,7 +49,7 @@ LL | | }; | |_____^ help: try this: `Ok::(42).is_err()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_result.rs:43:5 + --> $DIR/redundant_pattern_matching_result.rs:44:5 | LL | / match Err::(42) { LL | | Ok(_) => false, @@ -58,7 +58,7 @@ LL | | }; | |_____^ help: try this: `Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_result.rs:48:5 + --> $DIR/redundant_pattern_matching_result.rs:49:5 | LL | / match Err::(42) { LL | | Ok(_) => true, @@ -67,73 +67,73 @@ LL | | }; | |_____^ help: try this: `Err::(42).is_ok()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_result.rs:53:20 + --> $DIR/redundant_pattern_matching_result.rs:54:20 | LL | let _ = if let Ok(_) = Ok::(4) { true } else { false }; | -------^^^^^--------------------- help: try this: `if Ok::(4).is_ok()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_result.rs:61:20 + --> $DIR/redundant_pattern_matching_result.rs:62:20 | LL | let _ = if let Ok(_) = gen_res() { | -------^^^^^------------ help: try this: `if gen_res().is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_result.rs:63:19 + --> $DIR/redundant_pattern_matching_result.rs:64:19 | LL | } else if let Err(_) = gen_res() { | -------^^^^^^------------ help: try this: `if gen_res().is_err()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_result.rs:86:19 + --> $DIR/redundant_pattern_matching_result.rs:87:19 | LL | while let Some(_) = r#try!(result_opt()) {} | ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_result.rs:87:16 + --> $DIR/redundant_pattern_matching_result.rs:88:16 | LL | if let Some(_) = r#try!(result_opt()) {} | -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_result.rs:93:12 + --> $DIR/redundant_pattern_matching_result.rs:94:12 | LL | if let Some(_) = m!() {} | -------^^^^^^^------- help: try this: `if m!().is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_result.rs:94:15 + --> $DIR/redundant_pattern_matching_result.rs:95:15 | LL | while let Some(_) = m!() {} | ----------^^^^^^^------- help: try this: `while m!().is_some()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_result.rs:112:12 + --> $DIR/redundant_pattern_matching_result.rs:113:12 | LL | if let Ok(_) = Ok::(42) {} | -------^^^^^--------------------- help: try this: `if Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_result.rs:114:12 + --> $DIR/redundant_pattern_matching_result.rs:115:12 | LL | if let Err(_) = Err::(42) {} | -------^^^^^^---------------------- help: try this: `if Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_result.rs:116:15 + --> $DIR/redundant_pattern_matching_result.rs:117:15 | LL | while let Ok(_) = Ok::(10) {} | ----------^^^^^--------------------- help: try this: `while Ok::(10).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_result.rs:118:15 + --> $DIR/redundant_pattern_matching_result.rs:119:15 | LL | while let Err(_) = Ok::(10) {} | ----------^^^^^^--------------------- help: try this: `while Ok::(10).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_result.rs:120:5 + --> $DIR/redundant_pattern_matching_result.rs:121:5 | LL | / match Ok::(42) { LL | | Ok(_) => true, @@ -142,7 +142,7 @@ LL | | }; | |_____^ help: try this: `Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_result.rs:125:5 + --> $DIR/redundant_pattern_matching_result.rs:126:5 | LL | / match Err::(42) { LL | | Ok(_) => false, @@ -151,7 +151,7 @@ LL | | }; | |_____^ help: try this: `Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_result.rs:135:5 + --> $DIR/redundant_pattern_matching_result.rs:136:5 | LL | / match x { LL | | Ok(_) => true, @@ -160,7 +160,7 @@ LL | | }; | |_____^ help: try this: `x.is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_result.rs:140:5 + --> $DIR/redundant_pattern_matching_result.rs:141:5 | LL | / match x { LL | | Ok(_) => false, @@ -169,7 +169,7 @@ LL | | }; | |_____^ help: try this: `x.is_err()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_result.rs:145:5 + --> $DIR/redundant_pattern_matching_result.rs:146:5 | LL | / match x { LL | | Err(_) => true, @@ -178,7 +178,7 @@ LL | | }; | |_____^ help: try this: `x.is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_result.rs:150:5 + --> $DIR/redundant_pattern_matching_result.rs:151:5 | LL | / match x { LL | | Err(_) => false, @@ -187,13 +187,13 @@ LL | | }; | |_____^ help: try this: `x.is_ok()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_result.rs:171:13 + --> $DIR/redundant_pattern_matching_result.rs:172:13 | LL | let _ = matches!(x, Ok(_)); | ^^^^^^^^^^^^^^^^^^ help: try this: `x.is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_result.rs:173:13 + --> $DIR/redundant_pattern_matching_result.rs:174:13 | LL | let _ = matches!(x, Err(_)); | ^^^^^^^^^^^^^^^^^^^ help: try this: `x.is_err()` diff --git a/tests/ui/redundant_pub_crate.fixed b/tests/ui/redundant_pub_crate.fixed index f65c0fdd35da..a1ed491bbc6e 100644 --- a/tests/ui/redundant_pub_crate.fixed +++ b/tests/ui/redundant_pub_crate.fixed @@ -14,7 +14,7 @@ mod m1 { } pub mod m1_2 { - // ^ private due to m1 + //:^ private due to m1 fn f() {} pub fn g() {} // private due to m1_2 and m1 pub fn h() {} @@ -39,7 +39,7 @@ pub(crate) mod m2 { } pub mod m2_2 { - // ^ already crate visible due to m2 + //:^ already crate visible due to m2 fn f() {} pub fn g() {} // already crate visible due to m2_2 and m2 pub fn h() {} @@ -64,7 +64,7 @@ pub mod m3 { } pub(crate) mod m3_2 { - // ^ ok + //:^ ok fn f() {} pub fn g() {} // already crate visible due to m3_2 pub fn h() {} @@ -89,7 +89,7 @@ mod m4 { } pub mod m4_2 { - // ^ private: not re-exported by `pub use m4::*` + //:^ private: not re-exported by `pub use m4::*` fn f() {} pub fn g() {} // private due to m4_2 pub fn h() {} diff --git a/tests/ui/redundant_pub_crate.rs b/tests/ui/redundant_pub_crate.rs index fb07fed98bef..9accd297fc93 100644 --- a/tests/ui/redundant_pub_crate.rs +++ b/tests/ui/redundant_pub_crate.rs @@ -14,7 +14,7 @@ mod m1 { } pub(crate) mod m1_2 { - // ^ private due to m1 + //:^ private due to m1 fn f() {} pub(crate) fn g() {} // private due to m1_2 and m1 pub fn h() {} @@ -39,7 +39,7 @@ pub(crate) mod m2 { } pub(crate) mod m2_2 { - // ^ already crate visible due to m2 + //:^ already crate visible due to m2 fn f() {} pub(crate) fn g() {} // already crate visible due to m2_2 and m2 pub fn h() {} @@ -64,7 +64,7 @@ pub mod m3 { } pub(crate) mod m3_2 { - // ^ ok + //:^ ok fn f() {} pub(crate) fn g() {} // already crate visible due to m3_2 pub fn h() {} @@ -89,7 +89,7 @@ mod m4 { } pub(crate) mod m4_2 { - // ^ private: not re-exported by `pub use m4::*` + //:^ private: not re-exported by `pub use m4::*` fn f() {} pub(crate) fn g() {} // private due to m4_2 pub fn h() {} diff --git a/tests/ui/redundant_static_lifetimes.fixed b/tests/ui/redundant_static_lifetimes.fixed index 2651735d1036..a83699ec68da 100644 --- a/tests/ui/redundant_static_lifetimes.fixed +++ b/tests/ui/redundant_static_lifetimes.fixed @@ -5,39 +5,39 @@ #[derive(Debug)] struct Foo; -const VAR_ONE: &str = "Test constant #1"; // ERROR Consider removing 'static. +const VAR_ONE: &str = "Test constant #1"; // ERROR: Consider removing 'static. const VAR_TWO: &str = "Test constant #2"; // This line should not raise a warning. -const VAR_THREE: &[&str] = &["one", "two"]; // ERROR Consider removing 'static +const VAR_THREE: &[&str] = &["one", "two"]; // ERROR: Consider removing 'static -const VAR_FOUR: (&str, (&str, &str), &str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static +const VAR_FOUR: (&str, (&str, &str), &str) = ("on", ("th", "th"), "on"); // ERROR: Consider removing 'static const VAR_SIX: &u8 = &5; const VAR_HEIGHT: &Foo = &Foo {}; -const VAR_SLICE: &[u8] = b"Test constant #1"; // ERROR Consider removing 'static. +const VAR_SLICE: &[u8] = b"Test constant #1"; // ERROR: Consider removing 'static. -const VAR_TUPLE: &(u8, u8) = &(1, 2); // ERROR Consider removing 'static. +const VAR_TUPLE: &(u8, u8) = &(1, 2); // ERROR: Consider removing 'static. -const VAR_ARRAY: &[u8; 1] = b"T"; // ERROR Consider removing 'static. +const VAR_ARRAY: &[u8; 1] = b"T"; // ERROR: Consider removing 'static. -static STATIC_VAR_ONE: &str = "Test static #1"; // ERROR Consider removing 'static. +static STATIC_VAR_ONE: &str = "Test static #1"; // ERROR: Consider removing 'static. static STATIC_VAR_TWO: &str = "Test static #2"; // This line should not raise a warning. -static STATIC_VAR_THREE: &[&str] = &["one", "two"]; // ERROR Consider removing 'static +static STATIC_VAR_THREE: &[&str] = &["one", "two"]; // ERROR: Consider removing 'static static STATIC_VAR_SIX: &u8 = &5; static STATIC_VAR_HEIGHT: &Foo = &Foo {}; -static STATIC_VAR_SLICE: &[u8] = b"Test static #3"; // ERROR Consider removing 'static. +static STATIC_VAR_SLICE: &[u8] = b"Test static #3"; // ERROR: Consider removing 'static. -static STATIC_VAR_TUPLE: &(u8, u8) = &(1, 2); // ERROR Consider removing 'static. +static STATIC_VAR_TUPLE: &(u8, u8) = &(1, 2); // ERROR: Consider removing 'static. -static STATIC_VAR_ARRAY: &[u8; 1] = b"T"; // ERROR Consider removing 'static. +static STATIC_VAR_ARRAY: &[u8; 1] = b"T"; // ERROR: Consider removing 'static. static mut STATIC_MUT_SLICE: &mut [u32] = &mut [0]; diff --git a/tests/ui/redundant_static_lifetimes.rs b/tests/ui/redundant_static_lifetimes.rs index 7286652899d6..b165cbaa3aa1 100644 --- a/tests/ui/redundant_static_lifetimes.rs +++ b/tests/ui/redundant_static_lifetimes.rs @@ -5,39 +5,39 @@ #[derive(Debug)] struct Foo; -const VAR_ONE: &'static str = "Test constant #1"; // ERROR Consider removing 'static. +const VAR_ONE: &'static str = "Test constant #1"; // ERROR: Consider removing 'static. const VAR_TWO: &str = "Test constant #2"; // This line should not raise a warning. -const VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR Consider removing 'static +const VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR: Consider removing 'static -const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static +const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR: Consider removing 'static const VAR_SIX: &'static u8 = &5; const VAR_HEIGHT: &'static Foo = &Foo {}; -const VAR_SLICE: &'static [u8] = b"Test constant #1"; // ERROR Consider removing 'static. +const VAR_SLICE: &'static [u8] = b"Test constant #1"; // ERROR: Consider removing 'static. -const VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR Consider removing 'static. +const VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR: Consider removing 'static. -const VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removing 'static. +const VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR: Consider removing 'static. -static STATIC_VAR_ONE: &'static str = "Test static #1"; // ERROR Consider removing 'static. +static STATIC_VAR_ONE: &'static str = "Test static #1"; // ERROR: Consider removing 'static. static STATIC_VAR_TWO: &str = "Test static #2"; // This line should not raise a warning. -static STATIC_VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR Consider removing 'static +static STATIC_VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR: Consider removing 'static static STATIC_VAR_SIX: &'static u8 = &5; static STATIC_VAR_HEIGHT: &'static Foo = &Foo {}; -static STATIC_VAR_SLICE: &'static [u8] = b"Test static #3"; // ERROR Consider removing 'static. +static STATIC_VAR_SLICE: &'static [u8] = b"Test static #3"; // ERROR: Consider removing 'static. -static STATIC_VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR Consider removing 'static. +static STATIC_VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR: Consider removing 'static. -static STATIC_VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removing 'static. +static STATIC_VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR: Consider removing 'static. static mut STATIC_MUT_SLICE: &'static mut [u32] = &mut [0]; diff --git a/tests/ui/redundant_static_lifetimes.stderr b/tests/ui/redundant_static_lifetimes.stderr index b2cbd2d9d01b..a13e5eadf15d 100644 --- a/tests/ui/redundant_static_lifetimes.stderr +++ b/tests/ui/redundant_static_lifetimes.stderr @@ -1,7 +1,7 @@ error: constants have by default a `'static` lifetime --> $DIR/redundant_static_lifetimes.rs:8:17 | -LL | const VAR_ONE: &'static str = "Test constant #1"; // ERROR Consider removing 'static. +LL | const VAR_ONE: &'static str = "Test constant #1"; // ERROR: Consider removing 'static. | -^^^^^^^---- help: consider removing `'static`: `&str` | = note: `-D clippy::redundant-static-lifetimes` implied by `-D warnings` @@ -9,19 +9,19 @@ LL | const VAR_ONE: &'static str = "Test constant #1"; // ERROR Consider removin error: constants have by default a `'static` lifetime --> $DIR/redundant_static_lifetimes.rs:12:21 | -LL | const VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR Consider removing 'static +LL | const VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR: Consider removing 'static | -^^^^^^^---- help: consider removing `'static`: `&str` error: constants have by default a `'static` lifetime --> $DIR/redundant_static_lifetimes.rs:14:32 | -LL | const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static +LL | const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR: Consider removing 'static | -^^^^^^^---- help: consider removing `'static`: `&str` error: constants have by default a `'static` lifetime --> $DIR/redundant_static_lifetimes.rs:14:47 | -LL | const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static +LL | const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR: Consider removing 'static | -^^^^^^^---- help: consider removing `'static`: `&str` error: constants have by default a `'static` lifetime @@ -39,31 +39,31 @@ LL | const VAR_HEIGHT: &'static Foo = &Foo {}; error: constants have by default a `'static` lifetime --> $DIR/redundant_static_lifetimes.rs:20:19 | -LL | const VAR_SLICE: &'static [u8] = b"Test constant #1"; // ERROR Consider removing 'static. +LL | const VAR_SLICE: &'static [u8] = b"Test constant #1"; // ERROR: Consider removing 'static. | -^^^^^^^----- help: consider removing `'static`: `&[u8]` error: constants have by default a `'static` lifetime --> $DIR/redundant_static_lifetimes.rs:22:19 | -LL | const VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR Consider removing 'static. +LL | const VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR: Consider removing 'static. | -^^^^^^^--------- help: consider removing `'static`: `&(u8, u8)` error: constants have by default a `'static` lifetime --> $DIR/redundant_static_lifetimes.rs:24:19 | -LL | const VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removing 'static. +LL | const VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR: Consider removing 'static. | -^^^^^^^-------- help: consider removing `'static`: `&[u8; 1]` error: statics have by default a `'static` lifetime --> $DIR/redundant_static_lifetimes.rs:26:25 | -LL | static STATIC_VAR_ONE: &'static str = "Test static #1"; // ERROR Consider removing 'static. +LL | static STATIC_VAR_ONE: &'static str = "Test static #1"; // ERROR: Consider removing 'static. | -^^^^^^^---- help: consider removing `'static`: `&str` error: statics have by default a `'static` lifetime --> $DIR/redundant_static_lifetimes.rs:30:29 | -LL | static STATIC_VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR Consider removing 'static +LL | static STATIC_VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR: Consider removing 'static | -^^^^^^^---- help: consider removing `'static`: `&str` error: statics have by default a `'static` lifetime @@ -81,19 +81,19 @@ LL | static STATIC_VAR_HEIGHT: &'static Foo = &Foo {}; error: statics have by default a `'static` lifetime --> $DIR/redundant_static_lifetimes.rs:36:27 | -LL | static STATIC_VAR_SLICE: &'static [u8] = b"Test static #3"; // ERROR Consider removing 'static. +LL | static STATIC_VAR_SLICE: &'static [u8] = b"Test static #3"; // ERROR: Consider removing 'static. | -^^^^^^^----- help: consider removing `'static`: `&[u8]` error: statics have by default a `'static` lifetime --> $DIR/redundant_static_lifetimes.rs:38:27 | -LL | static STATIC_VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR Consider removing 'static. +LL | static STATIC_VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR: Consider removing 'static. | -^^^^^^^--------- help: consider removing `'static`: `&(u8, u8)` error: statics have by default a `'static` lifetime --> $DIR/redundant_static_lifetimes.rs:40:27 | -LL | static STATIC_VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removing 'static. +LL | static STATIC_VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR: Consider removing 'static. | -^^^^^^^-------- help: consider removing `'static`: `&[u8; 1]` error: statics have by default a `'static` lifetime diff --git a/tests/ui/redundant_static_lifetimes_multiple.rs b/tests/ui/redundant_static_lifetimes_multiple.rs index f57dd58e230a..b3f263a7d66d 100644 --- a/tests/ui/redundant_static_lifetimes_multiple.rs +++ b/tests/ui/redundant_static_lifetimes_multiple.rs @@ -1,12 +1,12 @@ // these are rustfixable, but run-rustfix tests cannot handle them -const VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR Consider removing 'static +const VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR: Consider removing 'static const VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])]; -static STATIC_VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static +static STATIC_VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR: Consider removing 'static -static STATIC_VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR Consider removing 'static +static STATIC_VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR: Consider removing 'static static STATIC_VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])]; diff --git a/tests/ui/redundant_static_lifetimes_multiple.stderr b/tests/ui/redundant_static_lifetimes_multiple.stderr index cc7e55a757a3..4e7500903f81 100644 --- a/tests/ui/redundant_static_lifetimes_multiple.stderr +++ b/tests/ui/redundant_static_lifetimes_multiple.stderr @@ -1,7 +1,7 @@ error: constants have by default a `'static` lifetime --> $DIR/redundant_static_lifetimes_multiple.rs:3:18 | -LL | const VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR Consider removing 'static +LL | const VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR: Consider removing 'static | -^^^^^^^------------------ help: consider removing `'static`: `&[&[&'static str]]` | = note: `-D clippy::redundant-static-lifetimes` implied by `-D warnings` @@ -9,7 +9,7 @@ LL | const VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; error: constants have by default a `'static` lifetime --> $DIR/redundant_static_lifetimes_multiple.rs:3:30 | -LL | const VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR Consider removing 'static +LL | const VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR: Consider removing 'static | -^^^^^^^---- help: consider removing `'static`: `&str` error: constants have by default a `'static` lifetime @@ -27,25 +27,25 @@ LL | const VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other error: statics have by default a `'static` lifetime --> $DIR/redundant_static_lifetimes_multiple.rs:7:40 | -LL | static STATIC_VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static +LL | static STATIC_VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR: Consider removing 'static | -^^^^^^^---- help: consider removing `'static`: `&str` error: statics have by default a `'static` lifetime --> $DIR/redundant_static_lifetimes_multiple.rs:7:55 | -LL | static STATIC_VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static +LL | static STATIC_VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR: Consider removing 'static | -^^^^^^^---- help: consider removing `'static`: `&str` error: statics have by default a `'static` lifetime --> $DIR/redundant_static_lifetimes_multiple.rs:9:26 | -LL | static STATIC_VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR Consider removing 'static +LL | static STATIC_VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR: Consider removing 'static | -^^^^^^^------------------ help: consider removing `'static`: `&[&[&'static str]]` error: statics have by default a `'static` lifetime --> $DIR/redundant_static_lifetimes_multiple.rs:9:38 | -LL | static STATIC_VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR Consider removing 'static +LL | static STATIC_VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR: Consider removing 'static | -^^^^^^^---- help: consider removing `'static`: `&str` error: statics have by default a `'static` lifetime diff --git a/tests/ui/redundant_type_annotations.rs b/tests/ui/redundant_type_annotations.rs new file mode 100644 index 000000000000..cc507b8d658c --- /dev/null +++ b/tests/ui/redundant_type_annotations.rs @@ -0,0 +1,176 @@ +#![allow(unused)] +#![warn(clippy::redundant_type_annotations)] + +#[derive(Debug, Default)] +struct Cake { + _data: T, +} + +fn make_something() -> T { + T::default() +} + +fn make_cake() -> Cake { + Cake::::default() +} + +fn plus_one>(val: T) -> T { + val + 1 +} + +#[derive(Default)] +struct Slice { + inner: u32, +} + +#[derive(Default)] +struct Pie { + inner: u32, + inner_struct: Slice, +} + +enum Pizza { + One, + Two, +} + +fn return_a_string() -> String { + String::new() +} + +fn return_a_struct() -> Pie { + Pie::default() +} + +fn return_an_enum() -> Pizza { + Pizza::One +} + +fn return_an_int() -> u32 { + 5 +} + +impl Pie { + fn return_an_int(&self) -> u32 { + self.inner + } + + fn return_a_ref(&self) -> &u32 { + &self.inner + } + + fn return_a_ref_to_struct(&self) -> &Slice { + &self.inner_struct + } + + fn associated_return_an_int() -> u32 { + 5 + } + + fn new() -> Self { + Self::default() + } + + fn associated_return_a_string() -> String { + String::from("") + } + + fn test_method_call(&self) { + // Everything here should be lint + + let v: u32 = self.return_an_int(); + let v: &u32 = self.return_a_ref(); + let v: &Slice = self.return_a_ref_to_struct(); + } +} + +fn test_generics() { + // The type annotation is needed to determine T + let _c: Cake = make_something(); + + // The type annotation is needed to determine the topic + let _c: Cake = make_cake(); + + // This could be lint, but currently doesn't + let _c: Cake = make_cake::(); + + // This could be lint, but currently doesn't + let _c: u8 = make_something::(); + + // This could be lint, but currently doesn't + let _c: u8 = plus_one(5_u8); + + // Annotation needed otherwise T is i32 + let _c: u8 = plus_one(5); + + // This could be lint, but currently doesn't + let _return: String = String::from("test"); +} + +fn test_non_locals() { + // This shouldn't be lint + fn _arg(x: u32) -> u32 { + x + } + + // This could lint, but probably shouldn't + let _closure_arg = |x: u32| x; +} + +fn test_complex_types() { + // Shouldn't be lint, since the literal will be i32 otherwise + let _u8: u8 = 128; + + // This could be lint, but currently doesn't + let _tuple_i32: (i32, i32) = (12, 13); + + // Shouldn't be lint, since the tuple will be i32 otherwise + let _tuple_u32: (u32, u32) = (1, 2); + + // Should be lint, since the type is determined by the init value, but currently doesn't + let _tuple_u32: (u32, u32) = (3_u32, 4_u32); + + // This could be lint, but currently doesn't + let _array: [i32; 3] = [5, 6, 7]; + + // Shouldn't be lint + let _array: [u32; 2] = [8, 9]; +} + +fn test_functions() { + // Everything here should be lint + + let _return: String = return_a_string(); + + let _return: Pie = return_a_struct(); + + let _return: Pizza = return_an_enum(); + + let _return: u32 = return_an_int(); + + let _return: String = String::new(); + + let new_pie: Pie = Pie::new(); + + let _return: u32 = new_pie.return_an_int(); + + let _return: u32 = Pie::associated_return_an_int(); + + let _return: String = Pie::associated_return_a_string(); +} + +fn test_simple_types() { + // Everything here should be lint + + let _var: u32 = u32::MAX; + + let _var: u32 = 5_u32; + + let _var: &str = "test"; + + let _var: &[u8] = b"test"; + + let _var: bool = false; +} + +fn main() {} diff --git a/tests/ui/redundant_type_annotations.stderr b/tests/ui/redundant_type_annotations.stderr new file mode 100644 index 000000000000..e8b2fe5c3847 --- /dev/null +++ b/tests/ui/redundant_type_annotations.stderr @@ -0,0 +1,106 @@ +error: redundant type annotation + --> $DIR/redundant_type_annotations.rs:81:9 + | +LL | let v: u32 = self.return_an_int(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::redundant-type-annotations` implied by `-D warnings` + +error: redundant type annotation + --> $DIR/redundant_type_annotations.rs:82:9 + | +LL | let v: &u32 = self.return_a_ref(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: redundant type annotation + --> $DIR/redundant_type_annotations.rs:83:9 + | +LL | let v: &Slice = self.return_a_ref_to_struct(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: redundant type annotation + --> $DIR/redundant_type_annotations.rs:143:5 + | +LL | let _return: String = return_a_string(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: redundant type annotation + --> $DIR/redundant_type_annotations.rs:145:5 + | +LL | let _return: Pie = return_a_struct(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: redundant type annotation + --> $DIR/redundant_type_annotations.rs:147:5 + | +LL | let _return: Pizza = return_an_enum(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: redundant type annotation + --> $DIR/redundant_type_annotations.rs:149:5 + | +LL | let _return: u32 = return_an_int(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: redundant type annotation + --> $DIR/redundant_type_annotations.rs:151:5 + | +LL | let _return: String = String::new(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: redundant type annotation + --> $DIR/redundant_type_annotations.rs:153:5 + | +LL | let new_pie: Pie = Pie::new(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: redundant type annotation + --> $DIR/redundant_type_annotations.rs:155:5 + | +LL | let _return: u32 = new_pie.return_an_int(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: redundant type annotation + --> $DIR/redundant_type_annotations.rs:157:5 + | +LL | let _return: u32 = Pie::associated_return_an_int(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: redundant type annotation + --> $DIR/redundant_type_annotations.rs:159:5 + | +LL | let _return: String = Pie::associated_return_a_string(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: redundant type annotation + --> $DIR/redundant_type_annotations.rs:165:5 + | +LL | let _var: u32 = u32::MAX; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: redundant type annotation + --> $DIR/redundant_type_annotations.rs:167:5 + | +LL | let _var: u32 = 5_u32; + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: redundant type annotation + --> $DIR/redundant_type_annotations.rs:169:5 + | +LL | let _var: &str = "test"; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: redundant type annotation + --> $DIR/redundant_type_annotations.rs:171:5 + | +LL | let _var: &[u8] = b"test"; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: redundant type annotation + --> $DIR/redundant_type_annotations.rs:173:5 + | +LL | let _var: bool = false; + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 17 previous errors + diff --git a/tests/ui/regex.rs b/tests/ui/regex.rs index 1c8e47ab5949..89d1d9494545 100644 --- a/tests/ui/regex.rs +++ b/tests/ui/regex.rs @@ -1,4 +1,9 @@ -#![allow(unused, clippy::needless_borrow)] +#![allow( + unused, + clippy::needless_raw_strings, + clippy::needless_raw_string_hashes, + clippy::needless_borrow +)] #![warn(clippy::invalid_regex, clippy::trivial_regex)] extern crate regex; diff --git a/tests/ui/regex.stderr b/tests/ui/regex.stderr index 1e8a21283cd9..21f1cb44460e 100644 --- a/tests/ui/regex.stderr +++ b/tests/ui/regex.stderr @@ -1,5 +1,5 @@ error: trivial regex - --> $DIR/regex.rs:13:45 + --> $DIR/regex.rs:18:45 | LL | let pipe_in_wrong_position = Regex::new("|"); | ^^^ @@ -8,7 +8,7 @@ LL | let pipe_in_wrong_position = Regex::new("|"); = note: `-D clippy::trivial-regex` implied by `-D warnings` error: trivial regex - --> $DIR/regex.rs:14:60 + --> $DIR/regex.rs:19:60 | LL | let pipe_in_wrong_position_builder = RegexBuilder::new("|"); | ^^^ @@ -16,7 +16,7 @@ LL | let pipe_in_wrong_position_builder = RegexBuilder::new("|"); = help: the regex is unlikely to be useful as it is error: regex syntax error: invalid character class range, the start must be <= the end - --> $DIR/regex.rs:15:42 + --> $DIR/regex.rs:20:42 | LL | let wrong_char_ranice = Regex::new("[z-a]"); | ^^^ @@ -24,7 +24,7 @@ LL | let wrong_char_ranice = Regex::new("[z-a]"); = note: `-D clippy::invalid-regex` implied by `-D warnings` error: regex syntax error: invalid character class range, the start must be <= the end - --> $DIR/regex.rs:16:37 + --> $DIR/regex.rs:21:37 | LL | let some_unicode = Regex::new("[é-è]"); | ^^^ @@ -33,13 +33,13 @@ error: regex parse error: ( ^ error: unclosed group - --> $DIR/regex.rs:18:33 + --> $DIR/regex.rs:23:33 | LL | let some_regex = Regex::new(OPENING_PAREN); | ^^^^^^^^^^^^^ error: trivial regex - --> $DIR/regex.rs:20:53 + --> $DIR/regex.rs:25:53 | LL | let binary_pipe_in_wrong_position = BRegex::new("|"); | ^^^ @@ -50,7 +50,7 @@ error: regex parse error: ( ^ error: unclosed group - --> $DIR/regex.rs:21:41 + --> $DIR/regex.rs:26:41 | LL | let some_binary_regex = BRegex::new(OPENING_PAREN); | ^^^^^^^^^^^^^ @@ -59,7 +59,7 @@ error: regex parse error: ( ^ error: unclosed group - --> $DIR/regex.rs:22:56 + --> $DIR/regex.rs:27:56 | LL | let some_binary_regex_builder = BRegexBuilder::new(OPENING_PAREN); | ^^^^^^^^^^^^^ @@ -68,7 +68,7 @@ error: regex parse error: ( ^ error: unclosed group - --> $DIR/regex.rs:34:37 + --> $DIR/regex.rs:39:37 | LL | let set_error = RegexSet::new(&[OPENING_PAREN, r"[a-z]+/.(com|org|net)"]); | ^^^^^^^^^^^^^ @@ -77,7 +77,7 @@ error: regex parse error: ( ^ error: unclosed group - --> $DIR/regex.rs:35:39 + --> $DIR/regex.rs:40:39 | LL | let bset_error = BRegexSet::new(&[OPENING_PAREN, r"[a-z]+/.(com|org|net)"]); | ^^^^^^^^^^^^^ @@ -86,27 +86,27 @@ error: regex parse error: /b/c ^^ error: unrecognized escape sequence - --> $DIR/regex.rs:42:42 + --> $DIR/regex.rs:47:42 | -LL | let escaped_string_span = Regex::new("/b/c"); +LL | let escaped_string_span = Regex::new("//b//c"); | ^^^^^^^^ | = help: consider using a raw string literal: `r".."` error: regex syntax error: duplicate flag - --> $DIR/regex.rs:44:34 + --> $DIR/regex.rs:49:34 | LL | let aux_span = Regex::new("(?ixi)"); | ^ ^ error: regex syntax error: pattern can match invalid UTF-8 - --> $DIR/regex.rs:49:53 + --> $DIR/regex.rs:54:53 | LL | let invalid_utf8_should_lint = Regex::new("(?-u)."); | ^ error: trivial regex - --> $DIR/regex.rs:53:33 + --> $DIR/regex.rs:58:33 | LL | let trivial_eq = Regex::new("^foobar$"); | ^^^^^^^^^^ @@ -114,7 +114,7 @@ LL | let trivial_eq = Regex::new("^foobar$"); = help: consider using `==` on `str`s error: trivial regex - --> $DIR/regex.rs:55:48 + --> $DIR/regex.rs:60:48 | LL | let trivial_eq_builder = RegexBuilder::new("^foobar$"); | ^^^^^^^^^^ @@ -122,7 +122,7 @@ LL | let trivial_eq_builder = RegexBuilder::new("^foobar$"); = help: consider using `==` on `str`s error: trivial regex - --> $DIR/regex.rs:57:42 + --> $DIR/regex.rs:62:42 | LL | let trivial_starts_with = Regex::new("^foobar"); | ^^^^^^^^^ @@ -130,7 +130,7 @@ LL | let trivial_starts_with = Regex::new("^foobar"); = help: consider using `str::starts_with` error: trivial regex - --> $DIR/regex.rs:59:40 + --> $DIR/regex.rs:64:40 | LL | let trivial_ends_with = Regex::new("foobar$"); | ^^^^^^^^^ @@ -138,7 +138,7 @@ LL | let trivial_ends_with = Regex::new("foobar$"); = help: consider using `str::ends_with` error: trivial regex - --> $DIR/regex.rs:61:39 + --> $DIR/regex.rs:66:39 | LL | let trivial_contains = Regex::new("foobar"); | ^^^^^^^^ @@ -146,7 +146,7 @@ LL | let trivial_contains = Regex::new("foobar"); = help: consider using `str::contains` error: trivial regex - --> $DIR/regex.rs:63:39 + --> $DIR/regex.rs:68:39 | LL | let trivial_contains = Regex::new(NOT_A_REAL_REGEX); | ^^^^^^^^^^^^^^^^ @@ -154,15 +154,15 @@ LL | let trivial_contains = Regex::new(NOT_A_REAL_REGEX); = help: consider using `str::contains` error: trivial regex - --> $DIR/regex.rs:65:40 + --> $DIR/regex.rs:70:40 | -LL | let trivial_backslash = Regex::new("a/.b"); +LL | let trivial_backslash = Regex::new("a//.b"); | ^^^^^^^ | = help: consider using `str::contains` error: trivial regex - --> $DIR/regex.rs:68:36 + --> $DIR/regex.rs:73:36 | LL | let trivial_empty = Regex::new(""); | ^^ @@ -170,7 +170,7 @@ LL | let trivial_empty = Regex::new(""); = help: the regex is unlikely to be useful as it is error: trivial regex - --> $DIR/regex.rs:70:36 + --> $DIR/regex.rs:75:36 | LL | let trivial_empty = Regex::new("^"); | ^^^ @@ -178,7 +178,7 @@ LL | let trivial_empty = Regex::new("^"); = help: the regex is unlikely to be useful as it is error: trivial regex - --> $DIR/regex.rs:72:36 + --> $DIR/regex.rs:77:36 | LL | let trivial_empty = Regex::new("^$"); | ^^^^ @@ -186,7 +186,7 @@ LL | let trivial_empty = Regex::new("^$"); = help: consider using `str::is_empty` error: trivial regex - --> $DIR/regex.rs:74:44 + --> $DIR/regex.rs:79:44 | LL | let binary_trivial_empty = BRegex::new("^$"); | ^^^^ diff --git a/tests/ui/rename.fixed b/tests/ui/rename.fixed index f1b25dc094ef..b24c83d9a0da 100644 --- a/tests/ui/rename.fixed +++ b/tests/ui/rename.fixed @@ -30,7 +30,7 @@ #![allow(clippy::invisible_characters)] #![allow(cast_ref_to_mut)] #![allow(suspicious_double_ref_op)] -#![allow(cast_ref_to_mut)] +#![allow(invalid_nan_comparisons)] #![allow(drop_bounds)] #![allow(dropping_copy_types)] #![allow(dropping_references)] @@ -41,12 +41,10 @@ #![allow(invalid_atomic_ordering)] #![allow(invalid_value)] #![allow(invalid_from_utf8_unchecked)] -#![allow(invalid_nan_comparisons)] #![allow(let_underscore_drop)] #![allow(enum_intrinsics_non_enums)] #![allow(non_fmt_panics)] #![allow(named_arguments_used_positionally)] -#![allow(suspicious_double_ref_op)] #![allow(temporary_cstring_as_ptr)] #![allow(undropped_manually_drops)] #![allow(unknown_lints)] @@ -56,7 +54,6 @@ #![warn(clippy::blocks_in_if_conditions)] #![warn(clippy::blocks_in_if_conditions)] #![warn(clippy::box_collection)] -#![warn(invalid_nan_comparisons)] #![warn(clippy::redundant_static_lifetimes)] #![warn(clippy::cognitive_complexity)] #![warn(clippy::derived_hash_with_manual_eq)] @@ -83,6 +80,7 @@ #![warn(clippy::invisible_characters)] #![warn(cast_ref_to_mut)] #![warn(suspicious_double_ref_op)] +#![warn(invalid_nan_comparisons)] #![warn(drop_bounds)] #![warn(dropping_copy_types)] #![warn(dropping_references)] diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs index 4af511c344c4..baa6345a64f8 100644 --- a/tests/ui/rename.rs +++ b/tests/ui/rename.rs @@ -30,7 +30,7 @@ #![allow(clippy::invisible_characters)] #![allow(cast_ref_to_mut)] #![allow(suspicious_double_ref_op)] -#![allow(cast_ref_to_mut)] +#![allow(invalid_nan_comparisons)] #![allow(drop_bounds)] #![allow(dropping_copy_types)] #![allow(dropping_references)] @@ -41,12 +41,10 @@ #![allow(invalid_atomic_ordering)] #![allow(invalid_value)] #![allow(invalid_from_utf8_unchecked)] -#![allow(invalid_nan_comparisons)] #![allow(let_underscore_drop)] #![allow(enum_intrinsics_non_enums)] #![allow(non_fmt_panics)] #![allow(named_arguments_used_positionally)] -#![allow(suspicious_double_ref_op)] #![allow(temporary_cstring_as_ptr)] #![allow(undropped_manually_drops)] #![allow(unknown_lints)] @@ -56,7 +54,6 @@ #![warn(clippy::block_in_if_condition_expr)] #![warn(clippy::block_in_if_condition_stmt)] #![warn(clippy::box_vec)] -#![warn(clippy::cmp_nan)] #![warn(clippy::const_static_lifetime)] #![warn(clippy::cyclomatic_complexity)] #![warn(clippy::derive_hash_xor_eq)] @@ -83,6 +80,7 @@ #![warn(clippy::zero_width_space)] #![warn(clippy::cast_ref_to_mut)] #![warn(clippy::clone_double_ref)] +#![warn(clippy::cmp_nan)] #![warn(clippy::drop_bounds)] #![warn(clippy::drop_copy)] #![warn(clippy::drop_ref)] diff --git a/tests/ui/rename.stderr b/tests/ui/rename.stderr index 156a8f96b502..ae25c3b46bd2 100644 --- a/tests/ui/rename.stderr +++ b/tests/ui/rename.stderr @@ -1,5 +1,5 @@ error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range` - --> $DIR/rename.rs:54:9 + --> $DIR/rename.rs:52:9 | LL | #![warn(clippy::almost_complete_letter_range)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range` @@ -7,307 +7,307 @@ LL | #![warn(clippy::almost_complete_letter_range)] = note: `-D renamed-and-removed-lints` implied by `-D warnings` error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names` - --> $DIR/rename.rs:55:9 + --> $DIR/rename.rs:53:9 | LL | #![warn(clippy::blacklisted_name)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names` error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:56:9 + --> $DIR/rename.rs:54:9 | LL | #![warn(clippy::block_in_if_condition_expr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:57:9 + --> $DIR/rename.rs:55:9 | LL | #![warn(clippy::block_in_if_condition_stmt)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::box_vec` has been renamed to `clippy::box_collection` - --> $DIR/rename.rs:58:9 + --> $DIR/rename.rs:56:9 | LL | #![warn(clippy::box_vec)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection` -error: lint `clippy::cmp_nan` has been renamed to `invalid_nan_comparisons` - --> $DIR/rename.rs:59:9 - | -LL | #![warn(clippy::cmp_nan)] - | ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons` - error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` - --> $DIR/rename.rs:60:9 + --> $DIR/rename.rs:57:9 | LL | #![warn(clippy::const_static_lifetime)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity` - --> $DIR/rename.rs:61:9 + --> $DIR/rename.rs:58:9 | LL | #![warn(clippy::cyclomatic_complexity)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity` error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq` - --> $DIR/rename.rs:62:9 + --> $DIR/rename.rs:59:9 | LL | #![warn(clippy::derive_hash_xor_eq)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq` error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods` - --> $DIR/rename.rs:63:9 + --> $DIR/rename.rs:60:9 | LL | #![warn(clippy::disallowed_method)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods` error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types` - --> $DIR/rename.rs:64:9 + --> $DIR/rename.rs:61:9 | LL | #![warn(clippy::disallowed_type)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types` error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression` - --> $DIR/rename.rs:65:9 + --> $DIR/rename.rs:62:9 | LL | #![warn(clippy::eval_order_dependence)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression` error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` - --> $DIR/rename.rs:66:9 + --> $DIR/rename.rs:63:9 | LL | #![warn(clippy::identity_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` - --> $DIR/rename.rs:67:9 + --> $DIR/rename.rs:64:9 | LL | #![warn(clippy::if_let_some_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok` error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects` - --> $DIR/rename.rs:68:9 + --> $DIR/rename.rs:65:9 | LL | #![warn(clippy::integer_arithmetic)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects` error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr` - --> $DIR/rename.rs:69:9 + --> $DIR/rename.rs:66:9 | LL | #![warn(clippy::logic_bug)] | ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr` error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` - --> $DIR/rename.rs:70:9 + --> $DIR/rename.rs:67:9 | LL | #![warn(clippy::new_without_default_derive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map` - --> $DIR/rename.rs:71:9 + --> $DIR/rename.rs:68:9 | LL | #![warn(clippy::option_and_then_some)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map` error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:72:9 + --> $DIR/rename.rs:69:9 | LL | #![warn(clippy::option_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:73:9 + --> $DIR/rename.rs:70:9 | LL | #![warn(clippy::option_map_unwrap_or)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:74:9 + --> $DIR/rename.rs:71:9 | LL | #![warn(clippy::option_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:75:9 + --> $DIR/rename.rs:72:9 | LL | #![warn(clippy::option_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow` - --> $DIR/rename.rs:76:9 + --> $DIR/rename.rs:73:9 | LL | #![warn(clippy::ref_in_deref)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow` error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:77:9 + --> $DIR/rename.rs:74:9 | LL | #![warn(clippy::result_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:78:9 + --> $DIR/rename.rs:75:9 | LL | #![warn(clippy::result_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:79:9 + --> $DIR/rename.rs:76:9 | LL | #![warn(clippy::result_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` - --> $DIR/rename.rs:80:9 + --> $DIR/rename.rs:77:9 | LL | #![warn(clippy::single_char_push_str)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str` error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` - --> $DIR/rename.rs:81:9 + --> $DIR/rename.rs:78:9 | LL | #![warn(clippy::stutter)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl` - --> $DIR/rename.rs:82:9 + --> $DIR/rename.rs:79:9 | LL | #![warn(clippy::to_string_in_display)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl` error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters` - --> $DIR/rename.rs:83:9 + --> $DIR/rename.rs:80:9 | LL | #![warn(clippy::zero_width_space)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters` error: lint `clippy::cast_ref_to_mut` has been renamed to `cast_ref_to_mut` - --> $DIR/rename.rs:84:9 + --> $DIR/rename.rs:81:9 | LL | #![warn(clippy::cast_ref_to_mut)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `cast_ref_to_mut` error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op` - --> $DIR/rename.rs:85:9 + --> $DIR/rename.rs:82:9 | LL | #![warn(clippy::clone_double_ref)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op` +error: lint `clippy::cmp_nan` has been renamed to `invalid_nan_comparisons` + --> $DIR/rename.rs:83:9 + | +LL | #![warn(clippy::cmp_nan)] + | ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons` + error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` - --> $DIR/rename.rs:86:9 + --> $DIR/rename.rs:84:9 | LL | #![warn(clippy::drop_bounds)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types` - --> $DIR/rename.rs:87:9 + --> $DIR/rename.rs:85:9 | LL | #![warn(clippy::drop_copy)] | ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types` error: lint `clippy::drop_ref` has been renamed to `dropping_references` - --> $DIR/rename.rs:88:9 + --> $DIR/rename.rs:86:9 | LL | #![warn(clippy::drop_ref)] | ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references` error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:89:9 + --> $DIR/rename.rs:87:9 | LL | #![warn(clippy::for_loop_over_option)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:90:9 + --> $DIR/rename.rs:88:9 | LL | #![warn(clippy::for_loop_over_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:91:9 + --> $DIR/rename.rs:89:9 | LL | #![warn(clippy::for_loops_over_fallibles)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types` - --> $DIR/rename.rs:92:9 + --> $DIR/rename.rs:90:9 | LL | #![warn(clippy::forget_copy)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types` error: lint `clippy::forget_ref` has been renamed to `forgetting_references` - --> $DIR/rename.rs:93:9 + --> $DIR/rename.rs:91:9 | LL | #![warn(clippy::forget_ref)] | ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references` error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` - --> $DIR/rename.rs:94:9 + --> $DIR/rename.rs:92:9 | LL | #![warn(clippy::into_iter_on_array)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` - --> $DIR/rename.rs:95:9 + --> $DIR/rename.rs:93:9 | LL | #![warn(clippy::invalid_atomic_ordering)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` error: lint `clippy::invalid_ref` has been renamed to `invalid_value` - --> $DIR/rename.rs:96:9 + --> $DIR/rename.rs:94:9 | LL | #![warn(clippy::invalid_ref)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked` - --> $DIR/rename.rs:97:9 + --> $DIR/rename.rs:95:9 | LL | #![warn(clippy::invalid_utf8_in_unchecked)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked` error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop` - --> $DIR/rename.rs:98:9 + --> $DIR/rename.rs:96:9 | LL | #![warn(clippy::let_underscore_drop)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop` error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` - --> $DIR/rename.rs:99:9 + --> $DIR/rename.rs:97:9 | LL | #![warn(clippy::mem_discriminant_non_enum)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` - --> $DIR/rename.rs:100:9 + --> $DIR/rename.rs:98:9 | LL | #![warn(clippy::panic_params)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally` - --> $DIR/rename.rs:101:9 + --> $DIR/rename.rs:99:9 | LL | #![warn(clippy::positional_named_format_parameters)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally` error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr` - --> $DIR/rename.rs:102:9 + --> $DIR/rename.rs:100:9 | LL | #![warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr` error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops` - --> $DIR/rename.rs:103:9 + --> $DIR/rename.rs:101:9 | LL | #![warn(clippy::undropped_manually_drops)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `undropped_manually_drops` error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` - --> $DIR/rename.rs:104:9 + --> $DIR/rename.rs:102:9 | LL | #![warn(clippy::unknown_clippy_lints)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` error: lint `clippy::unused_label` has been renamed to `unused_labels` - --> $DIR/rename.rs:105:9 + --> $DIR/rename.rs:103:9 | LL | #![warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` diff --git a/tests/ui/same_functions_in_if_condition.rs b/tests/ui/same_functions_in_if_condition.rs index 08916398cbb2..a207e4221355 100644 --- a/tests/ui/same_functions_in_if_condition.rs +++ b/tests/ui/same_functions_in_if_condition.rs @@ -37,33 +37,33 @@ fn ifs_same_cond_fn() { if function() { } else if function() { - //~ ERROR ifs same condition + //~^ ERROR: `if` has the same function call as a previous `if` } if fn_arg(a) { } else if fn_arg(a) { - //~ ERROR ifs same condition + //~^ ERROR: `if` has the same function call as a previous `if` } if obj.method() { } else if obj.method() { - //~ ERROR ifs same condition + //~^ ERROR: `if` has the same function call as a previous `if` } if obj.method_arg(a) { } else if obj.method_arg(a) { - //~ ERROR ifs same condition + //~^ ERROR: `if` has the same function call as a previous `if` } let mut v = vec![1]; if v.pop().is_none() { - //~ ERROR ifs same condition } else if v.pop().is_none() { + //~^ ERROR: `if` has the same function call as a previous `if` } if v.len() == 42 { - //~ ERROR ifs same condition } else if v.len() == 42 { + //~^ ERROR: `if` has the same function call as a previous `if` } if v.len() == 1 { diff --git a/tests/ui/same_functions_in_if_condition.stderr b/tests/ui/same_functions_in_if_condition.stderr index 6aacc73b90dc..199e6769ff76 100644 --- a/tests/ui/same_functions_in_if_condition.stderr +++ b/tests/ui/same_functions_in_if_condition.stderr @@ -52,7 +52,7 @@ LL | if obj.method_arg(a) { | ^^^^^^^^^^^^^^^^^ error: this `if` has the same function call as a previous `if` - --> $DIR/same_functions_in_if_condition.rs:61:15 + --> $DIR/same_functions_in_if_condition.rs:60:15 | LL | } else if v.pop().is_none() { | ^^^^^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | if v.pop().is_none() { | ^^^^^^^^^^^^^^^^^ error: this `if` has the same function call as a previous `if` - --> $DIR/same_functions_in_if_condition.rs:66:15 + --> $DIR/same_functions_in_if_condition.rs:65:15 | LL | } else if v.len() == 42 { | ^^^^^^^^^^^^^ diff --git a/tests/ui/search_is_some.rs b/tests/ui/search_is_some.rs index 670599b0dcf5..3cdbfaa16261 100644 --- a/tests/ui/search_is_some.rs +++ b/tests/ui/search_is_some.rs @@ -1,5 +1,6 @@ //@aux-build:option_helpers.rs #![warn(clippy::search_is_some)] +#![allow(clippy::useless_vec)] #![allow(dead_code)] extern crate option_helpers; use option_helpers::IteratorFalsePositives; diff --git a/tests/ui/search_is_some.stderr b/tests/ui/search_is_some.stderr index 6bea8c674779..7eff614d17c6 100644 --- a/tests/ui/search_is_some.stderr +++ b/tests/ui/search_is_some.stderr @@ -1,5 +1,5 @@ error: called `is_some()` after searching an `Iterator` with `find` - --> $DIR/search_is_some.rs:14:13 + --> $DIR/search_is_some.rs:15:13 | LL | let _ = v.iter().find(|&x| { | _____________^ @@ -12,7 +12,7 @@ LL | | ).is_some(); = note: `-D clippy::search-is-some` implied by `-D warnings` error: called `is_some()` after searching an `Iterator` with `position` - --> $DIR/search_is_some.rs:20:13 + --> $DIR/search_is_some.rs:21:13 | LL | let _ = v.iter().position(|&x| { | _____________^ @@ -24,7 +24,7 @@ LL | | ).is_some(); = help: this is more succinctly expressed by calling `any()` error: called `is_some()` after searching an `Iterator` with `rposition` - --> $DIR/search_is_some.rs:26:13 + --> $DIR/search_is_some.rs:27:13 | LL | let _ = v.iter().rposition(|&x| { | _____________^ @@ -36,13 +36,13 @@ LL | | ).is_some(); = help: this is more succinctly expressed by calling `any()` error: called `is_some()` after searching an `Iterator` with `find` - --> $DIR/search_is_some.rs:41:20 + --> $DIR/search_is_some.rs:42:20 | LL | let _ = (0..1).find(some_closure).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(some_closure)` error: called `is_none()` after searching an `Iterator` with `find` - --> $DIR/search_is_some.rs:51:13 + --> $DIR/search_is_some.rs:52:13 | LL | let _ = v.iter().find(|&x| { | _____________^ @@ -54,7 +54,7 @@ LL | | ).is_none(); = help: this is more succinctly expressed by calling `any()` with negation error: called `is_none()` after searching an `Iterator` with `position` - --> $DIR/search_is_some.rs:57:13 + --> $DIR/search_is_some.rs:58:13 | LL | let _ = v.iter().position(|&x| { | _____________^ @@ -66,7 +66,7 @@ LL | | ).is_none(); = help: this is more succinctly expressed by calling `any()` with negation error: called `is_none()` after searching an `Iterator` with `rposition` - --> $DIR/search_is_some.rs:63:13 + --> $DIR/search_is_some.rs:64:13 | LL | let _ = v.iter().rposition(|&x| { | _____________^ @@ -78,7 +78,7 @@ LL | | ).is_none(); = help: this is more succinctly expressed by calling `any()` with negation error: called `is_none()` after searching an `Iterator` with `find` - --> $DIR/search_is_some.rs:78:13 + --> $DIR/search_is_some.rs:79:13 | LL | let _ = (0..1).find(some_closure).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!(0..1).any(some_closure)` diff --git a/tests/ui/search_is_some_fixable_none.fixed b/tests/ui/search_is_some_fixable_none.fixed index 9386618c123e..08fb87cb306e 100644 --- a/tests/ui/search_is_some_fixable_none.fixed +++ b/tests/ui/search_is_some_fixable_none.fixed @@ -1,5 +1,5 @@ //@run-rustfix -#![allow(dead_code, clippy::explicit_auto_deref)] +#![allow(dead_code, clippy::explicit_auto_deref, clippy::useless_vec)] #![warn(clippy::search_is_some)] fn main() { diff --git a/tests/ui/search_is_some_fixable_none.rs b/tests/ui/search_is_some_fixable_none.rs index 6b2537a96c2a..ec3386933a61 100644 --- a/tests/ui/search_is_some_fixable_none.rs +++ b/tests/ui/search_is_some_fixable_none.rs @@ -1,5 +1,5 @@ //@run-rustfix -#![allow(dead_code, clippy::explicit_auto_deref)] +#![allow(dead_code, clippy::explicit_auto_deref, clippy::useless_vec)] #![warn(clippy::search_is_some)] fn main() { diff --git a/tests/ui/search_is_some_fixable_some.fixed b/tests/ui/search_is_some_fixable_some.fixed index e9116fc59f10..aa16f9da037d 100644 --- a/tests/ui/search_is_some_fixable_some.fixed +++ b/tests/ui/search_is_some_fixable_some.fixed @@ -1,5 +1,5 @@ //@run-rustfix -#![allow(dead_code, clippy::explicit_auto_deref)] +#![allow(dead_code, clippy::explicit_auto_deref, clippy::useless_vec)] #![warn(clippy::search_is_some)] fn main() { diff --git a/tests/ui/search_is_some_fixable_some.rs b/tests/ui/search_is_some_fixable_some.rs index b15283994576..aeb6f118bede 100644 --- a/tests/ui/search_is_some_fixable_some.rs +++ b/tests/ui/search_is_some_fixable_some.rs @@ -1,5 +1,5 @@ //@run-rustfix -#![allow(dead_code, clippy::explicit_auto_deref)] +#![allow(dead_code, clippy::explicit_auto_deref, clippy::useless_vec)] #![warn(clippy::search_is_some)] fn main() { diff --git a/tests/ui/self_assignment.rs b/tests/ui/self_assignment.rs index ef6476229102..ec3ae1209425 100644 --- a/tests/ui/self_assignment.rs +++ b/tests/ui/self_assignment.rs @@ -1,4 +1,5 @@ #![warn(clippy::self_assignment)] +#![allow(clippy::useless_vec)] pub struct S<'a> { a: i32, diff --git a/tests/ui/self_assignment.stderr b/tests/ui/self_assignment.stderr index 826e0d0ba888..bed88244eea7 100644 --- a/tests/ui/self_assignment.stderr +++ b/tests/ui/self_assignment.stderr @@ -1,5 +1,5 @@ error: self-assignment of `a` to `a` - --> $DIR/self_assignment.rs:12:5 + --> $DIR/self_assignment.rs:13:5 | LL | a = a; | ^^^^^ @@ -7,61 +7,61 @@ LL | a = a; = note: `-D clippy::self-assignment` implied by `-D warnings` error: self-assignment of `*b` to `*b` - --> $DIR/self_assignment.rs:13:5 + --> $DIR/self_assignment.rs:14:5 | LL | *b = *b; | ^^^^^^^ error: self-assignment of `s` to `s` - --> $DIR/self_assignment.rs:14:5 + --> $DIR/self_assignment.rs:15:5 | LL | s = s; | ^^^^^ error: self-assignment of `s.a` to `s.a` - --> $DIR/self_assignment.rs:15:5 + --> $DIR/self_assignment.rs:16:5 | LL | s.a = s.a; | ^^^^^^^^^ error: self-assignment of `s.b[5 + 5]` to `s.b[10]` - --> $DIR/self_assignment.rs:16:5 + --> $DIR/self_assignment.rs:17:5 | LL | s.b[10] = s.b[5 + 5]; | ^^^^^^^^^^^^^^^^^^^^ error: self-assignment of `s.c[0][1]` to `s.c[0][1]` - --> $DIR/self_assignment.rs:17:5 + --> $DIR/self_assignment.rs:18:5 | LL | s.c[0][1] = s.c[0][1]; | ^^^^^^^^^^^^^^^^^^^^^ error: self-assignment of `s.b[a]` to `s.b[a]` - --> $DIR/self_assignment.rs:18:5 + --> $DIR/self_assignment.rs:19:5 | LL | s.b[a] = s.b[a]; | ^^^^^^^^^^^^^^^ error: self-assignment of `*s.e` to `*s.e` - --> $DIR/self_assignment.rs:19:5 + --> $DIR/self_assignment.rs:20:5 | LL | *s.e = *s.e; | ^^^^^^^^^^^ error: self-assignment of `s.b[10 + a]` to `s.b[a + 10]` - --> $DIR/self_assignment.rs:20:5 + --> $DIR/self_assignment.rs:21:5 | LL | s.b[a + 10] = s.b[10 + a]; | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: self-assignment of `t.1` to `t.1` - --> $DIR/self_assignment.rs:23:5 + --> $DIR/self_assignment.rs:24:5 | LL | t.1 = t.1; | ^^^^^^^^^ error: self-assignment of `(t.0)` to `t.0` - --> $DIR/self_assignment.rs:24:5 + --> $DIR/self_assignment.rs:25:5 | LL | t.0 = (t.0); | ^^^^^^^^^^^ diff --git a/tests/ui/shadow.rs b/tests/ui/shadow.rs index 2c0fc3e3fd83..9be8c5e59d01 100644 --- a/tests/ui/shadow.rs +++ b/tests/ui/shadow.rs @@ -1,7 +1,7 @@ -//@aux-build:proc_macro_derive.rs +//@aux-build:proc_macro_derive.rs:proc-macro #![warn(clippy::shadow_same, clippy::shadow_reuse, clippy::shadow_unrelated)] -#![allow(clippy::let_unit_value)] +#![allow(clippy::let_unit_value, clippy::needless_if)] extern crate proc_macro_derive; diff --git a/tests/ui/significant_drop_in_scrutinee.fixed b/tests/ui/significant_drop_in_scrutinee.fixed new file mode 100644 index 000000000000..acc78d6bb043 --- /dev/null +++ b/tests/ui/significant_drop_in_scrutinee.fixed @@ -0,0 +1,627 @@ +// FIXME: Ideally these suggestions would be fixed via rustfix. Blocked by rust-lang/rust#53934 +// //@run-rustfix +#![warn(clippy::significant_drop_in_scrutinee)] +#![allow(dead_code, unused_assignments)] +#![allow(clippy::match_single_binding, clippy::single_match, clippy::uninlined_format_args)] + +use std::num::ParseIntError; +use std::ops::Deref; +use std::sync::atomic::{AtomicU64, Ordering}; +use std::sync::RwLock; +use std::sync::{Mutex, MutexGuard}; + +struct State {} + +impl State { + fn foo(&self) -> bool { + true + } + + fn bar(&self) {} +} + +fn should_not_trigger_lint_with_mutex_guard_outside_match() { + let mutex = Mutex::new(State {}); + + // Should not trigger lint because the temporary should drop at the `;` on line before the match + let is_foo = mutex.lock().unwrap().foo(); + match is_foo { + true => { + mutex.lock().unwrap().bar(); + }, + false => {}, + }; +} + +fn should_not_trigger_lint_with_mutex_guard_when_taking_ownership_in_match() { + let mutex = Mutex::new(State {}); + + // Should not trigger lint because the scrutinee is explicitly returning the MutexGuard, + // so its lifetime should not be surprising. + match mutex.lock() { + Ok(guard) => { + guard.foo(); + mutex.lock().unwrap().bar(); + }, + _ => {}, + }; +} + +fn should_trigger_lint_with_mutex_guard_in_match_scrutinee() { + let mutex = Mutex::new(State {}); + + // Should trigger lint because the lifetime of the temporary MutexGuard is surprising because it + // is preserved until the end of the match, but there is no clear indication that this is the + // case. + match mutex.lock().unwrap().foo() { + true => { + mutex.lock().unwrap().bar(); + }, + false => {}, + }; +} + +fn should_not_trigger_lint_with_mutex_guard_in_match_scrutinee_when_lint_allowed() { + let mutex = Mutex::new(State {}); + + // Lint should not be triggered because it is "allowed" below. + #[allow(clippy::significant_drop_in_scrutinee)] + match mutex.lock().unwrap().foo() { + true => { + mutex.lock().unwrap().bar(); + }, + false => {}, + }; +} + +fn should_not_trigger_lint_for_insignificant_drop() { + // Should not trigger lint because there are no temporaries whose drops have a significant + // side effect. + match 1u64.to_string().is_empty() { + true => { + println!("It was empty") + }, + false => { + println!("It was not empty") + }, + } +} + +struct StateWithMutex { + m: Mutex, +} + +struct MutexGuardWrapper<'a> { + mg: MutexGuard<'a, u64>, +} + +impl<'a> MutexGuardWrapper<'a> { + fn get_the_value(&self) -> u64 { + *self.mg.deref() + } +} + +struct MutexGuardWrapperWrapper<'a> { + mg: MutexGuardWrapper<'a>, +} + +impl<'a> MutexGuardWrapperWrapper<'a> { + fn get_the_value(&self) -> u64 { + *self.mg.mg.deref() + } +} + +impl StateWithMutex { + fn lock_m(&self) -> MutexGuardWrapper<'_> { + MutexGuardWrapper { + mg: self.m.lock().unwrap(), + } + } + + fn lock_m_m(&self) -> MutexGuardWrapperWrapper<'_> { + MutexGuardWrapperWrapper { + mg: MutexGuardWrapper { + mg: self.m.lock().unwrap(), + }, + } + } + + fn foo(&self) -> bool { + true + } + + fn bar(&self) {} +} + +fn should_trigger_lint_with_wrapped_mutex() { + let s = StateWithMutex { m: Mutex::new(1) }; + + // Should trigger lint because a temporary contains a type with a significant drop and its + // lifetime is not obvious. Additionally, it is not obvious from looking at the scrutinee that + // the temporary contains such a type, making it potentially even more surprising. + match s.lock_m().get_the_value() { + 1 => { + println!("Got 1. Is it still 1?"); + println!("{}", s.lock_m().get_the_value()); + }, + 2 => { + println!("Got 2. Is it still 2?"); + println!("{}", s.lock_m().get_the_value()); + }, + _ => {}, + } + println!("All done!"); +} + +fn should_trigger_lint_with_double_wrapped_mutex() { + let s = StateWithMutex { m: Mutex::new(1) }; + + // Should trigger lint because a temporary contains a type which further contains a type with a + // significant drop and its lifetime is not obvious. Additionally, it is not obvious from + // looking at the scrutinee that the temporary contains such a type, making it potentially even + // more surprising. + match s.lock_m_m().get_the_value() { + 1 => { + println!("Got 1. Is it still 1?"); + println!("{}", s.lock_m().get_the_value()); + }, + 2 => { + println!("Got 2. Is it still 2?"); + println!("{}", s.lock_m().get_the_value()); + }, + _ => {}, + } + println!("All done!"); +} + +struct Counter { + i: AtomicU64, +} + +#[clippy::has_significant_drop] +struct CounterWrapper<'a> { + counter: &'a Counter, +} + +impl<'a> CounterWrapper<'a> { + fn new(counter: &Counter) -> CounterWrapper { + counter.i.fetch_add(1, Ordering::Relaxed); + CounterWrapper { counter } + } +} + +impl<'a> Drop for CounterWrapper<'a> { + fn drop(&mut self) { + self.counter.i.fetch_sub(1, Ordering::Relaxed); + } +} + +impl Counter { + fn temp_increment(&self) -> Vec { + vec![CounterWrapper::new(self), CounterWrapper::new(self)] + } +} + +fn should_trigger_lint_for_vec() { + let counter = Counter { i: AtomicU64::new(0) }; + + // Should trigger lint because the temporary in the scrutinee returns a collection of types + // which have significant drops. The types with significant drops are also non-obvious when + // reading the expression in the scrutinee. + match counter.temp_increment().len() { + 2 => { + let current_count = counter.i.load(Ordering::Relaxed); + println!("Current count {}", current_count); + assert_eq!(current_count, 0); + }, + 1 => {}, + 3 => {}, + _ => {}, + }; +} + +struct StateWithField { + s: String, +} + +// Should trigger lint only on the type in the tuple which is created using a temporary +// with a significant drop. Additionally, this test ensures that the format of the tuple +// is preserved correctly in the suggestion. +fn should_trigger_lint_for_tuple_in_scrutinee() { + let mutex1 = Mutex::new(StateWithField { s: "one".to_owned() }); + + { + match (mutex1.lock().unwrap().s.len(), true) { + (3, _) => { + println!("started"); + mutex1.lock().unwrap().s.len(); + println!("done"); + }, + (_, _) => {}, + }; + + match (true, mutex1.lock().unwrap().s.len(), true) { + (_, 3, _) => { + println!("started"); + mutex1.lock().unwrap().s.len(); + println!("done"); + }, + (_, _, _) => {}, + }; + + let mutex2 = Mutex::new(StateWithField { s: "two".to_owned() }); + match (mutex1.lock().unwrap().s.len(), true, mutex2.lock().unwrap().s.len()) { + (3, _, 3) => { + println!("started"); + mutex1.lock().unwrap().s.len(); + mutex2.lock().unwrap().s.len(); + println!("done"); + }, + (_, _, _) => {}, + }; + + let mutex3 = Mutex::new(StateWithField { s: "three".to_owned() }); + match mutex3.lock().unwrap().s.as_str() { + "three" => { + println!("started"); + mutex1.lock().unwrap().s.len(); + mutex2.lock().unwrap().s.len(); + println!("done"); + }, + _ => {}, + }; + + match (true, mutex3.lock().unwrap().s.as_str()) { + (_, "three") => { + println!("started"); + mutex1.lock().unwrap().s.len(); + mutex2.lock().unwrap().s.len(); + println!("done"); + }, + (_, _) => {}, + }; + } +} + +// Should trigger lint when either side of a binary operation creates a temporary with a +// significant drop. +// To avoid potential unnecessary copies or creating references that would trigger the significant +// drop problem, the lint recommends moving the entire binary operation. +fn should_trigger_lint_for_accessing_field_in_mutex_in_one_side_of_binary_op() { + let mutex = Mutex::new(StateWithField { s: "state".to_owned() }); + + match mutex.lock().unwrap().s.len() > 1 { + true => { + mutex.lock().unwrap().s.len(); + }, + false => {}, + }; + + match 1 < mutex.lock().unwrap().s.len() { + true => { + mutex.lock().unwrap().s.len(); + }, + false => {}, + }; +} + +// Should trigger lint when both sides of a binary operation creates a temporary with a +// significant drop. +// To avoid potential unnecessary copies or creating references that would trigger the significant +// drop problem, the lint recommends moving the entire binary operation. +fn should_trigger_lint_for_accessing_fields_in_mutex_in_both_sides_of_binary_op() { + let mutex1 = Mutex::new(StateWithField { s: "state".to_owned() }); + let mutex2 = Mutex::new(StateWithField { + s: "statewithfield".to_owned(), + }); + + match mutex1.lock().unwrap().s.len() < mutex2.lock().unwrap().s.len() { + true => { + println!( + "{} < {}", + mutex1.lock().unwrap().s.len(), + mutex2.lock().unwrap().s.len() + ); + }, + false => {}, + }; + + match mutex1.lock().unwrap().s.len() >= mutex2.lock().unwrap().s.len() { + true => { + println!( + "{} >= {}", + mutex1.lock().unwrap().s.len(), + mutex2.lock().unwrap().s.len() + ); + }, + false => {}, + }; +} + +fn should_not_trigger_lint_for_closure_in_scrutinee() { + let mutex1 = Mutex::new(StateWithField { s: "one".to_owned() }); + + let get_mutex_guard = || mutex1.lock().unwrap().s.len(); + + // Should not trigger lint because the temporary with a significant drop will be dropped + // at the end of the closure, so the MutexGuard will be unlocked and not have a potentially + // surprising lifetime. + match get_mutex_guard() > 1 { + true => { + mutex1.lock().unwrap().s.len(); + }, + false => {}, + }; +} + +fn should_trigger_lint_for_return_from_closure_in_scrutinee() { + let mutex1 = Mutex::new(StateWithField { s: "one".to_owned() }); + + let get_mutex_guard = || mutex1.lock().unwrap(); + + // Should trigger lint because the temporary with a significant drop is returned from the + // closure but not used directly in any match arms, so it has a potentially surprising lifetime. + match get_mutex_guard().s.len() > 1 { + true => { + mutex1.lock().unwrap().s.len(); + }, + false => {}, + }; +} + +fn should_trigger_lint_for_return_from_match_in_scrutinee() { + let mutex1 = Mutex::new(StateWithField { s: "one".to_owned() }); + let mutex2 = Mutex::new(StateWithField { s: "two".to_owned() }); + + let i = 100; + + // Should trigger lint because the nested match within the scrutinee returns a temporary with a + // significant drop is but not used directly in any match arms, so it has a potentially + // surprising lifetime. + match match i { + 100 => mutex1.lock().unwrap(), + _ => mutex2.lock().unwrap(), + } + .s + .len() + > 1 + { + true => { + mutex1.lock().unwrap().s.len(); + }, + false => { + println!("nothing to do here"); + }, + }; +} + +fn should_trigger_lint_for_return_from_if_in_scrutinee() { + let mutex1 = Mutex::new(StateWithField { s: "one".to_owned() }); + let mutex2 = Mutex::new(StateWithField { s: "two".to_owned() }); + + let i = 100; + + // Should trigger lint because the nested if-expression within the scrutinee returns a temporary + // with a significant drop is but not used directly in any match arms, so it has a potentially + // surprising lifetime. + match if i > 1 { + mutex1.lock().unwrap() + } else { + mutex2.lock().unwrap() + } + .s + .len() + > 1 + { + true => { + mutex1.lock().unwrap().s.len(); + }, + false => {}, + }; +} + +fn should_not_trigger_lint_for_if_in_scrutinee() { + let mutex = Mutex::new(StateWithField { s: "state".to_owned() }); + + let i = 100; + + // Should not trigger the lint because the temporary with a significant drop *is* dropped within + // the body of the if-expression nested within the match scrutinee, and therefore does not have + // a potentially surprising lifetime. + match if i > 1 { + mutex.lock().unwrap().s.len() > 1 + } else { + false + } { + true => { + mutex.lock().unwrap().s.len(); + }, + false => {}, + }; +} + +struct StateWithBoxedMutexGuard { + u: Mutex, +} + +impl StateWithBoxedMutexGuard { + fn new() -> StateWithBoxedMutexGuard { + StateWithBoxedMutexGuard { u: Mutex::new(42) } + } + fn lock(&self) -> Box> { + Box::new(self.u.lock().unwrap()) + } +} + +fn should_trigger_lint_for_boxed_mutex_guard() { + let s = StateWithBoxedMutexGuard::new(); + + // Should trigger lint because a temporary Box holding a type with a significant drop in a match + // scrutinee may have a potentially surprising lifetime. + match s.lock().deref().deref() { + 0 | 1 => println!("Value was less than 2"), + _ => println!("Value is {}", s.lock().deref()), + }; +} + +struct StateStringWithBoxedMutexGuard { + s: Mutex, +} + +impl StateStringWithBoxedMutexGuard { + fn new() -> StateStringWithBoxedMutexGuard { + StateStringWithBoxedMutexGuard { + s: Mutex::new("A String".to_owned()), + } + } + fn lock(&self) -> Box> { + Box::new(self.s.lock().unwrap()) + } +} + +fn should_trigger_lint_for_boxed_mutex_guard_holding_string() { + let s = StateStringWithBoxedMutexGuard::new(); + + let matcher = String::from("A String"); + + // Should trigger lint because a temporary Box holding a type with a significant drop in a match + // scrutinee may have a potentially surprising lifetime. + match s.lock().deref().deref() { + matcher => println!("Value is {}", s.lock().deref()), + _ => println!("Value was not a match"), + }; +} + +struct StateWithIntField { + i: u64, +} + +// Should trigger lint when either side of an assign expression contains a temporary with a +// significant drop, because the temporary's lifetime will be extended to the end of the match. +// To avoid potential unnecessary copies or creating references that would trigger the significant +// drop problem, the lint recommends moving the entire binary operation. +fn should_trigger_lint_in_assign_expr() { + let mutex = Mutex::new(StateWithIntField { i: 10 }); + + let mut i = 100; + + match mutex.lock().unwrap().i = i { + _ => { + println!("{}", mutex.lock().unwrap().i); + }, + }; + + match i = mutex.lock().unwrap().i { + _ => { + println!("{}", mutex.lock().unwrap().i); + }, + }; + + match mutex.lock().unwrap().i += 1 { + _ => { + println!("{}", mutex.lock().unwrap().i); + }, + }; + + match i += mutex.lock().unwrap().i { + _ => { + println!("{}", mutex.lock().unwrap().i); + }, + }; +} + +#[derive(Debug)] +enum RecursiveEnum { + Foo(Option>), +} + +#[derive(Debug)] +enum GenericRecursiveEnum { + Foo(T, Option>>), +} + +fn should_not_cause_stack_overflow() { + // Test that when a type recursively contains itself, a stack overflow does not occur when + // checking sub-types for significant drops. + let f = RecursiveEnum::Foo(Some(Box::new(RecursiveEnum::Foo(None)))); + match f { + RecursiveEnum::Foo(Some(f)) => { + println!("{:?}", f) + }, + RecursiveEnum::Foo(f) => { + println!("{:?}", f) + }, + } + + let f = GenericRecursiveEnum::Foo(1u64, Some(Box::new(GenericRecursiveEnum::Foo(2u64, None)))); + match f { + GenericRecursiveEnum::Foo(i, Some(f)) => { + println!("{} {:?}", i, f) + }, + GenericRecursiveEnum::Foo(i, f) => { + println!("{} {:?}", i, f) + }, + } +} + +fn should_not_produce_lint_for_try_desugar() -> Result { + // TryDesugar (i.e. using `?` for a Result type) will turn into a match but is out of scope + // for this lint + let rwlock = RwLock::new("1".to_string()); + let result = rwlock.read().unwrap().parse::()?; + println!("{}", result); + rwlock.write().unwrap().push('2'); + Ok(result) +} + +struct ResultReturner { + s: String, +} + +impl ResultReturner { + fn to_number(&self) -> Result { + self.s.parse::() + } +} + +fn should_trigger_lint_for_non_ref_move_and_clone_suggestion() { + let rwlock = RwLock::::new(ResultReturner { s: "1".to_string() }); + match rwlock.read().unwrap().to_number() { + Ok(n) => println!("Converted to number: {}", n), + Err(e) => println!("Could not convert {} to number", e), + }; +} + +fn should_trigger_lint_for_read_write_lock_for_loop() { + // For-in loops desugar to match expressions and are prone to the type of deadlock this lint is + // designed to look for. + let rwlock = RwLock::>::new(vec!["1".to_string()]); + for s in rwlock.read().unwrap().iter() { + println!("{}", s); + } +} + +fn do_bar(mutex: &Mutex) { + mutex.lock().unwrap().bar(); +} + +fn should_trigger_lint_without_significant_drop_in_arm() { + let mutex = Mutex::new(State {}); + + // Should trigger lint because the lifetime of the temporary MutexGuard is surprising because it + // is preserved until the end of the match, but there is no clear indication that this is the + // case. + match mutex.lock().unwrap().foo() { + true => do_bar(&mutex), + false => {}, + }; +} + +fn should_not_trigger_on_significant_iterator_drop() { + let lines = std::io::stdin().lines(); + for line in lines { + println!("foo: {}", line.unwrap()); + } +} + +fn main() {} diff --git a/tests/ui/significant_drop_tightening.fixed b/tests/ui/significant_drop_tightening.fixed index ee7f2b0631ad..7b848ead7846 100644 --- a/tests/ui/significant_drop_tightening.fixed +++ b/tests/ui/significant_drop_tightening.fixed @@ -16,6 +16,18 @@ pub fn complex_return_triggers_the_lint() -> i32 { foo() } +pub fn issue_10413() { + let mutex = Mutex::new(Some(1)); + let opt = Some(1); + if opt.is_some() { + let lock = mutex.lock().unwrap(); + let _ = *lock; + if opt.is_some() { + let _ = *lock; + } + } +} + pub fn path_return_can_be_ignored() -> i32 { let mutex = Mutex::new(1); let lock = mutex.lock().unwrap(); diff --git a/tests/ui/significant_drop_tightening.rs b/tests/ui/significant_drop_tightening.rs index 9c139deb95f2..36f77cf1bdb6 100644 --- a/tests/ui/significant_drop_tightening.rs +++ b/tests/ui/significant_drop_tightening.rs @@ -15,6 +15,18 @@ pub fn complex_return_triggers_the_lint() -> i32 { foo() } +pub fn issue_10413() { + let mutex = Mutex::new(Some(1)); + let opt = Some(1); + if opt.is_some() { + let lock = mutex.lock().unwrap(); + let _ = *lock; + if opt.is_some() { + let _ = *lock; + } + } +} + pub fn path_return_can_be_ignored() -> i32 { let mutex = Mutex::new(1); let lock = mutex.lock().unwrap(); diff --git a/tests/ui/significant_drop_tightening.stderr b/tests/ui/significant_drop_tightening.stderr index ab8ce356ec7b..3bdac0b0a6b7 100644 --- a/tests/ui/significant_drop_tightening.stderr +++ b/tests/ui/significant_drop_tightening.stderr @@ -23,7 +23,7 @@ LL + drop(lock); | error: temporary with significant `Drop` can be early dropped - --> $DIR/significant_drop_tightening.rs:44:13 + --> $DIR/significant_drop_tightening.rs:56:13 | LL | / { LL | | let mutex = Mutex::new(1i32); @@ -43,7 +43,7 @@ LL + drop(lock); | error: temporary with significant `Drop` can be early dropped - --> $DIR/significant_drop_tightening.rs:65:13 + --> $DIR/significant_drop_tightening.rs:77:13 | LL | / { LL | | let mutex = Mutex::new(1i32); @@ -67,7 +67,7 @@ LL + | error: temporary with significant `Drop` can be early dropped - --> $DIR/significant_drop_tightening.rs:71:17 + --> $DIR/significant_drop_tightening.rs:83:17 | LL | / { LL | | let mutex = Mutex::new(vec![1i32]); diff --git a/tests/ui/single_call_fn.rs b/tests/ui/single_call_fn.rs new file mode 100644 index 000000000000..76e175014b87 --- /dev/null +++ b/tests/ui/single_call_fn.rs @@ -0,0 +1,74 @@ +//@aux-build:proc_macros.rs:proc-macro +#![allow(clippy::redundant_closure_call, unused)] +#![warn(clippy::single_call_fn)] +#![no_main] + +#[macro_use] +extern crate proc_macros; + +// Do not lint since it's public +pub fn f() {} + +fn i() {} +fn j() {} + +fn h() { + // Linted + let a = i; + // Do not lint closures + let a = (|| { + // Not linted + a(); + // Imo, it's reasonable to lint this as the function is still only being used once. Just in + // a closure. + j(); + }); + a(); +} + +fn g() { + f(); +} + +fn c() { + println!("really"); + println!("long"); + println!("function..."); +} + +fn d() { + c(); +} + +fn a() {} + +fn b() { + a(); + + external! { + fn lol() { + lol_inner(); + } + fn lol_inner() {} + } + with_span! { + span + fn lol2() { + lol2_inner(); + } + fn lol2_inner() {} + } +} + +fn e() { + b(); + b(); +} + +#[test] +fn k() {} + +#[test] +fn l() { + k(); +} diff --git a/tests/ui/single_call_fn.stderr b/tests/ui/single_call_fn.stderr new file mode 100644 index 000000000000..9ef8c487844f --- /dev/null +++ b/tests/ui/single_call_fn.stderr @@ -0,0 +1,55 @@ +error: this function is only used once + --> $DIR/single_call_fn.rs:33:1 + | +LL | / fn c() { +LL | | println!("really"); +LL | | println!("long"); +LL | | println!("function..."); +LL | | } + | |_^ + | +help: used here + --> $DIR/single_call_fn.rs:40:5 + | +LL | c(); + | ^ + = note: `-D clippy::single-call-fn` implied by `-D warnings` + +error: this function is only used once + --> $DIR/single_call_fn.rs:12:1 + | +LL | fn i() {} + | ^^^^^^^^^ + | +help: used here + --> $DIR/single_call_fn.rs:17:13 + | +LL | let a = i; + | ^ + +error: this function is only used once + --> $DIR/single_call_fn.rs:43:1 + | +LL | fn a() {} + | ^^^^^^^^^ + | +help: used here + --> $DIR/single_call_fn.rs:46:5 + | +LL | a(); + | ^ + +error: this function is only used once + --> $DIR/single_call_fn.rs:13:1 + | +LL | fn j() {} + | ^^^^^^^^^ + | +help: used here + --> $DIR/single_call_fn.rs:24:9 + | +LL | j(); + | ^ + +error: aborting due to 4 previous errors + diff --git a/tests/ui/single_char_add_str.fixed b/tests/ui/single_char_add_str.fixed index cbcf1ab21c9b..cb301c8bc152 100644 --- a/tests/ui/single_char_add_str.fixed +++ b/tests/ui/single_char_add_str.fixed @@ -1,5 +1,6 @@ //@run-rustfix #![warn(clippy::single_char_add_str)] +#![allow(clippy::needless_raw_strings, clippy::needless_raw_string_hashes)] macro_rules! get_string { () => { diff --git a/tests/ui/single_char_add_str.rs b/tests/ui/single_char_add_str.rs index a1f005cc833b..99baf35ac297 100644 --- a/tests/ui/single_char_add_str.rs +++ b/tests/ui/single_char_add_str.rs @@ -1,5 +1,6 @@ //@run-rustfix #![warn(clippy::single_char_add_str)] +#![allow(clippy::needless_raw_strings, clippy::needless_raw_string_hashes)] macro_rules! get_string { () => { diff --git a/tests/ui/single_char_add_str.stderr b/tests/ui/single_char_add_str.stderr index 55d91583ad04..3f93c18470ea 100644 --- a/tests/ui/single_char_add_str.stderr +++ b/tests/ui/single_char_add_str.stderr @@ -1,5 +1,5 @@ error: calling `push_str()` using a single-character string literal - --> $DIR/single_char_add_str.rs:14:5 + --> $DIR/single_char_add_str.rs:15:5 | LL | string.push_str("R"); | ^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('R')` @@ -7,85 +7,85 @@ LL | string.push_str("R"); = note: `-D clippy::single-char-add-str` implied by `-D warnings` error: calling `push_str()` using a single-character string literal - --> $DIR/single_char_add_str.rs:15:5 + --> $DIR/single_char_add_str.rs:16:5 | LL | string.push_str("'"); | ^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/'')` error: calling `push_str()` using a single-character string literal - --> $DIR/single_char_add_str.rs:20:5 + --> $DIR/single_char_add_str.rs:21:5 | LL | string.push_str("/x52"); | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/x52')` error: calling `push_str()` using a single-character string literal - --> $DIR/single_char_add_str.rs:21:5 + --> $DIR/single_char_add_str.rs:22:5 | LL | string.push_str("/u{0052}"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/u{0052}')` error: calling `push_str()` using a single-character string literal - --> $DIR/single_char_add_str.rs:22:5 + --> $DIR/single_char_add_str.rs:23:5 | LL | string.push_str(r##"a"##); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('a')` error: calling `push_str()` using a single-character string literal - --> $DIR/single_char_add_str.rs:24:5 + --> $DIR/single_char_add_str.rs:25:5 | LL | get_string!().push_str("ö"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `get_string!().push('ö')` error: calling `insert_str()` using a single-character string literal - --> $DIR/single_char_add_str.rs:29:5 + --> $DIR/single_char_add_str.rs:30:5 | LL | string.insert_str(0, "R"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, 'R')` error: calling `insert_str()` using a single-character string literal - --> $DIR/single_char_add_str.rs:30:5 + --> $DIR/single_char_add_str.rs:31:5 | LL | string.insert_str(1, "'"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(1, '/'')` error: calling `insert_str()` using a single-character string literal - --> $DIR/single_char_add_str.rs:35:5 + --> $DIR/single_char_add_str.rs:36:5 | LL | string.insert_str(0, "/x52"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, '/x52')` error: calling `insert_str()` using a single-character string literal - --> $DIR/single_char_add_str.rs:36:5 + --> $DIR/single_char_add_str.rs:37:5 | LL | string.insert_str(0, "/u{0052}"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, '/u{0052}')` error: calling `insert_str()` using a single-character string literal - --> $DIR/single_char_add_str.rs:38:5 + --> $DIR/single_char_add_str.rs:39:5 | LL | string.insert_str(x, r##"a"##); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(x, 'a')` error: calling `insert_str()` using a single-character string literal - --> $DIR/single_char_add_str.rs:40:5 + --> $DIR/single_char_add_str.rs:41:5 | LL | string.insert_str(Y, r##"a"##); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, 'a')` error: calling `insert_str()` using a single-character string literal - --> $DIR/single_char_add_str.rs:41:5 + --> $DIR/single_char_add_str.rs:42:5 | LL | string.insert_str(Y, r##"""##); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, '"')` error: calling `insert_str()` using a single-character string literal - --> $DIR/single_char_add_str.rs:42:5 + --> $DIR/single_char_add_str.rs:43:5 | LL | string.insert_str(Y, r##"'"##); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, '/'')` error: calling `insert_str()` using a single-character string literal - --> $DIR/single_char_add_str.rs:44:5 + --> $DIR/single_char_add_str.rs:45:5 | LL | get_string!().insert_str(1, "?"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `get_string!().insert(1, '?')` diff --git a/tests/ui/single_char_pattern.fixed b/tests/ui/single_char_pattern.fixed index dba89872070e..7ae62231acc0 100644 --- a/tests/ui/single_char_pattern.fixed +++ b/tests/ui/single_char_pattern.fixed @@ -1,6 +1,6 @@ //@run-rustfix -#![allow(unused_must_use)] +#![allow(clippy::needless_raw_strings, clippy::needless_raw_string_hashes, unused_must_use)] use std::collections::HashSet; diff --git a/tests/ui/single_char_pattern.rs b/tests/ui/single_char_pattern.rs index 6a145a14bfdc..0604624e767b 100644 --- a/tests/ui/single_char_pattern.rs +++ b/tests/ui/single_char_pattern.rs @@ -1,6 +1,6 @@ //@run-rustfix -#![allow(unused_must_use)] +#![allow(clippy::needless_raw_strings, clippy::needless_raw_string_hashes, unused_must_use)] use std::collections::HashSet; diff --git a/tests/ui/single_char_pattern.stderr b/tests/ui/single_char_pattern.stderr index 5564aac674d9..5ae2450c2268 100644 --- a/tests/ui/single_char_pattern.stderr +++ b/tests/ui/single_char_pattern.stderr @@ -226,13 +226,13 @@ error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:65:13 | LL | x.split(r#"/"#); - | ^^^^^^ help: try using a `char` instead: `'/'` + | ^^^^^^ help: try using a `char` instead: `'//'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:66:13 | LL | x.split(r"/"); - | ^^^^ help: try using a `char` instead: `'/'` + | ^^^^ help: try using a `char` instead: `'//'` error: aborting due to 39 previous errors diff --git a/tests/ui/single_element_loop.fixed b/tests/ui/single_element_loop.fixed index 1697a0cf29b8..598f259415da 100644 --- a/tests/ui/single_element_loop.fixed +++ b/tests/ui/single_element_loop.fixed @@ -1,6 +1,8 @@ //@run-rustfix // Tests from for_loop.rs that don't have suggestions +#![allow(clippy::single_range_in_vec_init)] + #[warn(clippy::single_element_loop)] fn main() { let item1 = 2; diff --git a/tests/ui/single_element_loop.rs b/tests/ui/single_element_loop.rs index 860424f42ddf..3fc461735a49 100644 --- a/tests/ui/single_element_loop.rs +++ b/tests/ui/single_element_loop.rs @@ -1,6 +1,8 @@ //@run-rustfix // Tests from for_loop.rs that don't have suggestions +#![allow(clippy::single_range_in_vec_init)] + #[warn(clippy::single_element_loop)] fn main() { let item1 = 2; diff --git a/tests/ui/single_element_loop.stderr b/tests/ui/single_element_loop.stderr index 14437a59745e..c40c6198945a 100644 --- a/tests/ui/single_element_loop.stderr +++ b/tests/ui/single_element_loop.stderr @@ -1,5 +1,5 @@ error: for loop over a single element - --> $DIR/single_element_loop.rs:7:5 + --> $DIR/single_element_loop.rs:9:5 | LL | / for item in &[item1] { LL | | dbg!(item); @@ -16,7 +16,7 @@ LL + } | error: for loop over a single element - --> $DIR/single_element_loop.rs:11:5 + --> $DIR/single_element_loop.rs:13:5 | LL | / for item in [item1].iter() { LL | | dbg!(item); @@ -32,7 +32,7 @@ LL + } | error: for loop over a single element - --> $DIR/single_element_loop.rs:15:5 + --> $DIR/single_element_loop.rs:17:5 | LL | / for item in &[0..5] { LL | | dbg!(item); @@ -48,7 +48,7 @@ LL + } | error: for loop over a single element - --> $DIR/single_element_loop.rs:19:5 + --> $DIR/single_element_loop.rs:21:5 | LL | / for item in [0..5].iter_mut() { LL | | dbg!(item); @@ -64,7 +64,7 @@ LL + } | error: for loop over a single element - --> $DIR/single_element_loop.rs:23:5 + --> $DIR/single_element_loop.rs:25:5 | LL | / for item in [0..5] { LL | | dbg!(item); @@ -80,7 +80,7 @@ LL + } | error: for loop over a single element - --> $DIR/single_element_loop.rs:27:5 + --> $DIR/single_element_loop.rs:29:5 | LL | / for item in [0..5].into_iter() { LL | | dbg!(item); @@ -96,7 +96,7 @@ LL + } | error: for loop over a single element - --> $DIR/single_element_loop.rs:46:5 + --> $DIR/single_element_loop.rs:48:5 | LL | / for _ in [42] { LL | | let _f = |n: u32| { diff --git a/tests/ui/single_match.fixed b/tests/ui/single_match.fixed index 77a2cf3b991f..e7b1fd6a85f2 100644 --- a/tests/ui/single_match.fixed +++ b/tests/ui/single_match.fixed @@ -1,6 +1,11 @@ //@run-rustfix #![warn(clippy::single_match)] -#![allow(unused, clippy::uninlined_format_args, clippy::redundant_pattern_matching)] +#![allow( + unused, + clippy::uninlined_format_args, + clippy::needless_if, + clippy::redundant_pattern_matching +)] fn dummy() {} fn single_match() { @@ -207,3 +212,43 @@ fn issue_10808(bar: Option) { } } } + +mod issue8634 { + struct SomeError(i32, i32); + + fn foo(x: Result) { + match x { + Ok(y) => { + println!("Yay! {y}"); + }, + Err(()) => { + // Ignore this error because blah blah blah. + }, + } + } + + fn bar(x: Result) { + match x { + Ok(y) => { + println!("Yay! {y}"); + }, + Err(_) => { + // TODO: Process the error properly. + }, + } + } + + fn block_comment(x: Result) { + match x { + Ok(y) => { + println!("Yay! {y}"); + }, + Err(_) => { + /* + let's make sure that this also + does not lint block comments. + */ + }, + } + } +} diff --git a/tests/ui/single_match.rs b/tests/ui/single_match.rs index 8d0ab5b99ad5..1515a7053e5d 100644 --- a/tests/ui/single_match.rs +++ b/tests/ui/single_match.rs @@ -1,6 +1,11 @@ //@run-rustfix #![warn(clippy::single_match)] -#![allow(unused, clippy::uninlined_format_args, clippy::redundant_pattern_matching)] +#![allow( + unused, + clippy::uninlined_format_args, + clippy::needless_if, + clippy::redundant_pattern_matching +)] fn dummy() {} fn single_match() { @@ -265,3 +270,43 @@ fn issue_10808(bar: Option) { _ => {}, } } + +mod issue8634 { + struct SomeError(i32, i32); + + fn foo(x: Result) { + match x { + Ok(y) => { + println!("Yay! {y}"); + }, + Err(()) => { + // Ignore this error because blah blah blah. + }, + } + } + + fn bar(x: Result) { + match x { + Ok(y) => { + println!("Yay! {y}"); + }, + Err(_) => { + // TODO: Process the error properly. + }, + } + } + + fn block_comment(x: Result) { + match x { + Ok(y) => { + println!("Yay! {y}"); + }, + Err(_) => { + /* + let's make sure that this also + does not lint block comments. + */ + }, + } + } +} diff --git a/tests/ui/single_match.stderr b/tests/ui/single_match.stderr index dad66e2ab2ec..ef9015132404 100644 --- a/tests/ui/single_match.stderr +++ b/tests/ui/single_match.stderr @@ -1,5 +1,5 @@ error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:9:5 + --> $DIR/single_match.rs:14:5 | LL | / match x { LL | | Some(y) => { @@ -18,7 +18,7 @@ LL ~ }; | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:17:5 + --> $DIR/single_match.rs:22:5 | LL | / match x { LL | | // Note the missing block braces. @@ -30,7 +30,7 @@ LL | | } | |_____^ help: try this: `if let Some(y) = x { println!("{:?}", y) }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:26:5 + --> $DIR/single_match.rs:31:5 | LL | / match z { LL | | (2..=3, 7..=9) => dummy(), @@ -39,7 +39,7 @@ LL | | }; | |_____^ help: try this: `if let (2..=3, 7..=9) = z { dummy() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:55:5 + --> $DIR/single_match.rs:60:5 | LL | / match x { LL | | Some(y) => dummy(), @@ -48,7 +48,7 @@ LL | | }; | |_____^ help: try this: `if let Some(y) = x { dummy() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:60:5 + --> $DIR/single_match.rs:65:5 | LL | / match y { LL | | Ok(y) => dummy(), @@ -57,7 +57,7 @@ LL | | }; | |_____^ help: try this: `if let Ok(y) = y { dummy() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:67:5 + --> $DIR/single_match.rs:72:5 | LL | / match c { LL | | Cow::Borrowed(..) => dummy(), @@ -66,7 +66,7 @@ LL | | }; | |_____^ help: try this: `if let Cow::Borrowed(..) = c { dummy() }` error: you seem to be trying to use `match` for an equality check. Consider using `if` - --> $DIR/single_match.rs:88:5 + --> $DIR/single_match.rs:93:5 | LL | / match x { LL | | "test" => println!(), @@ -75,7 +75,7 @@ LL | | } | |_____^ help: try this: `if x == "test" { println!() }` error: you seem to be trying to use `match` for an equality check. Consider using `if` - --> $DIR/single_match.rs:101:5 + --> $DIR/single_match.rs:106:5 | LL | / match x { LL | | Foo::A => println!(), @@ -84,7 +84,7 @@ LL | | } | |_____^ help: try this: `if x == Foo::A { println!() }` error: you seem to be trying to use `match` for an equality check. Consider using `if` - --> $DIR/single_match.rs:107:5 + --> $DIR/single_match.rs:112:5 | LL | / match x { LL | | FOO_C => println!(), @@ -93,7 +93,7 @@ LL | | } | |_____^ help: try this: `if x == FOO_C { println!() }` error: you seem to be trying to use `match` for an equality check. Consider using `if` - --> $DIR/single_match.rs:112:5 + --> $DIR/single_match.rs:117:5 | LL | / match &&x { LL | | Foo::A => println!(), @@ -102,7 +102,7 @@ LL | | } | |_____^ help: try this: `if x == Foo::A { println!() }` error: you seem to be trying to use `match` for an equality check. Consider using `if` - --> $DIR/single_match.rs:118:5 + --> $DIR/single_match.rs:123:5 | LL | / match &x { LL | | Foo::A => println!(), @@ -111,7 +111,7 @@ LL | | } | |_____^ help: try this: `if x == &Foo::A { println!() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:135:5 + --> $DIR/single_match.rs:140:5 | LL | / match x { LL | | Bar::A => println!(), @@ -120,7 +120,7 @@ LL | | } | |_____^ help: try this: `if let Bar::A = x { println!() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:143:5 + --> $DIR/single_match.rs:148:5 | LL | / match x { LL | | None => println!(), @@ -129,7 +129,7 @@ LL | | }; | |_____^ help: try this: `if let None = x { println!() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:165:5 + --> $DIR/single_match.rs:170:5 | LL | / match x { LL | | (Some(_), _) => {}, @@ -138,7 +138,7 @@ LL | | } | |_____^ help: try this: `if let (Some(_), _) = x {}` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:171:5 + --> $DIR/single_match.rs:176:5 | LL | / match x { LL | | (Some(E::V), _) => todo!(), @@ -147,7 +147,7 @@ LL | | } | |_____^ help: try this: `if let (Some(E::V), _) = x { todo!() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:177:5 + --> $DIR/single_match.rs:182:5 | LL | / match (Some(42), Some(E::V), Some(42)) { LL | | (.., Some(E::V), _) => {}, @@ -156,7 +156,7 @@ LL | | } | |_____^ help: try this: `if let (.., Some(E::V), _) = (Some(42), Some(E::V), Some(42)) {}` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:249:5 + --> $DIR/single_match.rs:254:5 | LL | / match bar { LL | | Some(v) => unsafe { @@ -176,7 +176,7 @@ LL + } } | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> $DIR/single_match.rs:257:5 + --> $DIR/single_match.rs:262:5 | LL | / match bar { LL | | #[rustfmt::skip] diff --git a/tests/ui/single_match_else.fixed b/tests/ui/single_match_else.fixed index f88498655a41..fcc8f14803d3 100644 --- a/tests/ui/single_match_else.fixed +++ b/tests/ui/single_match_else.fixed @@ -1,5 +1,5 @@ //@run-rustfix -//@aux-build: proc_macros.rs +//@aux-build: proc_macros.rs:proc-macro #![warn(clippy::single_match_else)] #![allow(unused, clippy::needless_return, clippy::no_effect, clippy::uninlined_format_args)] extern crate proc_macros; diff --git a/tests/ui/single_match_else.rs b/tests/ui/single_match_else.rs index b34b95539190..77afd58a08dc 100644 --- a/tests/ui/single_match_else.rs +++ b/tests/ui/single_match_else.rs @@ -1,5 +1,5 @@ //@run-rustfix -//@aux-build: proc_macros.rs +//@aux-build: proc_macros.rs:proc-macro #![warn(clippy::single_match_else)] #![allow(unused, clippy::needless_return, clippy::no_effect, clippy::uninlined_format_args)] extern crate proc_macros; diff --git a/tests/ui/single_range_in_vec_init.rs b/tests/ui/single_range_in_vec_init.rs new file mode 100644 index 000000000000..833e1c43bfc0 --- /dev/null +++ b/tests/ui/single_range_in_vec_init.rs @@ -0,0 +1,58 @@ +//@aux-build:proc_macros.rs:proc-macro +#![allow(clippy::no_effect, clippy::useless_vec, unused)] +#![warn(clippy::single_range_in_vec_init)] +#![feature(generic_arg_infer)] + +#[macro_use] +extern crate proc_macros; + +macro_rules! a { + () => { + vec![0..200]; + }; +} + +fn awa(start: T, end: T) { + [start..end]; +} + +fn awa_vec(start: T, end: T) { + vec![start..end]; +} + +fn main() { + // Lint + [0..200]; + vec![0..200]; + [0u8..200]; + [0usize..200]; + [0..200usize]; + vec![0u8..200]; + vec![0usize..200]; + vec![0..200usize]; + // Only suggest collect + [0..200isize]; + vec![0..200isize]; + // Do not lint + [0..200, 0..100]; + vec![0..200, 0..100]; + [0.0..200.0]; + vec![0.0..200.0]; + // `Copy` is not implemented for `Range`, so this doesn't matter + // FIXME: [0..200; 2]; + // FIXME: [vec!0..200; 2]; + + // Unfortunately skips any macros + a!(); + + // Skip external macros and procedural macros + external! { + [0..200]; + vec![0..200]; + } + with_span! { + span + [0..200]; + vec![0..200]; + } +} diff --git a/tests/ui/single_range_in_vec_init.stderr b/tests/ui/single_range_in_vec_init.stderr new file mode 100644 index 000000000000..3e3d521f4a50 --- /dev/null +++ b/tests/ui/single_range_in_vec_init.stderr @@ -0,0 +1,145 @@ +error: an array of `Range` that is only one element + --> $DIR/single_range_in_vec_init.rs:25:5 + | +LL | [0..200]; + | ^^^^^^^^ + | + = note: `-D clippy::single-range-in-vec-init` implied by `-D warnings` +help: if you wanted a `Vec` that contains the entire range, try + | +LL | (0..200).collect::>(); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +help: if you wanted an array of len 200, try + | +LL | [0; 200]; + | ~~~~~~ + +error: a `Vec` of `Range` that is only one element + --> $DIR/single_range_in_vec_init.rs:26:5 + | +LL | vec![0..200]; + | ^^^^^^^^^^^^ + | +help: if you wanted a `Vec` that contains the entire range, try + | +LL | (0..200).collect::>(); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +help: if you wanted a `Vec` of len 200, try + | +LL | vec![0; 200]; + | ~~~~~~ + +error: an array of `Range` that is only one element + --> $DIR/single_range_in_vec_init.rs:27:5 + | +LL | [0u8..200]; + | ^^^^^^^^^^ + | +help: if you wanted a `Vec` that contains the entire range, try + | +LL | (0u8..200).collect::>(); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +help: if you wanted an array of len 200, try + | +LL | [0u8; 200]; + | ~~~~~~~~ + +error: an array of `Range` that is only one element + --> $DIR/single_range_in_vec_init.rs:28:5 + | +LL | [0usize..200]; + | ^^^^^^^^^^^^^ + | +help: if you wanted a `Vec` that contains the entire range, try + | +LL | (0usize..200).collect::>(); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +help: if you wanted an array of len 200, try + | +LL | [0usize; 200]; + | ~~~~~~~~~~~ + +error: an array of `Range` that is only one element + --> $DIR/single_range_in_vec_init.rs:29:5 + | +LL | [0..200usize]; + | ^^^^^^^^^^^^^ + | +help: if you wanted a `Vec` that contains the entire range, try + | +LL | (0..200usize).collect::>(); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +help: if you wanted an array of len 200usize, try + | +LL | [0; 200usize]; + | ~~~~~~~~~~~ + +error: a `Vec` of `Range` that is only one element + --> $DIR/single_range_in_vec_init.rs:30:5 + | +LL | vec![0u8..200]; + | ^^^^^^^^^^^^^^ + | +help: if you wanted a `Vec` that contains the entire range, try + | +LL | (0u8..200).collect::>(); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +help: if you wanted a `Vec` of len 200, try + | +LL | vec![0u8; 200]; + | ~~~~~~~~ + +error: a `Vec` of `Range` that is only one element + --> $DIR/single_range_in_vec_init.rs:31:5 + | +LL | vec![0usize..200]; + | ^^^^^^^^^^^^^^^^^ + | +help: if you wanted a `Vec` that contains the entire range, try + | +LL | (0usize..200).collect::>(); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +help: if you wanted a `Vec` of len 200, try + | +LL | vec![0usize; 200]; + | ~~~~~~~~~~~ + +error: a `Vec` of `Range` that is only one element + --> $DIR/single_range_in_vec_init.rs:32:5 + | +LL | vec![0..200usize]; + | ^^^^^^^^^^^^^^^^^ + | +help: if you wanted a `Vec` that contains the entire range, try + | +LL | (0..200usize).collect::>(); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +help: if you wanted a `Vec` of len 200usize, try + | +LL | vec![0; 200usize]; + | ~~~~~~~~~~~ + +error: an array of `Range` that is only one element + --> $DIR/single_range_in_vec_init.rs:34:5 + | +LL | [0..200isize]; + | ^^^^^^^^^^^^^ + | +help: if you wanted a `Vec` that contains the entire range, try + | +LL | (0..200isize).collect::>(); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: a `Vec` of `Range` that is only one element + --> $DIR/single_range_in_vec_init.rs:35:5 + | +LL | vec![0..200isize]; + | ^^^^^^^^^^^^^^^^^ + | +help: if you wanted a `Vec` that contains the entire range, try + | +LL | (0..200isize).collect::>(); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to 10 previous errors + diff --git a/tests/ui/skip_while_next.rs b/tests/ui/skip_while_next.rs index 62574e2c8cea..8e4cd82cec30 100644 --- a/tests/ui/skip_while_next.rs +++ b/tests/ui/skip_while_next.rs @@ -1,7 +1,7 @@ //@aux-build:option_helpers.rs #![warn(clippy::skip_while_next)] -#![allow(clippy::disallowed_names)] +#![allow(clippy::disallowed_names, clippy::useless_vec)] extern crate option_helpers; use option_helpers::IteratorFalsePositives; diff --git a/tests/ui/stable_sort_primitive.fixed b/tests/ui/stable_sort_primitive.fixed index 1370dd2df4da..50c1fc71a3f9 100644 --- a/tests/ui/stable_sort_primitive.fixed +++ b/tests/ui/stable_sort_primitive.fixed @@ -1,5 +1,6 @@ //@run-rustfix #![warn(clippy::stable_sort_primitive)] +#![allow(clippy::useless_vec)] fn main() { // positive examples diff --git a/tests/ui/stable_sort_primitive.rs b/tests/ui/stable_sort_primitive.rs index cd344dd12389..bd1bb428f2bb 100644 --- a/tests/ui/stable_sort_primitive.rs +++ b/tests/ui/stable_sort_primitive.rs @@ -1,5 +1,6 @@ //@run-rustfix #![warn(clippy::stable_sort_primitive)] +#![allow(clippy::useless_vec)] fn main() { // positive examples diff --git a/tests/ui/stable_sort_primitive.stderr b/tests/ui/stable_sort_primitive.stderr index 1432fdcff77a..aa5d7b7e4914 100644 --- a/tests/ui/stable_sort_primitive.stderr +++ b/tests/ui/stable_sort_primitive.stderr @@ -1,5 +1,5 @@ error: used `sort` on primitive type `i32` - --> $DIR/stable_sort_primitive.rs:7:5 + --> $DIR/stable_sort_primitive.rs:8:5 | LL | vec.sort(); | ^^^^^^^^^^ help: try: `vec.sort_unstable()` @@ -8,7 +8,7 @@ LL | vec.sort(); = note: `-D clippy::stable-sort-primitive` implied by `-D warnings` error: used `sort` on primitive type `bool` - --> $DIR/stable_sort_primitive.rs:9:5 + --> $DIR/stable_sort_primitive.rs:10:5 | LL | vec.sort(); | ^^^^^^^^^^ help: try: `vec.sort_unstable()` @@ -16,7 +16,7 @@ LL | vec.sort(); = note: an unstable sort typically performs faster without any observable difference for this data type error: used `sort` on primitive type `char` - --> $DIR/stable_sort_primitive.rs:11:5 + --> $DIR/stable_sort_primitive.rs:12:5 | LL | vec.sort(); | ^^^^^^^^^^ help: try: `vec.sort_unstable()` @@ -24,7 +24,7 @@ LL | vec.sort(); = note: an unstable sort typically performs faster without any observable difference for this data type error: used `sort` on primitive type `str` - --> $DIR/stable_sort_primitive.rs:13:5 + --> $DIR/stable_sort_primitive.rs:14:5 | LL | vec.sort(); | ^^^^^^^^^^ help: try: `vec.sort_unstable()` @@ -32,7 +32,7 @@ LL | vec.sort(); = note: an unstable sort typically performs faster without any observable difference for this data type error: used `sort` on primitive type `tuple` - --> $DIR/stable_sort_primitive.rs:15:5 + --> $DIR/stable_sort_primitive.rs:16:5 | LL | vec.sort(); | ^^^^^^^^^^ help: try: `vec.sort_unstable()` @@ -40,7 +40,7 @@ LL | vec.sort(); = note: an unstable sort typically performs faster without any observable difference for this data type error: used `sort` on primitive type `array` - --> $DIR/stable_sort_primitive.rs:17:5 + --> $DIR/stable_sort_primitive.rs:18:5 | LL | vec.sort(); | ^^^^^^^^^^ help: try: `vec.sort_unstable()` @@ -48,7 +48,7 @@ LL | vec.sort(); = note: an unstable sort typically performs faster without any observable difference for this data type error: used `sort` on primitive type `i32` - --> $DIR/stable_sort_primitive.rs:19:5 + --> $DIR/stable_sort_primitive.rs:20:5 | LL | arr.sort(); | ^^^^^^^^^^ help: try: `arr.sort_unstable()` diff --git a/tests/ui/starts_ends_with.fixed b/tests/ui/starts_ends_with.fixed index 29d56f852edd..b7237069dc5c 100644 --- a/tests/ui/starts_ends_with.fixed +++ b/tests/ui/starts_ends_with.fixed @@ -1,5 +1,5 @@ //@run-rustfix -#![allow(dead_code, unused_must_use)] +#![allow(clippy::needless_if, dead_code, unused_must_use)] fn main() {} diff --git a/tests/ui/starts_ends_with.rs b/tests/ui/starts_ends_with.rs index 56bbe2574d42..658312e87e47 100644 --- a/tests/ui/starts_ends_with.rs +++ b/tests/ui/starts_ends_with.rs @@ -1,5 +1,5 @@ //@run-rustfix -#![allow(dead_code, unused_must_use)] +#![allow(clippy::needless_if, dead_code, unused_must_use)] fn main() {} diff --git a/tests/ui/string_add.rs b/tests/ui/string_add.rs index de78dfe4d699..6980242ae727 100644 --- a/tests/ui/string_add.rs +++ b/tests/ui/string_add.rs @@ -1,4 +1,4 @@ -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro extern crate proc_macros; use proc_macros::external; diff --git a/tests/ui/string_lit_as_bytes.fixed b/tests/ui/string_lit_as_bytes.fixed index 3fc11b8b0885..0edd81acc7af 100644 --- a/tests/ui/string_lit_as_bytes.fixed +++ b/tests/ui/string_lit_as_bytes.fixed @@ -1,7 +1,7 @@ //@run-rustfix //@aux-build:macro_rules.rs -#![allow(dead_code, unused_variables)] +#![allow(clippy::needless_raw_string_hashes, dead_code, unused_variables)] #![warn(clippy::string_lit_as_bytes)] #[macro_use] diff --git a/tests/ui/string_lit_as_bytes.rs b/tests/ui/string_lit_as_bytes.rs index 7d54acf630e6..2647f02f0e92 100644 --- a/tests/ui/string_lit_as_bytes.rs +++ b/tests/ui/string_lit_as_bytes.rs @@ -1,7 +1,7 @@ //@run-rustfix //@aux-build:macro_rules.rs -#![allow(dead_code, unused_variables)] +#![allow(clippy::needless_raw_string_hashes, dead_code, unused_variables)] #![warn(clippy::string_lit_as_bytes)] #[macro_use] diff --git a/tests/ui/suspicious_else_formatting.rs b/tests/ui/suspicious_else_formatting.rs index 4823d9092089..0473ccdc3f63 100644 --- a/tests/ui/suspicious_else_formatting.rs +++ b/tests/ui/suspicious_else_formatting.rs @@ -1,7 +1,12 @@ -//@aux-build:proc_macro_suspicious_else_formatting.rs +//@aux-build:proc_macro_suspicious_else_formatting.rs:proc-macro #![warn(clippy::suspicious_else_formatting)] -#![allow(clippy::if_same_then_else, clippy::let_unit_value, clippy::needless_else)] +#![allow( + clippy::if_same_then_else, + clippy::let_unit_value, + clippy::needless_if, + clippy::needless_else +)] extern crate proc_macro_suspicious_else_formatting; use proc_macro_suspicious_else_formatting::DeriveBadSpan; @@ -108,6 +113,13 @@ fn main() { else { } + + //#10273 This is fine. Don't warn + if foo() { + } else + /* whelp */ + { + } } // #7650 - Don't lint. Proc-macro using bad spans for `if` expressions. diff --git a/tests/ui/suspicious_else_formatting.stderr b/tests/ui/suspicious_else_formatting.stderr index 2e512b47f123..723fdd7e93e3 100644 --- a/tests/ui/suspicious_else_formatting.stderr +++ b/tests/ui/suspicious_else_formatting.stderr @@ -1,5 +1,5 @@ error: this looks like an `else {..}` but the `else` is missing - --> $DIR/suspicious_else_formatting.rs:17:6 + --> $DIR/suspicious_else_formatting.rs:22:6 | LL | } { | ^ @@ -8,7 +8,7 @@ LL | } { = note: `-D clippy::suspicious-else-formatting` implied by `-D warnings` error: this looks like an `else if` but the `else` is missing - --> $DIR/suspicious_else_formatting.rs:21:6 + --> $DIR/suspicious_else_formatting.rs:26:6 | LL | } if foo() { | ^ @@ -16,7 +16,7 @@ LL | } if foo() { = note: to remove this lint, add the missing `else` or add a new line before the second `if` error: this looks like an `else if` but the `else` is missing - --> $DIR/suspicious_else_formatting.rs:28:10 + --> $DIR/suspicious_else_formatting.rs:33:10 | LL | } if foo() { | ^ @@ -24,7 +24,7 @@ LL | } if foo() { = note: to remove this lint, add the missing `else` or add a new line before the second `if` error: this looks like an `else if` but the `else` is missing - --> $DIR/suspicious_else_formatting.rs:36:10 + --> $DIR/suspicious_else_formatting.rs:41:10 | LL | } if foo() { | ^ @@ -32,7 +32,7 @@ LL | } if foo() { = note: to remove this lint, add the missing `else` or add a new line before the second `if` error: this is an `else {..}` but the formatting might hide it - --> $DIR/suspicious_else_formatting.rs:45:6 + --> $DIR/suspicious_else_formatting.rs:50:6 | LL | } else | ______^ @@ -42,7 +42,7 @@ LL | | { = note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}` error: this is an `else if` but the formatting might hide it - --> $DIR/suspicious_else_formatting.rs:57:6 + --> $DIR/suspicious_else_formatting.rs:62:6 | LL | } else | ______^ @@ -52,7 +52,7 @@ LL | | if foo() { // the span of the above error should continue here = note: to remove this lint, remove the `else` or remove the new line between `else` and `if` error: this is an `else if` but the formatting might hide it - --> $DIR/suspicious_else_formatting.rs:62:6 + --> $DIR/suspicious_else_formatting.rs:67:6 | LL | } | ______^ @@ -63,7 +63,7 @@ LL | | if foo() { // the span of the above error should continue here = note: to remove this lint, remove the `else` or remove the new line between `else` and `if` error: this is an `else {..}` but the formatting might hide it - --> $DIR/suspicious_else_formatting.rs:89:6 + --> $DIR/suspicious_else_formatting.rs:94:6 | LL | } | ______^ @@ -75,7 +75,7 @@ LL | | { = note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}` error: this is an `else {..}` but the formatting might hide it - --> $DIR/suspicious_else_formatting.rs:97:6 + --> $DIR/suspicious_else_formatting.rs:102:6 | LL | } | ______^ diff --git a/tests/ui/suspicious_unary_op_formatting.rs b/tests/ui/suspicious_unary_op_formatting.rs index 9564e373c246..3c5ca1762fe4 100644 --- a/tests/ui/suspicious_unary_op_formatting.rs +++ b/tests/ui/suspicious_unary_op_formatting.rs @@ -1,4 +1,5 @@ #![warn(clippy::suspicious_unary_op_formatting)] +#![allow(clippy::needless_if)] #[rustfmt::skip] fn main() { diff --git a/tests/ui/suspicious_unary_op_formatting.stderr b/tests/ui/suspicious_unary_op_formatting.stderr index 9f1289ccba0c..52b0e99a1d3e 100644 --- a/tests/ui/suspicious_unary_op_formatting.stderr +++ b/tests/ui/suspicious_unary_op_formatting.stderr @@ -1,5 +1,5 @@ error: by not having a space between `>` and `-` it looks like `>-` is a single operator - --> $DIR/suspicious_unary_op_formatting.rs:8:9 + --> $DIR/suspicious_unary_op_formatting.rs:9:9 | LL | if a >- 30 {} | ^^^^ @@ -8,7 +8,7 @@ LL | if a >- 30 {} = note: `-D clippy::suspicious-unary-op-formatting` implied by `-D warnings` error: by not having a space between `>=` and `-` it looks like `>=-` is a single operator - --> $DIR/suspicious_unary_op_formatting.rs:9:9 + --> $DIR/suspicious_unary_op_formatting.rs:10:9 | LL | if a >=- 30 {} | ^^^^^ @@ -16,7 +16,7 @@ LL | if a >=- 30 {} = help: put a space between `>=` and `-` and remove the space after `-` error: by not having a space between `&&` and `!` it looks like `&&!` is a single operator - --> $DIR/suspicious_unary_op_formatting.rs:14:9 + --> $DIR/suspicious_unary_op_formatting.rs:15:9 | LL | if b &&! c {} | ^^^^^ @@ -24,7 +24,7 @@ LL | if b &&! c {} = help: put a space between `&&` and `!` and remove the space after `!` error: by not having a space between `>` and `-` it looks like `>-` is a single operator - --> $DIR/suspicious_unary_op_formatting.rs:16:9 + --> $DIR/suspicious_unary_op_formatting.rs:17:9 | LL | if a >- 30 {} | ^^^^^^ diff --git a/tests/ui/swap.fixed b/tests/ui/swap.fixed index fd3569cf3625..22f904e3fd9e 100644 --- a/tests/ui/swap.fixed +++ b/tests/ui/swap.fixed @@ -10,7 +10,8 @@ dead_code, unused_assignments, unused_variables, - clippy::let_and_return + clippy::let_and_return, + clippy::useless_vec )] struct Foo(u32); diff --git a/tests/ui/swap.rs b/tests/ui/swap.rs index 34fbce0524b2..ada64f89e6d2 100644 --- a/tests/ui/swap.rs +++ b/tests/ui/swap.rs @@ -10,7 +10,8 @@ dead_code, unused_assignments, unused_variables, - clippy::let_and_return + clippy::let_and_return, + clippy::useless_vec )] struct Foo(u32); diff --git a/tests/ui/swap.stderr b/tests/ui/swap.stderr index 0c246268499d..a3b9c2b744c9 100644 --- a/tests/ui/swap.stderr +++ b/tests/ui/swap.stderr @@ -1,5 +1,5 @@ error: this looks like you are swapping `bar.a` and `bar.b` manually - --> $DIR/swap.rs:27:5 + --> $DIR/swap.rs:28:5 | LL | / let temp = bar.a; LL | | bar.a = bar.b; @@ -10,7 +10,7 @@ LL | | bar.b = temp; = note: `-D clippy::manual-swap` implied by `-D warnings` error: this looks like you are swapping elements of `foo` manually - --> $DIR/swap.rs:39:5 + --> $DIR/swap.rs:40:5 | LL | / let temp = foo[0]; LL | | foo[0] = foo[1]; @@ -18,7 +18,7 @@ LL | | foo[1] = temp; | |__________________^ help: try: `foo.swap(0, 1);` error: this looks like you are swapping elements of `foo` manually - --> $DIR/swap.rs:48:5 + --> $DIR/swap.rs:49:5 | LL | / let temp = foo[0]; LL | | foo[0] = foo[1]; @@ -26,7 +26,7 @@ LL | | foo[1] = temp; | |__________________^ help: try: `foo.swap(0, 1);` error: this looks like you are swapping elements of `foo` manually - --> $DIR/swap.rs:67:5 + --> $DIR/swap.rs:68:5 | LL | / let temp = foo[0]; LL | | foo[0] = foo[1]; @@ -34,7 +34,7 @@ LL | | foo[1] = temp; | |__________________^ help: try: `foo.swap(0, 1);` error: this looks like you are swapping `a` and `b` manually - --> $DIR/swap.rs:78:5 + --> $DIR/swap.rs:79:5 | LL | / a ^= b; LL | | b ^= a; @@ -42,7 +42,7 @@ LL | | a ^= b; | |___________^ help: try: `std::mem::swap(&mut a, &mut b);` error: this looks like you are swapping `bar.a` and `bar.b` manually - --> $DIR/swap.rs:86:5 + --> $DIR/swap.rs:87:5 | LL | / bar.a ^= bar.b; LL | | bar.b ^= bar.a; @@ -50,7 +50,7 @@ LL | | bar.a ^= bar.b; | |___________________^ help: try: `std::mem::swap(&mut bar.a, &mut bar.b);` error: this looks like you are swapping elements of `foo` manually - --> $DIR/swap.rs:94:5 + --> $DIR/swap.rs:95:5 | LL | / foo[0] ^= foo[1]; LL | | foo[1] ^= foo[0]; @@ -58,7 +58,7 @@ LL | | foo[0] ^= foo[1]; | |_____________________^ help: try: `foo.swap(0, 1);` error: this looks like you are swapping `foo[0][1]` and `bar[1][0]` manually - --> $DIR/swap.rs:123:5 + --> $DIR/swap.rs:124:5 | LL | / let temp = foo[0][1]; LL | | foo[0][1] = bar[1][0]; @@ -68,7 +68,7 @@ LL | | bar[1][0] = temp; = note: or maybe you should use `std::mem::replace`? error: this looks like you are swapping `a` and `b` manually - --> $DIR/swap.rs:137:7 + --> $DIR/swap.rs:138:7 | LL | ; let t = a; | _______^ @@ -79,7 +79,7 @@ LL | | b = t; = note: or maybe you should use `std::mem::replace`? error: this looks like you are swapping `c.0` and `a` manually - --> $DIR/swap.rs:146:7 + --> $DIR/swap.rs:147:7 | LL | ; let t = c.0; | _______^ @@ -90,7 +90,7 @@ LL | | a = t; = note: or maybe you should use `std::mem::replace`? error: this looks like you are swapping `b` and `a` manually - --> $DIR/swap.rs:172:5 + --> $DIR/swap.rs:173:5 | LL | / let t = b; LL | | b = a; @@ -100,7 +100,7 @@ LL | | a = t; = note: or maybe you should use `std::mem::replace`? error: this looks like you are trying to swap `a` and `b` - --> $DIR/swap.rs:134:5 + --> $DIR/swap.rs:135:5 | LL | / a = b; LL | | b = a; @@ -110,7 +110,7 @@ LL | | b = a; = note: `-D clippy::almost-swapped` implied by `-D warnings` error: this looks like you are trying to swap `c.0` and `a` - --> $DIR/swap.rs:143:5 + --> $DIR/swap.rs:144:5 | LL | / c.0 = a; LL | | a = c.0; @@ -119,7 +119,7 @@ LL | | a = c.0; = note: or maybe you should use `std::mem::replace`? error: this looks like you are trying to swap `a` and `b` - --> $DIR/swap.rs:150:5 + --> $DIR/swap.rs:151:5 | LL | / let a = b; LL | | let b = a; @@ -128,7 +128,7 @@ LL | | let b = a; = note: or maybe you should use `std::mem::replace`? error: this looks like you are trying to swap `d` and `c` - --> $DIR/swap.rs:155:5 + --> $DIR/swap.rs:156:5 | LL | / d = c; LL | | c = d; @@ -137,7 +137,7 @@ LL | | c = d; = note: or maybe you should use `std::mem::replace`? error: this looks like you are trying to swap `a` and `b` - --> $DIR/swap.rs:159:5 + --> $DIR/swap.rs:160:5 | LL | / let a = b; LL | | b = a; @@ -146,7 +146,7 @@ LL | | b = a; = note: or maybe you should use `std::mem::replace`? error: this looks like you are swapping `s.0.x` and `s.0.y` manually - --> $DIR/swap.rs:207:5 + --> $DIR/swap.rs:208:5 | LL | / let t = s.0.x; LL | | s.0.x = s.0.y; diff --git a/tests/ui/tests_outside_test_module.rs b/tests/ui/tests_outside_test_module.rs index 21fdfdf90051..d53c692b78e1 100644 --- a/tests/ui/tests_outside_test_module.rs +++ b/tests/ui/tests_outside_test_module.rs @@ -1,4 +1,3 @@ -//@compile-flags: --test #![allow(unused)] #![warn(clippy::tests_outside_test_module)] diff --git a/tests/ui/tests_outside_test_module.stderr b/tests/ui/tests_outside_test_module.stderr index 125a79d6edfe..71c649c5d270 100644 --- a/tests/ui/tests_outside_test_module.stderr +++ b/tests/ui/tests_outside_test_module.stderr @@ -1,5 +1,5 @@ error: this function marked with #[test] is outside a #[cfg(test)] module - --> $DIR/tests_outside_test_module.rs:11:1 + --> $DIR/tests_outside_test_module.rs:10:1 | LL | fn my_test() {} | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/to_string_in_format_args_incremental.fixed b/tests/ui/to_string_in_format_args_incremental.fixed new file mode 100644 index 000000000000..9f75ad895cda --- /dev/null +++ b/tests/ui/to_string_in_format_args_incremental.fixed @@ -0,0 +1,9 @@ +//@run-rustfix +//@compile-flags: -C incremental=target/debug/test/incr + +// see https://github.com/rust-lang/rust-clippy/issues/10969 + +fn main() { + let s = "Hello, world!"; + println!("{}", s); +} diff --git a/tests/ui/to_string_in_format_args_incremental.rs b/tests/ui/to_string_in_format_args_incremental.rs new file mode 100644 index 000000000000..67115f7c5a7b --- /dev/null +++ b/tests/ui/to_string_in_format_args_incremental.rs @@ -0,0 +1,9 @@ +//@run-rustfix +//@compile-flags: -C incremental=target/debug/test/incr + +// see https://github.com/rust-lang/rust-clippy/issues/10969 + +fn main() { + let s = "Hello, world!"; + println!("{}", s.to_string()); +} diff --git a/tests/ui/to_string_in_format_args_incremental.stderr b/tests/ui/to_string_in_format_args_incremental.stderr new file mode 100644 index 000000000000..a992c5429149 --- /dev/null +++ b/tests/ui/to_string_in_format_args_incremental.stderr @@ -0,0 +1,10 @@ +error: `to_string` applied to a type that implements `Display` in `println!` args + --> $DIR/to_string_in_format_args_incremental.rs:8:21 + | +LL | println!("{}", s.to_string()); + | ^^^^^^^^^^^^ help: remove this + | + = note: `-D clippy::to-string-in-format-args` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/tests/ui/toplevel_ref_arg.fixed b/tests/ui/toplevel_ref_arg.fixed index ea30c1fda6fc..9ad45c7a817b 100644 --- a/tests/ui/toplevel_ref_arg.fixed +++ b/tests/ui/toplevel_ref_arg.fixed @@ -1,7 +1,7 @@ //@run-rustfix -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![warn(clippy::toplevel_ref_arg)] -#![allow(clippy::uninlined_format_args, unused)] +#![allow(clippy::uninlined_format_args, unused, clippy::useless_vec)] extern crate proc_macros; use proc_macros::{external, inline_macros}; diff --git a/tests/ui/toplevel_ref_arg.rs b/tests/ui/toplevel_ref_arg.rs index 7a3d33e5be5a..45ccc024cbde 100644 --- a/tests/ui/toplevel_ref_arg.rs +++ b/tests/ui/toplevel_ref_arg.rs @@ -1,7 +1,7 @@ //@run-rustfix -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![warn(clippy::toplevel_ref_arg)] -#![allow(clippy::uninlined_format_args, unused)] +#![allow(clippy::uninlined_format_args, unused, clippy::useless_vec)] extern crate proc_macros; use proc_macros::{external, inline_macros}; diff --git a/tests/ui/toplevel_ref_arg_non_rustfix.rs b/tests/ui/toplevel_ref_arg_non_rustfix.rs index 8aaf47b1bd0c..464762af8253 100644 --- a/tests/ui/toplevel_ref_arg_non_rustfix.rs +++ b/tests/ui/toplevel_ref_arg_non_rustfix.rs @@ -1,4 +1,4 @@ -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![warn(clippy::toplevel_ref_arg)] #![allow(unused)] diff --git a/tests/ui/transmute_ptr_to_ptr.rs b/tests/ui/transmute_ptr_to_ptr.rs index f06ffab5d9be..61a6c98ed5ac 100644 --- a/tests/ui/transmute_ptr_to_ptr.rs +++ b/tests/ui/transmute_ptr_to_ptr.rs @@ -32,7 +32,7 @@ fn transmute_ptr_to_ptr() { // ref-ref transmutes; bad let _: &f32 = std::mem::transmute(&1u32); let _: &f64 = std::mem::transmute(&1f32); - // ^ this test is here because both f32 and f64 are the same TypeVariant, but they are not + //:^ this test is here because both f32 and f64 are the same TypeVariant, but they are not // the same type let _: &mut f32 = std::mem::transmute(&mut 1u32); let _: &GenericParam = std::mem::transmute(&GenericParam { t: 1u32 }); diff --git a/tests/ui/transmute_ptr_to_ref.fixed b/tests/ui/transmute_ptr_to_ref.fixed index ac55ab5a8e2d..215f0ac18422 100644 --- a/tests/ui/transmute_ptr_to_ref.fixed +++ b/tests/ui/transmute_ptr_to_ref.fixed @@ -1,8 +1,7 @@ //@run-rustfix #![warn(clippy::transmute_ptr_to_ref)] -#![allow(clippy::match_single_binding)] -#![allow(unused_must_use)] +#![allow(clippy::match_single_binding, clippy::unnecessary_cast)] unsafe fn _ptr_to_ref(p: *const T, m: *mut T, o: *const U, om: *mut U) { let _: &T = &*p; @@ -39,7 +38,7 @@ fn _issue1231() { type Bar<'a> = &'a u8; let raw = 42 as *const i32; - let _ = unsafe { &*(raw as *const u8) }; + unsafe { &*(raw as *const u8) }; } unsafe fn _issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 { diff --git a/tests/ui/transmute_ptr_to_ref.rs b/tests/ui/transmute_ptr_to_ref.rs index 901a3e90dbec..3528e1379039 100644 --- a/tests/ui/transmute_ptr_to_ref.rs +++ b/tests/ui/transmute_ptr_to_ref.rs @@ -1,8 +1,7 @@ //@run-rustfix #![warn(clippy::transmute_ptr_to_ref)] -#![allow(clippy::match_single_binding)] -#![allow(unused_must_use)] +#![allow(clippy::match_single_binding, clippy::unnecessary_cast)] unsafe fn _ptr_to_ref(p: *const T, m: *mut T, o: *const U, om: *mut U) { let _: &T = std::mem::transmute(p); @@ -39,7 +38,7 @@ fn _issue1231() { type Bar<'a> = &'a u8; let raw = 42 as *const i32; - let _ = unsafe { std::mem::transmute::<_, Bar>(raw) }; + unsafe { std::mem::transmute::<_, Bar>(raw) }; } unsafe fn _issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 { diff --git a/tests/ui/transmute_ptr_to_ref.stderr b/tests/ui/transmute_ptr_to_ref.stderr index 68007edc4102..b3e6c09d2d7a 100644 --- a/tests/ui/transmute_ptr_to_ref.stderr +++ b/tests/ui/transmute_ptr_to_ref.stderr @@ -1,5 +1,5 @@ error: transmute from a pointer type (`*const T`) to a reference type (`&T`) - --> $DIR/transmute_ptr_to_ref.rs:8:17 + --> $DIR/transmute_ptr_to_ref.rs:7:17 | LL | let _: &T = std::mem::transmute(p); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*p` @@ -7,127 +7,127 @@ LL | let _: &T = std::mem::transmute(p); = note: `-D clippy::transmute-ptr-to-ref` implied by `-D warnings` error: transmute from a pointer type (`*mut T`) to a reference type (`&mut T`) - --> $DIR/transmute_ptr_to_ref.rs:11:21 + --> $DIR/transmute_ptr_to_ref.rs:10:21 | LL | let _: &mut T = std::mem::transmute(m); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *m` error: transmute from a pointer type (`*mut T`) to a reference type (`&T`) - --> $DIR/transmute_ptr_to_ref.rs:14:17 + --> $DIR/transmute_ptr_to_ref.rs:13:17 | LL | let _: &T = std::mem::transmute(m); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*m` error: transmute from a pointer type (`*mut T`) to a reference type (`&mut T`) - --> $DIR/transmute_ptr_to_ref.rs:17:21 + --> $DIR/transmute_ptr_to_ref.rs:16:21 | LL | let _: &mut T = std::mem::transmute(p as *mut T); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(p as *mut T)` error: transmute from a pointer type (`*const U`) to a reference type (`&T`) - --> $DIR/transmute_ptr_to_ref.rs:20:17 + --> $DIR/transmute_ptr_to_ref.rs:19:17 | LL | let _: &T = std::mem::transmute(o); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(o as *const T)` error: transmute from a pointer type (`*mut U`) to a reference type (`&mut T`) - --> $DIR/transmute_ptr_to_ref.rs:23:21 + --> $DIR/transmute_ptr_to_ref.rs:22:21 | LL | let _: &mut T = std::mem::transmute(om); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(om as *mut T)` error: transmute from a pointer type (`*mut U`) to a reference type (`&T`) - --> $DIR/transmute_ptr_to_ref.rs:26:17 + --> $DIR/transmute_ptr_to_ref.rs:25:17 | LL | let _: &T = std::mem::transmute(om); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(om as *const T)` error: transmute from a pointer type (`*const i32`) to a reference type (`&_issue1231::Foo<'_, u8>`) - --> $DIR/transmute_ptr_to_ref.rs:36:32 + --> $DIR/transmute_ptr_to_ref.rs:35:32 | LL | let _: &Foo = unsafe { std::mem::transmute::<_, &Foo<_>>(raw) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*raw.cast::>()` error: transmute from a pointer type (`*const i32`) to a reference type (`&_issue1231::Foo<'_, &u8>`) - --> $DIR/transmute_ptr_to_ref.rs:38:33 + --> $DIR/transmute_ptr_to_ref.rs:37:33 | LL | let _: &Foo<&u8> = unsafe { std::mem::transmute::<_, &Foo<&_>>(raw) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*raw.cast::>()` error: transmute from a pointer type (`*const i32`) to a reference type (`&u8`) - --> $DIR/transmute_ptr_to_ref.rs:42:22 + --> $DIR/transmute_ptr_to_ref.rs:41:14 | -LL | let _ = unsafe { std::mem::transmute::<_, Bar>(raw) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(raw as *const u8)` +LL | unsafe { std::mem::transmute::<_, Bar>(raw) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(raw as *const u8)` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> $DIR/transmute_ptr_to_ref.rs:47:14 + --> $DIR/transmute_ptr_to_ref.rs:46:14 | LL | 0 => std::mem::transmute(x), | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&u32>()` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> $DIR/transmute_ptr_to_ref.rs:48:14 + --> $DIR/transmute_ptr_to_ref.rs:47:14 | LL | 1 => std::mem::transmute(y), | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*y.cast::<&u32>()` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> $DIR/transmute_ptr_to_ref.rs:49:14 + --> $DIR/transmute_ptr_to_ref.rs:48:14 | LL | 2 => std::mem::transmute::<_, &&'b u32>(x), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&'b u32>()` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> $DIR/transmute_ptr_to_ref.rs:50:14 + --> $DIR/transmute_ptr_to_ref.rs:49:14 | LL | _ => std::mem::transmute::<_, &&'b u32>(y), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*y.cast::<&'b u32>()` error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`) - --> $DIR/transmute_ptr_to_ref.rs:58:19 + --> $DIR/transmute_ptr_to_ref.rs:57:19 | LL | let _: &u32 = std::mem::transmute(a); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a` error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`) - --> $DIR/transmute_ptr_to_ref.rs:59:19 + --> $DIR/transmute_ptr_to_ref.rs:58:19 | LL | let _: &u32 = std::mem::transmute::<_, &u32>(a); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a.cast::()` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> $DIR/transmute_ptr_to_ref.rs:61:14 + --> $DIR/transmute_ptr_to_ref.rs:60:14 | LL | 0 => std::mem::transmute(x), | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&u32>()` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> $DIR/transmute_ptr_to_ref.rs:62:14 + --> $DIR/transmute_ptr_to_ref.rs:61:14 | LL | _ => std::mem::transmute::<_, &&'b u32>(x), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&'b u32>()` error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`) - --> $DIR/transmute_ptr_to_ref.rs:70:19 + --> $DIR/transmute_ptr_to_ref.rs:69:19 | LL | let _: &u32 = std::mem::transmute(a); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a` error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`) - --> $DIR/transmute_ptr_to_ref.rs:71:19 + --> $DIR/transmute_ptr_to_ref.rs:70:19 | LL | let _: &u32 = std::mem::transmute::<_, &u32>(a); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a as *const u32)` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> $DIR/transmute_ptr_to_ref.rs:73:14 + --> $DIR/transmute_ptr_to_ref.rs:72:14 | LL | 0 => std::mem::transmute(x), | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(x as *const () as *const &u32)` error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`) - --> $DIR/transmute_ptr_to_ref.rs:74:14 + --> $DIR/transmute_ptr_to_ref.rs:73:14 | LL | _ => std::mem::transmute::<_, &&'b u32>(x), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(x as *const () as *const &'b u32)` diff --git a/tests/ui/try_err.fixed b/tests/ui/try_err.fixed index dc773ad4bad9..1816740870ad 100644 --- a/tests/ui/try_err.fixed +++ b/tests/ui/try_err.fixed @@ -1,5 +1,5 @@ //@run-rustfix -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![deny(clippy::try_err)] #![allow(clippy::unnecessary_wraps, clippy::needless_question_mark)] diff --git a/tests/ui/try_err.rs b/tests/ui/try_err.rs index 7a7433a7ec29..0e47c4d023ef 100644 --- a/tests/ui/try_err.rs +++ b/tests/ui/try_err.rs @@ -1,5 +1,5 @@ //@run-rustfix -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![deny(clippy::try_err)] #![allow(clippy::unnecessary_wraps, clippy::needless_question_mark)] diff --git a/tests/ui/tuple_array_conversions.rs b/tests/ui/tuple_array_conversions.rs new file mode 100644 index 000000000000..f96a7c97f1aa --- /dev/null +++ b/tests/ui/tuple_array_conversions.rs @@ -0,0 +1,73 @@ +//@aux-build:proc_macros.rs:proc-macro +#![allow(clippy::no_effect, clippy::useless_vec, unused)] +#![warn(clippy::tuple_array_conversions)] + +#[macro_use] +extern crate proc_macros; + +fn main() { + let x = [1, 2]; + let x = (x[0], x[1]); + let x = [x.0, x.1]; + let x = &[1, 2]; + let x = (x[0], x[1]); + + let t1: &[(u32, u32)] = &[(1, 2), (3, 4)]; + let v1: Vec<[u32; 2]> = t1.iter().map(|&(a, b)| [a, b]).collect(); + t1.iter().for_each(|&(a, b)| _ = [a, b]); + let t2: Vec<(u32, u32)> = v1.iter().map(|&[a, b]| (a, b)).collect(); + t1.iter().for_each(|&(a, b)| _ = [a, b]); + // Do not lint + let v2: Vec<[u32; 2]> = t1.iter().map(|&t| t.into()).collect(); + let t3: Vec<(u32, u32)> = v2.iter().map(|&v| v.into()).collect(); + let x = [1; 13]; + let x = ( + x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12], + ); + let x = [x.0, x.1, x.2, x.3, x.4, x.5, x.6, x.7, x.8, x.9, x.10, x.11, x.12]; + let x = (1, 2); + let x = (x.0, x.1); + let x = [1, 2]; + let x = [x[0], x[1]]; + let x = vec![1, 2]; + let x = (x[0], x[1]); + let x = [1; 3]; + let x = (x[0],); + let x = (1, 2, 3); + let x = [x.0]; + let x = (1, 2); + let y = (1, 2); + [x.0, y.0]; + [x.0, y.1]; + let x = [x.0, x.0]; + let x = (x[0], x[0]); + external! { + let t1: &[(u32, u32)] = &[(1, 2), (3, 4)]; + let v1: Vec<[u32; 2]> = t1.iter().map(|&(a, b)| [a, b]).collect(); + let t2: Vec<(u32, u32)> = v1.iter().map(|&[a, b]| (a, b)).collect(); + } + with_span! { + span + let t1: &[(u32, u32)] = &[(1, 2), (3, 4)]; + let v1: Vec<[u32; 2]> = t1.iter().map(|&(a, b)| [a, b]).collect(); + let t2: Vec<(u32, u32)> = v1.iter().map(|&[a, b]| (a, b)).collect(); + } +} + +#[clippy::msrv = "1.70.0"] +fn msrv_too_low() { + let x = [1, 2]; + let x = (x[0], x[1]); + let x = [x.0, x.1]; + let x = &[1, 2]; + let x = (x[0], x[1]); +} + +#[clippy::msrv = "1.71.0"] +fn msrv_juust_right() { + let x = [1, 2]; + let x = (x[0], x[1]); + let x = [x.0, x.1]; + let x = &[1, 2]; + let x = (x[0], x[1]); +} diff --git a/tests/ui/tuple_array_conversions.stderr b/tests/ui/tuple_array_conversions.stderr new file mode 100644 index 000000000000..be653e8efb79 --- /dev/null +++ b/tests/ui/tuple_array_conversions.stderr @@ -0,0 +1,83 @@ +error: it looks like you're trying to convert an array to a tuple + --> $DIR/tuple_array_conversions.rs:10:13 + | +LL | let x = (x[0], x[1]); + | ^^^^^^^^^^^^ + | + = help: use `.into()` instead, or `<(T0, T1, ..., Tn)>::from` if type annotations are needed + = note: `-D clippy::tuple-array-conversions` implied by `-D warnings` + +error: it looks like you're trying to convert a tuple to an array + --> $DIR/tuple_array_conversions.rs:11:13 + | +LL | let x = [x.0, x.1]; + | ^^^^^^^^^^ + | + = help: use `.into()` instead, or `<[T; N]>::from` if type annotations are needed + +error: it looks like you're trying to convert an array to a tuple + --> $DIR/tuple_array_conversions.rs:13:13 + | +LL | let x = (x[0], x[1]); + | ^^^^^^^^^^^^ + | + = help: use `.into()` instead, or `<(T0, T1, ..., Tn)>::from` if type annotations are needed + +error: it looks like you're trying to convert a tuple to an array + --> $DIR/tuple_array_conversions.rs:16:53 + | +LL | let v1: Vec<[u32; 2]> = t1.iter().map(|&(a, b)| [a, b]).collect(); + | ^^^^^^ + | + = help: use `.into()` instead, or `<[T; N]>::from` if type annotations are needed + +error: it looks like you're trying to convert a tuple to an array + --> $DIR/tuple_array_conversions.rs:17:38 + | +LL | t1.iter().for_each(|&(a, b)| _ = [a, b]); + | ^^^^^^ + | + = help: use `.into()` instead, or `<[T; N]>::from` if type annotations are needed + +error: it looks like you're trying to convert an array to a tuple + --> $DIR/tuple_array_conversions.rs:18:55 + | +LL | let t2: Vec<(u32, u32)> = v1.iter().map(|&[a, b]| (a, b)).collect(); + | ^^^^^^ + | + = help: use `.into()` instead, or `<(T0, T1, ..., Tn)>::from` if type annotations are needed + +error: it looks like you're trying to convert a tuple to an array + --> $DIR/tuple_array_conversions.rs:19:38 + | +LL | t1.iter().for_each(|&(a, b)| _ = [a, b]); + | ^^^^^^ + | + = help: use `.into()` instead, or `<[T; N]>::from` if type annotations are needed + +error: it looks like you're trying to convert an array to a tuple + --> $DIR/tuple_array_conversions.rs:69:13 + | +LL | let x = (x[0], x[1]); + | ^^^^^^^^^^^^ + | + = help: use `.into()` instead, or `<(T0, T1, ..., Tn)>::from` if type annotations are needed + +error: it looks like you're trying to convert a tuple to an array + --> $DIR/tuple_array_conversions.rs:70:13 + | +LL | let x = [x.0, x.1]; + | ^^^^^^^^^^ + | + = help: use `.into()` instead, or `<[T; N]>::from` if type annotations are needed + +error: it looks like you're trying to convert an array to a tuple + --> $DIR/tuple_array_conversions.rs:72:13 + | +LL | let x = (x[0], x[1]); + | ^^^^^^^^^^^^ + | + = help: use `.into()` instead, or `<(T0, T1, ..., Tn)>::from` if type annotations are needed + +error: aborting due to 10 previous errors + diff --git a/tests/ui/type_complexity.rs b/tests/ui/type_complexity.rs index 86a7bd7b6273..816950110b20 100644 --- a/tests/ui/type_complexity.rs +++ b/tests/ui/type_complexity.rs @@ -1,5 +1,5 @@ #![warn(clippy::all)] -#![allow(unused, clippy::needless_pass_by_value, clippy::vec_box)] +#![allow(unused, clippy::needless_pass_by_value, clippy::vec_box, clippy::useless_vec)] #![feature(associated_type_defaults)] type Alias = Vec>>; // no warning here diff --git a/tests/ui/type_repetition_in_bounds.rs b/tests/ui/type_repetition_in_bounds.rs index 8b4613b3f6ec..874d97f7a46c 100644 --- a/tests/ui/type_repetition_in_bounds.rs +++ b/tests/ui/type_repetition_in_bounds.rs @@ -1,6 +1,7 @@ #![deny(clippy::type_repetition_in_bounds)] #![allow(clippy::extra_unused_type_parameters)] +use serde::Deserialize; use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign}; pub fn foo(_t: T) @@ -70,6 +71,20 @@ mod issue4326 { } } +// Extern macros shouldn't lint, again (see #10504) +mod issue10504 { + use serde::{Deserialize, Serialize}; + use std::fmt::Debug; + use std::hash::Hash; + + #[derive(Debug, Serialize, Deserialize)] + #[serde(bound( + serialize = "T: Serialize + Hash + Eq", + deserialize = "Box: serde::de::DeserializeOwned + Hash + Eq" + ))] + struct OpaqueParams(std::marker::PhantomData); +} + // Issue #7360 struct Foo where @@ -95,4 +110,28 @@ where // This should not lint fn impl_trait(_: impl AsRef, _: impl AsRef) {} +#[clippy::msrv = "1.14.0"] +mod issue8772_fail { + pub trait Trait {} + + pub fn f(arg: usize) + where + T: Trait, Box<[String]>, bool> + 'static, + U: Clone + Sync + 'static, + { + } +} + +#[clippy::msrv = "1.15.0"] +mod issue8772_pass { + pub trait Trait {} + + pub fn f(arg: usize) + where + T: Trait, Box<[String]>, bool> + 'static, + U: Clone + Sync + 'static, + { + } +} + fn main() {} diff --git a/tests/ui/type_repetition_in_bounds.stderr b/tests/ui/type_repetition_in_bounds.stderr index a90df03c04ff..54973c5bda57 100644 --- a/tests/ui/type_repetition_in_bounds.stderr +++ b/tests/ui/type_repetition_in_bounds.stderr @@ -1,5 +1,5 @@ error: this type has already been used as a bound predicate - --> $DIR/type_repetition_in_bounds.rs:9:5 + --> $DIR/type_repetition_in_bounds.rs:10:5 | LL | T: Clone, | ^^^^^^^^ @@ -12,7 +12,7 @@ LL | #![deny(clippy::type_repetition_in_bounds)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this type has already been used as a bound predicate - --> $DIR/type_repetition_in_bounds.rs:26:5 + --> $DIR/type_repetition_in_bounds.rs:27:5 | LL | Self: Copy + Default + Ord, | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -20,7 +20,7 @@ LL | Self: Copy + Default + Ord, = help: consider combining the bounds: `Self: Clone + Copy + Default + Ord` error: this type has already been used as a bound predicate - --> $DIR/type_repetition_in_bounds.rs:86:5 + --> $DIR/type_repetition_in_bounds.rs:101:5 | LL | T: Clone, | ^^^^^^^^ @@ -28,12 +28,20 @@ LL | T: Clone, = help: consider combining the bounds: `T: ?Sized + Clone` error: this type has already been used as a bound predicate - --> $DIR/type_repetition_in_bounds.rs:91:5 + --> $DIR/type_repetition_in_bounds.rs:106:5 | LL | T: ?Sized, | ^^^^^^^^^ | = help: consider combining the bounds: `T: Clone + ?Sized` -error: aborting due to 4 previous errors +error: this type has already been used as a bound predicate + --> $DIR/type_repetition_in_bounds.rs:131:9 + | +LL | T: Trait, Box<[String]>, bool> + 'static, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider combining the bounds: `T: ?Sized + Trait, Box<[String]>, bool>` + +error: aborting due to 5 previous errors diff --git a/tests/ui/undocumented_unsafe_blocks.rs b/tests/ui/undocumented_unsafe_blocks.rs index 229d150851a4..a9cc42954356 100644 --- a/tests/ui/undocumented_unsafe_blocks.rs +++ b/tests/ui/undocumented_unsafe_blocks.rs @@ -1,4 +1,4 @@ -//@aux-build:proc_macro_unsafe.rs +//@aux-build:proc_macro_unsafe.rs:proc-macro #![warn(clippy::undocumented_unsafe_blocks, clippy::unnecessary_safety_comment)] #![allow(clippy::let_unit_value, clippy::missing_safety_doc)] @@ -509,4 +509,26 @@ fn issue_9142() { }; } +pub unsafe fn a_function_with_a_very_long_name_to_break_the_line() -> u32 { + 1 +} + +pub const unsafe fn a_const_function_with_a_very_long_name_to_break_the_line() -> u32 { + 2 +} + +fn issue_10832() { + // Safety: A safety comment. But it will warn anyways + let _some_variable_with_a_very_long_name_to_break_the_line = + unsafe { a_function_with_a_very_long_name_to_break_the_line() }; + + // Safety: Another safety comment. But it will warn anyways + const _SOME_CONST_WITH_A_VERY_LONG_NAME_TO_BREAK_THE_LINE: u32 = + unsafe { a_const_function_with_a_very_long_name_to_break_the_line() }; + + // Safety: Yet another safety comment. But it will warn anyways + static _SOME_STATIC_WITH_A_VERY_LONG_NAME_TO_BREAK_THE_LINE: u32 = + unsafe { a_const_function_with_a_very_long_name_to_break_the_line() }; +} + fn main() {} diff --git a/tests/ui/undocumented_unsafe_blocks.stderr b/tests/ui/undocumented_unsafe_blocks.stderr index d1c1bb5ffeac..ee1d3aa285a2 100644 --- a/tests/ui/undocumented_unsafe_blocks.stderr +++ b/tests/ui/undocumented_unsafe_blocks.stderr @@ -318,5 +318,29 @@ LL | let bar = unsafe {}; | = help: consider adding a safety comment on the preceding line -error: aborting due to 36 previous errors +error: unsafe block missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:523:9 + | +LL | unsafe { a_function_with_a_very_long_name_to_break_the_line() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider adding a safety comment on the preceding line + +error: unsafe block missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:527:9 + | +LL | unsafe { a_const_function_with_a_very_long_name_to_break_the_line() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider adding a safety comment on the preceding line + +error: unsafe block missing a safety comment + --> $DIR/undocumented_unsafe_blocks.rs:531:9 + | +LL | unsafe { a_const_function_with_a_very_long_name_to_break_the_line() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider adding a safety comment on the preceding line + +error: aborting due to 39 previous errors diff --git a/tests/ui/unicode.fixed b/tests/ui/unicode.fixed index 910968afa7f4..032040c4805c 100644 --- a/tests/ui/unicode.fixed +++ b/tests/ui/unicode.fixed @@ -1,5 +1,4 @@ //@run-rustfix -//@compile-flags: --test #![allow(dead_code)] #[warn(clippy::invisible_characters)] diff --git a/tests/ui/unicode.rs b/tests/ui/unicode.rs index bc4b84d34354..dd215bc60487 100644 --- a/tests/ui/unicode.rs +++ b/tests/ui/unicode.rs @@ -1,5 +1,4 @@ //@run-rustfix -//@compile-flags: --test #![allow(dead_code)] #[warn(clippy::invisible_characters)] diff --git a/tests/ui/unicode.stderr b/tests/ui/unicode.stderr index ea74a81451e3..21cc22a778bc 100644 --- a/tests/ui/unicode.stderr +++ b/tests/ui/unicode.stderr @@ -1,5 +1,5 @@ error: invisible character detected - --> $DIR/unicode.rs:7:12 + --> $DIR/unicode.rs:6:12 | LL | print!("Here >​< is a ZWS, and ​another"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >/u{200B}< is a ZWS, and /u{200B}another"` @@ -7,19 +7,19 @@ LL | print!("Here >​< is a ZWS, and ​another"); = note: `-D clippy::invisible-characters` implied by `-D warnings` error: invisible character detected - --> $DIR/unicode.rs:9:12 + --> $DIR/unicode.rs:8:12 | LL | print!("Here >­< is a SHY, and ­another"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >/u{AD}< is a SHY, and /u{AD}another"` error: invisible character detected - --> $DIR/unicode.rs:11:12 + --> $DIR/unicode.rs:10:12 | LL | print!("Here >⁠< is a WJ, and ⁠another"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >/u{2060}< is a WJ, and /u{2060}another"` error: non-NFC Unicode sequence detected - --> $DIR/unicode.rs:17:12 + --> $DIR/unicode.rs:16:12 | LL | print!("̀àh?"); | ^^^^^ help: consider replacing the string with: `"̀àh?"` @@ -27,37 +27,37 @@ LL | print!("̀àh?"); = note: `-D clippy::unicode-not-nfc` implied by `-D warnings` error: literal non-ASCII character detected - --> $DIR/unicode.rs:25:16 + --> $DIR/unicode.rs:24:16 | LL | print!("Üben!"); | ^^^^^^^ help: consider replacing the string with: `"/u{dc}ben!"` | note: the lint level is defined here - --> $DIR/unicode.rs:22:13 + --> $DIR/unicode.rs:21:13 | LL | #![deny(clippy::non_ascii_literal)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: literal non-ASCII character detected - --> $DIR/unicode.rs:31:36 + --> $DIR/unicode.rs:30:36 | LL | const _EMPTY_BLOCK: char = '▱'; | ^^^ help: consider replacing the string with: `'/u{25b1}'` error: literal non-ASCII character detected - --> $DIR/unicode.rs:32:35 + --> $DIR/unicode.rs:31:35 | LL | const _FULL_BLOCK: char = '▰'; | ^^^ help: consider replacing the string with: `'/u{25b0}'` error: literal non-ASCII character detected - --> $DIR/unicode.rs:52:21 + --> $DIR/unicode.rs:51:21 | LL | let _ = "悲しいかな、ここに日本語を書くことはできない。"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"/u{60b2}/u{3057}/u{3044}/u{304b}/u{306a}/u{3001}/u{3053}/u{3053}/u{306b}/u{65e5}/u{672c}/u{8a9e}/u{3092}/u{66f8}/u{304f}/u{3053}/u{3068}/u{306f}/u{3067}/u{304d}/u{306a}/u{3044}/u{3002}"` | note: the lint level is defined here - --> $DIR/unicode.rs:41:17 + --> $DIR/unicode.rs:40:17 | LL | #![deny(clippy::non_ascii_literal)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/uninlined_format_args.fixed b/tests/ui/uninlined_format_args.fixed index e25d123dd51f..a042731a9bf5 100644 --- a/tests/ui/uninlined_format_args.fixed +++ b/tests/ui/uninlined_format_args.fixed @@ -1,8 +1,13 @@ -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro //@run-rustfix #![warn(clippy::uninlined_format_args)] #![allow(named_arguments_used_positionally, unused)] -#![allow(clippy::eq_op, clippy::format_in_format_args, clippy::print_literal)] +#![allow( + clippy::eq_op, + clippy::format_in_format_args, + clippy::print_literal, + clippy::unnecessary_literal_unwrap +)] extern crate proc_macros; use proc_macros::with_span; diff --git a/tests/ui/uninlined_format_args.rs b/tests/ui/uninlined_format_args.rs index 6793ec24441c..d830b74d6072 100644 --- a/tests/ui/uninlined_format_args.rs +++ b/tests/ui/uninlined_format_args.rs @@ -1,8 +1,13 @@ -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro //@run-rustfix #![warn(clippy::uninlined_format_args)] #![allow(named_arguments_used_positionally, unused)] -#![allow(clippy::eq_op, clippy::format_in_format_args, clippy::print_literal)] +#![allow( + clippy::eq_op, + clippy::format_in_format_args, + clippy::print_literal, + clippy::unnecessary_literal_unwrap +)] extern crate proc_macros; use proc_macros::with_span; diff --git a/tests/ui/uninlined_format_args.stderr b/tests/ui/uninlined_format_args.stderr index dc4af6ef42ec..44ca61f008c5 100644 --- a/tests/ui/uninlined_format_args.stderr +++ b/tests/ui/uninlined_format_args.stderr @@ -1,5 +1,5 @@ error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:40:5 + --> $DIR/uninlined_format_args.rs:45:5 | LL | println!("val='{}'", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -12,7 +12,7 @@ LL + println!("val='{local_i32}'"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:41:5 + --> $DIR/uninlined_format_args.rs:46:5 | LL | println!("val='{ }'", local_i32); // 3 spaces | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL + println!("val='{local_i32}'"); // 3 spaces | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:42:5 + --> $DIR/uninlined_format_args.rs:47:5 | LL | println!("val='{ }'", local_i32); // tab | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -36,7 +36,7 @@ LL + println!("val='{local_i32}'"); // tab | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:43:5 + --> $DIR/uninlined_format_args.rs:48:5 | LL | println!("val='{ }'", local_i32); // space+tab | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL + println!("val='{local_i32}'"); // space+tab | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:44:5 + --> $DIR/uninlined_format_args.rs:49:5 | LL | println!("val='{ }'", local_i32); // tab+space | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -60,7 +60,7 @@ LL + println!("val='{local_i32}'"); // tab+space | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:45:5 + --> $DIR/uninlined_format_args.rs:50:5 | LL | / println!( LL | | "val='{ @@ -70,7 +70,7 @@ LL | | ); | |_____^ error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:50:5 + --> $DIR/uninlined_format_args.rs:55:5 | LL | println!("{}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -82,7 +82,7 @@ LL + println!("{local_i32}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:51:5 + --> $DIR/uninlined_format_args.rs:56:5 | LL | println!("{}", fn_arg); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -94,7 +94,7 @@ LL + println!("{fn_arg}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:52:5 + --> $DIR/uninlined_format_args.rs:57:5 | LL | println!("{:?}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -106,7 +106,7 @@ LL + println!("{local_i32:?}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:53:5 + --> $DIR/uninlined_format_args.rs:58:5 | LL | println!("{:#?}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -118,7 +118,7 @@ LL + println!("{local_i32:#?}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:54:5 + --> $DIR/uninlined_format_args.rs:59:5 | LL | println!("{:4}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -130,7 +130,7 @@ LL + println!("{local_i32:4}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:55:5 + --> $DIR/uninlined_format_args.rs:60:5 | LL | println!("{:04}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -142,7 +142,7 @@ LL + println!("{local_i32:04}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:56:5 + --> $DIR/uninlined_format_args.rs:61:5 | LL | println!("{:<3}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -154,7 +154,7 @@ LL + println!("{local_i32:<3}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:57:5 + --> $DIR/uninlined_format_args.rs:62:5 | LL | println!("{:#010x}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -166,7 +166,7 @@ LL + println!("{local_i32:#010x}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:58:5 + --> $DIR/uninlined_format_args.rs:63:5 | LL | println!("{:.1}", local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -178,7 +178,7 @@ LL + println!("{local_f64:.1}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:62:5 + --> $DIR/uninlined_format_args.rs:67:5 | LL | println!("{} {}", local_i32, local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -190,7 +190,7 @@ LL + println!("{local_i32} {local_f64}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:64:5 + --> $DIR/uninlined_format_args.rs:69:5 | LL | println!("{}", val); | ^^^^^^^^^^^^^^^^^^^ @@ -202,7 +202,7 @@ LL + println!("{val}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:65:5 + --> $DIR/uninlined_format_args.rs:70:5 | LL | println!("{}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -214,7 +214,7 @@ LL + println!("{val}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:67:5 + --> $DIR/uninlined_format_args.rs:72:5 | LL | println!("val='{/t }'", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -226,7 +226,7 @@ LL + println!("val='{local_i32}'"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:68:5 + --> $DIR/uninlined_format_args.rs:73:5 | LL | println!("val='{/n }'", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -238,7 +238,7 @@ LL + println!("val='{local_i32}'"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:69:5 + --> $DIR/uninlined_format_args.rs:74:5 | LL | println!("val='{local_i32}'", local_i32 = local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -250,7 +250,7 @@ LL + println!("val='{local_i32}'"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:70:5 + --> $DIR/uninlined_format_args.rs:75:5 | LL | println!("val='{local_i32}'", local_i32 = fn_arg); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -262,7 +262,7 @@ LL + println!("val='{fn_arg}'"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:71:5 + --> $DIR/uninlined_format_args.rs:76:5 | LL | println!("{0}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -274,7 +274,7 @@ LL + println!("{local_i32}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:72:5 + --> $DIR/uninlined_format_args.rs:77:5 | LL | println!("{0:?}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -286,7 +286,7 @@ LL + println!("{local_i32:?}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:73:5 + --> $DIR/uninlined_format_args.rs:78:5 | LL | println!("{0:#?}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -298,7 +298,7 @@ LL + println!("{local_i32:#?}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:74:5 + --> $DIR/uninlined_format_args.rs:79:5 | LL | println!("{0:04}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -310,7 +310,7 @@ LL + println!("{local_i32:04}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:75:5 + --> $DIR/uninlined_format_args.rs:80:5 | LL | println!("{0:<3}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -322,7 +322,7 @@ LL + println!("{local_i32:<3}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:76:5 + --> $DIR/uninlined_format_args.rs:81:5 | LL | println!("{0:#010x}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -334,7 +334,7 @@ LL + println!("{local_i32:#010x}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:77:5 + --> $DIR/uninlined_format_args.rs:82:5 | LL | println!("{0:.1}", local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -346,7 +346,7 @@ LL + println!("{local_f64:.1}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:78:5 + --> $DIR/uninlined_format_args.rs:83:5 | LL | println!("{0} {0}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -358,7 +358,7 @@ LL + println!("{local_i32} {local_i32}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:79:5 + --> $DIR/uninlined_format_args.rs:84:5 | LL | println!("{1} {} {0} {}", local_i32, local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -370,7 +370,7 @@ LL + println!("{local_f64} {local_i32} {local_i32} {local_f64}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:80:5 + --> $DIR/uninlined_format_args.rs:85:5 | LL | println!("{0} {1}", local_i32, local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -382,7 +382,7 @@ LL + println!("{local_i32} {local_f64}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:81:5 + --> $DIR/uninlined_format_args.rs:86:5 | LL | println!("{1} {0}", local_i32, local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -394,7 +394,7 @@ LL + println!("{local_f64} {local_i32}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:82:5 + --> $DIR/uninlined_format_args.rs:87:5 | LL | println!("{1} {0} {1} {0}", local_i32, local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -406,7 +406,7 @@ LL + println!("{local_f64} {local_i32} {local_f64} {local_i32}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:84:5 + --> $DIR/uninlined_format_args.rs:89:5 | LL | println!("{v}", v = local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -418,7 +418,7 @@ LL + println!("{local_i32}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:85:5 + --> $DIR/uninlined_format_args.rs:90:5 | LL | println!("{local_i32:0$}", width); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -430,7 +430,7 @@ LL + println!("{local_i32:width$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:86:5 + --> $DIR/uninlined_format_args.rs:91:5 | LL | println!("{local_i32:w$}", w = width); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -442,7 +442,7 @@ LL + println!("{local_i32:width$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:87:5 + --> $DIR/uninlined_format_args.rs:92:5 | LL | println!("{local_i32:.0$}", prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -454,7 +454,7 @@ LL + println!("{local_i32:.prec$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:88:5 + --> $DIR/uninlined_format_args.rs:93:5 | LL | println!("{local_i32:.p$}", p = prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -466,7 +466,7 @@ LL + println!("{local_i32:.prec$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:89:5 + --> $DIR/uninlined_format_args.rs:94:5 | LL | println!("{:0$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -478,7 +478,7 @@ LL + println!("{val:val$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:90:5 + --> $DIR/uninlined_format_args.rs:95:5 | LL | println!("{0:0$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -490,7 +490,7 @@ LL + println!("{val:val$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:91:5 + --> $DIR/uninlined_format_args.rs:96:5 | LL | println!("{:0$.0$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -502,7 +502,7 @@ LL + println!("{val:val$.val$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:92:5 + --> $DIR/uninlined_format_args.rs:97:5 | LL | println!("{0:0$.0$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -514,7 +514,7 @@ LL + println!("{val:val$.val$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:93:5 + --> $DIR/uninlined_format_args.rs:98:5 | LL | println!("{0:0$.v$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -526,7 +526,7 @@ LL + println!("{val:val$.val$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:94:5 + --> $DIR/uninlined_format_args.rs:99:5 | LL | println!("{0:v$.0$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -538,7 +538,7 @@ LL + println!("{val:val$.val$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:95:5 + --> $DIR/uninlined_format_args.rs:100:5 | LL | println!("{v:0$.0$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -550,7 +550,7 @@ LL + println!("{val:val$.val$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:96:5 + --> $DIR/uninlined_format_args.rs:101:5 | LL | println!("{v:v$.0$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -562,7 +562,7 @@ LL + println!("{val:val$.val$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:97:5 + --> $DIR/uninlined_format_args.rs:102:5 | LL | println!("{v:0$.v$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -574,7 +574,7 @@ LL + println!("{val:val$.val$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:98:5 + --> $DIR/uninlined_format_args.rs:103:5 | LL | println!("{v:v$.v$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -586,7 +586,7 @@ LL + println!("{val:val$.val$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:99:5 + --> $DIR/uninlined_format_args.rs:104:5 | LL | println!("{:0$}", width); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -598,7 +598,7 @@ LL + println!("{width:width$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:100:5 + --> $DIR/uninlined_format_args.rs:105:5 | LL | println!("{:1$}", local_i32, width); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -610,7 +610,7 @@ LL + println!("{local_i32:width$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:101:5 + --> $DIR/uninlined_format_args.rs:106:5 | LL | println!("{:w$}", w = width); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -622,7 +622,7 @@ LL + println!("{width:width$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:102:5 + --> $DIR/uninlined_format_args.rs:107:5 | LL | println!("{:w$}", local_i32, w = width); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -634,7 +634,7 @@ LL + println!("{local_i32:width$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:103:5 + --> $DIR/uninlined_format_args.rs:108:5 | LL | println!("{:.0$}", prec); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -646,7 +646,7 @@ LL + println!("{prec:.prec$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:104:5 + --> $DIR/uninlined_format_args.rs:109:5 | LL | println!("{:.1$}", local_i32, prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -658,7 +658,7 @@ LL + println!("{local_i32:.prec$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:105:5 + --> $DIR/uninlined_format_args.rs:110:5 | LL | println!("{:.p$}", p = prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -670,7 +670,7 @@ LL + println!("{prec:.prec$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:106:5 + --> $DIR/uninlined_format_args.rs:111:5 | LL | println!("{:.p$}", local_i32, p = prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -682,7 +682,7 @@ LL + println!("{local_i32:.prec$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:107:5 + --> $DIR/uninlined_format_args.rs:112:5 | LL | println!("{:0$.1$}", width, prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -694,7 +694,7 @@ LL + println!("{width:width$.prec$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:108:5 + --> $DIR/uninlined_format_args.rs:113:5 | LL | println!("{:0$.w$}", width, w = prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -706,7 +706,7 @@ LL + println!("{width:width$.prec$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:109:5 + --> $DIR/uninlined_format_args.rs:114:5 | LL | println!("{:1$.2$}", local_f64, width, prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -718,7 +718,7 @@ LL + println!("{local_f64:width$.prec$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:110:5 + --> $DIR/uninlined_format_args.rs:115:5 | LL | println!("{:1$.2$} {0} {1} {2}", local_f64, width, prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -730,7 +730,7 @@ LL + println!("{local_f64:width$.prec$} {local_f64} {width} {prec}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:111:5 + --> $DIR/uninlined_format_args.rs:116:5 | LL | / println!( LL | | "{0:1$.2$} {0:2$.1$} {1:0$.2$} {1:2$.0$} {2:0$.1$} {2:1$.0$}", @@ -739,7 +739,7 @@ LL | | ); | |_____^ error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:122:5 + --> $DIR/uninlined_format_args.rs:127:5 | LL | println!("Width = {}, value with width = {:0$}", local_i32, local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -751,7 +751,7 @@ LL + println!("Width = {local_i32}, value with width = {local_f64:local_i32$ | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:123:5 + --> $DIR/uninlined_format_args.rs:128:5 | LL | println!("{:w$.p$}", local_i32, w = width, p = prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -763,7 +763,7 @@ LL + println!("{local_i32:width$.prec$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:124:5 + --> $DIR/uninlined_format_args.rs:129:5 | LL | println!("{:w$.p$}", w = width, p = prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -775,7 +775,7 @@ LL + println!("{width:width$.prec$}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:143:5 + --> $DIR/uninlined_format_args.rs:148:5 | LL | / println!( LL | | "{}", @@ -785,7 +785,7 @@ LL | | ); | |_____^ error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:148:5 + --> $DIR/uninlined_format_args.rs:153:5 | LL | println!("{}", /* comment with a comma , in it */ val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -797,7 +797,7 @@ LL + println!("{val}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:154:9 + --> $DIR/uninlined_format_args.rs:159:9 | LL | panic!("p1 {}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -809,7 +809,7 @@ LL + panic!("p1 {local_i32}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:157:9 + --> $DIR/uninlined_format_args.rs:162:9 | LL | panic!("p2 {0}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -821,7 +821,7 @@ LL + panic!("p2 {local_i32}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:160:9 + --> $DIR/uninlined_format_args.rs:165:9 | LL | panic!("p3 {local_i32}", local_i32 = local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -833,7 +833,7 @@ LL + panic!("p3 {local_i32}"); | error: variables can be used directly in the `format!` string - --> $DIR/uninlined_format_args.rs:180:5 + --> $DIR/uninlined_format_args.rs:185:5 | LL | println!("expand='{}'", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/unit_arg.rs b/tests/ui/unit_arg.rs index d082063c8e82..fded8db5daf9 100644 --- a/tests/ui/unit_arg.rs +++ b/tests/ui/unit_arg.rs @@ -1,4 +1,4 @@ -//@aux-build: proc_macros.rs +//@aux-build: proc_macros.rs:proc-macro #![warn(clippy::unit_arg)] #![allow(unused_must_use, unused_variables)] #![allow( diff --git a/tests/ui/unit_cmp.rs b/tests/ui/unit_cmp.rs index 3d271104361b..fc75f548a1bc 100644 --- a/tests/ui/unit_cmp.rs +++ b/tests/ui/unit_cmp.rs @@ -2,7 +2,8 @@ #![allow( clippy::no_effect, clippy::unnecessary_operation, - clippy::derive_partial_eq_without_eq + clippy::derive_partial_eq_without_eq, + clippy::needless_if )] #[derive(PartialEq)] diff --git a/tests/ui/unit_cmp.stderr b/tests/ui/unit_cmp.stderr index 41cf19ae685e..79c890d644cd 100644 --- a/tests/ui/unit_cmp.stderr +++ b/tests/ui/unit_cmp.stderr @@ -1,5 +1,5 @@ error: ==-comparison of unit values detected. This will always be true - --> $DIR/unit_cmp.rs:16:8 + --> $DIR/unit_cmp.rs:17:8 | LL | if { | ________^ @@ -12,7 +12,7 @@ LL | | } {} = note: `-D clippy::unit-cmp` implied by `-D warnings` error: >-comparison of unit values detected. This will always be false - --> $DIR/unit_cmp.rs:22:8 + --> $DIR/unit_cmp.rs:23:8 | LL | if { | ________^ @@ -23,7 +23,7 @@ LL | | } {} | |_____^ error: `assert_eq` of unit values detected. This will always succeed - --> $DIR/unit_cmp.rs:28:5 + --> $DIR/unit_cmp.rs:29:5 | LL | / assert_eq!( LL | | { @@ -35,7 +35,7 @@ LL | | ); | |_____^ error: `debug_assert_eq` of unit values detected. This will always succeed - --> $DIR/unit_cmp.rs:36:5 + --> $DIR/unit_cmp.rs:37:5 | LL | / debug_assert_eq!( LL | | { @@ -47,7 +47,7 @@ LL | | ); | |_____^ error: `assert_ne` of unit values detected. This will always fail - --> $DIR/unit_cmp.rs:45:5 + --> $DIR/unit_cmp.rs:46:5 | LL | / assert_ne!( LL | | { @@ -59,7 +59,7 @@ LL | | ); | |_____^ error: `debug_assert_ne` of unit values detected. This will always fail - --> $DIR/unit_cmp.rs:53:5 + --> $DIR/unit_cmp.rs:54:5 | LL | / debug_assert_ne!( LL | | { diff --git a/tests/ui/unit_return_expecting_ord.rs b/tests/ui/unit_return_expecting_ord.rs index bdb4710cc697..f2a9694f99e5 100644 --- a/tests/ui/unit_return_expecting_ord.rs +++ b/tests/ui/unit_return_expecting_ord.rs @@ -1,6 +1,7 @@ #![warn(clippy::unit_return_expecting_ord)] #![allow(clippy::needless_return)] #![allow(clippy::unused_unit)] +#![allow(clippy::useless_vec)] #![feature(is_sorted)] struct Struct { diff --git a/tests/ui/unit_return_expecting_ord.stderr b/tests/ui/unit_return_expecting_ord.stderr index 1d9564ce225e..3a295af55eac 100644 --- a/tests/ui/unit_return_expecting_ord.stderr +++ b/tests/ui/unit_return_expecting_ord.stderr @@ -1,36 +1,36 @@ error: this closure returns the unit type which also implements Ord - --> $DIR/unit_return_expecting_ord.rs:18:25 + --> $DIR/unit_return_expecting_ord.rs:19:25 | LL | structs.sort_by_key(|s| { | ^^^ | help: probably caused by this trailing semicolon - --> $DIR/unit_return_expecting_ord.rs:19:24 + --> $DIR/unit_return_expecting_ord.rs:20:24 | LL | double(s.field); | ^ = note: `-D clippy::unit-return-expecting-ord` implied by `-D warnings` error: this closure returns the unit type which also implements PartialOrd - --> $DIR/unit_return_expecting_ord.rs:22:30 + --> $DIR/unit_return_expecting_ord.rs:23:30 | LL | structs.is_sorted_by_key(|s| { | ^^^ | help: probably caused by this trailing semicolon - --> $DIR/unit_return_expecting_ord.rs:23:24 + --> $DIR/unit_return_expecting_ord.rs:24:24 | LL | double(s.field); | ^ error: this closure returns the unit type which also implements PartialOrd - --> $DIR/unit_return_expecting_ord.rs:25:30 + --> $DIR/unit_return_expecting_ord.rs:26:30 | LL | structs.is_sorted_by_key(|s| { | ^^^ error: this closure returns the unit type which also implements Ord - --> $DIR/unit_return_expecting_ord.rs:35:25 + --> $DIR/unit_return_expecting_ord.rs:36:25 | LL | structs.sort_by_key(|s| unit(s.field)); | ^^^ diff --git a/tests/ui/unnecessary_cast.fixed b/tests/ui/unnecessary_cast.fixed index bcc231ea7bce..8efd44baf59f 100644 --- a/tests/ui/unnecessary_cast.fixed +++ b/tests/ui/unnecessary_cast.fixed @@ -1,13 +1,43 @@ //@run-rustfix +//@aux-build:extern_fake_libc.rs #![warn(clippy::unnecessary_cast)] #![allow( - unused_must_use, clippy::borrow_as_ptr, clippy::no_effect, clippy::nonstandard_macro_braces, - clippy::unnecessary_operation + clippy::unnecessary_operation, + nonstandard_style, + unused )] +extern crate extern_fake_libc; + +type PtrConstU8 = *const u8; +type PtrMutU8 = *mut u8; + +fn owo(ptr: *const T) -> *const T { + ptr +} + +fn uwu(ptr: *const T) -> *const U { + ptr as *const U +} + +mod fake_libc { + type pid_t = i32; + pub unsafe fn getpid() -> pid_t { + pid_t::from(0) + } + // Make sure a where clause does not break it + pub fn getpid_SAFE_TRUTH(t: &T) -> pid_t + where + T: Clone, + { + t; + unsafe { getpid() } + } +} + #[rustfmt::skip] fn main() { // Test cast_unnecessary @@ -22,6 +52,26 @@ fn main() { 1_i32; 1_f32; + let _: *mut u8 = [1u8, 2].as_ptr() as *mut u8; + + [1u8, 2].as_ptr(); + [1u8, 2].as_ptr() as *mut u8; + [1u8, 2].as_mut_ptr(); + [1u8, 2].as_mut_ptr() as *const u8; + [1u8, 2].as_ptr() as PtrConstU8; + [1u8, 2].as_ptr() as PtrMutU8; + [1u8, 2].as_mut_ptr() as PtrMutU8; + [1u8, 2].as_mut_ptr() as PtrConstU8; + let _: *const u8 = [1u8, 2].as_ptr() as _; + let _: *mut u8 = [1u8, 2].as_mut_ptr() as _; + let _: *const u8 = [1u8, 2].as_ptr() as *const _; + let _: *mut u8 = [1u8, 2].as_mut_ptr() as *mut _; + + owo::([1u32].as_ptr()); + uwu::([1u32].as_ptr()); + // this will not lint in the function body even though they have the same type, instead here + uwu::([1u32].as_ptr()); + // macro version macro_rules! foo { ($a:ident, $b:ident) => { @@ -35,12 +85,37 @@ fn main() { foo!(b, f32); foo!(c, f64); + // do not lint cast from cfg-dependant type + let x = 0 as std::ffi::c_ulong; + let y = x as u64; + let x: std::ffi::c_ulong = 0; + let y = x as u64; + // do not lint cast to cfg-dependant type - 1 as std::os::raw::c_char; + let x = 1 as std::os::raw::c_char; + let y = x as u64; // do not lint cast to alias type 1 as I32Alias; &1 as &I32Alias; + // or from + let x: I32Alias = 1; + let y = x as u64; + fake_libc::getpid_SAFE_TRUTH(&0u32) as i32; + extern_fake_libc::getpid_SAFE_TRUTH() as i32; + let pid = unsafe { fake_libc::getpid() }; + pid as i32; + + let i8_ptr: *const i8 = &1; + let u8_ptr: *const u8 = &1; + + // cfg dependant pointees + i8_ptr as *const std::os::raw::c_char; + u8_ptr as *const std::os::raw::c_char; + + // type aliased pointees + i8_ptr as *const std::ffi::c_char; + u8_ptr as *const std::ffi::c_char; // issue #9960 macro_rules! bind_var { diff --git a/tests/ui/unnecessary_cast.rs b/tests/ui/unnecessary_cast.rs index 282b2f1283ee..c7723ef51f99 100644 --- a/tests/ui/unnecessary_cast.rs +++ b/tests/ui/unnecessary_cast.rs @@ -1,13 +1,43 @@ //@run-rustfix +//@aux-build:extern_fake_libc.rs #![warn(clippy::unnecessary_cast)] #![allow( - unused_must_use, clippy::borrow_as_ptr, clippy::no_effect, clippy::nonstandard_macro_braces, - clippy::unnecessary_operation + clippy::unnecessary_operation, + nonstandard_style, + unused )] +extern crate extern_fake_libc; + +type PtrConstU8 = *const u8; +type PtrMutU8 = *mut u8; + +fn owo(ptr: *const T) -> *const T { + ptr as *const T +} + +fn uwu(ptr: *const T) -> *const U { + ptr as *const U +} + +mod fake_libc { + type pid_t = i32; + pub unsafe fn getpid() -> pid_t { + pid_t::from(0) + } + // Make sure a where clause does not break it + pub fn getpid_SAFE_TRUTH(t: &T) -> pid_t + where + T: Clone, + { + t; + unsafe { getpid() } + } +} + #[rustfmt::skip] fn main() { // Test cast_unnecessary @@ -22,6 +52,26 @@ fn main() { 1_i32 as i32; 1_f32 as f32; + let _: *mut u8 = [1u8, 2].as_ptr() as *const u8 as *mut u8; + + [1u8, 2].as_ptr() as *const u8; + [1u8, 2].as_ptr() as *mut u8; + [1u8, 2].as_mut_ptr() as *mut u8; + [1u8, 2].as_mut_ptr() as *const u8; + [1u8, 2].as_ptr() as PtrConstU8; + [1u8, 2].as_ptr() as PtrMutU8; + [1u8, 2].as_mut_ptr() as PtrMutU8; + [1u8, 2].as_mut_ptr() as PtrConstU8; + let _: *const u8 = [1u8, 2].as_ptr() as _; + let _: *mut u8 = [1u8, 2].as_mut_ptr() as _; + let _: *const u8 = [1u8, 2].as_ptr() as *const _; + let _: *mut u8 = [1u8, 2].as_mut_ptr() as *mut _; + + owo::([1u32].as_ptr()) as *const u32; + uwu::([1u32].as_ptr()) as *const u8; + // this will not lint in the function body even though they have the same type, instead here + uwu::([1u32].as_ptr()) as *const u32; + // macro version macro_rules! foo { ($a:ident, $b:ident) => { @@ -35,12 +85,37 @@ fn main() { foo!(b, f32); foo!(c, f64); + // do not lint cast from cfg-dependant type + let x = 0 as std::ffi::c_ulong; + let y = x as u64; + let x: std::ffi::c_ulong = 0; + let y = x as u64; + // do not lint cast to cfg-dependant type - 1 as std::os::raw::c_char; + let x = 1 as std::os::raw::c_char; + let y = x as u64; // do not lint cast to alias type 1 as I32Alias; &1 as &I32Alias; + // or from + let x: I32Alias = 1; + let y = x as u64; + fake_libc::getpid_SAFE_TRUTH(&0u32) as i32; + extern_fake_libc::getpid_SAFE_TRUTH() as i32; + let pid = unsafe { fake_libc::getpid() }; + pid as i32; + + let i8_ptr: *const i8 = &1; + let u8_ptr: *const u8 = &1; + + // cfg dependant pointees + i8_ptr as *const std::os::raw::c_char; + u8_ptr as *const std::os::raw::c_char; + + // type aliased pointees + i8_ptr as *const std::ffi::c_char; + u8_ptr as *const std::ffi::c_char; // issue #9960 macro_rules! bind_var { diff --git a/tests/ui/unnecessary_cast.stderr b/tests/ui/unnecessary_cast.stderr index fcee4ee2a65c..f0443556fb4d 100644 --- a/tests/ui/unnecessary_cast.stderr +++ b/tests/ui/unnecessary_cast.stderr @@ -1,190 +1,232 @@ -error: casting integer literal to `i32` is unnecessary - --> $DIR/unnecessary_cast.rs:14:5 +error: casting raw pointers to the same type and constness is unnecessary (`*const T` -> `*const T`) + --> $DIR/unnecessary_cast.rs:19:5 | -LL | 1i32 as i32; - | ^^^^^^^^^^^ help: try: `1_i32` +LL | ptr as *const T + | ^^^^^^^^^^^^^^^ help: try: `ptr` | = note: `-D clippy::unnecessary-cast` implied by `-D warnings` +error: casting integer literal to `i32` is unnecessary + --> $DIR/unnecessary_cast.rs:44:5 + | +LL | 1i32 as i32; + | ^^^^^^^^^^^ help: try: `1_i32` + error: casting float literal to `f32` is unnecessary - --> $DIR/unnecessary_cast.rs:15:5 + --> $DIR/unnecessary_cast.rs:45:5 | LL | 1f32 as f32; | ^^^^^^^^^^^ help: try: `1_f32` error: casting to the same type is unnecessary (`bool` -> `bool`) - --> $DIR/unnecessary_cast.rs:16:5 + --> $DIR/unnecessary_cast.rs:46:5 | LL | false as bool; | ^^^^^^^^^^^^^ help: try: `false` error: casting integer literal to `i32` is unnecessary - --> $DIR/unnecessary_cast.rs:19:5 + --> $DIR/unnecessary_cast.rs:49:5 | LL | -1_i32 as i32; | ^^^^^^^^^^^^^ help: try: `-1_i32` error: casting integer literal to `i32` is unnecessary - --> $DIR/unnecessary_cast.rs:20:5 + --> $DIR/unnecessary_cast.rs:50:5 | LL | - 1_i32 as i32; | ^^^^^^^^^^^^^^ help: try: `- 1_i32` error: casting float literal to `f32` is unnecessary - --> $DIR/unnecessary_cast.rs:21:5 + --> $DIR/unnecessary_cast.rs:51:5 | LL | -1f32 as f32; | ^^^^^^^^^^^^ help: try: `-1_f32` error: casting integer literal to `i32` is unnecessary - --> $DIR/unnecessary_cast.rs:22:5 + --> $DIR/unnecessary_cast.rs:52:5 | LL | 1_i32 as i32; | ^^^^^^^^^^^^ help: try: `1_i32` error: casting float literal to `f32` is unnecessary - --> $DIR/unnecessary_cast.rs:23:5 + --> $DIR/unnecessary_cast.rs:53:5 | LL | 1_f32 as f32; | ^^^^^^^^^^^^ help: try: `1_f32` +error: casting raw pointers to the same type and constness is unnecessary (`*const u8` -> `*const u8`) + --> $DIR/unnecessary_cast.rs:55:22 + | +LL | let _: *mut u8 = [1u8, 2].as_ptr() as *const u8 as *mut u8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[1u8, 2].as_ptr()` + +error: casting raw pointers to the same type and constness is unnecessary (`*const u8` -> `*const u8`) + --> $DIR/unnecessary_cast.rs:57:5 + | +LL | [1u8, 2].as_ptr() as *const u8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[1u8, 2].as_ptr()` + +error: casting raw pointers to the same type and constness is unnecessary (`*mut u8` -> `*mut u8`) + --> $DIR/unnecessary_cast.rs:59:5 + | +LL | [1u8, 2].as_mut_ptr() as *mut u8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[1u8, 2].as_mut_ptr()` + +error: casting raw pointers to the same type and constness is unnecessary (`*const u32` -> `*const u32`) + --> $DIR/unnecessary_cast.rs:70:5 + | +LL | owo::([1u32].as_ptr()) as *const u32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `owo::([1u32].as_ptr())` + +error: casting raw pointers to the same type and constness is unnecessary (`*const u8` -> `*const u8`) + --> $DIR/unnecessary_cast.rs:71:5 + | +LL | uwu::([1u32].as_ptr()) as *const u8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `uwu::([1u32].as_ptr())` + +error: casting raw pointers to the same type and constness is unnecessary (`*const u32` -> `*const u32`) + --> $DIR/unnecessary_cast.rs:73:5 + | +LL | uwu::([1u32].as_ptr()) as *const u32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `uwu::([1u32].as_ptr())` + error: casting integer literal to `f32` is unnecessary - --> $DIR/unnecessary_cast.rs:64:9 + --> $DIR/unnecessary_cast.rs:139:9 | LL | 100 as f32; | ^^^^^^^^^^ help: try: `100_f32` error: casting integer literal to `f64` is unnecessary - --> $DIR/unnecessary_cast.rs:65:9 + --> $DIR/unnecessary_cast.rs:140:9 | LL | 100 as f64; | ^^^^^^^^^^ help: try: `100_f64` error: casting integer literal to `f64` is unnecessary - --> $DIR/unnecessary_cast.rs:66:9 + --> $DIR/unnecessary_cast.rs:141:9 | LL | 100_i32 as f64; | ^^^^^^^^^^^^^^ help: try: `100_f64` error: casting integer literal to `f32` is unnecessary - --> $DIR/unnecessary_cast.rs:67:17 + --> $DIR/unnecessary_cast.rs:142:17 | LL | let _ = -100 as f32; | ^^^^^^^^^^^ help: try: `-100_f32` error: casting integer literal to `f64` is unnecessary - --> $DIR/unnecessary_cast.rs:68:17 + --> $DIR/unnecessary_cast.rs:143:17 | LL | let _ = -100 as f64; | ^^^^^^^^^^^ help: try: `-100_f64` error: casting integer literal to `f64` is unnecessary - --> $DIR/unnecessary_cast.rs:69:17 + --> $DIR/unnecessary_cast.rs:144:17 | LL | let _ = -100_i32 as f64; | ^^^^^^^^^^^^^^^ help: try: `-100_f64` error: casting float literal to `f32` is unnecessary - --> $DIR/unnecessary_cast.rs:70:9 + --> $DIR/unnecessary_cast.rs:145:9 | LL | 100. as f32; | ^^^^^^^^^^^ help: try: `100_f32` error: casting float literal to `f64` is unnecessary - --> $DIR/unnecessary_cast.rs:71:9 + --> $DIR/unnecessary_cast.rs:146:9 | LL | 100. as f64; | ^^^^^^^^^^^ help: try: `100_f64` error: casting integer literal to `u32` is unnecessary - --> $DIR/unnecessary_cast.rs:83:9 + --> $DIR/unnecessary_cast.rs:158:9 | LL | 1 as u32; | ^^^^^^^^ help: try: `1_u32` error: casting integer literal to `i32` is unnecessary - --> $DIR/unnecessary_cast.rs:84:9 + --> $DIR/unnecessary_cast.rs:159:9 | LL | 0x10 as i32; | ^^^^^^^^^^^ help: try: `0x10_i32` error: casting integer literal to `usize` is unnecessary - --> $DIR/unnecessary_cast.rs:85:9 + --> $DIR/unnecessary_cast.rs:160:9 | LL | 0b10 as usize; | ^^^^^^^^^^^^^ help: try: `0b10_usize` error: casting integer literal to `u16` is unnecessary - --> $DIR/unnecessary_cast.rs:86:9 + --> $DIR/unnecessary_cast.rs:161:9 | LL | 0o73 as u16; | ^^^^^^^^^^^ help: try: `0o73_u16` error: casting integer literal to `u32` is unnecessary - --> $DIR/unnecessary_cast.rs:87:9 + --> $DIR/unnecessary_cast.rs:162:9 | LL | 1_000_000_000 as u32; | ^^^^^^^^^^^^^^^^^^^^ help: try: `1_000_000_000_u32` error: casting float literal to `f64` is unnecessary - --> $DIR/unnecessary_cast.rs:89:9 + --> $DIR/unnecessary_cast.rs:164:9 | LL | 1.0 as f64; | ^^^^^^^^^^ help: try: `1.0_f64` error: casting float literal to `f32` is unnecessary - --> $DIR/unnecessary_cast.rs:90:9 + --> $DIR/unnecessary_cast.rs:165:9 | LL | 0.5 as f32; | ^^^^^^^^^^ help: try: `0.5_f32` error: casting integer literal to `i32` is unnecessary - --> $DIR/unnecessary_cast.rs:94:17 + --> $DIR/unnecessary_cast.rs:169:17 | LL | let _ = -1 as i32; | ^^^^^^^^^ help: try: `-1_i32` error: casting float literal to `f32` is unnecessary - --> $DIR/unnecessary_cast.rs:95:17 + --> $DIR/unnecessary_cast.rs:170:17 | LL | let _ = -1.0 as f32; | ^^^^^^^^^^^ help: try: `-1.0_f32` error: casting to the same type is unnecessary (`i32` -> `i32`) - --> $DIR/unnecessary_cast.rs:101:18 + --> $DIR/unnecessary_cast.rs:176:18 | LL | let _ = &(x as i32); | ^^^^^^^^^^ help: try: `{ x }` error: casting integer literal to `i32` is unnecessary - --> $DIR/unnecessary_cast.rs:107:22 + --> $DIR/unnecessary_cast.rs:182:22 | LL | let _: i32 = -(1) as i32; | ^^^^^^^^^^^ help: try: `-1_i32` error: casting integer literal to `i64` is unnecessary - --> $DIR/unnecessary_cast.rs:109:22 + --> $DIR/unnecessary_cast.rs:184:22 | LL | let _: i64 = -(1) as i64; | ^^^^^^^^^^^ help: try: `-1_i64` error: casting float literal to `f64` is unnecessary - --> $DIR/unnecessary_cast.rs:116:22 + --> $DIR/unnecessary_cast.rs:191:22 | LL | let _: f64 = (-8.0 as f64).exp(); | ^^^^^^^^^^^^^ help: try: `(-8.0_f64)` error: casting float literal to `f64` is unnecessary - --> $DIR/unnecessary_cast.rs:118:23 + --> $DIR/unnecessary_cast.rs:193:23 | LL | let _: f64 = -(8.0 as f64).exp(); // should suggest `-8.0_f64.exp()` here not to change code behavior | ^^^^^^^^^^^^ help: try: `8.0_f64` error: casting to the same type is unnecessary (`f32` -> `f32`) - --> $DIR/unnecessary_cast.rs:126:20 + --> $DIR/unnecessary_cast.rs:201:20 | LL | let _num = foo() as f32; | ^^^^^^^^^^^^ help: try: `foo()` -error: aborting due to 31 previous errors +error: aborting due to 38 previous errors diff --git a/tests/ui/unnecessary_fold.fixed b/tests/ui/unnecessary_fold.fixed index 2bed14973caa..bd1d4a152aeb 100644 --- a/tests/ui/unnecessary_fold.fixed +++ b/tests/ui/unnecessary_fold.fixed @@ -49,4 +49,28 @@ fn unnecessary_fold_over_multiple_lines() { .any(|x| x > 2); } +fn issue10000() { + use std::collections::HashMap; + use std::hash::BuildHasher; + + fn anything(_: T) {} + fn num(_: i32) {} + fn smoketest_map(mut map: HashMap) { + map.insert(0, 0); + assert_eq!(map.values().sum::(), 0); + + // more cases: + let _ = map.values().sum::(); + let _ = map.values().product::(); + let _: i32 = map.values().sum(); + let _: i32 = map.values().product(); + anything(map.values().sum::()); + anything(map.values().product::()); + num(map.values().sum()); + num(map.values().product()); + } + + smoketest_map(HashMap::new()); +} + fn main() {} diff --git a/tests/ui/unnecessary_fold.rs b/tests/ui/unnecessary_fold.rs index a3cec8ea3d55..d27cc460c44a 100644 --- a/tests/ui/unnecessary_fold.rs +++ b/tests/ui/unnecessary_fold.rs @@ -49,4 +49,28 @@ fn unnecessary_fold_over_multiple_lines() { .fold(false, |acc, x| acc || x > 2); } +fn issue10000() { + use std::collections::HashMap; + use std::hash::BuildHasher; + + fn anything(_: T) {} + fn num(_: i32) {} + fn smoketest_map(mut map: HashMap) { + map.insert(0, 0); + assert_eq!(map.values().fold(0, |x, y| x + y), 0); + + // more cases: + let _ = map.values().fold(0, |x, y| x + y); + let _ = map.values().fold(1, |x, y| x * y); + let _: i32 = map.values().fold(0, |x, y| x + y); + let _: i32 = map.values().fold(1, |x, y| x * y); + anything(map.values().fold(0, |x, y| x + y)); + anything(map.values().fold(1, |x, y| x * y)); + num(map.values().fold(0, |x, y| x + y)); + num(map.values().fold(1, |x, y| x * y)); + } + + smoketest_map(HashMap::new()); +} + fn main() {} diff --git a/tests/ui/unnecessary_fold.stderr b/tests/ui/unnecessary_fold.stderr index 22c44588ab7a..98979f7477fb 100644 --- a/tests/ui/unnecessary_fold.stderr +++ b/tests/ui/unnecessary_fold.stderr @@ -36,5 +36,59 @@ error: this `.fold` can be written more succinctly using another method LL | .fold(false, |acc, x| acc || x > 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `any(|x| x > 2)` -error: aborting due to 6 previous errors +error: this `.fold` can be written more succinctly using another method + --> $DIR/unnecessary_fold.rs:60:33 + | +LL | assert_eq!(map.values().fold(0, |x, y| x + y), 0); + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `sum::()` + +error: this `.fold` can be written more succinctly using another method + --> $DIR/unnecessary_fold.rs:63:30 + | +LL | let _ = map.values().fold(0, |x, y| x + y); + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `sum::()` + +error: this `.fold` can be written more succinctly using another method + --> $DIR/unnecessary_fold.rs:64:30 + | +LL | let _ = map.values().fold(1, |x, y| x * y); + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `product::()` + +error: this `.fold` can be written more succinctly using another method + --> $DIR/unnecessary_fold.rs:65:35 + | +LL | let _: i32 = map.values().fold(0, |x, y| x + y); + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `sum()` + +error: this `.fold` can be written more succinctly using another method + --> $DIR/unnecessary_fold.rs:66:35 + | +LL | let _: i32 = map.values().fold(1, |x, y| x * y); + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `product()` + +error: this `.fold` can be written more succinctly using another method + --> $DIR/unnecessary_fold.rs:67:31 + | +LL | anything(map.values().fold(0, |x, y| x + y)); + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `sum::()` + +error: this `.fold` can be written more succinctly using another method + --> $DIR/unnecessary_fold.rs:68:31 + | +LL | anything(map.values().fold(1, |x, y| x * y)); + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `product::()` + +error: this `.fold` can be written more succinctly using another method + --> $DIR/unnecessary_fold.rs:69:26 + | +LL | num(map.values().fold(0, |x, y| x + y)); + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `sum()` + +error: this `.fold` can be written more succinctly using another method + --> $DIR/unnecessary_fold.rs:70:26 + | +LL | num(map.values().fold(1, |x, y| x * y)); + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `product()` + +error: aborting due to 15 previous errors diff --git a/tests/ui/unnecessary_join.fixed b/tests/ui/unnecessary_join.fixed index e102df625998..f13a5275e31b 100644 --- a/tests/ui/unnecessary_join.fixed +++ b/tests/ui/unnecessary_join.fixed @@ -1,6 +1,6 @@ //@run-rustfix #![warn(clippy::unnecessary_join)] -#![allow(clippy::uninlined_format_args)] +#![allow(clippy::uninlined_format_args, clippy::useless_vec)] fn main() { // should be linted diff --git a/tests/ui/unnecessary_join.rs b/tests/ui/unnecessary_join.rs index b87c15bc1263..6014d723a2f4 100644 --- a/tests/ui/unnecessary_join.rs +++ b/tests/ui/unnecessary_join.rs @@ -1,6 +1,6 @@ //@run-rustfix #![warn(clippy::unnecessary_join)] -#![allow(clippy::uninlined_format_args)] +#![allow(clippy::uninlined_format_args, clippy::useless_vec)] fn main() { // should be linted diff --git a/tests/ui/unnecessary_lazy_eval.fixed b/tests/ui/unnecessary_lazy_eval.fixed index c3728886ec9c..dca38034177b 100644 --- a/tests/ui/unnecessary_lazy_eval.fixed +++ b/tests/ui/unnecessary_lazy_eval.fixed @@ -1,9 +1,13 @@ //@run-rustfix -//@aux-build: proc_macros.rs +//@aux-build: proc_macros.rs:proc-macro #![warn(clippy::unnecessary_lazy_evaluations)] #![allow(clippy::redundant_closure)] #![allow(clippy::bind_instead_of_map)] #![allow(clippy::map_identity)] +#![allow(clippy::needless_borrow)] +#![allow(clippy::unnecessary_literal_unwrap)] + +use std::ops::Deref; extern crate proc_macros; use proc_macros::with_span; @@ -41,6 +45,15 @@ impl Drop for Issue9427FollowUp { } } +struct Issue10437; +impl Deref for Issue10437 { + type Target = u32; + fn deref(&self) -> &Self::Target { + println!("side effect deref"); + &0 + } +} + fn main() { let astronomers_pi = 10; let ext_arr: [usize; 1] = [2]; @@ -65,6 +78,15 @@ fn main() { let _ = nested_tuple_opt.unwrap_or(Some((1, 2))); let _ = cond.then_some(astronomers_pi); + // Should lint - Builtin deref + let r = &1; + let _ = Some(1).unwrap_or(*r); + let b = Box::new(1); + let _ = Some(1).unwrap_or(*b); + // Should lint - Builtin deref through autoderef + let _ = Some(1).as_ref().unwrap_or(&r); + let _ = Some(1).as_ref().unwrap_or(&b); + // Cases when unwrap is not called on a simple variable let _ = Some(10).unwrap_or(2); let _ = Some(10).and(ext_opt); @@ -93,6 +115,12 @@ fn main() { let _ = deep.0.or_else(|| some_call()); let _ = opt.ok_or_else(|| ext_arr[0]); + let _ = Some(1).unwrap_or_else(|| *Issue10437); // Issue10437 has a deref impl + let _ = Some(1).unwrap_or(*Issue10437); + + let _ = Some(1).as_ref().unwrap_or_else(|| &Issue10437); + let _ = Some(1).as_ref().unwrap_or(&Issue10437); + // Should not lint - bool let _ = (0 == 1).then(|| Issue9427(0)); // Issue9427 has a significant drop let _ = false.then(|| Issue9427FollowUp); // Issue9427FollowUp has a significant drop diff --git a/tests/ui/unnecessary_lazy_eval.rs b/tests/ui/unnecessary_lazy_eval.rs index 76e50fa5b030..7fda719edc1b 100644 --- a/tests/ui/unnecessary_lazy_eval.rs +++ b/tests/ui/unnecessary_lazy_eval.rs @@ -1,9 +1,13 @@ //@run-rustfix -//@aux-build: proc_macros.rs +//@aux-build: proc_macros.rs:proc-macro #![warn(clippy::unnecessary_lazy_evaluations)] #![allow(clippy::redundant_closure)] #![allow(clippy::bind_instead_of_map)] #![allow(clippy::map_identity)] +#![allow(clippy::needless_borrow)] +#![allow(clippy::unnecessary_literal_unwrap)] + +use std::ops::Deref; extern crate proc_macros; use proc_macros::with_span; @@ -41,6 +45,15 @@ impl Drop for Issue9427FollowUp { } } +struct Issue10437; +impl Deref for Issue10437 { + type Target = u32; + fn deref(&self) -> &Self::Target { + println!("side effect deref"); + &0 + } +} + fn main() { let astronomers_pi = 10; let ext_arr: [usize; 1] = [2]; @@ -65,6 +78,15 @@ fn main() { let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); let _ = cond.then(|| astronomers_pi); + // Should lint - Builtin deref + let r = &1; + let _ = Some(1).unwrap_or_else(|| *r); + let b = Box::new(1); + let _ = Some(1).unwrap_or_else(|| *b); + // Should lint - Builtin deref through autoderef + let _ = Some(1).as_ref().unwrap_or_else(|| &r); + let _ = Some(1).as_ref().unwrap_or_else(|| &b); + // Cases when unwrap is not called on a simple variable let _ = Some(10).unwrap_or_else(|| 2); let _ = Some(10).and_then(|_| ext_opt); @@ -93,6 +115,12 @@ fn main() { let _ = deep.0.or_else(|| some_call()); let _ = opt.ok_or_else(|| ext_arr[0]); + let _ = Some(1).unwrap_or_else(|| *Issue10437); // Issue10437 has a deref impl + let _ = Some(1).unwrap_or(*Issue10437); + + let _ = Some(1).as_ref().unwrap_or_else(|| &Issue10437); + let _ = Some(1).as_ref().unwrap_or(&Issue10437); + // Should not lint - bool let _ = (0 == 1).then(|| Issue9427(0)); // Issue9427 has a significant drop let _ = false.then(|| Issue9427FollowUp); // Issue9427FollowUp has a significant drop diff --git a/tests/ui/unnecessary_lazy_eval.stderr b/tests/ui/unnecessary_lazy_eval.stderr index 0339755442c5..458eed1f359a 100644 --- a/tests/ui/unnecessary_lazy_eval.stderr +++ b/tests/ui/unnecessary_lazy_eval.stderr @@ -1,5 +1,5 @@ error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:56:13 + --> $DIR/unnecessary_lazy_eval.rs:69:13 | LL | let _ = opt.unwrap_or_else(|| 2); | ^^^^-------------------- @@ -9,7 +9,7 @@ LL | let _ = opt.unwrap_or_else(|| 2); = note: `-D clippy::unnecessary-lazy-evaluations` implied by `-D warnings` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:57:13 + --> $DIR/unnecessary_lazy_eval.rs:70:13 | LL | let _ = opt.unwrap_or_else(|| astronomers_pi); | ^^^^--------------------------------- @@ -17,7 +17,7 @@ LL | let _ = opt.unwrap_or_else(|| astronomers_pi); | help: use `unwrap_or(..)` instead: `unwrap_or(astronomers_pi)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:58:13 + --> $DIR/unnecessary_lazy_eval.rs:71:13 | LL | let _ = opt.unwrap_or_else(|| ext_str.some_field); | ^^^^------------------------------------- @@ -25,7 +25,7 @@ LL | let _ = opt.unwrap_or_else(|| ext_str.some_field); | help: use `unwrap_or(..)` instead: `unwrap_or(ext_str.some_field)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:60:13 + --> $DIR/unnecessary_lazy_eval.rs:73:13 | LL | let _ = opt.and_then(|_| ext_opt); | ^^^^--------------------- @@ -33,7 +33,7 @@ LL | let _ = opt.and_then(|_| ext_opt); | help: use `and(..)` instead: `and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:61:13 + --> $DIR/unnecessary_lazy_eval.rs:74:13 | LL | let _ = opt.or_else(|| ext_opt); | ^^^^------------------- @@ -41,7 +41,7 @@ LL | let _ = opt.or_else(|| ext_opt); | help: use `or(..)` instead: `or(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:62:13 + --> $DIR/unnecessary_lazy_eval.rs:75:13 | LL | let _ = opt.or_else(|| None); | ^^^^---------------- @@ -49,7 +49,7 @@ LL | let _ = opt.or_else(|| None); | help: use `or(..)` instead: `or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:63:13 + --> $DIR/unnecessary_lazy_eval.rs:76:13 | LL | let _ = opt.get_or_insert_with(|| 2); | ^^^^------------------------ @@ -57,7 +57,7 @@ LL | let _ = opt.get_or_insert_with(|| 2); | help: use `get_or_insert(..)` instead: `get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:64:13 + --> $DIR/unnecessary_lazy_eval.rs:77:13 | LL | let _ = opt.ok_or_else(|| 2); | ^^^^---------------- @@ -65,7 +65,7 @@ LL | let _ = opt.ok_or_else(|| 2); | help: use `ok_or(..)` instead: `ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:65:13 + --> $DIR/unnecessary_lazy_eval.rs:78:13 | LL | let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); | ^^^^^^^^^^^^^^^^^------------------------------- @@ -73,7 +73,7 @@ LL | let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); | help: use `unwrap_or(..)` instead: `unwrap_or(Some((1, 2)))` error: unnecessary closure used with `bool::then` - --> $DIR/unnecessary_lazy_eval.rs:66:13 + --> $DIR/unnecessary_lazy_eval.rs:79:13 | LL | let _ = cond.then(|| astronomers_pi); | ^^^^^----------------------- @@ -81,7 +81,39 @@ LL | let _ = cond.then(|| astronomers_pi); | help: use `then_some(..)` instead: `then_some(astronomers_pi)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:69:13 + --> $DIR/unnecessary_lazy_eval.rs:83:13 + | +LL | let _ = Some(1).unwrap_or_else(|| *r); + | ^^^^^^^^--------------------- + | | + | help: use `unwrap_or(..)` instead: `unwrap_or(*r)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:85:13 + | +LL | let _ = Some(1).unwrap_or_else(|| *b); + | ^^^^^^^^--------------------- + | | + | help: use `unwrap_or(..)` instead: `unwrap_or(*b)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:87:13 + | +LL | let _ = Some(1).as_ref().unwrap_or_else(|| &r); + | ^^^^^^^^^^^^^^^^^--------------------- + | | + | help: use `unwrap_or(..)` instead: `unwrap_or(&r)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:88:13 + | +LL | let _ = Some(1).as_ref().unwrap_or_else(|| &b); + | ^^^^^^^^^^^^^^^^^--------------------- + | | + | help: use `unwrap_or(..)` instead: `unwrap_or(&b)` + +error: unnecessary closure used to substitute value for `Option::None` + --> $DIR/unnecessary_lazy_eval.rs:91:13 | LL | let _ = Some(10).unwrap_or_else(|| 2); | ^^^^^^^^^-------------------- @@ -89,7 +121,7 @@ LL | let _ = Some(10).unwrap_or_else(|| 2); | help: use `unwrap_or(..)` instead: `unwrap_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:70:13 + --> $DIR/unnecessary_lazy_eval.rs:92:13 | LL | let _ = Some(10).and_then(|_| ext_opt); | ^^^^^^^^^--------------------- @@ -97,7 +129,7 @@ LL | let _ = Some(10).and_then(|_| ext_opt); | help: use `and(..)` instead: `and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:71:28 + --> $DIR/unnecessary_lazy_eval.rs:93:28 | LL | let _: Option = None.or_else(|| ext_opt); | ^^^^^------------------- @@ -105,7 +137,7 @@ LL | let _: Option = None.or_else(|| ext_opt); | help: use `or(..)` instead: `or(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:72:13 + --> $DIR/unnecessary_lazy_eval.rs:94:13 | LL | let _ = None.get_or_insert_with(|| 2); | ^^^^^------------------------ @@ -113,7 +145,7 @@ LL | let _ = None.get_or_insert_with(|| 2); | help: use `get_or_insert(..)` instead: `get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:73:35 + --> $DIR/unnecessary_lazy_eval.rs:95:35 | LL | let _: Result = None.ok_or_else(|| 2); | ^^^^^---------------- @@ -121,7 +153,7 @@ LL | let _: Result = None.ok_or_else(|| 2); | help: use `ok_or(..)` instead: `ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:74:28 + --> $DIR/unnecessary_lazy_eval.rs:96:28 | LL | let _: Option = None.or_else(|| None); | ^^^^^---------------- @@ -129,7 +161,7 @@ LL | let _: Option = None.or_else(|| None); | help: use `or(..)` instead: `or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:77:13 + --> $DIR/unnecessary_lazy_eval.rs:99:13 | LL | let _ = deep.0.unwrap_or_else(|| 2); | ^^^^^^^-------------------- @@ -137,7 +169,7 @@ LL | let _ = deep.0.unwrap_or_else(|| 2); | help: use `unwrap_or(..)` instead: `unwrap_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:78:13 + --> $DIR/unnecessary_lazy_eval.rs:100:13 | LL | let _ = deep.0.and_then(|_| ext_opt); | ^^^^^^^--------------------- @@ -145,7 +177,7 @@ LL | let _ = deep.0.and_then(|_| ext_opt); | help: use `and(..)` instead: `and(ext_opt)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:79:13 + --> $DIR/unnecessary_lazy_eval.rs:101:13 | LL | let _ = deep.0.or_else(|| None); | ^^^^^^^---------------- @@ -153,7 +185,7 @@ LL | let _ = deep.0.or_else(|| None); | help: use `or(..)` instead: `or(None)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:80:13 + --> $DIR/unnecessary_lazy_eval.rs:102:13 | LL | let _ = deep.0.get_or_insert_with(|| 2); | ^^^^^^^------------------------ @@ -161,7 +193,7 @@ LL | let _ = deep.0.get_or_insert_with(|| 2); | help: use `get_or_insert(..)` instead: `get_or_insert(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:81:13 + --> $DIR/unnecessary_lazy_eval.rs:103:13 | LL | let _ = deep.0.ok_or_else(|| 2); | ^^^^^^^---------------- @@ -169,7 +201,7 @@ LL | let _ = deep.0.ok_or_else(|| 2); | help: use `ok_or(..)` instead: `ok_or(2)` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:105:28 + --> $DIR/unnecessary_lazy_eval.rs:133:28 | LL | let _: Option = None.or_else(|| Some(3)); | ^^^^^------------------- @@ -177,7 +209,7 @@ LL | let _: Option = None.or_else(|| Some(3)); | help: use `or(..)` instead: `or(Some(3))` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:106:13 + --> $DIR/unnecessary_lazy_eval.rs:134:13 | LL | let _ = deep.0.or_else(|| Some(3)); | ^^^^^^^------------------- @@ -185,7 +217,7 @@ LL | let _ = deep.0.or_else(|| Some(3)); | help: use `or(..)` instead: `or(Some(3))` error: unnecessary closure used to substitute value for `Option::None` - --> $DIR/unnecessary_lazy_eval.rs:107:13 + --> $DIR/unnecessary_lazy_eval.rs:135:13 | LL | let _ = opt.or_else(|| Some(3)); | ^^^^------------------- @@ -193,7 +225,7 @@ LL | let _ = opt.or_else(|| Some(3)); | help: use `or(..)` instead: `or(Some(3))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:113:13 + --> $DIR/unnecessary_lazy_eval.rs:141:13 | LL | let _ = res2.unwrap_or_else(|_| 2); | ^^^^^--------------------- @@ -201,7 +233,7 @@ LL | let _ = res2.unwrap_or_else(|_| 2); | help: use `unwrap_or(..)` instead: `unwrap_or(2)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:114:13 + --> $DIR/unnecessary_lazy_eval.rs:142:13 | LL | let _ = res2.unwrap_or_else(|_| astronomers_pi); | ^^^^^---------------------------------- @@ -209,7 +241,7 @@ LL | let _ = res2.unwrap_or_else(|_| astronomers_pi); | help: use `unwrap_or(..)` instead: `unwrap_or(astronomers_pi)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:115:13 + --> $DIR/unnecessary_lazy_eval.rs:143:13 | LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field); | ^^^^^-------------------------------------- @@ -217,7 +249,7 @@ LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field); | help: use `unwrap_or(..)` instead: `unwrap_or(ext_str.some_field)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:137:35 + --> $DIR/unnecessary_lazy_eval.rs:165:35 | LL | let _: Result = res.and_then(|_| Err(2)); | ^^^^-------------------- @@ -225,7 +257,7 @@ LL | let _: Result = res.and_then(|_| Err(2)); | help: use `and(..)` instead: `and(Err(2))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:138:35 + --> $DIR/unnecessary_lazy_eval.rs:166:35 | LL | let _: Result = res.and_then(|_| Err(astronomers_pi)); | ^^^^--------------------------------- @@ -233,7 +265,7 @@ LL | let _: Result = res.and_then(|_| Err(astronomers_pi)); | help: use `and(..)` instead: `and(Err(astronomers_pi))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:139:35 + --> $DIR/unnecessary_lazy_eval.rs:167:35 | LL | let _: Result = res.and_then(|_| Err(ext_str.some_field)); | ^^^^------------------------------------- @@ -241,7 +273,7 @@ LL | let _: Result = res.and_then(|_| Err(ext_str.some_field)) | help: use `and(..)` instead: `and(Err(ext_str.some_field))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:141:35 + --> $DIR/unnecessary_lazy_eval.rs:169:35 | LL | let _: Result = res.or_else(|_| Ok(2)); | ^^^^------------------ @@ -249,7 +281,7 @@ LL | let _: Result = res.or_else(|_| Ok(2)); | help: use `or(..)` instead: `or(Ok(2))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:142:35 + --> $DIR/unnecessary_lazy_eval.rs:170:35 | LL | let _: Result = res.or_else(|_| Ok(astronomers_pi)); | ^^^^------------------------------- @@ -257,7 +289,7 @@ LL | let _: Result = res.or_else(|_| Ok(astronomers_pi)); | help: use `or(..)` instead: `or(Ok(astronomers_pi))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:143:35 + --> $DIR/unnecessary_lazy_eval.rs:171:35 | LL | let _: Result = res.or_else(|_| Ok(ext_str.some_field)); | ^^^^----------------------------------- @@ -265,7 +297,7 @@ LL | let _: Result = res.or_else(|_| Ok(ext_str.some_field)); | help: use `or(..)` instead: `or(Ok(ext_str.some_field))` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval.rs:144:35 + --> $DIR/unnecessary_lazy_eval.rs:172:35 | LL | let _: Result = res. | ___________________________________^ @@ -279,5 +311,5 @@ LL | | or_else(|_| Ok(ext_str.some_field)); | | | help: use `or(..)` instead: `or(Ok(ext_str.some_field))` -error: aborting due to 34 previous errors +error: aborting due to 38 previous errors diff --git a/tests/ui/unnecessary_lazy_eval_unfixable.rs b/tests/ui/unnecessary_lazy_eval_unfixable.rs index b05dd143bfd7..b4a1f81679ad 100644 --- a/tests/ui/unnecessary_lazy_eval_unfixable.rs +++ b/tests/ui/unnecessary_lazy_eval_unfixable.rs @@ -1,4 +1,5 @@ #![warn(clippy::unnecessary_lazy_evaluations)] +#![allow(clippy::unnecessary_literal_unwrap)] struct Deep(Option); diff --git a/tests/ui/unnecessary_lazy_eval_unfixable.stderr b/tests/ui/unnecessary_lazy_eval_unfixable.stderr index 20acab6e844f..7f353ba06982 100644 --- a/tests/ui/unnecessary_lazy_eval_unfixable.stderr +++ b/tests/ui/unnecessary_lazy_eval_unfixable.stderr @@ -1,5 +1,5 @@ error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval_unfixable.rs:12:13 + --> $DIR/unnecessary_lazy_eval_unfixable.rs:13:13 | LL | let _ = Ok(1).unwrap_or_else(|()| 2); | ^^^^^^---------------------- @@ -9,7 +9,7 @@ LL | let _ = Ok(1).unwrap_or_else(|()| 2); = note: `-D clippy::unnecessary-lazy-evaluations` implied by `-D warnings` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval_unfixable.rs:16:13 + --> $DIR/unnecessary_lazy_eval_unfixable.rs:17:13 | LL | let _ = Ok(1).unwrap_or_else(|e::E| 2); | ^^^^^^------------------------ @@ -17,7 +17,7 @@ LL | let _ = Ok(1).unwrap_or_else(|e::E| 2); | help: use `unwrap_or(..)` instead: `unwrap_or(2)` error: unnecessary closure used to substitute value for `Result::Err` - --> $DIR/unnecessary_lazy_eval_unfixable.rs:17:13 + --> $DIR/unnecessary_lazy_eval_unfixable.rs:18:13 | LL | let _ = Ok(1).unwrap_or_else(|SomeStruct { .. }| 2); | ^^^^^^------------------------------------- diff --git a/tests/ui/unnecessary_literal_unwrap.fixed b/tests/ui/unnecessary_literal_unwrap.fixed new file mode 100644 index 000000000000..630a1bea3c87 --- /dev/null +++ b/tests/ui/unnecessary_literal_unwrap.fixed @@ -0,0 +1,78 @@ +//@run-rustfix +#![warn(clippy::unnecessary_literal_unwrap)] +#![allow(unreachable_code)] +#![allow( + clippy::unnecessary_lazy_evaluations, + clippy::diverging_sub_expression, + clippy::let_unit_value, + clippy::no_effect +)] + +fn unwrap_option_some() { + let _val = 1; + let _val = 1; + + 1; + 1; +} + +fn unwrap_option_none() { + let _val = panic!(); + let _val = panic!("this always happens"); + + panic!(); + panic!("this always happens"); +} + +fn unwrap_result_ok() { + let _val = 1; + let _val = 1; + let _val = panic!("{:?}", 1); + let _val = panic!("{1}: {:?}", 1, "this always happens"); + + 1; + 1; + panic!("{:?}", 1); + panic!("{1}: {:?}", 1, "this always happens"); +} + +fn unwrap_result_err() { + let _val = 1; + let _val = 1; + let _val = panic!("{:?}", 1); + let _val = panic!("{1}: {:?}", 1, "this always happens"); + + 1; + 1; + panic!("{:?}", 1); + panic!("{1}: {:?}", 1, "this always happens"); +} + +fn unwrap_methods_option() { + let _val = 1; + let _val = 1; + let _val = 1; + + 1; + 1; + 1; +} + +fn unwrap_methods_result() { + let _val = 1; + let _val = 1; + let _val = 1; + + 1; + 1; + 1; +} + +fn main() { + unwrap_option_some(); + unwrap_option_none(); + unwrap_result_ok(); + unwrap_result_err(); + unwrap_methods_option(); + unwrap_methods_result(); +} diff --git a/tests/ui/unnecessary_literal_unwrap.rs b/tests/ui/unnecessary_literal_unwrap.rs new file mode 100644 index 000000000000..14f92cb370f6 --- /dev/null +++ b/tests/ui/unnecessary_literal_unwrap.rs @@ -0,0 +1,78 @@ +//@run-rustfix +#![warn(clippy::unnecessary_literal_unwrap)] +#![allow(unreachable_code)] +#![allow( + clippy::unnecessary_lazy_evaluations, + clippy::diverging_sub_expression, + clippy::let_unit_value, + clippy::no_effect +)] + +fn unwrap_option_some() { + let _val = Some(1).unwrap(); + let _val = Some(1).expect("this never happens"); + + Some(1).unwrap(); + Some(1).expect("this never happens"); +} + +fn unwrap_option_none() { + let _val = None::<()>.unwrap(); + let _val = None::<()>.expect("this always happens"); + + None::<()>.unwrap(); + None::<()>.expect("this always happens"); +} + +fn unwrap_result_ok() { + let _val = Ok::<_, ()>(1).unwrap(); + let _val = Ok::<_, ()>(1).expect("this never happens"); + let _val = Ok::<_, ()>(1).unwrap_err(); + let _val = Ok::<_, ()>(1).expect_err("this always happens"); + + Ok::<_, ()>(1).unwrap(); + Ok::<_, ()>(1).expect("this never happens"); + Ok::<_, ()>(1).unwrap_err(); + Ok::<_, ()>(1).expect_err("this always happens"); +} + +fn unwrap_result_err() { + let _val = Err::<(), _>(1).unwrap_err(); + let _val = Err::<(), _>(1).expect_err("this never happens"); + let _val = Err::<(), _>(1).unwrap(); + let _val = Err::<(), _>(1).expect("this always happens"); + + Err::<(), _>(1).unwrap_err(); + Err::<(), _>(1).expect_err("this never happens"); + Err::<(), _>(1).unwrap(); + Err::<(), _>(1).expect("this always happens"); +} + +fn unwrap_methods_option() { + let _val = Some(1).unwrap_or(2); + let _val = Some(1).unwrap_or_default(); + let _val = Some(1).unwrap_or_else(|| 2); + + Some(1).unwrap_or(2); + Some(1).unwrap_or_default(); + Some(1).unwrap_or_else(|| 2); +} + +fn unwrap_methods_result() { + let _val = Ok::<_, ()>(1).unwrap_or(2); + let _val = Ok::<_, ()>(1).unwrap_or_default(); + let _val = Ok::<_, ()>(1).unwrap_or_else(|_| 2); + + Ok::<_, ()>(1).unwrap_or(2); + Ok::<_, ()>(1).unwrap_or_default(); + Ok::<_, ()>(1).unwrap_or_else(|_| 2); +} + +fn main() { + unwrap_option_some(); + unwrap_option_none(); + unwrap_result_ok(); + unwrap_result_err(); + unwrap_methods_option(); + unwrap_methods_result(); +} diff --git a/tests/ui/unnecessary_literal_unwrap.stderr b/tests/ui/unnecessary_literal_unwrap.stderr new file mode 100644 index 000000000000..0c71ee053231 --- /dev/null +++ b/tests/ui/unnecessary_literal_unwrap.stderr @@ -0,0 +1,413 @@ +error: used `unwrap()` on `Some` value + --> $DIR/unnecessary_literal_unwrap.rs:12:16 + | +LL | let _val = Some(1).unwrap(); + | ^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::unnecessary-literal-unwrap` implied by `-D warnings` +help: remove the `Some` and `unwrap()` + | +LL - let _val = Some(1).unwrap(); +LL + let _val = 1; + | + +error: used `expect()` on `Some` value + --> $DIR/unnecessary_literal_unwrap.rs:13:16 + | +LL | let _val = Some(1).expect("this never happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `expect()` + | +LL - let _val = Some(1).expect("this never happens"); +LL + let _val = 1; + | + +error: used `unwrap()` on `Some` value + --> $DIR/unnecessary_literal_unwrap.rs:15:5 + | +LL | Some(1).unwrap(); + | ^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap()` + | +LL - Some(1).unwrap(); +LL + 1; + | + +error: used `expect()` on `Some` value + --> $DIR/unnecessary_literal_unwrap.rs:16:5 + | +LL | Some(1).expect("this never happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `expect()` + | +LL - Some(1).expect("this never happens"); +LL + 1; + | + +error: used `unwrap()` on `None` value + --> $DIR/unnecessary_literal_unwrap.rs:20:16 + | +LL | let _val = None::<()>.unwrap(); + | ^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap()`: `panic!()` + +error: used `expect()` on `None` value + --> $DIR/unnecessary_literal_unwrap.rs:21:16 + | +LL | let _val = None::<()>.expect("this always happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `None` and `expect()` + | +LL | let _val = panic!("this always happens"); + | ~~~~~~~ ~ + +error: used `unwrap()` on `None` value + --> $DIR/unnecessary_literal_unwrap.rs:23:5 + | +LL | None::<()>.unwrap(); + | ^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap()`: `panic!()` + +error: used `expect()` on `None` value + --> $DIR/unnecessary_literal_unwrap.rs:24:5 + | +LL | None::<()>.expect("this always happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `None` and `expect()` + | +LL | panic!("this always happens"); + | ~~~~~~~ ~ + +error: used `unwrap()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap.rs:28:16 + | +LL | let _val = Ok::<_, ()>(1).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap()` + | +LL - let _val = Ok::<_, ()>(1).unwrap(); +LL + let _val = 1; + | + +error: used `expect()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap.rs:29:16 + | +LL | let _val = Ok::<_, ()>(1).expect("this never happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `expect()` + | +LL - let _val = Ok::<_, ()>(1).expect("this never happens"); +LL + let _val = 1; + | + +error: used `unwrap_err()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap.rs:30:16 + | +LL | let _val = Ok::<_, ()>(1).unwrap_err(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_err()` + | +LL | let _val = panic!("{:?}", 1); + | ~~~~~~~~~~~~~~ ~ + +error: used `expect_err()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap.rs:31:16 + | +LL | let _val = Ok::<_, ()>(1).expect_err("this always happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `expect_err()` + | +LL | let _val = panic!("{1}: {:?}", 1, "this always happens"); + | ~~~~~~~~~~~~~~~~~~~ ~ + +error: used `unwrap()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap.rs:33:5 + | +LL | Ok::<_, ()>(1).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap()` + | +LL - Ok::<_, ()>(1).unwrap(); +LL + 1; + | + +error: used `expect()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap.rs:34:5 + | +LL | Ok::<_, ()>(1).expect("this never happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `expect()` + | +LL - Ok::<_, ()>(1).expect("this never happens"); +LL + 1; + | + +error: used `unwrap_err()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap.rs:35:5 + | +LL | Ok::<_, ()>(1).unwrap_err(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_err()` + | +LL | panic!("{:?}", 1); + | ~~~~~~~~~~~~~~ ~ + +error: used `expect_err()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap.rs:36:5 + | +LL | Ok::<_, ()>(1).expect_err("this always happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `expect_err()` + | +LL | panic!("{1}: {:?}", 1, "this always happens"); + | ~~~~~~~~~~~~~~~~~~~ ~ + +error: used `unwrap_err()` on `Err` value + --> $DIR/unnecessary_literal_unwrap.rs:40:16 + | +LL | let _val = Err::<(), _>(1).unwrap_err(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Err` and `unwrap_err()` + | +LL - let _val = Err::<(), _>(1).unwrap_err(); +LL + let _val = 1; + | + +error: used `expect_err()` on `Err` value + --> $DIR/unnecessary_literal_unwrap.rs:41:16 + | +LL | let _val = Err::<(), _>(1).expect_err("this never happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Err` and `expect_err()` + | +LL - let _val = Err::<(), _>(1).expect_err("this never happens"); +LL + let _val = 1; + | + +error: used `unwrap()` on `Err` value + --> $DIR/unnecessary_literal_unwrap.rs:42:16 + | +LL | let _val = Err::<(), _>(1).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Err` and `unwrap()` + | +LL | let _val = panic!("{:?}", 1); + | ~~~~~~~~~~~~~~ ~ + +error: used `expect()` on `Err` value + --> $DIR/unnecessary_literal_unwrap.rs:43:16 + | +LL | let _val = Err::<(), _>(1).expect("this always happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Err` and `expect()` + | +LL | let _val = panic!("{1}: {:?}", 1, "this always happens"); + | ~~~~~~~~~~~~~~~~~~~ ~ + +error: used `unwrap_err()` on `Err` value + --> $DIR/unnecessary_literal_unwrap.rs:45:5 + | +LL | Err::<(), _>(1).unwrap_err(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Err` and `unwrap_err()` + | +LL - Err::<(), _>(1).unwrap_err(); +LL + 1; + | + +error: used `expect_err()` on `Err` value + --> $DIR/unnecessary_literal_unwrap.rs:46:5 + | +LL | Err::<(), _>(1).expect_err("this never happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Err` and `expect_err()` + | +LL - Err::<(), _>(1).expect_err("this never happens"); +LL + 1; + | + +error: used `unwrap()` on `Err` value + --> $DIR/unnecessary_literal_unwrap.rs:47:5 + | +LL | Err::<(), _>(1).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Err` and `unwrap()` + | +LL | panic!("{:?}", 1); + | ~~~~~~~~~~~~~~ ~ + +error: used `expect()` on `Err` value + --> $DIR/unnecessary_literal_unwrap.rs:48:5 + | +LL | Err::<(), _>(1).expect("this always happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Err` and `expect()` + | +LL | panic!("{1}: {:?}", 1, "this always happens"); + | ~~~~~~~~~~~~~~~~~~~ ~ + +error: used `unwrap_or()` on `Some` value + --> $DIR/unnecessary_literal_unwrap.rs:52:16 + | +LL | let _val = Some(1).unwrap_or(2); + | ^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap_or()` + | +LL - let _val = Some(1).unwrap_or(2); +LL + let _val = 1; + | + +error: used `unwrap_or_default()` on `Some` value + --> $DIR/unnecessary_literal_unwrap.rs:53:16 + | +LL | let _val = Some(1).unwrap_or_default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap_or_default()` + | +LL - let _val = Some(1).unwrap_or_default(); +LL + let _val = 1; + | + +error: used `unwrap_or_else()` on `Some` value + --> $DIR/unnecessary_literal_unwrap.rs:54:16 + | +LL | let _val = Some(1).unwrap_or_else(|| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap_or_else()` + | +LL - let _val = Some(1).unwrap_or_else(|| 2); +LL + let _val = 1; + | + +error: used `unwrap_or()` on `Some` value + --> $DIR/unnecessary_literal_unwrap.rs:56:5 + | +LL | Some(1).unwrap_or(2); + | ^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap_or()` + | +LL - Some(1).unwrap_or(2); +LL + 1; + | + +error: used `unwrap_or_default()` on `Some` value + --> $DIR/unnecessary_literal_unwrap.rs:57:5 + | +LL | Some(1).unwrap_or_default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap_or_default()` + | +LL - Some(1).unwrap_or_default(); +LL + 1; + | + +error: used `unwrap_or_else()` on `Some` value + --> $DIR/unnecessary_literal_unwrap.rs:58:5 + | +LL | Some(1).unwrap_or_else(|| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap_or_else()` + | +LL - Some(1).unwrap_or_else(|| 2); +LL + 1; + | + +error: used `unwrap_or()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap.rs:62:16 + | +LL | let _val = Ok::<_, ()>(1).unwrap_or(2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_or()` + | +LL - let _val = Ok::<_, ()>(1).unwrap_or(2); +LL + let _val = 1; + | + +error: used `unwrap_or_default()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap.rs:63:16 + | +LL | let _val = Ok::<_, ()>(1).unwrap_or_default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_or_default()` + | +LL - let _val = Ok::<_, ()>(1).unwrap_or_default(); +LL + let _val = 1; + | + +error: used `unwrap_or_else()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap.rs:64:16 + | +LL | let _val = Ok::<_, ()>(1).unwrap_or_else(|_| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_or_else()` + | +LL - let _val = Ok::<_, ()>(1).unwrap_or_else(|_| 2); +LL + let _val = 1; + | + +error: used `unwrap_or()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap.rs:66:5 + | +LL | Ok::<_, ()>(1).unwrap_or(2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_or()` + | +LL - Ok::<_, ()>(1).unwrap_or(2); +LL + 1; + | + +error: used `unwrap_or_default()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap.rs:67:5 + | +LL | Ok::<_, ()>(1).unwrap_or_default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_or_default()` + | +LL - Ok::<_, ()>(1).unwrap_or_default(); +LL + 1; + | + +error: used `unwrap_or_else()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap.rs:68:5 + | +LL | Ok::<_, ()>(1).unwrap_or_else(|_| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_or_else()` + | +LL - Ok::<_, ()>(1).unwrap_or_else(|_| 2); +LL + 1; + | + +error: aborting due to 36 previous errors + diff --git a/tests/ui/unnecessary_literal_unwrap_unfixable.rs b/tests/ui/unnecessary_literal_unwrap_unfixable.rs new file mode 100644 index 000000000000..711fdce39624 --- /dev/null +++ b/tests/ui/unnecessary_literal_unwrap_unfixable.rs @@ -0,0 +1,116 @@ +#![warn(clippy::unnecessary_literal_unwrap)] +#![allow(unreachable_code)] +#![allow(clippy::unnecessary_lazy_evaluations, clippy::let_unit_value)] + +fn unwrap_option_some() { + let val = Some(1); + let _val2 = val.unwrap(); + let _val2 = val.expect("this never happens"); +} + +fn unwrap_option_some_context() { + let _val = Some::([1, 2, 3].iter().sum()).unwrap(); + let _val = Some::([1, 2, 3].iter().sum()).expect("this never happens"); + + let val = Some::([1, 2, 3].iter().sum()); + let _val2 = val.unwrap(); + let _val2 = val.expect("this never happens"); +} + +fn unwrap_option_none() { + let val = None::<()>; + let _val2 = val.unwrap(); + let _val2 = val.expect("this always happens"); +} + +fn unwrap_result_ok() { + let val = Ok::<_, ()>(1); + let _val2 = val.unwrap(); + let _val2 = val.expect("this never happens"); + let _val2 = val.unwrap_err(); + let _val2 = val.expect_err("this always happens"); +} + +fn unwrap_result_ok_context() { + let _val = Ok::([1, 2, 3].iter().sum()).unwrap(); + let _val = Ok::([1, 2, 3].iter().sum()).expect("this never happens"); + let _val = Ok::([1, 2, 3].iter().sum()).unwrap_err(); + let _val = Ok::([1, 2, 3].iter().sum()).expect_err("this always happens"); + + let val = Ok::([1, 2, 3].iter().sum()); + let _val2 = val.unwrap(); + let _val2 = val.expect("this never happens"); + let _val2 = val.unwrap_err(); + let _val2 = val.expect_err("this always happens"); +} + +fn unwrap_result_err() { + let val = Err::<(), _>(1); + let _val2 = val.unwrap_err(); + let _val2 = val.expect_err("this never happens"); + let _val2 = val.unwrap(); + let _val2 = val.expect("this always happens"); +} + +fn unwrap_result_err_context() { + let _val = Err::<(), usize>([1, 2, 3].iter().sum()).unwrap_err(); + let _val = Err::<(), usize>([1, 2, 3].iter().sum()).expect_err("this never happens"); + let _val = Err::<(), usize>([1, 2, 3].iter().sum()).unwrap(); + let _val = Err::<(), usize>([1, 2, 3].iter().sum()).expect("this always happens"); + + let val = Err::<(), usize>([1, 2, 3].iter().sum()); + let _val2 = val.unwrap_err(); + let _val2 = val.expect_err("this never happens"); + let _val2 = val.unwrap(); + let _val2 = val.expect("this always happens"); +} + +fn unwrap_methods_option() { + let val = Some(1); + let _val2 = val.unwrap_or(2); + let _val2 = val.unwrap_or_default(); + let _val2 = val.unwrap_or_else(|| 2); +} + +fn unwrap_methods_option_context() { + let _val = Some::([1, 2, 3].iter().sum()).unwrap_or(2); + let _val = Some::([1, 2, 3].iter().sum()).unwrap_or_default(); + let _val = Some::([1, 2, 3].iter().sum()).unwrap_or_else(|| 2); + + let val = Some::([1, 2, 3].iter().sum()); + let _val2 = val.unwrap_or(2); + let _val2 = val.unwrap_or_default(); + let _val2 = val.unwrap_or_else(|| 2); +} + +fn unwrap_methods_result() { + let val = Ok::<_, ()>(1); + let _val2 = val.unwrap_or(2); + let _val2 = val.unwrap_or_default(); + let _val2 = val.unwrap_or_else(|_| 2); +} + +fn unwrap_methods_result_context() { + let _val = Ok::([1, 2, 3].iter().sum()).unwrap_or(2); + let _val = Ok::([1, 2, 3].iter().sum()).unwrap_or_default(); + let _val = Ok::([1, 2, 3].iter().sum()).unwrap_or_else(|_| 2); + + let val = Ok::([1, 2, 3].iter().sum()); + let _val2 = val.unwrap_or(2); + let _val2 = val.unwrap_or_default(); + let _val2 = val.unwrap_or_else(|_| 2); +} + +fn main() { + unwrap_option_some(); + unwrap_option_some_context(); + unwrap_option_none(); + unwrap_result_ok(); + unwrap_result_ok_context(); + unwrap_result_err(); + unwrap_result_err_context(); + unwrap_methods_option(); + unwrap_methods_option_context(); + unwrap_methods_result(); + unwrap_methods_result_context(); +} diff --git a/tests/ui/unnecessary_literal_unwrap_unfixable.stderr b/tests/ui/unnecessary_literal_unwrap_unfixable.stderr new file mode 100644 index 000000000000..feb9325b77a6 --- /dev/null +++ b/tests/ui/unnecessary_literal_unwrap_unfixable.stderr @@ -0,0 +1,603 @@ +error: used `unwrap()` on `Some` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:7:17 + | +LL | let _val2 = val.unwrap(); + | ^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:6:15 + | +LL | let val = Some(1); + | ^^^^^^^ + = note: `-D clippy::unnecessary-literal-unwrap` implied by `-D warnings` + +error: used `expect()` on `Some` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:8:17 + | +LL | let _val2 = val.expect("this never happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `expect()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:6:15 + | +LL | let val = Some(1); + | ^^^^^^^ + +error: used `unwrap()` on `Some` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:12:16 + | +LL | let _val = Some::([1, 2, 3].iter().sum()).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:12:16 + | +LL | let _val = Some::([1, 2, 3].iter().sum()).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `expect()` on `Some` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:13:16 + | +LL | let _val = Some::([1, 2, 3].iter().sum()).expect("this never happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `expect()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:13:16 + | +LL | let _val = Some::([1, 2, 3].iter().sum()).expect("this never happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `unwrap()` on `Some` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:16:17 + | +LL | let _val2 = val.unwrap(); + | ^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:15:15 + | +LL | let val = Some::([1, 2, 3].iter().sum()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `expect()` on `Some` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:17:17 + | +LL | let _val2 = val.expect("this never happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `expect()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:15:15 + | +LL | let val = Some::([1, 2, 3].iter().sum()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `unwrap()` on `None` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:22:17 + | +LL | let _val2 = val.unwrap(); + | ^^^^^^^^^^^^ + | +help: remove the `None` and `unwrap()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:21:15 + | +LL | let val = None::<()>; + | ^^^^^^^^^^ + +error: used `expect()` on `None` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:23:17 + | +LL | let _val2 = val.expect("this always happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `None` and `expect()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:21:15 + | +LL | let val = None::<()>; + | ^^^^^^^^^^ + +error: used `unwrap()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:28:17 + | +LL | let _val2 = val.unwrap(); + | ^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:27:15 + | +LL | let val = Ok::<_, ()>(1); + | ^^^^^^^^^^^^^^ + +error: used `expect()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:29:17 + | +LL | let _val2 = val.expect("this never happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `expect()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:27:15 + | +LL | let val = Ok::<_, ()>(1); + | ^^^^^^^^^^^^^^ + +error: used `unwrap_err()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:30:17 + | +LL | let _val2 = val.unwrap_err(); + | ^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_err()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:27:15 + | +LL | let val = Ok::<_, ()>(1); + | ^^^^^^^^^^^^^^ + +error: used `expect_err()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:31:17 + | +LL | let _val2 = val.expect_err("this always happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `expect_err()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:27:15 + | +LL | let val = Ok::<_, ()>(1); + | ^^^^^^^^^^^^^^ + +error: used `unwrap()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:35:16 + | +LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:35:16 + | +LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `expect()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:36:16 + | +LL | let _val = Ok::([1, 2, 3].iter().sum()).expect("this never happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `expect()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:36:16 + | +LL | let _val = Ok::([1, 2, 3].iter().sum()).expect("this never happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `unwrap_err()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:37:16 + | +LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap_err(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_err()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:37:16 + | +LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap_err(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `expect_err()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:38:16 + | +LL | let _val = Ok::([1, 2, 3].iter().sum()).expect_err("this always happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `expect_err()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:38:16 + | +LL | let _val = Ok::([1, 2, 3].iter().sum()).expect_err("this always happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `unwrap()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:41:17 + | +LL | let _val2 = val.unwrap(); + | ^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:40:15 + | +LL | let val = Ok::([1, 2, 3].iter().sum()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `expect()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:42:17 + | +LL | let _val2 = val.expect("this never happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `expect()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:40:15 + | +LL | let val = Ok::([1, 2, 3].iter().sum()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `unwrap_err()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:43:17 + | +LL | let _val2 = val.unwrap_err(); + | ^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_err()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:40:15 + | +LL | let val = Ok::([1, 2, 3].iter().sum()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `expect_err()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:44:17 + | +LL | let _val2 = val.expect_err("this always happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `expect_err()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:40:15 + | +LL | let val = Ok::([1, 2, 3].iter().sum()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `unwrap_err()` on `Err` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:49:17 + | +LL | let _val2 = val.unwrap_err(); + | ^^^^^^^^^^^^^^^^ + | +help: remove the `Err` and `unwrap_err()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:48:15 + | +LL | let val = Err::<(), _>(1); + | ^^^^^^^^^^^^^^^ + +error: used `expect_err()` on `Err` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:50:17 + | +LL | let _val2 = val.expect_err("this never happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Err` and `expect_err()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:48:15 + | +LL | let val = Err::<(), _>(1); + | ^^^^^^^^^^^^^^^ + +error: used `unwrap()` on `Err` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:51:17 + | +LL | let _val2 = val.unwrap(); + | ^^^^^^^^^^^^ + | +help: remove the `Err` and `unwrap()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:48:15 + | +LL | let val = Err::<(), _>(1); + | ^^^^^^^^^^^^^^^ + +error: used `expect()` on `Err` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:52:17 + | +LL | let _val2 = val.expect("this always happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Err` and `expect()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:48:15 + | +LL | let val = Err::<(), _>(1); + | ^^^^^^^^^^^^^^^ + +error: used `unwrap_err()` on `Err` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:56:16 + | +LL | let _val = Err::<(), usize>([1, 2, 3].iter().sum()).unwrap_err(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Err` and `unwrap_err()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:56:16 + | +LL | let _val = Err::<(), usize>([1, 2, 3].iter().sum()).unwrap_err(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `expect_err()` on `Err` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:57:16 + | +LL | let _val = Err::<(), usize>([1, 2, 3].iter().sum()).expect_err("this never happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Err` and `expect_err()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:57:16 + | +LL | let _val = Err::<(), usize>([1, 2, 3].iter().sum()).expect_err("this never happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `unwrap()` on `Err` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:58:16 + | +LL | let _val = Err::<(), usize>([1, 2, 3].iter().sum()).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Err` and `unwrap()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:58:16 + | +LL | let _val = Err::<(), usize>([1, 2, 3].iter().sum()).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `expect()` on `Err` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:59:16 + | +LL | let _val = Err::<(), usize>([1, 2, 3].iter().sum()).expect("this always happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Err` and `expect()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:59:16 + | +LL | let _val = Err::<(), usize>([1, 2, 3].iter().sum()).expect("this always happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `unwrap_err()` on `Err` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:62:17 + | +LL | let _val2 = val.unwrap_err(); + | ^^^^^^^^^^^^^^^^ + | +help: remove the `Err` and `unwrap_err()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:61:15 + | +LL | let val = Err::<(), usize>([1, 2, 3].iter().sum()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `expect_err()` on `Err` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:63:17 + | +LL | let _val2 = val.expect_err("this never happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Err` and `expect_err()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:61:15 + | +LL | let val = Err::<(), usize>([1, 2, 3].iter().sum()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `unwrap()` on `Err` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:64:17 + | +LL | let _val2 = val.unwrap(); + | ^^^^^^^^^^^^ + | +help: remove the `Err` and `unwrap()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:61:15 + | +LL | let val = Err::<(), usize>([1, 2, 3].iter().sum()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `expect()` on `Err` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:65:17 + | +LL | let _val2 = val.expect("this always happens"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Err` and `expect()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:61:15 + | +LL | let val = Err::<(), usize>([1, 2, 3].iter().sum()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `unwrap_or()` on `Some` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:70:17 + | +LL | let _val2 = val.unwrap_or(2); + | ^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap_or()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:69:15 + | +LL | let val = Some(1); + | ^^^^^^^ + +error: used `unwrap_or_default()` on `Some` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:71:17 + | +LL | let _val2 = val.unwrap_or_default(); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap_or_default()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:69:15 + | +LL | let val = Some(1); + | ^^^^^^^ + +error: used `unwrap_or_else()` on `Some` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:72:17 + | +LL | let _val2 = val.unwrap_or_else(|| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap_or_else()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:69:15 + | +LL | let val = Some(1); + | ^^^^^^^ + +error: used `unwrap_or()` on `Some` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:76:16 + | +LL | let _val = Some::([1, 2, 3].iter().sum()).unwrap_or(2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap_or()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:76:16 + | +LL | let _val = Some::([1, 2, 3].iter().sum()).unwrap_or(2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `unwrap_or_default()` on `Some` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:77:16 + | +LL | let _val = Some::([1, 2, 3].iter().sum()).unwrap_or_default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap_or_default()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:77:16 + | +LL | let _val = Some::([1, 2, 3].iter().sum()).unwrap_or_default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `unwrap_or_else()` on `Some` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:78:16 + | +LL | let _val = Some::([1, 2, 3].iter().sum()).unwrap_or_else(|| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap_or_else()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:78:16 + | +LL | let _val = Some::([1, 2, 3].iter().sum()).unwrap_or_else(|| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `unwrap_or()` on `Some` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:81:17 + | +LL | let _val2 = val.unwrap_or(2); + | ^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap_or()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:80:15 + | +LL | let val = Some::([1, 2, 3].iter().sum()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `unwrap_or_default()` on `Some` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:82:17 + | +LL | let _val2 = val.unwrap_or_default(); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap_or_default()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:80:15 + | +LL | let val = Some::([1, 2, 3].iter().sum()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `unwrap_or_else()` on `Some` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:83:17 + | +LL | let _val2 = val.unwrap_or_else(|| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Some` and `unwrap_or_else()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:80:15 + | +LL | let val = Some::([1, 2, 3].iter().sum()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `unwrap_or()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:88:17 + | +LL | let _val2 = val.unwrap_or(2); + | ^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_or()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:87:15 + | +LL | let val = Ok::<_, ()>(1); + | ^^^^^^^^^^^^^^ + +error: used `unwrap_or_default()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:89:17 + | +LL | let _val2 = val.unwrap_or_default(); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_or_default()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:87:15 + | +LL | let val = Ok::<_, ()>(1); + | ^^^^^^^^^^^^^^ + +error: used `unwrap_or_else()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:90:17 + | +LL | let _val2 = val.unwrap_or_else(|_| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_or_else()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:87:15 + | +LL | let val = Ok::<_, ()>(1); + | ^^^^^^^^^^^^^^ + +error: used `unwrap_or()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:94:16 + | +LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap_or(2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_or()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:94:16 + | +LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap_or(2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `unwrap_or_default()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:95:16 + | +LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap_or_default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_or_default()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:95:16 + | +LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap_or_default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `unwrap_or_else()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:96:16 + | +LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap_or_else(|_| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_or_else()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:96:16 + | +LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap_or_else(|_| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `unwrap_or()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:99:17 + | +LL | let _val2 = val.unwrap_or(2); + | ^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_or()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:98:15 + | +LL | let val = Ok::([1, 2, 3].iter().sum()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `unwrap_or_default()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:100:17 + | +LL | let _val2 = val.unwrap_or_default(); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_or_default()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:98:15 + | +LL | let val = Ok::([1, 2, 3].iter().sum()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: used `unwrap_or_else()` on `Ok` value + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:101:17 + | +LL | let _val2 = val.unwrap_or_else(|_| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `Ok` and `unwrap_or_else()` + --> $DIR/unnecessary_literal_unwrap_unfixable.rs:98:15 + | +LL | let val = Ok::([1, 2, 3].iter().sum()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 50 previous errors + diff --git a/tests/ui/unnecessary_safety_comment.rs b/tests/ui/unnecessary_safety_comment.rs index 89fedb145f88..d858701ae8ac 100644 --- a/tests/ui/unnecessary_safety_comment.rs +++ b/tests/ui/unnecessary_safety_comment.rs @@ -1,5 +1,5 @@ #![warn(clippy::undocumented_unsafe_blocks, clippy::unnecessary_safety_comment)] -#![allow(clippy::let_unit_value, clippy::missing_safety_doc)] +#![allow(clippy::let_unit_value, clippy::missing_safety_doc, clippy::needless_if)] mod unsafe_items_invalid_comment { // SAFETY: diff --git a/tests/ui/unnecessary_sort_by.fixed b/tests/ui/unnecessary_sort_by.fixed index 165cabd82989..19380ad00dcd 100644 --- a/tests/ui/unnecessary_sort_by.fixed +++ b/tests/ui/unnecessary_sort_by.fixed @@ -1,6 +1,6 @@ //@run-rustfix -#![allow(clippy::stable_sort_primitive)] +#![allow(clippy::stable_sort_primitive, clippy::useless_vec)] use std::cell::Ref; diff --git a/tests/ui/unnecessary_sort_by.rs b/tests/ui/unnecessary_sort_by.rs index 8a2158d5a841..cea1b65b5203 100644 --- a/tests/ui/unnecessary_sort_by.rs +++ b/tests/ui/unnecessary_sort_by.rs @@ -1,6 +1,6 @@ //@run-rustfix -#![allow(clippy::stable_sort_primitive)] +#![allow(clippy::stable_sort_primitive, clippy::useless_vec)] use std::cell::Ref; diff --git a/tests/ui/unnecessary_struct_initialization.fixed b/tests/ui/unnecessary_struct_initialization.fixed index bdf746cf2c42..eae1271d1aa7 100644 --- a/tests/ui/unnecessary_struct_initialization.fixed +++ b/tests/ui/unnecessary_struct_initialization.fixed @@ -1,6 +1,6 @@ //@run-rustfix -#![allow(unused)] +#![allow(clippy::incorrect_clone_impl_on_copy_type, unused)] #![warn(clippy::unnecessary_struct_initialization)] struct S { diff --git a/tests/ui/unnecessary_struct_initialization.rs b/tests/ui/unnecessary_struct_initialization.rs index 7271e2f957a8..4abd560f84be 100644 --- a/tests/ui/unnecessary_struct_initialization.rs +++ b/tests/ui/unnecessary_struct_initialization.rs @@ -1,6 +1,6 @@ //@run-rustfix -#![allow(unused)] +#![allow(clippy::incorrect_clone_impl_on_copy_type, unused)] #![warn(clippy::unnecessary_struct_initialization)] struct S { diff --git a/tests/ui/unnecessary_to_owned.fixed b/tests/ui/unnecessary_to_owned.fixed index c879fdc3b6ae..592a53f3a819 100644 --- a/tests/ui/unnecessary_to_owned.fixed +++ b/tests/ui/unnecessary_to_owned.fixed @@ -1,7 +1,7 @@ //@run-rustfix #![allow(clippy::needless_borrow, clippy::ptr_arg)] -#![warn(clippy::unnecessary_to_owned)] +#![warn(clippy::unnecessary_to_owned, clippy::redundant_clone)] use std::borrow::Cow; use std::ffi::{CStr, CString, OsStr, OsString}; @@ -474,3 +474,36 @@ mod issue_10021 { Ok(()) } } + +mod issue_10033 { + #![allow(dead_code)] + use std::{fmt::Display, ops::Deref}; + + fn _main() { + let f = Foo; + + // Not actually unnecessary - this calls `Foo`'s `Display` impl, not `str`'s (even though `Foo` does + // deref to `str`) + foo(&f.to_string()); + } + + fn foo(s: &str) { + println!("{}", s); + } + + struct Foo; + + impl Deref for Foo { + type Target = str; + + fn deref(&self) -> &Self::Target { + "str" + } + } + + impl Display for Foo { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Foo") + } + } +} diff --git a/tests/ui/unnecessary_to_owned.rs b/tests/ui/unnecessary_to_owned.rs index 10588beb263b..f2e48b1c4a6a 100644 --- a/tests/ui/unnecessary_to_owned.rs +++ b/tests/ui/unnecessary_to_owned.rs @@ -1,7 +1,7 @@ //@run-rustfix #![allow(clippy::needless_borrow, clippy::ptr_arg)] -#![warn(clippy::unnecessary_to_owned)] +#![warn(clippy::unnecessary_to_owned, clippy::redundant_clone)] use std::borrow::Cow; use std::ffi::{CStr, CString, OsStr, OsString}; @@ -474,3 +474,36 @@ mod issue_10021 { Ok(()) } } + +mod issue_10033 { + #![allow(dead_code)] + use std::{fmt::Display, ops::Deref}; + + fn _main() { + let f = Foo; + + // Not actually unnecessary - this calls `Foo`'s `Display` impl, not `str`'s (even though `Foo` does + // deref to `str`) + foo(&f.to_string()); + } + + fn foo(s: &str) { + println!("{}", s); + } + + struct Foo; + + impl Deref for Foo { + type Target = str; + + fn deref(&self) -> &Self::Target { + "str" + } + } + + impl Display for Foo { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Foo") + } + } +} diff --git a/tests/ui/unnecessary_unsafety_doc.rs b/tests/ui/unnecessary_unsafety_doc.rs index 373b18470f69..2d55dc664a32 100644 --- a/tests/ui/unnecessary_unsafety_doc.rs +++ b/tests/ui/unnecessary_unsafety_doc.rs @@ -1,4 +1,4 @@ -//@aux-build:proc_macros.rs +//@aux-build:proc_macros.rs:proc-macro #![allow(clippy::let_unit_value)] #![warn(clippy::unnecessary_safety_doc)] diff --git a/tests/ui/unneeded_field_pattern.rs b/tests/ui/unneeded_field_pattern.rs index fa639aa70d61..48ae1cf66405 100644 --- a/tests/ui/unneeded_field_pattern.rs +++ b/tests/ui/unneeded_field_pattern.rs @@ -1,5 +1,9 @@ +//@aux-build:proc_macros.rs:proc-macro #![warn(clippy::unneeded_field_pattern)] -#[allow(dead_code, unused)] +#![allow(dead_code, unused)] + +#[macro_use] +extern crate proc_macros; struct Foo { a: i32, @@ -19,4 +23,12 @@ fn main() { Foo { b: 0, .. } => {}, // should be OK Foo { .. } => {}, // and the Force might be with this one } + external! { + let f = Foo { a: 0, b: 0, c: 0 }; + match f { + Foo { a: _, b: 0, .. } => {}, + + Foo { a: _, b: _, c: _ } => {}, + } + } } diff --git a/tests/ui/unneeded_field_pattern.stderr b/tests/ui/unneeded_field_pattern.stderr index 6f7c31545696..3f15684986fe 100644 --- a/tests/ui/unneeded_field_pattern.stderr +++ b/tests/ui/unneeded_field_pattern.stderr @@ -1,5 +1,5 @@ error: you matched a field with a wildcard pattern, consider using `..` instead - --> $DIR/unneeded_field_pattern.rs:14:15 + --> $DIR/unneeded_field_pattern.rs:18:15 | LL | Foo { a: _, b: 0, .. } => {}, | ^^^^ @@ -8,7 +8,7 @@ LL | Foo { a: _, b: 0, .. } => {}, = note: `-D clippy::unneeded-field-pattern` implied by `-D warnings` error: all the struct fields are matched to a wildcard pattern, consider using `..` - --> $DIR/unneeded_field_pattern.rs:16:9 + --> $DIR/unneeded_field_pattern.rs:20:9 | LL | Foo { a: _, b: _, c: _ } => {}, | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/unneeded_wildcard_pattern.fixed b/tests/ui/unneeded_wildcard_pattern.fixed index 16c2de760e55..2eeba509e833 100644 --- a/tests/ui/unneeded_wildcard_pattern.fixed +++ b/tests/ui/unneeded_wildcard_pattern.fixed @@ -1,6 +1,11 @@ //@run-rustfix +//@aux-build:proc_macros.rs:proc-macro #![feature(stmt_expr_attributes)] #![deny(clippy::unneeded_wildcard_pattern)] +#![allow(clippy::needless_if)] + +#[macro_use] +extern crate proc_macros; fn main() { let t = (0, 1, 2, 3); @@ -42,4 +47,8 @@ fn main() { { if let S(0, ..,) = s {}; } + external! { + let t = (0, 1, 2, 3); + if let (0, _, ..) = t {}; + } } diff --git a/tests/ui/unneeded_wildcard_pattern.rs b/tests/ui/unneeded_wildcard_pattern.rs index 9d9eae1d9033..5416cfaa5425 100644 --- a/tests/ui/unneeded_wildcard_pattern.rs +++ b/tests/ui/unneeded_wildcard_pattern.rs @@ -1,6 +1,11 @@ //@run-rustfix +//@aux-build:proc_macros.rs:proc-macro #![feature(stmt_expr_attributes)] #![deny(clippy::unneeded_wildcard_pattern)] +#![allow(clippy::needless_if)] + +#[macro_use] +extern crate proc_macros; fn main() { let t = (0, 1, 2, 3); @@ -42,4 +47,8 @@ fn main() { { if let S(0, .., _, _,) = s {}; } + external! { + let t = (0, 1, 2, 3); + if let (0, _, ..) = t {}; + } } diff --git a/tests/ui/unneeded_wildcard_pattern.stderr b/tests/ui/unneeded_wildcard_pattern.stderr index 716d9ecff89a..ffbdc049506e 100644 --- a/tests/ui/unneeded_wildcard_pattern.stderr +++ b/tests/ui/unneeded_wildcard_pattern.stderr @@ -1,89 +1,89 @@ error: this pattern is unneeded as the `..` pattern can match that element - --> $DIR/unneeded_wildcard_pattern.rs:8:18 + --> $DIR/unneeded_wildcard_pattern.rs:13:18 | LL | if let (0, .., _) = t {}; | ^^^ help: remove it | note: the lint level is defined here - --> $DIR/unneeded_wildcard_pattern.rs:3:9 + --> $DIR/unneeded_wildcard_pattern.rs:4:9 | LL | #![deny(clippy::unneeded_wildcard_pattern)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this pattern is unneeded as the `..` pattern can match that element - --> $DIR/unneeded_wildcard_pattern.rs:9:16 + --> $DIR/unneeded_wildcard_pattern.rs:14:16 | LL | if let (0, _, ..) = t {}; | ^^^ help: remove it error: this pattern is unneeded as the `..` pattern can match that element - --> $DIR/unneeded_wildcard_pattern.rs:10:13 + --> $DIR/unneeded_wildcard_pattern.rs:15:13 | LL | if let (_, .., 0) = t {}; | ^^^ help: remove it error: this pattern is unneeded as the `..` pattern can match that element - --> $DIR/unneeded_wildcard_pattern.rs:11:15 + --> $DIR/unneeded_wildcard_pattern.rs:16:15 | LL | if let (.., _, 0) = t {}; | ^^^ help: remove it error: these patterns are unneeded as the `..` pattern can match those elements - --> $DIR/unneeded_wildcard_pattern.rs:12:16 + --> $DIR/unneeded_wildcard_pattern.rs:17:16 | LL | if let (0, _, _, ..) = t {}; | ^^^^^^ help: remove them error: these patterns are unneeded as the `..` pattern can match those elements - --> $DIR/unneeded_wildcard_pattern.rs:13:18 + --> $DIR/unneeded_wildcard_pattern.rs:18:18 | LL | if let (0, .., _, _) = t {}; | ^^^^^^ help: remove them error: these patterns are unneeded as the `..` pattern can match those elements - --> $DIR/unneeded_wildcard_pattern.rs:22:22 + --> $DIR/unneeded_wildcard_pattern.rs:27:22 | LL | if let (0, .., _, _,) = t {}; | ^^^^^^ help: remove them error: this pattern is unneeded as the `..` pattern can match that element - --> $DIR/unneeded_wildcard_pattern.rs:29:19 + --> $DIR/unneeded_wildcard_pattern.rs:34:19 | LL | if let S(0, .., _) = s {}; | ^^^ help: remove it error: this pattern is unneeded as the `..` pattern can match that element - --> $DIR/unneeded_wildcard_pattern.rs:30:17 + --> $DIR/unneeded_wildcard_pattern.rs:35:17 | LL | if let S(0, _, ..) = s {}; | ^^^ help: remove it error: this pattern is unneeded as the `..` pattern can match that element - --> $DIR/unneeded_wildcard_pattern.rs:31:14 + --> $DIR/unneeded_wildcard_pattern.rs:36:14 | LL | if let S(_, .., 0) = s {}; | ^^^ help: remove it error: this pattern is unneeded as the `..` pattern can match that element - --> $DIR/unneeded_wildcard_pattern.rs:32:16 + --> $DIR/unneeded_wildcard_pattern.rs:37:16 | LL | if let S(.., _, 0) = s {}; | ^^^ help: remove it error: these patterns are unneeded as the `..` pattern can match those elements - --> $DIR/unneeded_wildcard_pattern.rs:33:17 + --> $DIR/unneeded_wildcard_pattern.rs:38:17 | LL | if let S(0, _, _, ..) = s {}; | ^^^^^^ help: remove them error: these patterns are unneeded as the `..` pattern can match those elements - --> $DIR/unneeded_wildcard_pattern.rs:34:19 + --> $DIR/unneeded_wildcard_pattern.rs:39:19 | LL | if let S(0, .., _, _) = s {}; | ^^^^^^ help: remove them error: these patterns are unneeded as the `..` pattern can match those elements - --> $DIR/unneeded_wildcard_pattern.rs:43:23 + --> $DIR/unneeded_wildcard_pattern.rs:48:23 | LL | if let S(0, .., _, _,) = s {}; | ^^^^^^ help: remove them diff --git a/tests/ui/unnested_or_patterns.fixed b/tests/ui/unnested_or_patterns.fixed index 8ec35ba4eea7..738045595c0b 100644 --- a/tests/ui/unnested_or_patterns.fixed +++ b/tests/ui/unnested_or_patterns.fixed @@ -2,7 +2,13 @@ #![feature(box_patterns)] #![warn(clippy::unnested_or_patterns)] -#![allow(clippy::cognitive_complexity, clippy::match_ref_pats, clippy::upper_case_acronyms)] +#![allow( + clippy::cognitive_complexity, + clippy::match_ref_pats, + clippy::upper_case_acronyms, + clippy::needless_if, + clippy::manual_range_patterns +)] #![allow(unreachable_patterns, irrefutable_let_patterns, unused)] fn main() { diff --git a/tests/ui/unnested_or_patterns.rs b/tests/ui/unnested_or_patterns.rs index efdb91b2402b..9e0e7b5def98 100644 --- a/tests/ui/unnested_or_patterns.rs +++ b/tests/ui/unnested_or_patterns.rs @@ -2,7 +2,13 @@ #![feature(box_patterns)] #![warn(clippy::unnested_or_patterns)] -#![allow(clippy::cognitive_complexity, clippy::match_ref_pats, clippy::upper_case_acronyms)] +#![allow( + clippy::cognitive_complexity, + clippy::match_ref_pats, + clippy::upper_case_acronyms, + clippy::needless_if, + clippy::manual_range_patterns +)] #![allow(unreachable_patterns, irrefutable_let_patterns, unused)] fn main() { diff --git a/tests/ui/unnested_or_patterns.stderr b/tests/ui/unnested_or_patterns.stderr index a1f193db555a..b997e4ce85fb 100644 --- a/tests/ui/unnested_or_patterns.stderr +++ b/tests/ui/unnested_or_patterns.stderr @@ -1,5 +1,5 @@ error: unnested or-patterns - --> $DIR/unnested_or_patterns.rs:12:12 + --> $DIR/unnested_or_patterns.rs:18:12 | LL | if let box 0 | box 2 = Box::new(0) {} | ^^^^^^^^^^^^^ @@ -11,7 +11,7 @@ LL | if let box (0 | 2) = Box::new(0) {} | ~~~~~~~~~~~ error: unnested or-patterns - --> $DIR/unnested_or_patterns.rs:13:12 + --> $DIR/unnested_or_patterns.rs:19:12 | LL | if let box ((0 | 1)) | box (2 | 3) | box 4 = Box::new(0) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -22,7 +22,7 @@ LL | if let box (0 | 1 | 2 | 3 | 4) = Box::new(0) {} | ~~~~~~~~~~~~~~~~~~~~~~~ error: unnested or-patterns - --> $DIR/unnested_or_patterns.rs:15:12 + --> $DIR/unnested_or_patterns.rs:21:12 | LL | if let Some(1) | C0 | Some(2) = None {} | ^^^^^^^^^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | if let Some(1 | 2) | C0 = None {} | ~~~~~~~~~~~~~~~~ error: unnested or-patterns - --> $DIR/unnested_or_patterns.rs:16:12 + --> $DIR/unnested_or_patterns.rs:22:12 | LL | if let &mut 0 | &mut 2 = &mut 0 {} | ^^^^^^^^^^^^^^^ @@ -44,7 +44,7 @@ LL | if let &mut (0 | 2) = &mut 0 {} | ~~~~~~~~~~~~ error: unnested or-patterns - --> $DIR/unnested_or_patterns.rs:17:12 + --> $DIR/unnested_or_patterns.rs:23:12 | LL | if let x @ 0 | x @ 2 = 0 {} | ^^^^^^^^^^^^^ @@ -55,7 +55,7 @@ LL | if let x @ (0 | 2) = 0 {} | ~~~~~~~~~~~ error: unnested or-patterns - --> $DIR/unnested_or_patterns.rs:18:12 + --> $DIR/unnested_or_patterns.rs:24:12 | LL | if let (0, 1) | (0, 2) | (0, 3) = (0, 0) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -66,7 +66,7 @@ LL | if let (0, 1 | 2 | 3) = (0, 0) {} | ~~~~~~~~~~~~~~ error: unnested or-patterns - --> $DIR/unnested_or_patterns.rs:19:12 + --> $DIR/unnested_or_patterns.rs:25:12 | LL | if let (1, 0) | (2, 0) | (3, 0) = (0, 0) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -77,7 +77,7 @@ LL | if let (1 | 2 | 3, 0) = (0, 0) {} | ~~~~~~~~~~~~~~ error: unnested or-patterns - --> $DIR/unnested_or_patterns.rs:20:12 + --> $DIR/unnested_or_patterns.rs:26:12 | LL | if let (x, ..) | (x, 1) | (x, 2) = (0, 1) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -88,7 +88,7 @@ LL | if let (x, ..) | (x, 1 | 2) = (0, 1) {} | ~~~~~~~~~~~~~~~~~~~~ error: unnested or-patterns - --> $DIR/unnested_or_patterns.rs:21:12 + --> $DIR/unnested_or_patterns.rs:27:12 | LL | if let [0] | [1] = [0] {} | ^^^^^^^^^ @@ -99,7 +99,7 @@ LL | if let [0 | 1] = [0] {} | ~~~~~~~ error: unnested or-patterns - --> $DIR/unnested_or_patterns.rs:22:12 + --> $DIR/unnested_or_patterns.rs:28:12 | LL | if let [x, 0] | [x, 1] = [0, 1] {} | ^^^^^^^^^^^^^^^ @@ -110,7 +110,7 @@ LL | if let [x, 0 | 1] = [0, 1] {} | ~~~~~~~~~~ error: unnested or-patterns - --> $DIR/unnested_or_patterns.rs:23:12 + --> $DIR/unnested_or_patterns.rs:29:12 | LL | if let [x, 0] | [x, 1] | [x, 2] = [0, 1] {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -121,7 +121,7 @@ LL | if let [x, 0 | 1 | 2] = [0, 1] {} | ~~~~~~~~~~~~~~ error: unnested or-patterns - --> $DIR/unnested_or_patterns.rs:24:12 + --> $DIR/unnested_or_patterns.rs:30:12 | LL | if let [x, ..] | [x, 1] | [x, 2] = [0, 1] {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -132,7 +132,7 @@ LL | if let [x, ..] | [x, 1 | 2] = [0, 1] {} | ~~~~~~~~~~~~~~~~~~~~ error: unnested or-patterns - --> $DIR/unnested_or_patterns.rs:26:12 + --> $DIR/unnested_or_patterns.rs:32:12 | LL | if let TS(0, x) | TS(1, x) = TS(0, 0) {} | ^^^^^^^^^^^^^^^^^^^ @@ -143,7 +143,7 @@ LL | if let TS(0 | 1, x) = TS(0, 0) {} | ~~~~~~~~~~~~ error: unnested or-patterns - --> $DIR/unnested_or_patterns.rs:27:12 + --> $DIR/unnested_or_patterns.rs:33:12 | LL | if let TS(1, 0) | TS(2, 0) | TS(3, 0) = TS(0, 0) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -154,7 +154,7 @@ LL | if let TS(1 | 2 | 3, 0) = TS(0, 0) {} | ~~~~~~~~~~~~~~~~ error: unnested or-patterns - --> $DIR/unnested_or_patterns.rs:28:12 + --> $DIR/unnested_or_patterns.rs:34:12 | LL | if let TS(x, ..) | TS(x, 1) | TS(x, 2) = TS(0, 0) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -165,7 +165,7 @@ LL | if let TS(x, ..) | TS(x, 1 | 2) = TS(0, 0) {} | ~~~~~~~~~~~~~~~~~~~~~~~~ error: unnested or-patterns - --> $DIR/unnested_or_patterns.rs:33:12 + --> $DIR/unnested_or_patterns.rs:39:12 | LL | if let S { x: 0, y } | S { y, x: 1 } = (S { x: 0, y: 1 }) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -176,7 +176,7 @@ LL | if let S { x: 0 | 1, y } = (S { x: 0, y: 1 }) {} | ~~~~~~~~~~~~~~~~~ error: unnested or-patterns - --> $DIR/unnested_or_patterns.rs:44:12 + --> $DIR/unnested_or_patterns.rs:50:12 | LL | if let [1] | [53] = [0] {} | ^^^^^^^^^^ diff --git a/tests/ui/unnested_or_patterns2.fixed b/tests/ui/unnested_or_patterns2.fixed index de40e9367471..11dc34378758 100644 --- a/tests/ui/unnested_or_patterns2.fixed +++ b/tests/ui/unnested_or_patterns2.fixed @@ -2,7 +2,12 @@ #![feature(box_patterns)] #![warn(clippy::unnested_or_patterns)] -#![allow(clippy::cognitive_complexity, clippy::match_ref_pats)] +#![allow( + clippy::cognitive_complexity, + clippy::match_ref_pats, + clippy::needless_if, + clippy::manual_range_patterns +)] #![allow(unreachable_patterns, irrefutable_let_patterns, unused_variables)] fn main() { diff --git a/tests/ui/unnested_or_patterns2.rs b/tests/ui/unnested_or_patterns2.rs index 87f66d26c467..b25560827413 100644 --- a/tests/ui/unnested_or_patterns2.rs +++ b/tests/ui/unnested_or_patterns2.rs @@ -2,7 +2,12 @@ #![feature(box_patterns)] #![warn(clippy::unnested_or_patterns)] -#![allow(clippy::cognitive_complexity, clippy::match_ref_pats)] +#![allow( + clippy::cognitive_complexity, + clippy::match_ref_pats, + clippy::needless_if, + clippy::manual_range_patterns +)] #![allow(unreachable_patterns, irrefutable_let_patterns, unused_variables)] fn main() { diff --git a/tests/ui/unnested_or_patterns2.stderr b/tests/ui/unnested_or_patterns2.stderr index 41e8d3fc7092..76e890b3a2e3 100644 --- a/tests/ui/unnested_or_patterns2.stderr +++ b/tests/ui/unnested_or_patterns2.stderr @@ -1,5 +1,5 @@ error: unnested or-patterns - --> $DIR/unnested_or_patterns2.rs:9:12 + --> $DIR/unnested_or_patterns2.rs:14:12 | LL | if let Some(Some(0)) | Some(Some(1)) = None {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -11,7 +11,7 @@ LL | if let Some(Some(0 | 1)) = None {} | ~~~~~~~~~~~~~~~~~ error: unnested or-patterns - --> $DIR/unnested_or_patterns2.rs:10:12 + --> $DIR/unnested_or_patterns2.rs:15:12 | LL | if let Some(Some(0)) | Some(Some(1) | Some(2)) = None {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -22,7 +22,7 @@ LL | if let Some(Some(0 | 1 | 2)) = None {} | ~~~~~~~~~~~~~~~~~~~~~ error: unnested or-patterns - --> $DIR/unnested_or_patterns2.rs:11:12 + --> $DIR/unnested_or_patterns2.rs:16:12 | LL | if let Some(Some(0 | 1) | Some(2)) | Some(Some(3) | Some(4)) = None {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | if let Some(Some(0 | 1 | 2 | 3 | 4)) = None {} | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: unnested or-patterns - --> $DIR/unnested_or_patterns2.rs:12:12 + --> $DIR/unnested_or_patterns2.rs:17:12 | LL | if let Some(Some(0) | Some(1 | 2)) = None {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -44,7 +44,7 @@ LL | if let Some(Some(0 | 1 | 2)) = None {} | ~~~~~~~~~~~~~~~~~~~~~ error: unnested or-patterns - --> $DIR/unnested_or_patterns2.rs:13:12 + --> $DIR/unnested_or_patterns2.rs:18:12 | LL | if let ((0,),) | ((1,) | (2,),) = ((0,),) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -55,7 +55,7 @@ LL | if let ((0 | 1 | 2,),) = ((0,),) {} | ~~~~~~~~~~~~~~~ error: unnested or-patterns - --> $DIR/unnested_or_patterns2.rs:14:12 + --> $DIR/unnested_or_patterns2.rs:19:12 | LL | if let 0 | (1 | 2) = 0 {} | ^^^^^^^^^^^ @@ -66,7 +66,7 @@ LL | if let 0 | 1 | 2 = 0 {} | ~~~~~~~~~ error: unnested or-patterns - --> $DIR/unnested_or_patterns2.rs:15:12 + --> $DIR/unnested_or_patterns2.rs:20:12 | LL | if let box (0 | 1) | (box 2 | box (3 | 4)) = Box::new(0) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -77,7 +77,7 @@ LL | if let box (0 | 1 | 2 | 3 | 4) = Box::new(0) {} | ~~~~~~~~~~~~~~~~~~~~~~~ error: unnested or-patterns - --> $DIR/unnested_or_patterns2.rs:16:12 + --> $DIR/unnested_or_patterns2.rs:21:12 | LL | if let box box 0 | box (box 2 | box 4) = Box::new(Box::new(0)) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/unseparated_prefix_literals.fixed b/tests/ui/unseparated_prefix_literals.fixed index b6241612d9da..125120872670 100644 --- a/tests/ui/unseparated_prefix_literals.fixed +++ b/tests/ui/unseparated_prefix_literals.fixed @@ -1,5 +1,5 @@ //@run-rustfix -//@aux-build:proc_macro_derive.rs +//@aux-build:proc_macro_derive.rs:proc-macro #![warn(clippy::unseparated_literal_suffix)] #![allow(dead_code)] diff --git a/tests/ui/unseparated_prefix_literals.rs b/tests/ui/unseparated_prefix_literals.rs index ae583f4bde37..0a3ffc4784b2 100644 --- a/tests/ui/unseparated_prefix_literals.rs +++ b/tests/ui/unseparated_prefix_literals.rs @@ -1,5 +1,5 @@ //@run-rustfix -//@aux-build:proc_macro_derive.rs +//@aux-build:proc_macro_derive.rs:proc-macro #![warn(clippy::unseparated_literal_suffix)] #![allow(dead_code)] diff --git a/tests/ui/unused_async.rs b/tests/ui/unused_async.rs index bfaa5dadfa59..69e46ab47362 100644 --- a/tests/ui/unused_async.rs +++ b/tests/ui/unused_async.rs @@ -1,4 +1,6 @@ #![warn(clippy::unused_async)] +#![feature(async_fn_in_trait)] +#![allow(incomplete_features)] use std::future::Future; use std::pin::Pin; @@ -23,6 +25,18 @@ mod issue10800 { } } +mod issue10459 { + trait HasAsyncMethod { + async fn do_something() -> u32; + } + + impl HasAsyncMethod for () { + async fn do_something() -> u32 { + 1 + } + } +} + async fn foo() -> i32 { 4 } diff --git a/tests/ui/unused_async.stderr b/tests/ui/unused_async.stderr index 8ac2066a6b24..ffae8366b88c 100644 --- a/tests/ui/unused_async.stderr +++ b/tests/ui/unused_async.stderr @@ -1,5 +1,5 @@ error: unused `async` for function with no await statements - --> $DIR/unused_async.rs:11:5 + --> $DIR/unused_async.rs:13:5 | LL | / async fn async_block_await() { LL | | async { @@ -10,14 +10,14 @@ LL | | } | = help: consider removing the `async` from this function note: `await` used in an async block, which does not require the enclosing function to be `async` - --> $DIR/unused_async.rs:13:23 + --> $DIR/unused_async.rs:15:23 | LL | ready(()).await; | ^^^^^ = note: `-D clippy::unused-async` implied by `-D warnings` error: unused `async` for function with no await statements - --> $DIR/unused_async.rs:26:1 + --> $DIR/unused_async.rs:40:1 | LL | / async fn foo() -> i32 { LL | | 4 @@ -27,7 +27,7 @@ LL | | } = help: consider removing the `async` from this function error: unused `async` for function with no await statements - --> $DIR/unused_async.rs:37:5 + --> $DIR/unused_async.rs:51:5 | LL | / async fn unused(&self) -> i32 { LL | | 1 diff --git a/tests/ui/unwrap.rs b/tests/ui/unwrap.rs index d9fd402e7cfb..64d6437834e6 100644 --- a/tests/ui/unwrap.rs +++ b/tests/ui/unwrap.rs @@ -1,4 +1,5 @@ #![warn(clippy::unwrap_used)] +#![allow(clippy::unnecessary_literal_unwrap)] fn unwrap_option() { let opt = Some(0); diff --git a/tests/ui/unwrap.stderr b/tests/ui/unwrap.stderr index d49bf2b32283..3796d942ff9f 100644 --- a/tests/ui/unwrap.stderr +++ b/tests/ui/unwrap.stderr @@ -1,5 +1,5 @@ error: used `unwrap()` on an `Option` value - --> $DIR/unwrap.rs:5:13 + --> $DIR/unwrap.rs:6:13 | LL | let _ = opt.unwrap(); | ^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | let _ = opt.unwrap(); = note: `-D clippy::unwrap-used` implied by `-D warnings` error: used `unwrap()` on a `Result` value - --> $DIR/unwrap.rs:10:13 + --> $DIR/unwrap.rs:11:13 | LL | let _ = res.unwrap(); | ^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | let _ = res.unwrap(); = help: if you don't want to handle the `Err` case gracefully, consider using `expect()` to provide a better panic message error: used `unwrap_err()` on a `Result` value - --> $DIR/unwrap.rs:11:13 + --> $DIR/unwrap.rs:12:13 | LL | let _ = res.unwrap_err(); | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/unwrap_expect_used.rs b/tests/ui/unwrap_expect_used.rs index 9f27fef82494..7f57efc53c9c 100644 --- a/tests/ui/unwrap_expect_used.rs +++ b/tests/ui/unwrap_expect_used.rs @@ -1,4 +1,5 @@ #![warn(clippy::unwrap_used, clippy::expect_used)] +#![allow(clippy::unnecessary_literal_unwrap)] trait OptionExt { type Item; diff --git a/tests/ui/unwrap_expect_used.stderr b/tests/ui/unwrap_expect_used.stderr index fe4ecef11453..1a551ab5ab8e 100644 --- a/tests/ui/unwrap_expect_used.stderr +++ b/tests/ui/unwrap_expect_used.stderr @@ -1,5 +1,5 @@ error: used `unwrap()` on an `Option` value - --> $DIR/unwrap_expect_used.rs:23:5 + --> $DIR/unwrap_expect_used.rs:24:5 | LL | Some(3).unwrap(); | ^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | Some(3).unwrap(); = note: `-D clippy::unwrap-used` implied by `-D warnings` error: used `expect()` on an `Option` value - --> $DIR/unwrap_expect_used.rs:24:5 + --> $DIR/unwrap_expect_used.rs:25:5 | LL | Some(3).expect("Hello world!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | Some(3).expect("Hello world!"); = note: `-D clippy::expect-used` implied by `-D warnings` error: used `unwrap()` on a `Result` value - --> $DIR/unwrap_expect_used.rs:31:5 + --> $DIR/unwrap_expect_used.rs:32:5 | LL | a.unwrap(); | ^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | a.unwrap(); = help: if this value is an `Err`, it will panic error: used `expect()` on a `Result` value - --> $DIR/unwrap_expect_used.rs:32:5 + --> $DIR/unwrap_expect_used.rs:33:5 | LL | a.expect("Hello world!"); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | a.expect("Hello world!"); = help: if this value is an `Err`, it will panic error: used `unwrap_err()` on a `Result` value - --> $DIR/unwrap_expect_used.rs:33:5 + --> $DIR/unwrap_expect_used.rs:34:5 | LL | a.unwrap_err(); | ^^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ LL | a.unwrap_err(); = help: if this value is an `Ok`, it will panic error: used `expect_err()` on a `Result` value - --> $DIR/unwrap_expect_used.rs:34:5 + --> $DIR/unwrap_expect_used.rs:35:5 | LL | a.expect_err("Hello error!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/unwrap_or.rs b/tests/ui/unwrap_or.rs index a0c003f5b1ea..5bea85e66924 100644 --- a/tests/ui/unwrap_or.rs +++ b/tests/ui/unwrap_or.rs @@ -1,4 +1,5 @@ #![warn(clippy::all, clippy::or_fun_call)] +#![allow(clippy::unnecessary_literal_unwrap)] fn main() { let s = Some(String::from("test string")).unwrap_or("Fail".to_string()).len(); diff --git a/tests/ui/unwrap_or.stderr b/tests/ui/unwrap_or.stderr index c3a7464fd470..cf720eaaf052 100644 --- a/tests/ui/unwrap_or.stderr +++ b/tests/ui/unwrap_or.stderr @@ -1,5 +1,5 @@ error: use of `unwrap_or` followed by a function call - --> $DIR/unwrap_or.rs:4:47 + --> $DIR/unwrap_or.rs:5:47 | LL | let s = Some(String::from("test string")).unwrap_or("Fail".to_string()).len(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "Fail".to_string())` @@ -7,7 +7,7 @@ LL | let s = Some(String::from("test string")).unwrap_or("Fail".to_string()) = note: `-D clippy::or-fun-call` implied by `-D warnings` error: use of `unwrap_or` followed by a function call - --> $DIR/unwrap_or.rs:8:47 + --> $DIR/unwrap_or.rs:9:47 | LL | let s = Some(String::from("test string")).unwrap_or("Fail".to_string()).len(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "Fail".to_string())` diff --git a/tests/ui/unwrap_or_else_default.fixed b/tests/ui/unwrap_or_else_default.fixed index 59a0ca3f192f..08b89a18bbbd 100644 --- a/tests/ui/unwrap_or_else_default.fixed +++ b/tests/ui/unwrap_or_else_default.fixed @@ -2,7 +2,7 @@ #![warn(clippy::unwrap_or_else_default)] #![allow(dead_code)] -#![allow(clippy::unnecessary_wraps)] +#![allow(clippy::unnecessary_wraps, clippy::unnecessary_literal_unwrap)] /// Checks implementation of the `UNWRAP_OR_ELSE_DEFAULT` lint. fn unwrap_or_else_default() { diff --git a/tests/ui/unwrap_or_else_default.rs b/tests/ui/unwrap_or_else_default.rs index 97cafa336eda..ad2a744908fc 100644 --- a/tests/ui/unwrap_or_else_default.rs +++ b/tests/ui/unwrap_or_else_default.rs @@ -2,7 +2,7 @@ #![warn(clippy::unwrap_or_else_default)] #![allow(dead_code)] -#![allow(clippy::unnecessary_wraps)] +#![allow(clippy::unnecessary_wraps, clippy::unnecessary_literal_unwrap)] /// Checks implementation of the `UNWRAP_OR_ELSE_DEFAULT` lint. fn unwrap_or_else_default() { diff --git a/tests/ui/update-all-references.sh b/tests/ui/update-all-references.sh index 4391499a1e1f..d42043070261 100755 --- a/tests/ui/update-all-references.sh +++ b/tests/ui/update-all-references.sh @@ -1,3 +1,3 @@ #!/bin/bash -echo "Please use 'cargo dev bless' instead." +echo "Please use 'cargo bless' instead." diff --git a/tests/ui/use_self.fixed b/tests/ui/use_self.fixed index 89ea14759b7d..4179f21c5100 100644 --- a/tests/ui/use_self.fixed +++ b/tests/ui/use_self.fixed @@ -1,5 +1,5 @@ //@run-rustfix -//@aux-build:proc_macro_derive.rs +//@aux-build:proc_macro_derive.rs:proc-macro #![warn(clippy::use_self)] #![allow(dead_code, unreachable_code)] diff --git a/tests/ui/use_self.rs b/tests/ui/use_self.rs index 49e5bcb7ed96..01a36def9e97 100644 --- a/tests/ui/use_self.rs +++ b/tests/ui/use_self.rs @@ -1,5 +1,5 @@ //@run-rustfix -//@aux-build:proc_macro_derive.rs +//@aux-build:proc_macro_derive.rs:proc-macro #![warn(clippy::use_self)] #![allow(dead_code, unreachable_code)] diff --git a/tests/ui/used_underscore_binding.rs b/tests/ui/used_underscore_binding.rs index c672eff1c271..879e2e24ab34 100644 --- a/tests/ui/used_underscore_binding.rs +++ b/tests/ui/used_underscore_binding.rs @@ -1,4 +1,4 @@ -//@aux-build:proc_macro_derive.rs +//@aux-build:proc_macro_derive.rs:proc-macro #![feature(rustc_private)] #![warn(clippy::all)] #![warn(clippy::used_underscore_binding)] diff --git a/tests/ui/useless_attribute.fixed b/tests/ui/useless_attribute.fixed index de6660c95e6e..8e77ec444b52 100644 --- a/tests/ui/useless_attribute.fixed +++ b/tests/ui/useless_attribute.fixed @@ -1,5 +1,5 @@ //@run-rustfix -//@aux-build:proc_macro_derive.rs +//@aux-build:proc_macro_derive.rs:proc-macro #![allow(unused)] #![warn(clippy::useless_attribute)] diff --git a/tests/ui/useless_attribute.rs b/tests/ui/useless_attribute.rs index 8de4331e8a69..27498d9bc132 100644 --- a/tests/ui/useless_attribute.rs +++ b/tests/ui/useless_attribute.rs @@ -1,5 +1,5 @@ //@run-rustfix -//@aux-build:proc_macro_derive.rs +//@aux-build:proc_macro_derive.rs:proc-macro #![allow(unused)] #![warn(clippy::useless_attribute)] diff --git a/tests/ui/useless_conversion.fixed b/tests/ui/useless_conversion.fixed index c16caa38fe93..5d2c5b11658e 100644 --- a/tests/ui/useless_conversion.fixed +++ b/tests/ui/useless_conversion.fixed @@ -1,7 +1,7 @@ //@run-rustfix #![deny(clippy::useless_conversion)] -#![allow(clippy::unnecessary_wraps)] +#![allow(clippy::needless_if, clippy::unnecessary_wraps)] fn test_generic(val: T) -> T { let _ = val; @@ -155,6 +155,35 @@ fn main() { let _ = vec![s4, s4, s4].into_iter(); } +#[allow(dead_code)] +fn explicit_into_iter_fn_arg() { + fn a(_: T) {} + fn b>(_: T) {} + fn c(_: impl IntoIterator) {} + fn d(_: T) + where + T: IntoIterator, + { + } + fn f(_: std::vec::IntoIter) {} + + a(vec![1, 2].into_iter()); + b(vec![1, 2]); + c(vec![1, 2]); + d(vec![1, 2]); + b([&1, &2, &3].into_iter().cloned()); + + b(vec![1, 2]); + b(vec![1, 2]); + + macro_rules! macro_generated { + () => { + vec![1, 2].into_iter() + }; + } + b(macro_generated!()); +} + #[derive(Copy, Clone)] struct Foo; diff --git a/tests/ui/useless_conversion.rs b/tests/ui/useless_conversion.rs index c75a2bce4ca2..03a3e3f95ba4 100644 --- a/tests/ui/useless_conversion.rs +++ b/tests/ui/useless_conversion.rs @@ -1,7 +1,7 @@ //@run-rustfix #![deny(clippy::useless_conversion)] -#![allow(clippy::unnecessary_wraps)] +#![allow(clippy::needless_if, clippy::unnecessary_wraps)] fn test_generic(val: T) -> T { let _ = T::from(val); @@ -155,6 +155,35 @@ fn main() { let _ = vec![s4, s4, s4].into_iter().into_iter(); } +#[allow(dead_code)] +fn explicit_into_iter_fn_arg() { + fn a(_: T) {} + fn b>(_: T) {} + fn c(_: impl IntoIterator) {} + fn d(_: T) + where + T: IntoIterator, + { + } + fn f(_: std::vec::IntoIter) {} + + a(vec![1, 2].into_iter()); + b(vec![1, 2].into_iter()); + c(vec![1, 2].into_iter()); + d(vec![1, 2].into_iter()); + b([&1, &2, &3].into_iter().cloned()); + + b(vec![1, 2].into_iter().into_iter()); + b(vec![1, 2].into_iter().into_iter().into_iter()); + + macro_rules! macro_generated { + () => { + vec![1, 2].into_iter() + }; + } + b(macro_generated!()); +} + #[derive(Copy, Clone)] struct Foo; diff --git a/tests/ui/useless_conversion.stderr b/tests/ui/useless_conversion.stderr index 4dca3aac5336..4957f73a469a 100644 --- a/tests/ui/useless_conversion.stderr +++ b/tests/ui/useless_conversion.stderr @@ -118,5 +118,65 @@ error: useless conversion to the same type: `std::vec::IntoIter>` LL | let _ = vec![s4, s4, s4].into_iter().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![s4, s4, s4].into_iter()` -error: aborting due to 19 previous errors +error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` + --> $DIR/useless_conversion.rs:171:7 + | +LL | b(vec![1, 2].into_iter()); + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `vec![1, 2]` + | +note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` + --> $DIR/useless_conversion.rs:161:13 + | +LL | fn b>(_: T) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` + --> $DIR/useless_conversion.rs:172:7 + | +LL | c(vec![1, 2].into_iter()); + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `vec![1, 2]` + | +note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` + --> $DIR/useless_conversion.rs:162:18 + | +LL | fn c(_: impl IntoIterator) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` + --> $DIR/useless_conversion.rs:173:7 + | +LL | d(vec![1, 2].into_iter()); + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`: `vec![1, 2]` + | +note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` + --> $DIR/useless_conversion.rs:165:12 + | +LL | T: IntoIterator, + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` + --> $DIR/useless_conversion.rs:176:7 + | +LL | b(vec![1, 2].into_iter().into_iter()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`s: `vec![1, 2]` + | +note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` + --> $DIR/useless_conversion.rs:161:13 + | +LL | fn b>(_: T) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` + --> $DIR/useless_conversion.rs:177:7 + | +LL | b(vec![1, 2].into_iter().into_iter().into_iter()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing the `.into_iter()`s: `vec![1, 2]` + | +note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` + --> $DIR/useless_conversion.rs:161:13 + | +LL | fn b>(_: T) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 24 previous errors diff --git a/tests/ui/useless_conversion_try.rs b/tests/ui/useless_conversion_try.rs index 4acf5b5fa2d1..ec0512ce210b 100644 --- a/tests/ui/useless_conversion_try.rs +++ b/tests/ui/useless_conversion_try.rs @@ -1,4 +1,5 @@ #![deny(clippy::useless_conversion)] +#![allow(clippy::needless_if)] fn test_generic(val: T) -> T { let _ = T::try_from(val).unwrap(); diff --git a/tests/ui/useless_conversion_try.stderr b/tests/ui/useless_conversion_try.stderr index 9aef9dda6f68..54189f8d2860 100644 --- a/tests/ui/useless_conversion_try.stderr +++ b/tests/ui/useless_conversion_try.stderr @@ -1,5 +1,5 @@ error: useless conversion to the same type: `T` - --> $DIR/useless_conversion_try.rs:4:13 + --> $DIR/useless_conversion_try.rs:5:13 | LL | let _ = T::try_from(val).unwrap(); | ^^^^^^^^^^^^^^^^ @@ -12,7 +12,7 @@ LL | #![deny(clippy::useless_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: useless conversion to the same type: `T` - --> $DIR/useless_conversion_try.rs:5:5 + --> $DIR/useless_conversion_try.rs:6:5 | LL | val.try_into().unwrap() | ^^^^^^^^^^^^^^ @@ -20,7 +20,7 @@ LL | val.try_into().unwrap() = help: consider removing `.try_into()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion_try.rs:27:21 + --> $DIR/useless_conversion_try.rs:28:21 | LL | let _: String = "foo".to_string().try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -28,7 +28,7 @@ LL | let _: String = "foo".to_string().try_into().unwrap(); = help: consider removing `.try_into()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion_try.rs:28:21 + --> $DIR/useless_conversion_try.rs:29:21 | LL | let _: String = TryFrom::try_from("foo".to_string()).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -36,7 +36,7 @@ LL | let _: String = TryFrom::try_from("foo".to_string()).unwrap(); = help: consider removing `TryFrom::try_from()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion_try.rs:29:13 + --> $DIR/useless_conversion_try.rs:30:13 | LL | let _ = String::try_from("foo".to_string()).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -44,7 +44,7 @@ LL | let _ = String::try_from("foo".to_string()).unwrap(); = help: consider removing `String::try_from()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion_try.rs:30:13 + --> $DIR/useless_conversion_try.rs:31:13 | LL | let _ = String::try_from(format!("A: {:04}", 123)).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -52,7 +52,7 @@ LL | let _ = String::try_from(format!("A: {:04}", 123)).unwrap(); = help: consider removing `String::try_from()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion_try.rs:31:21 + --> $DIR/useless_conversion_try.rs:32:21 | LL | let _: String = format!("Hello {}", "world").try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -60,7 +60,7 @@ LL | let _: String = format!("Hello {}", "world").try_into().unwrap(); = help: consider removing `.try_into()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion_try.rs:32:21 + --> $DIR/useless_conversion_try.rs:33:21 | LL | let _: String = String::new().try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -68,7 +68,7 @@ LL | let _: String = String::new().try_into().unwrap(); = help: consider removing `.try_into()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion_try.rs:33:27 + --> $DIR/useless_conversion_try.rs:34:27 | LL | let _: String = match String::from("_").try_into() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/vec.fixed b/tests/ui/vec.fixed index d77a4dd8e0b0..fcdc917c1b13 100644 --- a/tests/ui/vec.fixed +++ b/tests/ui/vec.fixed @@ -1,9 +1,12 @@ //@run-rustfix #![warn(clippy::useless_vec)] -#![allow(clippy::nonstandard_macro_braces, clippy::uninlined_format_args)] +#![allow(clippy::nonstandard_macro_braces, clippy::uninlined_format_args, unused)] -#[derive(Debug)] -struct NonCopy; +use std::rc::Rc; + +struct StructWithVec { + _x: Vec, +} fn on_slice(_: &[u8]) {} @@ -60,14 +63,6 @@ fn main() { on_mut_slice(&mut vec![2; line.length]); on_mut_slice(&mut vec![2; line.length()]); - for a in &[1, 2, 3] { - println!("{:?}", a); - } - - for a in vec![NonCopy, NonCopy] { - println!("{:?}", a); - } - on_vec(&vec![1; 201]); // Ok, size of `vec` higher than `too_large_for_stack` on_mut_vec(&mut vec![1; 201]); // Ok, size of `vec` higher than `too_large_for_stack` @@ -75,4 +70,69 @@ fn main() { for a in vec![1; 201] { println!("{:?}", a); } + + // https://github.com/rust-lang/rust-clippy/issues/2262#issuecomment-783979246 + let _x: i32 = [1, 2, 3].iter().sum(); + + // Do lint + let mut x = [1, 2, 3]; + x.fill(123); + dbg!(x[0]); + dbg!(x.len()); + dbg!(x.iter().sum::()); + + let _x: &[i32] = &[1, 2, 3]; + + for _ in [1, 2, 3] {} + + // Don't lint + let x = vec![1, 2, 3]; + let _v: Vec = x; + + let x = vec![1, 2, 3]; + let _s = StructWithVec { _x: x }; + + // Explicit type annotation would make the change to [1, 2, 3] + // a compile error. + let _x: Vec = vec![1, 2, 3]; + + // Calling a Vec method through a mutable reference + let mut x = vec![1, 2, 3]; + let re = &mut x; + re.push(4); + + // Comparing arrays whose length is not equal is a compile error + let x = vec![1, 2, 3]; + let y = vec![1, 2, 3, 4]; + dbg!(x == y); + + // Non-copy types + let _x = vec![String::new(); 10]; + #[allow(clippy::rc_clone_in_vec_init)] + let _x = vec![Rc::new(1); 10]; + + // Too large + let _x = vec![1; 201]; +} + +#[clippy::msrv = "1.53"] +fn above() { + for a in [1, 2, 3] { + let _: usize = a; + } + + for a in [String::new(), String::new()] { + let _: String = a; + } +} + +#[clippy::msrv = "1.52"] +fn below() { + for a in vec![1, 2, 3] { + let _: usize = a; + } + + for a in vec![String::new(), String::new()] { + let _: String = a; + } } diff --git a/tests/ui/vec.rs b/tests/ui/vec.rs index dfed3a29a03e..0404d8cdb842 100644 --- a/tests/ui/vec.rs +++ b/tests/ui/vec.rs @@ -1,9 +1,12 @@ //@run-rustfix #![warn(clippy::useless_vec)] -#![allow(clippy::nonstandard_macro_braces, clippy::uninlined_format_args)] +#![allow(clippy::nonstandard_macro_braces, clippy::uninlined_format_args, unused)] -#[derive(Debug)] -struct NonCopy; +use std::rc::Rc; + +struct StructWithVec { + _x: Vec, +} fn on_slice(_: &[u8]) {} @@ -60,14 +63,6 @@ fn main() { on_mut_slice(&mut vec![2; line.length]); on_mut_slice(&mut vec![2; line.length()]); - for a in vec![1, 2, 3] { - println!("{:?}", a); - } - - for a in vec![NonCopy, NonCopy] { - println!("{:?}", a); - } - on_vec(&vec![1; 201]); // Ok, size of `vec` higher than `too_large_for_stack` on_mut_vec(&mut vec![1; 201]); // Ok, size of `vec` higher than `too_large_for_stack` @@ -75,4 +70,69 @@ fn main() { for a in vec![1; 201] { println!("{:?}", a); } + + // https://github.com/rust-lang/rust-clippy/issues/2262#issuecomment-783979246 + let _x: i32 = vec![1, 2, 3].iter().sum(); + + // Do lint + let mut x = vec![1, 2, 3]; + x.fill(123); + dbg!(x[0]); + dbg!(x.len()); + dbg!(x.iter().sum::()); + + let _x: &[i32] = &vec![1, 2, 3]; + + for _ in vec![1, 2, 3] {} + + // Don't lint + let x = vec![1, 2, 3]; + let _v: Vec = x; + + let x = vec![1, 2, 3]; + let _s = StructWithVec { _x: x }; + + // Explicit type annotation would make the change to [1, 2, 3] + // a compile error. + let _x: Vec = vec![1, 2, 3]; + + // Calling a Vec method through a mutable reference + let mut x = vec![1, 2, 3]; + let re = &mut x; + re.push(4); + + // Comparing arrays whose length is not equal is a compile error + let x = vec![1, 2, 3]; + let y = vec![1, 2, 3, 4]; + dbg!(x == y); + + // Non-copy types + let _x = vec![String::new(); 10]; + #[allow(clippy::rc_clone_in_vec_init)] + let _x = vec![Rc::new(1); 10]; + + // Too large + let _x = vec![1; 201]; +} + +#[clippy::msrv = "1.53"] +fn above() { + for a in vec![1, 2, 3] { + let _: usize = a; + } + + for a in vec![String::new(), String::new()] { + let _: String = a; + } +} + +#[clippy::msrv = "1.52"] +fn below() { + for a in vec![1, 2, 3] { + let _: usize = a; + } + + for a in vec![String::new(), String::new()] { + let _: String = a; + } } diff --git a/tests/ui/vec.stderr b/tests/ui/vec.stderr index 7d1de05a5c83..33d565b2d525 100644 --- a/tests/ui/vec.stderr +++ b/tests/ui/vec.stderr @@ -1,5 +1,5 @@ error: useless use of `vec!` - --> $DIR/vec.rs:28:14 + --> $DIR/vec.rs:31:14 | LL | on_slice(&vec![]); | ^^^^^^^ help: you can use a slice directly: `&[]` @@ -7,64 +7,94 @@ LL | on_slice(&vec![]); = note: `-D clippy::useless-vec` implied by `-D warnings` error: useless use of `vec!` - --> $DIR/vec.rs:30:18 + --> $DIR/vec.rs:33:18 | LL | on_mut_slice(&mut vec![]); | ^^^^^^^^^^^ help: you can use a slice directly: `&mut []` error: useless use of `vec!` - --> $DIR/vec.rs:32:14 + --> $DIR/vec.rs:35:14 | LL | on_slice(&vec![1, 2]); | ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]` error: useless use of `vec!` - --> $DIR/vec.rs:34:18 + --> $DIR/vec.rs:37:18 | LL | on_mut_slice(&mut vec![1, 2]); | ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1, 2]` error: useless use of `vec!` - --> $DIR/vec.rs:36:14 + --> $DIR/vec.rs:39:14 | LL | on_slice(&vec![1, 2]); | ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]` error: useless use of `vec!` - --> $DIR/vec.rs:38:18 + --> $DIR/vec.rs:41:18 | LL | on_mut_slice(&mut vec![1, 2]); | ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1, 2]` error: useless use of `vec!` - --> $DIR/vec.rs:40:14 + --> $DIR/vec.rs:43:14 | LL | on_slice(&vec!(1, 2)); | ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]` error: useless use of `vec!` - --> $DIR/vec.rs:42:18 + --> $DIR/vec.rs:45:18 | LL | on_mut_slice(&mut vec![1, 2]); | ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1, 2]` error: useless use of `vec!` - --> $DIR/vec.rs:44:14 + --> $DIR/vec.rs:47:14 | LL | on_slice(&vec![1; 2]); | ^^^^^^^^^^^ help: you can use a slice directly: `&[1; 2]` error: useless use of `vec!` - --> $DIR/vec.rs:46:18 + --> $DIR/vec.rs:49:18 | LL | on_mut_slice(&mut vec![1; 2]); | ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1; 2]` error: useless use of `vec!` - --> $DIR/vec.rs:63:14 + --> $DIR/vec.rs:75:19 + | +LL | let _x: i32 = vec![1, 2, 3].iter().sum(); + | ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]` + +error: useless use of `vec!` + --> $DIR/vec.rs:78:17 + | +LL | let mut x = vec![1, 2, 3]; + | ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]` + +error: useless use of `vec!` + --> $DIR/vec.rs:84:22 + | +LL | let _x: &[i32] = &vec![1, 2, 3]; + | ^^^^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2, 3]` + +error: useless use of `vec!` + --> $DIR/vec.rs:86:14 + | +LL | for _ in vec![1, 2, 3] {} + | ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]` + +error: useless use of `vec!` + --> $DIR/vec.rs:120:14 | LL | for a in vec![1, 2, 3] { - | ^^^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2, 3]` + | ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]` -error: aborting due to 11 previous errors +error: useless use of `vec!` + --> $DIR/vec.rs:124:14 + | +LL | for a in vec![String::new(), String::new()] { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can use an array directly: `[String::new(), String::new()]` + +error: aborting due to 16 previous errors diff --git a/tests/ui/while_let_on_iterator.fixed b/tests/ui/while_let_on_iterator.fixed index c2f216a8911c..41a380ab8f6a 100644 --- a/tests/ui/while_let_on_iterator.fixed +++ b/tests/ui/while_let_on_iterator.fixed @@ -6,7 +6,9 @@ clippy::manual_find, clippy::never_loop, clippy::redundant_closure_call, - clippy::uninlined_format_args + clippy::single_range_in_vec_init, + clippy::uninlined_format_args, + clippy::useless_vec )] fn base() { diff --git a/tests/ui/while_let_on_iterator.rs b/tests/ui/while_let_on_iterator.rs index 971bd5f0c4a8..4c6433880b63 100644 --- a/tests/ui/while_let_on_iterator.rs +++ b/tests/ui/while_let_on_iterator.rs @@ -6,7 +6,9 @@ clippy::manual_find, clippy::never_loop, clippy::redundant_closure_call, - clippy::uninlined_format_args + clippy::single_range_in_vec_init, + clippy::uninlined_format_args, + clippy::useless_vec )] fn base() { diff --git a/tests/ui/while_let_on_iterator.stderr b/tests/ui/while_let_on_iterator.stderr index 4d98666190d6..3236765e1db0 100644 --- a/tests/ui/while_let_on_iterator.stderr +++ b/tests/ui/while_let_on_iterator.stderr @@ -1,5 +1,5 @@ error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:14:5 + --> $DIR/while_let_on_iterator.rs:16:5 | LL | while let Option::Some(x) = iter.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in iter` @@ -7,151 +7,151 @@ LL | while let Option::Some(x) = iter.next() { = note: `-D clippy::while-let-on-iterator` implied by `-D warnings` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:19:5 + --> $DIR/while_let_on_iterator.rs:21:5 | LL | while let Some(x) = iter.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in iter` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:24:5 + --> $DIR/while_let_on_iterator.rs:26:5 | LL | while let Some(_) = iter.next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in iter` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:100:9 + --> $DIR/while_let_on_iterator.rs:102:9 | LL | while let Some([..]) = it.next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [..] in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:107:9 + --> $DIR/while_let_on_iterator.rs:109:9 | LL | while let Some([_x]) = it.next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [_x] in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:120:9 + --> $DIR/while_let_on_iterator.rs:122:9 | LL | while let Some(x @ [_]) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x @ [_] in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:140:9 + --> $DIR/while_let_on_iterator.rs:142:9 | LL | while let Some(_) = y.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in y` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:197:9 + --> $DIR/while_let_on_iterator.rs:199:9 | LL | while let Some(m) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:208:5 + --> $DIR/while_let_on_iterator.rs:210:5 | LL | while let Some(n) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for n in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:210:9 + --> $DIR/while_let_on_iterator.rs:212:9 | LL | while let Some(m) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:219:9 + --> $DIR/while_let_on_iterator.rs:221:9 | LL | while let Some(m) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:228:9 + --> $DIR/while_let_on_iterator.rs:230:9 | LL | while let Some(m) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:245:9 + --> $DIR/while_let_on_iterator.rs:247:9 | LL | while let Some(m) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:260:13 + --> $DIR/while_let_on_iterator.rs:262:13 | LL | while let Some(i) = self.0.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for i in self.0.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:292:13 + --> $DIR/while_let_on_iterator.rs:294:13 | LL | while let Some(i) = self.0.0.0.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for i in self.0.0.0.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:321:5 + --> $DIR/while_let_on_iterator.rs:323:5 | LL | while let Some(n) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for n in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:333:9 + --> $DIR/while_let_on_iterator.rs:335:9 | LL | while let Some(x) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:347:5 + --> $DIR/while_let_on_iterator.rs:349:5 | LL | while let Some(x) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:358:5 + --> $DIR/while_let_on_iterator.rs:360:5 | LL | while let Some(x) = it.0.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.0.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:393:5 + --> $DIR/while_let_on_iterator.rs:395:5 | LL | while let Some(x) = s.x.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in s.x.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:400:5 + --> $DIR/while_let_on_iterator.rs:402:5 | LL | while let Some(x) = x[0].next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in x[0].by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:408:9 + --> $DIR/while_let_on_iterator.rs:410:9 | LL | while let Some(x) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:418:9 + --> $DIR/while_let_on_iterator.rs:420:9 | LL | while let Some(x) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:428:9 + --> $DIR/while_let_on_iterator.rs:430:9 | LL | while let Some(x) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.by_ref()` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:438:9 + --> $DIR/while_let_on_iterator.rs:440:9 | LL | while let Some(x) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:448:5 + --> $DIR/while_let_on_iterator.rs:450:5 | LL | while let Some(..) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in it` diff --git a/tests/ui/wildcard_imports.fixed b/tests/ui/wildcard_imports.fixed index 733bbcfbcefa..2961b062ec37 100644 --- a/tests/ui/wildcard_imports.fixed +++ b/tests/ui/wildcard_imports.fixed @@ -211,7 +211,7 @@ mod super_imports { } mod use_explicit_should_be_replaced { - use super_imports::foofoo; + use crate::super_imports::foofoo; fn with_explicit() { let _ = foofoo(); diff --git a/tests/ui/wildcard_imports.rs b/tests/ui/wildcard_imports.rs index 4acdd374bdec..28508a2538b2 100644 --- a/tests/ui/wildcard_imports.rs +++ b/tests/ui/wildcard_imports.rs @@ -212,7 +212,7 @@ mod super_imports { } mod use_explicit_should_be_replaced { - use super_imports::*; + use crate::super_imports::*; fn with_explicit() { let _ = foofoo(); diff --git a/tests/ui/wildcard_imports.stderr b/tests/ui/wildcard_imports.stderr index 235be2d57081..c96b3041a005 100644 --- a/tests/ui/wildcard_imports.stderr +++ b/tests/ui/wildcard_imports.stderr @@ -107,8 +107,8 @@ LL | use super::*; error: usage of wildcard import --> $DIR/wildcard_imports.rs:215:13 | -LL | use super_imports::*; - | ^^^^^^^^^^^^^^^^ help: try: `super_imports::foofoo` +LL | use crate::super_imports::*; + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo` error: usage of wildcard import --> $DIR/wildcard_imports.rs:224:17 diff --git a/tests/ui/write_literal_2.rs b/tests/ui/write_literal_2.rs index 55a11daa1d34..805127e27500 100644 --- a/tests/ui/write_literal_2.rs +++ b/tests/ui/write_literal_2.rs @@ -1,5 +1,5 @@ #![allow(unused_must_use)] -#![warn(clippy::write_literal)] +#![warn(clippy::needless_raw_strings, clippy::write_literal)] use std::io::Write; diff --git a/tests/ui/write_literal_2.stderr b/tests/ui/write_literal_2.stderr index d5956db9ff0b..18591250aad9 100644 --- a/tests/ui/write_literal_2.stderr +++ b/tests/ui/write_literal_2.stderr @@ -1,3 +1,11 @@ +error: unnecessary raw string literal + --> $DIR/write_literal_2.rs:10:24 + | +LL | writeln!(v, r"{}", r"{hello}"); + | ^^^^^^^^^^ help: try: `"{hello}"` + | + = note: `-D clippy::needless-raw-strings` implied by `-D warnings` + error: literal with an empty format string --> $DIR/write_literal_2.rs:9:23 | @@ -87,7 +95,7 @@ LL | "1", "2", "3", help: try this | LL ~ "some 1/ -LL ~ {} / {}", "2", "3", +LL ~ {} // {}", "2", "3", | error: literal with an empty format string @@ -98,7 +106,7 @@ LL | "1", "2", "3", | help: try this | -LL ~ 2 / {}", +LL ~ 2 // {}", LL ~ "1", "3", | @@ -110,43 +118,43 @@ LL | "1", "2", "3", | help: try this | -LL ~ {} / 3", +LL ~ {} // 3", LL ~ "1", "2", | error: literal with an empty format string --> $DIR/write_literal_2.rs:27:23 | -LL | writeln!(v, "{}", "/"); +LL | writeln!(v, "{}", "//"); | ^^^^ | help: try this | -LL - writeln!(v, "{}", "/"); -LL + writeln!(v, "/"); +LL - writeln!(v, "{}", "//"); +LL + writeln!(v, "//"); | error: literal with an empty format string --> $DIR/write_literal_2.rs:28:24 | -LL | writeln!(v, r"{}", "/"); +LL | writeln!(v, r"{}", "//"); | ^^^^ | help: try this | -LL - writeln!(v, r"{}", "/"); +LL - writeln!(v, r"{}", "//"); LL + writeln!(v, r"/"); | error: literal with an empty format string --> $DIR/write_literal_2.rs:29:26 | -LL | writeln!(v, r#"{}"#, "/"); +LL | writeln!(v, r#"{}"#, "//"); | ^^^^ | help: try this | -LL - writeln!(v, r#"{}"#, "/"); +LL - writeln!(v, r#"{}"#, "//"); LL + writeln!(v, r#"/"#); | @@ -159,7 +167,7 @@ LL | writeln!(v, "{}", r"/"); help: try this | LL - writeln!(v, "{}", r"/"); -LL + writeln!(v, "/"); +LL + writeln!(v, "//"); | error: literal with an empty format string @@ -186,5 +194,5 @@ error: literal with an empty format string LL | writeln!(v, r#"{}{}"#, '#', '"'); // hard mode | ^^^ -error: aborting due to 17 previous errors +error: aborting due to 18 previous errors diff --git a/tests/ui/write_with_newline.fixed b/tests/ui/write_with_newline.fixed new file mode 100644 index 000000000000..0a10e526a2f5 --- /dev/null +++ b/tests/ui/write_with_newline.fixed @@ -0,0 +1,63 @@ +// FIXME: Ideally these suggestions would be fixed via rustfix. Blocked by rust-lang/rust#53934 +// //@run-rustfix + +#![allow(clippy::write_literal)] +#![warn(clippy::write_with_newline)] + +use std::io::Write; + +fn main() { + let mut v = Vec::new(); + + // These should fail + writeln!(v, "Hello"); + writeln!(v, "Hello {}", "world"); + writeln!(v, "Hello {} {}", "world", "#2"); + writeln!(v, "{}", 1265); + writeln!(v); + + // These should be fine + write!(v, ""); + write!(v, "Hello"); + writeln!(v, "Hello"); + writeln!(v, "Hello\n"); + writeln!(v, "Hello {}\n", "world"); + write!(v, "Issue\n{}", 1265); + write!(v, "{}", 1265); + write!(v, "\n{}", 1275); + write!(v, "\n\n"); + write!(v, "like eof\n\n"); + write!(v, "Hello {} {}\n\n", "world", "#2"); + writeln!(v, "\ndon't\nwarn\nfor\nmultiple\nnewlines\n"); // #3126 + writeln!(v, "\nbla\n\n"); // #3126 + + // Escaping + write!(v, "\\n"); // #3514 + writeln!(v, "\\"); // should fail + write!(v, "\\\\n"); + + // Raw strings + write!(v, r"\n"); // #3778 + + // Literal newlines should also fail + writeln!( + v + ); + writeln!( + v + ); + + // Don't warn on CRLF (#4208) + write!(v, "\r\n"); + write!(v, "foo\r\n"); + writeln!(v, "\\r"); // warns + write!(v, "foo\rbar\n"); + + // Ignore expanded format strings + macro_rules! newline { + () => { + "\n" + }; + } + write!(v, newline!()); +} diff --git a/tests/ui/write_with_newline.stderr b/tests/ui/write_with_newline.stderr index 9035275b29db..03a18a4dc3f3 100644 --- a/tests/ui/write_with_newline.stderr +++ b/tests/ui/write_with_newline.stderr @@ -62,13 +62,13 @@ LL + writeln!(v); error: using `write!()` with a format string that ends in a single newline --> $DIR/write_with_newline.rs:36:5 | -LL | write!(v, "//n"); // should fail +LL | write!(v, "///n"); // should fail | ^^^^^^^^^^^^^^^^^ | help: use `writeln!` instead | -LL - write!(v, "//n"); // should fail -LL + writeln!(v, "/"); // should fail +LL - write!(v, "///n"); // should fail +LL + writeln!(v, "//"); // should fail | error: using `write!()` with a format string that ends in a single newline @@ -106,13 +106,13 @@ LL ~ v error: using `write!()` with a format string that ends in a single newline --> $DIR/write_with_newline.rs:57:5 | -LL | write!(v, "/r/n"); +LL | write!(v, "//r/n"); | ^^^^^^^^^^^^^^^^^^ | help: use `writeln!` instead | -LL - write!(v, "/r/n"); -LL + writeln!(v, "/r"); +LL - write!(v, "//r/n"); +LL + writeln!(v, "//r"); | error: aborting due to 9 previous errors diff --git a/tests/workspace.rs b/tests/workspace.rs index c9cbc50546cf..699ab2be199a 100644 --- a/tests/workspace.rs +++ b/tests/workspace.rs @@ -6,6 +6,46 @@ use test_utils::{CARGO_CLIPPY_PATH, IS_RUSTC_TEST_SUITE}; mod test_utils; +#[test] +fn test_module_style_with_dep_in_subdir() { + if IS_RUSTC_TEST_SUITE { + return; + } + let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let target_dir = root.join("target").join("workspace_test"); + let cwd = root.join("tests/workspace_test"); + + // Make sure we start with a clean state + Command::new("cargo") + .current_dir(&cwd) + .env("CARGO_TARGET_DIR", &target_dir) + .arg("clean") + .args(["-p", "pass-no-mod-with-dep-in-subdir"]) + .args(["-p", "pass-mod-with-dep-in-subdir"]) + .output() + .unwrap(); + + // [#8887](https://github.com/rust-lang/rust-clippy/issues/8887) + // `mod.rs` checks should not be applied to crate dependencies + // located in the subdirectory of workspace + let output = Command::new(&*CARGO_CLIPPY_PATH) + .current_dir(&cwd) + .env("CARGO_INCREMENTAL", "0") + .env("CARGO_TARGET_DIR", &target_dir) + .arg("clippy") + .args(["-p", "pass-no-mod-with-dep-in-subdir"]) + .args(["-p", "pass-mod-with-dep-in-subdir"]) + .arg("--") + .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir + .output() + .unwrap(); + + println!("status: {}", output.status); + println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); + println!("stderr: {}", String::from_utf8_lossy(&output.stderr)); + assert!(output.status.success()); +} + #[test] fn test_no_deps_ignores_path_deps_in_workspaces() { if IS_RUSTC_TEST_SUITE { diff --git a/tests/workspace_test/Cargo.toml b/tests/workspace_test/Cargo.toml index bf5b4ca5288a..d24b278ccc28 100644 --- a/tests/workspace_test/Cargo.toml +++ b/tests/workspace_test/Cargo.toml @@ -4,4 +4,4 @@ version = "0.1.0" edition = "2018" [workspace] -members = ["subcrate"] +members = ["subcrate", "module_style/pass_no_mod_with_dep_in_subdir", "module_style/pass_mod_with_dep_in_subdir"] diff --git a/tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/Cargo.toml b/tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/Cargo.toml new file mode 100644 index 000000000000..15dcde4e30a1 --- /dev/null +++ b/tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "pass-mod-with-dep-in-subdir" +version = "0.1.0" +edition = "2018" +publish = false + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +dep-no-mod = { path = "dep_no_mod"} diff --git a/tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/dep_no_mod/Cargo.toml b/tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/dep_no_mod/Cargo.toml new file mode 100644 index 000000000000..55569bc25ed7 --- /dev/null +++ b/tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/dep_no_mod/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "dep-no-mod" +version = "0.1.0" +edition = "2018" +publish = false + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/dep_no_mod/src/foo.rs b/tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/dep_no_mod/src/foo.rs new file mode 100644 index 000000000000..7b0966a45867 --- /dev/null +++ b/tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/dep_no_mod/src/foo.rs @@ -0,0 +1,2 @@ +pub mod hello; +pub struct Thing; diff --git a/tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/dep_no_mod/src/foo/hello.rs b/tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/dep_no_mod/src/foo/hello.rs new file mode 100644 index 000000000000..99940dce528a --- /dev/null +++ b/tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/dep_no_mod/src/foo/hello.rs @@ -0,0 +1 @@ +pub struct Hello; diff --git a/tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/dep_no_mod/src/lib.rs b/tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/dep_no_mod/src/lib.rs new file mode 100644 index 000000000000..c62f9acbf2cb --- /dev/null +++ b/tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/dep_no_mod/src/lib.rs @@ -0,0 +1,5 @@ +pub mod foo; + +pub fn foo() { + let _ = foo::Thing; +} diff --git a/tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/src/bad/mod.rs b/tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/src/bad/mod.rs new file mode 100644 index 000000000000..f19ab10d5fb0 --- /dev/null +++ b/tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/src/bad/mod.rs @@ -0,0 +1 @@ +pub struct Thing; diff --git a/tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/src/main.rs b/tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/src/main.rs new file mode 100644 index 000000000000..5cb4795e9451 --- /dev/null +++ b/tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/src/main.rs @@ -0,0 +1,13 @@ +#![deny(clippy::self_named_module_files)] + +mod bad; +mod more; +extern crate dep_no_mod; + +fn main() { + let _ = bad::Thing; + let _ = more::foo::Foo; + let _ = more::inner::Inner; + let _ = dep_no_mod::foo::Thing; + let _ = dep_no_mod::foo::hello::Hello; +} diff --git a/tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/src/more/foo.rs b/tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/src/more/foo.rs new file mode 100644 index 000000000000..4a835673a596 --- /dev/null +++ b/tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/src/more/foo.rs @@ -0,0 +1 @@ +pub struct Foo; diff --git a/tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/src/more/inner/mod.rs b/tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/src/more/inner/mod.rs new file mode 100644 index 000000000000..aa84f78cc2ca --- /dev/null +++ b/tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/src/more/inner/mod.rs @@ -0,0 +1 @@ +pub struct Inner; diff --git a/tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/src/more/mod.rs b/tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/src/more/mod.rs new file mode 100644 index 000000000000..d79569f78ffb --- /dev/null +++ b/tests/workspace_test/module_style/pass_mod_with_dep_in_subdir/src/more/mod.rs @@ -0,0 +1,2 @@ +pub mod foo; +pub mod inner; diff --git a/tests/workspace_test/module_style/pass_no_mod_with_dep_in_subdir/Cargo.toml b/tests/workspace_test/module_style/pass_no_mod_with_dep_in_subdir/Cargo.toml new file mode 100644 index 000000000000..060cb18dc9f9 --- /dev/null +++ b/tests/workspace_test/module_style/pass_no_mod_with_dep_in_subdir/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "pass-no-mod-with-dep-in-subdir" +version = "0.1.0" +edition = "2018" +publish = false + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +dep-with-mod = { path = "dep_with_mod"} diff --git a/tests/workspace_test/module_style/pass_no_mod_with_dep_in_subdir/dep_with_mod/Cargo.toml b/tests/workspace_test/module_style/pass_no_mod_with_dep_in_subdir/dep_with_mod/Cargo.toml new file mode 100644 index 000000000000..b25725cd5610 --- /dev/null +++ b/tests/workspace_test/module_style/pass_no_mod_with_dep_in_subdir/dep_with_mod/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "dep-with-mod" +version = "0.1.0" +edition = "2018" +publish = false + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/tests/workspace_test/module_style/pass_no_mod_with_dep_in_subdir/dep_with_mod/src/lib.rs b/tests/workspace_test/module_style/pass_no_mod_with_dep_in_subdir/dep_with_mod/src/lib.rs new file mode 100644 index 000000000000..4647424f2c2f --- /dev/null +++ b/tests/workspace_test/module_style/pass_no_mod_with_dep_in_subdir/dep_with_mod/src/lib.rs @@ -0,0 +1,7 @@ +pub mod with_mod; + +pub fn foo() { + let _ = with_mod::Thing; + let _ = with_mod::inner::stuff::Inner; + let _ = with_mod::inner::stuff::most::Snarks; +} diff --git a/tests/workspace_test/module_style/pass_no_mod_with_dep_in_subdir/dep_with_mod/src/with_mod/inner.rs b/tests/workspace_test/module_style/pass_no_mod_with_dep_in_subdir/dep_with_mod/src/with_mod/inner.rs new file mode 100644 index 000000000000..91cd540a28fd --- /dev/null +++ b/tests/workspace_test/module_style/pass_no_mod_with_dep_in_subdir/dep_with_mod/src/with_mod/inner.rs @@ -0,0 +1 @@ +pub mod stuff; diff --git a/tests/workspace_test/module_style/pass_no_mod_with_dep_in_subdir/dep_with_mod/src/with_mod/inner/stuff.rs b/tests/workspace_test/module_style/pass_no_mod_with_dep_in_subdir/dep_with_mod/src/with_mod/inner/stuff.rs new file mode 100644 index 000000000000..7713fa9d35c4 --- /dev/null +++ b/tests/workspace_test/module_style/pass_no_mod_with_dep_in_subdir/dep_with_mod/src/with_mod/inner/stuff.rs @@ -0,0 +1,3 @@ +pub mod most; + +pub struct Inner; diff --git a/tests/workspace_test/module_style/pass_no_mod_with_dep_in_subdir/dep_with_mod/src/with_mod/inner/stuff/most.rs b/tests/workspace_test/module_style/pass_no_mod_with_dep_in_subdir/dep_with_mod/src/with_mod/inner/stuff/most.rs new file mode 100644 index 000000000000..5a5eaf9670f9 --- /dev/null +++ b/tests/workspace_test/module_style/pass_no_mod_with_dep_in_subdir/dep_with_mod/src/with_mod/inner/stuff/most.rs @@ -0,0 +1 @@ +pub struct Snarks; diff --git a/tests/workspace_test/module_style/pass_no_mod_with_dep_in_subdir/dep_with_mod/src/with_mod/mod.rs b/tests/workspace_test/module_style/pass_no_mod_with_dep_in_subdir/dep_with_mod/src/with_mod/mod.rs new file mode 100644 index 000000000000..a12734db7cb5 --- /dev/null +++ b/tests/workspace_test/module_style/pass_no_mod_with_dep_in_subdir/dep_with_mod/src/with_mod/mod.rs @@ -0,0 +1,3 @@ +pub mod inner; + +pub struct Thing; diff --git a/tests/workspace_test/module_style/pass_no_mod_with_dep_in_subdir/src/good.rs b/tests/workspace_test/module_style/pass_no_mod_with_dep_in_subdir/src/good.rs new file mode 100644 index 000000000000..f19ab10d5fb0 --- /dev/null +++ b/tests/workspace_test/module_style/pass_no_mod_with_dep_in_subdir/src/good.rs @@ -0,0 +1 @@ +pub struct Thing; diff --git a/tests/workspace_test/module_style/pass_no_mod_with_dep_in_subdir/src/main.rs b/tests/workspace_test/module_style/pass_no_mod_with_dep_in_subdir/src/main.rs new file mode 100644 index 000000000000..42eb99cd7a3e --- /dev/null +++ b/tests/workspace_test/module_style/pass_no_mod_with_dep_in_subdir/src/main.rs @@ -0,0 +1,9 @@ +#![deny(clippy::mod_module_files)] + +mod good; +pub use dep_with_mod::with_mod::Thing; + +fn main() { + let _ = good::Thing; + let _ = dep_with_mod::with_mod::Thing; +} diff --git a/util/etc/vscode-tasks.json b/util/etc/vscode-tasks.json index ab98f9b4154a..38e31b337a06 100644 --- a/util/etc/vscode-tasks.json +++ b/util/etc/vscode-tasks.json @@ -47,9 +47,9 @@ "group": "test" }, { - "label": "cargo dev bless", + "label": "bless ui tests", "type": "shell", - "command": "cargo dev bless", + "command": "cargo bless", "problemMatcher": [], "group": "none" } diff --git a/util/gh-pages/index.html b/util/gh-pages/index.html index 8791debad723..99e211654d19 100644 --- a/util/gh-pages/index.html +++ b/util/gh-pages/index.html @@ -501,9 +501,11 @@ Otherwise, have a great day =^.^=
- + - @@ -517,7 +519,8 @@ Otherwise, have a great day =^.^=

{{lint.id}} - + 📋 diff --git a/util/gh-pages/script.js b/util/gh-pages/script.js index 1c16ecd6b0b1..f59245e556cd 100644 --- a/util/gh-pages/script.js +++ b/util/gh-pages/script.js @@ -24,9 +24,9 @@ target.scrollIntoView(); } - function scrollToLintByURL($scope) { - var removeListener = $scope.$on('ngRepeatFinished', function(ngRepeatFinishedEvent) { - scrollToLint(window.location.hash.slice(1)); + function scrollToLintByURL($scope, $location) { + var removeListener = $scope.$on('ngRepeatFinished', function (ngRepeatFinishedEvent) { + scrollToLint($location.path().substring(1)); removeListener(); }); } @@ -106,10 +106,10 @@ } }; }) - .controller("lintList", function ($scope, $http, $timeout) { + .controller("lintList", function ($scope, $http, $location, $timeout) { // Level filter var LEVEL_FILTERS_DEFAULT = {allow: true, warn: true, deny: true, none: true}; - $scope.levels = LEVEL_FILTERS_DEFAULT; + $scope.levels = { ...LEVEL_FILTERS_DEFAULT }; $scope.byLevels = function (lint) { return $scope.levels[lint.level]; }; @@ -146,6 +146,165 @@ "=": {enabled: false, minorVersion: null }, }; + // Map the versionFilters to the query parameters in a way that is easier to work with in a URL + const versionFilterKeyMap = { + "≥": "gte", + "≤": "lte", + "=": "eq" + }; + const reverseVersionFilterKeyMap = Object.fromEntries( + Object.entries(versionFilterKeyMap).map(([key, value]) => [value, key]) + ); + + // loadFromURLParameters retrieves filter settings from the URL parameters and assigns them + // to corresponding $scope variables. + function loadFromURLParameters() { + // Extract parameters from URL + const urlParameters = $location.search(); + + // Define a helper function that assigns URL parameters to a provided scope variable + const handleParameter = (parameter, scopeVariable, defaultValues) => { + if (urlParameters[parameter]) { + const items = urlParameters[parameter].split(','); + for (const key in scopeVariable) { + if (scopeVariable.hasOwnProperty(key)) { + scopeVariable[key] = items.includes(key); + } + } + } else if (defaultValues) { + for (const key in defaultValues) { + if (scopeVariable.hasOwnProperty(key)) { + scopeVariable[key] = defaultValues[key]; + } + } + } + }; + + handleParameter('levels', $scope.levels, LEVEL_FILTERS_DEFAULT); + handleParameter('groups', $scope.groups, GROUPS_FILTER_DEFAULT); + + // Handle 'versions' parameter separately because it needs additional processing + if (urlParameters.versions) { + const versionFilters = urlParameters.versions.split(','); + for (const versionFilter of versionFilters) { + const [key, minorVersion] = versionFilter.split(':'); + const parsedMinorVersion = parseInt(minorVersion); + + // Map the key from the URL parameter to its original form + const originalKey = reverseVersionFilterKeyMap[key]; + + if (originalKey in $scope.versionFilters && !isNaN(parsedMinorVersion)) { + $scope.versionFilters[originalKey].enabled = true; + $scope.versionFilters[originalKey].minorVersion = parsedMinorVersion; + } + } + } + + // Load the search parameter from the URL path + const searchParameter = $location.path().substring(1); // Remove the leading slash + if (searchParameter) { + $scope.search = searchParameter; + $scope.open[searchParameter] = true; + scrollToLintByURL($scope, $location); + } + } + + // updateURLParameter updates the URL parameter with the given key to the given value + function updateURLParameter(filterObj, urlKey, defaultValue = {}, processFilter = filter => filter) { + const parameter = Object.keys(filterObj) + .filter(filter => filterObj[filter]) + .sort() + .map(processFilter) + .filter(Boolean) // Filters out any falsy values, including null + .join(','); + + const defaultParameter = Object.keys(defaultValue) + .filter(filter => defaultValue[filter]) + .sort() + .map(processFilter) + .filter(Boolean) // Filters out any falsy values, including null + .join(','); + + // if we ended up back at the defaults, just remove it from the URL + if (parameter === defaultParameter) { + $location.search(urlKey, null); + } else { + $location.search(urlKey, parameter || null); + } + } + + // updateVersionURLParameter updates the version URL parameter with the given version filters + function updateVersionURLParameter(versionFilters) { + updateURLParameter( + versionFilters, + 'versions', {}, + versionFilter => versionFilters[versionFilter].enabled && versionFilters[versionFilter].minorVersion != null + ? `${versionFilterKeyMap[versionFilter]}:${versionFilters[versionFilter].minorVersion}` + : null + ); + } + + // updateAllURLParameters updates all the URL parameters with the current filter settings + function updateAllURLParameters() { + updateURLParameter($scope.levels, 'levels', LEVEL_FILTERS_DEFAULT); + updateURLParameter($scope.groups, 'groups', GROUPS_FILTER_DEFAULT); + updateVersionURLParameter($scope.versionFilters); + } + + // Add $watches to automatically update URL parameters when the data changes + $scope.$watch('levels', function (newVal, oldVal) { + if (newVal !== oldVal) { + updateURLParameter(newVal, 'levels', LEVEL_FILTERS_DEFAULT); + } + }, true); + + $scope.$watch('groups', function (newVal, oldVal) { + if (newVal !== oldVal) { + updateURLParameter(newVal, 'groups', GROUPS_FILTER_DEFAULT); + } + }, true); + + $scope.$watch('versionFilters', function (newVal, oldVal) { + if (newVal !== oldVal) { + updateVersionURLParameter(newVal); + } + }, true); + + // Watch for changes in the URL path and update the search and lint display + $scope.$watch(function () { return $location.path(); }, function (newPath) { + const searchParameter = newPath.substring(1); + if ($scope.search !== searchParameter) { + $scope.search = searchParameter; + $scope.open[searchParameter] = true; + scrollToLintByURL($scope, $location); + } + }); + + let debounceTimeout; + $scope.$watch('search', function (newVal, oldVal) { + if (newVal !== oldVal) { + if (debounceTimeout) { + $timeout.cancel(debounceTimeout); + } + + debounceTimeout = $timeout(function () { + $location.path(newVal); + }, 1000); + } + }); + + $scope.$watch(function () { return $location.search(); }, function (newParameters) { + loadFromURLParameters(); + }, true); + + $scope.updatePath = function () { + if (debounceTimeout) { + $timeout.cancel(debounceTimeout); + } + + $location.path($scope.search); + } + $scope.selectTheme = function (theme) { setTheme(theme, true); } @@ -169,10 +328,9 @@ }; $scope.resetGroupsToDefault = function () { - const groups = $scope.groups; - for (const [key, value] of Object.entries(GROUPS_FILTER_DEFAULT)) { - groups[key] = value; - } + $scope.groups = { + ...GROUPS_FILTER_DEFAULT + }; }; $scope.selectedValuesCount = function (obj) { @@ -272,6 +430,12 @@ return true; } + // Show details for one lint + $scope.openLint = function (lint) { + $scope.open[lint.id] = true; + $location.path(lint.id); + }; + $scope.copyToClipboard = function (lint) { const clipboard = document.getElementById("clipboard-" + lint.id); if (clipboard) { @@ -296,14 +460,12 @@ // Get data $scope.open = {}; $scope.loading = true; + // This will be used to jump into the source code of the version that this documentation is for. $scope.docVersion = window.location.pathname.split('/')[2] || "master"; - if (window.location.hash.length > 1) { - $scope.search = window.location.hash.slice(1); - $scope.open[window.location.hash.slice(1)] = true; - scrollToLintByURL($scope); - } + // Set up the filters from the URL parameters before we start loading the data + loadFromURLParameters(); $http.get('./lints.json') .success(function (data) { @@ -315,7 +477,7 @@ selectGroup($scope, selectedGroup.toLowerCase()); } - scrollToLintByURL($scope); + scrollToLintByURL($scope, $location); setTimeout(function () { var el = document.getElementById('filter-input'); @@ -326,18 +488,6 @@ $scope.error = data; $scope.loading = false; }); - - window.addEventListener('hashchange', function () { - // trigger re-render - $timeout(function () { - $scope.levels = LEVEL_FILTERS_DEFAULT; - $scope.search = window.location.hash.slice(1); - $scope.open[window.location.hash.slice(1)] = true; - - scrollToLintByURL($scope); - }); - return true; - }, false); }); })(); diff --git a/util/gh-pages/versions.html b/util/gh-pages/versions.html index 6e810a349bfc..31ce88193295 100644 --- a/util/gh-pages/versions.html +++ b/util/gh-pages/versions.html @@ -36,7 +36,7 @@ @@ -54,18 +54,15 @@ .controller('docVersions', function ($scope, $http) { $scope.loading = true; - $scope.normalizeVersionDisplay = function(v) { - return v.replace(/^v/, ''); - }; - $scope.normalizeVersion = function(v) { - return v.replace(/^v/, '').replace(/^rust-/, ''); + return v.replace(/^rust-/, ''); }; $scope.versionOrder = function(v) { if (v === 'master') { return Infinity; } if (v === 'stable') { return Number.MAX_VALUE; } if (v === 'beta') { return Number.MAX_VALUE - 1; } + if (v === 'pre-1.29.0') { return Number.MIN_VALUE; } return $scope.normalizeVersion(v) .split('.') diff --git a/util/versions.py b/util/versions.py index 0cfa007d1b27..c041fc606a8f 100755 --- a/util/versions.py +++ b/util/versions.py @@ -1,24 +1,27 @@ #!/usr/bin/env python import json +import logging as log import os import sys -import logging as log -log.basicConfig(level=log.INFO, format='%(levelname)s: %(message)s') + +log.basicConfig(level=log.INFO, format="%(levelname)s: %(message)s") def key(v): - if v == 'master': - return float('inf') - if v == 'stable': + if v == "master": + return float("inf") + if v == "stable": return sys.maxsize - if v == 'beta': + if v == "beta": return sys.maxsize - 1 + if v == "pre-1.29.0": + return -1 - v = v.replace('v', '').replace('rust-', '') + v = v.replace("rust-", "") s = 0 - for i, val in enumerate(v.split('.')[::-1]): + for i, val in enumerate(v.split(".")[::-1]): s += int(val) * 100**i return s @@ -31,7 +34,11 @@ def main(): outdir = sys.argv[1] versions = [ - dir for dir in os.listdir(outdir) if not dir.startswith(".") and os.path.isdir(os.path.join(outdir, dir)) + dir + for dir in os.listdir(outdir) + if not dir.startswith(".") + and not dir.startswith("v") + and os.path.isdir(os.path.join(outdir, dir)) ] versions.sort(key=key) From ba1ffec5b5284bca28c58f18b875b3a8e50a277a Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Sun, 2 Jul 2023 14:59:44 +0200 Subject: [PATCH 126/324] Fix valtree changes --- clippy_utils/src/consts.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 068820801dfe..dd3cda8ec527 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -725,8 +725,8 @@ fn field_of_struct<'tcx>( result: mir::ConstantKind<'tcx>, field: &Ident, ) -> Option> { - let dc = lcx.tcx.destructure_mir_constant(lcx.param_env, result); - if let Some(dc_variant) = dc.variant + if let Some(dc) = lcx.tcx.try_destructure_mir_constant(lcx.param_env.and(result)) + && let Some(dc_variant) = dc.variant && let Some(variant) = adt_def.variants().get(dc_variant) && let Some(field_idx) = variant.fields.iter().position(|el| el.name == field.name) && let Some(dc_field) = dc.fields.get(field_idx) From 4aa4fecf897869b656d91791b8dcb03db189733d Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Sun, 2 Jul 2023 15:07:39 +0200 Subject: [PATCH 127/324] Fix compile-test tests to work with the new ui_test crate --- tests/compile-test.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/tests/compile-test.rs b/tests/compile-test.rs index dce6f2fc2726..0fd37c640aef 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -31,7 +31,7 @@ fn base_config(test_dir: &str) -> compiletest::Config { }, dependencies_crate_manifest_path: Some("clippy_test_deps/Cargo.toml".into()), target: None, - out_dir: "target/ui_test".into(), + out_dir: PathBuf::from(std::env::var_os("CARGO_TARGET_DIR").unwrap_or("target".into())).join("ui_test"), ..compiletest::Config::rustc(Path::new("tests").join(test_dir)) }; @@ -116,10 +116,7 @@ fn run_ui_toml() { config.stderr_filter( ®ex::escape( - &std::path::Path::new(file!()) - .parent() - .unwrap() - .canonicalize() + &fs::canonicalize("tests") .unwrap() .parent() .unwrap() @@ -175,10 +172,7 @@ fn run_ui_cargo() { config.stderr_filter( ®ex::escape( - &std::path::Path::new(file!()) - .parent() - .unwrap() - .canonicalize() + &fs::canonicalize("tests") .unwrap() .parent() .unwrap() From e29a5acf6f177e35ad00d7120fc3422ac94c3ac9 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Sun, 2 Jul 2023 14:17:34 +0000 Subject: [PATCH 128/324] let_and_return: lint 'static lifetimes, don't lint borrows in closures --- clippy_lints/src/returns.rs | 6 ++-- tests/ui/let_and_return.rs | 61 ++++++++++++++++++---------------- tests/ui/let_and_return.stderr | 22 +++++++++--- 3 files changed, 53 insertions(+), 36 deletions(-) diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 958351ad81bb..ad0167a3d327 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::source::{snippet_opt, snippet_with_context}; -use clippy_utils::visitors::{for_each_expr, Descend}; +use clippy_utils::visitors::{for_each_expr_with_closures, Descend}; use clippy_utils::{fn_def_id, path_to_local_id, span_find_starting_semi}; use core::ops::ControlFlow; use if_chain::if_chain; @@ -328,7 +328,7 @@ fn emit_return_lint(cx: &LateContext<'_>, ret_span: Span, semi_spans: Vec, } fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { - for_each_expr(expr, |e| { + for_each_expr_with_closures(cx, expr, |e| { if let Some(def_id) = fn_def_id(cx, e) && cx .tcx @@ -337,7 +337,7 @@ fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) .skip_binder() .output() .walk() - .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_))) + .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(re) if !re.is_static())) { ControlFlow::Break(()) } else { diff --git a/tests/ui/let_and_return.rs b/tests/ui/let_and_return.rs index bb162adc9adb..7e4d783a026c 100644 --- a/tests/ui/let_and_return.rs +++ b/tests/ui/let_and_return.rs @@ -1,6 +1,8 @@ #![allow(unused)] #![warn(clippy::let_and_return)] +use std::cell::RefCell; + fn test() -> i32 { let _y = 0; // no warning let x = 5; @@ -65,45 +67,46 @@ macro_rules! tuple_encode { ); } +fn issue_3792() -> String { + use std::io::{self, BufRead, Stdin}; + + let stdin = io::stdin(); + // `Stdin::lock` returns `StdinLock<'static>` so `line` doesn't borrow from `stdin` + // https://github.com/rust-lang/rust/pull/93965 + let line = stdin.lock().lines().next().unwrap().unwrap(); + line +} + tuple_encode!(T0, T1, T2, T3, T4, T5, T6, T7); mod no_lint_if_stmt_borrows { - mod issue_3792 { - use std::io::{self, BufRead, Stdin}; + use std::cell::RefCell; + use std::rc::{Rc, Weak}; + struct Bar; - fn read_line() -> String { - let stdin = io::stdin(); - let line = stdin.lock().lines().next().unwrap().unwrap(); - line + impl Bar { + fn new() -> Self { + Bar {} + } + fn baz(&self) -> u32 { + 0 } } - mod issue_3324 { - use std::cell::RefCell; - use std::rc::{Rc, Weak}; + fn issue_3324(value: Weak>) -> u32 { + let value = value.upgrade().unwrap(); + let ret = value.borrow().baz(); + ret + } - fn test(value: Weak>) -> u32 { - let value = value.upgrade().unwrap(); - let ret = value.borrow().baz(); - ret + fn borrows_in_closure(value: Weak>) -> u32 { + fn f(mut x: impl FnMut() -> u32) -> impl FnMut() -> u32 { + x } - struct Bar; - - impl Bar { - fn new() -> Self { - Bar {} - } - fn baz(&self) -> u32 { - 0 - } - } - - fn main() { - let a = Rc::new(RefCell::new(Bar::new())); - let b = Rc::downgrade(&a); - test(b); - } + let value = value.upgrade().unwrap(); + let ret = f(|| value.borrow().baz())(); + ret } mod free_function { diff --git a/tests/ui/let_and_return.stderr b/tests/ui/let_and_return.stderr index 17fd694bf7ac..4ca0a05c858f 100644 --- a/tests/ui/let_and_return.stderr +++ b/tests/ui/let_and_return.stderr @@ -1,5 +1,5 @@ error: returning the result of a `let` binding from a block - --> $DIR/let_and_return.rs:7:5 + --> $DIR/let_and_return.rs:9:5 | LL | let x = 5; | ---------- unnecessary `let` binding @@ -14,7 +14,7 @@ LL ~ 5 | error: returning the result of a `let` binding from a block - --> $DIR/let_and_return.rs:13:9 + --> $DIR/let_and_return.rs:15:9 | LL | let x = 5; | ---------- unnecessary `let` binding @@ -28,7 +28,21 @@ LL ~ 5 | error: returning the result of a `let` binding from a block - --> $DIR/let_and_return.rs:164:13 + --> $DIR/let_and_return.rs:77:5 + | +LL | let line = stdin.lock().lines().next().unwrap().unwrap(); + | --------------------------------------------------------- unnecessary `let` binding +LL | line + | ^^^^ + | +help: return the expression directly + | +LL ~ +LL ~ stdin.lock().lines().next().unwrap().unwrap() + | + +error: returning the result of a `let` binding from a block + --> $DIR/let_and_return.rs:167:13 | LL | let clone = Arc::clone(&self.foo); | ---------------------------------- unnecessary `let` binding @@ -41,5 +55,5 @@ LL ~ LL ~ Arc::clone(&self.foo) as _ | -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors From 555ceb83fefc937e03bade598b608b76700234cb Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sun, 2 Jul 2023 21:42:39 +0200 Subject: [PATCH 129/324] [`missing_fields_in_debug`]: make sure `self` is an adt --- clippy_lints/src/missing_fields_in_debug.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/missing_fields_in_debug.rs b/clippy_lints/src/missing_fields_in_debug.rs index 1138d1163a4a..497514fbcd60 100644 --- a/clippy_lints/src/missing_fields_in_debug.rs +++ b/clippy_lints/src/missing_fields_in_debug.rs @@ -207,11 +207,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingFieldsInDebug { if let ItemKind::Impl(Impl { of_trait: Some(trait_ref), self_ty, items, .. }) = item.kind && let Res::Def(DefKind::Trait, trait_def_id) = trait_ref.path.res && let TyKind::Path(QPath::Resolved(_, self_path)) = &self_ty.kind - // don't trigger if self is a generic parameter, e.g. `impl Debug for T` - // this can only happen in core itself, where the trait is defined, - // but it caused ICEs in the past: - // https://github.com/rust-lang/rust-clippy/issues/10887 - && !matches!(self_path.res, Res::Def(DefKind::TyParam, _)) + // make sure that the self type is either a struct, an enum or a union + // this prevents ICEs such as when self is a type parameter or a primitive type + // (see #10887, #11063) + && let Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, self_path_did) = self_path.res && cx.match_def_path(trait_def_id, &[sym::core, sym::fmt, sym::Debug]) // don't trigger if this impl was derived && !cx.tcx.has_attr(item.owner_id, sym::automatically_derived) @@ -222,7 +221,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingFieldsInDebug { && let body = cx.tcx.hir().body(*body_id) && let ExprKind::Block(block, _) = body.value.kind // inspect `self` - && let self_ty = cx.tcx.type_of(self_path.res.def_id()).skip_binder().peel_refs() + && let self_ty = cx.tcx.type_of(self_path_did).skip_binder().peel_refs() && let Some(self_adt) = self_ty.ty_adt_def() && let Some(self_def_id) = self_adt.did().as_local() && let Some(Node::Item(self_item)) = cx.tcx.hir().find_by_def_id(self_def_id) From 6086ced61dec91d81559ee666481628152113260 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Mon, 3 Jul 2023 05:06:55 +0900 Subject: [PATCH 130/324] Revert "Support `#[rustc_coinductive]`" This reverts commit d026479ba6084d00b900fed3c5c06363d605e68e. --- crates/hir-ty/src/chalk_db.rs | 8 ++----- crates/hir-ty/src/tests/traits.rs | 32 -------------------------- crates/ide/src/inlay_hints/chaining.rs | 12 +++++----- crates/test-utils/src/minicore.rs | 1 - 4 files changed, 8 insertions(+), 45 deletions(-) diff --git a/crates/hir-ty/src/chalk_db.rs b/crates/hir-ty/src/chalk_db.rs index 5bc75912221c..ff80d4cf9d59 100644 --- a/crates/hir-ty/src/chalk_db.rs +++ b/crates/hir-ty/src/chalk_db.rs @@ -550,10 +550,6 @@ pub(crate) fn trait_datum_query( debug!("trait_datum {:?}", trait_id); let trait_ = from_chalk_trait_id(trait_id); let trait_data = db.trait_data(trait_); - - let coinductive = - trait_data.is_auto || db.attrs(trait_.into()).by_key("rustc_coinductive").exists(); - debug!("trait {:?} = {:?}", trait_id, trait_data.name); let generic_params = generics(db.upcast(), trait_.into()); let bound_vars = generic_params.bound_vars_subst(db, DebruijnIndex::INNERMOST); @@ -561,7 +557,7 @@ pub(crate) fn trait_datum_query( auto: trait_data.is_auto, upstream: trait_.lookup(db.upcast()).container.krate() != krate, non_enumerable: true, - coinductive, + coinductive: false, // only relevant for Chalk testing // FIXME: set these flags correctly marker: false, fundamental: false, @@ -643,7 +639,7 @@ pub(crate) fn struct_datum_query( fundamental: false, phantom_data: false, }; - // FIXME provide enum variants properly (for auto traits and `Sized`) + // FIXME provide enum variants properly (for auto traits) let variant = rust_ir::AdtVariantDatum { fields: Vec::new(), // FIXME add fields (only relevant for auto traits), }; diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs index 764e77950f5e..97ae732a9046 100644 --- a/crates/hir-ty/src/tests/traits.rs +++ b/crates/hir-ty/src/tests/traits.rs @@ -4410,35 +4410,3 @@ fn test(v: S) { "#, ); } - -#[test] -fn rustc_coinductive() { - // Taken from rust-lang/rust#108033 with modification. - check_types( - r#" -#[rustc_coinductive] -trait Trait { type Assoc; } - -impl Trait for (T, U) -where - (U, T): Trait, - (): ConstrainToU32, -{ - type Assoc = i32; -} - -trait ConstrainToU32 {} -impl ConstrainToU32 for () {} - -fn impls_trait() -> R -where - (T, U): Trait, -{ loop {} } - -fn main() { - let _ = impls_trait::<_, _, _>(); - //^ i32 -} -"#, - ); -} diff --git a/crates/ide/src/inlay_hints/chaining.rs b/crates/ide/src/inlay_hints/chaining.rs index 8ac62bee7b09..774383d50d61 100644 --- a/crates/ide/src/inlay_hints/chaining.rs +++ b/crates/ide/src/inlay_hints/chaining.rs @@ -474,7 +474,7 @@ fn main() { file_id: FileId( 1, ), - range: 9313..9321, + range: 9288..9296, }, ), tooltip: "", @@ -487,7 +487,7 @@ fn main() { file_id: FileId( 1, ), - range: 9345..9349, + range: 9320..9324, }, ), tooltip: "", @@ -511,7 +511,7 @@ fn main() { file_id: FileId( 1, ), - range: 9313..9321, + range: 9288..9296, }, ), tooltip: "", @@ -524,7 +524,7 @@ fn main() { file_id: FileId( 1, ), - range: 9345..9349, + range: 9320..9324, }, ), tooltip: "", @@ -548,7 +548,7 @@ fn main() { file_id: FileId( 1, ), - range: 9313..9321, + range: 9288..9296, }, ), tooltip: "", @@ -561,7 +561,7 @@ fn main() { file_id: FileId( 1, ), - range: 9345..9349, + range: 9320..9324, }, ), tooltip: "", diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs index 73a322389e87..ebde017686df 100644 --- a/crates/test-utils/src/minicore.rs +++ b/crates/test-utils/src/minicore.rs @@ -63,7 +63,6 @@ pub mod marker { #[lang = "sized"] #[fundamental] #[rustc_specialization_trait] - #[rustc_coinductive] pub trait Sized {} // endregion:sized From 6990eaa9720e45b3b09eb00d9476b89839935c10 Mon Sep 17 00:00:00 2001 From: est31 Date: Sun, 2 Jul 2023 04:03:20 +0200 Subject: [PATCH 131/324] Don't suppress manual_let_else if question_mark is allowed If question_mark is allowed, there is no overlap any more, so we can just not suppress it. --- clippy_lints/src/manual_let_else.rs | 20 +++++++++---------- tests/ui/manual_let_else_question_mark.fixed | 7 +++++++ tests/ui/manual_let_else_question_mark.rs | 7 +++++++ tests/ui/manual_let_else_question_mark.stderr | 8 +++++++- 4 files changed, 31 insertions(+), 11 deletions(-) diff --git a/clippy_lints/src/manual_let_else.rs b/clippy_lints/src/manual_let_else.rs index 363018f13819..18739e9d8e20 100644 --- a/clippy_lints/src/manual_let_else.rs +++ b/clippy_lints/src/manual_let_else.rs @@ -1,12 +1,10 @@ -use crate::question_mark::{pat_and_expr_can_be_question_mark, QuestionMark}; +use crate::question_mark::{pat_and_expr_can_be_question_mark, QuestionMark, QUESTION_MARK}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::IfLetOrMatch; -use clippy_utils::msrvs; -use clippy_utils::peel_blocks; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::{Descend, Visitable}; -use if_chain::if_chain; +use clippy_utils::{is_lint_allowed, msrvs, peel_blocks}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, Visitor}; @@ -65,12 +63,14 @@ impl<'tcx> QuestionMark { let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init) { match if_let_or_match { - IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else) => if_chain! { - if let Some(ident_map) = expr_simple_identity_map(local.pat, let_pat, if_then); - if let Some(if_else) = if_else; - if expr_diverges(cx, if_else); - if pat_and_expr_can_be_question_mark(cx, let_pat, if_else).is_none(); - then { + IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else) => { + if + let Some(ident_map) = expr_simple_identity_map(local.pat, let_pat, if_then) && + let Some(if_else) = if_else && + expr_diverges(cx, if_else) && + let qm_allowed = is_lint_allowed(cx, QUESTION_MARK, stmt.hir_id) && + (qm_allowed || pat_and_expr_can_be_question_mark(cx, let_pat, if_else).is_none()) + { emit_manual_let_else(cx, stmt.span, if_let_expr, &ident_map, let_pat, if_else); } }, diff --git a/tests/ui/manual_let_else_question_mark.fixed b/tests/ui/manual_let_else_question_mark.fixed index 617f127b9a86..02308bc7c4c1 100644 --- a/tests/ui/manual_let_else_question_mark.fixed +++ b/tests/ui/manual_let_else_question_mark.fixed @@ -52,5 +52,12 @@ fn foo() -> Option<()> { let Some(v) = g() else { return None }; } + // This is a copy of the case above where we'd fire the question_mark lint, but here we have allowed + // it. Make sure that manual_let_else is fired as the fallback. + #[allow(clippy::question_mark)] + { + let Some(v) = g() else { return None }; + } + Some(()) } diff --git a/tests/ui/manual_let_else_question_mark.rs b/tests/ui/manual_let_else_question_mark.rs index 3cf1eca86734..9c7ad386dc99 100644 --- a/tests/ui/manual_let_else_question_mark.rs +++ b/tests/ui/manual_let_else_question_mark.rs @@ -57,5 +57,12 @@ fn foo() -> Option<()> { }; } + // This is a copy of the case above where we'd fire the question_mark lint, but here we have allowed + // it. Make sure that manual_let_else is fired as the fallback. + #[allow(clippy::question_mark)] + { + let v = if let Some(v_some) = g() { v_some } else { return None }; + } + Some(()) } diff --git a/tests/ui/manual_let_else_question_mark.stderr b/tests/ui/manual_let_else_question_mark.stderr index 31052acf75cd..d7d2e127ea3f 100644 --- a/tests/ui/manual_let_else_question_mark.stderr +++ b/tests/ui/manual_let_else_question_mark.stderr @@ -45,5 +45,11 @@ LL | | _ => return None, LL | | }; | |__________^ help: consider writing: `let Some(v) = g() else { return None };` -error: aborting due to 5 previous errors +error: this could be rewritten as `let...else` + --> $DIR/manual_let_else_question_mark.rs:64:9 + | +LL | let v = if let Some(v_some) = g() { v_some } else { return None }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { return None };` + +error: aborting due to 6 previous errors From d80581c7d2db05a899e3363c8fc937012311de69 Mon Sep 17 00:00:00 2001 From: est31 Date: Mon, 3 Jul 2023 09:42:43 +0200 Subject: [PATCH 132/324] Move pat_and_expr_can_be_question_mark into clippy_utils --- clippy_lints/src/manual_let_else.rs | 4 +-- clippy_lints/src/question_mark.rs | 50 ++--------------------------- clippy_utils/src/lib.rs | 45 ++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 49 deletions(-) diff --git a/clippy_lints/src/manual_let_else.rs b/clippy_lints/src/manual_let_else.rs index 18739e9d8e20..ade85e23bd3a 100644 --- a/clippy_lints/src/manual_let_else.rs +++ b/clippy_lints/src/manual_let_else.rs @@ -1,10 +1,10 @@ -use crate::question_mark::{pat_and_expr_can_be_question_mark, QuestionMark, QUESTION_MARK}; +use crate::question_mark::{QuestionMark, QUESTION_MARK}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::IfLetOrMatch; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::{Descend, Visitable}; -use clippy_utils::{is_lint_allowed, msrvs, peel_blocks}; +use clippy_utils::{is_lint_allowed, msrvs, pat_and_expr_can_be_question_mark, peel_blocks}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, Visitor}; diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index d473b6fd5c43..9840d464b75f 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -4,8 +4,8 @@ use clippy_utils::msrvs::Msrv; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{ - eq_expr_value, get_parent_node, in_constant, is_else_clause, is_refutable, is_res_lang_ctor, path_to_local, - path_to_local_id, peel_blocks, peel_blocks_with_stmt, + eq_expr_value, get_parent_node, in_constant, is_else_clause, is_res_lang_ctor, pat_and_expr_can_be_question_mark, + path_to_local, path_to_local_id, peel_blocks, peel_blocks_with_stmt, }; use clippy_utils::{higher, is_path_lang_item}; use if_chain::if_chain; @@ -13,7 +13,7 @@ use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::LangItem::{self, OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::{ - BindingAnnotation, Block, ByRef, Expr, ExprKind, Local, Node, Pat, PatKind, PathSegment, QPath, Stmt, StmtKind, + BindingAnnotation, Block, ByRef, Expr, ExprKind, Local, Node, PatKind, PathSegment, QPath, Stmt, StmtKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; @@ -95,50 +95,6 @@ enum IfBlockType<'hir> { ), } -/// Returns whether the given let pattern and else body can be turned into a question mark -/// -/// For this example: -/// ```ignore -/// let FooBar { a, b } = if let Some(a) = ex { a } else { return None }; -/// ``` -/// We get as parameters: -/// ```ignore -/// pat: Some(a) -/// else_body: return None -/// ``` - -/// And for this example: -/// ```ignore -/// let Some(FooBar { a, b }) = ex else { return None }; -/// ``` -/// We get as parameters: -/// ```ignore -/// pat: Some(FooBar { a, b }) -/// else_body: return None -/// ``` - -/// We output `Some(a)` in the first instance, and `Some(FooBar { a, b })` in the second, because -/// the question mark operator is applicable here. Callers have to check whether we are in a -/// constant or not. -pub(crate) fn pat_and_expr_can_be_question_mark<'a, 'hir>( - cx: &LateContext<'_>, - pat: &'a Pat<'hir>, - else_body: &Expr<'_>, -) -> Option<&'a Pat<'hir>> { - if let PatKind::TupleStruct(pat_path, [inner_pat], _) = pat.kind && - is_res_lang_ctor(cx, cx.qpath_res(&pat_path, pat.hir_id), OptionSome) && - !is_refutable(cx, inner_pat) && - let else_body = peel_blocks(else_body) && - let ExprKind::Ret(Some(ret_val)) = else_body.kind && - let ExprKind::Path(ret_path) = ret_val.kind && - is_res_lang_ctor(cx, cx.qpath_res(&ret_path, ret_val.hir_id), OptionNone) - { - Some(inner_pat) - } else { - None - } -} - fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) { if let StmtKind::Local(Local { pat, init: Some(init_expr), els: Some(els), .. }) = stmt.kind && let Block { stmts: &[], expr: Some(els), .. } = els && diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 727b59f1f432..02ab1b31e72a 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -87,6 +87,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; use rustc_hir::hir_id::{HirIdMap, HirIdSet}; use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; +use rustc_hir::LangItem::OptionSome; use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk}; use rustc_hir::{ self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Destination, Expr, @@ -2542,6 +2543,50 @@ pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span { sm.span_take_while(span, |&ch| ch == ' ' || ch == ';') } +/// Returns whether the given let pattern and else body can be turned into a question mark +/// +/// For this example: +/// ```ignore +/// let FooBar { a, b } = if let Some(a) = ex { a } else { return None }; +/// ``` +/// We get as parameters: +/// ```ignore +/// pat: Some(a) +/// else_body: return None +/// ``` + +/// And for this example: +/// ```ignore +/// let Some(FooBar { a, b }) = ex else { return None }; +/// ``` +/// We get as parameters: +/// ```ignore +/// pat: Some(FooBar { a, b }) +/// else_body: return None +/// ``` + +/// We output `Some(a)` in the first instance, and `Some(FooBar { a, b })` in the second, because +/// the question mark operator is applicable here. Callers have to check whether we are in a +/// constant or not. +pub fn pat_and_expr_can_be_question_mark<'a, 'hir>( + cx: &LateContext<'_>, + pat: &'a Pat<'hir>, + else_body: &Expr<'_>, +) -> Option<&'a Pat<'hir>> { + if let PatKind::TupleStruct(pat_path, [inner_pat], _) = pat.kind && + is_res_lang_ctor(cx, cx.qpath_res(&pat_path, pat.hir_id), OptionSome) && + !is_refutable(cx, inner_pat) && + let else_body = peel_blocks(else_body) && + let ExprKind::Ret(Some(ret_val)) = else_body.kind && + let ExprKind::Path(ret_path) = ret_val.kind && + is_res_lang_ctor(cx, cx.qpath_res(&ret_path, ret_val.hir_id), OptionNone) + { + Some(inner_pat) + } else { + None + } +} + macro_rules! op_utils { ($($name:ident $assign:ident)*) => { /// Binary operation traits like `LangItem::Add` From 75c339cd0ad7c38f8d258a369570400eae933973 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Mon, 3 Jul 2023 11:34:02 +0200 Subject: [PATCH 133/324] [`arc_with_non_send_sync`]: look for nested type parameters --- clippy_lints/src/arc_with_non_send_sync.rs | 6 +++++- tests/ui/arc_with_non_send_sync.rs | 3 +++ tests/ui/arc_with_non_send_sync.stderr | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/arc_with_non_send_sync.rs b/clippy_lints/src/arc_with_non_send_sync.rs index a1e44668e1ad..62313df9f90e 100644 --- a/clippy_lints/src/arc_with_non_send_sync.rs +++ b/clippy_lints/src/arc_with_non_send_sync.rs @@ -7,6 +7,7 @@ use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_lint::LateLintPass; use rustc_middle::ty; +use rustc_middle::ty::GenericArgKind; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::sym; @@ -47,7 +48,10 @@ impl LateLintPass<'_> for ArcWithNonSendSync { if let ExprKind::Path(func_path) = func.kind; if last_path_segment(&func_path).ident.name == sym::new; if let arg_ty = cx.typeck_results().expr_ty(arg); - if !matches!(arg_ty.kind(), ty::Param(_)); + // make sure that the type is not and does not contain any type parameters + if arg_ty.walk().all(|arg| { + !matches!(arg.unpack(), GenericArgKind::Type(ty) if matches!(ty.kind(), ty::Param(_))) + }); if !cx.tcx .lang_items() .sync_trait() diff --git a/tests/ui/arc_with_non_send_sync.rs b/tests/ui/arc_with_non_send_sync.rs index ac786f68c123..9d5849277c20 100644 --- a/tests/ui/arc_with_non_send_sync.rs +++ b/tests/ui/arc_with_non_send_sync.rs @@ -7,6 +7,9 @@ fn foo(x: T) { // Should not lint - purposefully ignoring generic args. let a = Arc::new(x); } +fn issue11076() { + let a: Arc> = Arc::new(Vec::new()); +} fn main() { // This is safe, as `i32` implements `Send` and `Sync`. diff --git a/tests/ui/arc_with_non_send_sync.stderr b/tests/ui/arc_with_non_send_sync.stderr index fc2fc5f93b13..520c21b565ba 100644 --- a/tests/ui/arc_with_non_send_sync.stderr +++ b/tests/ui/arc_with_non_send_sync.stderr @@ -1,5 +1,5 @@ error: usage of `Arc` where `T` is not `Send` or `Sync` - --> $DIR/arc_with_non_send_sync.rs:16:13 + --> $DIR/arc_with_non_send_sync.rs:19:13 | LL | let b = Arc::new(RefCell::new(42)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ From 9a581077d41dcc9a751a30cdfeca17464d5a7be2 Mon Sep 17 00:00:00 2001 From: Catherine <114838443+Centri3@users.noreply.github.com> Date: Mon, 3 Jul 2023 06:35:04 -0500 Subject: [PATCH 134/324] Fix FP [`needless_raw_string_hashes`] --- clippy_lints/src/raw_strings.rs | 2 +- tests/ui/needless_raw_string_hashes.fixed | 4 ++++ tests/ui/needless_raw_string_hashes.rs | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/raw_strings.rs b/clippy_lints/src/raw_strings.rs index f45bb1ef3e1f..0e964ec4724d 100644 --- a/clippy_lints/src/raw_strings.rs +++ b/clippy_lints/src/raw_strings.rs @@ -95,7 +95,7 @@ impl EarlyLintPass for RawStrings { // `once` so a raw string ending in hashes is still checked let num = str.as_bytes().iter().chain(once(&0)).try_fold(0u8, |acc, &b| { match b { - b'"' => (following_quote, req) = (true, 1), + b'"' if !following_quote => (following_quote, req) = (true, 1), // I'm a bit surprised the compiler didn't optimize this out, there's no // branch but it still ends up doing an unnecessary comparison, it's: // - cmp r9b,1h diff --git a/tests/ui/needless_raw_string_hashes.fixed b/tests/ui/needless_raw_string_hashes.fixed index e4d7d8fb017a..a9a6282628e9 100644 --- a/tests/ui/needless_raw_string_hashes.fixed +++ b/tests/ui/needless_raw_string_hashes.fixed @@ -16,4 +16,8 @@ fn main() { cr#"Hello "world"!"#; cr####" "### "## "# "####; cr###" "aa" "# "## "###; + // Issue #11068, do not lint + r##"a"#"a"##; + br##"a"#"a"##; + cr##"a"#"a"##; } diff --git a/tests/ui/needless_raw_string_hashes.rs b/tests/ui/needless_raw_string_hashes.rs index e2d85c52e78c..baa97d864703 100644 --- a/tests/ui/needless_raw_string_hashes.rs +++ b/tests/ui/needless_raw_string_hashes.rs @@ -16,4 +16,8 @@ fn main() { cr##"Hello "world"!"##; cr######" "### "## "# "######; cr######" "aa" "# "## "######; + // Issue #11068, do not lint + r##"a"#"a"##; + br##"a"#"a"##; + cr##"a"#"a"##; } From 1f77f8cc3cca968d47d15c9e621d48f0193f8ab1 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Mon, 3 Jul 2023 13:40:33 +0200 Subject: [PATCH 135/324] [`useless_vec`]: use the source span --- clippy_lints/src/vec.rs | 2 +- tests/ui/vec.fixed | 11 +++++++++++ tests/ui/vec.rs | 11 +++++++++++ tests/ui/vec.stderr | 12 +++++++++--- 4 files changed, 32 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index 2a594e750b9b..ca0daa9eceec 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -181,7 +181,7 @@ impl UselessVec { if args.len() as u64 * size_of(cx, last) > self.too_large_for_stack { return; } - let span = args[0].span.to(last.span); + let span = args[0].span.source_callsite().to(last.span.source_callsite()); let args = snippet_with_applicability(cx, span, "..", &mut applicability); match suggest_slice { diff --git a/tests/ui/vec.fixed b/tests/ui/vec.fixed index fcdc917c1b13..14ab8bd8897e 100644 --- a/tests/ui/vec.fixed +++ b/tests/ui/vec.fixed @@ -115,6 +115,17 @@ fn main() { let _x = vec![1; 201]; } +fn issue11075() { + macro_rules! repro { + ($e:expr) => { + stringify!($e) + }; + } + for _string in [repro!(true), repro!(null)] { + unimplemented!(); + } +} + #[clippy::msrv = "1.53"] fn above() { for a in [1, 2, 3] { diff --git a/tests/ui/vec.rs b/tests/ui/vec.rs index 0404d8cdb842..e57cb4374e38 100644 --- a/tests/ui/vec.rs +++ b/tests/ui/vec.rs @@ -115,6 +115,17 @@ fn main() { let _x = vec![1; 201]; } +fn issue11075() { + macro_rules! repro { + ($e:expr) => { + stringify!($e) + }; + } + for _string in vec![repro!(true), repro!(null)] { + unimplemented!(); + } +} + #[clippy::msrv = "1.53"] fn above() { for a in vec![1, 2, 3] { diff --git a/tests/ui/vec.stderr b/tests/ui/vec.stderr index 33d565b2d525..1b82d5cbea88 100644 --- a/tests/ui/vec.stderr +++ b/tests/ui/vec.stderr @@ -85,16 +85,22 @@ LL | for _ in vec![1, 2, 3] {} | ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]` error: useless use of `vec!` - --> $DIR/vec.rs:120:14 + --> $DIR/vec.rs:124:20 + | +LL | for _string in vec![repro!(true), repro!(null)] { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can use an array directly: `[repro!(true), repro!(null)]` + +error: useless use of `vec!` + --> $DIR/vec.rs:131:14 | LL | for a in vec![1, 2, 3] { | ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]` error: useless use of `vec!` - --> $DIR/vec.rs:124:14 + --> $DIR/vec.rs:135:14 | LL | for a in vec![String::new(), String::new()] { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can use an array directly: `[String::new(), String::new()]` -error: aborting due to 16 previous errors +error: aborting due to 17 previous errors From 321e570d92d5ff32280247d0a67145c4ae4eab48 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 3 Jul 2023 14:23:36 +0200 Subject: [PATCH 136/324] Don't diagnose builtin derives --- .../hir-def/src/macro_expansion_tests/mod.rs | 2 +- crates/hir-expand/src/lib.rs | 27 ++++++++++++++----- crates/hir/src/lib.rs | 18 ++++++++----- crates/ide/src/navigation_target.rs | 10 +++---- 4 files changed, 38 insertions(+), 19 deletions(-) diff --git a/crates/hir-def/src/macro_expansion_tests/mod.rs b/crates/hir-def/src/macro_expansion_tests/mod.rs index 4a62696df081..836f0afb1d84 100644 --- a/crates/hir-def/src/macro_expansion_tests/mod.rs +++ b/crates/hir-def/src/macro_expansion_tests/mod.rs @@ -239,7 +239,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream for impl_id in def_map[local_id].scope.impls() { let src = impl_id.lookup(&db).source(&db); - if src.file_id.is_builtin_derive(&db).is_some() { + if src.file_id.is_builtin_derive(&db) { let pp = pretty_print_macro_expansion(src.value.syntax().clone(), None); format_to!(expanded_text, "\n{}", pp) } diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs index 4c37ad3d1547..b0dc8e1b5c98 100644 --- a/crates/hir-expand/src/lib.rs +++ b/crates/hir-expand/src/lib.rs @@ -319,8 +319,10 @@ impl HirFileId { }) } - /// Indicate it is macro file generated for builtin derive - pub fn is_builtin_derive(&self, db: &dyn db::ExpandDatabase) -> Option> { + pub fn as_builtin_derive_attr_node( + &self, + db: &dyn db::ExpandDatabase, + ) -> Option> { let macro_file = self.macro_file()?; let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); let attr = match loc.def.kind { @@ -333,8 +335,22 @@ impl HirFileId { pub fn is_custom_derive(&self, db: &dyn db::ExpandDatabase) -> bool { match self.macro_file() { Some(macro_file) => { - let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); - matches!(loc.def.kind, MacroDefKind::ProcMacro(_, ProcMacroKind::CustomDerive, _)) + matches!( + db.lookup_intern_macro_call(macro_file.macro_call_id).def.kind, + MacroDefKind::ProcMacro(_, ProcMacroKind::CustomDerive, _) + ) + } + None => false, + } + } + + pub fn is_builtin_derive(&self, db: &dyn db::ExpandDatabase) -> bool { + match self.macro_file() { + Some(macro_file) => { + matches!( + db.lookup_intern_macro_call(macro_file.macro_call_id).def.kind, + MacroDefKind::BuiltInDerive(..) + ) } None => false, } @@ -344,8 +360,7 @@ impl HirFileId { pub fn is_include_macro(&self, db: &dyn db::ExpandDatabase) -> bool { match self.macro_file() { Some(macro_file) => { - let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); - loc.def.is_include() + db.lookup_intern_macro_call(macro_file.macro_call_id).def.is_include() } _ => false, } diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 74eb9f658838..7d07e9cce421 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -614,15 +614,21 @@ impl Module { let inherent_impls = db.inherent_impls_in_crate(self.id.krate()); for impl_def in self.impl_defs(db) { + let loc = impl_def.id.lookup(db.upcast()); + let tree = loc.id.item_tree(db.upcast()); + let node = &tree[loc.id.value]; + let file_id = loc.id.file_id(); + if file_id.is_builtin_derive(db.upcast()) { + // these expansion come from us, diagnosing them is a waste of resources + // FIXME: Once we diagnose the inputs to builtin derives, we should at least extract those diagnostics somehow + continue; + } + for diag in db.impl_data_with_diagnostics(impl_def.id).1.iter() { emit_def_diagnostic(db, acc, diag); } if inherent_impls.invalid_impls().contains(&impl_def.id) { - let loc = impl_def.id.lookup(db.upcast()); - let tree = loc.id.item_tree(db.upcast()); - let node = &tree[loc.id.value]; - let file_id = loc.id.file_id(); let ast_id_map = db.ast_id_map(file_id); acc.push(IncoherentImpl { impl_: ast_id_map.get(node.ast_id()), file_id }.into()) @@ -3278,9 +3284,9 @@ impl Impl { self.id.lookup(db.upcast()).container.into() } - pub fn is_builtin_derive(self, db: &dyn HirDatabase) -> Option> { + pub fn as_builtin_derive(self, db: &dyn HirDatabase) -> Option> { let src = self.source(db)?; - src.file_id.is_builtin_derive(db.upcast()) + src.file_id.as_builtin_derive_attr_node(db.upcast()) } } diff --git a/crates/ide/src/navigation_target.rs b/crates/ide/src/navigation_target.rs index 385c1b0c0081..c7abecb4f1e3 100644 --- a/crates/ide/src/navigation_target.rs +++ b/crates/ide/src/navigation_target.rs @@ -357,13 +357,11 @@ impl ToNav for hir::Module { impl TryToNav for hir::Impl { fn try_to_nav(&self, db: &RootDatabase) -> Option { let InFile { file_id, value } = self.source(db)?; - let derive_attr = self.is_builtin_derive(db); + let derive_attr = self.as_builtin_derive(db); - let focus = if derive_attr.is_some() { None } else { value.self_ty() }; - - let syntax = match &derive_attr { - Some(attr) => attr.value.syntax(), - None => value.syntax(), + let (focus, syntax) = match &derive_attr { + Some(attr) => (None, attr.value.syntax()), + None => (value.self_ty(), value.syntax()), }; let (file_id, full_range, focus_range) = orig_range_with_focus(db, file_id, syntax, focus); From bdc3d0f5514d677f31eb362172f564f6470d3c36 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 3 Jul 2023 14:42:27 +0200 Subject: [PATCH 137/324] Shuffle some proc_macro_expand query things around --- crates/hir-expand/src/db.rs | 87 +++++++++++++++++++++++-------------- 1 file changed, 54 insertions(+), 33 deletions(-) diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs index 78b2db7306b9..de653d76b483 100644 --- a/crates/hir-expand/src/db.rs +++ b/crates/hir-expand/src/db.rs @@ -57,10 +57,7 @@ impl TokenExpander { TokenExpander::BuiltinAttr(it) => it.expand(db, id, tt), TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt), TokenExpander::ProcMacro(_) => { - // We store the result in salsa db to prevent non-deterministic behavior in - // some proc-macro implementation - // See #4315 for details - db.expand_proc_macro(id) + unreachable!("ExpandDatabase::expand_proc_macro should be used for proc macros") } } } @@ -141,8 +138,8 @@ pub trait ExpandDatabase: SourceDatabase { /// Special case of the previous query for procedural macros. We can't LRU /// proc macros, since they are not deterministic in general, and /// non-determinism breaks salsa in a very, very, very bad way. - /// @edwin0cheng heroically debugged this once! - fn expand_proc_macro(&self, call: MacroCallId) -> ExpandResult; + /// @edwin0cheng heroically debugged this once! See #4315 for details + fn expand_proc_macro(&self, call: MacroCallId) -> ExpandResult>; /// Firewall query that returns the errors from the `parse_macro_expansion` query. fn parse_macro_expansion_error( &self, @@ -297,6 +294,14 @@ fn parse_macro_expansion( ExpandResult { value: (parse, Arc::new(rev_token_map)), err } } +fn parse_macro_expansion_error( + db: &dyn ExpandDatabase, + macro_call_id: MacroCallId, +) -> ExpandResult> { + db.parse_macro_expansion(MacroFile { macro_call_id }) + .map(|it| it.0.errors().to_vec().into_boxed_slice()) +} + fn macro_arg( db: &dyn ExpandDatabase, id: MacroCallId, @@ -445,6 +450,11 @@ fn macro_expand(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult it, // FIXME: We should make sure to enforce a variant that invalid macro @@ -467,7 +477,7 @@ fn macro_expand(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult ExpandResult ExpandResult ExpandResult> { - db.parse_macro_expansion(MacroFile { macro_call_id }) - .map(|it| it.0.errors().to_vec().into_boxed_slice()) -} - -fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult { +fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult> { let loc = db.lookup_intern_macro_call(id); let Some(macro_arg) = db.macro_arg(id) else { return ExpandResult { - value: tt::Subtree { + value: Arc::new(tt::Subtree { delimiter: tt::Delimiter::UNSPECIFIED, token_trees: Vec::new(), - }, + }), err: Some(ExpandError::other( "invalid token tree" )), }; }; + let (arg_tt, arg_tm, undo_info) = &*macro_arg; let expander = match loc.def.kind { MacroDefKind::ProcMacro(expander, ..) => expander, @@ -533,13 +525,23 @@ fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult { let mut attr_args = attr_args.0.clone(); - mbe::Shift::new(¯o_arg.0).shift_all(&mut attr_args); + mbe::Shift::new(arg_tt).shift_all(&mut attr_args); Some(attr_args) } _ => None, }; - expander.expand(db, loc.def.krate, loc.krate, ¯o_arg.0, attr_arg.as_ref()) + let ExpandResult { value: mut tt, err } = + expander.expand(db, loc.def.krate, loc.krate, arg_tt, attr_arg.as_ref()); + + // Set a hard limit for the expanded tt + if let Err(value) = check_tt_count(&tt) { + return value; + } + + fixup::reverse_fixups(&mut tt, arg_tm, undo_info); + + ExpandResult { value: Arc::new(tt), err } } fn hygiene_frame(db: &dyn ExpandDatabase, file_id: HirFileId) -> Arc { @@ -563,3 +565,22 @@ fn token_tree_to_syntax_node( }; mbe::token_tree_to_syntax_node(tt, entry_point) } + +fn check_tt_count(tt: &tt::Subtree) -> Result<(), ExpandResult>> { + let count = tt.count(); + if TOKEN_LIMIT.check(count).is_err() { + Err(ExpandResult { + value: Arc::new(tt::Subtree { + delimiter: tt::Delimiter::UNSPECIFIED, + token_trees: vec![], + }), + err: Some(ExpandError::other(format!( + "macro invocation exceeds token limit: produced {} tokens, limit is {}", + count, + TOKEN_LIMIT.inner(), + ))), + }) + } else { + Ok(()) + } +} From e52027861e0c2c0b966160e42fec33df92a2da9e Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 3 Jul 2023 16:03:22 +0200 Subject: [PATCH 138/324] Add analysis-stats flag to trigger some IDE features --- crates/ide-diagnostics/src/lib.rs | 3 + crates/ide/src/lib.rs | 2 +- .../rust-analyzer/src/cli/analysis_stats.rs | 87 ++++++++++++++++++- crates/rust-analyzer/src/cli/flags.rs | 5 ++ crates/rust-analyzer/src/config.rs | 1 + 5 files changed, 95 insertions(+), 3 deletions(-) diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs index f883ea8d4fc5..3d6cfddb3b6b 100644 --- a/crates/ide-diagnostics/src/lib.rs +++ b/crates/ide-diagnostics/src/lib.rs @@ -155,6 +155,8 @@ impl Default for ExprFillDefaultMode { #[derive(Debug, Clone)] pub struct DiagnosticsConfig { + /// Whether native diagnostics are enabled. + pub enabled: bool, pub proc_macros_enabled: bool, pub proc_attr_macros_enabled: bool, pub disable_experimental: bool, @@ -171,6 +173,7 @@ impl DiagnosticsConfig { use ide_db::imports::insert_use::ImportGranularity; Self { + enabled: true, proc_macros_enabled: Default::default(), proc_attr_macros_enabled: Default::default(), disable_experimental: Default::default(), diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index f195f78b3ab8..cb2a1140ba88 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -642,7 +642,7 @@ impl Analysis { }; self.with_db(|db| { - let diagnostic_assists = if include_fixes { + let diagnostic_assists = if diagnostics_config.enabled && include_fixes { ide_diagnostics::diagnostics(db, diagnostics_config, &resolve, frange.file_id) .into_iter() .flat_map(|it| it.fixes.unwrap_or_default()) diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index 826b89926bf3..1ceda8d824e7 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -15,7 +15,7 @@ use hir_def::{ hir::{ExprId, PatId}, }; use hir_ty::{Interner, Substitution, TyExt, TypeFlags}; -use ide::{LineCol, RootDatabase}; +use ide::{Analysis, AnnotationConfig, DiagnosticsConfig, InlayHintsConfig, LineCol, RootDatabase}; use ide_db::{ base_db::{ salsa::{self, debug::DebugQueryTable, ParallelDatabase}, @@ -30,7 +30,7 @@ use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace, RustLibSourc use rayon::prelude::*; use rustc_hash::FxHashSet; use syntax::{AstNode, SyntaxNode}; -use vfs::{AbsPathBuf, Vfs, VfsPath}; +use vfs::{AbsPathBuf, FileId, Vfs, VfsPath}; use crate::cli::{ flags::{self, OutputFormat}, @@ -149,8 +149,10 @@ impl flags::AnalysisStats { let mut bodies = Vec::new(); let mut adts = Vec::new(); let mut consts = Vec::new(); + let mut file_ids = Vec::new(); while let Some(module) = visit_queue.pop() { if visited_modules.insert(module) { + file_ids.extend(module.as_source_file_id(db)); visit_queue.extend(module.children(db)); for decl in module.declarations(db) { @@ -224,6 +226,10 @@ impl flags::AnalysisStats { self.run_const_eval(db, &consts, verbosity); } + if self.run_all_ide_things { + self.run_ide_things(host.analysis(), file_ids); + } + let total_span = analysis_sw.elapsed(); eprintln!("{:<20} {total_span}", "Total:"); report_metric("total time", total_span.time.as_millis() as u64, "ms"); @@ -729,6 +735,83 @@ impl flags::AnalysisStats { report_metric("body lowering time", body_lowering_time.time.as_millis() as u64, "ms"); } + fn run_ide_things(&self, analysis: Analysis, mut file_ids: Vec) { + file_ids.sort(); + file_ids.dedup(); + let mut sw = self.stop_watch(); + + for &file_id in &file_ids { + _ = analysis.diagnostics( + &DiagnosticsConfig { + enabled: true, + proc_macros_enabled: true, + proc_attr_macros_enabled: true, + disable_experimental: false, + disabled: Default::default(), + expr_fill_default: Default::default(), + insert_use: ide_db::imports::insert_use::InsertUseConfig { + granularity: ide_db::imports::insert_use::ImportGranularity::Crate, + enforce_granularity: true, + prefix_kind: hir::PrefixKind::ByCrate, + group: true, + skip_glob_imports: true, + }, + prefer_no_std: Default::default(), + }, + ide::AssistResolveStrategy::All, + file_id, + ); + } + for &file_id in &file_ids { + _ = analysis.inlay_hints( + &InlayHintsConfig { + render_colons: false, + type_hints: true, + discriminant_hints: ide::DiscriminantHints::Always, + parameter_hints: true, + chaining_hints: true, + adjustment_hints: ide::AdjustmentHints::Always, + adjustment_hints_mode: ide::AdjustmentHintsMode::Postfix, + adjustment_hints_hide_outside_unsafe: false, + closure_return_type_hints: ide::ClosureReturnTypeHints::Always, + closure_capture_hints: true, + binding_mode_hints: true, + lifetime_elision_hints: ide::LifetimeElisionHints::Always, + param_names_for_lifetime_elision_hints: true, + hide_named_constructor_hints: false, + hide_closure_initialization_hints: false, + closure_style: hir::ClosureStyle::ImplFn, + max_length: Some(25), + closing_brace_hints_min_lines: Some(20), + }, + file_id, + None, + ); + } + for &file_id in &file_ids { + analysis + .annotations( + &AnnotationConfig { + binary_target: true, + annotate_runnables: true, + annotate_impls: true, + annotate_references: false, + annotate_method_references: false, + annotate_enum_variant_references: false, + location: ide::AnnotationLocation::AboveName, + }, + file_id, + ) + .unwrap() + .into_iter() + .for_each(|annotation| { + _ = analysis.resolve_annotation(annotation); + }); + } + let ide_time = sw.elapsed(); + eprintln!("{:<20} {} ({} files)", "IDE:", ide_time, file_ids.len()); + } + fn stop_watch(&self) -> StopWatch { StopWatch::start().memory(self.memory_usage) } diff --git a/crates/rust-analyzer/src/cli/flags.rs b/crates/rust-analyzer/src/cli/flags.rs index 9848739504a3..31be535fc285 100644 --- a/crates/rust-analyzer/src/cli/flags.rs +++ b/crates/rust-analyzer/src/cli/flags.rs @@ -88,6 +88,10 @@ xflags::xflags! { optional --skip-data-layout /// Skip const evaluation optional --skip-const-eval + /// Runs several IDE features after analysis, including semantics highlighting, diagnostics + /// and annotations. This is useful for benchmarking the memory usage on a project that has + /// been worked on for a bit in a longer running session. + optional --run-all-ide-things } /// Run unit tests of the project using mir interpreter @@ -199,6 +203,7 @@ pub struct AnalysisStats { pub skip_mir_stats: bool, pub skip_data_layout: bool, pub skip_const_eval: bool, + pub run_all_ide_things: bool, } #[derive(Debug)] diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 6355c620f780..fa20c796ec27 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -1079,6 +1079,7 @@ impl Config { pub fn diagnostics(&self) -> DiagnosticsConfig { DiagnosticsConfig { + enabled: self.data.diagnostics_enable, proc_attr_macros_enabled: self.expand_proc_attr_macros(), proc_macros_enabled: self.data.procMacro_enable, disable_experimental: !self.data.diagnostics_experimental_enable, From 97748b0fc6d132504437777644ad3a240c417b14 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 27 Jun 2023 15:21:58 +0200 Subject: [PATCH 139/324] Speedup line index calculation via SSE2 --- Cargo.lock | 8 +- lib/line-index/Cargo.toml | 2 +- lib/line-index/src/lib.rs | 218 +++++++++++++++++++++++++++++------- lib/line-index/src/tests.rs | 127 +++++++++++++++++++-- lib/line-index/tests/it.rs | 62 ---------- 5 files changed, 303 insertions(+), 114 deletions(-) delete mode 100644 lib/line-index/tests/it.rs diff --git a/Cargo.lock b/Cargo.lock index d5a31e1e262c..dfc49c037dd1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -730,7 +730,7 @@ dependencies = [ "indexmap 2.0.0", "itertools", "limit", - "line-index 0.1.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)", + "line-index 0.1.0-pre.1", "memchr", "nohash-hasher", "once_cell", @@ -947,6 +947,8 @@ version = "0.0.0" [[package]] name = "line-index" version = "0.1.0-pre.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cad96769710c1745e11d4f940a8ff36000ade4bbada4285b001cb8aa2f745ce" dependencies = [ "nohash-hasher", "text-size", @@ -954,9 +956,7 @@ dependencies = [ [[package]] name = "line-index" -version = "0.1.0-pre.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cad96769710c1745e11d4f940a8ff36000ade4bbada4285b001cb8aa2f745ce" +version = "0.1.0" dependencies = [ "nohash-hasher", "text-size", diff --git a/lib/line-index/Cargo.toml b/lib/line-index/Cargo.toml index b267daa2050f..6c0d06f47178 100644 --- a/lib/line-index/Cargo.toml +++ b/lib/line-index/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "line-index" -version = "0.1.0-pre.1" +version = "0.1.0" description = "Maps flat `TextSize` offsets to/from `(line, column)` representation." license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/rust-analyzer/tree/master/lib/line-index" diff --git a/lib/line-index/src/lib.rs b/lib/line-index/src/lib.rs index ad67d3f246ec..58db93a58909 100644 --- a/lib/line-index/src/lib.rs +++ b/lib/line-index/src/lib.rs @@ -94,44 +94,7 @@ pub struct LineIndex { impl LineIndex { /// Returns a `LineIndex` for the `text`. pub fn new(text: &str) -> LineIndex { - let mut newlines = Vec::::with_capacity(16); - let mut line_wide_chars = IntMap::>::default(); - - let mut wide_chars = Vec::::new(); - let mut cur_row = TextSize::from(0); - let mut cur_col = TextSize::from(0); - let mut line = 0u32; - - for c in text.chars() { - let c_len = TextSize::of(c); - cur_row += c_len; - if c == '\n' { - newlines.push(cur_row); - - // Save any wide characters seen in the previous line - if !wide_chars.is_empty() { - let cs = std::mem::take(&mut wide_chars).into_boxed_slice(); - line_wide_chars.insert(line, cs); - } - - // Prepare for processing the next line - cur_col = TextSize::from(0); - line += 1; - continue; - } - - if !c.is_ascii() { - wide_chars.push(WideChar { start: cur_col, end: cur_col + c_len }); - } - - cur_col += c_len; - } - - // Save any wide characters seen in the last line - if !wide_chars.is_empty() { - line_wide_chars.insert(line, wide_chars.into_boxed_slice()); - } - + let (newlines, line_wide_chars) = analyze_source_file(text); LineIndex { newlines: newlines.into_boxed_slice(), line_wide_chars, @@ -235,3 +198,182 @@ impl LineIndex { self.len } } + +/// This is adapted from the rustc_span crate, https://github.com/rust-lang/rust/blob/master/compiler/rustc_span/src/analyze_source_file.rs +fn analyze_source_file(src: &str) -> (Vec, IntMap>) { + assert!(src.len() < !0u32 as usize); + let mut lines = vec![]; + let mut line_wide_chars = IntMap::>::default(); + + // Calls the right implementation, depending on hardware support available. + analyze_source_file_dispatch(src, &mut lines, &mut line_wide_chars); + + (lines, line_wide_chars.into_iter().map(|(k, v)| (k, v.into_boxed_slice())).collect()) +} + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +fn analyze_source_file_dispatch( + src: &str, + lines: &mut Vec, + multi_byte_chars: &mut IntMap>, +) { + if is_x86_feature_detected!("sse2") { + // SAFETY: SSE2 support was checked + unsafe { + analyze_source_file_sse2(src, lines, multi_byte_chars); + } + } else { + analyze_source_file_generic(src, src.len(), TextSize::from(0), lines, multi_byte_chars); + } +} + +/// Checks 16 byte chunks of text at a time. If the chunk contains +/// something other than printable ASCII characters and newlines, the +/// function falls back to the generic implementation. Otherwise it uses +/// SSE2 intrinsics to quickly find all newlines. +#[target_feature(enable = "sse2")] +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +unsafe fn analyze_source_file_sse2( + src: &str, + lines: &mut Vec, + multi_byte_chars: &mut IntMap>, +) { + #[cfg(target_arch = "x86")] + use std::arch::x86::*; + #[cfg(target_arch = "x86_64")] + use std::arch::x86_64::*; + + const CHUNK_SIZE: usize = 16; + + let src_bytes = src.as_bytes(); + + let chunk_count = src.len() / CHUNK_SIZE; + + // This variable keeps track of where we should start decoding a + // chunk. If a multi-byte character spans across chunk boundaries, + // we need to skip that part in the next chunk because we already + // handled it. + let mut intra_chunk_offset = 0; + + for chunk_index in 0..chunk_count { + let ptr = src_bytes.as_ptr() as *const __m128i; + // We don't know if the pointer is aligned to 16 bytes, so we + // use `loadu`, which supports unaligned loading. + let chunk = _mm_loadu_si128(ptr.add(chunk_index)); + + // For character in the chunk, see if its byte value is < 0, which + // indicates that it's part of a UTF-8 char. + let multibyte_test = _mm_cmplt_epi8(chunk, _mm_set1_epi8(0)); + // Create a bit mask from the comparison results. + let multibyte_mask = _mm_movemask_epi8(multibyte_test); + + // If the bit mask is all zero, we only have ASCII chars here: + if multibyte_mask == 0 { + assert!(intra_chunk_offset == 0); + + // Check for newlines in the chunk + let newlines_test = _mm_cmpeq_epi8(chunk, _mm_set1_epi8(b'\n' as i8)); + let newlines_mask = _mm_movemask_epi8(newlines_test); + + if newlines_mask != 0 { + // All control characters are newlines, record them + let mut newlines_mask = 0xFFFF0000 | newlines_mask as u32; + let output_offset = TextSize::from((chunk_index * CHUNK_SIZE + 1) as u32); + + loop { + let index = newlines_mask.trailing_zeros(); + + if index >= CHUNK_SIZE as u32 { + // We have arrived at the end of the chunk. + break; + } + + lines.push(TextSize::from(index) + output_offset); + + // Clear the bit, so we can find the next one. + newlines_mask &= (!1) << index; + } + } + continue; + } + + // The slow path. + // There are control chars in here, fallback to generic decoding. + let scan_start = chunk_index * CHUNK_SIZE + intra_chunk_offset; + intra_chunk_offset = analyze_source_file_generic( + &src[scan_start..], + CHUNK_SIZE - intra_chunk_offset, + TextSize::from(scan_start as u32), + lines, + multi_byte_chars, + ); + } + + // There might still be a tail left to analyze + let tail_start = chunk_count * CHUNK_SIZE + intra_chunk_offset; + if tail_start < src.len() { + analyze_source_file_generic( + &src[tail_start..], + src.len() - tail_start, + TextSize::from(tail_start as u32), + lines, + multi_byte_chars, + ); + } +} + +#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +// The target (or compiler version) does not support SSE2 ... +fn analyze_source_file_dispatch( + src: &str, + lines: &mut Vec, + multi_byte_chars: &mut IntMap>, +) { + analyze_source_file_generic(src, src.len(), TextSize::from(0), lines, multi_byte_chars); +} + +// `scan_len` determines the number of bytes in `src` to scan. Note that the +// function can read past `scan_len` if a multi-byte character start within the +// range but extends past it. The overflow is returned by the function. +fn analyze_source_file_generic( + src: &str, + scan_len: usize, + output_offset: TextSize, + lines: &mut Vec, + multi_byte_chars: &mut IntMap>, +) -> usize { + assert!(src.len() >= scan_len); + let mut i = 0; + let src_bytes = src.as_bytes(); + + while i < scan_len { + let byte = unsafe { + // We verified that i < scan_len <= src.len() + *src_bytes.get_unchecked(i) + }; + + // How much to advance in order to get to the next UTF-8 char in the + // string. + let mut char_len = 1; + + if byte == b'\n' { + lines.push(TextSize::from(i as u32 + 1) + output_offset); + } else if byte >= 127 { + // The slow path: Just decode to `char`. + let c = src[i..].chars().next().unwrap(); + char_len = c.len_utf8(); + + let pos = TextSize::from(i as u32) + output_offset; + + if char_len > 1 { + assert!((2..=4).contains(&char_len)); + let mbc = WideChar { start: pos, end: pos + TextSize::from(char_len as u32) }; + multi_byte_chars.entry(lines.len() as u32).or_default().push(mbc); + } + } + + i += char_len; + } + + i - scan_len +} diff --git a/lib/line-index/src/tests.rs b/lib/line-index/src/tests.rs index 31c01c20ee36..8f3762d19106 100644 --- a/lib/line-index/src/tests.rs +++ b/lib/line-index/src/tests.rs @@ -1,11 +1,120 @@ -use super::LineIndex; +use crate::{LineIndex, TextSize, WideChar}; -#[test] -fn test_empty_index() { - let col_index = LineIndex::new( - " -const C: char = 'x'; -", - ); - assert_eq!(col_index.line_wide_chars.len(), 0); +macro_rules! test { + ( + case: $test_name:ident, + text: $text:expr, + lines: $lines:expr, + multi_byte_chars: $multi_byte_chars:expr, + ) => { + #[test] + fn $test_name() { + let line_index = LineIndex::new($text); + + let expected_lines: Vec = + $lines.into_iter().map(>::from).collect(); + + assert_eq!(&*line_index.newlines, &*expected_lines); + + let expected_mbcs: Vec<_> = $multi_byte_chars + .into_iter() + .map(|(line, (pos, end)): (u32, (u32, u32))| { + (line, WideChar { start: TextSize::from(pos), end: TextSize::from(end) }) + }) + .collect(); + + assert_eq!( + line_index + .line_wide_chars + .iter() + .flat_map(|(line, val)| std::iter::repeat(*line).zip(val.iter().copied())) + .collect::>(), + expected_mbcs + ); + } + }; } + +test!( + case: empty_text, + text: "", + lines: vec![], + multi_byte_chars: vec![], +); + +test!( + case: newlines_short, + text: "a\nc", + lines: vec![2], + multi_byte_chars: vec![], +); + +test!( + case: newlines_long, + text: "012345678\nabcdef012345678\na", + lines: vec![10, 26], + multi_byte_chars: vec![], +); + +test!( + case: newline_and_multi_byte_char_in_same_chunk, + text: "01234β789\nbcdef0123456789abcdef", + lines: vec![11], + multi_byte_chars: vec![(0, (5, 7))], +); + +test!( + case: newline_and_control_char_in_same_chunk, + text: "01234\u{07}6789\nbcdef0123456789abcdef", + lines: vec![11], + multi_byte_chars: vec![], +); + +test!( + case: multi_byte_char_short, + text: "aβc", + lines: vec![], + multi_byte_chars: vec![(0, (1, 3))], +); + +test!( + case: multi_byte_char_long, + text: "0123456789abcΔf012345β", + lines: vec![], + multi_byte_chars: vec![(0, (13, 15)), (0, (22, 24))], +); + +test!( + case: multi_byte_char_across_chunk_boundary, + text: "0123456789abcdeΔ123456789abcdef01234", + lines: vec![], + multi_byte_chars: vec![(0, (15, 17))], +); + +test!( + case: multi_byte_char_across_chunk_boundary_tail, + text: "0123456789abcdeΔ....", + lines: vec![], + multi_byte_chars: vec![(0, (15, 17))], +); + +test!( + case: multi_byte_with_new_lines, + text: "01\t345\n789abcΔf01234567\u{07}9\nbcΔf", + lines: vec![7, 27], + multi_byte_chars: vec![(1, (13, 15)), (2, (29, 31))], +); + +test!( + case: trailing_newline, + text: "0123456789\n", + lines: vec![11], + multi_byte_chars: vec![], +); + +test!( + case: trailing_newline_chunk_boundary, + text: "0123456789abcde\n", + lines: vec![16], + multi_byte_chars: vec![], +); diff --git a/lib/line-index/tests/it.rs b/lib/line-index/tests/it.rs deleted file mode 100644 index ce1c0bc6f143..000000000000 --- a/lib/line-index/tests/it.rs +++ /dev/null @@ -1,62 +0,0 @@ -use line_index::{LineCol, LineIndex, TextRange}; - -#[test] -fn test_line_index() { - let text = "hello\nworld"; - let table = [ - (00, 0, 0), - (01, 0, 1), - (05, 0, 5), - (06, 1, 0), - (07, 1, 1), - (08, 1, 2), - (10, 1, 4), - (11, 1, 5), - ]; - - let index = LineIndex::new(text); - for (offset, line, col) in table { - assert_eq!(index.line_col(offset.into()), LineCol { line, col }); - } - - let text = "\nhello\nworld"; - let table = [(0, 0, 0), (1, 1, 0), (2, 1, 1), (6, 1, 5), (7, 2, 0)]; - let index = LineIndex::new(text); - for (offset, line, col) in table { - assert_eq!(index.line_col(offset.into()), LineCol { line, col }); - } -} - -#[test] -fn test_char_len() { - assert_eq!('メ'.len_utf8(), 3); - assert_eq!('メ'.len_utf16(), 1); -} - -#[test] -fn test_splitlines() { - fn r(lo: u32, hi: u32) -> TextRange { - TextRange::new(lo.into(), hi.into()) - } - - let text = "a\nbb\nccc\n"; - let line_index = LineIndex::new(text); - - let actual = line_index.lines(r(0, 9)).collect::>(); - let expected = vec![r(0, 2), r(2, 5), r(5, 9)]; - assert_eq!(actual, expected); - - let text = ""; - let line_index = LineIndex::new(text); - - let actual = line_index.lines(r(0, 0)).collect::>(); - let expected = vec![]; - assert_eq!(actual, expected); - - let text = "\n"; - let line_index = LineIndex::new(text); - - let actual = line_index.lines(r(0, 1)).collect::>(); - let expected = vec![r(0, 1)]; - assert_eq!(actual, expected) -} From 28fcd1bdd762455509914850e31aa983c7ff952c Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 3 Jul 2023 17:40:31 +0200 Subject: [PATCH 140/324] Split out project loading capabilities from rust-analyzer crate --- Cargo.lock | 19 +- Cargo.toml | 1 + crates/load-cargo/Cargo.toml | 23 + crates/load-cargo/src/lib.rs | 441 ++++++++++++++++++ crates/rust-analyzer/Cargo.toml | 2 +- crates/rust-analyzer/src/cli.rs | 1 - .../rust-analyzer/src/cli/analysis_stats.rs | 5 +- crates/rust-analyzer/src/cli/diagnostics.rs | 6 +- crates/rust-analyzer/src/cli/load_cargo.rs | 204 -------- crates/rust-analyzer/src/cli/lsif.rs | 22 +- crates/rust-analyzer/src/cli/run_tests.rs | 9 +- crates/rust-analyzer/src/cli/scip.rs | 13 +- crates/rust-analyzer/src/cli/ssr.rs | 6 +- crates/rust-analyzer/src/global_state.rs | 3 +- .../src/integrated_benchmarks.rs | 2 +- crates/rust-analyzer/src/reload.rs | 265 +---------- 16 files changed, 518 insertions(+), 504 deletions(-) create mode 100644 crates/load-cargo/Cargo.toml create mode 100644 crates/load-cargo/src/lib.rs delete mode 100644 crates/rust-analyzer/src/cli/load_cargo.rs diff --git a/Cargo.lock b/Cargo.lock index 01d891004282..5621224116a1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -962,6 +962,23 @@ dependencies = [ "text-size", ] +[[package]] +name = "load-cargo" +version = "0.0.0" +dependencies = [ + "anyhow", + "crossbeam-channel", + "ide", + "ide-db", + "itertools", + "proc-macro-api", + "project-model", + "tracing", + "tt", + "vfs", + "vfs-notify", +] + [[package]] name = "lock_api" version = "0.4.10" @@ -1535,6 +1552,7 @@ dependencies = [ "ide-db", "ide-ssr", "itertools", + "load-cargo", "lsp-server 0.7.1", "lsp-types", "mbe", @@ -1564,7 +1582,6 @@ dependencies = [ "tracing-subscriber", "tracing-tree", "triomphe", - "tt", "vfs", "vfs-notify", "winapi", diff --git a/Cargo.toml b/Cargo.toml index 83d9fd801e29..24889fc1421b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,6 +61,7 @@ ide-diagnostics = { path = "./crates/ide-diagnostics", version = "0.0.0" } ide-ssr = { path = "./crates/ide-ssr", version = "0.0.0" } intern = { path = "./crates/intern", version = "0.0.0" } limit = { path = "./crates/limit", version = "0.0.0" } +load-cargo = { path = "./crates/load-cargo", version = "0.0.0" } mbe = { path = "./crates/mbe", version = "0.0.0" } parser = { path = "./crates/parser", version = "0.0.0" } paths = { path = "./crates/paths", version = "0.0.0" } diff --git a/crates/load-cargo/Cargo.toml b/crates/load-cargo/Cargo.toml new file mode 100644 index 000000000000..4a6946d7f617 --- /dev/null +++ b/crates/load-cargo/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "load-cargo" +version = "0.0.0" +rust-version.workspace = true +edition.workspace = true +license.workspace = true +authors.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1.0.62" +crossbeam-channel = "0.5.5" +itertools = "0.10.5" +tracing = "0.1.35" + +ide.workspace = true +ide-db.workspace =true +proc-macro-api.workspace = true +project-model.workspace = true +tt.workspace = true +vfs.workspace = true +vfs-notify.workspace = true diff --git a/crates/load-cargo/src/lib.rs b/crates/load-cargo/src/lib.rs new file mode 100644 index 000000000000..7a795dd62ab7 --- /dev/null +++ b/crates/load-cargo/src/lib.rs @@ -0,0 +1,441 @@ +//! Loads a Cargo project into a static instance of analysis, without support +//! for incorporating changes. +// Note, don't remove any public api from this. This API is consumed by external tools +// to run rust-analyzer as a library. +use std::{collections::hash_map::Entry, mem, path::Path, sync}; + +use ::tt::token_id as tt; +use crossbeam_channel::{unbounded, Receiver}; +use ide::{AnalysisHost, Change, SourceRoot}; +use ide_db::{ + base_db::{ + CrateGraph, Env, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind, + ProcMacroLoadResult, ProcMacros, + }, + FxHashMap, +}; +use itertools::Itertools; +use proc_macro_api::{MacroDylib, ProcMacroServer}; +use project_model::{CargoConfig, PackageRoot, ProjectManifest, ProjectWorkspace}; +use vfs::{file_set::FileSetConfig, loader::Handle, AbsPath, AbsPathBuf, VfsPath}; + +pub struct LoadCargoConfig { + pub load_out_dirs_from_check: bool, + pub with_proc_macro_server: ProcMacroServerChoice, + pub prefill_caches: bool, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum ProcMacroServerChoice { + Sysroot, + Explicit(AbsPathBuf), + None, +} + +pub fn load_workspace_at( + root: &Path, + cargo_config: &CargoConfig, + load_config: &LoadCargoConfig, + progress: &dyn Fn(String), +) -> anyhow::Result<(AnalysisHost, vfs::Vfs, Option)> { + let root = AbsPathBuf::assert(std::env::current_dir()?.join(root)); + let root = ProjectManifest::discover_single(&root)?; + let mut workspace = ProjectWorkspace::load(root, cargo_config, progress)?; + + if load_config.load_out_dirs_from_check { + let build_scripts = workspace.run_build_scripts(cargo_config, progress)?; + workspace.set_build_scripts(build_scripts) + } + + load_workspace(workspace, &cargo_config.extra_env, load_config) +} + +pub fn load_workspace( + ws: ProjectWorkspace, + extra_env: &FxHashMap, + load_config: &LoadCargoConfig, +) -> anyhow::Result<(AnalysisHost, vfs::Vfs, Option)> { + let (sender, receiver) = unbounded(); + let mut vfs = vfs::Vfs::default(); + let mut loader = { + let loader = + vfs_notify::NotifyHandle::spawn(Box::new(move |msg| sender.send(msg).unwrap())); + Box::new(loader) + }; + + let proc_macro_server = match &load_config.with_proc_macro_server { + ProcMacroServerChoice::Sysroot => ws + .find_sysroot_proc_macro_srv() + .and_then(|it| ProcMacroServer::spawn(it).map_err(Into::into)), + ProcMacroServerChoice::Explicit(path) => { + ProcMacroServer::spawn(path.clone()).map_err(Into::into) + } + ProcMacroServerChoice::None => Err(anyhow::format_err!("proc macro server disabled")), + }; + + let (crate_graph, proc_macros) = ws.to_crate_graph( + &mut |path: &AbsPath| { + let contents = loader.load_sync(path); + let path = vfs::VfsPath::from(path.to_path_buf()); + vfs.set_file_contents(path.clone(), contents); + vfs.file_id(&path) + }, + extra_env, + ); + let proc_macros = { + let proc_macro_server = match &proc_macro_server { + Ok(it) => Ok(it), + Err(e) => Err(e.to_string()), + }; + proc_macros + .into_iter() + .map(|(crate_id, path)| { + ( + crate_id, + path.map_or_else( + |_| Err("proc macro crate is missing dylib".to_owned()), + |(_, path)| { + proc_macro_server.as_ref().map_err(Clone::clone).and_then( + |proc_macro_server| load_proc_macro(proc_macro_server, &path, &[]), + ) + }, + ), + ) + }) + .collect() + }; + + let project_folders = ProjectFolders::new(&[ws], &[]); + loader.set_config(vfs::loader::Config { + load: project_folders.load, + watch: vec![], + version: 0, + }); + + let host = load_crate_graph( + crate_graph, + proc_macros, + project_folders.source_root_config, + &mut vfs, + &receiver, + ); + + if load_config.prefill_caches { + host.analysis().parallel_prime_caches(1, |_| {})?; + } + Ok((host, vfs, proc_macro_server.ok())) +} + +#[derive(Default)] +pub struct ProjectFolders { + pub load: Vec, + pub watch: Vec, + pub source_root_config: SourceRootConfig, +} + +impl ProjectFolders { + pub fn new(workspaces: &[ProjectWorkspace], global_excludes: &[AbsPathBuf]) -> ProjectFolders { + let mut res = ProjectFolders::default(); + let mut fsc = FileSetConfig::builder(); + let mut local_filesets = vec![]; + + // Dedup source roots + // Depending on the project setup, we can have duplicated source roots, or for example in + // the case of the rustc workspace, we can end up with two source roots that are almost the + // same but not quite, like: + // PackageRoot { is_local: false, include: [AbsPathBuf(".../rust/src/tools/miri/cargo-miri")], exclude: [] } + // PackageRoot { + // is_local: true, + // include: [AbsPathBuf(".../rust/src/tools/miri/cargo-miri"), AbsPathBuf(".../rust/build/x86_64-pc-windows-msvc/stage0-tools/x86_64-pc-windows-msvc/release/build/cargo-miri-85801cd3d2d1dae4/out")], + // exclude: [AbsPathBuf(".../rust/src/tools/miri/cargo-miri/.git"), AbsPathBuf(".../rust/src/tools/miri/cargo-miri/target")] + // } + // + // The first one comes from the explicit rustc workspace which points to the rustc workspace itself + // The second comes from the rustc workspace that we load as the actual project workspace + // These `is_local` differing in this kind of way gives us problems, especially when trying to filter diagnostics as we don't report diagnostics for external libraries. + // So we need to deduplicate these, usually it would be enough to deduplicate by `include`, but as the rustc example shows here that doesn't work, + // so we need to also coalesce the includes if they overlap. + + let mut roots: Vec<_> = workspaces + .iter() + .flat_map(|ws| ws.to_roots()) + .update(|root| root.include.sort()) + .sorted_by(|a, b| a.include.cmp(&b.include)) + .collect(); + + // map that tracks indices of overlapping roots + let mut overlap_map = FxHashMap::<_, Vec<_>>::default(); + let mut done = false; + + while !mem::replace(&mut done, true) { + // maps include paths to indices of the corresponding root + let mut include_to_idx = FxHashMap::default(); + // Find and note down the indices of overlapping roots + for (idx, root) in roots.iter().enumerate().filter(|(_, it)| !it.include.is_empty()) { + for include in &root.include { + match include_to_idx.entry(include) { + Entry::Occupied(e) => { + overlap_map.entry(*e.get()).or_default().push(idx); + } + Entry::Vacant(e) => { + e.insert(idx); + } + } + } + } + for (k, v) in overlap_map.drain() { + done = false; + for v in v { + let r = mem::replace( + &mut roots[v], + PackageRoot { is_local: false, include: vec![], exclude: vec![] }, + ); + roots[k].is_local |= r.is_local; + roots[k].include.extend(r.include); + roots[k].exclude.extend(r.exclude); + } + roots[k].include.sort(); + roots[k].exclude.sort(); + roots[k].include.dedup(); + roots[k].exclude.dedup(); + } + } + + for root in roots.into_iter().filter(|it| !it.include.is_empty()) { + let file_set_roots: Vec = + root.include.iter().cloned().map(VfsPath::from).collect(); + + let entry = { + let mut dirs = vfs::loader::Directories::default(); + dirs.extensions.push("rs".into()); + dirs.include.extend(root.include); + dirs.exclude.extend(root.exclude); + for excl in global_excludes { + if dirs + .include + .iter() + .any(|incl| incl.starts_with(excl) || excl.starts_with(incl)) + { + dirs.exclude.push(excl.clone()); + } + } + + vfs::loader::Entry::Directories(dirs) + }; + + if root.is_local { + res.watch.push(res.load.len()); + } + res.load.push(entry); + + if root.is_local { + local_filesets.push(fsc.len()); + } + fsc.add_file_set(file_set_roots) + } + + let fsc = fsc.build(); + res.source_root_config = SourceRootConfig { fsc, local_filesets }; + + res + } +} + +#[derive(Default, Debug)] +pub struct SourceRootConfig { + pub fsc: FileSetConfig, + pub local_filesets: Vec, +} + +impl SourceRootConfig { + pub fn partition(&self, vfs: &vfs::Vfs) -> Vec { + self.fsc + .partition(vfs) + .into_iter() + .enumerate() + .map(|(idx, file_set)| { + let is_local = self.local_filesets.contains(&idx); + if is_local { + SourceRoot::new_local(file_set) + } else { + SourceRoot::new_library(file_set) + } + }) + .collect() + } +} + +/// Load the proc-macros for the given lib path, replacing all expanders whose names are in `dummy_replace` +/// with an identity dummy expander. +pub fn load_proc_macro( + server: &ProcMacroServer, + path: &AbsPath, + dummy_replace: &[Box], +) -> ProcMacroLoadResult { + let res: Result, String> = (|| { + let dylib = MacroDylib::new(path.to_path_buf()); + let vec = server.load_dylib(dylib).map_err(|e| format!("{e}"))?; + if vec.is_empty() { + return Err("proc macro library returned no proc macros".to_string()); + } + Ok(vec + .into_iter() + .map(|expander| expander_to_proc_macro(expander, dummy_replace)) + .collect()) + })(); + match res { + Ok(proc_macros) => { + tracing::info!( + "Loaded proc-macros for {path}: {:?}", + proc_macros.iter().map(|it| it.name.clone()).collect::>() + ); + Ok(proc_macros) + } + Err(e) => { + tracing::warn!("proc-macro loading for {path} failed: {e}"); + Err(e) + } + } +} + +fn load_crate_graph( + crate_graph: CrateGraph, + proc_macros: ProcMacros, + source_root_config: SourceRootConfig, + vfs: &mut vfs::Vfs, + receiver: &Receiver, +) -> AnalysisHost { + let lru_cap = std::env::var("RA_LRU_CAP").ok().and_then(|it| it.parse::().ok()); + let mut host = AnalysisHost::new(lru_cap); + let mut analysis_change = Change::new(); + + host.raw_database_mut().enable_proc_attr_macros(); + + // wait until Vfs has loaded all roots + for task in receiver { + match task { + vfs::loader::Message::Progress { n_done, n_total, config_version: _ } => { + if n_done == n_total { + break; + } + } + vfs::loader::Message::Loaded { files } => { + for (path, contents) in files { + vfs.set_file_contents(path.into(), contents); + } + } + } + } + let changes = vfs.take_changes(); + for file in changes { + if file.exists() { + let contents = vfs.file_contents(file.file_id); + if let Ok(text) = std::str::from_utf8(contents) { + analysis_change.change_file(file.file_id, Some(text.into())) + } + } + } + let source_roots = source_root_config.partition(vfs); + analysis_change.set_roots(source_roots); + + analysis_change.set_crate_graph(crate_graph); + analysis_change.set_proc_macros(proc_macros); + + host.apply_change(analysis_change); + host +} + +fn expander_to_proc_macro( + expander: proc_macro_api::ProcMacro, + dummy_replace: &[Box], +) -> ProcMacro { + let name = From::from(expander.name()); + let kind = match expander.kind() { + proc_macro_api::ProcMacroKind::CustomDerive => ProcMacroKind::CustomDerive, + proc_macro_api::ProcMacroKind::FuncLike => ProcMacroKind::FuncLike, + proc_macro_api::ProcMacroKind::Attr => ProcMacroKind::Attr, + }; + let expander: sync::Arc = + if dummy_replace.iter().any(|replace| &**replace == name) { + match kind { + ProcMacroKind::Attr => sync::Arc::new(IdentityExpander), + _ => sync::Arc::new(EmptyExpander), + } + } else { + sync::Arc::new(Expander(expander)) + }; + ProcMacro { name, kind, expander } +} + +#[derive(Debug)] +struct Expander(proc_macro_api::ProcMacro); + +impl ProcMacroExpander for Expander { + fn expand( + &self, + subtree: &tt::Subtree, + attrs: Option<&tt::Subtree>, + env: &Env, + ) -> Result { + let env = env.iter().map(|(k, v)| (k.to_string(), v.to_string())).collect(); + match self.0.expand(subtree, attrs, env) { + Ok(Ok(subtree)) => Ok(subtree), + Ok(Err(err)) => Err(ProcMacroExpansionError::Panic(err.0)), + Err(err) => Err(ProcMacroExpansionError::System(err.to_string())), + } + } +} + +/// Dummy identity expander, used for attribute proc-macros that are deliberately ignored by the user. +#[derive(Debug)] +struct IdentityExpander; + +impl ProcMacroExpander for IdentityExpander { + fn expand( + &self, + subtree: &tt::Subtree, + _: Option<&tt::Subtree>, + _: &Env, + ) -> Result { + Ok(subtree.clone()) + } +} + +/// Empty expander, used for proc-macros that are deliberately ignored by the user. +#[derive(Debug)] +struct EmptyExpander; + +impl ProcMacroExpander for EmptyExpander { + fn expand( + &self, + _: &tt::Subtree, + _: Option<&tt::Subtree>, + _: &Env, + ) -> Result { + Ok(tt::Subtree::empty()) + } +} + +#[cfg(test)] +mod tests { + use ide_db::base_db::SourceDatabase; + + use super::*; + + #[test] + fn test_loading_rust_analyzer() { + let path = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap().parent().unwrap(); + let cargo_config = CargoConfig::default(); + let load_cargo_config = LoadCargoConfig { + load_out_dirs_from_check: false, + with_proc_macro_server: ProcMacroServerChoice::None, + prefill_caches: false, + }; + let (host, _vfs, _proc_macro) = + load_workspace_at(path, &cargo_config, &load_cargo_config, &|_| {}).unwrap(); + + let n_crates = host.raw_database().crate_graph().iter().count(); + // RA has quite a few crates, but the exact count doesn't matter + assert!(n_crates > 20); + } +} diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index 14104b095504..5bfac7ee45c6 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml @@ -62,13 +62,13 @@ ide-db.workspace = true # This should only be used in CLI ide-ssr.workspace = true ide.workspace = true +load-cargo.workspace = true proc-macro-api.workspace = true profile.workspace = true project-model.workspace = true stdx.workspace = true syntax.workspace = true toolchain.workspace = true -tt.workspace = true vfs-notify.workspace = true vfs.workspace = true diff --git a/crates/rust-analyzer/src/cli.rs b/crates/rust-analyzer/src/cli.rs index 893eadf3fa10..64646b33ad48 100644 --- a/crates/rust-analyzer/src/cli.rs +++ b/crates/rust-analyzer/src/cli.rs @@ -1,7 +1,6 @@ //! Various batch processing tasks, intended primarily for debugging. pub mod flags; -pub mod load_cargo; mod parse; mod symbols; mod highlight; diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index 826b89926bf3..1c09af9abd2b 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -24,6 +24,7 @@ use ide_db::{ LineIndexDatabase, }; use itertools::Itertools; +use load_cargo::{load_workspace, LoadCargoConfig, ProcMacroServerChoice}; use oorandom::Rand32; use profile::{Bytes, StopWatch}; use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace, RustLibSource}; @@ -34,9 +35,7 @@ use vfs::{AbsPathBuf, Vfs, VfsPath}; use crate::cli::{ flags::{self, OutputFormat}, - full_name_of_item, - load_cargo::{load_workspace, LoadCargoConfig, ProcMacroServerChoice}, - print_memory_usage, + full_name_of_item, print_memory_usage, progress_report::ProgressReport, report_metric, Verbosity, }; diff --git a/crates/rust-analyzer/src/cli/diagnostics.rs b/crates/rust-analyzer/src/cli/diagnostics.rs index 0b46f35074e7..0db5fb4740ea 100644 --- a/crates/rust-analyzer/src/cli/diagnostics.rs +++ b/crates/rust-analyzer/src/cli/diagnostics.rs @@ -7,11 +7,9 @@ use rustc_hash::FxHashSet; use hir::{db::HirDatabase, Crate, Module}; use ide::{AssistResolveStrategy, DiagnosticsConfig, Severity}; use ide_db::base_db::SourceDatabaseExt; +use load_cargo::{load_workspace_at, LoadCargoConfig, ProcMacroServerChoice}; -use crate::cli::{ - flags, - load_cargo::{load_workspace_at, LoadCargoConfig, ProcMacroServerChoice}, -}; +use crate::cli::flags; impl flags::Diagnostics { pub fn run(self) -> anyhow::Result<()> { diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs deleted file mode 100644 index 1b413029e0c6..000000000000 --- a/crates/rust-analyzer/src/cli/load_cargo.rs +++ /dev/null @@ -1,204 +0,0 @@ -//! Loads a Cargo project into a static instance of analysis, without support -//! for incorporating changes. -use std::path::Path; - -use crossbeam_channel::{unbounded, Receiver}; -use ide::{AnalysisHost, Change}; -use ide_db::{ - base_db::{CrateGraph, ProcMacros}, - FxHashMap, -}; -use proc_macro_api::ProcMacroServer; -use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace}; -use triomphe::Arc; -use vfs::{loader::Handle, AbsPath, AbsPathBuf}; - -use crate::reload::{load_proc_macro, ProjectFolders, SourceRootConfig}; - -// Note: Since this type is used by external tools that use rust-analyzer as a library -// what otherwise would be `pub(crate)` has to be `pub` here instead. -pub struct LoadCargoConfig { - pub load_out_dirs_from_check: bool, - pub with_proc_macro_server: ProcMacroServerChoice, - pub prefill_caches: bool, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ProcMacroServerChoice { - Sysroot, - Explicit(AbsPathBuf), - None, -} - -// Note: Since this function is used by external tools that use rust-analyzer as a library -// what otherwise would be `pub(crate)` has to be `pub` here instead. -pub fn load_workspace_at( - root: &Path, - cargo_config: &CargoConfig, - load_config: &LoadCargoConfig, - progress: &dyn Fn(String), -) -> anyhow::Result<(AnalysisHost, vfs::Vfs, Option)> { - let root = AbsPathBuf::assert(std::env::current_dir()?.join(root)); - let root = ProjectManifest::discover_single(&root)?; - let mut workspace = ProjectWorkspace::load(root, cargo_config, progress)?; - - if load_config.load_out_dirs_from_check { - let build_scripts = workspace.run_build_scripts(cargo_config, progress)?; - workspace.set_build_scripts(build_scripts) - } - - load_workspace(workspace, &cargo_config.extra_env, load_config) -} - -// Note: Since this function is used by external tools that use rust-analyzer as a library -// what otherwise would be `pub(crate)` has to be `pub` here instead. -// -// The reason both, `load_workspace_at` and `load_workspace` are `pub` is that some of -// these tools need access to `ProjectWorkspace`, too, which `load_workspace_at` hides. -pub fn load_workspace( - ws: ProjectWorkspace, - extra_env: &FxHashMap, - load_config: &LoadCargoConfig, -) -> anyhow::Result<(AnalysisHost, vfs::Vfs, Option)> { - let (sender, receiver) = unbounded(); - let mut vfs = vfs::Vfs::default(); - let mut loader = { - let loader = - vfs_notify::NotifyHandle::spawn(Box::new(move |msg| sender.send(msg).unwrap())); - Box::new(loader) - }; - - let proc_macro_server = match &load_config.with_proc_macro_server { - ProcMacroServerChoice::Sysroot => ws - .find_sysroot_proc_macro_srv() - .and_then(|it| ProcMacroServer::spawn(it).map_err(Into::into)), - ProcMacroServerChoice::Explicit(path) => { - ProcMacroServer::spawn(path.clone()).map_err(Into::into) - } - ProcMacroServerChoice::None => Err(anyhow::format_err!("proc macro server disabled")), - }; - - let (crate_graph, proc_macros) = ws.to_crate_graph( - &mut |path: &AbsPath| { - let contents = loader.load_sync(path); - let path = vfs::VfsPath::from(path.to_path_buf()); - vfs.set_file_contents(path.clone(), contents); - vfs.file_id(&path) - }, - extra_env, - ); - let proc_macros = { - let proc_macro_server = match &proc_macro_server { - Ok(it) => Ok(it), - Err(e) => Err(e.to_string()), - }; - proc_macros - .into_iter() - .map(|(crate_id, path)| { - ( - crate_id, - path.map_or_else( - |_| Err("proc macro crate is missing dylib".to_owned()), - |(_, path)| { - proc_macro_server.as_ref().map_err(Clone::clone).and_then( - |proc_macro_server| load_proc_macro(proc_macro_server, &path, &[]), - ) - }, - ), - ) - }) - .collect() - }; - - let project_folders = ProjectFolders::new(&[ws], &[]); - loader.set_config(vfs::loader::Config { - load: project_folders.load, - watch: vec![], - version: 0, - }); - - tracing::debug!("crate graph: {:?}", crate_graph); - let host = load_crate_graph( - crate_graph, - proc_macros, - project_folders.source_root_config, - &mut vfs, - &receiver, - ); - - if load_config.prefill_caches { - host.analysis().parallel_prime_caches(1, |_| {})?; - } - Ok((host, vfs, proc_macro_server.ok())) -} - -fn load_crate_graph( - crate_graph: CrateGraph, - proc_macros: ProcMacros, - source_root_config: SourceRootConfig, - vfs: &mut vfs::Vfs, - receiver: &Receiver, -) -> AnalysisHost { - let lru_cap = std::env::var("RA_LRU_CAP").ok().and_then(|it| it.parse::().ok()); - let mut host = AnalysisHost::new(lru_cap); - let mut analysis_change = Change::new(); - - host.raw_database_mut().enable_proc_attr_macros(); - - // wait until Vfs has loaded all roots - for task in receiver { - match task { - vfs::loader::Message::Progress { n_done, n_total, config_version: _ } => { - if n_done == n_total { - break; - } - } - vfs::loader::Message::Loaded { files } => { - for (path, contents) in files { - vfs.set_file_contents(path.into(), contents); - } - } - } - } - let changes = vfs.take_changes(); - for file in changes { - if file.exists() { - let contents = vfs.file_contents(file.file_id); - if let Ok(text) = std::str::from_utf8(contents) { - analysis_change.change_file(file.file_id, Some(Arc::from(text))) - } - } - } - let source_roots = source_root_config.partition(vfs); - analysis_change.set_roots(source_roots); - - analysis_change.set_crate_graph(crate_graph); - analysis_change.set_proc_macros(proc_macros); - - host.apply_change(analysis_change); - host -} - -#[cfg(test)] -mod tests { - use super::*; - - use hir::Crate; - - #[test] - fn test_loading_rust_analyzer() { - let path = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap().parent().unwrap(); - let cargo_config = CargoConfig::default(); - let load_cargo_config = LoadCargoConfig { - load_out_dirs_from_check: false, - with_proc_macro_server: ProcMacroServerChoice::None, - prefill_caches: false, - }; - let (host, _vfs, _proc_macro) = - load_workspace_at(path, &cargo_config, &load_cargo_config, &|_| {}).unwrap(); - - let n_crates = Crate::all(host.raw_database()).len(); - // RA has quite a few crates, but the exact count doesn't matter - assert!(n_crates > 20); - } -} diff --git a/crates/rust-analyzer/src/cli/lsif.rs b/crates/rust-analyzer/src/cli/lsif.rs index 6506f4cc4f2e..bb5016349abe 100644 --- a/crates/rust-analyzer/src/cli/lsif.rs +++ b/crates/rust-analyzer/src/cli/lsif.rs @@ -8,22 +8,22 @@ use ide::{ Analysis, FileId, FileRange, MonikerKind, PackageInformation, RootDatabase, StaticIndex, StaticIndexedFile, TokenId, TokenStaticData, }; -use ide_db::LineIndexDatabase; - -use ide_db::base_db::salsa::{self, ParallelDatabase}; -use ide_db::line_index::WideEncoding; +use ide_db::{ + base_db::salsa::{self, ParallelDatabase}, + line_index::WideEncoding, + LineIndexDatabase, +}; +use load_cargo::{load_workspace, LoadCargoConfig, ProcMacroServerChoice}; use lsp_types::{self, lsif}; use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace, RustLibSource}; use vfs::{AbsPathBuf, Vfs}; -use crate::cli::load_cargo::ProcMacroServerChoice; -use crate::cli::{ - flags, - load_cargo::{load_workspace, LoadCargoConfig}, +use crate::{ + cli::flags, + line_index::{LineEndings, LineIndex, PositionEncoding}, + to_proto, + version::version, }; -use crate::line_index::{LineEndings, LineIndex, PositionEncoding}; -use crate::to_proto; -use crate::version::version; /// Need to wrap Snapshot to provide `Clone` impl for `map_with` struct Snap(DB); diff --git a/crates/rust-analyzer/src/cli/run_tests.rs b/crates/rust-analyzer/src/cli/run_tests.rs index bebbf26b54ce..b63a266a57ae 100644 --- a/crates/rust-analyzer/src/cli/run_tests.rs +++ b/crates/rust-analyzer/src/cli/run_tests.rs @@ -7,12 +7,9 @@ use profile::StopWatch; use project_model::{CargoConfig, RustLibSource}; use syntax::TextRange; -use crate::cli::{ - flags, full_name_of_item, - load_cargo::load_workspace_at, - load_cargo::{LoadCargoConfig, ProcMacroServerChoice}, - Result, -}; +use load_cargo::{load_workspace_at, LoadCargoConfig, ProcMacroServerChoice}; + +use crate::cli::{flags, full_name_of_item, Result}; impl flags::RunTests { pub fn run(self) -> Result<()> { diff --git a/crates/rust-analyzer/src/cli/scip.rs b/crates/rust-analyzer/src/cli/scip.rs index 3dd2dc69a18f..4579aca30219 100644 --- a/crates/rust-analyzer/src/cli/scip.rs +++ b/crates/rust-analyzer/src/cli/scip.rs @@ -6,22 +6,19 @@ use std::{ time::Instant, }; -use crate::{ - cli::load_cargo::ProcMacroServerChoice, - line_index::{LineEndings, LineIndex, PositionEncoding}, -}; use ide::{ LineCol, MonikerDescriptorKind, StaticIndex, StaticIndexedFile, TextRange, TokenId, TokenStaticData, }; use ide_db::LineIndexDatabase; +use load_cargo::{load_workspace, LoadCargoConfig, ProcMacroServerChoice}; use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace, RustLibSource}; use scip::types as scip_types; use std::env; -use crate::cli::{ - flags, - load_cargo::{load_workspace, LoadCargoConfig}, +use crate::{ + cli::flags, + line_index::{LineEndings, LineIndex, PositionEncoding}, }; impl flags::Scip { @@ -275,7 +272,7 @@ mod test { let change_fixture = ChangeFixture::parse(ra_fixture); host.raw_database_mut().apply_change(change_fixture.change); let (file_id, range_or_offset) = - change_fixture.file_position.expect("expected a marker ($0)"); + change_fixture.file_position.expect("expected a marker ()"); let offset = range_or_offset.expect_offset(); (host, FilePosition { file_id, offset }) } diff --git a/crates/rust-analyzer/src/cli/ssr.rs b/crates/rust-analyzer/src/cli/ssr.rs index 7ccb3e216a71..f87dcb889a48 100644 --- a/crates/rust-analyzer/src/cli/ssr.rs +++ b/crates/rust-analyzer/src/cli/ssr.rs @@ -2,12 +2,10 @@ use anyhow::Context; use ide_ssr::MatchFinder; +use load_cargo::{load_workspace_at, LoadCargoConfig, ProcMacroServerChoice}; use project_model::{CargoConfig, RustLibSource}; -use crate::cli::{ - flags, - load_cargo::{load_workspace_at, LoadCargoConfig, ProcMacroServerChoice}, -}; +use crate::cli::flags; impl flags::Ssr { pub fn run(self) -> anyhow::Result<()> { diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 19a931f65bc6..ea8a69751951 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -9,6 +9,7 @@ use crossbeam_channel::{unbounded, Receiver, Sender}; use flycheck::FlycheckHandle; use ide::{Analysis, AnalysisHost, Cancellable, Change, FileId}; use ide_db::base_db::{CrateId, FileLoader, ProcMacroPaths, SourceDatabase}; +use load_cargo::SourceRootConfig; use lsp_types::{SemanticTokens, Url}; use nohash_hasher::IntMap; use parking_lot::{Mutex, RwLock}; @@ -27,7 +28,7 @@ use crate::{ main_loop::Task, mem_docs::MemDocs, op_queue::OpQueue, - reload::{self, SourceRootConfig}, + reload, task_pool::TaskPool, to_proto::url_from_abs_path, }; diff --git a/crates/rust-analyzer/src/integrated_benchmarks.rs b/crates/rust-analyzer/src/integrated_benchmarks.rs index bd9f471a46d1..5a11012b93cf 100644 --- a/crates/rust-analyzer/src/integrated_benchmarks.rs +++ b/crates/rust-analyzer/src/integrated_benchmarks.rs @@ -20,7 +20,7 @@ use test_utils::project_root; use triomphe::Arc; use vfs::{AbsPathBuf, VfsPath}; -use crate::cli::load_cargo::{load_workspace_at, LoadCargoConfig, ProcMacroServerChoice}; +use load_cargo::{load_workspace_at, LoadCargoConfig, ProcMacroServerChoice}; #[test] fn integrated_highlighting_benchmark() { diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index f9e6152f5b52..dd5517e6979a 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -12,26 +12,22 @@ //! correct. Instead, we try to provide a best-effort service. Even if the //! project is currently loading and we don't have a full project model, we //! still want to respond to various requests. -use std::{collections::hash_map::Entry, iter, mem, sync}; +use std::{iter, mem}; use flycheck::{FlycheckConfig, FlycheckHandle}; use hir::db::DefDatabase; use ide::Change; use ide_db::{ - base_db::{ - salsa::Durability, CrateGraph, Env, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, - ProcMacroKind, ProcMacroLoadResult, ProcMacroPaths, ProcMacros, SourceRoot, VfsPath, - }, + base_db::{salsa::Durability, CrateGraph, ProcMacroPaths, ProcMacros}, FxHashMap, }; -use itertools::Itertools; -use proc_macro_api::{MacroDylib, ProcMacroServer}; -use project_model::{PackageRoot, ProjectWorkspace, WorkspaceBuildScripts}; +use load_cargo::{load_proc_macro, ProjectFolders}; +use proc_macro_api::ProcMacroServer; +use project_model::{ProjectWorkspace, WorkspaceBuildScripts}; use rustc_hash::FxHashSet; use stdx::{format_to, thread::ThreadIntent}; -use syntax::SmolStr; use triomphe::Arc; -use vfs::{file_set::FileSetConfig, AbsPath, AbsPathBuf, ChangeKind}; +use vfs::{AbsPath, ChangeKind}; use crate::{ config::{Config, FilesWatcher, LinkedProject}, @@ -41,8 +37,6 @@ use crate::{ op_queue::Cause, }; -use ::tt::token_id as tt; - #[derive(Debug)] pub(crate) enum ProjectWorkspaceProgress { Begin, @@ -619,253 +613,6 @@ impl GlobalState { } } -#[derive(Default)] -pub(crate) struct ProjectFolders { - pub(crate) load: Vec, - pub(crate) watch: Vec, - pub(crate) source_root_config: SourceRootConfig, -} - -impl ProjectFolders { - pub(crate) fn new( - workspaces: &[ProjectWorkspace], - global_excludes: &[AbsPathBuf], - ) -> ProjectFolders { - let mut res = ProjectFolders::default(); - let mut fsc = FileSetConfig::builder(); - let mut local_filesets = vec![]; - - // Dedup source roots - // Depending on the project setup, we can have duplicated source roots, or for example in - // the case of the rustc workspace, we can end up with two source roots that are almost the - // same but not quite, like: - // PackageRoot { is_local: false, include: [AbsPathBuf(".../rust/src/tools/miri/cargo-miri")], exclude: [] } - // PackageRoot { - // is_local: true, - // include: [AbsPathBuf(".../rust/src/tools/miri/cargo-miri"), AbsPathBuf(".../rust/build/x86_64-pc-windows-msvc/stage0-tools/x86_64-pc-windows-msvc/release/build/cargo-miri-85801cd3d2d1dae4/out")], - // exclude: [AbsPathBuf(".../rust/src/tools/miri/cargo-miri/.git"), AbsPathBuf(".../rust/src/tools/miri/cargo-miri/target")] - // } - // - // The first one comes from the explicit rustc workspace which points to the rustc workspace itself - // The second comes from the rustc workspace that we load as the actual project workspace - // These `is_local` differing in this kind of way gives us problems, especially when trying to filter diagnostics as we don't report diagnostics for external libraries. - // So we need to deduplicate these, usually it would be enough to deduplicate by `include`, but as the rustc example shows here that doesn't work, - // so we need to also coalesce the includes if they overlap. - - let mut roots: Vec<_> = workspaces - .iter() - .flat_map(|ws| ws.to_roots()) - .update(|root| root.include.sort()) - .sorted_by(|a, b| a.include.cmp(&b.include)) - .collect(); - - // map that tracks indices of overlapping roots - let mut overlap_map = FxHashMap::<_, Vec<_>>::default(); - let mut done = false; - - while !mem::replace(&mut done, true) { - // maps include paths to indices of the corresponding root - let mut include_to_idx = FxHashMap::default(); - // Find and note down the indices of overlapping roots - for (idx, root) in roots.iter().enumerate().filter(|(_, it)| !it.include.is_empty()) { - for include in &root.include { - match include_to_idx.entry(include) { - Entry::Occupied(e) => { - overlap_map.entry(*e.get()).or_default().push(idx); - } - Entry::Vacant(e) => { - e.insert(idx); - } - } - } - } - for (k, v) in overlap_map.drain() { - done = false; - for v in v { - let r = mem::replace( - &mut roots[v], - PackageRoot { is_local: false, include: vec![], exclude: vec![] }, - ); - roots[k].is_local |= r.is_local; - roots[k].include.extend(r.include); - roots[k].exclude.extend(r.exclude); - } - roots[k].include.sort(); - roots[k].exclude.sort(); - roots[k].include.dedup(); - roots[k].exclude.dedup(); - } - } - - for root in roots.into_iter().filter(|it| !it.include.is_empty()) { - let file_set_roots: Vec = - root.include.iter().cloned().map(VfsPath::from).collect(); - - let entry = { - let mut dirs = vfs::loader::Directories::default(); - dirs.extensions.push("rs".into()); - dirs.include.extend(root.include); - dirs.exclude.extend(root.exclude); - for excl in global_excludes { - if dirs - .include - .iter() - .any(|incl| incl.starts_with(excl) || excl.starts_with(incl)) - { - dirs.exclude.push(excl.clone()); - } - } - - vfs::loader::Entry::Directories(dirs) - }; - - if root.is_local { - res.watch.push(res.load.len()); - } - res.load.push(entry); - - if root.is_local { - local_filesets.push(fsc.len()); - } - fsc.add_file_set(file_set_roots) - } - - let fsc = fsc.build(); - res.source_root_config = SourceRootConfig { fsc, local_filesets }; - - res - } -} - -#[derive(Default, Debug)] -pub(crate) struct SourceRootConfig { - pub(crate) fsc: FileSetConfig, - pub(crate) local_filesets: Vec, -} - -impl SourceRootConfig { - pub(crate) fn partition(&self, vfs: &vfs::Vfs) -> Vec { - let _p = profile::span("SourceRootConfig::partition"); - self.fsc - .partition(vfs) - .into_iter() - .enumerate() - .map(|(idx, file_set)| { - let is_local = self.local_filesets.contains(&idx); - if is_local { - SourceRoot::new_local(file_set) - } else { - SourceRoot::new_library(file_set) - } - }) - .collect() - } -} - -/// Load the proc-macros for the given lib path, replacing all expanders whose names are in `dummy_replace` -/// with an identity dummy expander. -pub(crate) fn load_proc_macro( - server: &ProcMacroServer, - path: &AbsPath, - dummy_replace: &[Box], -) -> ProcMacroLoadResult { - let res: Result, String> = (|| { - let dylib = MacroDylib::new(path.to_path_buf()); - let vec = server.load_dylib(dylib).map_err(|e| format!("{e}"))?; - if vec.is_empty() { - return Err("proc macro library returned no proc macros".to_string()); - } - Ok(vec - .into_iter() - .map(|expander| expander_to_proc_macro(expander, dummy_replace)) - .collect()) - })(); - return match res { - Ok(proc_macros) => { - tracing::info!( - "Loaded proc-macros for {path}: {:?}", - proc_macros.iter().map(|it| it.name.clone()).collect::>() - ); - Ok(proc_macros) - } - Err(e) => { - tracing::warn!("proc-macro loading for {path} failed: {e}"); - Err(e) - } - }; - - fn expander_to_proc_macro( - expander: proc_macro_api::ProcMacro, - dummy_replace: &[Box], - ) -> ProcMacro { - let name = SmolStr::from(expander.name()); - let kind = match expander.kind() { - proc_macro_api::ProcMacroKind::CustomDerive => ProcMacroKind::CustomDerive, - proc_macro_api::ProcMacroKind::FuncLike => ProcMacroKind::FuncLike, - proc_macro_api::ProcMacroKind::Attr => ProcMacroKind::Attr, - }; - let expander: sync::Arc = - if dummy_replace.iter().any(|replace| &**replace == name) { - match kind { - ProcMacroKind::Attr => sync::Arc::new(IdentityExpander), - _ => sync::Arc::new(EmptyExpander), - } - } else { - sync::Arc::new(Expander(expander)) - }; - ProcMacro { name, kind, expander } - } - - #[derive(Debug)] - struct Expander(proc_macro_api::ProcMacro); - - impl ProcMacroExpander for Expander { - fn expand( - &self, - subtree: &tt::Subtree, - attrs: Option<&tt::Subtree>, - env: &Env, - ) -> Result { - let env = env.iter().map(|(k, v)| (k.to_string(), v.to_string())).collect(); - match self.0.expand(subtree, attrs, env) { - Ok(Ok(subtree)) => Ok(subtree), - Ok(Err(err)) => Err(ProcMacroExpansionError::Panic(err.0)), - Err(err) => Err(ProcMacroExpansionError::System(err.to_string())), - } - } - } - - /// Dummy identity expander, used for attribute proc-macros that are deliberately ignored by the user. - #[derive(Debug)] - struct IdentityExpander; - - impl ProcMacroExpander for IdentityExpander { - fn expand( - &self, - subtree: &tt::Subtree, - _: Option<&tt::Subtree>, - _: &Env, - ) -> Result { - Ok(subtree.clone()) - } - } - - /// Empty expander, used for proc-macros that are deliberately ignored by the user. - #[derive(Debug)] - struct EmptyExpander; - - impl ProcMacroExpander for EmptyExpander { - fn expand( - &self, - _: &tt::Subtree, - _: Option<&tt::Subtree>, - _: &Env, - ) -> Result { - Ok(tt::Subtree::empty()) - } - } -} - pub(crate) fn should_refresh_for_change(path: &AbsPath, change_kind: ChangeKind) -> bool { const IMPLICIT_TARGET_FILES: &[&str] = &["build.rs", "src/main.rs", "src/lib.rs"]; const IMPLICIT_TARGET_DIRS: &[&str] = &["src/bin", "examples", "tests", "benches"]; From b4549c50b599929ec47ff4e9d880c27654342bb9 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Mon, 3 Jul 2023 18:13:01 +0200 Subject: [PATCH 141/324] [`useless_vec`]: add more tests for macro combinations --- clippy_lints/src/vec.rs | 4 ++++ tests/ui/vec.fixed | 29 +++++++++++++++++++++++++++++ tests/ui/vec.rs | 29 +++++++++++++++++++++++++++++ tests/ui/vec.stderr | 18 +++++++++++++++--- 4 files changed, 77 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index ca0daa9eceec..6a96114ae769 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -154,6 +154,10 @@ impl UselessVec { span: Span, suggest_slice: SuggestedType, ) { + if span.from_expansion() { + return; + } + let mut applicability = Applicability::MachineApplicable; let snippet = match *vec_args { diff --git a/tests/ui/vec.fixed b/tests/ui/vec.fixed index 14ab8bd8897e..7a7d0026f797 100644 --- a/tests/ui/vec.fixed +++ b/tests/ui/vec.fixed @@ -124,6 +124,35 @@ fn issue11075() { for _string in [repro!(true), repro!(null)] { unimplemented!(); } + + macro_rules! in_macro { + ($e:expr, $vec:expr, $vec2:expr) => {{ + vec![1; 2].fill(3); + vec![1, 2].fill(3); + for _ in vec![1, 2] {} + for _ in vec![1; 2] {} + for _ in vec![$e, $e] {} + for _ in vec![$e; 2] {} + for _ in $vec {} + for _ in $vec2 {} + }}; + } + + in_macro!(1, [1, 2], [1; 2]); + + macro_rules! from_macro { + () => { + vec![1, 2, 3] + }; + } + macro_rules! from_macro_repeat { + () => { + vec![1; 3] + }; + } + + for _ in from_macro!() {} + for _ in from_macro_repeat!() {} } #[clippy::msrv = "1.53"] diff --git a/tests/ui/vec.rs b/tests/ui/vec.rs index e57cb4374e38..cbe7685b4533 100644 --- a/tests/ui/vec.rs +++ b/tests/ui/vec.rs @@ -124,6 +124,35 @@ fn issue11075() { for _string in vec![repro!(true), repro!(null)] { unimplemented!(); } + + macro_rules! in_macro { + ($e:expr, $vec:expr, $vec2:expr) => {{ + vec![1; 2].fill(3); + vec![1, 2].fill(3); + for _ in vec![1, 2] {} + for _ in vec![1; 2] {} + for _ in vec![$e, $e] {} + for _ in vec![$e; 2] {} + for _ in $vec {} + for _ in $vec2 {} + }}; + } + + in_macro!(1, vec![1, 2], vec![1; 2]); + + macro_rules! from_macro { + () => { + vec![1, 2, 3] + }; + } + macro_rules! from_macro_repeat { + () => { + vec![1; 3] + }; + } + + for _ in from_macro!() {} + for _ in from_macro_repeat!() {} } #[clippy::msrv = "1.53"] diff --git a/tests/ui/vec.stderr b/tests/ui/vec.stderr index 1b82d5cbea88..8f6d2a1df803 100644 --- a/tests/ui/vec.stderr +++ b/tests/ui/vec.stderr @@ -91,16 +91,28 @@ LL | for _string in vec![repro!(true), repro!(null)] { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can use an array directly: `[repro!(true), repro!(null)]` error: useless use of `vec!` - --> $DIR/vec.rs:131:14 + --> $DIR/vec.rs:141:18 + | +LL | in_macro!(1, vec![1, 2], vec![1; 2]); + | ^^^^^^^^^^ help: you can use an array directly: `[1, 2]` + +error: useless use of `vec!` + --> $DIR/vec.rs:141:30 + | +LL | in_macro!(1, vec![1, 2], vec![1; 2]); + | ^^^^^^^^^^ help: you can use an array directly: `[1; 2]` + +error: useless use of `vec!` + --> $DIR/vec.rs:160:14 | LL | for a in vec![1, 2, 3] { | ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]` error: useless use of `vec!` - --> $DIR/vec.rs:135:14 + --> $DIR/vec.rs:164:14 | LL | for a in vec![String::new(), String::new()] { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can use an array directly: `[String::new(), String::new()]` -error: aborting due to 17 previous errors +error: aborting due to 19 previous errors From 69cd3c30ac68739268b2acbd5238f6de9a4b1d8e Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 3 Jul 2023 20:34:09 +0200 Subject: [PATCH 142/324] Format let-else --- crates/hir-def/src/attr.rs | 17 +- crates/hir-def/src/body/lower.rs | 4 +- crates/hir-def/src/nameres/collector.rs | 8 +- crates/hir-def/src/path.rs | 5 +- crates/hir-def/src/path/lower.rs | 4 +- crates/hir-expand/src/builtin_fn_macro.rs | 2 +- crates/hir-expand/src/db.rs | 18 +- crates/hir-expand/src/eager.rs | 9 +- crates/hir-ty/src/chalk_ext.rs | 3 +- crates/hir-ty/src/display.rs | 3 +- crates/hir-ty/src/infer.rs | 4 +- crates/hir-ty/src/layout.rs | 4 +- crates/hir-ty/src/layout/adt.rs | 4 +- crates/hir-ty/src/method_resolution.rs | 6 +- crates/hir-ty/src/mir/borrowck.rs | 5 +- crates/hir-ty/src/mir/eval.rs | 8 +- crates/hir-ty/src/mir/eval/shim.rs | 77 ++- crates/hir-ty/src/mir/eval/shim/simd.rs | 7 +- crates/hir-ty/src/mir/lower.rs | 523 +++++++++++------- crates/hir-ty/src/mir/lower/as_place.rs | 55 +- crates/hir-ty/src/tests.rs | 4 +- crates/hir/src/lib.rs | 6 +- crates/hir/src/semantics.rs | 6 +- .../src/handlers/desugar_doc_comment.rs | 4 +- .../src/handlers/fix_visibility.rs | 8 +- .../src/handlers/generate_delegate_methods.rs | 4 +- .../src/handlers/generate_function.rs | 4 +- .../src/handlers/move_const_to_impl.rs | 6 +- .../src/handlers/unwrap_result_return_type.rs | 16 +- crates/ide-completion/src/context.rs | 4 +- crates/ide-completion/src/context/analysis.rs | 5 +- .../src/handlers/unlinked_file.rs | 9 +- crates/ide/src/doc_links.rs | 4 +- crates/ide/src/inlay_hints/adjustment.rs | 2 +- .../rust-analyzer/src/cli/analysis_stats.rs | 10 +- crates/rust-analyzer/src/handlers/request.rs | 8 +- crates/rust-analyzer/src/reload.rs | 8 +- crates/sourcegen/src/lib.rs | 4 +- 38 files changed, 572 insertions(+), 306 deletions(-) diff --git a/crates/hir-def/src/attr.rs b/crates/hir-def/src/attr.rs index 3ff58814d17d..a16670b244a8 100644 --- a/crates/hir-def/src/attr.rs +++ b/crates/hir-def/src/attr.rs @@ -137,13 +137,16 @@ impl Attrs { let cfg_options = &crate_graph[krate].cfg_options; - let Some(variant) = enum_.variants.clone().filter(|variant| { - let attrs = item_tree.attrs(db, krate, (*variant).into()); - attrs.is_cfg_enabled(cfg_options) - }) - .zip(0u32..) - .find(|(_variant, idx)| it.local_id == Idx::from_raw(RawIdx::from(*idx))) - .map(|(variant, _idx)| variant) + let Some(variant) = enum_ + .variants + .clone() + .filter(|variant| { + let attrs = item_tree.attrs(db, krate, (*variant).into()); + attrs.is_cfg_enabled(cfg_options) + }) + .zip(0u32..) + .find(|(_variant, idx)| it.local_id == Idx::from_raw(RawIdx::from(*idx))) + .map(|(variant, _idx)| variant) else { return Arc::new(res); }; diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs index b375ec63a67b..b89eb9fe6238 100644 --- a/crates/hir-def/src/body/lower.rs +++ b/crates/hir-def/src/body/lower.rs @@ -1451,9 +1451,7 @@ impl ExprCollector<'_> { &self, lifetime: Option, ) -> Result, BodyDiagnostic> { - let Some(lifetime) = lifetime else { - return Ok(None) - }; + let Some(lifetime) = lifetime else { return Ok(None) }; let name = Name::new_lifetime(&lifetime); for (rib_idx, rib) in self.label_ribs.iter().enumerate().rev() { diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index fb332c06d0a0..a5cdee9628db 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -2235,8 +2235,12 @@ impl ModCollector<'_, '_> { } fn import_all_legacy_macros(&mut self, module_id: LocalModuleId) { - let Some((source, target)) = Self::borrow_modules(self.def_collector.def_map.modules.as_mut(), module_id, self.module_id) else { - return + let Some((source, target)) = Self::borrow_modules( + self.def_collector.def_map.modules.as_mut(), + module_id, + self.module_id, + ) else { + return; }; for (name, macs) in source.scope.legacy_macros() { diff --git a/crates/hir-def/src/path.rs b/crates/hir-def/src/path.rs index ff4ae69546cf..409c9f874853 100644 --- a/crates/hir-def/src/path.rs +++ b/crates/hir-def/src/path.rs @@ -135,10 +135,7 @@ impl Path { pub fn segments(&self) -> PathSegments<'_> { let Path::Normal { mod_path, generic_args, .. } = self else { - return PathSegments { - segments: &[], - generic_args: None, - }; + return PathSegments { segments: &[], generic_args: None }; }; let s = PathSegments { segments: mod_path.segments(), generic_args: generic_args.as_deref() }; diff --git a/crates/hir-def/src/path/lower.rs b/crates/hir-def/src/path/lower.rs index 1cb17ff0d261..abd817893cc4 100644 --- a/crates/hir-def/src/path/lower.rs +++ b/crates/hir-def/src/path/lower.rs @@ -74,8 +74,8 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx<'_>) -> Option>::Foo desugars to Trait::Foo Some(trait_ref) => { let Path::Normal { mod_path, generic_args: path_generic_args, .. } = - Path::from_src(trait_ref.path()?, ctx)? else - { + Path::from_src(trait_ref.path()?, ctx)? + else { return None; }; let num_segments = mod_path.segments().len(); diff --git a/crates/hir-expand/src/builtin_fn_macro.rs b/crates/hir-expand/src/builtin_fn_macro.rs index dc00b8601b8a..306bae45b429 100644 --- a/crates/hir-expand/src/builtin_fn_macro.rs +++ b/crates/hir-expand/src/builtin_fn_macro.rs @@ -692,7 +692,7 @@ pub(crate) fn include_arg_to_tt( arg_id: MacroCallId, ) -> Result<(triomphe::Arc<(::tt::Subtree<::tt::TokenId>, TokenMap)>, FileId), ExpandError> { let loc = db.lookup_intern_macro_call(arg_id); - let Some(EagerCallInfo {arg, arg_id: Some(arg_id), .. }) = loc.eager.as_deref() else { + let Some(EagerCallInfo { arg, arg_id: Some(arg_id), .. }) = loc.eager.as_deref() else { panic!("include_arg_to_tt called on non include macro call: {:?}", &loc.eager); }; let path = parse_string(&arg.0)?; diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs index de653d76b483..3f08a0986931 100644 --- a/crates/hir-expand/src/db.rs +++ b/crates/hir-expand/src/db.rs @@ -471,17 +471,13 @@ fn macro_expand(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult ExpandResult bool { let crate_id = owner.module(db.upcast()).krate(); - let Some(copy_trait) = db.lang_item(crate_id, LangItem::Copy).and_then(|x| x.as_trait()) else { + let Some(copy_trait) = db.lang_item(crate_id, LangItem::Copy).and_then(|x| x.as_trait()) + else { return false; }; let trait_ref = TyBuilder::trait_ref(db, copy_trait).push(self).build(); diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs index 82cc4f9f5900..7405b51e6e09 100644 --- a/crates/hir-ty/src/display.rs +++ b/crates/hir-ty/src/display.rs @@ -636,7 +636,8 @@ fn render_const_scalar( } hir_def::AdtId::EnumId(e) => { let Some((var_id, var_layout)) = - detect_variant_from_bytes(&layout, f.db, krate, b, e) else { + detect_variant_from_bytes(&layout, f.db, krate, b, e) + else { return f.write_str(""); }; let data = &f.db.enum_data(e).variants[var_id]; diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 1ac0837b5b2c..d53644e2798c 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -1232,7 +1232,9 @@ impl<'a> InferenceContext<'a> { .as_function()? .lookup(self.db.upcast()) .container - else { return None }; + else { + return None; + }; self.resolve_output_on(trait_) } diff --git a/crates/hir-ty/src/layout.rs b/crates/hir-ty/src/layout.rs index 2a9b2debd4b9..06be1f80ad3a 100644 --- a/crates/hir-ty/src/layout.rs +++ b/crates/hir-ty/src/layout.rs @@ -154,7 +154,9 @@ pub fn layout_of_ty_query( ty: Ty, krate: CrateId, ) -> Result, LayoutError> { - let Some(target) = db.target_data_layout(krate) else { return Err(LayoutError::TargetLayoutNotAvailable) }; + let Some(target) = db.target_data_layout(krate) else { + return Err(LayoutError::TargetLayoutNotAvailable); + }; let cx = LayoutCx { krate, target: &target }; let dl = &*cx.current_data_layout(); let trait_env = Arc::new(TraitEnvironment::empty(krate)); diff --git a/crates/hir-ty/src/layout/adt.rs b/crates/hir-ty/src/layout/adt.rs index bd2752a7119a..0012b4179d77 100644 --- a/crates/hir-ty/src/layout/adt.rs +++ b/crates/hir-ty/src/layout/adt.rs @@ -31,7 +31,9 @@ pub fn layout_of_adt_query( subst: Substitution, krate: CrateId, ) -> Result, LayoutError> { - let Some(target) = db.target_data_layout(krate) else { return Err(LayoutError::TargetLayoutNotAvailable) }; + let Some(target) = db.target_data_layout(krate) else { + return Err(LayoutError::TargetLayoutNotAvailable); + }; let cx = LayoutCx { krate, target: &target }; let dl = cx.current_data_layout(); let handle_variant = |def: VariantId, var: &VariantData| { diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index ab6430e8f195..39d1a0e05fcb 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -689,7 +689,7 @@ pub fn lookup_impl_method( fn_subst: Substitution, ) -> (FunctionId, Substitution) { let ItemContainerId::TraitId(trait_id) = func.lookup(db.upcast()).container else { - return (func, fn_subst) + return (func, fn_subst); }; let trait_params = db.generic_params(trait_id.into()).type_or_consts.len(); let fn_params = fn_subst.len(Interner) - trait_params; @@ -699,8 +699,8 @@ pub fn lookup_impl_method( }; let name = &db.function_data(func).name; - let Some((impl_fn, impl_subst)) = lookup_impl_assoc_item_for_trait_ref(trait_ref, db, env, name) - .and_then(|assoc| { + let Some((impl_fn, impl_subst)) = + lookup_impl_assoc_item_for_trait_ref(trait_ref, db, env, name).and_then(|assoc| { if let (AssocItemId::FunctionId(id), subst) = assoc { Some((id, subst)) } else { diff --git a/crates/hir-ty/src/mir/borrowck.rs b/crates/hir-ty/src/mir/borrowck.rs index a5dd0182eb65..0e6a63df4109 100644 --- a/crates/hir-ty/src/mir/borrowck.rs +++ b/crates/hir-ty/src/mir/borrowck.rs @@ -271,7 +271,10 @@ fn ever_initialized_map( } } let Some(terminator) = &block.terminator else { - never!("Terminator should be none only in construction.\nThe body:\n{}", body.pretty_print(db)); + never!( + "Terminator should be none only in construction.\nThe body:\n{}", + body.pretty_print(db) + ); return; }; let targets = match &terminator.kind { diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index ddcfc57185fb..51a75cbbff2e 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -1226,8 +1226,8 @@ impl Evaluator<'_> { } Variants::Multiple { tag, tag_encoding, variants, .. } => { let Some(target_data_layout) = self.db.target_data_layout(self.crate_id) else { - not_supported!("missing target data layout"); - }; + not_supported!("missing target data layout"); + }; let size = tag.size(&*target_data_layout).bytes_usize(); let offset = layout.fields.offset(0).bytes_usize(); // The only field on enum variants is the tag field match tag_encoding { @@ -1344,7 +1344,9 @@ impl Evaluator<'_> { AdtId::UnionId(_) => not_supported!("unsizing unions"), AdtId::EnumId(_) => not_supported!("unsizing enums"), }; - let Some((last_field, _)) = self.db.struct_data(id).variant_data.fields().iter().rev().next() else { + let Some((last_field, _)) = + self.db.struct_data(id).variant_data.fields().iter().rev().next() + else { not_supported!("unsizing struct without field"); }; let target_last_field = self.db.field_types(id.into())[last_field] diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs index 23bb4a29f877..73ed52f3b325 100644 --- a/crates/hir-ty/src/mir/eval/shim.rs +++ b/crates/hir-ty/src/mir/eval/shim.rs @@ -327,7 +327,9 @@ impl Evaluator<'_> { } "pthread_getspecific" => { let Some(arg0) = args.get(0) else { - return Err(MirEvalError::TypeError("pthread_getspecific arg0 is not provided")); + return Err(MirEvalError::TypeError( + "pthread_getspecific arg0 is not provided", + )); }; let key = from_bytes!(usize, &pad16(arg0.get(self)?, false)[0..8]); let value = self.thread_local_storage.get_key(key)?; @@ -336,11 +338,15 @@ impl Evaluator<'_> { } "pthread_setspecific" => { let Some(arg0) = args.get(0) else { - return Err(MirEvalError::TypeError("pthread_setspecific arg0 is not provided")); + return Err(MirEvalError::TypeError( + "pthread_setspecific arg0 is not provided", + )); }; let key = from_bytes!(usize, &pad16(arg0.get(self)?, false)[0..8]); let Some(arg1) = args.get(1) else { - return Err(MirEvalError::TypeError("pthread_setspecific arg1 is not provided")); + return Err(MirEvalError::TypeError( + "pthread_setspecific arg1 is not provided", + )); }; let value = from_bytes!(u128, pad16(arg1.get(self)?, false)); self.thread_local_storage.set_key(key, value)?; @@ -390,7 +396,9 @@ impl Evaluator<'_> { "sqrt" | "sin" | "cos" | "exp" | "exp2" | "log" | "log10" | "log2" | "fabs" | "floor" | "ceil" | "trunc" | "rint" | "nearbyint" | "round" | "roundeven" => { let [arg] = args else { - return Err(MirEvalError::TypeError("f64 intrinsic signature doesn't match fn (f64) -> f64")); + return Err(MirEvalError::TypeError( + "f64 intrinsic signature doesn't match fn (f64) -> f64", + )); }; let arg = from_bytes!(f64, arg.get(self)?); match name { @@ -416,7 +424,9 @@ impl Evaluator<'_> { } "pow" | "minnum" | "maxnum" | "copysign" => { let [arg1, arg2] = args else { - return Err(MirEvalError::TypeError("f64 intrinsic signature doesn't match fn (f64, f64) -> f64")); + return Err(MirEvalError::TypeError( + "f64 intrinsic signature doesn't match fn (f64, f64) -> f64", + )); }; let arg1 = from_bytes!(f64, arg1.get(self)?); let arg2 = from_bytes!(f64, arg2.get(self)?); @@ -430,7 +440,9 @@ impl Evaluator<'_> { } "powi" => { let [arg1, arg2] = args else { - return Err(MirEvalError::TypeError("powif64 signature doesn't match fn (f64, i32) -> f64")); + return Err(MirEvalError::TypeError( + "powif64 signature doesn't match fn (f64, i32) -> f64", + )); }; let arg1 = from_bytes!(f64, arg1.get(self)?); let arg2 = from_bytes!(i32, arg2.get(self)?); @@ -438,7 +450,9 @@ impl Evaluator<'_> { } "fma" => { let [arg1, arg2, arg3] = args else { - return Err(MirEvalError::TypeError("fmaf64 signature doesn't match fn (f64, f64, f64) -> f64")); + return Err(MirEvalError::TypeError( + "fmaf64 signature doesn't match fn (f64, f64, f64) -> f64", + )); }; let arg1 = from_bytes!(f64, arg1.get(self)?); let arg2 = from_bytes!(f64, arg2.get(self)?); @@ -454,7 +468,9 @@ impl Evaluator<'_> { "sqrt" | "sin" | "cos" | "exp" | "exp2" | "log" | "log10" | "log2" | "fabs" | "floor" | "ceil" | "trunc" | "rint" | "nearbyint" | "round" | "roundeven" => { let [arg] = args else { - return Err(MirEvalError::TypeError("f32 intrinsic signature doesn't match fn (f32) -> f32")); + return Err(MirEvalError::TypeError( + "f32 intrinsic signature doesn't match fn (f32) -> f32", + )); }; let arg = from_bytes!(f32, arg.get(self)?); match name { @@ -480,7 +496,9 @@ impl Evaluator<'_> { } "pow" | "minnum" | "maxnum" | "copysign" => { let [arg1, arg2] = args else { - return Err(MirEvalError::TypeError("f32 intrinsic signature doesn't match fn (f32, f32) -> f32")); + return Err(MirEvalError::TypeError( + "f32 intrinsic signature doesn't match fn (f32, f32) -> f32", + )); }; let arg1 = from_bytes!(f32, arg1.get(self)?); let arg2 = from_bytes!(f32, arg2.get(self)?); @@ -494,7 +512,9 @@ impl Evaluator<'_> { } "powi" => { let [arg1, arg2] = args else { - return Err(MirEvalError::TypeError("powif32 signature doesn't match fn (f32, i32) -> f32")); + return Err(MirEvalError::TypeError( + "powif32 signature doesn't match fn (f32, i32) -> f32", + )); }; let arg1 = from_bytes!(f32, arg1.get(self)?); let arg2 = from_bytes!(i32, arg2.get(self)?); @@ -502,7 +522,9 @@ impl Evaluator<'_> { } "fma" => { let [arg1, arg2, arg3] = args else { - return Err(MirEvalError::TypeError("fmaf32 signature doesn't match fn (f32, f32, f32) -> f32")); + return Err(MirEvalError::TypeError( + "fmaf32 signature doesn't match fn (f32, f32, f32) -> f32", + )); }; let arg1 = from_bytes!(f32, arg1.get(self)?); let arg2 = from_bytes!(f32, arg2.get(self)?); @@ -515,14 +537,16 @@ impl Evaluator<'_> { } match name { "size_of" => { - let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) else { + let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) + else { return Err(MirEvalError::TypeError("size_of generic arg is not provided")); }; let size = self.size_of_sized(ty, locals, "size_of arg")?; destination.write_from_bytes(self, &size.to_le_bytes()[0..destination.size]) } "size_of_val" => { - let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) else { + let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) + else { return Err(MirEvalError::TypeError("size_of_val generic arg is not provided")); }; let [arg] = args else { @@ -549,14 +573,16 @@ impl Evaluator<'_> { destination.write_from_bytes(self, &size.to_le_bytes()) } "min_align_of" | "pref_align_of" => { - let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) else { + let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) + else { return Err(MirEvalError::TypeError("align_of generic arg is not provided")); }; let align = self.layout(ty)?.align.abi.bytes(); destination.write_from_bytes(self, &align.to_le_bytes()[0..destination.size]) } "needs_drop" => { - let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) else { + let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) + else { return Err(MirEvalError::TypeError("size_of generic arg is not provided")); }; let result = !ty.clone().is_copy(self.db, locals.body.owner); @@ -697,10 +723,15 @@ impl Evaluator<'_> { } "copy" | "copy_nonoverlapping" => { let [src, dst, offset] = args else { - return Err(MirEvalError::TypeError("copy_nonoverlapping args are not provided")); + return Err(MirEvalError::TypeError( + "copy_nonoverlapping args are not provided", + )); }; - let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) else { - return Err(MirEvalError::TypeError("copy_nonoverlapping generic arg is not provided")); + let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) + else { + return Err(MirEvalError::TypeError( + "copy_nonoverlapping generic arg is not provided", + )); }; let src = Address::from_bytes(src.get(self)?)?; let dst = Address::from_bytes(dst.get(self)?)?; @@ -715,7 +746,8 @@ impl Evaluator<'_> { let [ptr, offset] = args else { return Err(MirEvalError::TypeError("offset args are not provided")); }; - let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) else { + let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) + else { return Err(MirEvalError::TypeError("offset generic arg is not provided")); }; let ptr = u128::from_le_bytes(pad16(ptr.get(self)?, false)); @@ -824,8 +856,11 @@ impl Evaluator<'_> { let [arg] = args else { return Err(MirEvalError::TypeError("discriminant_value arg is not provided")); }; - let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) else { - return Err(MirEvalError::TypeError("discriminant_value generic arg is not provided")); + let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) + else { + return Err(MirEvalError::TypeError( + "discriminant_value generic arg is not provided", + )); }; let addr = Address::from_bytes(arg.get(self)?)?; let size = self.size_of_sized(ty, locals, "discriminant_value ptr type")?; diff --git a/crates/hir-ty/src/mir/eval/shim/simd.rs b/crates/hir-ty/src/mir/eval/shim/simd.rs index c41e2790c1b7..89b04eb36bb0 100644 --- a/crates/hir-ty/src/mir/eval/shim/simd.rs +++ b/crates/hir-ty/src/mir/eval/shim/simd.rs @@ -23,7 +23,8 @@ impl Evaluator<'_> { fn detect_simd_ty(&self, ty: &Ty) -> Result { match ty.kind(Interner) { TyKind::Adt(_, subst) => { - let Some(len) = subst.as_slice(Interner).get(1).and_then(|x| x.constant(Interner)) else { + let Some(len) = subst.as_slice(Interner).get(1).and_then(|x| x.constant(Interner)) + else { return Err(MirEvalError::TypeError("simd type without len param")); }; match try_const_usize(self.db, len) { @@ -89,7 +90,9 @@ impl Evaluator<'_> { return Err(MirEvalError::TypeError("simd_shuffle args are not provided")); }; let TyKind::Array(_, index_len) = index.ty.kind(Interner) else { - return Err(MirEvalError::TypeError("simd_shuffle index argument has non-array type")); + return Err(MirEvalError::TypeError( + "simd_shuffle index argument has non-array type", + )); }; let index_len = match try_const_usize(self.db, index_len) { Some(x) => x as usize, diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index 800e490e9a60..41a773835713 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -310,24 +310,30 @@ impl<'ctx> MirLowerCtx<'ctx> { self.lower_expr_to_place_with_adjust(expr_id, temp.into(), current, rest) } Adjust::Deref(_) => { - let Some((p, current)) = self.lower_expr_as_place_with_adjust(current, expr_id, true, adjustments)? else { - return Ok(None); - }; + let Some((p, current)) = + self.lower_expr_as_place_with_adjust(current, expr_id, true, adjustments)? + else { + return Ok(None); + }; self.push_assignment(current, place, Operand::Copy(p).into(), expr_id.into()); Ok(Some(current)) } Adjust::Borrow(AutoBorrow::Ref(m) | AutoBorrow::RawPtr(m)) => { - let Some((p, current)) = self.lower_expr_as_place_with_adjust(current, expr_id, true, rest)? else { - return Ok(None); - }; + let Some((p, current)) = + self.lower_expr_as_place_with_adjust(current, expr_id, true, rest)? + else { + return Ok(None); + }; let bk = BorrowKind::from_chalk(*m); self.push_assignment(current, place, Rvalue::Ref(bk, p), expr_id.into()); Ok(Some(current)) } Adjust::Pointer(cast) => { - let Some((p, current)) = self.lower_expr_as_place_with_adjust(current, expr_id, true, rest)? else { - return Ok(None); - }; + let Some((p, current)) = + self.lower_expr_as_place_with_adjust(current, expr_id, true, rest)? + else { + return Ok(None); + }; self.push_assignment( current, place, @@ -373,45 +379,49 @@ impl<'ctx> MirLowerCtx<'ctx> { } } Err(MirLowerError::IncompleteExpr) - }, + } Expr::Path(p) => { - let pr = if let Some((assoc, subst)) = self - .infer - .assoc_resolutions_for_expr(expr_id) - { - match assoc { - hir_def::AssocItemId::ConstId(c) => { - self.lower_const(c.into(), current, place, subst, expr_id.into(), self.expr_ty_without_adjust(expr_id))?; - return Ok(Some(current)) - }, - hir_def::AssocItemId::FunctionId(_) => { - // FnDefs are zero sized, no action is needed. - return Ok(Some(current)) + let pr = + if let Some((assoc, subst)) = self.infer.assoc_resolutions_for_expr(expr_id) { + match assoc { + hir_def::AssocItemId::ConstId(c) => { + self.lower_const( + c.into(), + current, + place, + subst, + expr_id.into(), + self.expr_ty_without_adjust(expr_id), + )?; + return Ok(Some(current)); + } + hir_def::AssocItemId::FunctionId(_) => { + // FnDefs are zero sized, no action is needed. + return Ok(Some(current)); + } + hir_def::AssocItemId::TypeAliasId(_) => { + // FIXME: If it is unreachable, use proper error instead of `not_supported`. + not_supported!("associated functions and types") + } } - hir_def::AssocItemId::TypeAliasId(_) => { - // FIXME: If it is unreachable, use proper error instead of `not_supported`. - not_supported!("associated functions and types") - }, - } - } else if let Some(variant) = self - .infer - .variant_resolution_for_expr(expr_id) - { - match variant { - VariantId::EnumVariantId(e) => ValueNs::EnumVariantId(e), - VariantId::StructId(s) => ValueNs::StructId(s), - VariantId::UnionId(_) => implementation_error!("Union variant as path"), - } - } else { - let unresolved_name = || MirLowerError::unresolved_path(self.db, p); - let resolver = resolver_for_expr(self.db.upcast(), self.owner, expr_id); - resolver - .resolve_path_in_value_ns_fully(self.db.upcast(), p) - .ok_or_else(unresolved_name)? - }; + } else if let Some(variant) = self.infer.variant_resolution_for_expr(expr_id) { + match variant { + VariantId::EnumVariantId(e) => ValueNs::EnumVariantId(e), + VariantId::StructId(s) => ValueNs::StructId(s), + VariantId::UnionId(_) => implementation_error!("Union variant as path"), + } + } else { + let unresolved_name = || MirLowerError::unresolved_path(self.db, p); + let resolver = resolver_for_expr(self.db.upcast(), self.owner, expr_id); + resolver + .resolve_path_in_value_ns_fully(self.db.upcast(), p) + .ok_or_else(unresolved_name)? + }; match pr { ValueNs::LocalBinding(_) | ValueNs::StaticId(_) => { - let Some((temp, current)) = self.lower_expr_as_place_without_adjust(current, expr_id, false)? else { + let Some((temp, current)) = + self.lower_expr_as_place_without_adjust(current, expr_id, false)? + else { return Ok(None); }; self.push_assignment( @@ -423,11 +433,19 @@ impl<'ctx> MirLowerCtx<'ctx> { Ok(Some(current)) } ValueNs::ConstId(const_id) => { - self.lower_const(const_id.into(), current, place, Substitution::empty(Interner), expr_id.into(), self.expr_ty_without_adjust(expr_id))?; + self.lower_const( + const_id.into(), + current, + place, + Substitution::empty(Interner), + expr_id.into(), + self.expr_ty_without_adjust(expr_id), + )?; Ok(Some(current)) } ValueNs::EnumVariantId(variant_id) => { - let variant_data = &self.db.enum_data(variant_id.parent).variants[variant_id.local_id]; + let variant_data = + &self.db.enum_data(variant_id.parent).variants[variant_id.local_id]; if variant_data.variant_data.kind() == StructKind::Unit { let ty = self.infer.type_of_expr[expr_id].clone(); current = self.lower_enum_variant( @@ -478,7 +496,9 @@ impl<'ctx> MirLowerCtx<'ctx> { } } Expr::If { condition, then_branch, else_branch } => { - let Some((discr, current)) = self.lower_expr_to_some_operand(*condition, current)? else { + let Some((discr, current)) = + self.lower_expr_to_some_operand(*condition, current)? + else { return Ok(None); }; let start_of_then = self.new_basic_block(); @@ -501,15 +521,12 @@ impl<'ctx> MirLowerCtx<'ctx> { Ok(self.merge_blocks(end_of_then, end_of_else, expr_id.into())) } Expr::Let { pat, expr } => { - let Some((cond_place, current)) = self.lower_expr_as_place(current, *expr, true)? else { + let Some((cond_place, current)) = self.lower_expr_as_place(current, *expr, true)? + else { return Ok(None); }; - let (then_target, else_target) = self.pattern_match( - current, - None, - cond_place, - *pat, - )?; + let (then_target, else_target) = + self.pattern_match(current, None, cond_place, *pat)?; self.write_bytes_to_place( then_target, place.clone(), @@ -533,31 +550,47 @@ impl<'ctx> MirLowerCtx<'ctx> { } Expr::Block { id: _, statements, tail, label } => { if let Some(label) = label { - self.lower_loop(current, place.clone(), Some(*label), expr_id.into(), |this, begin| { - if let Some(current) = this.lower_block_to_place(statements, begin, *tail, place, expr_id.into())? { - let end = this.current_loop_end()?; - this.set_goto(current, end, expr_id.into()); - } - Ok(()) - }) + self.lower_loop( + current, + place.clone(), + Some(*label), + expr_id.into(), + |this, begin| { + if let Some(current) = this.lower_block_to_place( + statements, + begin, + *tail, + place, + expr_id.into(), + )? { + let end = this.current_loop_end()?; + this.set_goto(current, end, expr_id.into()); + } + Ok(()) + }, + ) } else { self.lower_block_to_place(statements, current, *tail, place, expr_id.into()) } } - Expr::Loop { body, label } => self.lower_loop(current, place, *label, expr_id.into(), |this, begin| { - let scope = this.push_drop_scope(); - if let Some((_, mut current)) = this.lower_expr_as_place(begin, *body, true)? { - current = scope.pop_and_drop(this, current); - this.set_goto(current, begin, expr_id.into()); - } else { - scope.pop_assume_dropped(this); - } - Ok(()) - }), - Expr::While { condition, body, label } => { - self.lower_loop(current, place, *label, expr_id.into(),|this, begin| { + Expr::Loop { body, label } => { + self.lower_loop(current, place, *label, expr_id.into(), |this, begin| { let scope = this.push_drop_scope(); - let Some((discr, to_switch)) = this.lower_expr_to_some_operand(*condition, begin)? else { + if let Some((_, mut current)) = this.lower_expr_as_place(begin, *body, true)? { + current = scope.pop_and_drop(this, current); + this.set_goto(current, begin, expr_id.into()); + } else { + scope.pop_assume_dropped(this); + } + Ok(()) + }) + } + Expr::While { condition, body, label } => { + self.lower_loop(current, place, *label, expr_id.into(), |this, begin| { + let scope = this.push_drop_scope(); + let Some((discr, to_switch)) = + this.lower_expr_to_some_operand(*condition, begin)? + else { return Ok(()); }; let fail_cond = this.new_basic_block(); @@ -583,8 +616,7 @@ impl<'ctx> MirLowerCtx<'ctx> { }) } Expr::Call { callee, args, .. } => { - if let Some((func_id, generic_args)) = - self.infer.method_resolution(expr_id) { + if let Some((func_id, generic_args)) = self.infer.method_resolution(expr_id) { let ty = chalk_ir::TyKind::FnDef( CallableDefId::FunctionId(func_id).to_chalk(self.db), generic_args, @@ -604,21 +636,43 @@ impl<'ctx> MirLowerCtx<'ctx> { match &callee_ty.data(Interner).kind { chalk_ir::TyKind::FnDef(..) => { let func = Operand::from_bytes(vec![], callee_ty.clone()); - self.lower_call_and_args(func, args.iter().copied(), place, current, self.is_uninhabited(expr_id), expr_id.into()) + self.lower_call_and_args( + func, + args.iter().copied(), + place, + current, + self.is_uninhabited(expr_id), + expr_id.into(), + ) } chalk_ir::TyKind::Function(_) => { - let Some((func, current)) = self.lower_expr_to_some_operand(*callee, current)? else { + let Some((func, current)) = + self.lower_expr_to_some_operand(*callee, current)? + else { return Ok(None); }; - self.lower_call_and_args(func, args.iter().copied(), place, current, self.is_uninhabited(expr_id), expr_id.into()) + self.lower_call_and_args( + func, + args.iter().copied(), + place, + current, + self.is_uninhabited(expr_id), + expr_id.into(), + ) + } + TyKind::Error => { + return Err(MirLowerError::MissingFunctionDefinition(self.owner, expr_id)) } - TyKind::Error => return Err(MirLowerError::MissingFunctionDefinition(self.owner, expr_id)), _ => return Err(MirLowerError::TypeError("function call on bad type")), } } Expr::MethodCall { receiver, args, method_name, .. } => { let (func_id, generic_args) = - self.infer.method_resolution(expr_id).ok_or_else(|| MirLowerError::UnresolvedMethod(method_name.display(self.db.upcast()).to_string()))?; + self.infer.method_resolution(expr_id).ok_or_else(|| { + MirLowerError::UnresolvedMethod( + method_name.display(self.db.upcast()).to_string(), + ) + })?; let func = Operand::from_fn(self.db, func_id, generic_args); self.lower_call_and_args( func, @@ -630,23 +684,27 @@ impl<'ctx> MirLowerCtx<'ctx> { ) } Expr::Match { expr, arms } => { - let Some((cond_place, mut current)) = self.lower_expr_as_place(current, *expr, true)? + let Some((cond_place, mut current)) = + self.lower_expr_as_place(current, *expr, true)? else { return Ok(None); }; let mut end = None; for MatchArm { pat, guard, expr } in arms.iter() { - let (then, mut otherwise) = self.pattern_match( - current, - None, - cond_place.clone(), - *pat, - )?; + let (then, mut otherwise) = + self.pattern_match(current, None, cond_place.clone(), *pat)?; let then = if let &Some(guard) = guard { let next = self.new_basic_block(); let o = otherwise.get_or_insert_with(|| self.new_basic_block()); if let Some((discr, c)) = self.lower_expr_to_some_operand(guard, then)? { - self.set_terminator(c, TerminatorKind::SwitchInt { discr, targets: SwitchTargets::static_if(1, next, *o) }, expr_id.into()); + self.set_terminator( + c, + TerminatorKind::SwitchInt { + discr, + targets: SwitchTargets::static_if(1, next, *o), + }, + expr_id.into(), + ); } next } else { @@ -672,33 +730,53 @@ impl<'ctx> MirLowerCtx<'ctx> { } Expr::Continue { label } => { let loop_data = match label { - Some(l) => self.labeled_loop_blocks.get(l).ok_or(MirLowerError::UnresolvedLabel)?, - None => self.current_loop_blocks.as_ref().ok_or(MirLowerError::ContinueWithoutLoop)?, + Some(l) => { + self.labeled_loop_blocks.get(l).ok_or(MirLowerError::UnresolvedLabel)? + } + None => self + .current_loop_blocks + .as_ref() + .ok_or(MirLowerError::ContinueWithoutLoop)?, }; let begin = loop_data.begin; current = self.drop_until_scope(loop_data.drop_scope_index, current); self.set_goto(current, begin, expr_id.into()); Ok(None) - }, + } &Expr::Break { expr, label } => { if let Some(expr) = expr { let loop_data = match label { - Some(l) => self.labeled_loop_blocks.get(&l).ok_or(MirLowerError::UnresolvedLabel)?, - None => self.current_loop_blocks.as_ref().ok_or(MirLowerError::BreakWithoutLoop)?, + Some(l) => self + .labeled_loop_blocks + .get(&l) + .ok_or(MirLowerError::UnresolvedLabel)?, + None => self + .current_loop_blocks + .as_ref() + .ok_or(MirLowerError::BreakWithoutLoop)?, }; - let Some(c) = self.lower_expr_to_place(expr, loop_data.place.clone(), current)? else { + let Some(c) = + self.lower_expr_to_place(expr, loop_data.place.clone(), current)? + else { return Ok(None); }; current = c; } let (end, drop_scope) = match label { Some(l) => { - let loop_blocks = self.labeled_loop_blocks.get(&l).ok_or(MirLowerError::UnresolvedLabel)?; - (loop_blocks.end.expect("We always generate end for labeled loops"), loop_blocks.drop_scope_index) - }, - None => { - (self.current_loop_end()?, self.current_loop_blocks.as_ref().unwrap().drop_scope_index) - }, + let loop_blocks = self + .labeled_loop_blocks + .get(&l) + .ok_or(MirLowerError::UnresolvedLabel)?; + ( + loop_blocks.end.expect("We always generate end for labeled loops"), + loop_blocks.drop_scope_index, + ) + } + None => ( + self.current_loop_end()?, + self.current_loop_blocks.as_ref().unwrap().drop_scope_index, + ), }; current = self.drop_until_scope(drop_scope, current); self.set_goto(current, end, expr_id.into()); @@ -706,7 +784,9 @@ impl<'ctx> MirLowerCtx<'ctx> { } Expr::Return { expr } => { if let Some(expr) = expr { - if let Some(c) = self.lower_expr_to_place(*expr, return_slot().into(), current)? { + if let Some(c) = + self.lower_expr_to_place(*expr, return_slot().into(), current)? + { current = c; } else { return Ok(None); @@ -725,13 +805,11 @@ impl<'ctx> MirLowerCtx<'ctx> { }; current = c; Some(p) - }, + } None => None, }; - let variant_id = self - .infer - .variant_resolution_for_expr(expr_id) - .ok_or_else(|| match path { + let variant_id = + self.infer.variant_resolution_for_expr(expr_id).ok_or_else(|| match path { Some(p) => MirLowerError::UnresolvedName(p.display(self.db).to_string()), None => MirLowerError::RecordLiteralWithoutPath, })?; @@ -746,7 +824,8 @@ impl<'ctx> MirLowerCtx<'ctx> { for RecordLitField { name, expr } in fields.iter() { let field_id = variant_data.field(name).ok_or(MirLowerError::UnresolvedField)?; - let Some((op, c)) = self.lower_expr_to_some_operand(*expr, current)? else { + let Some((op, c)) = self.lower_expr_to_some_operand(*expr, current)? + else { return Ok(None); }; current = c; @@ -758,18 +837,23 @@ impl<'ctx> MirLowerCtx<'ctx> { Rvalue::Aggregate( AggregateKind::Adt(variant_id, subst), match spread_place { - Some(sp) => operands.into_iter().enumerate().map(|(i, x)| { - match x { + Some(sp) => operands + .into_iter() + .enumerate() + .map(|(i, x)| match x { Some(x) => x, None => { - let p = sp.project(ProjectionElem::Field(FieldId { - parent: variant_id, - local_id: LocalFieldId::from_raw(RawIdx::from(i as u32)), - })); + let p = + sp.project(ProjectionElem::Field(FieldId { + parent: variant_id, + local_id: LocalFieldId::from_raw( + RawIdx::from(i as u32), + ), + })); Operand::Copy(p) - }, - } - }).collect(), + } + }) + .collect(), None => operands.into_iter().collect::>().ok_or( MirLowerError::TypeError("missing field in record literal"), )?, @@ -785,7 +869,10 @@ impl<'ctx> MirLowerCtx<'ctx> { }; let local_id = variant_data.field(name).ok_or(MirLowerError::UnresolvedField)?; - let place = place.project(PlaceElem::Field(FieldId { parent: union_id.into(), local_id })); + let place = place.project(PlaceElem::Field(FieldId { + parent: union_id.into(), + local_id, + })); self.lower_expr_to_place(*expr, place, current) } } @@ -795,9 +882,16 @@ impl<'ctx> MirLowerCtx<'ctx> { Expr::Async { .. } => not_supported!("async block"), &Expr::Const(id) => { let subst = self.placeholder_subst(); - self.lower_const(id.into(), current, place, subst, expr_id.into(), self.expr_ty_without_adjust(expr_id))?; + self.lower_const( + id.into(), + current, + place, + subst, + expr_id.into(), + self.expr_ty_without_adjust(expr_id), + )?; Ok(Some(current)) - }, + } Expr::Cast { expr, type_ref: _ } => { let Some((x, current)) = self.lower_expr_to_some_operand(*expr, current)? else { return Ok(None); @@ -822,23 +916,37 @@ impl<'ctx> MirLowerCtx<'ctx> { } Expr::Box { expr } => { let ty = self.expr_ty_after_adjustments(*expr); - self.push_assignment(current, place.clone(), Rvalue::ShallowInitBoxWithAlloc(ty), expr_id.into()); - let Some((operand, current)) = self.lower_expr_to_some_operand(*expr, current)? else { + self.push_assignment( + current, + place.clone(), + Rvalue::ShallowInitBoxWithAlloc(ty), + expr_id.into(), + ); + let Some((operand, current)) = self.lower_expr_to_some_operand(*expr, current)? + else { return Ok(None); }; let p = place.project(ProjectionElem::Deref); self.push_assignment(current, p, operand.into(), expr_id.into()); Ok(Some(current)) - }, - Expr::Field { .. } | Expr::Index { .. } | Expr::UnaryOp { op: hir_def::hir::UnaryOp::Deref, .. } => { - let Some((p, current)) = self.lower_expr_as_place_without_adjust(current, expr_id, true)? else { + } + Expr::Field { .. } + | Expr::Index { .. } + | Expr::UnaryOp { op: hir_def::hir::UnaryOp::Deref, .. } => { + let Some((p, current)) = + self.lower_expr_as_place_without_adjust(current, expr_id, true)? + else { return Ok(None); }; self.push_assignment(current, place, Operand::Copy(p).into(), expr_id.into()); Ok(Some(current)) } - Expr::UnaryOp { expr, op: op @ (hir_def::hir::UnaryOp::Not | hir_def::hir::UnaryOp::Neg) } => { - let Some((operand, current)) = self.lower_expr_to_some_operand(*expr, current)? else { + Expr::UnaryOp { + expr, + op: op @ (hir_def::hir::UnaryOp::Not | hir_def::hir::UnaryOp::Neg), + } => { + let Some((operand, current)) = self.lower_expr_to_some_operand(*expr, current)? + else { return Ok(None); }; let operation = match op { @@ -853,7 +961,7 @@ impl<'ctx> MirLowerCtx<'ctx> { expr_id.into(), ); Ok(Some(current)) - }, + } Expr::BinaryOp { lhs, rhs, op } => { let op = op.ok_or(MirLowerError::IncompleteExpr)?; let is_builtin = 'b: { @@ -861,16 +969,19 @@ impl<'ctx> MirLowerCtx<'ctx> { // for binary operator, and use without adjust to simplify our conditions. let lhs_ty = self.expr_ty_without_adjust(*lhs); let rhs_ty = self.expr_ty_without_adjust(*rhs); - if matches!(op ,BinaryOp::CmpOp(syntax::ast::CmpOp::Eq { .. })) { + if matches!(op, BinaryOp::CmpOp(syntax::ast::CmpOp::Eq { .. })) { if lhs_ty.as_raw_ptr().is_some() && rhs_ty.as_raw_ptr().is_some() { break 'b true; } } let builtin_inequal_impls = matches!( op, - BinaryOp::ArithOp(ArithOp::Shl | ArithOp::Shr) | BinaryOp::Assignment { op: Some(ArithOp::Shl | ArithOp::Shr) } + BinaryOp::ArithOp(ArithOp::Shl | ArithOp::Shr) + | BinaryOp::Assignment { op: Some(ArithOp::Shl | ArithOp::Shr) } ); - lhs_ty.is_scalar() && rhs_ty.is_scalar() && (lhs_ty == rhs_ty || builtin_inequal_impls) + lhs_ty.is_scalar() + && rhs_ty.is_scalar() + && (lhs_ty == rhs_ty || builtin_inequal_impls) }; if !is_builtin { if let Some((func_id, generic_args)) = self.infer.method_resolution(expr_id) { @@ -894,32 +1005,43 @@ impl<'ctx> MirLowerCtx<'ctx> { .get(lhs) .and_then(|x| x.split_last()) .map(|x| x.1) - .ok_or(MirLowerError::TypeError("adjustment of binary op was missing"))?; + .ok_or(MirLowerError::TypeError( + "adjustment of binary op was missing", + ))?; let Some((lhs_place, current)) = self.lower_expr_as_place_with_adjust(current, *lhs, false, adjusts)? else { return Ok(None); }; - let Some((rhs_op, current)) = self.lower_expr_to_some_operand(*rhs, current)? else { + let Some((rhs_op, current)) = + self.lower_expr_to_some_operand(*rhs, current)? + else { return Ok(None); }; - let r_value = Rvalue::CheckedBinaryOp(op.into(), Operand::Copy(lhs_place.clone()), rhs_op); + let r_value = Rvalue::CheckedBinaryOp( + op.into(), + Operand::Copy(lhs_place.clone()), + rhs_op, + ); self.push_assignment(current, lhs_place, r_value, expr_id.into()); return Ok(Some(current)); } else { let Some((lhs_place, current)) = - self.lower_expr_as_place(current, *lhs, false)? + self.lower_expr_as_place(current, *lhs, false)? else { return Ok(None); }; - let Some((rhs_op, current)) = self.lower_expr_to_some_operand(*rhs, current)? else { + let Some((rhs_op, current)) = + self.lower_expr_to_some_operand(*rhs, current)? + else { return Ok(None); }; self.push_assignment(current, lhs_place, rhs_op.into(), expr_id.into()); return Ok(Some(current)); } } - let Some((lhs_op, current)) = self.lower_expr_to_some_operand(*lhs, current)? else { + let Some((lhs_op, current)) = self.lower_expr_to_some_operand(*lhs, current)? + else { return Ok(None); }; if let hir_def::hir::BinaryOp::LogicOp(op) = op { @@ -928,22 +1050,31 @@ impl<'ctx> MirLowerCtx<'ctx> { syntax::ast::LogicOp::Or => 1, }; let start_of_then = self.new_basic_block(); - self.push_assignment(start_of_then, place.clone(), lhs_op.clone().into(), expr_id.into()); + self.push_assignment( + start_of_then, + place.clone(), + lhs_op.clone().into(), + expr_id.into(), + ); let end_of_then = Some(start_of_then); let start_of_else = self.new_basic_block(); - let end_of_else = - self.lower_expr_to_place(*rhs, place, start_of_else)?; + let end_of_else = self.lower_expr_to_place(*rhs, place, start_of_else)?; self.set_terminator( current, TerminatorKind::SwitchInt { discr: lhs_op, - targets: SwitchTargets::static_if(value_to_short, start_of_then, start_of_else), + targets: SwitchTargets::static_if( + value_to_short, + start_of_then, + start_of_else, + ), }, expr_id.into(), ); return Ok(self.merge_blocks(end_of_then, end_of_else, expr_id.into())); } - let Some((rhs_op, current)) = self.lower_expr_to_some_operand(*rhs, current)? else { + let Some((rhs_op, current)) = self.lower_expr_to_some_operand(*rhs, current)? + else { return Ok(None); }; self.push_assignment( @@ -995,20 +1126,28 @@ impl<'ctx> MirLowerCtx<'ctx> { place, Rvalue::Aggregate( AggregateKind::Adt(st.into(), subst.clone()), - self.db.struct_data(st).variant_data.fields().iter().map(|x| { - let o = match x.1.name.as_str() { - Some("start") => lp.take(), - Some("end") => rp.take(), - Some("exhausted") => Some(Operand::from_bytes(vec![0], TyBuilder::bool())), - _ => None, - }; - o.ok_or(MirLowerError::UnresolvedField) - }).collect::>()?, + self.db + .struct_data(st) + .variant_data + .fields() + .iter() + .map(|x| { + let o = match x.1.name.as_str() { + Some("start") => lp.take(), + Some("end") => rp.take(), + Some("exhausted") => { + Some(Operand::from_bytes(vec![0], TyBuilder::bool())) + } + _ => None, + }; + o.ok_or(MirLowerError::UnresolvedField) + }) + .collect::>()?, ), expr_id.into(), ); Ok(Some(current)) - }, + } Expr::Closure { .. } => { let ty = self.expr_ty_without_adjust(expr_id); let TyKind::Closure(id, _) = ty.kind(Interner) else { @@ -1020,22 +1159,33 @@ impl<'ctx> MirLowerCtx<'ctx> { for capture in captures.iter() { let p = Place { local: self.binding_local(capture.place.local)?, - projection: capture.place.projections.clone().into_iter().map(|x| { - match x { + projection: capture + .place + .projections + .clone() + .into_iter() + .map(|x| match x { ProjectionElem::Deref => ProjectionElem::Deref, ProjectionElem::Field(x) => ProjectionElem::Field(x), - ProjectionElem::TupleOrClosureField(x) => ProjectionElem::TupleOrClosureField(x), - ProjectionElem::ConstantIndex { offset, from_end } => ProjectionElem::ConstantIndex { offset, from_end }, - ProjectionElem::Subslice { from, to } => ProjectionElem::Subslice { from, to }, + ProjectionElem::TupleOrClosureField(x) => { + ProjectionElem::TupleOrClosureField(x) + } + ProjectionElem::ConstantIndex { offset, from_end } => { + ProjectionElem::ConstantIndex { offset, from_end } + } + ProjectionElem::Subslice { from, to } => { + ProjectionElem::Subslice { from, to } + } ProjectionElem::OpaqueCast(x) => ProjectionElem::OpaqueCast(x), - ProjectionElem::Index(x) => match x { }, - } - }).collect(), + ProjectionElem::Index(x) => match x {}, + }) + .collect(), }; match &capture.kind { CaptureKind::ByRef(bk) => { let placeholder_subst = self.placeholder_subst(); - let tmp_ty = capture.ty.clone().substitute(Interner, &placeholder_subst); + let tmp_ty = + capture.ty.clone().substitute(Interner, &placeholder_subst); let tmp: Place = self.temp(tmp_ty, current, capture.span)?.into(); self.push_assignment( current, @@ -1044,7 +1194,7 @@ impl<'ctx> MirLowerCtx<'ctx> { capture.span, ); operands.push(Operand::Move(tmp)); - }, + } CaptureKind::ByValue => operands.push(Operand::Move(p)), } } @@ -1055,18 +1205,18 @@ impl<'ctx> MirLowerCtx<'ctx> { expr_id.into(), ); Ok(Some(current)) - }, + } Expr::Tuple { exprs, is_assignee_expr: _ } => { let Some(values) = exprs - .iter() - .map(|x| { - let Some((o, c)) = self.lower_expr_to_some_operand(*x, current)? else { - return Ok(None); - }; - current = c; - Ok(Some(o)) - }) - .collect::>>()? + .iter() + .map(|x| { + let Some((o, c)) = self.lower_expr_to_some_operand(*x, current)? else { + return Ok(None); + }; + current = c; + Ok(Some(o)) + }) + .collect::>>()? else { return Ok(None); }; @@ -1088,27 +1238,26 @@ impl<'ctx> MirLowerCtx<'ctx> { } }; let Some(values) = elements - .iter() - .map(|x| { - let Some((o, c)) = self.lower_expr_to_some_operand(*x, current)? else { - return Ok(None); - }; - current = c; - Ok(Some(o)) - }) - .collect::>>()? + .iter() + .map(|x| { + let Some((o, c)) = self.lower_expr_to_some_operand(*x, current)? else { + return Ok(None); + }; + current = c; + Ok(Some(o)) + }) + .collect::>>()? else { return Ok(None); }; - let r = Rvalue::Aggregate( - AggregateKind::Array(elem_ty), - values, - ); + let r = Rvalue::Aggregate(AggregateKind::Array(elem_ty), values); self.push_assignment(current, place, r, expr_id.into()); Ok(Some(current)) } Array::Repeat { initializer, .. } => { - let Some((init, current)) = self.lower_expr_to_some_operand(*initializer, current)? else { + let Some((init, current)) = + self.lower_expr_to_some_operand(*initializer, current)? + else { return Ok(None); }; let len = match &self.expr_ty_without_adjust(expr_id).data(Interner).kind { @@ -1122,7 +1271,7 @@ impl<'ctx> MirLowerCtx<'ctx> { let r = Rvalue::Repeat(init, len); self.push_assignment(current, place, r, expr_id.into()); Ok(Some(current)) - }, + } }, Expr::Literal(l) => { let ty = self.expr_ty_without_adjust(expr_id); diff --git a/crates/hir-ty/src/mir/lower/as_place.rs b/crates/hir-ty/src/mir/lower/as_place.rs index d2c8d9a089e0..79f6da48ce56 100644 --- a/crates/hir-ty/src/mir/lower/as_place.rs +++ b/crates/hir-ty/src/mir/lower/as_place.rs @@ -18,7 +18,9 @@ impl MirLowerCtx<'_> { ) -> Result> { let ty = self.expr_ty_without_adjust(expr_id); let place = self.temp(ty, prev_block, expr_id.into())?; - let Some(current) = self.lower_expr_to_place_without_adjust(expr_id, place.into(), prev_block)? else { + let Some(current) = + self.lower_expr_to_place_without_adjust(expr_id, place.into(), prev_block)? + else { return Ok(None); }; Ok(Some((place.into(), current))) @@ -35,7 +37,9 @@ impl MirLowerCtx<'_> { .map(|x| x.target.clone()) .unwrap_or_else(|| self.expr_ty_without_adjust(expr_id)); let place = self.temp(ty, prev_block, expr_id.into())?; - let Some(current) = self.lower_expr_to_place_with_adjust(expr_id, place.into(), prev_block, adjustments)? else { + let Some(current) = + self.lower_expr_to_place_with_adjust(expr_id, place.into(), prev_block, adjustments)? + else { return Ok(None); }; Ok(Some((place.into(), current))) @@ -62,7 +66,8 @@ impl MirLowerCtx<'_> { expr_id, upgrade_rvalue, rest, - )? else { + )? + else { return Ok(None); }; x.0 = x.0.project(ProjectionElem::Deref); @@ -74,7 +79,8 @@ impl MirLowerCtx<'_> { expr_id, upgrade_rvalue, rest, - )? else { + )? + else { return Ok(None); }; self.lower_overloaded_deref( @@ -165,7 +171,8 @@ impl MirLowerCtx<'_> { _ => false, }; if !is_builtin { - let Some((p, current)) = self.lower_expr_as_place(current, *expr, true)? else { + let Some((p, current)) = self.lower_expr_as_place(current, *expr, true)? + else { return Ok(None); }; return self.lower_overloaded_deref( @@ -192,7 +199,8 @@ impl MirLowerCtx<'_> { }, ); } - let Some((mut r, current)) = self.lower_expr_as_place(current, *expr, true)? else { + let Some((mut r, current)) = self.lower_expr_as_place(current, *expr, true)? + else { return Ok(None); }; r = r.project(ProjectionElem::Deref); @@ -217,12 +225,18 @@ impl MirLowerCtx<'_> { ) { let Some(index_fn) = self.infer.method_resolution(expr_id) else { - return Err(MirLowerError::UnresolvedMethod("[overloaded index]".to_string())); + return Err(MirLowerError::UnresolvedMethod( + "[overloaded index]".to_string(), + )); }; - let Some((base_place, current)) = self.lower_expr_as_place(current, *base, true)? else { + let Some((base_place, current)) = + self.lower_expr_as_place(current, *base, true)? + else { return Ok(None); }; - let Some((index_operand, current)) = self.lower_expr_to_some_operand(*index, current)? else { + let Some((index_operand, current)) = + self.lower_expr_to_some_operand(*index, current)? + else { return Ok(None); }; return self.lower_overloaded_index( @@ -249,7 +263,8 @@ impl MirLowerCtx<'_> { }; let l_index = self.temp(self.expr_ty_after_adjustments(*index), current, expr_id.into())?; - let Some(current) = self.lower_expr_to_place(*index, l_index.into(), current)? else { + let Some(current) = self.lower_expr_to_place(*index, l_index.into(), current)? + else { return Ok(None); }; p_base = p_base.project(ProjectionElem::Index(l_index)); @@ -282,7 +297,15 @@ impl MirLowerCtx<'_> { ) .intern(Interner), ); - let Some(current) = self.lower_call(index_fn_op, Box::new([Operand::Copy(place), index_operand]), result.clone(), current, false, span)? else { + let Some(current) = self.lower_call( + index_fn_op, + Box::new([Operand::Copy(place), index_operand]), + result.clone(), + current, + false, + span, + )? + else { return Ok(None); }; result = result.project(ProjectionElem::Deref); @@ -329,7 +352,15 @@ impl MirLowerCtx<'_> { .intern(Interner), ); let mut result: Place = self.temp(target_ty_ref, current, span)?.into(); - let Some(current) = self.lower_call(deref_fn_op, Box::new([Operand::Copy(ref_place)]), result.clone(), current, false, span)? else { + let Some(current) = self.lower_call( + deref_fn_op, + Box::new([Operand::Copy(ref_place)]), + result.clone(), + current, + false, + span, + )? + else { return Ok(None); }; result = result.project(ProjectionElem::Deref); diff --git a/crates/hir-ty/src/tests.rs b/crates/hir-ty/src/tests.rs index 8e5514353d55..d22d0d85c8e1 100644 --- a/crates/hir-ty/src/tests.rs +++ b/crates/hir-ty/src/tests.rs @@ -206,7 +206,9 @@ fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool, display_sour let Some(node) = (match expr_or_pat { hir_def::hir::ExprOrPatId::ExprId(expr) => expr_node(&body_source_map, expr, &db), hir_def::hir::ExprOrPatId::PatId(pat) => pat_node(&body_source_map, pat, &db), - }) else { continue; }; + }) else { + continue; + }; let range = node.as_ref().original_file_range(&db); let actual = format!( "expected {}, got {}", diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 7d07e9cce421..90825684368e 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -701,9 +701,9 @@ fn emit_macro_def_diagnostics(db: &dyn HirDatabase, acc: &mut Vec let id = macro_id_to_def_id(db.upcast(), m.id); if let Err(e) = db.macro_def(id) { let Some(ast) = id.ast_id().left() else { - never!("MacroDefError for proc-macro: {:?}", e); - return; - }; + never!("MacroDefError for proc-macro: {:?}", e); + return; + }; emit_def_diagnostic_( db, acc, diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 0c46e2a4fe58..39a3e1c4489e 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -1494,7 +1494,11 @@ impl<'db> SemanticsImpl<'db> { } fn is_inside_unsafe(&self, expr: &ast::Expr) -> bool { - let Some(enclosing_item) = expr.syntax().ancestors().find_map(Either::::cast) else { return false }; + let Some(enclosing_item) = + expr.syntax().ancestors().find_map(Either::::cast) + else { + return false; + }; let def = match &enclosing_item { Either::Left(ast::Item::Fn(it)) if it.unsafe_token().is_some() => return true, diff --git a/crates/ide-assists/src/handlers/desugar_doc_comment.rs b/crates/ide-assists/src/handlers/desugar_doc_comment.rs index 226a5dd9fa8b..ddc8a50ed400 100644 --- a/crates/ide-assists/src/handlers/desugar_doc_comment.rs +++ b/crates/ide-assists/src/handlers/desugar_doc_comment.rs @@ -27,7 +27,9 @@ use crate::{ pub(crate) fn desugar_doc_comment(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let comment = ctx.find_token_at_offset::()?; // Only allow doc comments - let Some(placement) = comment.kind().doc else { return None; }; + let Some(placement) = comment.kind().doc else { + return None; + }; // Only allow comments which are alone on their line if let Some(prev) = comment.syntax().prev_token() { diff --git a/crates/ide-assists/src/handlers/fix_visibility.rs b/crates/ide-assists/src/handlers/fix_visibility.rs index d6c59a9c8295..4a2ab18c983d 100644 --- a/crates/ide-assists/src/handlers/fix_visibility.rs +++ b/crates/ide-assists/src/handlers/fix_visibility.rs @@ -40,12 +40,16 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext<'_>) let qualifier = path.qualifier()?; let name_ref = path.segment()?.name_ref()?; let qualifier_res = ctx.sema.resolve_path(&qualifier)?; - let PathResolution::Def(ModuleDef::Module(module)) = qualifier_res else { return None; }; + let PathResolution::Def(ModuleDef::Module(module)) = qualifier_res else { + return None; + }; let (_, def) = module .scope(ctx.db(), None) .into_iter() .find(|(name, _)| name.to_smol_str() == name_ref.text().as_str())?; - let ScopeDef::ModuleDef(def) = def else { return None; }; + let ScopeDef::ModuleDef(def) = def else { + return None; + }; let current_module = ctx.sema.scope(path.syntax())?.module(); let target_module = def.module(ctx.db())?; diff --git a/crates/ide-assists/src/handlers/generate_delegate_methods.rs b/crates/ide-assists/src/handlers/generate_delegate_methods.rs index b68c766e6477..1c2ec79809bd 100644 --- a/crates/ide-assists/src/handlers/generate_delegate_methods.rs +++ b/crates/ide-assists/src/handlers/generate_delegate_methods.rs @@ -88,7 +88,9 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' let adt = ast::Adt::Struct(strukt.clone()); let name = name.display(ctx.db()).to_string(); // if `find_struct_impl` returns None, that means that a function named `name` already exists. - let Some(impl_def) = find_struct_impl(ctx, &adt, std::slice::from_ref(&name)) else { continue; }; + let Some(impl_def) = find_struct_impl(ctx, &adt, std::slice::from_ref(&name)) else { + continue; + }; acc.add_group( &GroupLabel("Generate delegate methods…".to_owned()), AssistId("generate_delegate_methods", AssistKind::Generate), diff --git a/crates/ide-assists/src/handlers/generate_function.rs b/crates/ide-assists/src/handlers/generate_function.rs index c579f6780db8..8085572497aa 100644 --- a/crates/ide-assists/src/handlers/generate_function.rs +++ b/crates/ide-assists/src/handlers/generate_function.rs @@ -623,7 +623,9 @@ fn fn_generic_params( fn params_and_where_preds_in_scope( ctx: &AssistContext<'_>, ) -> (Vec, Vec) { - let Some(body) = containing_body(ctx) else { return Default::default(); }; + let Some(body) = containing_body(ctx) else { + return Default::default(); + }; let mut generic_params = Vec::new(); let mut where_clauses = Vec::new(); diff --git a/crates/ide-assists/src/handlers/move_const_to_impl.rs b/crates/ide-assists/src/handlers/move_const_to_impl.rs index b6027eac55de..e1849eb71d57 100644 --- a/crates/ide-assists/src/handlers/move_const_to_impl.rs +++ b/crates/ide-assists/src/handlers/move_const_to_impl.rs @@ -54,7 +54,11 @@ pub(crate) fn move_const_to_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> // NOTE: We can technically provide this assist for default methods in trait definitions, but // it's somewhat complex to handle it correctly when the const's name conflicts with // supertrait's item. We may want to consider implementing it in the future. - let AssocItemContainer::Impl(impl_) = ctx.sema.to_def(&parent_fn)?.as_assoc_item(db)?.container(db) else { return None; }; + let AssocItemContainer::Impl(impl_) = + ctx.sema.to_def(&parent_fn)?.as_assoc_item(db)?.container(db) + else { + return None; + }; if impl_.trait_(db).is_some() { return None; } diff --git a/crates/ide-assists/src/handlers/unwrap_result_return_type.rs b/crates/ide-assists/src/handlers/unwrap_result_return_type.rs index 26f3c192617e..f235b554e61f 100644 --- a/crates/ide-assists/src/handlers/unwrap_result_return_type.rs +++ b/crates/ide-assists/src/handlers/unwrap_result_return_type.rs @@ -38,14 +38,18 @@ pub(crate) fn unwrap_result_return_type(acc: &mut Assists, ctx: &AssistContext<' }; let type_ref = &ret_type.ty()?; - let Some(hir::Adt::Enum(ret_enum)) = ctx.sema.resolve_type(type_ref)?.as_adt() else { return None; }; + let Some(hir::Adt::Enum(ret_enum)) = ctx.sema.resolve_type(type_ref)?.as_adt() else { + return None; + }; let result_enum = FamousDefs(&ctx.sema, ctx.sema.scope(type_ref.syntax())?.krate()).core_result_Result()?; if ret_enum != result_enum { return None; } - let Some(ok_type) = unwrap_result_type(type_ref) else { return None; }; + let Some(ok_type) = unwrap_result_type(type_ref) else { + return None; + }; acc.add( AssistId("unwrap_result_return_type", AssistKind::RefactorRewrite), @@ -130,12 +134,16 @@ fn tail_cb_impl(acc: &mut Vec, e: &ast::Expr) { // Tries to extract `T` from `Result`. fn unwrap_result_type(ty: &ast::Type) -> Option { - let ast::Type::PathType(path_ty) = ty else { return None; }; + let ast::Type::PathType(path_ty) = ty else { + return None; + }; let path = path_ty.path()?; let segment = path.first_segment()?; let generic_arg_list = segment.generic_arg_list()?; let generic_args: Vec<_> = generic_arg_list.generic_args().collect(); - let ast::GenericArg::TypeArg(ok_type) = generic_args.first()? else { return None; }; + let ast::GenericArg::TypeArg(ok_type) = generic_args.first()? else { + return None; + }; ok_type.ty() } diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs index 7b145f3c14e3..3cb65b2729ac 100644 --- a/crates/ide-completion/src/context.rs +++ b/crates/ide-completion/src/context.rs @@ -463,7 +463,9 @@ impl CompletionContext<'_> { /// Checks whether this item should be listed in regards to stability. Returns `true` if we should. pub(crate) fn check_stability(&self, attrs: Option<&hir::Attrs>) -> bool { - let Some(attrs) = attrs else { return true; }; + let Some(attrs) = attrs else { + return true; + }; !attrs.is_unstable() || self.is_nightly } diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs index cc5221cfccbd..932233ad63b6 100644 --- a/crates/ide-completion/src/context/analysis.rs +++ b/crates/ide-completion/src/context/analysis.rs @@ -243,10 +243,7 @@ fn analyze( let Some(name_like) = find_node_at_offset(&speculative_file, offset) else { let analysis = if let Some(original) = ast::String::cast(original_token.clone()) { - CompletionAnalysis::String { - original, - expanded: ast::String::cast(self_token.clone()), - } + CompletionAnalysis::String { original, expanded: ast::String::cast(self_token.clone()) } } else { // Fix up trailing whitespace problem // #[attr(foo = $0 diff --git a/crates/ide-diagnostics/src/handlers/unlinked_file.rs b/crates/ide-diagnostics/src/handlers/unlinked_file.rs index 271e7ce73bcd..7e0d9532819e 100644 --- a/crates/ide-diagnostics/src/handlers/unlinked_file.rs +++ b/crates/ide-diagnostics/src/handlers/unlinked_file.rs @@ -119,10 +119,11 @@ fn fixes(ctx: &DiagnosticsContext<'_>, file_id: FileId) -> Option> { stack.pop(); 'crates: for &krate in ctx.sema.db.relevant_crates(parent_id).iter() { let crate_def_map = ctx.sema.db.crate_def_map(krate); - let Some((_, module)) = - crate_def_map.modules() - .find(|(_, module)| module.origin.file_id() == Some(parent_id) && !module.origin.is_inline()) - else { continue }; + let Some((_, module)) = crate_def_map.modules().find(|(_, module)| { + module.origin.file_id() == Some(parent_id) && !module.origin.is_inline() + }) else { + continue; + }; if stack.is_empty() { return make_fixes( diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs index 8112c4f7259c..c90ba2125353 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs @@ -330,7 +330,9 @@ fn get_doc_links( base_url.and_then(|url| url.join(path).ok()) }; - let Some((target, file, frag)) = filename_and_frag_for_def(db, def) else { return Default::default(); }; + let Some((target, file, frag)) = filename_and_frag_for_def(db, def) else { + return Default::default(); + }; let (mut web_url, mut local_url) = get_doc_base_urls(db, target, target_dir, sysroot); diff --git a/crates/ide/src/inlay_hints/adjustment.rs b/crates/ide/src/inlay_hints/adjustment.rs index 10bee2a6accf..6d6bd315ebb4 100644 --- a/crates/ide/src/inlay_hints/adjustment.rs +++ b/crates/ide/src/inlay_hints/adjustment.rs @@ -259,7 +259,7 @@ fn needs_parens_for_adjustment_hints(expr: &ast::Expr, postfix: bool) -> (bool, } })() else { never!("broken syntax tree?\n{:?}\n{:?}", expr, dummy_expr); - return (true, true) + return (true, true); }; // At this point diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index 1c09af9abd2b..e2db1957eaa1 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -268,10 +268,12 @@ impl flags::AnalysisStats { continue; } all += 1; - let Err(e) - = db.layout_of_adt(hir_def::AdtId::from(a).into(), Substitution::empty(Interner), a.krate(db).into()) - else { - continue + let Err(e) = db.layout_of_adt( + hir_def::AdtId::from(a).into(), + Substitution::empty(Interner), + a.krate(db).into(), + ) else { + continue; }; if verbosity.is_spammy() { let full_name = full_name_of_item(db, a.module(db), a.name(db)); diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs index 69799a54cb11..bb0c7ffa7289 100644 --- a/crates/rust-analyzer/src/handlers/request.rs +++ b/crates/rust-analyzer/src/handlers/request.rs @@ -1331,7 +1331,9 @@ pub(crate) fn handle_code_lens_resolve( snap: GlobalStateSnapshot, code_lens: CodeLens, ) -> anyhow::Result { - let Some(annotation) = from_proto::annotation(&snap, code_lens.clone())? else { return Ok(code_lens) }; + let Some(annotation) = from_proto::annotation(&snap, code_lens.clone())? else { + return Ok(code_lens); + }; let annotation = snap.analysis.resolve_annotation(annotation)?; let mut acc = Vec::new(); @@ -1632,9 +1634,9 @@ pub(crate) fn handle_open_docs( let Ok(remote_urls) = snap.analysis.external_docs(position, target_dir, sysroot) else { return if snap.config.local_docs() { Ok(ExternalDocsResponse::WithLocal(Default::default())) - } else { + } else { Ok(ExternalDocsResponse::Simple(None)) - } + }; }; let web = remote_urls.web_url.and_then(|it| Url::parse(&it).ok()); diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index dd5517e6979a..18d9151d4aab 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -334,7 +334,11 @@ impl GlobalState { let _p = profile::span("GlobalState::switch_workspaces"); tracing::info!(%cause, "will switch workspaces"); - let Some((workspaces, force_reload_crate_graph)) = self.fetch_workspaces_queue.last_op_result() else { return; }; + let Some((workspaces, force_reload_crate_graph)) = + self.fetch_workspaces_queue.last_op_result() + else { + return; + }; if let Err(_) = self.fetch_workspace_error() { if !self.workspaces.is_empty() { @@ -525,7 +529,7 @@ impl GlobalState { let mut buf = String::new(); let Some((last_op_result, _)) = self.fetch_workspaces_queue.last_op_result() else { - return Ok(()) + return Ok(()); }; if last_op_result.is_empty() { stdx::format_to!(buf, "rust-analyzer failed to discover workspace"); diff --git a/crates/sourcegen/src/lib.rs b/crates/sourcegen/src/lib.rs index c5da6ceb4d19..1514c6c7d4c1 100644 --- a/crates/sourcegen/src/lib.rs +++ b/crates/sourcegen/src/lib.rs @@ -61,7 +61,9 @@ impl CommentBlock { let mut blocks = CommentBlock::extract_untagged(text); blocks.retain_mut(|block| { let first = block.contents.remove(0); - let Some(id) = first.strip_prefix(&tag) else { return false; }; + let Some(id) = first.strip_prefix(&tag) else { + return false; + }; if block.is_doc { panic!("Use plain (non-doc) comments with tags like {tag}:\n {first}"); From 34f6d2414cea30003491b4debbfd8c059b09125b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Mon, 3 Jul 2023 15:11:04 -0400 Subject: [PATCH 143/324] Update `debuginfo` test output to describe new structure of `Rc`/`Arc` --- tests/debuginfo/rc_arc.rs | 24 ++++++++++++------------ tests/debuginfo/thread.rs | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/debuginfo/rc_arc.rs b/tests/debuginfo/rc_arc.rs index 5d5492d72177..1d07bd76eabd 100644 --- a/tests/debuginfo/rc_arc.rs +++ b/tests/debuginfo/rc_arc.rs @@ -27,37 +27,37 @@ // cdb-command:g // cdb-command:dx rc,d -// cdb-check:rc,d : 111 [Type: alloc::rc::Rc] +// cdb-check:rc,d : 111 [Type: alloc::rc::Rc] // cdb-check: [Reference count] : 11 [Type: core::cell::Cell] // cdb-check: [Weak reference count] : 2 [Type: core::cell::Cell] // cdb-command:dx weak_rc,d -// cdb-check:weak_rc,d : 111 [Type: alloc::rc::Weak] +// cdb-check:weak_rc,d : 111 [Type: alloc::rc::Weak] // cdb-check: [Reference count] : 11 [Type: core::cell::Cell] // cdb-check: [Weak reference count] : 2 [Type: core::cell::Cell] // cdb-command:dx arc,d -// cdb-check:arc,d : 222 [Type: alloc::sync::Arc] +// cdb-check:arc,d : 222 [Type: alloc::sync::Arc] // cdb-check: [Reference count] : 21 [Type: core::sync::atomic::AtomicUsize] // cdb-check: [Weak reference count] : 2 [Type: core::sync::atomic::AtomicUsize] // cdb-command:dx weak_arc,d -// cdb-check:weak_arc,d : 222 [Type: alloc::sync::Weak] +// cdb-check:weak_arc,d : 222 [Type: alloc::sync::Weak] // cdb-check: [Reference count] : 21 [Type: core::sync::atomic::AtomicUsize] // cdb-check: [Weak reference count] : 2 [Type: core::sync::atomic::AtomicUsize] // cdb-command:dx dyn_rc,d -// cdb-check:dyn_rc,d [Type: alloc::rc::Rc >] +// cdb-check:dyn_rc,d [Type: alloc::rc::Rc,alloc::alloc::Global>] // cdb-check: [Reference count] : 31 [Type: core::cell::Cell] // cdb-check: [Weak reference count] : 2 [Type: core::cell::Cell] // cdb-command:dx dyn_rc_weak,d -// cdb-check:dyn_rc_weak,d [Type: alloc::rc::Weak >] +// cdb-check:dyn_rc_weak,d [Type: alloc::rc::Weak,alloc::alloc::Global>] // cdb-check: [Reference count] : 31 [Type: core::cell::Cell] // cdb-check: [Weak reference count] : 2 [Type: core::cell::Cell] // cdb-command:dx slice_rc,d -// cdb-check:slice_rc,d : { len=3 } [Type: alloc::rc::Rc >] +// cdb-check:slice_rc,d : { len=3 } [Type: alloc::rc::Rc,alloc::alloc::Global>] // cdb-check: [Length] : 3 [Type: [...]] // cdb-check: [Reference count] : 41 [Type: core::cell::Cell] // cdb-check: [Weak reference count] : 2 [Type: core::cell::Cell] @@ -66,7 +66,7 @@ // cdb-check: [2] : 3 [Type: u32] // cdb-command:dx slice_rc_weak,d -// cdb-check:slice_rc_weak,d : { len=3 } [Type: alloc::rc::Weak >] +// cdb-check:slice_rc_weak,d : { len=3 } [Type: alloc::rc::Weak,alloc::alloc::Global>] // cdb-check: [Length] : 3 [Type: [...]] // cdb-check: [Reference count] : 41 [Type: core::cell::Cell] // cdb-check: [Weak reference count] : 2 [Type: core::cell::Cell] @@ -75,17 +75,17 @@ // cdb-check: [2] : 3 [Type: u32] // cdb-command:dx dyn_arc,d -// cdb-check:dyn_arc,d [Type: alloc::sync::Arc >] +// cdb-check:dyn_arc,d [Type: alloc::sync::Arc,alloc::alloc::Global>] // cdb-check: [Reference count] : 51 [Type: core::sync::atomic::AtomicUsize] // cdb-check: [Weak reference count] : 2 [Type: core::sync::atomic::AtomicUsize] // cdb-command:dx dyn_arc_weak,d -// cdb-check:dyn_arc_weak,d [Type: alloc::sync::Weak >] +// cdb-check:dyn_arc_weak,d [Type: alloc::sync::Weak,alloc::alloc::Global>] // cdb-check: [Reference count] : 51 [Type: core::sync::atomic::AtomicUsize] // cdb-check: [Weak reference count] : 2 [Type: core::sync::atomic::AtomicUsize] // cdb-command:dx slice_arc,d -// cdb-check:slice_arc,d : { len=3 } [Type: alloc::sync::Arc >] +// cdb-check:slice_arc,d : { len=3 } [Type: alloc::sync::Arc,alloc::alloc::Global>] // cdb-check: [Length] : 3 [Type: [...]] // cdb-check: [Reference count] : 61 [Type: core::sync::atomic::AtomicUsize] // cdb-check: [Weak reference count] : 2 [Type: core::sync::atomic::AtomicUsize] @@ -94,7 +94,7 @@ // cdb-check: [2] : 6 [Type: u32] // cdb-command:dx slice_arc_weak,d -// cdb-check:slice_arc_weak,d : { len=3 } [Type: alloc::sync::Weak >] +// cdb-check:slice_arc_weak,d : { len=3 } [Type: alloc::sync::Weak,alloc::alloc::Global>] // cdb-check: [Length] : 3 [Type: [...]] // cdb-check: [Reference count] : 61 [Type: core::sync::atomic::AtomicUsize] // cdb-check: [Weak reference count] : 2 [Type: core::sync::atomic::AtomicUsize] diff --git a/tests/debuginfo/thread.rs b/tests/debuginfo/thread.rs index e7e83c7aacd4..d888ad00f967 100644 --- a/tests/debuginfo/thread.rs +++ b/tests/debuginfo/thread.rs @@ -14,7 +14,7 @@ // // cdb-command:dx t,d // cdb-check:t,d : [...] [Type: std::thread::Thread *] -// cdb-check:[...] inner [...][Type: core::pin::Pin >] +// cdb-check:[...] inner [...][Type: core::pin::Pin,alloc::alloc::Global>] use std::thread; From b41fc6784fc723ea52da0e0668fc5205b740f81a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 6 Jun 2023 19:27:12 +0200 Subject: [PATCH 144/324] Add needless_pass_by_ref lint --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/lib.rs | 2 + clippy_lints/src/needless_pass_by_ref_mut.rs | 238 +++++++++++++++++++ clippy_lints/src/needless_pass_by_value.rs | 2 +- 5 files changed, 243 insertions(+), 1 deletion(-) create mode 100644 clippy_lints/src/needless_pass_by_ref_mut.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index f9310b4ab31f..762efed5c120 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5047,6 +5047,7 @@ Released 2018-09-13 [`needless_option_as_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_option_as_deref [`needless_option_take`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_option_take [`needless_parens_on_range_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_parens_on_range_literals +[`needless_pass_by_ref_mut`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut [`needless_pass_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_value [`needless_pub_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_pub_self [`needless_question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_question_mark diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index e1dbe5003965..4f945ebc6101 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -470,6 +470,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::needless_if::NEEDLESS_IF_INFO, crate::needless_late_init::NEEDLESS_LATE_INIT_INFO, crate::needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS_INFO, + crate::needless_pass_by_ref_mut::NEEDLESS_PASS_BY_REF_MUT_INFO, crate::needless_pass_by_value::NEEDLESS_PASS_BY_VALUE_INFO, crate::needless_question_mark::NEEDLESS_QUESTION_MARK_INFO, crate::needless_update::NEEDLESS_UPDATE_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index c43e0b753dc8..e1e4a83b031b 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -229,6 +229,7 @@ mod needless_for_each; mod needless_if; mod needless_late_init; mod needless_parens_on_range_literals; +mod needless_pass_by_ref_mut; mod needless_pass_by_value; mod needless_question_mark; mod needless_update; @@ -1057,6 +1058,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: let stack_size_threshold = conf.stack_size_threshold; store.register_late_pass(move |_| Box::new(large_stack_frames::LargeStackFrames::new(stack_size_threshold))); store.register_late_pass(|_| Box::new(single_range_in_vec_init::SingleRangeInVecInit)); + store.register_late_pass(|_| Box::new(needless_pass_by_ref_mut::NeedlessPassByRefMut)); store.register_late_pass(|_| Box::new(incorrect_impls::IncorrectImpls)); store.register_late_pass(move |_| { Box::new(single_call_fn::SingleCallFn { diff --git a/clippy_lints/src/needless_pass_by_ref_mut.rs b/clippy_lints/src/needless_pass_by_ref_mut.rs new file mode 100644 index 000000000000..c5dc87cdfa88 --- /dev/null +++ b/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -0,0 +1,238 @@ +use super::needless_pass_by_value::requires_exact_signature; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use clippy_utils::{is_from_proc_macro, is_self}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::intravisit::FnKind; +use rustc_hir::{Body, FnDecl, HirId, Impl, ItemKind, Mutability, Node, PatKind}; +use rustc_hir::{HirIdMap, HirIdSet}; +use rustc_hir_typeck::expr_use_visitor as euv; +use rustc_infer::infer::TyCtxtInferExt; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::mir::FakeReadCause; +use rustc_middle::ty::{self, Ty}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::def_id::LocalDefId; +use rustc_span::symbol::kw; +use rustc_span::Span; +use rustc_target::spec::abi::Abi; + +declare_clippy_lint! { + /// ### What it does + /// Check if a `&mut` function argument is actually used mutably. + /// + /// ### Why is this bad? + /// Less `mut` means less fights with the borrow checker. It can also lead to more + /// opportunities for parallelization. + /// + /// ### Example + /// ```rust + /// fn foo(y: &mut i32) -> i32 { + /// 12 + *y + /// } + /// ``` + /// Use instead: + /// ```rust + /// fn foo(y: &i32) -> i32 { + /// 12 + *y + /// } + /// ``` + #[clippy::version = "1.72.0"] + pub NEEDLESS_PASS_BY_REF_MUT, + suspicious, + "using a `&mut` argument when it's not mutated" +} +declare_lint_pass!(NeedlessPassByRefMut => [NEEDLESS_PASS_BY_REF_MUT]); + +fn should_skip<'tcx>( + cx: &LateContext<'tcx>, + input: rustc_hir::Ty<'tcx>, + ty: Ty<'_>, + arg: &rustc_hir::Param<'_>, +) -> bool { + // We check if this a `&mut`. `ref_mutability` returns `None` if it's not a reference. + if !matches!(ty.ref_mutability(), Some(Mutability::Mut)) { + return true; + } + + if is_self(arg) { + return true; + } + + if let PatKind::Binding(.., name, _) = arg.pat.kind { + // If it's a potentially unused variable, we don't check it. + if name.name == kw::Underscore || name.as_str().starts_with('_') { + return true; + } + } + + // All spans generated from a proc-macro invocation are the same... + is_from_proc_macro(cx, &input) +} + +impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut { + fn check_fn( + &mut self, + cx: &LateContext<'tcx>, + kind: FnKind<'tcx>, + decl: &'tcx FnDecl<'_>, + body: &'tcx Body<'_>, + span: Span, + fn_def_id: LocalDefId, + ) { + if span.from_expansion() { + return; + } + + let hir_id = cx.tcx.hir().local_def_id_to_hir_id(fn_def_id); + + match kind { + FnKind::ItemFn(.., header) => { + let attrs = cx.tcx.hir().attrs(hir_id); + if header.abi != Abi::Rust || requires_exact_signature(attrs) { + return; + } + }, + FnKind::Method(..) => (), + FnKind::Closure => return, + } + + // Exclude non-inherent impls + if let Some(Node::Item(item)) = cx.tcx.hir().find_parent(hir_id) { + if matches!( + item.kind, + ItemKind::Impl(Impl { of_trait: Some(_), .. }) | ItemKind::Trait(..) + ) { + return; + } + } + + let fn_sig = cx.tcx.fn_sig(fn_def_id).subst_identity(); + let fn_sig = cx.tcx.liberate_late_bound_regions(fn_def_id.to_def_id(), fn_sig); + + // If there are no `&mut` argument, no need to go any further. + if !decl + .inputs + .iter() + .zip(fn_sig.inputs()) + .zip(body.params) + .any(|((&input, &ty), arg)| !should_skip(cx, input, ty, arg)) + { + return; + } + + // Collect variables mutably used and spans which will need dereferencings from the + // function body. + let MutablyUsedVariablesCtxt { mutably_used_vars, .. } = { + let mut ctx = MutablyUsedVariablesCtxt::default(); + let infcx = cx.tcx.infer_ctxt().build(); + euv::ExprUseVisitor::new(&mut ctx, &infcx, fn_def_id, cx.param_env, cx.typeck_results()).consume_body(body); + ctx + }; + + for ((&input, &ty), arg) in decl.inputs.iter().zip(fn_sig.inputs()).zip(body.params) { + if should_skip(cx, input, ty, arg) { + continue; + } + + // Only take `&mut` arguments. + if_chain! { + if let PatKind::Binding(_, canonical_id, ..) = arg.pat.kind; + if !mutably_used_vars.contains(&canonical_id); + if let rustc_hir::TyKind::Ref(_, inner_ty) = input.kind; + then { + // If the argument is never used mutably, we emit the error. + span_lint_and_sugg( + cx, + NEEDLESS_PASS_BY_REF_MUT, + input.span, + "this argument is a mutable reference, but not used mutably", + "consider changing to", + format!("&{}", snippet(cx, cx.tcx.hir().span(inner_ty.ty.hir_id), "_")), + Applicability::Unspecified, + ); + } + } + } + } +} + +#[derive(Default)] +struct MutablyUsedVariablesCtxt { + mutably_used_vars: HirIdSet, + prev_bind: Option, + aliases: HirIdMap, +} + +impl MutablyUsedVariablesCtxt { + fn add_mutably_used_var(&mut self, mut used_id: HirId) { + while let Some(id) = self.aliases.get(&used_id) { + self.mutably_used_vars.insert(used_id); + used_id = *id; + } + self.mutably_used_vars.insert(used_id); + } +} + +impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt { + fn consume(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, _id: HirId) { + if let euv::Place { + base: euv::PlaceBase::Local(vid), + base_ty, + .. + } = &cmt.place + { + if let Some(bind_id) = self.prev_bind.take() { + self.aliases.insert(bind_id, *vid); + } else if matches!(base_ty.ref_mutability(), Some(Mutability::Mut)) { + self.add_mutably_used_var(*vid); + } + } + } + + fn borrow(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, _id: HirId, borrow: ty::BorrowKind) { + self.prev_bind = None; + if let euv::Place { + base: euv::PlaceBase::Local(vid), + base_ty, + .. + } = &cmt.place + { + // If this is a mutable borrow, it was obviously used mutably so we add it. However + // for `UniqueImmBorrow`, it's interesting because if you do: `array[0] = value` inside + // a closure, it'll return this variant whereas if you have just an index access, it'll + // return `ImmBorrow`. So if there is "Unique" and it's a mutable reference, we add it + // to the mutably used variables set. + if borrow == ty::BorrowKind::MutBorrow + || (borrow == ty::BorrowKind::UniqueImmBorrow && base_ty.ref_mutability() == Some(Mutability::Mut)) + { + self.add_mutably_used_var(*vid); + } + } + } + + fn mutate(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, _id: HirId) { + self.prev_bind = None; + if let euv::Place { + projections, + base: euv::PlaceBase::Local(vid), + .. + } = &cmt.place + { + if !projections.is_empty() { + self.add_mutably_used_var(*vid); + } + } + } + + fn copy(&mut self, _cmt: &euv::PlaceWithHirId<'tcx>, _id: HirId) { + self.prev_bind = None; + } + + fn fake_read(&mut self, _: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {} + + fn bind(&mut self, _cmt: &euv::PlaceWithHirId<'tcx>, id: HirId) { + self.prev_bind = Some(id); + } +} diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index ece10474715f..5d299f9355d5 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -289,7 +289,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { } /// Functions marked with these attributes must have the exact signature. -fn requires_exact_signature(attrs: &[Attribute]) -> bool { +pub(crate) fn requires_exact_signature(attrs: &[Attribute]) -> bool { attrs.iter().any(|attr| { [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive] .iter() From a43bea101621d6ecbf2b33f5fcf122819115171d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 6 Jun 2023 21:06:49 +0200 Subject: [PATCH 145/324] Add UI test for `needless_pass_by_ref_mut` --- tests/ui/needless_pass_by_ref_mut.rs | 105 +++++++++++++++++++++++ tests/ui/needless_pass_by_ref_mut.stderr | 28 ++++++ 2 files changed, 133 insertions(+) create mode 100644 tests/ui/needless_pass_by_ref_mut.rs create mode 100644 tests/ui/needless_pass_by_ref_mut.stderr diff --git a/tests/ui/needless_pass_by_ref_mut.rs b/tests/ui/needless_pass_by_ref_mut.rs new file mode 100644 index 000000000000..5e7280995c60 --- /dev/null +++ b/tests/ui/needless_pass_by_ref_mut.rs @@ -0,0 +1,105 @@ +#![allow(unused)] + +use std::ptr::NonNull; + +// Should only warn for `s`. +fn foo(s: &mut Vec, b: &u32, x: &mut u32) { + *x += *b + s.len() as u32; +} + +// Should not warn. +fn foo2(s: &mut Vec) { + s.push(8); +} + +// Should not warn because we return it. +fn foo3(s: &mut Vec) -> &mut Vec { + s +} + +// Should not warn because `s` is used as mutable. +fn foo4(s: &mut Vec) { + Vec::push(s, 4); +} + +// Should not warn. +fn foo5(s: &mut Vec) { + foo2(s); +} + +// Should warn. +fn foo6(s: &mut Vec) { + non_mut_ref(s); +} + +fn non_mut_ref(_: &Vec) {} + +struct Bar; + +impl Bar { + // Should not warn on `&mut self`. + fn bar(&mut self) {} + + // Should warn about `vec` + fn mushroom(&self, vec: &mut Vec) -> usize { + vec.len() + } + + // Should warn about `vec` (and not `self`). + fn badger(&mut self, vec: &mut Vec) -> usize { + vec.len() + } +} + +trait Babar { + // Should not warn here since it's a trait method. + fn method(arg: &mut u32); +} + +impl Babar for Bar { + // Should not warn here since it's a trait method. + fn method(a: &mut u32) {} +} + +// Should not warn (checking variable aliasing). +fn alias_check(s: &mut Vec) { + let mut alias = s; + let mut alias2 = alias; + let mut alias3 = alias2; + alias3.push(0); +} + +// Should not warn (checking variable aliasing). +fn alias_check2(mut s: &mut Vec) { + let mut alias = &mut s; + alias.push(0); +} + +struct Mut { + ptr: NonNull, +} + +impl Mut { + // Should not warn because `NonNull::from` also accepts `&mut`. + fn new(ptr: &mut T) -> Self { + Mut { + ptr: NonNull::from(ptr), + } + } +} + +// Should not warn. +fn unused(_: &mut u32, _b: &mut u8) {} + +fn main() { + let mut u = 0; + let mut v = vec![0]; + foo(&mut v, &0, &mut u); + foo2(&mut v); + foo3(&mut v); + foo4(&mut v); + foo5(&mut v); + alias_check(&mut v); + alias_check2(&mut v); + println!("{u}"); +} diff --git a/tests/ui/needless_pass_by_ref_mut.stderr b/tests/ui/needless_pass_by_ref_mut.stderr new file mode 100644 index 000000000000..5e9d80bb6c48 --- /dev/null +++ b/tests/ui/needless_pass_by_ref_mut.stderr @@ -0,0 +1,28 @@ +error: this argument is a mutable reference, but not used mutably + --> $DIR/needless_pass_by_ref_mut.rs:6:11 + | +LL | fn foo(s: &mut Vec, b: &u32, x: &mut u32) { + | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` + | + = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` + +error: this argument is a mutable reference, but not used mutably + --> $DIR/needless_pass_by_ref_mut.rs:31:12 + | +LL | fn foo6(s: &mut Vec) { + | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` + +error: this argument is a mutable reference, but not used mutably + --> $DIR/needless_pass_by_ref_mut.rs:44:29 + | +LL | fn mushroom(&self, vec: &mut Vec) -> usize { + | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` + +error: this argument is a mutable reference, but not used mutably + --> $DIR/needless_pass_by_ref_mut.rs:49:31 + | +LL | fn badger(&mut self, vec: &mut Vec) -> usize { + | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` + +error: aborting due to 4 previous errors + From c62c7fadac19354ca24c79fc9b9fb0e747a11505 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 15 Jun 2023 17:24:39 +0200 Subject: [PATCH 146/324] Update UI tests with new `needless_pass_by_ref_mut` lint --- tests/ui-toml/toml_trivially_copy/test.rs | 1 + tests/ui-toml/toml_trivially_copy/test.stderr | 4 +- tests/ui/borrow_box.rs | 6 ++- tests/ui/borrow_box.stderr | 20 ++++---- tests/ui/infinite_loop.stderr | 10 +++- tests/ui/let_underscore_future.stderr | 10 +++- tests/ui/must_use_candidates.fixed | 7 ++- tests/ui/must_use_candidates.rs | 7 ++- tests/ui/must_use_candidates.stderr | 10 ++-- tests/ui/mut_from_ref.rs | 2 +- tests/ui/mut_key.stderr | 10 +++- tests/ui/mut_mut.rs | 7 ++- tests/ui/mut_mut.stderr | 18 ++++---- tests/ui/mut_reference.stderr | 16 ++++++- tests/ui/ptr_arg.rs | 3 +- tests/ui/ptr_arg.stderr | 46 +++++++++---------- tests/ui/read_zero_byte_vec.rs | 2 +- tests/ui/self_assignment.rs | 2 +- .../ui/should_impl_trait/method_list_2.stderr | 10 +++- tests/ui/slow_vector_initialization.stderr | 10 +++- tests/ui/trivially_copy_pass_by_ref.rs | 3 +- tests/ui/trivially_copy_pass_by_ref.stderr | 36 +++++++-------- tests/ui/unused_io_amount.rs | 2 +- tests/ui/useless_asref.fixed | 6 ++- tests/ui/useless_asref.rs | 6 ++- tests/ui/useless_asref.stderr | 22 ++++----- 26 files changed, 180 insertions(+), 96 deletions(-) diff --git a/tests/ui-toml/toml_trivially_copy/test.rs b/tests/ui-toml/toml_trivially_copy/test.rs index f267a67f40ee..78784bfff0fd 100644 --- a/tests/ui-toml/toml_trivially_copy/test.rs +++ b/tests/ui-toml/toml_trivially_copy/test.rs @@ -2,6 +2,7 @@ //@normalize-stderr-test: "\(limit: \d+ byte\)" -> "(limit: N byte)" #![warn(clippy::trivially_copy_pass_by_ref)] +#![allow(clippy::needless_pass_by_ref_mut)] #[derive(Copy, Clone)] struct Foo(u8); diff --git a/tests/ui-toml/toml_trivially_copy/test.stderr b/tests/ui-toml/toml_trivially_copy/test.stderr index d2b55eff16db..db5d6805362d 100644 --- a/tests/ui-toml/toml_trivially_copy/test.stderr +++ b/tests/ui-toml/toml_trivially_copy/test.stderr @@ -1,5 +1,5 @@ error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/test.rs:14:11 + --> $DIR/test.rs:15:11 | LL | fn bad(x: &u16, y: &Foo) {} | ^^^^ help: consider passing by value instead: `u16` @@ -7,7 +7,7 @@ LL | fn bad(x: &u16, y: &Foo) {} = note: `-D clippy::trivially-copy-pass-by-ref` implied by `-D warnings` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/test.rs:14:20 + --> $DIR/test.rs:15:20 | LL | fn bad(x: &u16, y: &Foo) {} | ^^^^ help: consider passing by value instead: `Foo` diff --git a/tests/ui/borrow_box.rs b/tests/ui/borrow_box.rs index 3b5b6bf4c950..95b6b0f50383 100644 --- a/tests/ui/borrow_box.rs +++ b/tests/ui/borrow_box.rs @@ -1,6 +1,10 @@ #![deny(clippy::borrowed_box)] #![allow(dead_code, unused_variables)] -#![allow(clippy::uninlined_format_args, clippy::disallowed_names)] +#![allow( + clippy::uninlined_format_args, + clippy::disallowed_names, + clippy::needless_pass_by_ref_mut +)] use std::fmt::Display; diff --git a/tests/ui/borrow_box.stderr b/tests/ui/borrow_box.stderr index 99cb60a1ead9..90e752211ff0 100644 --- a/tests/ui/borrow_box.stderr +++ b/tests/ui/borrow_box.stderr @@ -1,5 +1,5 @@ error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:20:14 + --> $DIR/borrow_box.rs:24:14 | LL | let foo: &Box; | ^^^^^^^^^^ help: try: `&bool` @@ -11,55 +11,55 @@ LL | #![deny(clippy::borrowed_box)] | ^^^^^^^^^^^^^^^^^^^^ error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:24:10 + --> $DIR/borrow_box.rs:28:10 | LL | foo: &'a Box, | ^^^^^^^^^^^^^ help: try: `&'a bool` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:28:17 + --> $DIR/borrow_box.rs:32:17 | LL | fn test4(a: &Box); | ^^^^^^^^^^ help: try: `&bool` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:94:25 + --> $DIR/borrow_box.rs:98:25 | LL | pub fn test14(_display: &Box) {} | ^^^^^^^^^^^^^^^^^ help: try: `&dyn Display` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:95:25 + --> $DIR/borrow_box.rs:99:25 | LL | pub fn test15(_display: &Box) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(dyn Display + Send)` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:96:29 + --> $DIR/borrow_box.rs:100:29 | LL | pub fn test16<'a>(_display: &'a Box) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&'a (dyn Display + 'a)` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:98:25 + --> $DIR/borrow_box.rs:102:25 | LL | pub fn test17(_display: &Box) {} | ^^^^^^^^^^^^^^^^^^ help: try: `&impl Display` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:99:25 + --> $DIR/borrow_box.rs:103:25 | LL | pub fn test18(_display: &Box) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(impl Display + Send)` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:100:29 + --> $DIR/borrow_box.rs:104:29 | LL | pub fn test19<'a>(_display: &'a Box) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&'a (impl Display + 'a)` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:105:25 + --> $DIR/borrow_box.rs:109:25 | LL | pub fn test20(_display: &Box<(dyn Display + Send)>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(dyn Display + Send)` diff --git a/tests/ui/infinite_loop.stderr b/tests/ui/infinite_loop.stderr index 85258b9d64f9..701b3cd19041 100644 --- a/tests/ui/infinite_loop.stderr +++ b/tests/ui/infinite_loop.stderr @@ -1,3 +1,11 @@ +error: this argument is a mutable reference, but not used mutably + --> $DIR/infinite_loop.rs:7:17 + | +LL | fn fn_mutref(i: &mut i32) { + | ^^^^^^^^ help: consider changing to: `&i32` + | + = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` + error: variables in the condition are not mutated in the loop body --> $DIR/infinite_loop.rs:20:11 | @@ -91,5 +99,5 @@ LL | while y < 10 { = note: this loop contains `return`s or `break`s = help: rewrite it as `if cond { loop { } }` -error: aborting due to 11 previous errors +error: aborting due to 12 previous errors diff --git a/tests/ui/let_underscore_future.stderr b/tests/ui/let_underscore_future.stderr index 33a748736a88..9e69fb041330 100644 --- a/tests/ui/let_underscore_future.stderr +++ b/tests/ui/let_underscore_future.stderr @@ -1,3 +1,11 @@ +error: this argument is a mutable reference, but not used mutably + --> $DIR/let_underscore_future.rs:11:35 + | +LL | fn do_something_to_future(future: &mut impl Future) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&impl Future` + | + = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` + error: non-binding `let` on a future --> $DIR/let_underscore_future.rs:14:5 | @@ -23,5 +31,5 @@ LL | let _ = future; | = help: consider awaiting the future or dropping explicitly with `std::mem::drop` -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors diff --git a/tests/ui/must_use_candidates.fixed b/tests/ui/must_use_candidates.fixed index 0c275504d36b..3ca20c07d9ba 100644 --- a/tests/ui/must_use_candidates.fixed +++ b/tests/ui/must_use_candidates.fixed @@ -1,6 +1,11 @@ //@run-rustfix #![feature(never_type)] -#![allow(unused_mut, unused_tuple_struct_fields, clippy::redundant_allocation)] +#![allow( + unused_mut, + unused_tuple_struct_fields, + clippy::redundant_allocation, + clippy::needless_pass_by_ref_mut +)] #![warn(clippy::must_use_candidate)] use std::rc::Rc; use std::sync::atomic::{AtomicBool, Ordering}; diff --git a/tests/ui/must_use_candidates.rs b/tests/ui/must_use_candidates.rs index d1c9267732fa..dc4e0118ec72 100644 --- a/tests/ui/must_use_candidates.rs +++ b/tests/ui/must_use_candidates.rs @@ -1,6 +1,11 @@ //@run-rustfix #![feature(never_type)] -#![allow(unused_mut, unused_tuple_struct_fields, clippy::redundant_allocation)] +#![allow( + unused_mut, + unused_tuple_struct_fields, + clippy::redundant_allocation, + clippy::needless_pass_by_ref_mut +)] #![warn(clippy::must_use_candidate)] use std::rc::Rc; use std::sync::atomic::{AtomicBool, Ordering}; diff --git a/tests/ui/must_use_candidates.stderr b/tests/ui/must_use_candidates.stderr index 0fa3849d03bf..5fb302ccbf14 100644 --- a/tests/ui/must_use_candidates.stderr +++ b/tests/ui/must_use_candidates.stderr @@ -1,5 +1,5 @@ error: this function could have a `#[must_use]` attribute - --> $DIR/must_use_candidates.rs:12:1 + --> $DIR/must_use_candidates.rs:17:1 | LL | pub fn pure(i: u8) -> u8 { | ^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn pure(i: u8) -> u8` @@ -7,25 +7,25 @@ LL | pub fn pure(i: u8) -> u8 { = note: `-D clippy::must-use-candidate` implied by `-D warnings` error: this method could have a `#[must_use]` attribute - --> $DIR/must_use_candidates.rs:17:5 + --> $DIR/must_use_candidates.rs:22:5 | LL | pub fn inherent_pure(&self) -> u8 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn inherent_pure(&self) -> u8` error: this function could have a `#[must_use]` attribute - --> $DIR/must_use_candidates.rs:48:1 + --> $DIR/must_use_candidates.rs:53:1 | LL | pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool` error: this function could have a `#[must_use]` attribute - --> $DIR/must_use_candidates.rs:60:1 + --> $DIR/must_use_candidates.rs:65:1 | LL | pub fn rcd(_x: Rc) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn rcd(_x: Rc) -> bool` error: this function could have a `#[must_use]` attribute - --> $DIR/must_use_candidates.rs:68:1 + --> $DIR/must_use_candidates.rs:73:1 | LL | pub fn arcd(_x: Arc) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn arcd(_x: Arc) -> bool` diff --git a/tests/ui/mut_from_ref.rs b/tests/ui/mut_from_ref.rs index 7de153305947..8c0c23b65706 100644 --- a/tests/ui/mut_from_ref.rs +++ b/tests/ui/mut_from_ref.rs @@ -1,4 +1,4 @@ -#![allow(unused, clippy::needless_lifetimes)] +#![allow(unused, clippy::needless_lifetimes, clippy::needless_pass_by_ref_mut)] #![warn(clippy::mut_from_ref)] struct Foo; diff --git a/tests/ui/mut_key.stderr b/tests/ui/mut_key.stderr index 25dd029b16ee..fe1eeb31d07a 100644 --- a/tests/ui/mut_key.stderr +++ b/tests/ui/mut_key.stderr @@ -12,6 +12,14 @@ error: mutable key type LL | fn should_not_take_this_arg(m: &mut HashMap, _n: usize) -> HashSet { | ^^^^^^^^^^^^ +error: this argument is a mutable reference, but not used mutably + --> $DIR/mut_key.rs:30:32 + | +LL | fn should_not_take_this_arg(m: &mut HashMap, _n: usize) -> HashSet { + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&HashMap` + | + = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` + error: mutable key type --> $DIR/mut_key.rs:31:5 | @@ -102,5 +110,5 @@ error: mutable key type LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 17 previous errors +error: aborting due to 18 previous errors diff --git a/tests/ui/mut_mut.rs b/tests/ui/mut_mut.rs index b72134283677..fe7d53e8e999 100644 --- a/tests/ui/mut_mut.rs +++ b/tests/ui/mut_mut.rs @@ -1,7 +1,12 @@ //@aux-build:proc_macros.rs:proc-macro #![warn(clippy::mut_mut)] #![allow(unused)] -#![allow(clippy::no_effect, clippy::uninlined_format_args, clippy::unnecessary_operation)] +#![allow( + clippy::no_effect, + clippy::uninlined_format_args, + clippy::unnecessary_operation, + clippy::needless_pass_by_ref_mut +)] extern crate proc_macros; use proc_macros::{external, inline_macros}; diff --git a/tests/ui/mut_mut.stderr b/tests/ui/mut_mut.stderr index 93b857eb2074..58a1c4e683c9 100644 --- a/tests/ui/mut_mut.stderr +++ b/tests/ui/mut_mut.stderr @@ -1,5 +1,5 @@ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:9:11 + --> $DIR/mut_mut.rs:14:11 | LL | fn fun(x: &mut &mut u32) -> bool { | ^^^^^^^^^^^^^ @@ -7,13 +7,13 @@ LL | fn fun(x: &mut &mut u32) -> bool { = note: `-D clippy::mut-mut` implied by `-D warnings` error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:26:17 + --> $DIR/mut_mut.rs:31:17 | LL | let mut x = &mut &mut 1u32; | ^^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:41:25 + --> $DIR/mut_mut.rs:46:25 | LL | let mut z = inline!(&mut $(&mut 3u32)); | ^ @@ -21,37 +21,37 @@ LL | let mut z = inline!(&mut $(&mut 3u32)); = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: this expression mutably borrows a mutable reference. Consider reborrowing - --> $DIR/mut_mut.rs:28:21 + --> $DIR/mut_mut.rs:33:21 | LL | let mut y = &mut x; | ^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:32:32 + --> $DIR/mut_mut.rs:37:32 | LL | let y: &mut &mut u32 = &mut &mut 2; | ^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:32:16 + --> $DIR/mut_mut.rs:37:16 | LL | let y: &mut &mut u32 = &mut &mut 2; | ^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:37:37 + --> $DIR/mut_mut.rs:42:37 | LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2; | ^^^^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:37:16 + --> $DIR/mut_mut.rs:42:16 | LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2; | ^^^^^^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:37:21 + --> $DIR/mut_mut.rs:42:21 | LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2; | ^^^^^^^^^^^^^ diff --git a/tests/ui/mut_reference.stderr b/tests/ui/mut_reference.stderr index 062d30b262c1..23c812475c2a 100644 --- a/tests/ui/mut_reference.stderr +++ b/tests/ui/mut_reference.stderr @@ -1,3 +1,17 @@ +error: this argument is a mutable reference, but not used mutably + --> $DIR/mut_reference.rs:4:33 + | +LL | fn takes_a_mutable_reference(a: &mut i32) {} + | ^^^^^^^^ help: consider changing to: `&i32` + | + = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` + +error: this argument is a mutable reference, but not used mutably + --> $DIR/mut_reference.rs:11:44 + | +LL | fn takes_a_mutable_reference(&self, a: &mut i32) {} + | ^^^^^^^^ help: consider changing to: `&i32` + error: the function `takes_an_immutable_reference` doesn't need a mutable reference --> $DIR/mut_reference.rs:17:34 | @@ -18,5 +32,5 @@ error: the method `takes_an_immutable_reference` doesn't need a mutable referenc LL | my_struct.takes_an_immutable_reference(&mut 42); | ^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 5 previous errors diff --git a/tests/ui/ptr_arg.rs b/tests/ui/ptr_arg.rs index 709f74ee6aa2..13e993d247b2 100644 --- a/tests/ui/ptr_arg.rs +++ b/tests/ui/ptr_arg.rs @@ -3,7 +3,8 @@ unused, clippy::many_single_char_names, clippy::needless_lifetimes, - clippy::redundant_clone + clippy::redundant_clone, + clippy::needless_pass_by_ref_mut )] #![warn(clippy::ptr_arg)] diff --git a/tests/ui/ptr_arg.stderr b/tests/ui/ptr_arg.stderr index d663b070b9cf..0e9dd760f453 100644 --- a/tests/ui/ptr_arg.stderr +++ b/tests/ui/ptr_arg.stderr @@ -1,5 +1,5 @@ error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:13:14 + --> $DIR/ptr_arg.rs:14:14 | LL | fn do_vec(x: &Vec) { | ^^^^^^^^^ help: change this to: `&[i64]` @@ -7,43 +7,43 @@ LL | fn do_vec(x: &Vec) { = note: `-D clippy::ptr-arg` implied by `-D warnings` error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:17:18 + --> $DIR/ptr_arg.rs:18:18 | LL | fn do_vec_mut(x: &mut Vec) { | ^^^^^^^^^^^^^ help: change this to: `&mut [i64]` error: writing `&String` instead of `&str` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:21:14 + --> $DIR/ptr_arg.rs:22:14 | LL | fn do_str(x: &String) { | ^^^^^^^ help: change this to: `&str` error: writing `&mut String` instead of `&mut str` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:25:18 + --> $DIR/ptr_arg.rs:26:18 | LL | fn do_str_mut(x: &mut String) { | ^^^^^^^^^^^ help: change this to: `&mut str` error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:29:15 + --> $DIR/ptr_arg.rs:30:15 | LL | fn do_path(x: &PathBuf) { | ^^^^^^^^ help: change this to: `&Path` error: writing `&mut PathBuf` instead of `&mut Path` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:33:19 + --> $DIR/ptr_arg.rs:34:19 | LL | fn do_path_mut(x: &mut PathBuf) { | ^^^^^^^^^^^^ help: change this to: `&mut Path` error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:41:18 + --> $DIR/ptr_arg.rs:42:18 | LL | fn do_vec(x: &Vec); | ^^^^^^^^^ help: change this to: `&[i64]` error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:54:14 + --> $DIR/ptr_arg.rs:55:14 | LL | fn cloned(x: &Vec) -> Vec { | ^^^^^^^^ @@ -60,7 +60,7 @@ LL ~ x.to_owned() | error: writing `&String` instead of `&str` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:63:18 + --> $DIR/ptr_arg.rs:64:18 | LL | fn str_cloned(x: &String) -> String { | ^^^^^^^ @@ -76,7 +76,7 @@ LL ~ x.to_owned() | error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:71:19 + --> $DIR/ptr_arg.rs:72:19 | LL | fn path_cloned(x: &PathBuf) -> PathBuf { | ^^^^^^^^ @@ -92,7 +92,7 @@ LL ~ x.to_path_buf() | error: writing `&String` instead of `&str` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:79:44 + --> $DIR/ptr_arg.rs:80:44 | LL | fn false_positive_capacity(x: &Vec, y: &String) { | ^^^^^^^ @@ -106,19 +106,19 @@ LL ~ let c = y; | error: using a reference to `Cow` is not recommended - --> $DIR/ptr_arg.rs:93:25 + --> $DIR/ptr_arg.rs:94:25 | LL | fn test_cow_with_ref(c: &Cow<[i32]>) {} | ^^^^^^^^^^^ help: change this to: `&[i32]` error: writing `&String` instead of `&str` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:122:66 + --> $DIR/ptr_arg.rs:123:66 | LL | fn some_allowed(#[allow(clippy::ptr_arg)] _v: &Vec, _s: &String) {} | ^^^^^^^ help: change this to: `&str` error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:151:21 + --> $DIR/ptr_arg.rs:152:21 | LL | fn foo_vec(vec: &Vec) { | ^^^^^^^^ @@ -131,7 +131,7 @@ LL ~ let _ = vec.to_owned().clone(); | error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:156:23 + --> $DIR/ptr_arg.rs:157:23 | LL | fn foo_path(path: &PathBuf) { | ^^^^^^^^ @@ -144,7 +144,7 @@ LL ~ let _ = path.to_path_buf().clone(); | error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:161:21 + --> $DIR/ptr_arg.rs:162:21 | LL | fn foo_str(str: &PathBuf) { | ^^^^^^^^ @@ -157,43 +157,43 @@ LL ~ let _ = str.to_path_buf().clone(); | error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:167:29 + --> $DIR/ptr_arg.rs:168:29 | LL | fn mut_vec_slice_methods(v: &mut Vec) { | ^^^^^^^^^^^^^ help: change this to: `&mut [u32]` error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:229:17 + --> $DIR/ptr_arg.rs:230:17 | LL | fn dyn_trait(a: &mut Vec, b: &mut String, c: &mut PathBuf) { | ^^^^^^^^^^^^^ help: change this to: `&mut [u32]` error: writing `&mut String` instead of `&mut str` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:229:35 + --> $DIR/ptr_arg.rs:230:35 | LL | fn dyn_trait(a: &mut Vec, b: &mut String, c: &mut PathBuf) { | ^^^^^^^^^^^ help: change this to: `&mut str` error: writing `&mut PathBuf` instead of `&mut Path` involves a new object where a slice will do - --> $DIR/ptr_arg.rs:229:51 + --> $DIR/ptr_arg.rs:230:51 | LL | fn dyn_trait(a: &mut Vec, b: &mut String, c: &mut PathBuf) { | ^^^^^^^^^^^^ help: change this to: `&mut Path` error: using a reference to `Cow` is not recommended - --> $DIR/ptr_arg.rs:252:39 + --> $DIR/ptr_arg.rs:253:39 | LL | fn cow_elided_lifetime<'a>(input: &'a Cow) -> &'a str { | ^^^^^^^^^^^^ help: change this to: `&str` error: using a reference to `Cow` is not recommended - --> $DIR/ptr_arg.rs:257:36 + --> $DIR/ptr_arg.rs:258:36 | LL | fn cow_bad_ret_ty_1<'a>(input: &'a Cow<'a, str>) -> &'static str { | ^^^^^^^^^^^^^^^^ help: change this to: `&str` error: using a reference to `Cow` is not recommended - --> $DIR/ptr_arg.rs:260:40 + --> $DIR/ptr_arg.rs:261:40 | LL | fn cow_bad_ret_ty_2<'a, 'b>(input: &'a Cow<'a, str>) -> &'b str { | ^^^^^^^^^^^^^^^^ help: change this to: `&str` diff --git a/tests/ui/read_zero_byte_vec.rs b/tests/ui/read_zero_byte_vec.rs index 30807e0f8b92..c6025ef1f4da 100644 --- a/tests/ui/read_zero_byte_vec.rs +++ b/tests/ui/read_zero_byte_vec.rs @@ -1,5 +1,5 @@ #![warn(clippy::read_zero_byte_vec)] -#![allow(clippy::unused_io_amount)] +#![allow(clippy::unused_io_amount, clippy::needless_pass_by_ref_mut)] use std::fs::File; use std::io; use std::io::prelude::*; diff --git a/tests/ui/self_assignment.rs b/tests/ui/self_assignment.rs index ec3ae1209425..d6682cc63dcf 100644 --- a/tests/ui/self_assignment.rs +++ b/tests/ui/self_assignment.rs @@ -1,5 +1,5 @@ #![warn(clippy::self_assignment)] -#![allow(clippy::useless_vec)] +#![allow(clippy::useless_vec, clippy::needless_pass_by_ref_mut)] pub struct S<'a> { a: i32, diff --git a/tests/ui/should_impl_trait/method_list_2.stderr b/tests/ui/should_impl_trait/method_list_2.stderr index 10bfea68ff57..e47cb209b839 100644 --- a/tests/ui/should_impl_trait/method_list_2.stderr +++ b/tests/ui/should_impl_trait/method_list_2.stderr @@ -39,6 +39,14 @@ LL | | } | = help: consider implementing the trait `std::hash::Hash` or choosing a less ambiguous method name +error: this argument is a mutable reference, but not used mutably + --> $DIR/method_list_2.rs:38:31 + | +LL | pub fn hash(&self, state: &mut T) { + | ^^^^^^ help: consider changing to: `&T` + | + = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` + error: method `index` can be confused for the standard trait method `std::ops::Index::index` --> $DIR/method_list_2.rs:42:5 | @@ -149,5 +157,5 @@ LL | | } | = help: consider implementing the trait `std::ops::Sub` or choosing a less ambiguous method name -error: aborting due to 15 previous errors +error: aborting due to 16 previous errors diff --git a/tests/ui/slow_vector_initialization.stderr b/tests/ui/slow_vector_initialization.stderr index cb3ce3e95a7a..22376680a8e6 100644 --- a/tests/ui/slow_vector_initialization.stderr +++ b/tests/ui/slow_vector_initialization.stderr @@ -72,5 +72,13 @@ LL | vec1 = Vec::with_capacity(10); LL | vec1.resize(10, 0); | ^^^^^^^^^^^^^^^^^^ -error: aborting due to 9 previous errors +error: this argument is a mutable reference, but not used mutably + --> $DIR/slow_vector_initialization.rs:62:18 + | +LL | fn do_stuff(vec: &mut [u8]) {} + | ^^^^^^^^^ help: consider changing to: `&[u8]` + | + = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` + +error: aborting due to 10 previous errors diff --git a/tests/ui/trivially_copy_pass_by_ref.rs b/tests/ui/trivially_copy_pass_by_ref.rs index 486155831561..86f5cc937f44 100644 --- a/tests/ui/trivially_copy_pass_by_ref.rs +++ b/tests/ui/trivially_copy_pass_by_ref.rs @@ -5,7 +5,8 @@ clippy::disallowed_names, clippy::needless_lifetimes, clippy::redundant_field_names, - clippy::uninlined_format_args + clippy::uninlined_format_args, + clippy::needless_pass_by_ref_mut )] #[derive(Copy, Clone)] diff --git a/tests/ui/trivially_copy_pass_by_ref.stderr b/tests/ui/trivially_copy_pass_by_ref.stderr index 8c5cfa8a0f17..2af668537f5c 100644 --- a/tests/ui/trivially_copy_pass_by_ref.stderr +++ b/tests/ui/trivially_copy_pass_by_ref.stderr @@ -1,5 +1,5 @@ error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:51:11 + --> $DIR/trivially_copy_pass_by_ref.rs:52:11 | LL | fn bad(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` @@ -11,103 +11,103 @@ LL | #![deny(clippy::trivially_copy_pass_by_ref)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:51:20 + --> $DIR/trivially_copy_pass_by_ref.rs:52:20 | LL | fn bad(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:51:29 + --> $DIR/trivially_copy_pass_by_ref.rs:52:29 | LL | fn bad(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:58:12 + --> $DIR/trivially_copy_pass_by_ref.rs:59:12 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^^ help: consider passing by value instead: `self` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:58:22 + --> $DIR/trivially_copy_pass_by_ref.rs:59:22 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:58:31 + --> $DIR/trivially_copy_pass_by_ref.rs:59:31 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:58:40 + --> $DIR/trivially_copy_pass_by_ref.rs:59:40 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:60:16 + --> $DIR/trivially_copy_pass_by_ref.rs:61:16 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:60:25 + --> $DIR/trivially_copy_pass_by_ref.rs:61:25 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:60:34 + --> $DIR/trivially_copy_pass_by_ref.rs:61:34 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:62:35 + --> $DIR/trivially_copy_pass_by_ref.rs:63:35 | LL | fn bad_issue7518(self, other: &Self) {} | ^^^^^ help: consider passing by value instead: `Self` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:74:16 + --> $DIR/trivially_copy_pass_by_ref.rs:75:16 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:74:25 + --> $DIR/trivially_copy_pass_by_ref.rs:75:25 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:74:34 + --> $DIR/trivially_copy_pass_by_ref.rs:75:34 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:78:34 + --> $DIR/trivially_copy_pass_by_ref.rs:79:34 | LL | fn trait_method(&self, _foo: &Foo); | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:110:21 + --> $DIR/trivially_copy_pass_by_ref.rs:111:21 | LL | fn foo_never(x: &i32) { | ^^^^ help: consider passing by value instead: `i32` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:115:15 + --> $DIR/trivially_copy_pass_by_ref.rs:116:15 | LL | fn foo(x: &i32) { | ^^^^ help: consider passing by value instead: `i32` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:142:37 + --> $DIR/trivially_copy_pass_by_ref.rs:143:37 | LL | fn _unrelated_lifetimes<'a, 'b>(_x: &'a u32, y: &'b u32) -> &'b u32 { | ^^^^^^^ help: consider passing by value instead: `u32` diff --git a/tests/ui/unused_io_amount.rs b/tests/ui/unused_io_amount.rs index 8d3e094b7596..e9d1eeb31612 100644 --- a/tests/ui/unused_io_amount.rs +++ b/tests/ui/unused_io_amount.rs @@ -1,4 +1,4 @@ -#![allow(dead_code)] +#![allow(dead_code, clippy::needless_pass_by_ref_mut)] #![warn(clippy::unused_io_amount)] extern crate futures; diff --git a/tests/ui/useless_asref.fixed b/tests/ui/useless_asref.fixed index 490d36ae6d69..e42731f9bcf6 100644 --- a/tests/ui/useless_asref.fixed +++ b/tests/ui/useless_asref.fixed @@ -1,6 +1,10 @@ //@run-rustfix #![deny(clippy::useless_asref)] -#![allow(clippy::explicit_auto_deref, clippy::uninlined_format_args)] +#![allow( + clippy::explicit_auto_deref, + clippy::uninlined_format_args, + clippy::needless_pass_by_ref_mut +)] use std::fmt::Debug; diff --git a/tests/ui/useless_asref.rs b/tests/ui/useless_asref.rs index f2681af924da..50c9990bb045 100644 --- a/tests/ui/useless_asref.rs +++ b/tests/ui/useless_asref.rs @@ -1,6 +1,10 @@ //@run-rustfix #![deny(clippy::useless_asref)] -#![allow(clippy::explicit_auto_deref, clippy::uninlined_format_args)] +#![allow( + clippy::explicit_auto_deref, + clippy::uninlined_format_args, + clippy::needless_pass_by_ref_mut +)] use std::fmt::Debug; diff --git a/tests/ui/useless_asref.stderr b/tests/ui/useless_asref.stderr index 67ce8b64e0e3..b6515e4fe0ee 100644 --- a/tests/ui/useless_asref.stderr +++ b/tests/ui/useless_asref.stderr @@ -1,5 +1,5 @@ error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:43:18 + --> $DIR/useless_asref.rs:47:18 | LL | foo_rstr(rstr.as_ref()); | ^^^^^^^^^^^^^ help: try this: `rstr` @@ -11,61 +11,61 @@ LL | #![deny(clippy::useless_asref)] | ^^^^^^^^^^^^^^^^^^^^^ error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:45:20 + --> $DIR/useless_asref.rs:49:20 | LL | foo_rslice(rslice.as_ref()); | ^^^^^^^^^^^^^^^ help: try this: `rslice` error: this call to `as_mut` does nothing - --> $DIR/useless_asref.rs:49:21 + --> $DIR/useless_asref.rs:53:21 | LL | foo_mrslice(mrslice.as_mut()); | ^^^^^^^^^^^^^^^^ help: try this: `mrslice` error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:51:20 + --> $DIR/useless_asref.rs:55:20 | LL | foo_rslice(mrslice.as_ref()); | ^^^^^^^^^^^^^^^^ help: try this: `mrslice` error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:58:20 + --> $DIR/useless_asref.rs:62:20 | LL | foo_rslice(rrrrrslice.as_ref()); | ^^^^^^^^^^^^^^^^^^^ help: try this: `rrrrrslice` error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:60:18 + --> $DIR/useless_asref.rs:64:18 | LL | foo_rstr(rrrrrstr.as_ref()); | ^^^^^^^^^^^^^^^^^ help: try this: `rrrrrstr` error: this call to `as_mut` does nothing - --> $DIR/useless_asref.rs:65:21 + --> $DIR/useless_asref.rs:69:21 | LL | foo_mrslice(mrrrrrslice.as_mut()); | ^^^^^^^^^^^^^^^^^^^^ help: try this: `mrrrrrslice` error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:67:20 + --> $DIR/useless_asref.rs:71:20 | LL | foo_rslice(mrrrrrslice.as_ref()); | ^^^^^^^^^^^^^^^^^^^^ help: try this: `mrrrrrslice` error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:71:16 + --> $DIR/useless_asref.rs:75:16 | LL | foo_rrrrmr((&&&&MoreRef).as_ref()); | ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(&&&&MoreRef)` error: this call to `as_mut` does nothing - --> $DIR/useless_asref.rs:121:13 + --> $DIR/useless_asref.rs:125:13 | LL | foo_mrt(mrt.as_mut()); | ^^^^^^^^^^^^ help: try this: `mrt` error: this call to `as_ref` does nothing - --> $DIR/useless_asref.rs:123:12 + --> $DIR/useless_asref.rs:127:12 | LL | foo_rt(mrt.as_ref()); | ^^^^^^^^^^^^ help: try this: `mrt` From dd3e00f102aa9773c10a645db37c3a10967f31cb Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 15 Jun 2023 20:53:08 +0200 Subject: [PATCH 147/324] Fix warnings of `needless_pass_by_ref_mut` in clippy --- clippy_lints/src/literal_representation.rs | 4 ++-- clippy_lints/src/non_expressive_names.rs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index dadcd9c5135c..09ca0317337c 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -264,7 +264,7 @@ impl LiteralDigitGrouping { return; } - if Self::is_literal_uuid_formatted(&mut num_lit) { + if Self::is_literal_uuid_formatted(&num_lit) { return; } @@ -376,7 +376,7 @@ impl LiteralDigitGrouping { /// /// Returns `true` if the radix is hexadecimal, and the groups match the /// UUID format of 8-4-4-4-12. - fn is_literal_uuid_formatted(num_lit: &mut NumericLiteral<'_>) -> bool { + fn is_literal_uuid_formatted(num_lit: &NumericLiteral<'_>) -> bool { if num_lit.radix != Radix::Hexadecimal { return false; } diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index 9f6917c146f6..d562047cbf15 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -91,7 +91,7 @@ struct ExistingName { struct SimilarNamesLocalVisitor<'a, 'tcx> { names: Vec, cx: &'a EarlyContext<'tcx>, - lint: &'a NonExpressiveNames, + lint: NonExpressiveNames, /// A stack of scopes containing the single-character bindings in each scope. single_char_names: Vec>, @@ -365,7 +365,7 @@ impl EarlyLintPass for NonExpressiveNames { .. }) = item.kind { - do_check(self, cx, &item.attrs, &sig.decl, blk); + do_check(*self, cx, &item.attrs, &sig.decl, blk); } } @@ -380,12 +380,12 @@ impl EarlyLintPass for NonExpressiveNames { .. }) = item.kind { - do_check(self, cx, &item.attrs, &sig.decl, blk); + do_check(*self, cx, &item.attrs, &sig.decl, blk); } } } -fn do_check(lint: &mut NonExpressiveNames, cx: &EarlyContext<'_>, attrs: &[Attribute], decl: &FnDecl, blk: &Block) { +fn do_check(lint: NonExpressiveNames, cx: &EarlyContext<'_>, attrs: &[Attribute], decl: &FnDecl, blk: &Block) { if !attrs.iter().any(|attr| attr.has_name(sym::test)) { let mut visitor = SimilarNamesLocalVisitor { names: Vec::new(), From 33adfcd327880f45fce08660c1bd70f83ce09f84 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 3 Jul 2023 22:48:40 +0200 Subject: [PATCH 148/324] Add warning for `NEEDLESS_PASS_BY_REF_MUT` lint about the fact that it changes API --- clippy_lints/src/needless_pass_by_ref_mut.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/clippy_lints/src/needless_pass_by_ref_mut.rs b/clippy_lints/src/needless_pass_by_ref_mut.rs index c5dc87cdfa88..d535963a1dc4 100644 --- a/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -22,6 +22,9 @@ declare_clippy_lint! { /// ### What it does /// Check if a `&mut` function argument is actually used mutably. /// + /// Be careful if the function is publically reexported as it would break compatibility with + /// users of this function. + /// /// ### Why is this bad? /// Less `mut` means less fights with the borrow checker. It can also lead to more /// opportunities for parallelization. From 8fad54e8f942e545458c7f339f0444513c5fcb1e Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Sat, 17 Jun 2023 01:41:11 +0200 Subject: [PATCH 149/324] new lint: `read_line_without_trim` --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/methods/mod.rs | 34 +++++++++ .../src/methods/read_line_without_trim.rs | 74 +++++++++++++++++++ tests/ui/read_line_without_trim.fixed | 19 +++++ tests/ui/read_line_without_trim.rs | 19 +++++ tests/ui/read_line_without_trim.stderr | 31 ++++++++ 7 files changed, 179 insertions(+) create mode 100644 clippy_lints/src/methods/read_line_without_trim.rs create mode 100644 tests/ui/read_line_without_trim.fixed create mode 100644 tests/ui/read_line_without_trim.rs create mode 100644 tests/ui/read_line_without_trim.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index f9310b4ab31f..e2004c2931d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5134,6 +5134,7 @@ Released 2018-09-13 [`rc_buffer`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_buffer [`rc_clone_in_vec_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_clone_in_vec_init [`rc_mutex`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex +[`read_line_without_trim`]: https://rust-lang.github.io/rust-clippy/master/index.html#read_line_without_trim [`read_zero_byte_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#read_zero_byte_vec [`recursive_format_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#recursive_format_impl [`redundant_allocation`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index e1dbe5003965..ca97db040792 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -389,6 +389,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::OR_THEN_UNWRAP_INFO, crate::methods::PATH_BUF_PUSH_OVERWRITE_INFO, crate::methods::RANGE_ZIP_WITH_LEN_INFO, + crate::methods::READ_LINE_WITHOUT_TRIM_INFO, crate::methods::REPEAT_ONCE_INFO, crate::methods::RESULT_MAP_OR_INTO_OPTION_INFO, crate::methods::SEARCH_IS_SOME_INFO, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index ab97cf0e53dc..c99f7c1fdd9f 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -72,6 +72,7 @@ mod or_fun_call; mod or_then_unwrap; mod path_buf_push_overwrite; mod range_zip_with_len; +mod read_line_without_trim; mod repeat_once; mod search_is_some; mod seek_from_current; @@ -3348,6 +3349,35 @@ declare_clippy_lint! { "checks for usage of `Iterator::fold` with a type that implements `Try`" } +declare_clippy_lint! { + /// Looks for calls to [`Stdin::read_line`] to read a line from the standard input + /// into a string, then later attempting to parse this string into a type without first trimming it, which will + /// always fail because the string has a trailing newline in it. + /// + /// ### Why is this bad? + /// The `.parse()` call will always fail. + /// + /// ### Example + /// ```rust,ignore + /// let mut input = String::new(); + /// std::io::stdin().read_line(&mut input).expect("Failed to read a line"); + /// let num: i32 = input.parse().expect("Not a number!"); + /// assert_eq!(num, 42); // we never even get here! + /// ``` + /// Use instead: + /// ```rust,ignore + /// let mut input = String::new(); + /// std::io::stdin().read_line(&mut input).expect("Failed to read a line"); + /// let num: i32 = input.trim_end().parse().expect("Not a number!"); + /// // ^^^^^^^^^^^ remove the trailing newline + /// assert_eq!(num, 42); + /// ``` + #[clippy::version = "1.72.0"] + pub READ_LINE_WITHOUT_TRIM, + correctness, + "calling `Stdin::read_line`, then trying to parse it without first trimming" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -3468,6 +3498,7 @@ impl_lint_pass!(Methods => [ REPEAT_ONCE, STABLE_SORT_PRIMITIVE, UNIT_HASH, + READ_LINE_WITHOUT_TRIM, UNNECESSARY_SORT_BY, VEC_RESIZE_TO_ZERO, VERBOSE_FILE_READS, @@ -3879,6 +3910,9 @@ impl Methods { ("read_to_string", [_]) => { verbose_file_reads::check(cx, expr, recv, verbose_file_reads::READ_TO_STRING_MSG); }, + ("read_line", [arg]) => { + read_line_without_trim::check(cx, expr, recv, arg); + } ("repeat", [arg]) => { repeat_once::check(cx, expr, recv, arg); }, diff --git a/clippy_lints/src/methods/read_line_without_trim.rs b/clippy_lints/src/methods/read_line_without_trim.rs new file mode 100644 index 000000000000..49e4f1acaa6f --- /dev/null +++ b/clippy_lints/src/methods/read_line_without_trim.rs @@ -0,0 +1,74 @@ +use std::ops::ControlFlow; + +use clippy_utils::{ + diagnostics::span_lint_and_then, get_parent_expr, match_def_path, source::snippet, ty::is_type_diagnostic_item, + visitors::for_each_local_use_after_expr, +}; +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_hir::QPath; +use rustc_hir::{def::Res, ExprKind}; +use rustc_lint::LateContext; +use rustc_middle::ty::{self, Ty}; +use rustc_span::sym; + +use super::READ_LINE_WITHOUT_TRIM; + +/// Will a `.parse::()` call fail if the input has a trailing newline? +fn parse_fails_on_trailing_newline(ty: Ty<'_>) -> bool { + // only allow a very limited set of types for now, for which we 100% know parsing will fail + matches!(ty.kind(), ty::Float(_) | ty::Bool | ty::Int(_) | ty::Uint(_)) +} + +pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) { + if let Some(recv_adt) = cx.typeck_results().expr_ty(recv).ty_adt_def() + && match_def_path(cx, recv_adt.did(), &["std", "io", "stdio", "Stdin"]) + && let ExprKind::Path(QPath::Resolved(_, path)) = arg.peel_borrows().kind + && let Res::Local(local_id) = path.res + { + // We've checked that `call` is a call to `Stdin::read_line()` with the right receiver, + // now let's check if the first use of the string passed to `::read_line()` is + // parsed into a type that will always fail if it has a trailing newline. + for_each_local_use_after_expr(cx, local_id, call.hir_id, |expr| { + if let Some(parent) = get_parent_expr(cx, expr) + && let ExprKind::MethodCall(segment, .., span) = parent.kind + && segment.ident.name == sym!(parse) + && let parse_result_ty = cx.typeck_results().expr_ty(parent) + && is_type_diagnostic_item(cx, parse_result_ty, sym::Result) + && let ty::Adt(_, substs) = parse_result_ty.kind() + && let Some(ok_ty) = substs[0].as_type() + && parse_fails_on_trailing_newline(ok_ty) + { + let local_snippet = snippet(cx, expr.span, ""); + span_lint_and_then( + cx, + READ_LINE_WITHOUT_TRIM, + span, + "calling `.parse()` without trimming the trailing newline character", + |diag| { + diag.span_note(call.span, "call to `.read_line()` here, \ + which leaves a trailing newline character in the buffer, \ + which in turn will cause `.parse()` to fail"); + + diag.span_suggestion( + expr.span, + "try", + format!("{local_snippet}.trim_end()"), + Applicability::MachineApplicable, + ); + } + ); + } + + // only consider the first use to prevent this scenario: + // ``` + // let mut s = String::new(); + // std::io::stdin().read_line(&mut s); + // s.pop(); + // let _x: i32 = s.parse().unwrap(); + // ``` + // this is actually fine, because the pop call removes the trailing newline. + ControlFlow::<(), ()>::Break(()) + }); + } +} diff --git a/tests/ui/read_line_without_trim.fixed b/tests/ui/read_line_without_trim.fixed new file mode 100644 index 000000000000..5995c8f523e2 --- /dev/null +++ b/tests/ui/read_line_without_trim.fixed @@ -0,0 +1,19 @@ +//@run-rustfix + +#![allow(unused)] +#![warn(clippy::read_line_without_trim)] + +fn main() { + let mut input = String::new(); + std::io::stdin().read_line(&mut input).unwrap(); + input.pop(); + let _x: i32 = input.parse().unwrap(); // don't trigger here, newline character is popped + + let mut input = String::new(); + std::io::stdin().read_line(&mut input).unwrap(); + let _x: i32 = input.trim_end().parse().unwrap(); + + let mut input = String::new(); + std::io::stdin().read_line(&mut input).unwrap(); + let _x = input.trim_end().parse::().unwrap(); +} diff --git a/tests/ui/read_line_without_trim.rs b/tests/ui/read_line_without_trim.rs new file mode 100644 index 000000000000..84527b624b68 --- /dev/null +++ b/tests/ui/read_line_without_trim.rs @@ -0,0 +1,19 @@ +//@run-rustfix + +#![allow(unused)] +#![warn(clippy::read_line_without_trim)] + +fn main() { + let mut input = String::new(); + std::io::stdin().read_line(&mut input).unwrap(); + input.pop(); + let _x: i32 = input.parse().unwrap(); // don't trigger here, newline character is popped + + let mut input = String::new(); + std::io::stdin().read_line(&mut input).unwrap(); + let _x: i32 = input.parse().unwrap(); + + let mut input = String::new(); + std::io::stdin().read_line(&mut input).unwrap(); + let _x = input.parse::().unwrap(); +} diff --git a/tests/ui/read_line_without_trim.stderr b/tests/ui/read_line_without_trim.stderr new file mode 100644 index 000000000000..f0f7a61e9ffa --- /dev/null +++ b/tests/ui/read_line_without_trim.stderr @@ -0,0 +1,31 @@ +error: calling `.parse()` without trimming the trailing newline character + --> $DIR/read_line_without_trim.rs:14:25 + | +LL | let _x: i32 = input.parse().unwrap(); + | ----- ^^^^^^^ + | | + | help: try: `input.trim_end()` + | +note: call to `.read_line()` here, which leaves a trailing newline character in the buffer, which in turn will cause `.parse()` to fail + --> $DIR/read_line_without_trim.rs:13:5 + | +LL | std::io::stdin().read_line(&mut input).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `-D clippy::read-line-without-trim` implied by `-D warnings` + +error: calling `.parse()` without trimming the trailing newline character + --> $DIR/read_line_without_trim.rs:18:20 + | +LL | let _x = input.parse::().unwrap(); + | ----- ^^^^^^^^^^^^^^ + | | + | help: try: `input.trim_end()` + | +note: call to `.read_line()` here, which leaves a trailing newline character in the buffer, which in turn will cause `.parse()` to fail + --> $DIR/read_line_without_trim.rs:17:5 + | +LL | std::io::stdin().read_line(&mut input).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + From 85f535b25f58a58de561216aa4e8378ad0b56391 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Mon, 3 Jul 2023 22:50:41 +0200 Subject: [PATCH 150/324] add test cases for u32, f32, bool, String --- tests/ui/read_line_without_trim.fixed | 17 ++++++++++ tests/ui/read_line_without_trim.rs | 17 ++++++++++ tests/ui/read_line_without_trim.stderr | 44 +++++++++++++++++++++++++- 3 files changed, 77 insertions(+), 1 deletion(-) diff --git a/tests/ui/read_line_without_trim.fixed b/tests/ui/read_line_without_trim.fixed index 5995c8f523e2..cb6aab84e49a 100644 --- a/tests/ui/read_line_without_trim.fixed +++ b/tests/ui/read_line_without_trim.fixed @@ -16,4 +16,21 @@ fn main() { let mut input = String::new(); std::io::stdin().read_line(&mut input).unwrap(); let _x = input.trim_end().parse::().unwrap(); + + let mut input = String::new(); + std::io::stdin().read_line(&mut input).unwrap(); + let _x = input.trim_end().parse::().unwrap(); + + let mut input = String::new(); + std::io::stdin().read_line(&mut input).unwrap(); + let _x = input.trim_end().parse::().unwrap(); + + let mut input = String::new(); + std::io::stdin().read_line(&mut input).unwrap(); + let _x = input.trim_end().parse::().unwrap(); + + let mut input = String::new(); + std::io::stdin().read_line(&mut input).unwrap(); + // this is actually ok, so don't lint here + let _x = input.parse::().unwrap(); } diff --git a/tests/ui/read_line_without_trim.rs b/tests/ui/read_line_without_trim.rs index 84527b624b68..bdc409a70106 100644 --- a/tests/ui/read_line_without_trim.rs +++ b/tests/ui/read_line_without_trim.rs @@ -16,4 +16,21 @@ fn main() { let mut input = String::new(); std::io::stdin().read_line(&mut input).unwrap(); let _x = input.parse::().unwrap(); + + let mut input = String::new(); + std::io::stdin().read_line(&mut input).unwrap(); + let _x = input.parse::().unwrap(); + + let mut input = String::new(); + std::io::stdin().read_line(&mut input).unwrap(); + let _x = input.parse::().unwrap(); + + let mut input = String::new(); + std::io::stdin().read_line(&mut input).unwrap(); + let _x = input.parse::().unwrap(); + + let mut input = String::new(); + std::io::stdin().read_line(&mut input).unwrap(); + // this is actually ok, so don't lint here + let _x = input.parse::().unwrap(); } diff --git a/tests/ui/read_line_without_trim.stderr b/tests/ui/read_line_without_trim.stderr index f0f7a61e9ffa..f3d7b60425fb 100644 --- a/tests/ui/read_line_without_trim.stderr +++ b/tests/ui/read_line_without_trim.stderr @@ -27,5 +27,47 @@ note: call to `.read_line()` here, which leaves a trailing newline character in LL | std::io::stdin().read_line(&mut input).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: calling `.parse()` without trimming the trailing newline character + --> $DIR/read_line_without_trim.rs:22:20 + | +LL | let _x = input.parse::().unwrap(); + | ----- ^^^^^^^^^^^^^^ + | | + | help: try: `input.trim_end()` + | +note: call to `.read_line()` here, which leaves a trailing newline character in the buffer, which in turn will cause `.parse()` to fail + --> $DIR/read_line_without_trim.rs:21:5 + | +LL | std::io::stdin().read_line(&mut input).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: calling `.parse()` without trimming the trailing newline character + --> $DIR/read_line_without_trim.rs:26:20 + | +LL | let _x = input.parse::().unwrap(); + | ----- ^^^^^^^^^^^^^^ + | | + | help: try: `input.trim_end()` + | +note: call to `.read_line()` here, which leaves a trailing newline character in the buffer, which in turn will cause `.parse()` to fail + --> $DIR/read_line_without_trim.rs:25:5 + | +LL | std::io::stdin().read_line(&mut input).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: calling `.parse()` without trimming the trailing newline character + --> $DIR/read_line_without_trim.rs:30:20 + | +LL | let _x = input.parse::().unwrap(); + | ----- ^^^^^^^^^^^^^^^ + | | + | help: try: `input.trim_end()` + | +note: call to `.read_line()` here, which leaves a trailing newline character in the buffer, which in turn will cause `.parse()` to fail + --> $DIR/read_line_without_trim.rs:29:5 + | +LL | std::io::stdin().read_line(&mut input).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors From fed3c8cd28a42988a8379a3e61694dc7fa7a9e6a Mon Sep 17 00:00:00 2001 From: Cyborus04 <87248184+Cyborus04@users.noreply.github.com> Date: Mon, 3 Jul 2023 17:09:42 -0400 Subject: [PATCH 151/324] fix type braces --- tests/debuginfo/thread.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/debuginfo/thread.rs b/tests/debuginfo/thread.rs index d888ad00f967..0f7d69650348 100644 --- a/tests/debuginfo/thread.rs +++ b/tests/debuginfo/thread.rs @@ -14,7 +14,7 @@ // // cdb-command:dx t,d // cdb-check:t,d : [...] [Type: std::thread::Thread *] -// cdb-check:[...] inner [...][Type: core::pin::Pin,alloc::alloc::Global>] +// cdb-check:[...] inner [...][Type: core::pin::Pin>] use std::thread; From 8886d707b84e3623211b82841f7539b570479d4f Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 4 Jul 2023 09:16:15 +0200 Subject: [PATCH 152/324] Stronger typing for AstId and AstIdMap --- crates/hir-def/src/data.rs | 2 +- crates/hir-def/src/data/adt.rs | 10 +-- crates/hir-def/src/item_tree.rs | 4 +- crates/hir-def/src/lib.rs | 6 +- crates/hir-def/src/lower.rs | 8 ++- crates/hir-def/src/nameres/collector.rs | 2 +- crates/hir-def/src/nameres/diagnostics.rs | 11 ++-- crates/hir-expand/src/ast_id_map.rs | 79 +++++++++++++++++------ crates/hir-expand/src/lib.rs | 28 +++++--- crates/hir/src/lib.rs | 2 +- 10 files changed, 102 insertions(+), 50 deletions(-) diff --git a/crates/hir-def/src/data.rs b/crates/hir-def/src/data.rs index 4a9f08dca6d0..54fe9a2e8440 100644 --- a/crates/hir-def/src/data.rs +++ b/crates/hir-def/src/data.rs @@ -599,7 +599,7 @@ impl<'a> AssocItemCollector<'a> { if !attrs.is_cfg_enabled(self.expander.cfg_options()) { self.diagnostics.push(DefDiagnostic::unconfigured_code( self.module_id.local_id, - InFile::new(self.expander.current_file_id(), item.ast_id(item_tree).upcast()), + InFile::new(self.expander.current_file_id(), item.ast_id(item_tree).erase()), attrs.cfg().unwrap(), self.expander.cfg_options().clone(), )); diff --git a/crates/hir-def/src/data/adt.rs b/crates/hir-def/src/data/adt.rs index 612a5ca1a283..595b9b770b7d 100644 --- a/crates/hir-def/src/data/adt.rs +++ b/crates/hir-def/src/data/adt.rs @@ -330,7 +330,7 @@ impl EnumData { } else { diagnostics.push(DefDiagnostic::unconfigured_code( loc.container.local_id, - InFile::new(loc.id.file_id(), var.ast_id.upcast()), + InFile::new(loc.id.file_id(), var.ast_id.erase()), attrs.cfg().unwrap(), cfg_options.clone(), )) @@ -540,8 +540,8 @@ fn lower_fields( InFile::new( current_file_id, match field.ast_id { - FieldAstId::Record(it) => it.upcast(), - FieldAstId::Tuple(it) => it.upcast(), + FieldAstId::Record(it) => it.erase(), + FieldAstId::Tuple(it) => it.erase(), }, ), attrs.cfg().unwrap(), @@ -564,8 +564,8 @@ fn lower_fields( InFile::new( current_file_id, match field.ast_id { - FieldAstId::Record(it) => it.upcast(), - FieldAstId::Tuple(it) => it.upcast(), + FieldAstId::Record(it) => it.erase(), + FieldAstId::Tuple(it) => it.erase(), }, ), attrs.cfg().unwrap(), diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs index e74b71888c2b..6f80bb6e07ce 100644 --- a/crates/hir-def/src/item_tree.rs +++ b/crates/hir-def/src/item_tree.rs @@ -46,7 +46,7 @@ use ast::{AstNode, HasName, StructKind}; use base_db::CrateId; use either::Either; use hir_expand::{ - ast_id_map::FileAstId, + ast_id_map::{AstIdNode, FileAstId}, attrs::RawAttrs, hygiene::Hygiene, name::{name, AsName, Name}, @@ -314,7 +314,7 @@ from_attrs!(ModItem(ModItem), Variant(Idx), Field(Idx), Param(Id /// Trait implemented by all item nodes in the item tree. pub trait ItemTreeNode: Clone { - type Source: AstNode + Into; + type Source: AstIdNode + Into; fn ast_id(&self) -> FileAstId; diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index e5149ab577c8..c0701e2576a1 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -64,7 +64,7 @@ use std::{ use base_db::{impl_intern_key, salsa, CrateId, ProcMacroKind}; use hir_expand::{ - ast_id_map::FileAstId, + ast_id_map::{AstIdNode, FileAstId}, attrs::{Attr, AttrId, AttrInput}, builtin_attr_macro::BuiltinAttrExpander, builtin_derive_macro::BuiltinDeriveExpander, @@ -1124,12 +1124,12 @@ impl AsMacroCall for InFile<&ast::MacroCall> { /// Helper wrapper for `AstId` with `ModPath` #[derive(Clone, Debug, Eq, PartialEq)] -struct AstIdWithPath { +struct AstIdWithPath { ast_id: AstId, path: path::ModPath, } -impl AstIdWithPath { +impl AstIdWithPath { fn new(file_id: HirFileId, ast_id: FileAstId, path: path::ModPath) -> AstIdWithPath { AstIdWithPath { ast_id: AstId::new(file_id, ast_id), path } } diff --git a/crates/hir-def/src/lower.rs b/crates/hir-def/src/lower.rs index af623fd0e5d4..e523c229179b 100644 --- a/crates/hir-def/src/lower.rs +++ b/crates/hir-def/src/lower.rs @@ -1,5 +1,9 @@ //! Context for lowering paths. -use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, AstId, HirFileId, InFile}; +use hir_expand::{ + ast_id_map::{AstIdMap, AstIdNode}, + hygiene::Hygiene, + AstId, HirFileId, InFile, +}; use once_cell::unsync::OnceCell; use syntax::ast; use triomphe::Arc; @@ -37,7 +41,7 @@ impl<'a> LowerCtx<'a> { Path::from_src(ast, self) } - pub(crate) fn ast_id(&self, item: &N) -> Option> { + pub(crate) fn ast_id(&self, item: &N) -> Option> { let &(file_id, ref ast_id_map) = self.ast_id_map.as_ref()?; let ast_id_map = ast_id_map.get_or_init(|| self.db.ast_id_map(file_id)); Some(InFile::new(file_id, ast_id_map.ast_id(item))) diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index a5cdee9628db..c048716d7403 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -2280,7 +2280,7 @@ impl ModCollector<'_, '_> { fn emit_unconfigured_diagnostic(&mut self, item: ModItem, cfg: &CfgExpr) { let ast_id = item.ast_id(self.item_tree); - let ast_id = InFile::new(self.file_id(), ast_id.upcast()); + let ast_id = InFile::new(self.file_id(), ast_id.erase()); self.def_collector.def_map.diagnostics.push(DefDiagnostic::unconfigured_code( self.module_id, ast_id, diff --git a/crates/hir-def/src/nameres/diagnostics.rs b/crates/hir-def/src/nameres/diagnostics.rs index 18b424255cd6..e82e97b628e9 100644 --- a/crates/hir-def/src/nameres/diagnostics.rs +++ b/crates/hir-def/src/nameres/diagnostics.rs @@ -2,12 +2,9 @@ use base_db::CrateId; use cfg::{CfgExpr, CfgOptions}; -use hir_expand::{attrs::AttrId, MacroCallKind}; +use hir_expand::{attrs::AttrId, ErasedAstId, MacroCallKind}; use la_arena::Idx; -use syntax::{ - ast::{self, AnyHasAttrs}, - SyntaxError, -}; +use syntax::{ast, SyntaxError}; use crate::{ item_tree::{self, ItemTreeId}, @@ -24,7 +21,7 @@ pub enum DefDiagnosticKind { UnresolvedImport { id: ItemTreeId, index: Idx }, - UnconfiguredCode { ast: AstId, cfg: CfgExpr, opts: CfgOptions }, + UnconfiguredCode { ast: ErasedAstId, cfg: CfgExpr, opts: CfgOptions }, UnresolvedProcMacro { ast: MacroCallKind, krate: CrateId }, @@ -81,7 +78,7 @@ impl DefDiagnostic { pub fn unconfigured_code( container: LocalModuleId, - ast: AstId, + ast: ErasedAstId, cfg: CfgExpr, opts: CfgOptions, ) -> Self { diff --git a/crates/hir-expand/src/ast_id_map.rs b/crates/hir-expand/src/ast_id_map.rs index c2b0d5985e3c..1906ed15baec 100644 --- a/crates/hir-expand/src/ast_id_map.rs +++ b/crates/hir-expand/src/ast_id_map.rs @@ -18,47 +18,89 @@ use rustc_hash::FxHasher; use syntax::{ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr}; /// `AstId` points to an AST node in a specific file. -pub struct FileAstId { +pub struct FileAstId { raw: ErasedFileAstId, covariant: PhantomData N>, } -impl Clone for FileAstId { +impl Clone for FileAstId { fn clone(&self) -> FileAstId { *self } } -impl Copy for FileAstId {} +impl Copy for FileAstId {} -impl PartialEq for FileAstId { +impl PartialEq for FileAstId { fn eq(&self, other: &Self) -> bool { self.raw == other.raw } } -impl Eq for FileAstId {} -impl Hash for FileAstId { +impl Eq for FileAstId {} +impl Hash for FileAstId { fn hash(&self, hasher: &mut H) { self.raw.hash(hasher); } } -impl fmt::Debug for FileAstId { +impl fmt::Debug for FileAstId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "FileAstId::<{}>({})", type_name::(), self.raw.into_raw()) } } -impl FileAstId { +impl FileAstId { // Can't make this a From implementation because of coherence - pub fn upcast(self) -> FileAstId + pub fn upcast(self) -> FileAstId where N: Into, { FileAstId { raw: self.raw, covariant: PhantomData } } + + pub fn erase(self) -> ErasedFileAstId { + self.raw + } } -type ErasedFileAstId = Idx; +pub type ErasedFileAstId = Idx; + +pub trait AstIdNode: AstNode {} +macro_rules! register_ast_id_node { + (impl AstIdNode for $($ident:ident),+ ) => { + $( + impl AstIdNode for ast::$ident {} + )+ + fn should_alloc_id(kind: syntax::SyntaxKind) -> bool { + $( + ast::$ident::can_cast(kind) + )||+ + } + }; +} +register_ast_id_node! { + impl AstIdNode for + Item, + Adt, + Enum, + Struct, + Union, + Const, + ExternBlock, + ExternCrate, + Fn, + Impl, + Macro, + MacroDef, + MacroRules, + MacroCall, + Module, + Static, + Trait, + TraitAlias, + TypeAlias, + Use, + AssocItem, BlockExpr, Variant, RecordField, TupleField, ConstArg +} /// Maps items' `SyntaxNode`s to `ErasedFileAstId`s and back. #[derive(Default)] @@ -92,14 +134,7 @@ impl AstIdMap { // change parent's id. This means that, say, adding a new function to a // trait does not change ids of top-level items, which helps caching. bdfs(node, |it| { - let kind = it.kind(); - if ast::Item::can_cast(kind) - || ast::BlockExpr::can_cast(kind) - || ast::Variant::can_cast(kind) - || ast::RecordField::can_cast(kind) - || ast::TupleField::can_cast(kind) - || ast::ConstArg::can_cast(kind) - { + if should_alloc_id(it.kind()) { res.alloc(&it); true } else { @@ -120,15 +155,19 @@ impl AstIdMap { res } - pub fn ast_id(&self, item: &N) -> FileAstId { + pub fn ast_id(&self, item: &N) -> FileAstId { let raw = self.erased_ast_id(item.syntax()); FileAstId { raw, covariant: PhantomData } } - pub fn get(&self, id: FileAstId) -> AstPtr { + pub fn get(&self, id: FileAstId) -> AstPtr { AstPtr::try_from_raw(self.arena[id.raw].clone()).unwrap() } + pub(crate) fn get_raw(&self, id: ErasedFileAstId) -> SyntaxNodePtr { + self.arena[id].clone() + } + fn erased_ast_id(&self, item: &SyntaxNode) -> ErasedFileAstId { let ptr = SyntaxNodePtr::new(item); let hash = hash_ptr(&ptr); diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs index b0dc8e1b5c98..3a534f56e4f8 100644 --- a/crates/hir-expand/src/lib.rs +++ b/crates/hir-expand/src/lib.rs @@ -37,11 +37,11 @@ use either::Either; use syntax::{ algo::{self, skip_trivia_token}, ast::{self, AstNode, HasDocComments}, - Direction, SyntaxNode, SyntaxToken, + AstPtr, Direction, SyntaxNode, SyntaxNodePtr, SyntaxToken, }; use crate::{ - ast_id_map::FileAstId, + ast_id_map::{AstIdNode, ErasedFileAstId, FileAstId}, attrs::AttrId, builtin_attr_macro::BuiltinAttrExpander, builtin_derive_macro::BuiltinDeriveExpander, @@ -551,9 +551,9 @@ impl MacroCallKind { }; let range = match kind { - MacroCallKind::FnLike { ast_id, .. } => ast_id.to_node(db).syntax().text_range(), - MacroCallKind::Derive { ast_id, .. } => ast_id.to_node(db).syntax().text_range(), - MacroCallKind::Attr { ast_id, .. } => ast_id.to_node(db).syntax().text_range(), + MacroCallKind::FnLike { ast_id, .. } => ast_id.to_ptr(db).text_range(), + MacroCallKind::Derive { ast_id, .. } => ast_id.to_ptr(db).text_range(), + MacroCallKind::Attr { ast_id, .. } => ast_id.to_ptr(db).text_range(), }; FileRange { range, file_id } @@ -801,13 +801,25 @@ impl ExpansionInfo { /// It is stable across reparses, and can be used as salsa key/value. pub type AstId = InFile>; -impl AstId { +impl AstId { pub fn to_node(&self, db: &dyn db::ExpandDatabase) -> N { - let root = db.parse_or_expand(self.file_id); - db.ast_id_map(self.file_id).get(self.value).to_node(&root) + self.to_ptr(db).to_node(&db.parse_or_expand(self.file_id)) + } + pub fn to_ptr(&self, db: &dyn db::ExpandDatabase) -> AstPtr { + db.ast_id_map(self.file_id).get(self.value) } } +pub type ErasedAstId = InFile; + +impl ErasedAstId { + pub fn to_node(&self, db: &dyn db::ExpandDatabase) -> SyntaxNode { + self.to_ptr(db).to_node(&db.parse_or_expand(self.file_id)) + } + pub fn to_ptr(&self, db: &dyn db::ExpandDatabase) -> SyntaxNodePtr { + db.ast_id_map(self.file_id).get_raw(self.value) + } +} /// `InFile` stores a value of `T` inside a particular file/syntax tree. /// /// Typical usages are: diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 645ea42f538d..3688fd0e837d 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -754,7 +754,7 @@ fn emit_def_diagnostic_( let item = ast.to_node(db.upcast()); acc.push( InactiveCode { - node: ast.with_value(AstPtr::new(&item).into()), + node: ast.with_value(SyntaxNodePtr::new(&item).into()), cfg: cfg.clone(), opts: opts.clone(), } From 7b36a7335101712df2196abdcbafa14b6934b113 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 4 Jul 2023 10:38:23 +0200 Subject: [PATCH 153/324] internal: Remove CfgExpander --- crates/hir-def/src/data/adt.rs | 120 +++++++++++++++++++++++---------- crates/hir-def/src/expander.rs | 57 +++++----------- 2 files changed, 100 insertions(+), 77 deletions(-) diff --git a/crates/hir-def/src/data/adt.rs b/crates/hir-def/src/data/adt.rs index 595b9b770b7d..c8df3f3f96a5 100644 --- a/crates/hir-def/src/data/adt.rs +++ b/crates/hir-def/src/data/adt.rs @@ -18,7 +18,6 @@ use triomphe::Arc; use crate::{ builtin_type::{BuiltinInt, BuiltinUint}, db::DefDatabase, - expander::CfgExpander, item_tree::{AttrOwner, Field, FieldAstId, Fields, ItemTree, ModItem, RawVisibilityId}, lang_item::LangItem, lower::LowerCtx, @@ -29,8 +28,8 @@ use crate::{ tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree}, type_ref::TypeRef, visibility::RawVisibility, - EnumId, LocalEnumVariantId, LocalFieldId, LocalModuleId, Lookup, ModuleId, StructId, UnionId, - VariantId, + EnumId, EnumLoc, LocalEnumVariantId, LocalFieldId, LocalModuleId, Lookup, ModuleId, StructId, + UnionId, VariantId, }; /// Note that we use `StructData` for unions as well! @@ -76,6 +75,7 @@ pub struct EnumData { pub struct EnumVariantData { pub name: Name, pub variant_data: Arc, + pub tree_id: la_arena::Idx, } #[derive(Debug, Clone, PartialEq, Eq)] @@ -326,6 +326,7 @@ impl EnumData { variants.alloc(EnumVariantData { name: var.name.clone(), variant_data: Arc::new(var_data), + tree_id, }); } else { diagnostics.push(DefDiagnostic::unconfigured_code( @@ -368,9 +369,10 @@ impl HasChildSource for EnumId { &self, db: &dyn DefDatabase, ) -> InFile> { - let src = self.lookup(db).source(db); + let loc = &self.lookup(db); + let src = loc.source(db); let mut trace = Trace::new_for_map(); - lower_enum(db, &mut trace, &src, self.lookup(db).container); + lower_enum(db, &mut trace, &src, loc); src.with_value(trace.into_map()) } } @@ -379,31 +381,58 @@ fn lower_enum( db: &dyn DefDatabase, trace: &mut Trace, ast: &InFile, - module_id: ModuleId, + loc: &EnumLoc, ) { - let expander = CfgExpander::new(db, ast.file_id, module_id.krate); + let item_tree = loc.id.item_tree(db); + let krate = loc.container.krate; + + let item_tree_variants = item_tree[loc.id.value].variants.clone(); + + let cfg_options = &db.crate_graph()[krate].cfg_options; let variants = ast .value .variant_list() .into_iter() .flat_map(|it| it.variants()) - .filter(|var| expander.is_cfg_enabled(db, var)); - for var in variants { + .zip(item_tree_variants) + .filter(|&(_, item_tree_id)| { + item_tree.attrs(db, krate, item_tree_id.into()).is_cfg_enabled(cfg_options) + }); + for (var, item_tree_id) in variants { trace.alloc( || var.clone(), || EnumVariantData { name: var.name().map_or_else(Name::missing, |it| it.as_name()), - variant_data: Arc::new(VariantData::new(db, ast.with_value(var.kind()), module_id)), + variant_data: Arc::new(VariantData::new( + db, + ast.with_value(var.kind()), + loc.container, + &item_tree, + item_tree_id, + )), + tree_id: item_tree_id, }, ); } } impl VariantData { - fn new(db: &dyn DefDatabase, flavor: InFile, module_id: ModuleId) -> Self { - let mut expander = CfgExpander::new(db, flavor.file_id, module_id.krate); + fn new( + db: &dyn DefDatabase, + flavor: InFile, + module_id: ModuleId, + item_tree: &ItemTree, + variant: la_arena::Idx, + ) -> Self { let mut trace = Trace::new_for_arena(); - match lower_struct(db, &mut expander, &mut trace, &flavor) { + match lower_struct( + db, + &mut trace, + &flavor, + module_id.krate, + item_tree, + &item_tree[variant].fields, + ) { StructKind::Tuple => VariantData::Tuple(trace.into_arena()), StructKind::Record => VariantData::Record(trace.into_arena()), StructKind::Unit => VariantData::Unit, @@ -435,28 +464,43 @@ impl HasChildSource for VariantId { type Value = Either; fn child_source(&self, db: &dyn DefDatabase) -> InFile> { - let (src, module_id) = match self { + let item_tree; + let (src, fields, container) = match *self { VariantId::EnumVariantId(it) => { // I don't really like the fact that we call into parent source // here, this might add to more queries then necessary. + let lookup = it.parent.lookup(db); + item_tree = lookup.id.item_tree(db); let src = it.parent.child_source(db); - (src.map(|map| map[it.local_id].kind()), it.parent.lookup(db).container) + let tree_id = db.enum_data(it.parent).variants[it.local_id].tree_id; + let fields = &item_tree[tree_id].fields; + (src.map(|map| map[it.local_id].kind()), fields, lookup.container) } VariantId::StructId(it) => { - (it.lookup(db).source(db).map(|it| it.kind()), it.lookup(db).container) + let lookup = it.lookup(db); + item_tree = lookup.id.item_tree(db); + ( + lookup.source(db).map(|it| it.kind()), + &item_tree[lookup.id.value].fields, + lookup.container, + ) + } + VariantId::UnionId(it) => { + let lookup = it.lookup(db); + item_tree = lookup.id.item_tree(db); + ( + lookup.source(db).map(|it| { + it.record_field_list() + .map(ast::StructKind::Record) + .unwrap_or(ast::StructKind::Unit) + }), + &item_tree[lookup.id.value].fields, + lookup.container, + ) } - VariantId::UnionId(it) => ( - it.lookup(db).source(db).map(|it| { - it.record_field_list() - .map(ast::StructKind::Record) - .unwrap_or(ast::StructKind::Unit) - }), - it.lookup(db).container, - ), }; - let mut expander = CfgExpander::new(db, src.file_id, module_id.krate); let mut trace = Trace::new_for_map(); - lower_struct(db, &mut expander, &mut trace, &src); + lower_struct(db, &mut trace, &src, container.krate, &item_tree, fields); src.with_value(trace.into_map()) } } @@ -470,16 +514,19 @@ pub enum StructKind { fn lower_struct( db: &dyn DefDatabase, - expander: &mut CfgExpander, trace: &mut Trace>, ast: &InFile, + krate: CrateId, + item_tree: &ItemTree, + fields: &Fields, ) -> StructKind { - let ctx = LowerCtx::new(db, &expander.hygiene(), ast.file_id); + let ctx = LowerCtx::with_file_id(db, ast.file_id); - match &ast.value { - ast::StructKind::Tuple(fl) => { - for (i, fd) in fl.fields().enumerate() { - if !expander.is_cfg_enabled(db, &fd) { + match (&ast.value, fields) { + (ast::StructKind::Tuple(fl), Fields::Tuple(fields)) => { + let cfg_options = &db.crate_graph()[krate].cfg_options; + for ((i, fd), item_tree_id) in fl.fields().enumerate().zip(fields.clone()) { + if !item_tree.attrs(db, krate, item_tree_id.into()).is_cfg_enabled(cfg_options) { continue; } @@ -494,9 +541,10 @@ fn lower_struct( } StructKind::Tuple } - ast::StructKind::Record(fl) => { - for fd in fl.fields() { - if !expander.is_cfg_enabled(db, &fd) { + (ast::StructKind::Record(fl), Fields::Record(fields)) => { + let cfg_options = &db.crate_graph()[krate].cfg_options; + for (fd, item_tree_id) in fl.fields().zip(fields.clone()) { + if !item_tree.attrs(db, krate, item_tree_id.into()).is_cfg_enabled(cfg_options) { continue; } @@ -511,7 +559,7 @@ fn lower_struct( } StructKind::Record } - ast::StructKind::Unit => StructKind::Unit, + _ => StructKind::Unit, } } diff --git a/crates/hir-def/src/expander.rs b/crates/hir-def/src/expander.rs index a588827c8d39..cc85bd893ac4 100644 --- a/crates/hir-def/src/expander.rs +++ b/crates/hir-def/src/expander.rs @@ -15,18 +15,11 @@ use crate::{ MacroId, ModuleId, }; -/// A subset of Expander that only deals with cfg attributes. We only need it to -/// avoid cyclic queries in crate def map during enum processing. #[derive(Debug)] -pub(crate) struct CfgExpander { +pub struct Expander { cfg_options: CfgOptions, hygiene: Hygiene, krate: CrateId, -} - -#[derive(Debug)] -pub struct Expander { - cfg_expander: CfgExpander, pub(crate) current_file_id: HirFileId, pub(crate) module: ModuleId, /// `recursion_depth == usize::MAX` indicates that the recursion limit has been reached. @@ -34,41 +27,23 @@ pub struct Expander { recursion_limit: Limit, } -impl CfgExpander { - pub(crate) fn new( - db: &dyn DefDatabase, - current_file_id: HirFileId, - krate: CrateId, - ) -> CfgExpander { - let hygiene = Hygiene::new(db.upcast(), current_file_id); - let cfg_options = db.crate_graph()[krate].cfg_options.clone(); - CfgExpander { cfg_options, hygiene, krate } - } - - pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> Attrs { - Attrs::filter(db, self.krate, RawAttrs::new(db.upcast(), owner, &self.hygiene)) - } - - pub(crate) fn is_cfg_enabled(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> bool { - let attrs = self.parse_attrs(db, owner); - attrs.is_cfg_enabled(&self.cfg_options) - } - - pub(crate) fn hygiene(&self) -> &Hygiene { - &self.hygiene - } -} - impl Expander { pub fn new(db: &dyn DefDatabase, current_file_id: HirFileId, module: ModuleId) -> Expander { - let cfg_expander = CfgExpander::new(db, current_file_id, module.krate); let recursion_limit = db.recursion_limit(module.krate); #[cfg(not(test))] let recursion_limit = Limit::new(recursion_limit as usize); // Without this, `body::tests::your_stack_belongs_to_me` stack-overflows in debug #[cfg(test)] let recursion_limit = Limit::new(std::cmp::min(32, recursion_limit as usize)); - Expander { cfg_expander, current_file_id, module, recursion_depth: 0, recursion_limit } + Expander { + current_file_id, + module, + recursion_depth: 0, + recursion_limit, + cfg_options: db.crate_graph()[module.krate].cfg_options.clone(), + hygiene: Hygiene::new(db.upcast(), current_file_id), + krate: module.krate, + } } pub fn enter_expand( @@ -120,7 +95,7 @@ impl Expander { } pub fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) { - self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id); + self.hygiene = Hygiene::new(db.upcast(), mark.file_id); self.current_file_id = mark.file_id; if self.recursion_depth == u32::MAX { // Recursion limit has been reached somewhere in the macro expansion tree. Reset the @@ -135,7 +110,7 @@ impl Expander { } pub fn ctx<'a>(&self, db: &'a dyn DefDatabase) -> LowerCtx<'a> { - LowerCtx::new(db, &self.cfg_expander.hygiene, self.current_file_id) + LowerCtx::new(db, &self.hygiene, self.current_file_id) } pub(crate) fn to_source(&self, value: T) -> InFile { @@ -143,11 +118,11 @@ impl Expander { } pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> Attrs { - self.cfg_expander.parse_attrs(db, owner) + Attrs::filter(db, self.krate, RawAttrs::new(db.upcast(), owner, &self.hygiene)) } pub(crate) fn cfg_options(&self) -> &CfgOptions { - &self.cfg_expander.cfg_options + &self.cfg_options } pub fn current_file_id(&self) -> HirFileId { @@ -155,7 +130,7 @@ impl Expander { } pub(crate) fn parse_path(&mut self, db: &dyn DefDatabase, path: ast::Path) -> Option { - let ctx = LowerCtx::new(db, &self.cfg_expander.hygiene, self.current_file_id); + let ctx = LowerCtx::new(db, &self.hygiene, self.current_file_id); Path::from_src(path, &ctx) } @@ -194,7 +169,7 @@ impl Expander { let parse = value.cast::()?; self.recursion_depth += 1; - self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id); + self.hygiene = Hygiene::new(db.upcast(), file_id); let old_file_id = std::mem::replace(&mut self.current_file_id, file_id); let mark = Mark { file_id: old_file_id, bomb: DropBomb::new("expansion mark dropped") }; From 9fd5f8c6702656f76054622294cba438a8b29fe5 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Tue, 4 Jul 2023 18:58:19 +0900 Subject: [PATCH 154/324] Support GATs in bounds for associated types --- crates/hir-ty/src/chalk_db.rs | 26 ++++++++++++++++---------- crates/hir-ty/src/tests/traits.rs | 24 ++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/crates/hir-ty/src/chalk_db.rs b/crates/hir-ty/src/chalk_db.rs index ff80d4cf9d59..0038b0d18365 100644 --- a/crates/hir-ty/src/chalk_db.rs +++ b/crates/hir-ty/src/chalk_db.rs @@ -5,7 +5,7 @@ use std::{iter, sync::Arc}; use tracing::debug; -use chalk_ir::{cast::Cast, fold::shift::Shift, CanonicalVarKinds}; +use chalk_ir::{cast::Caster, fold::shift::Shift, CanonicalVarKinds}; use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait}; use base_db::CrateId; @@ -846,28 +846,34 @@ pub(super) fn generic_predicate_to_inline_bound( } let args_no_self = trait_ref.substitution.as_slice(Interner)[1..] .iter() - .map(|ty| ty.clone().cast(Interner)) + .cloned() + .casted(Interner) .collect(); let trait_bound = rust_ir::TraitBound { trait_id: trait_ref.trait_id, args_no_self }; Some(chalk_ir::Binders::new(binders, rust_ir::InlineBound::TraitBound(trait_bound))) } WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => { - let trait_ = projection_ty.trait_(db); - if projection_ty.self_type_parameter(db) != self_ty_shifted_in { + let generics = + generics(db.upcast(), from_assoc_type_id(projection_ty.associated_ty_id).into()); + let (assoc_args, trait_args) = + projection_ty.substitution.as_slice(Interner).split_at(generics.len_self()); + let (self_ty, args_no_self) = + trait_args.split_first().expect("projection without trait self type"); + if self_ty.assert_ty_ref(Interner) != &self_ty_shifted_in { return None; } - let args_no_self = projection_ty.substitution.as_slice(Interner)[1..] - .iter() - .map(|ty| ty.clone().cast(Interner)) - .collect(); + + let args_no_self = args_no_self.iter().cloned().casted(Interner).collect(); + let parameters = assoc_args.to_vec(); + let alias_eq_bound = rust_ir::AliasEqBound { value: ty.clone(), trait_bound: rust_ir::TraitBound { - trait_id: to_chalk_trait_id(trait_), + trait_id: to_chalk_trait_id(projection_ty.trait_(db)), args_no_self, }, associated_ty_id: projection_ty.associated_ty_id, - parameters: Vec::new(), // FIXME we don't support generic associated types yet + parameters, }; Some(chalk_ir::Binders::new( binders, diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs index 97ae732a9046..5f5cd794512c 100644 --- a/crates/hir-ty/src/tests/traits.rs +++ b/crates/hir-ty/src/tests/traits.rs @@ -4148,6 +4148,30 @@ where ); } +#[test] +fn gats_in_bounds_for_assoc() { + check_types( + r#" +trait Trait { + type Assoc: Another = usize>; + type Assoc2: Another = T>; +} +trait Another { + type Gat; + fn foo(&self) -> Self::Gat; + fn bar(&self) -> Self::Gat; +} + +fn test(a: T::Assoc, b: T::Assoc2) { + let v = a.foo(); + //^ usize + let v = b.bar::(); + //^ isize +} +"#, + ); +} + #[test] fn bin_op_with_scalar_fallback() { // Extra impls are significant so that chalk doesn't give us definite guidances. From 49b039f1d1591757e7fbd77243c23154691c38a9 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Tue, 4 Jul 2023 20:34:55 +0900 Subject: [PATCH 155/324] Recover from missing associated items and generic const defaults --- crates/parser/src/grammar/generic_args.rs | 19 +++++++- crates/parser/src/grammar/generic_params.rs | 3 +- ...cover_from_missing_assoc_item_binding.rast | 48 +++++++++++++++++++ ...recover_from_missing_assoc_item_binding.rs | 1 + ...22_recover_from_missing_const_default.rast | 44 +++++++++++++++++ ...0022_recover_from_missing_const_default.rs | 1 + 6 files changed, 113 insertions(+), 3 deletions(-) create mode 100644 crates/parser/test_data/parser/inline/err/0021_recover_from_missing_assoc_item_binding.rast create mode 100644 crates/parser/test_data/parser/inline/err/0021_recover_from_missing_assoc_item_binding.rs create mode 100644 crates/parser/test_data/parser/inline/err/0022_recover_from_missing_const_default.rast create mode 100644 crates/parser/test_data/parser/inline/err/0022_recover_from_missing_const_default.rs diff --git a/crates/parser/src/grammar/generic_args.rs b/crates/parser/src/grammar/generic_args.rs index e589b69934d2..211af98e6ef0 100644 --- a/crates/parser/src/grammar/generic_args.rs +++ b/crates/parser/src/grammar/generic_args.rs @@ -32,6 +32,9 @@ const GENERIC_ARG_FIRST: TokenSet = TokenSet::new(&[ ]) .union(types::TYPE_FIRST); +// Despite its name, it can also be used for generic param list. +const GENERIC_ARG_RECOVERY_SET: TokenSet = TokenSet::new(&[T![>], T![,]]); + // test generic_arg // type T = S; fn generic_arg(p: &mut Parser<'_>) -> bool { @@ -55,6 +58,15 @@ fn generic_arg(p: &mut Parser<'_>) -> bool { // test assoc_type_eq // type T = StreamingIterator = &'a T>; types::type_(p); + } else if p.at_ts(GENERIC_ARG_RECOVERY_SET) { + // Although `const_arg()` recovers as expected, we want to + // handle those here to give the following message because + // we don't know whether this associated item is a type or + // const at this point. + + // test_err recover_from_missing_assoc_item_binding + // fn f() -> impl Iterator {} + p.error("missing associated item binding"); } else { // test assoc_const_eq // fn foo>() {} @@ -141,12 +153,17 @@ pub(super) fn const_arg_expr(p: &mut Parser<'_>) { expressions::literal(p); lm.complete(p, PREFIX_EXPR); } - _ => { + _ if paths::is_use_path_start(p) => { // This shouldn't be hit by `const_arg` let lm = p.start(); paths::use_path(p); lm.complete(p, PATH_EXPR); } + _ => { + // test_err recover_from_missing_const_default + // struct A; + p.err_recover("expected a generic const argument", GENERIC_ARG_RECOVERY_SET); + } } } diff --git a/crates/parser/src/grammar/generic_params.rs b/crates/parser/src/grammar/generic_params.rs index 7fcf938babdb..8ed1c84c4c64 100644 --- a/crates/parser/src/grammar/generic_params.rs +++ b/crates/parser/src/grammar/generic_params.rs @@ -79,10 +79,9 @@ fn const_param(p: &mut Parser<'_>, m: Marker) { p.error("missing type for const parameter"); } - if p.at(T![=]) { + if p.eat(T![=]) { // test const_param_default_literal // struct A; - p.bump(T![=]); // test const_param_default_expression // struct A; diff --git a/crates/parser/test_data/parser/inline/err/0021_recover_from_missing_assoc_item_binding.rast b/crates/parser/test_data/parser/inline/err/0021_recover_from_missing_assoc_item_binding.rast new file mode 100644 index 000000000000..fc59db84e77d --- /dev/null +++ b/crates/parser/test_data/parser/inline/err/0021_recover_from_missing_assoc_item_binding.rast @@ -0,0 +1,48 @@ +SOURCE_FILE + FN + FN_KW "fn" + WHITESPACE " " + NAME + IDENT "f" + PARAM_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + RET_TYPE + THIN_ARROW "->" + WHITESPACE " " + IMPL_TRAIT_TYPE + IMPL_KW "impl" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Iterator" + GENERIC_ARG_LIST + L_ANGLE "<" + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + WHITESPACE " " + EQ "=" + WHITESPACE " " + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + WHITESPACE " " + EQ "=" + WHITESPACE " " + R_ANGLE ">" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + R_CURLY "}" + WHITESPACE "\n" +error 30: missing associated item binding +error 39: missing associated item binding diff --git a/crates/parser/test_data/parser/inline/err/0021_recover_from_missing_assoc_item_binding.rs b/crates/parser/test_data/parser/inline/err/0021_recover_from_missing_assoc_item_binding.rs new file mode 100644 index 000000000000..e484e433a09f --- /dev/null +++ b/crates/parser/test_data/parser/inline/err/0021_recover_from_missing_assoc_item_binding.rs @@ -0,0 +1 @@ +fn f() -> impl Iterator {} diff --git a/crates/parser/test_data/parser/inline/err/0022_recover_from_missing_const_default.rast b/crates/parser/test_data/parser/inline/err/0022_recover_from_missing_const_default.rast new file mode 100644 index 000000000000..809ad1b8d5b9 --- /dev/null +++ b/crates/parser/test_data/parser/inline/err/0022_recover_from_missing_const_default.rast @@ -0,0 +1,44 @@ +SOURCE_FILE + STRUCT + STRUCT_KW "struct" + WHITESPACE " " + NAME + IDENT "A" + GENERIC_PARAM_LIST + L_ANGLE "<" + CONST_PARAM + CONST_KW "const" + WHITESPACE " " + NAME + IDENT "N" + COLON ":" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + WHITESPACE " " + EQ "=" + WHITESPACE " " + COMMA "," + WHITESPACE " " + CONST_PARAM + CONST_KW "const" + WHITESPACE " " + NAME + IDENT "M" + COLON ":" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + WHITESPACE " " + EQ "=" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" +error 23: expected a generic const argument +error 40: expected a generic const argument diff --git a/crates/parser/test_data/parser/inline/err/0022_recover_from_missing_const_default.rs b/crates/parser/test_data/parser/inline/err/0022_recover_from_missing_const_default.rs new file mode 100644 index 000000000000..5bab13da92b6 --- /dev/null +++ b/crates/parser/test_data/parser/inline/err/0022_recover_from_missing_const_default.rs @@ -0,0 +1 @@ +struct A; From 03423116ad533e1e80d7095595429e7cb0af2af7 Mon Sep 17 00:00:00 2001 From: Ali Bektas Date: Tue, 4 Jul 2023 17:13:07 +0200 Subject: [PATCH 156/324] Generate trait from impl v2 --- .../src/handlers/generate_trait_from_impl.rs | 108 +++++++++++++----- crates/syntax/src/ast/make.rs | 2 +- 2 files changed, 79 insertions(+), 31 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_trait_from_impl.rs b/crates/ide-assists/src/handlers/generate_trait_from_impl.rs index ce9eeb820074..d3192ae40914 100644 --- a/crates/ide-assists/src/handlers/generate_trait_from_impl.rs +++ b/crates/ide-assists/src/handlers/generate_trait_from_impl.rs @@ -1,8 +1,8 @@ use crate::assist_context::{AssistContext, Assists}; -use ide_db::{assists::AssistId, SnippetCap}; +use ide_db::assists::AssistId; use syntax::{ - ast::{self, HasGenericParams, HasVisibility}, - AstNode, + ast::{self, edit::IndentLevel, make, HasGenericParams, HasVisibility}, + ted, AstNode, SyntaxKind, }; // NOTES : @@ -68,6 +68,16 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_ // Get AST Node let impl_ast = ctx.find_node_at_offset::()?; + // Check if cursor is to the left of assoc item list's L_CURLY. + // if no L_CURLY then return. + let l_curly = impl_ast.assoc_item_list()?.l_curly_token()?; + + let cursor_offset = ctx.offset(); + let l_curly_offset = l_curly.text_range(); + if cursor_offset >= l_curly_offset.start() { + return None; + } + // If impl is not inherent then we don't really need to go any further. if impl_ast.for_token().is_some() { return None; @@ -80,9 +90,11 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_ return None; } + let impl_name = impl_ast.self_ty()?; + acc.add( AssistId("generate_trait_from_impl", ide_db::assists::AssistKind::Generate), - "Generate trait from impl".to_owned(), + "Generate trait from impl", impl_ast.syntax().text_range(), |builder| { let trait_items = assoc_items.clone_for_update(); @@ -93,45 +105,43 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_ remove_items_visibility(&item); }); - syntax::ted::replace(assoc_items.clone_for_update().syntax(), impl_items.syntax()); + ted::replace(assoc_items.clone_for_update().syntax(), impl_items.syntax()); impl_items.assoc_items().for_each(|item| { remove_items_visibility(&item); }); - let trait_ast = ast::make::trait_( + let trait_ast = make::trait_( false, - "NewTrait".to_string(), - HasGenericParams::generic_param_list(&impl_ast), - HasGenericParams::where_clause(&impl_ast), + "NewTrait", + impl_ast.generic_param_list(), + impl_ast.where_clause(), trait_items, ); // Change `impl Foo` to `impl NewTrait for Foo` - // First find the PATH_TYPE which is what Foo is. - let impl_name = impl_ast.self_ty().unwrap(); - let trait_name = if let Some(genpars) = impl_ast.generic_param_list() { - format!("NewTrait{}", genpars.to_generic_args()) + let arg_list = if let Some(genpars) = impl_ast.generic_param_list() { + genpars.to_generic_args().to_string() } else { - format!("NewTrait") + "".to_string() }; // // Then replace builder.replace( - impl_name.clone().syntax().text_range(), - format!("{} for {}", trait_name, impl_name.to_string()), + impl_name.syntax().text_range(), + format!("NewTrait{} for {}", arg_list, impl_name.to_string()), ); - builder.replace( - impl_ast.assoc_item_list().unwrap().syntax().text_range(), - impl_items.to_string(), - ); + builder.replace(assoc_items.syntax().text_range(), impl_items.to_string()); // Insert trait before TraitImpl - builder.insert_snippet( - SnippetCap::new(true).unwrap(), + builder.insert( impl_ast.syntax().text_range().start(), - format!("{}\n\n", trait_ast.to_string()), + format!( + "{}\n\n{}", + trait_ast.to_string(), + IndentLevel::from_node(impl_ast.syntax()) + ), ); }, ); @@ -144,17 +154,17 @@ fn remove_items_visibility(item: &ast::AssocItem) { match item { ast::AssocItem::Const(c) => { if let Some(vis) = c.visibility() { - syntax::ted::remove(vis.syntax()); + ted::remove(vis.syntax()); } } ast::AssocItem::Fn(f) => { if let Some(vis) = f.visibility() { - syntax::ted::remove(vis.syntax()); + ted::remove(vis.syntax()); } } ast::AssocItem::TypeAlias(t) => { if let Some(vis) = t.visibility() { - syntax::ted::remove(vis.syntax()); + ted::remove(vis.syntax()); } } _ => (), @@ -168,12 +178,12 @@ fn strip_body(item: &ast::AssocItem) { // In constrast to function bodies, we want to see no ws before a semicolon. // So let's remove them if we see any. if let Some(prev) = body.syntax().prev_sibling_or_token() { - if prev.kind() == syntax::SyntaxKind::WHITESPACE { - syntax::ted::remove(prev); + if prev.kind() == SyntaxKind::WHITESPACE { + ted::remove(prev); } } - syntax::ted::replace(body.syntax(), ast::make::tokens::semicolon()); + ted::replace(body.syntax(), ast::make::tokens::semicolon()); } } _ => (), @@ -185,6 +195,21 @@ mod tests { use super::*; use crate::tests::{check_assist, check_assist_not_applicable}; + #[test] + fn test_trigger_when_cursor_on_header() { + check_assist_not_applicable( + generate_trait_from_impl, + r#" +struct Foo(f64); + +impl Foo { $0 + fn add(&mut self, x: f64) { + self.0 += x; + } +}"#, + ); + } + #[test] fn test_assoc_item_fn() { check_assist( @@ -299,7 +324,7 @@ impl NewTrait for Foo { } #[test] - fn test_e0449_avoided() { + fn test_trait_items_should_not_have_vis() { check_assist( generate_trait_from_impl, r#" @@ -334,4 +359,27 @@ impl Emp$0tyImpl{} "#, ) } + + #[test] + fn test_not_top_level_impl() { + check_assist( + generate_trait_from_impl, + r#" +mod a { + impl S$0 { + fn foo() {} + } +}"#, + r#" +mod a { + trait NewTrait { + fn foo(); + } + + impl NewTrait for S { + fn foo() {} + } +}"#, + ) + } } diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index 1675d1af1dd2..3facd90a11d9 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs @@ -865,7 +865,7 @@ pub fn param_list( pub fn trait_( is_unsafe: bool, - ident: String, + ident: &str, gen_params: Option, where_clause: Option, assoc_items: ast::AssocItemList, From bb35d8fa8ef9de3c8282602b411c40b266dc3a4e Mon Sep 17 00:00:00 2001 From: Tetsuharu Ohzeki Date: Wed, 28 Jun 2023 04:15:01 +0900 Subject: [PATCH 157/324] editor/code: Set ts' --moduleResolution=node16 option https://www.typescriptlang.org/tsconfig#moduleResolution By this change, typescript compiler can read `exports` field in package.json for dependencies. https://nodejs.org/api/packages.html#exports-sugar --- editors/code/tsconfig.json | 1 + 1 file changed, 1 insertion(+) diff --git a/editors/code/tsconfig.json b/editors/code/tsconfig.json index 04bd4569377c..3f887a41b3d7 100644 --- a/editors/code/tsconfig.json +++ b/editors/code/tsconfig.json @@ -3,6 +3,7 @@ "compilerOptions": { "esModuleInterop": false, "module": "commonjs", + "moduleResolution": "node16", "target": "es2021", "outDir": "out", "lib": ["es2021"], From f048f73251309075c558f078538682c2e52b01a3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 4 Jul 2023 20:35:23 +0200 Subject: [PATCH 158/324] Add warning about semver compatibility if it's a public function --- clippy_lints/src/lib.rs | 6 +- clippy_lints/src/needless_pass_by_ref_mut.rs | 61 ++++++++++++++----- .../ui/should_impl_trait/method_list_2.stderr | 1 + 3 files changed, 53 insertions(+), 15 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index e1e4a83b031b..040ed1a8619a 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1058,7 +1058,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: let stack_size_threshold = conf.stack_size_threshold; store.register_late_pass(move |_| Box::new(large_stack_frames::LargeStackFrames::new(stack_size_threshold))); store.register_late_pass(|_| Box::new(single_range_in_vec_init::SingleRangeInVecInit)); - store.register_late_pass(|_| Box::new(needless_pass_by_ref_mut::NeedlessPassByRefMut)); + store.register_late_pass(move |_| { + Box::new(needless_pass_by_ref_mut::NeedlessPassByRefMut::new( + avoid_breaking_exported_api, + )) + }); store.register_late_pass(|_| Box::new(incorrect_impls::IncorrectImpls)); store.register_late_pass(move |_| { Box::new(single_call_fn::SingleCallFn { diff --git a/clippy_lints/src/needless_pass_by_ref_mut.rs b/clippy_lints/src/needless_pass_by_ref_mut.rs index d535963a1dc4..96cb09c071ac 100644 --- a/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -1,5 +1,5 @@ use super::needless_pass_by_value::requires_exact_signature; -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::snippet; use clippy_utils::{is_from_proc_macro, is_self}; use if_chain::if_chain; @@ -12,7 +12,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{self, Ty}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::kw; use rustc_span::Span; @@ -46,7 +46,21 @@ declare_clippy_lint! { suspicious, "using a `&mut` argument when it's not mutated" } -declare_lint_pass!(NeedlessPassByRefMut => [NEEDLESS_PASS_BY_REF_MUT]); + +#[derive(Copy, Clone)] +pub struct NeedlessPassByRefMut { + avoid_breaking_exported_api: bool, +} + +impl NeedlessPassByRefMut { + pub fn new(avoid_breaking_exported_api: bool) -> Self { + Self { + avoid_breaking_exported_api, + } + } +} + +impl_lint_pass!(NeedlessPassByRefMut => [NEEDLESS_PASS_BY_REF_MUT]); fn should_skip<'tcx>( cx: &LateContext<'tcx>, @@ -134,26 +148,45 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut { ctx }; - for ((&input, &ty), arg) in decl.inputs.iter().zip(fn_sig.inputs()).zip(body.params) { - if should_skip(cx, input, ty, arg) { - continue; - } - + let mut it = decl + .inputs + .iter() + .zip(fn_sig.inputs()) + .zip(body.params) + .filter(|((&input, &ty), arg)| !should_skip(cx, input, ty, arg)) + .peekable(); + if it.peek().is_none() { + return; + } + let show_semver_warning = self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(fn_def_id); + for ((&input, &_), arg) in it { // Only take `&mut` arguments. if_chain! { if let PatKind::Binding(_, canonical_id, ..) = arg.pat.kind; if !mutably_used_vars.contains(&canonical_id); if let rustc_hir::TyKind::Ref(_, inner_ty) = input.kind; then { - // If the argument is never used mutably, we emit the error. - span_lint_and_sugg( + // If the argument is never used mutably, we emit the warning. + let sp = input.span; + span_lint_and_then( cx, NEEDLESS_PASS_BY_REF_MUT, - input.span, + sp, "this argument is a mutable reference, but not used mutably", - "consider changing to", - format!("&{}", snippet(cx, cx.tcx.hir().span(inner_ty.ty.hir_id), "_")), - Applicability::Unspecified, + |diag| { + diag.span_suggestion( + sp, + "consider changing to".to_string(), + format!( + "&{}", + snippet(cx, cx.tcx.hir().span(inner_ty.ty.hir_id), "_"), + ), + Applicability::Unspecified, + ); + if show_semver_warning { + diag.warn("changing this function will impact semver compatibility"); + } + }, ); } } diff --git a/tests/ui/should_impl_trait/method_list_2.stderr b/tests/ui/should_impl_trait/method_list_2.stderr index e47cb209b839..2ae9fa34d142 100644 --- a/tests/ui/should_impl_trait/method_list_2.stderr +++ b/tests/ui/should_impl_trait/method_list_2.stderr @@ -45,6 +45,7 @@ error: this argument is a mutable reference, but not used mutably LL | pub fn hash(&self, state: &mut T) { | ^^^^^^ help: consider changing to: `&T` | + = warning: changing this function will impact semver compatibility = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings` error: method `index` can be confused for the standard trait method `std::ops::Index::index` From 406241832efef6efbf553a8ba332a6da37e19365 Mon Sep 17 00:00:00 2001 From: Boxy Date: Tue, 4 Jul 2023 15:41:45 +0100 Subject: [PATCH 159/324] Deal with fallout --- clippy_utils/src/consts.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index dd3cda8ec527..1e1bb2a1d962 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -689,7 +689,7 @@ pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::ConstantKind<'t mir::ConstantKind::Val(ConstValue::ByRef { alloc, offset: _ }, _) => match result.ty().kind() { ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)), ty::Array(sub_type, len) => match sub_type.kind() { - ty::Float(FloatTy::F32) => match len.kind().try_to_target_usize(lcx.tcx) { + ty::Float(FloatTy::F32) => match len.try_to_target_usize(lcx.tcx) { Some(len) => alloc .inner() .inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * usize::try_from(len).unwrap())) @@ -700,7 +700,7 @@ pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::ConstantKind<'t .map(Constant::Vec), _ => None, }, - ty::Float(FloatTy::F64) => match len.kind().try_to_target_usize(lcx.tcx) { + ty::Float(FloatTy::F64) => match len.try_to_target_usize(lcx.tcx) { Some(len) => alloc .inner() .inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * usize::try_from(len).unwrap())) From 6868c0a74bb1edeff8c078bb8b09994075e826cb Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Wed, 5 Jul 2023 12:30:39 +0200 Subject: [PATCH 160/324] [`unnecessary_literal_unwrap`]: don't lint if binding initializer is expn --- clippy_lints/src/methods/unnecessary_literal_unwrap.rs | 5 +++++ tests/ui/unnecessary_literal_unwrap.fixed | 10 ++++++++++ tests/ui/unnecessary_literal_unwrap.rs | 10 ++++++++++ 3 files changed, 25 insertions(+) diff --git a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs index 7877f6a386cb..ce93d7c3eb33 100644 --- a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs +++ b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs @@ -29,6 +29,11 @@ pub(super) fn check( args: &[hir::Expr<'_>], ) { let init = clippy_utils::expr_or_init(cx, recv); + if init.span.from_expansion() { + // don't lint if the receiver or binding initializer comes from a macro + // (e.g. `let x = option_env!(..); x.unwrap()`) + return; + } let (constructor, call_args, ty) = if let hir::ExprKind::Call(call, call_args) = init.kind { let Some(qpath) = call.qpath_opt() else { return }; diff --git a/tests/ui/unnecessary_literal_unwrap.fixed b/tests/ui/unnecessary_literal_unwrap.fixed index 630a1bea3c87..092bf78feabe 100644 --- a/tests/ui/unnecessary_literal_unwrap.fixed +++ b/tests/ui/unnecessary_literal_unwrap.fixed @@ -68,6 +68,16 @@ fn unwrap_methods_result() { 1; } +fn unwrap_from_binding() { + macro_rules! from_macro { + () => { + Some("") + }; + } + let val = from_macro!(); + let _ = val.unwrap_or(""); +} + fn main() { unwrap_option_some(); unwrap_option_none(); diff --git a/tests/ui/unnecessary_literal_unwrap.rs b/tests/ui/unnecessary_literal_unwrap.rs index 14f92cb370f6..b9df893d1d2b 100644 --- a/tests/ui/unnecessary_literal_unwrap.rs +++ b/tests/ui/unnecessary_literal_unwrap.rs @@ -68,6 +68,16 @@ fn unwrap_methods_result() { Ok::<_, ()>(1).unwrap_or_else(|_| 2); } +fn unwrap_from_binding() { + macro_rules! from_macro { + () => { + Some("") + }; + } + let val = from_macro!(); + let _ = val.unwrap_or(""); +} + fn main() { unwrap_option_some(); unwrap_option_none(); From 30cbba20de13ed37250d0610980636e43f673022 Mon Sep 17 00:00:00 2001 From: Ali Bektas Date: Wed, 5 Jul 2023 13:32:12 +0200 Subject: [PATCH 161/324] Add snippet insert if client supports it --- .../src/handlers/generate_trait_from_impl.rs | 94 ++++++++++++++----- crates/ide-assists/src/tests/generated.rs | 4 +- 2 files changed, 72 insertions(+), 26 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_trait_from_impl.rs b/crates/ide-assists/src/handlers/generate_trait_from_impl.rs index d3192ae40914..2027309940a1 100644 --- a/crates/ide-assists/src/handlers/generate_trait_from_impl.rs +++ b/crates/ide-assists/src/handlers/generate_trait_from_impl.rs @@ -44,7 +44,7 @@ use syntax::{ // }; // } // -// trait NewTrait { +// trait ${0:TraitName} { // // Used as an associated constant. // const CONST_ASSOC: usize = N * 4; // @@ -53,7 +53,7 @@ use syntax::{ // const_maker! {i32, 7} // } // -// impl NewTrait for Foo { +// impl ${0:TraitName} for Foo { // // Used as an associated constant. // const CONST_ASSOC: usize = N * 4; // @@ -126,23 +126,41 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_ "".to_string() }; - // // Then replace - builder.replace( - impl_name.syntax().text_range(), - format!("NewTrait{} for {}", arg_list, impl_name.to_string()), - ); + if let Some(snippet_cap) = ctx.config.snippet_cap { + builder.replace_snippet( + snippet_cap, + impl_name.syntax().text_range(), + format!("${{0:TraitName}}{} for {}", arg_list, impl_name.to_string()), + ); + + // Insert trait before TraitImpl + builder.insert_snippet( + snippet_cap, + impl_ast.syntax().text_range().start(), + format!( + "{}\n\n{}", + trait_ast.to_string().replace("NewTrait", "${0:TraitName}"), + IndentLevel::from_node(impl_ast.syntax()) + ), + ); + } else { + builder.replace( + impl_name.syntax().text_range(), + format!("NewTrait{} for {}", arg_list, impl_name.to_string()), + ); + + // Insert trait before TraitImpl + builder.insert( + impl_ast.syntax().text_range().start(), + format!( + "{}\n\n{}", + trait_ast.to_string(), + IndentLevel::from_node(impl_ast.syntax()) + ), + ); + } builder.replace(assoc_items.syntax().text_range(), impl_items.to_string()); - - // Insert trait before TraitImpl - builder.insert( - impl_ast.syntax().text_range().start(), - format!( - "{}\n\n{}", - trait_ast.to_string(), - IndentLevel::from_node(impl_ast.syntax()) - ), - ); }, ); @@ -193,7 +211,7 @@ fn strip_body(item: &ast::AssocItem) { #[cfg(test)] mod tests { use super::*; - use crate::tests::{check_assist, check_assist_not_applicable}; + use crate::tests::{check_assist, check_assist_no_snippet_cap, check_assist_not_applicable}; #[test] fn test_trigger_when_cursor_on_header() { @@ -212,7 +230,7 @@ impl Foo { $0 #[test] fn test_assoc_item_fn() { - check_assist( + check_assist_no_snippet_cap( generate_trait_from_impl, r#" struct Foo(f64); @@ -239,7 +257,7 @@ impl NewTrait for Foo { #[test] fn test_assoc_item_macro() { - check_assist( + check_assist_no_snippet_cap( generate_trait_from_impl, r#" struct Foo; @@ -274,7 +292,7 @@ impl NewTrait for Foo { #[test] fn test_assoc_item_const() { - check_assist( + check_assist_no_snippet_cap( generate_trait_from_impl, r#" struct Foo; @@ -297,7 +315,7 @@ impl NewTrait for Foo { #[test] fn test_impl_with_generics() { - check_assist( + check_assist_no_snippet_cap( generate_trait_from_impl, r#" struct Foo([i32; N]); @@ -325,7 +343,7 @@ impl NewTrait for Foo { #[test] fn test_trait_items_should_not_have_vis() { - check_assist( + check_assist_no_snippet_cap( generate_trait_from_impl, r#" struct Foo; @@ -362,7 +380,7 @@ impl Emp$0tyImpl{} #[test] fn test_not_top_level_impl() { - check_assist( + check_assist_no_snippet_cap( generate_trait_from_impl, r#" mod a { @@ -382,4 +400,32 @@ mod a { }"#, ) } + + #[test] + fn test_snippet_cap_is_some() { + check_assist( + generate_trait_from_impl, + r#" +struct Foo([i32; N]); + +impl F$0oo { + // Used as an associated constant. + const CONST: usize = N * 4; +} + "#, + r#" +struct Foo([i32; N]); + +trait ${0:TraitName} { + // Used as an associated constant. + const CONST: usize = N * 4; +} + +impl ${0:TraitName} for Foo { + // Used as an associated constant. + const CONST: usize = N * 4; +} + "#, + ) + } } diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index 2404fecc4529..edab13c754de 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -1533,7 +1533,7 @@ macro_rules! const_maker { }; } -trait NewTrait { +trait ${0:TraitName} { // Used as an associated constant. const CONST_ASSOC: usize = N * 4; @@ -1542,7 +1542,7 @@ trait NewTrait { const_maker! {i32, 7} } -impl NewTrait for Foo { +impl ${0:TraitName} for Foo { // Used as an associated constant. const CONST_ASSOC: usize = N * 4; From ce0239bd6a58ce5326b7480c8bdd8552d111a46f Mon Sep 17 00:00:00 2001 From: AmrDeveloper Date: Wed, 5 Jul 2023 16:34:04 +0200 Subject: [PATCH 162/324] Disable remove unnecessary braces diagnotics for self imports --- .../src/handlers/useless_braces.rs | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/crates/ide-diagnostics/src/handlers/useless_braces.rs b/crates/ide-diagnostics/src/handlers/useless_braces.rs index 11ce811efaa5..49cdcdb00f04 100644 --- a/crates/ide-diagnostics/src/handlers/useless_braces.rs +++ b/crates/ide-diagnostics/src/handlers/useless_braces.rs @@ -1,6 +1,6 @@ use ide_db::{base_db::FileId, source_change::SourceChange}; use itertools::Itertools; -use syntax::{ast, AstNode, SyntaxNode, TextRange}; +use syntax::{ast, AstNode, SyntaxKind, SyntaxNode, TextRange}; use text_edit::TextEdit; use crate::{fix, Diagnostic, DiagnosticCode}; @@ -15,6 +15,11 @@ pub(crate) fn useless_braces( ) -> Option<()> { let use_tree_list = ast::UseTreeList::cast(node.clone())?; if let Some((single_use_tree,)) = use_tree_list.use_trees().collect_tuple() { + // If there is a `self` inside the bracketed `use`, don't show diagnostic. + if single_use_tree.syntax().first_token().unwrap().kind() == SyntaxKind::SELF_KW { + return Some(()); + } + // If there is a comment inside the bracketed `use`, // assume it is a commented out module path and don't show diagnostic. if use_tree_list.has_inner_comment() { @@ -91,6 +96,22 @@ mod a { pub mod e {} } } +"#, + ); + check_diagnostics( + r#" +use a::{self}; + +mod a { +} +"#, + ); + check_diagnostics( + r#" +use a::{self as cool_name}; + +mod a { +} "#, ); check_fix( @@ -121,16 +142,6 @@ use a::{c$0}; r#" mod a { pub mod c {} } use a::c; -"#, - ); - check_fix( - r#" -mod a {} -use a::{self$0}; -"#, - r#" -mod a {} -use a; "#, ); check_fix( From 8edb3e192aa9b7faff864e852b8b3302fcd426b1 Mon Sep 17 00:00:00 2001 From: Ali Bektas Date: Wed, 5 Jul 2023 16:45:54 +0200 Subject: [PATCH 163/324] Minor changes --- crates/ide-assists/src/handlers/generate_trait_from_impl.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_trait_from_impl.rs b/crates/ide-assists/src/handlers/generate_trait_from_impl.rs index 2027309940a1..0f67380d12b6 100644 --- a/crates/ide-assists/src/handlers/generate_trait_from_impl.rs +++ b/crates/ide-assists/src/handlers/generate_trait_from_impl.rs @@ -105,8 +105,6 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_ remove_items_visibility(&item); }); - ted::replace(assoc_items.clone_for_update().syntax(), impl_items.syntax()); - impl_items.assoc_items().for_each(|item| { remove_items_visibility(&item); }); @@ -201,7 +199,7 @@ fn strip_body(item: &ast::AssocItem) { } } - ted::replace(body.syntax(), ast::make::tokens::semicolon()); + ted::replace(body.syntax(), make::tokens::semicolon()); } } _ => (), From 3fb6a3be8242cfd57d891c4b6a666e3e9e38c01d Mon Sep 17 00:00:00 2001 From: AmrDeveloper Date: Wed, 5 Jul 2023 17:38:58 +0200 Subject: [PATCH 164/324] Remove un needed extra handling for remove self with braces --- .../src/handlers/useless_braces.rs | 22 +++++-------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/crates/ide-diagnostics/src/handlers/useless_braces.rs b/crates/ide-diagnostics/src/handlers/useless_braces.rs index 49cdcdb00f04..79dd09378ca9 100644 --- a/crates/ide-diagnostics/src/handlers/useless_braces.rs +++ b/crates/ide-diagnostics/src/handlers/useless_braces.rs @@ -27,13 +27,11 @@ pub(crate) fn useless_braces( } let use_range = use_tree_list.syntax().text_range(); - let edit = remove_braces(&single_use_tree).unwrap_or_else(|| { - let to_replace = single_use_tree.syntax().text().to_string(); - let mut edit_builder = TextEdit::builder(); - edit_builder.delete(use_range); - edit_builder.insert(use_range.start(), to_replace); - edit_builder.finish() - }); + let to_replace = single_use_tree.syntax().text().to_string(); + let mut edit_builder = TextEdit::builder(); + edit_builder.delete(use_range); + edit_builder.insert(use_range.start(), to_replace); + let edit = edit_builder.finish(); acc.push( Diagnostic::new( @@ -53,16 +51,6 @@ pub(crate) fn useless_braces( Some(()) } -fn remove_braces(single_use_tree: &ast::UseTree) -> Option { - let use_tree_list_node = single_use_tree.syntax().parent()?; - if single_use_tree.path()?.segment()?.self_token().is_some() { - let start = use_tree_list_node.prev_sibling_or_token()?.text_range().start(); - let end = use_tree_list_node.text_range().end(); - return Some(TextEdit::delete(TextRange::new(start, end))); - } - None -} - #[cfg(test)] mod tests { use crate::tests::{check_diagnostics, check_fix}; From fe65eabc819551b584e20e102d41f34b27ba2c74 Mon Sep 17 00:00:00 2001 From: AmrDeveloper Date: Wed, 5 Jul 2023 17:41:51 +0200 Subject: [PATCH 165/324] Remove un used import --- crates/ide-diagnostics/src/handlers/useless_braces.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ide-diagnostics/src/handlers/useless_braces.rs b/crates/ide-diagnostics/src/handlers/useless_braces.rs index 79dd09378ca9..d9a9c486a36a 100644 --- a/crates/ide-diagnostics/src/handlers/useless_braces.rs +++ b/crates/ide-diagnostics/src/handlers/useless_braces.rs @@ -1,6 +1,6 @@ use ide_db::{base_db::FileId, source_change::SourceChange}; use itertools::Itertools; -use syntax::{ast, AstNode, SyntaxKind, SyntaxNode, TextRange}; +use syntax::{ast, AstNode, SyntaxKind, SyntaxNode}; use text_edit::TextEdit; use crate::{fix, Diagnostic, DiagnosticCode}; From a4f99149fce5ce1ea03a85f73d06d29ee7bd6d5e Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 5 Jul 2023 16:16:03 +0000 Subject: [PATCH 166/324] Patch clippy --- clippy_utils/src/consts.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index dd3cda8ec527..b7f62af75b81 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -725,13 +725,14 @@ fn field_of_struct<'tcx>( result: mir::ConstantKind<'tcx>, field: &Ident, ) -> Option> { - if let Some(dc) = lcx.tcx.try_destructure_mir_constant(lcx.param_env.and(result)) + if let mir::ConstantKind::Val(result, ty) = result + && let Some(dc) = lcx.tcx.try_destructure_mir_constant_for_diagnostics((result, ty)) && let Some(dc_variant) = dc.variant && let Some(variant) = adt_def.variants().get(dc_variant) && let Some(field_idx) = variant.fields.iter().position(|el| el.name == field.name) - && let Some(dc_field) = dc.fields.get(field_idx) + && let Some(&(val, ty)) = dc.fields.get(field_idx) { - Some(*dc_field) + Some(mir::ConstantKind::Val(val, ty)) } else { None From 54e897368d88650b2990aa62ba39dfee0a4f970c Mon Sep 17 00:00:00 2001 From: AmrDeveloper Date: Wed, 5 Jul 2023 19:31:37 +0200 Subject: [PATCH 167/324] Cover disable diagnostic from case with invalid syntax --- .../src/handlers/useless_braces.rs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/crates/ide-diagnostics/src/handlers/useless_braces.rs b/crates/ide-diagnostics/src/handlers/useless_braces.rs index d9a9c486a36a..0aa439f797a1 100644 --- a/crates/ide-diagnostics/src/handlers/useless_braces.rs +++ b/crates/ide-diagnostics/src/handlers/useless_braces.rs @@ -1,6 +1,6 @@ use ide_db::{base_db::FileId, source_change::SourceChange}; use itertools::Itertools; -use syntax::{ast, AstNode, SyntaxKind, SyntaxNode}; +use syntax::{ast, AstNode, SyntaxNode}; use text_edit::TextEdit; use crate::{fix, Diagnostic, DiagnosticCode}; @@ -16,7 +16,7 @@ pub(crate) fn useless_braces( let use_tree_list = ast::UseTreeList::cast(node.clone())?; if let Some((single_use_tree,)) = use_tree_list.use_trees().collect_tuple() { // If there is a `self` inside the bracketed `use`, don't show diagnostic. - if single_use_tree.syntax().first_token().unwrap().kind() == SyntaxKind::SELF_KW { + if single_use_tree.path()?.segment()?.self_token().is_some() { return Some(()); } @@ -53,7 +53,10 @@ pub(crate) fn useless_braces( #[cfg(test)] mod tests { - use crate::tests::{check_diagnostics, check_fix}; + use crate::{ + tests::{check_diagnostics, check_diagnostics_with_config, check_fix}, + DiagnosticsConfig, + }; #[test] fn test_check_unnecessary_braces_in_use_statement() { @@ -100,6 +103,16 @@ use a::{self as cool_name}; mod a { } +"#, + ); + + let mut config = DiagnosticsConfig::test_sample(); + config.disabled.insert("syntax-error".to_string()); + check_diagnostics_with_config( + config, + r#" +mod a { pub mod b {} } +use a::{b::self}; "#, ); check_fix( From f9453511701192ac391a42b37c1794621ece0f77 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Wed, 5 Jul 2023 18:04:10 +0000 Subject: [PATCH 168/324] Fix regex lints for regex 1.9.0 --- clippy_lints/src/lib.rs | 2 +- clippy_lints/src/regex.rs | 66 +++++++++++++++++++++++++++------------ clippy_utils/src/paths.rs | 12 +++---- 3 files changed, 53 insertions(+), 27 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index c43e0b753dc8..00d46025caa8 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -722,7 +722,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(drop_forget_ref::DropForgetRef)); store.register_late_pass(|_| Box::new(empty_enum::EmptyEnum)); store.register_late_pass(|_| Box::new(invalid_upcast_comparisons::InvalidUpcastComparisons)); - store.register_late_pass(|_| Box::new(regex::Regex)); + store.register_late_pass(|_| Box::::default()); let ignore_interior_mutability = conf.ignore_interior_mutability.clone(); store.register_late_pass(move |_| Box::new(copies::CopyAndPaste::new(ignore_interior_mutability.clone()))); store.register_late_pass(|_| Box::new(copy_iterator::CopyIterator)); diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index 674f8bf4c0f3..b795e4b15bac 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -3,12 +3,12 @@ use std::fmt::Display; use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::source::snippet_opt; -use clippy_utils::{match_def_path, paths}; -use if_chain::if_chain; +use clippy_utils::{def_path_def_ids, path_def_id, paths}; use rustc_ast::ast::{LitKind, StrStyle}; +use rustc_hir::def_id::DefIdMap; use rustc_hir::{BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::{BytePos, Span}; declare_clippy_lint! { @@ -55,26 +55,52 @@ declare_clippy_lint! { "trivial regular expressions" } -declare_lint_pass!(Regex => [INVALID_REGEX, TRIVIAL_REGEX]); +#[derive(Copy, Clone)] +enum RegexKind { + Unicode, + UnicodeSet, + Bytes, + BytesSet, +} + +#[derive(Default)] +pub struct Regex { + definitions: DefIdMap, +} + +impl_lint_pass!(Regex => [INVALID_REGEX, TRIVIAL_REGEX]); impl<'tcx> LateLintPass<'tcx> for Regex { + fn check_crate(&mut self, cx: &LateContext<'tcx>) { + // We don't use `match_def_path` here because that relies on matching the exact path, which changed + // between regex 1.8 and 1.9 + // + // `def_path_def_ids` will resolve through re-exports but is relatively heavy, so we only perform + // the operation once and store the results + let mut resolve = |path, kind| { + for id in def_path_def_ids(cx, path) { + self.definitions.insert(id, kind); + } + }; + + resolve(&paths::REGEX_NEW, RegexKind::Unicode); + resolve(&paths::REGEX_BUILDER_NEW, RegexKind::Unicode); + resolve(&paths::REGEX_SET_NEW, RegexKind::UnicodeSet); + resolve(&paths::REGEX_BYTES_NEW, RegexKind::Bytes); + resolve(&paths::REGEX_BYTES_BUILDER_NEW, RegexKind::Bytes); + resolve(&paths::REGEX_BYTES_SET_NEW, RegexKind::BytesSet); + } + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if_chain! { - if let ExprKind::Call(fun, [arg]) = expr.kind; - if let ExprKind::Path(ref qpath) = fun.kind; - if let Some(def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id(); - then { - if match_def_path(cx, def_id, &paths::REGEX_NEW) || - match_def_path(cx, def_id, &paths::REGEX_BUILDER_NEW) { - check_regex(cx, arg, true); - } else if match_def_path(cx, def_id, &paths::REGEX_BYTES_NEW) || - match_def_path(cx, def_id, &paths::REGEX_BYTES_BUILDER_NEW) { - check_regex(cx, arg, false); - } else if match_def_path(cx, def_id, &paths::REGEX_SET_NEW) { - check_set(cx, arg, true); - } else if match_def_path(cx, def_id, &paths::REGEX_BYTES_SET_NEW) { - check_set(cx, arg, false); - } + if let ExprKind::Call(fun, [arg]) = expr.kind + && let Some(def_id) = path_def_id(cx, fun) + && let Some(regex_kind) = self.definitions.get(&def_id) + { + match regex_kind { + RegexKind::Unicode => check_regex(cx, arg, true), + RegexKind::UnicodeSet => check_set(cx, arg, true), + RegexKind::Bytes => check_regex(cx, arg, false), + RegexKind::BytesSet => check_set(cx, arg, false), } } } diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 0e6f01287b56..f3677e6f6141 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -94,12 +94,12 @@ pub const PUSH_STR: [&str; 4] = ["alloc", "string", "String", "push_str"]; pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["core", "ops", "RangeBounds"]; pub const REFCELL_REF: [&str; 3] = ["core", "cell", "Ref"]; pub const REFCELL_REFMUT: [&str; 3] = ["core", "cell", "RefMut"]; -pub const REGEX_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "unicode", "RegexBuilder", "new"]; -pub const REGEX_BYTES_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "bytes", "RegexBuilder", "new"]; -pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "re_bytes", "Regex", "new"]; -pub const REGEX_BYTES_SET_NEW: [&str; 5] = ["regex", "re_set", "bytes", "RegexSet", "new"]; -pub const REGEX_NEW: [&str; 4] = ["regex", "re_unicode", "Regex", "new"]; -pub const REGEX_SET_NEW: [&str; 5] = ["regex", "re_set", "unicode", "RegexSet", "new"]; +pub const REGEX_BUILDER_NEW: [&str; 3] = ["regex", "RegexBuilder", "new"]; +pub const REGEX_BYTES_BUILDER_NEW: [&str; 4] = ["regex", "bytes", "RegexBuilder", "new"]; +pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "bytes", "Regex", "new"]; +pub const REGEX_BYTES_SET_NEW: [&str; 4] = ["regex", "bytes", "RegexSet", "new"]; +pub const REGEX_NEW: [&str; 3] = ["regex", "Regex", "new"]; +pub const REGEX_SET_NEW: [&str; 3] = ["regex", "RegexSet", "new"]; pub const SERDE_DESERIALIZE: [&str; 3] = ["serde", "de", "Deserialize"]; pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"]; pub const SLICE_FROM_RAW_PARTS: [&str; 4] = ["core", "slice", "raw", "from_raw_parts"]; From cbe468222a068f59ba0dd9ac15d5f45eeda8b83e Mon Sep 17 00:00:00 2001 From: Boxy Date: Wed, 5 Jul 2023 20:13:26 +0100 Subject: [PATCH 169/324] Move `TyCtxt::mk_x` to `Ty::new_x` where applicable --- clippy_lints/src/bool_assert_comparison.rs | 2 +- clippy_lints/src/loops/explicit_iter_loop.rs | 4 ++-- clippy_lints/src/methods/needless_collect.rs | 4 ++-- clippy_lints/src/methods/unnecessary_to_owned.rs | 2 +- clippy_lints/src/needless_pass_by_value.rs | 4 ++-- clippy_lints/src/ptr.rs | 4 ++-- clippy_lints/src/redundant_slicing.rs | 3 ++- clippy_lints/src/transmute/transmute_ptr_to_ptr.rs | 2 +- clippy_lints/src/transmute/transmute_ref_to_ref.rs | 4 ++-- clippy_lints/src/transmute/useless_transmute.rs | 2 +- clippy_utils/src/ty.rs | 4 ++-- 11 files changed, 18 insertions(+), 17 deletions(-) diff --git a/clippy_lints/src/bool_assert_comparison.rs b/clippy_lints/src/bool_assert_comparison.rs index 8c3ad24eeed4..e8775b081444 100644 --- a/clippy_lints/src/bool_assert_comparison.rs +++ b/clippy_lints/src/bool_assert_comparison.rs @@ -61,7 +61,7 @@ fn is_impl_not_trait_with_bool_out<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) - ) }) .map_or(false, |assoc_item| { - let proj = cx.tcx.mk_projection(assoc_item.def_id, cx.tcx.mk_substs_trait(ty, [])); + let proj = Ty::new_projection(cx.tcx,assoc_item.def_id, cx.tcx.mk_substs_trait(ty, [])); let nty = cx.tcx.normalize_erasing_regions(cx.param_env, proj); nty.is_bool() diff --git a/clippy_lints/src/loops/explicit_iter_loop.rs b/clippy_lints/src/loops/explicit_iter_loop.rs index f3347e33077b..5c5a4cfce884 100644 --- a/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/clippy_lints/src/loops/explicit_iter_loop.rs @@ -149,7 +149,7 @@ fn is_ref_iterable<'tcx>( let self_ty = if mutbl.is_mut() { self_ty } else { - cx.tcx.mk_ref(region, TypeAndMut { ty, mutbl }) + Ty::new_ref(cx.tcx,region, TypeAndMut { ty, mutbl }) }; if implements_trait(cx, self_ty, trait_id, &[]) && let Some(ty) = @@ -164,7 +164,7 @@ fn is_ref_iterable<'tcx>( && !self_ty.is_ref() { // Attempt to borrow - let self_ty = cx.tcx.mk_ref(cx.tcx.lifetimes.re_erased, TypeAndMut { + let self_ty = Ty::new_ref(cx.tcx,cx.tcx.lifetimes.re_erased, TypeAndMut { ty: self_ty, mutbl, }); diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs index ac209d014062..8ca7af8107f6 100644 --- a/clippy_lints/src/methods/needless_collect.rs +++ b/clippy_lints/src/methods/needless_collect.rs @@ -215,7 +215,7 @@ fn iterates_same_ty<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<'tcx>, collect_ty: && let Some(into_iter_item_proj) = make_projection(cx.tcx, into_iter_trait, item, [collect_ty]) && let Ok(into_iter_item_ty) = cx.tcx.try_normalize_erasing_regions( cx.param_env, - cx.tcx.mk_projection(into_iter_item_proj.def_id, into_iter_item_proj.substs) + Ty::new_projection(cx.tcx,into_iter_item_proj.def_id, into_iter_item_proj.substs) ) { iter_item_ty == into_iter_item_ty @@ -238,7 +238,7 @@ fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) - .associated_items(iter_trait) .find_by_name_and_kind(cx.tcx, Ident::with_dummy_span(Symbol::intern("Item")), AssocKind::Type, iter_trait) && let substs = cx.tcx.mk_substs(&[GenericArg::from(typeck.expr_ty_adjusted(iter_expr))]) - && let proj_ty = cx.tcx.mk_projection(iter_item.def_id, substs) + && let proj_ty = Ty::new_projection(cx.tcx,iter_item.def_id, substs) && let Ok(item_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, proj_ty) { item_ty == EarlyBinder::bind(search_ty).subst(cx.tcx, cx.typeck_results().node_substs(call_id)) diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 16ef24bd4e34..6bd5e9e88c84 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -270,7 +270,7 @@ fn check_other_call_arg<'tcx>( if let Some((n_refs, receiver_ty)) = if n_refs > 0 || is_copy(cx, receiver_ty) { Some((n_refs, receiver_ty)) } else if trait_predicate.def_id() != deref_trait_id { - Some((1, cx.tcx.mk_ref( + Some((1, Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, ty::TypeAndMut { ty: receiver_ty, diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index ece10474715f..f11d5773d041 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -17,7 +17,7 @@ use rustc_hir_typeck::expr_use_visitor as euv; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::FakeReadCause; -use rustc_middle::ty::{self, TypeVisitableExt}; +use rustc_middle::ty::{self, TypeVisitableExt, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::kw; @@ -168,7 +168,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { ( preds.iter().any(|t| cx.tcx.is_diagnostic_item(sym::Borrow, t.def_id())), !preds.is_empty() && { - let ty_empty_region = cx.tcx.mk_imm_ref(cx.tcx.lifetimes.re_erased, ty); + let ty_empty_region = Ty::new_imm_ref(cx.tcx,cx.tcx.lifetimes.re_erased, ty); preds.iter().all(|t| { let ty_params = t.trait_ref.substs.iter().skip(1).collect::>(); implements_trait(cx, ty_empty_region, t.def_id(), &ty_params) diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 866a04466c90..32213718b270 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -389,11 +389,11 @@ impl<'tcx> DerefTy<'tcx> { fn ty(&self, cx: &LateContext<'tcx>) -> Ty<'tcx> { match *self { Self::Str => cx.tcx.types.str_, - Self::Path => cx.tcx.mk_adt( + Self::Path => Ty::new_adt(cx.tcx, cx.tcx.adt_def(cx.tcx.get_diagnostic_item(sym::Path).unwrap()), List::empty(), ), - Self::Slice(_, ty) => cx.tcx.mk_slice(ty), + Self::Slice(_, ty) => Ty::new_slice(cx.tcx,ty), } } diff --git a/clippy_lints/src/redundant_slicing.rs b/clippy_lints/src/redundant_slicing.rs index 2fdd775ad489..c70ce83a9c45 100644 --- a/clippy_lints/src/redundant_slicing.rs +++ b/clippy_lints/src/redundant_slicing.rs @@ -7,6 +7,7 @@ use rustc_ast::util::parser::PREC_PREFIX; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability}; use rustc_lint::{LateContext, LateLintPass, Lint}; +use rustc_middle::ty::Ty; use rustc_middle::ty::adjustment::{Adjust, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::subst::GenericArg; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -134,7 +135,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing { } else if let Some(target_id) = cx.tcx.lang_items().deref_target() { if let Ok(deref_ty) = cx.tcx.try_normalize_erasing_regions( cx.param_env, - cx.tcx.mk_projection(target_id, cx.tcx.mk_substs(&[GenericArg::from(indexed_ty)])), + Ty::new_projection(cx.tcx,target_id, cx.tcx.mk_substs(&[GenericArg::from(indexed_ty)])), ) { if deref_ty == expr_ty { let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0; diff --git a/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs b/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs index 31a9b69ca158..857d2ad82588 100644 --- a/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs +++ b/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs @@ -24,7 +24,7 @@ pub(super) fn check<'tcx>( "transmute from a pointer to a pointer", |diag| { if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) { - let sugg = arg.as_ty(cx.tcx.mk_ptr(*to_ty)); + let sugg = arg.as_ty(Ty::new_ptr(cx.tcx,*to_ty)); diag.span_suggestion(e.span, "try", sugg, Applicability::Unspecified); } }, diff --git a/clippy_lints/src/transmute/transmute_ref_to_ref.rs b/clippy_lints/src/transmute/transmute_ref_to_ref.rs index 426c7253806e..ea9ad99618ab 100644 --- a/clippy_lints/src/transmute/transmute_ref_to_ref.rs +++ b/clippy_lints/src/transmute/transmute_ref_to_ref.rs @@ -64,8 +64,8 @@ pub(super) fn check<'tcx>( }; let ty_to_and_mut = ty::TypeAndMut { ty: *ty_to, mutbl: *to_mutbl }; let sugg_paren = arg - .as_ty(cx.tcx.mk_ptr(ty_from_and_mut)) - .as_ty(cx.tcx.mk_ptr(ty_to_and_mut)); + .as_ty(Ty::new_ptr(cx.tcx,ty_from_and_mut)) + .as_ty(Ty::new_ptr(cx.tcx,ty_to_and_mut)); let sugg = if *to_mutbl == Mutability::Mut { sugg_paren.mut_addr_deref() } else { diff --git a/clippy_lints/src/transmute/useless_transmute.rs b/clippy_lints/src/transmute/useless_transmute.rs index 56207fe767c5..b6615410e257 100644 --- a/clippy_lints/src/transmute/useless_transmute.rs +++ b/clippy_lints/src/transmute/useless_transmute.rs @@ -43,7 +43,7 @@ pub(super) fn check<'tcx>( let sugg = if *ptr_ty == rty_and_mut { arg.as_ty(to_ty) } else { - arg.as_ty(cx.tcx.mk_ptr(rty_and_mut)).as_ty(to_ty) + arg.as_ty(Ty::new_ptr(cx.tcx,rty_and_mut)).as_ty(to_ty) }; diag.span_suggestion(e.span, "try", sugg, Applicability::Unspecified); diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 9c39d22c61b2..d650cbe0b132 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -1124,7 +1124,7 @@ pub fn make_normalized_projection<'tcx>( ); return None; } - match tcx.try_normalize_erasing_regions(param_env, tcx.mk_projection(ty.def_id, ty.substs)) { + match tcx.try_normalize_erasing_regions(param_env, Ty::new_projection(tcx,ty.def_id, ty.substs)) { Ok(ty) => Some(ty), Err(e) => { debug_assert!(false, "failed to normalize type `{ty}`: {e:#?}"); @@ -1207,7 +1207,7 @@ pub fn make_normalized_projection_with_regions<'tcx>( .infer_ctxt() .build() .at(&cause, param_env) - .query_normalize(tcx.mk_projection(ty.def_id, ty.substs)) + .query_normalize(Ty::new_projection(tcx,ty.def_id, ty.substs)) { Ok(ty) => Some(ty.value), Err(e) => { From 72a3883a7128b4eae6f38d6479f33aaaaae4790b Mon Sep 17 00:00:00 2001 From: Tetsuharu Ohzeki Date: Wed, 28 Jun 2023 04:03:53 +0900 Subject: [PATCH 170/324] editor/code: Enable `noUncheckedIndexedAccess` ts option https://www.typescriptlang.org/tsconfig#noUncheckedIndexedAccess --- editors/code/src/ast_inspector.ts | 6 ++- editors/code/src/client.ts | 7 ++- editors/code/src/commands.ts | 14 ++++-- editors/code/src/config.ts | 54 ++++++++++++----------- editors/code/src/debug.ts | 12 +++-- editors/code/src/dependencies_provider.ts | 8 +++- editors/code/src/diagnostics.ts | 4 +- editors/code/src/nullable.ts | 19 ++++++++ editors/code/src/run.ts | 11 +++-- editors/code/src/snippets.ts | 6 ++- editors/code/src/tasks.ts | 4 +- editors/code/src/toolchain.ts | 9 +++- editors/code/src/undefinable.ts | 19 ++++++++ editors/code/tsconfig.json | 3 +- 14 files changed, 124 insertions(+), 52 deletions(-) create mode 100644 editors/code/src/nullable.ts create mode 100644 editors/code/src/undefinable.ts diff --git a/editors/code/src/ast_inspector.ts b/editors/code/src/ast_inspector.ts index 176040120f41..fa963d8eb993 100644 --- a/editors/code/src/ast_inspector.ts +++ b/editors/code/src/ast_inspector.ts @@ -2,6 +2,7 @@ import * as vscode from "vscode"; import { Ctx, Disposable } from "./ctx"; import { RustEditor, isRustEditor } from "./util"; +import { unwrapUndefinable } from "./undefinable"; // FIXME: consider implementing this via the Tree View API? // https://code.visualstudio.com/api/extension-guides/tree-view @@ -164,8 +165,9 @@ export class AstInspector implements vscode.HoverProvider, vscode.DefinitionProv if (!parsedRange) return; const [begin, end] = parsedRange.slice(1).map((off) => this.positionAt(doc, +off)); - - return new vscode.Range(begin, end); + const actualBegin = unwrapUndefinable(begin); + const actualEnd = unwrapUndefinable(end); + return new vscode.Range(actualBegin, actualEnd); } // Memoize the last value, otherwise the CPU is at 100% single core diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index f721fcce7663..7b151c804afe 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts @@ -9,6 +9,7 @@ import { WorkspaceEdit } from "vscode"; import { Config, prepareVSCodeConfig } from "./config"; import { randomUUID } from "crypto"; import { sep as pathSeparator } from "path"; +import { unwrapUndefinable } from "./undefinable"; export interface Env { [name: string]: string; @@ -323,10 +324,12 @@ export async function createClient( } for (const [group, { index, items }] of groups) { if (items.length === 1) { - result[index] = items[0]; + const item = unwrapUndefinable(items[0]); + result[index] = item; } else { const action = new vscode.CodeAction(group); - action.kind = items[0].kind; + const item = unwrapUndefinable(items[0]); + action.kind = item.kind; action.command = { command: "rust-analyzer.applyActionGroup", title: "", diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts index 98ccd50dc040..3c6105e89fee 100644 --- a/editors/code/src/commands.ts +++ b/editors/code/src/commands.ts @@ -20,6 +20,7 @@ import { startDebugSession, makeDebugConfig } from "./debug"; import { LanguageClient } from "vscode-languageclient/node"; import { LINKED_COMMANDS } from "./client"; import { DependencyId } from "./dependencies_provider"; +import { unwrapUndefinable } from "./undefinable"; export * from "./ast_inspector"; export * from "./run"; @@ -129,7 +130,8 @@ export function matchingBrace(ctx: CtxInit): Cmd { ), }); editor.selections = editor.selections.map((sel, idx) => { - const active = client.protocol2CodeConverter.asPosition(response[idx]); + const position = unwrapUndefinable(response[idx]); + const active = client.protocol2CodeConverter.asPosition(position); const anchor = sel.isEmpty ? active : sel.anchor; return new vscode.Selection(anchor, active); }); @@ -231,7 +233,7 @@ export function parentModule(ctx: CtxInit): Cmd { if (!locations) return; if (locations.length === 1) { - const loc = locations[0]; + const loc = unwrapUndefinable(locations[0]); const uri = client.protocol2CodeConverter.asUri(loc.targetUri); const range = client.protocol2CodeConverter.asRange(loc.targetRange); @@ -331,7 +333,13 @@ async function revealParentChain(document: RustDocument, ctx: CtxInit) { } while (!ctx.dependencies?.contains(documentPath)); parentChain.reverse(); for (const idx in parentChain) { - await ctx.treeView?.reveal(parentChain[idx], { select: true, expand: true }); + const treeView = ctx.treeView; + if (!treeView) { + continue; + } + + const dependency = unwrapUndefinable(parentChain[idx]); + await treeView.reveal(dependency, { select: true, expand: true }); } } diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index 15a1d4e0f1d8..9595ba052828 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts @@ -4,6 +4,7 @@ import * as path from "path"; import * as vscode from "vscode"; import { Env } from "./client"; import { log } from "./util"; +import { expectNotUndefined, unwrapUndefinable } from "./undefinable"; export type RunnableEnvCfg = | undefined @@ -338,7 +339,7 @@ export function substituteVariablesInEnv(env: Env): Env { const depRe = new RegExp(/\${(?.+?)}/g); let match = undefined; while ((match = depRe.exec(value))) { - const depName = match.groups!.depName; + const depName = unwrapUndefinable(match.groups?.depName); deps.add(depName); // `depName` at this point can have a form of `expression` or // `prefix:expression` @@ -356,7 +357,7 @@ export function substituteVariablesInEnv(env: Env): Env { if (match) { const { prefix, body } = match.groups!; if (prefix === "env") { - const envName = body; + const envName = unwrapUndefinable(body); envWithDeps[dep] = { value: process.env[envName] ?? "", deps: [], @@ -384,13 +385,12 @@ export function substituteVariablesInEnv(env: Env): Env { do { leftToResolveSize = toResolve.size; for (const key of toResolve) { - if (envWithDeps[key].deps.every((dep) => resolved.has(dep))) { - envWithDeps[key].value = envWithDeps[key].value.replace( - /\${(?.+?)}/g, - (_wholeMatch, depName) => { - return envWithDeps[depName].value; - } - ); + const item = unwrapUndefinable(envWithDeps[key]); + if (item.deps.every((dep) => resolved.has(dep))) { + item.value = item.value.replace(/\${(?.+?)}/g, (_wholeMatch, depName) => { + const item = unwrapUndefinable(envWithDeps[depName]); + return item.value; + }); resolved.add(key); toResolve.delete(key); } @@ -399,7 +399,8 @@ export function substituteVariablesInEnv(env: Env): Env { const resolvedEnv: Env = {}; for (const key of Object.keys(env)) { - resolvedEnv[key] = envWithDeps[`env:${key}`].value; + const item = unwrapUndefinable(envWithDeps[`env:${key}`]); + resolvedEnv[key] = item.value; } return resolvedEnv; } @@ -418,20 +419,19 @@ function substituteVSCodeVariableInString(val: string): string { function computeVscodeVar(varName: string): string | null { const workspaceFolder = () => { const folders = vscode.workspace.workspaceFolders ?? []; - if (folders.length === 1) { - // TODO: support for remote workspaces? - return folders[0].uri.fsPath; - } else if (folders.length > 1) { - // could use currently opened document to detect the correct - // workspace. However, that would be determined by the document - // user has opened on Editor startup. Could lead to - // unpredictable workspace selection in practice. - // It's better to pick the first one - return folders[0].uri.fsPath; - } else { - // no workspace opened - return ""; - } + const folder = folders[0]; + // TODO: support for remote workspaces? + const fsPath: string = + folder === undefined + ? // no workspace opened + "" + : // could use currently opened document to detect the correct + // workspace. However, that would be determined by the document + // user has opened on Editor startup. Could lead to + // unpredictable workspace selection in practice. + // It's better to pick the first one + folder.uri.fsPath; + return fsPath; }; // https://code.visualstudio.com/docs/editor/variables-reference const supportedVariables: { [k: string]: () => string } = { @@ -454,7 +454,11 @@ function computeVscodeVar(varName: string): string | null { }; if (varName in supportedVariables) { - return supportedVariables[varName](); + const fn = expectNotUndefined( + supportedVariables[varName], + `${varName} should not be undefined here` + ); + return fn(); } else { // return "${" + varName + "}"; return null; diff --git a/editors/code/src/debug.ts b/editors/code/src/debug.ts index 8fbd427039e4..ede90d707dd8 100644 --- a/editors/code/src/debug.ts +++ b/editors/code/src/debug.ts @@ -6,6 +6,7 @@ import * as ra from "./lsp_ext"; import { Cargo, getRustcId, getSysroot } from "./toolchain"; import { Ctx } from "./ctx"; import { prepareEnv } from "./run"; +import { unwrapUndefinable } from "./undefinable"; const debugOutput = vscode.window.createOutputChannel("Debug"); type DebugConfigProvider = ( @@ -105,12 +106,13 @@ async function getDebugConfiguration( const workspaceFolders = vscode.workspace.workspaceFolders!; const isMultiFolderWorkspace = workspaceFolders.length > 1; const firstWorkspace = workspaceFolders[0]; - const workspace = + const maybeWorkspace = !isMultiFolderWorkspace || !runnable.args.workspaceRoot ? firstWorkspace : workspaceFolders.find((w) => runnable.args.workspaceRoot?.includes(w.uri.fsPath)) || firstWorkspace; + const workspace = unwrapUndefinable(maybeWorkspace); const wsFolder = path.normalize(workspace.uri.fsPath); const workspaceQualifier = isMultiFolderWorkspace ? `:${workspace.name}` : ""; function simplifyPath(p: string): string { @@ -130,12 +132,8 @@ async function getDebugConfiguration( sourceFileMap[`/rustc/${commitHash}/`] = rustlib; } - const debugConfig = knownEngines[debugEngine.id]( - runnable, - simplifyPath(executable), - env, - sourceFileMap - ); + const provider = unwrapUndefinable(knownEngines[debugEngine.id]); + const debugConfig = provider(runnable, simplifyPath(executable), env, sourceFileMap); if (debugConfig.type in debugOptions.engineSettings) { const settingsMap = (debugOptions.engineSettings as any)[debugConfig.type]; for (var key in settingsMap) { diff --git a/editors/code/src/dependencies_provider.ts b/editors/code/src/dependencies_provider.ts index d67345258ec8..51ba11ecc92f 100644 --- a/editors/code/src/dependencies_provider.ts +++ b/editors/code/src/dependencies_provider.ts @@ -4,6 +4,7 @@ import * as fs from "fs"; import { CtxInit } from "./ctx"; import * as ra from "./lsp_ext"; import { FetchDependencyListResult } from "./lsp_ext"; +import { unwrapUndefinable } from "./undefinable"; export class RustDependenciesProvider implements vscode.TreeDataProvider @@ -49,7 +50,12 @@ export class RustDependenciesProvider } getTreeItem(element: Dependency | DependencyFile): vscode.TreeItem | Thenable { - if (element.id! in this.dependenciesMap) return this.dependenciesMap[element.id!]; + const dependenciesMap = this.dependenciesMap; + const elementId = element.id!; + if (elementId in dependenciesMap) { + const dependency = unwrapUndefinable(dependenciesMap[elementId]); + return dependency; + } return element; } diff --git a/editors/code/src/diagnostics.ts b/editors/code/src/diagnostics.ts index 9695d8bf26d5..a7e0845a2780 100644 --- a/editors/code/src/diagnostics.ts +++ b/editors/code/src/diagnostics.ts @@ -2,6 +2,7 @@ import * as anser from "anser"; import * as vscode from "vscode"; import { ProviderResult, Range, TextEditorDecorationType, ThemeColor, window } from "vscode"; import { Ctx } from "./ctx"; +import { unwrapUndefinable } from "./undefinable"; export const URI_SCHEME = "rust-analyzer-diagnostics-view"; @@ -195,7 +196,8 @@ export class AnsiDecorationProvider implements vscode.Disposable { // anser won't return both the RGB and the color name at the same time, // so just fake a single foreground control char with the palette number: const spans = anser.ansiToJson(`\x1b[38;5;${paletteColor}m`); - const rgb = spans[1].fg; + const span = unwrapUndefinable(spans[1]); + const rgb = span.fg; if (rgb) { return `rgb(${rgb})`; diff --git a/editors/code/src/nullable.ts b/editors/code/src/nullable.ts new file mode 100644 index 000000000000..e973e1629075 --- /dev/null +++ b/editors/code/src/nullable.ts @@ -0,0 +1,19 @@ +export type NotNull = T extends null ? never : T; + +export type Nullable = T | null; + +function isNotNull(input: Nullable): input is NotNull { + return input !== null; +} + +function expectNotNull(input: Nullable, msg: string): NotNull { + if (isNotNull(input)) { + return input; + } + + throw new TypeError(msg); +} + +export function unwrapNullable(input: Nullable): NotNull { + return expectNotNull(input, `unwrapping \`null\``); +} diff --git a/editors/code/src/run.ts b/editors/code/src/run.ts index bdd852431334..c20a5487b77f 100644 --- a/editors/code/src/run.ts +++ b/editors/code/src/run.ts @@ -6,6 +6,7 @@ import * as tasks from "./tasks"; import { CtxInit } from "./ctx"; import { makeDebugConfig } from "./debug"; import { Config, RunnableEnvCfg } from "./config"; +import { unwrapUndefinable } from "./undefinable"; const quickPickButtons = [ { iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configuration." }, @@ -68,12 +69,14 @@ export async function selectRunnable( quickPick.onDidHide(() => close()), quickPick.onDidAccept(() => close(quickPick.selectedItems[0])), quickPick.onDidTriggerButton(async (_button) => { - await makeDebugConfig(ctx, quickPick.activeItems[0].runnable); + const runnable = unwrapUndefinable(quickPick.activeItems[0]).runnable; + await makeDebugConfig(ctx, runnable); close(); }), - quickPick.onDidChangeActive((active) => { - if (showButtons && active.length > 0) { - if (active[0].label.startsWith("cargo")) { + quickPick.onDidChangeActive((activeList) => { + if (showButtons && activeList.length > 0) { + const active = unwrapUndefinable(activeList[0]); + if (active.label.startsWith("cargo")) { // save button makes no sense for `cargo test` or `cargo check` quickPick.buttons = []; } else if (quickPick.buttons.length === 0) { diff --git a/editors/code/src/snippets.ts b/editors/code/src/snippets.ts index 299d29c27ee0..1ad93d280ba0 100644 --- a/editors/code/src/snippets.ts +++ b/editors/code/src/snippets.ts @@ -1,10 +1,11 @@ import * as vscode from "vscode"; import { assert } from "./util"; +import { unwrapUndefinable } from "./undefinable"; export async function applySnippetWorkspaceEdit(edit: vscode.WorkspaceEdit) { if (edit.entries().length === 1) { - const [uri, edits] = edit.entries()[0]; + const [uri, edits] = unwrapUndefinable(edit.entries()[0]); const editor = await editorFromUri(uri); if (editor) await applySnippetTextEdits(editor, edits); return; @@ -68,7 +69,8 @@ export async function applySnippetTextEdits(editor: vscode.TextEditor, edits: vs }); if (selections.length > 0) editor.selections = selections; if (selections.length === 1) { - editor.revealRange(selections[0], vscode.TextEditorRevealType.InCenterIfOutsideViewport); + const selection = unwrapUndefinable(selections[0]); + editor.revealRange(selection, vscode.TextEditorRevealType.InCenterIfOutsideViewport); } } diff --git a/editors/code/src/tasks.ts b/editors/code/src/tasks.ts index efb889dc7974..5199508c822c 100644 --- a/editors/code/src/tasks.ts +++ b/editors/code/src/tasks.ts @@ -2,6 +2,7 @@ import * as vscode from "vscode"; import * as toolchain from "./toolchain"; import { Config } from "./config"; import { log } from "./util"; +import { unwrapUndefinable } from "./undefinable"; // This ends up as the `type` key in tasks.json. RLS also uses `cargo` and // our configuration should be compatible with it so use the same key. @@ -120,7 +121,8 @@ export async function buildCargoTask( const fullCommand = [...cargoCommand, ...args]; - exec = new vscode.ProcessExecution(fullCommand[0], fullCommand.slice(1), definition); + const processName = unwrapUndefinable(fullCommand[0]); + exec = new vscode.ProcessExecution(processName, fullCommand.slice(1), definition); } return new vscode.Task( diff --git a/editors/code/src/toolchain.ts b/editors/code/src/toolchain.ts index 917a1d6b0997..b2c0c669db29 100644 --- a/editors/code/src/toolchain.ts +++ b/editors/code/src/toolchain.ts @@ -4,6 +4,8 @@ import * as path from "path"; import * as readline from "readline"; import * as vscode from "vscode"; import { execute, log, memoizeAsync } from "./util"; +import { unwrapNullable } from "./nullable"; +import { unwrapUndefinable } from "./undefinable"; interface CompilationArtifact { fileName: string; @@ -93,7 +95,8 @@ export class Cargo { throw new Error("Multiple compilation artifacts are not supported."); } - return artifacts[0].fileName; + const artifact = unwrapUndefinable(artifacts[0]); + return artifact.fileName; } private async runCargo( @@ -142,7 +145,9 @@ export async function getRustcId(dir: string): Promise { const data = await execute(`${rustcPath} -V -v`, { cwd: dir }); const rx = /commit-hash:\s(.*)$/m; - return rx.exec(data)![1]; + const result = unwrapNullable(rx.exec(data)); + const first = unwrapUndefinable(result[1]); + return first; } /** Mirrors `toolchain::cargo()` implementation */ diff --git a/editors/code/src/undefinable.ts b/editors/code/src/undefinable.ts new file mode 100644 index 000000000000..813bac5a123f --- /dev/null +++ b/editors/code/src/undefinable.ts @@ -0,0 +1,19 @@ +export type NotUndefined = T extends undefined ? never : T; + +export type Undefinable = T | undefined; + +function isNotUndefined(input: Undefinable): input is NotUndefined { + return input !== undefined; +} + +export function expectNotUndefined(input: Undefinable, msg: string): NotUndefined { + if (isNotUndefined(input)) { + return input; + } + + throw new TypeError(msg); +} + +export function unwrapUndefinable(input: Undefinable): NotUndefined { + return expectNotUndefined(input, `unwrapping \`undefined\``); +} diff --git a/editors/code/tsconfig.json b/editors/code/tsconfig.json index 3f887a41b3d7..12d31f0bee39 100644 --- a/editors/code/tsconfig.json +++ b/editors/code/tsconfig.json @@ -14,8 +14,7 @@ // to update typescript version without any code change. "useUnknownInCatchVariables": false, "exactOptionalPropertyTypes": false, - "noPropertyAccessFromIndexSignature": false, - "noUncheckedIndexedAccess": false + "noPropertyAccessFromIndexSignature": false }, "exclude": ["node_modules", ".vscode-test"], "include": ["src", "tests"] From f70845305f54181e1681828c7935305c66e743bb Mon Sep 17 00:00:00 2001 From: Tetsuharu Ohzeki Date: Wed, 28 Jun 2023 18:15:30 +0900 Subject: [PATCH 171/324] editor/code: Enable `noPropertyAccessFromIndexSignature` ts option --- editors/code/src/bootstrap.ts | 2 +- editors/code/src/config.ts | 4 ++-- editors/code/src/debug.ts | 5 +++-- editors/code/src/toolchain.ts | 2 +- editors/code/tests/unit/settings.test.ts | 2 +- editors/code/tsconfig.json | 3 +-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/editors/code/src/bootstrap.ts b/editors/code/src/bootstrap.ts index b38fa06a85cc..7b831a8a695c 100644 --- a/editors/code/src/bootstrap.ts +++ b/editors/code/src/bootstrap.ts @@ -36,7 +36,7 @@ async function getServer( config: Config, state: PersistentState ): Promise { - const explicitPath = process.env.__RA_LSP_SERVER_DEBUG ?? config.serverPath; + const explicitPath = process.env["__RA_LSP_SERVER_DEBUG"] ?? config.serverPath; if (explicitPath) { if (explicitPath.startsWith("~/")) { return os.homedir() + explicitPath.slice("~".length); diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index 9595ba052828..deea958f8dad 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts @@ -339,7 +339,7 @@ export function substituteVariablesInEnv(env: Env): Env { const depRe = new RegExp(/\${(?.+?)}/g); let match = undefined; while ((match = depRe.exec(value))) { - const depName = unwrapUndefinable(match.groups?.depName); + const depName = unwrapUndefinable(match.groups?.["depName"]); deps.add(depName); // `depName` at this point can have a form of `expression` or // `prefix:expression` @@ -448,7 +448,7 @@ function computeVscodeVar(varName: string): string | null { // https://github.com/microsoft/vscode/blob/08ac1bb67ca2459496b272d8f4a908757f24f56f/src/vs/workbench/api/common/extHostVariableResolverService.ts#L81 // or // https://github.com/microsoft/vscode/blob/29eb316bb9f154b7870eb5204ec7f2e7cf649bec/src/vs/server/node/remoteTerminalChannel.ts#L56 - execPath: () => process.env.VSCODE_EXEC_PATH ?? process.execPath, + execPath: () => process.env["VSCODE_EXEC_PATH"] ?? process.execPath, pathSeparator: () => path.sep, }; diff --git a/editors/code/src/debug.ts b/editors/code/src/debug.ts index ede90d707dd8..29758feafe4d 100644 --- a/editors/code/src/debug.ts +++ b/editors/code/src/debug.ts @@ -147,8 +147,9 @@ async function getDebugConfiguration( debugConfig.name = `run ${path.basename(executable)}`; } - if (debugConfig.cwd) { - debugConfig.cwd = simplifyPath(debugConfig.cwd); + const cwd = debugConfig["cwd"]; + if (cwd) { + debugConfig["cwd"] = simplifyPath(cwd); } return debugConfig; diff --git a/editors/code/src/toolchain.ts b/editors/code/src/toolchain.ts index b2c0c669db29..014e6b66f64d 100644 --- a/editors/code/src/toolchain.ts +++ b/editors/code/src/toolchain.ts @@ -176,7 +176,7 @@ export const getPathForExecutable = memoizeAsync( ); async function lookupInPath(exec: string): Promise { - const paths = process.env.PATH ?? ""; + const paths = process.env["PATH"] ?? ""; const candidates = paths.split(path.delimiter).flatMap((dirInPath) => { const candidate = path.join(dirInPath, exec); diff --git a/editors/code/tests/unit/settings.test.ts b/editors/code/tests/unit/settings.test.ts index 2cc1b670dc8f..f171f5f74f30 100644 --- a/editors/code/tests/unit/settings.test.ts +++ b/editors/code/tests/unit/settings.test.ts @@ -57,7 +57,7 @@ export async function getTests(ctx: Context) { USING_VSCODE_VAR: "${workspaceFolderBasename}", }; const actualEnv = await substituteVariablesInEnv(envJson); - assert.deepStrictEqual(actualEnv.USING_VSCODE_VAR, "code"); + assert.deepStrictEqual(actualEnv["USING_VSCODE_VAR"], "code"); }); }); } diff --git a/editors/code/tsconfig.json b/editors/code/tsconfig.json index 12d31f0bee39..4b107a5d2514 100644 --- a/editors/code/tsconfig.json +++ b/editors/code/tsconfig.json @@ -13,8 +13,7 @@ // These disables some enhancement type checking options // to update typescript version without any code change. "useUnknownInCatchVariables": false, - "exactOptionalPropertyTypes": false, - "noPropertyAccessFromIndexSignature": false + "exactOptionalPropertyTypes": false }, "exclude": ["node_modules", ".vscode-test"], "include": ["src", "tests"] From 1829d550acedeb067c8b3a7b4db6d5dd59277b14 Mon Sep 17 00:00:00 2001 From: Ali Bektas Date: Thu, 6 Jul 2023 10:57:38 +0200 Subject: [PATCH 172/324] Unify getter and setter assists --- ...getter.rs => generate_getter_or_setter.rs} | 438 +++++++++++++----- .../src/handlers/generate_setter.rs | 175 ------- crates/ide-assists/src/lib.rs | 9 +- crates/ide-assists/src/tests/generated.rs | 2 +- 4 files changed, 324 insertions(+), 300 deletions(-) rename crates/ide-assists/src/handlers/{generate_getter.rs => generate_getter_or_setter.rs} (61%) delete mode 100644 crates/ide-assists/src/handlers/generate_setter.rs diff --git a/crates/ide-assists/src/handlers/generate_getter.rs b/crates/ide-assists/src/handlers/generate_getter_or_setter.rs similarity index 61% rename from crates/ide-assists/src/handlers/generate_getter.rs rename to crates/ide-assists/src/handlers/generate_getter_or_setter.rs index dd6bbd84afcc..9c9478b040d1 100644 --- a/crates/ide-assists/src/handlers/generate_getter.rs +++ b/crates/ide-assists/src/handlers/generate_getter_or_setter.rs @@ -1,4 +1,4 @@ -use ide_db::famous_defs::FamousDefs; +use ide_db::{famous_defs::FamousDefs, source_change::SourceChangeBuilder}; use stdx::{format_to, to_lower_snake_case}; use syntax::{ ast::{self, AstNode, HasName, HasVisibility}, @@ -10,6 +10,66 @@ use crate::{ AssistContext, AssistId, AssistKind, Assists, GroupLabel, }; +// Assist: generate_setter +// +// Generate a setter method. +// +// ``` +// struct Person { +// nam$0e: String, +// } +// ``` +// -> +// ``` +// struct Person { +// name: String, +// } +// +// impl Person { +// fn $0set_name(&mut self, name: String) { +// self.name = name; +// } +// } +// ``` +pub(crate) fn generate_setter(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + // This if condition denotes two modes this assist can work in: + // - First is acting upon selection of record fields + // - Next is acting upon a single record field + // + // This is the only part where implementation diverges a bit, + // subsequent code is generic for both of these modes + + let (strukt, info_of_record_fields, mut fn_names) = extract_and_parse(ctx, AssistType::Set)?; + + // No record fields to do work on :( + if info_of_record_fields.len() == 0 { + return None; + } + + // Prepend set_ to fn names. + fn_names.iter_mut().for_each(|name| *name = format!("set_{}", name)); + + // Return early if we've found an existing fn + let impl_def = find_struct_impl(ctx, &ast::Adt::Struct(strukt.clone()), &fn_names)?; + + // Computing collective text range of all record fields in selected region + let target: TextRange = info_of_record_fields + .iter() + .map(|record_field_info| record_field_info.target) + .reduce(|acc, target| acc.cover(target))?; + + let setter_info = AssistInfo { impl_def, strukt, assist_type: AssistType::Set }; + + acc.add_group( + &GroupLabel("Generate getter/setter".to_owned()), + AssistId("generate_setter", AssistKind::Generate), + "Generate a setter method", + target, + |builder| build_source_change(builder, ctx, info_of_record_fields, setter_info), + ); + Some(()) +} + // Assist: generate_getter // // Generate a getter method. @@ -83,10 +143,16 @@ struct RecordFieldInfo { target: TextRange, } -struct GetterInfo { +struct AssistInfo { impl_def: Option, strukt: ast::Struct, - mutable: bool, + assist_type: AssistType, +} + +enum AssistType { + Get, + MutGet, + Set, } pub(crate) fn generate_getter_impl( @@ -94,40 +160,8 @@ pub(crate) fn generate_getter_impl( ctx: &AssistContext<'_>, mutable: bool, ) -> Option<()> { - // This if condition denotes two modes this assist can work in: - // - First is acting upon selection of record fields - // - Next is acting upon a single record field - // - // This is the only part where implementation diverges a bit, - // subsequent code is generic for both of these modes - - let (strukt, info_of_record_fields, fn_names) = if !ctx.has_empty_selection() { - // Selection Mode - let node = ctx.covering_element(); - - let node = match node { - syntax::NodeOrToken::Node(n) => n, - syntax::NodeOrToken::Token(t) => t.parent()?, - }; - - let parent_struct = node.ancestors().find_map(ast::Struct::cast)?; - - let (info_of_record_fields, field_names) = - extract_and_parse_record_fields(&parent_struct, ctx.selection_trimmed(), mutable)?; - - (parent_struct, info_of_record_fields, field_names) - } else { - // Single Record Field mode - let strukt = ctx.find_node_at_offset::()?; - let field = ctx.find_node_at_offset::()?; - - let record_field_info = parse_record_field(field, mutable)?; - - let fn_name = record_field_info.fn_name.clone(); - - (strukt, vec![record_field_info], vec![fn_name]) - }; - + let (strukt, info_of_record_fields, fn_names) = + extract_and_parse(ctx, if mutable { AssistType::MutGet } else { AssistType::Get })?; // No record fields to do work on :( if info_of_record_fields.len() == 0 { return None; @@ -147,98 +181,30 @@ pub(crate) fn generate_getter_impl( .map(|record_field_info| record_field_info.target) .reduce(|acc, target| acc.cover(target))?; - let getter_info = GetterInfo { impl_def, strukt, mutable }; + let getter_info = AssistInfo { + impl_def, + strukt, + assist_type: if mutable { AssistType::MutGet } else { AssistType::Get }, + }; acc.add_group( &GroupLabel("Generate getter/setter".to_owned()), AssistId(id, AssistKind::Generate), label, target, - |builder| { - let record_fields_count = info_of_record_fields.len(); - - let mut buf = String::with_capacity(512); - - // Check if an impl exists - if let Some(impl_def) = &getter_info.impl_def { - // Check if impl is empty - if let Some(assoc_item_list) = impl_def.assoc_item_list() { - if assoc_item_list.assoc_items().next().is_some() { - // If not empty then only insert a new line - buf.push('\n'); - } - } - } - - for (i, record_field_info) in info_of_record_fields.iter().enumerate() { - // this buf inserts a newline at the end of a getter - // automatically, if one wants to add one more newline - // for separating it from other assoc items, that needs - // to be handled separately - let mut getter_buf = - generate_getter_from_info(ctx, &getter_info, record_field_info); - - // Insert `$0` only for last getter we generate - if i == record_fields_count - 1 { - if ctx.config.snippet_cap.is_some() { - getter_buf = getter_buf.replacen("fn ", "fn $0", 1); - } - } - - // For first element we do not merge with '\n', as - // that can be inserted by impl_def check defined - // above, for other cases which are: - // - // - impl exists but it empty, here we would ideally - // not want to keep newline between impl { - // and fn () { line - // - // - next if impl itself does not exist, in this - // case we ourselves generate a new impl and that - // again ends up with the same reasoning as above - // for not keeping newline - if i == 0 { - buf = buf + &getter_buf; - } else { - buf = buf + "\n" + &getter_buf; - } - - // We don't insert a new line at the end of - // last getter as it will end up in the end - // of an impl where we would not like to keep - // getter and end of impl ( i.e. `}` ) with an - // extra line for no reason - if i < record_fields_count - 1 { - buf = buf + "\n"; - } - } - - let start_offset = getter_info - .impl_def - .as_ref() - .and_then(|impl_def| find_impl_block_end(impl_def.to_owned(), &mut buf)) - .unwrap_or_else(|| { - buf = generate_impl_text(&ast::Adt::Struct(getter_info.strukt.clone()), &buf); - getter_info.strukt.syntax().text_range().end() - }); - - match ctx.config.snippet_cap { - Some(cap) => builder.insert_snippet(cap, start_offset, buf), - None => builder.insert(start_offset, buf), - } - }, + |builder| build_source_change(builder, ctx, info_of_record_fields, getter_info), ) } fn generate_getter_from_info( ctx: &AssistContext<'_>, - info: &GetterInfo, + info: &AssistInfo, record_field_info: &RecordFieldInfo, ) -> String { let mut buf = String::with_capacity(512); let vis = info.strukt.visibility().map_or(String::new(), |v| format!("{v} ")); - let (ty, body) = if info.mutable { + let (ty, body) = if matches!(info.assist_type, AssistType::MutGet) { ( format!("&mut {}", record_field_info.field_ty), format!("&mut self.{}", record_field_info.field_name), @@ -273,7 +239,7 @@ fn generate_getter_from_info( }}", vis, record_field_info.fn_name, - info.mutable.then_some("mut ").unwrap_or_default(), + matches!(info.assist_type, AssistType::MutGet).then_some("mut ").unwrap_or_default(), ty, body, ); @@ -281,10 +247,58 @@ fn generate_getter_from_info( buf } +fn generate_setter_from_info(info: &AssistInfo, record_field_info: &RecordFieldInfo) -> String { + let mut buf = String::with_capacity(512); + let strukt = &info.strukt; + let fn_name = &record_field_info.fn_name; + let field_ty = &record_field_info.field_ty; + let vis = strukt.visibility().map_or(String::new(), |v| format!("{v} ")); + format_to!( + buf, + " {vis}fn set_{fn_name}(&mut self, {fn_name}: {field_ty}) {{ + self.{fn_name} = {fn_name}; + }}" + ); + + buf +} + +fn extract_and_parse( + ctx: &AssistContext<'_>, + assist_type: AssistType, +) -> Option<(ast::Struct, Vec, Vec)> { + // This if condition denotes two modes assists can work in: + // - First is acting upon selection of record fields + // - Next is acting upon a single record field + if !ctx.has_empty_selection() { + // Selection Mode + let node = ctx.covering_element(); + + let node = match node { + syntax::NodeOrToken::Node(n) => n, + syntax::NodeOrToken::Token(t) => t.parent()?, + }; + + let parent_struct = node.ancestors().find_map(ast::Struct::cast)?; + + let (info_of_record_fields, field_names) = + extract_and_parse_record_fields(&parent_struct, ctx.selection_trimmed(), &assist_type)?; + + return Some((parent_struct, info_of_record_fields, field_names)); + } + + // Single Record Field mode + let strukt = ctx.find_node_at_offset::()?; + let field = ctx.find_node_at_offset::()?; + let record_field_info = parse_record_field(field, &assist_type)?; + let fn_name = record_field_info.fn_name.clone(); + Some((strukt, vec![record_field_info], vec![fn_name])) +} + fn extract_and_parse_record_fields( node: &ast::Struct, selection_range: TextRange, - mutable: bool, + assist_type: &AssistType, ) -> Option<(Vec, Vec)> { let mut field_names: Vec = vec![]; let field_list = node.field_list()?; @@ -295,7 +309,7 @@ fn extract_and_parse_record_fields( .fields() .filter_map(|record_field| { if selection_range.contains_range(record_field.syntax().text_range()) { - let record_field_info = parse_record_field(record_field, mutable)?; + let record_field_info = parse_record_field(record_field, assist_type)?; field_names.push(record_field_info.fn_name.clone()); return Some(record_field_info); } @@ -316,12 +330,15 @@ fn extract_and_parse_record_fields( } } -fn parse_record_field(record_field: ast::RecordField, mutable: bool) -> Option { +fn parse_record_field( + record_field: ast::RecordField, + assist_type: &AssistType, +) -> Option { let field_name = record_field.name()?; let field_ty = record_field.ty()?; let mut fn_name = to_lower_snake_case(&field_name.to_string()); - if mutable { + if matches!(assist_type, AssistType::MutGet) { format_to!(fn_name, "_mut"); } @@ -330,8 +347,89 @@ fn parse_record_field(record_field: ast::RecordField, mutable: bool) -> Option, + info_of_record_fields: Vec, + assist_info: AssistInfo, +) { + let record_fields_count = info_of_record_fields.len(); + + let mut buf = String::with_capacity(512); + + // Check if an impl exists + if let Some(impl_def) = &assist_info.impl_def { + // Check if impl is empty + if let Some(assoc_item_list) = impl_def.assoc_item_list() { + if assoc_item_list.assoc_items().next().is_some() { + // If not empty then only insert a new line + buf.push('\n'); + } + } + } + + for (i, record_field_info) in info_of_record_fields.iter().enumerate() { + // this buf inserts a newline at the end of a getter + // automatically, if one wants to add one more newline + // for separating it from other assoc items, that needs + // to be handled separately + let mut getter_buf = match assist_info.assist_type { + AssistType::Set => generate_setter_from_info(&assist_info, record_field_info), + _ => generate_getter_from_info(ctx, &assist_info, record_field_info), + }; + + // Insert `$0` only for last getter we generate + if i == record_fields_count - 1 { + if ctx.config.snippet_cap.is_some() { + getter_buf = getter_buf.replacen("fn ", "fn $0", 1); + } + } + + // For first element we do not merge with '\n', as + // that can be inserted by impl_def check defined + // above, for other cases which are: + // + // - impl exists but it empty, here we would ideally + // not want to keep newline between impl { + // and fn () { line + // + // - next if impl itself does not exist, in this + // case we ourselves generate a new impl and that + // again ends up with the same reasoning as above + // for not keeping newline + if i == 0 { + buf = buf + &getter_buf; + } else { + buf = buf + "\n" + &getter_buf; + } + + // We don't insert a new line at the end of + // last getter as it will end up in the end + // of an impl where we would not like to keep + // getter and end of impl ( i.e. `}` ) with an + // extra line for no reason + if i < record_fields_count - 1 { + buf = buf + "\n"; + } + } + + let start_offset = assist_info + .impl_def + .as_ref() + .and_then(|impl_def| find_impl_block_end(impl_def.to_owned(), &mut buf)) + .unwrap_or_else(|| { + buf = generate_impl_text(&ast::Adt::Struct(assist_info.strukt.clone()), &buf); + assist_info.strukt.syntax().text_range().end() + }); + + match ctx.config.snippet_cap { + Some(cap) => builder.insert_snippet(cap, start_offset, buf), + None => builder.insert(start_offset, buf), + } +} + #[cfg(test)] -mod tests { +mod tests_getter { use crate::tests::{check_assist, check_assist_no_snippet_cap, check_assist_not_applicable}; use super::*; @@ -812,3 +910,105 @@ impl Context { ); } } + +#[cfg(test)] +mod tests_setter { + use crate::tests::{check_assist, check_assist_not_applicable}; + + use super::*; + + fn check_not_applicable(ra_fixture: &str) { + check_assist_not_applicable(generate_setter, ra_fixture) + } + + #[test] + fn test_generate_setter_from_field() { + check_assist( + generate_setter, + r#" +struct Person { + dat$0a: T, +}"#, + r#" +struct Person { + data: T, +} + +impl Person { + fn $0set_data(&mut self, data: T) { + self.data = data; + } +}"#, + ); + } + + #[test] + fn test_generate_setter_already_implemented() { + check_not_applicable( + r#" +struct Person { + dat$0a: T, +} + +impl Person { + fn set_data(&mut self, data: T) { + self.data = data; + } +}"#, + ); + } + + #[test] + fn test_generate_setter_from_field_with_visibility_marker() { + check_assist( + generate_setter, + r#" +pub(crate) struct Person { + dat$0a: T, +}"#, + r#" +pub(crate) struct Person { + data: T, +} + +impl Person { + pub(crate) fn $0set_data(&mut self, data: T) { + self.data = data; + } +}"#, + ); + } + + #[test] + fn test_multiple_generate_setter() { + check_assist( + generate_setter, + r#" +struct Context { + data: T, + cou$0nt: usize, +} + +impl Context { + fn set_data(&mut self, data: T) { + self.data = data; + } +}"#, + r#" +struct Context { + data: T, + count: usize, +} + +impl Context { + fn set_data(&mut self, data: T) { + self.data = data; + } + + fn $0set_count(&mut self, count: usize) { + self.count = count; + } +}"#, + ); + } +} diff --git a/crates/ide-assists/src/handlers/generate_setter.rs b/crates/ide-assists/src/handlers/generate_setter.rs deleted file mode 100644 index 62f72df1c9d6..000000000000 --- a/crates/ide-assists/src/handlers/generate_setter.rs +++ /dev/null @@ -1,175 +0,0 @@ -use stdx::{format_to, to_lower_snake_case}; -use syntax::ast::{self, AstNode, HasName, HasVisibility}; - -use crate::{ - utils::{find_impl_block_end, find_struct_impl, generate_impl_text}, - AssistContext, AssistId, AssistKind, Assists, GroupLabel, -}; - -// Assist: generate_setter -// -// Generate a setter method. -// -// ``` -// struct Person { -// nam$0e: String, -// } -// ``` -// -> -// ``` -// struct Person { -// name: String, -// } -// -// impl Person { -// fn set_name(&mut self, name: String) { -// self.name = name; -// } -// } -// ``` -pub(crate) fn generate_setter(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - let strukt = ctx.find_node_at_offset::()?; - let field = ctx.find_node_at_offset::()?; - - let field_name = field.name()?; - let field_ty = field.ty()?; - - // Return early if we've found an existing fn - let fn_name = to_lower_snake_case(&field_name.to_string()); - let impl_def = - find_struct_impl(ctx, &ast::Adt::Struct(strukt.clone()), &[format!("set_{fn_name}")])?; - - let target = field.syntax().text_range(); - acc.add_group( - &GroupLabel("Generate getter/setter".to_owned()), - AssistId("generate_setter", AssistKind::Generate), - "Generate a setter method", - target, - |builder| { - let mut buf = String::with_capacity(512); - - if impl_def.is_some() { - buf.push('\n'); - } - - let vis = strukt.visibility().map_or(String::new(), |v| format!("{v} ")); - format_to!( - buf, - " {vis}fn set_{fn_name}(&mut self, {fn_name}: {field_ty}) {{ - self.{fn_name} = {fn_name}; - }}" - ); - - let start_offset = impl_def - .and_then(|impl_def| find_impl_block_end(impl_def, &mut buf)) - .unwrap_or_else(|| { - buf = generate_impl_text(&ast::Adt::Struct(strukt.clone()), &buf); - strukt.syntax().text_range().end() - }); - - builder.insert(start_offset, buf); - }, - ) -} - -#[cfg(test)] -mod tests { - use crate::tests::{check_assist, check_assist_not_applicable}; - - use super::*; - - fn check_not_applicable(ra_fixture: &str) { - check_assist_not_applicable(generate_setter, ra_fixture) - } - - #[test] - fn test_generate_setter_from_field() { - check_assist( - generate_setter, - r#" -struct Person { - dat$0a: T, -}"#, - r#" -struct Person { - data: T, -} - -impl Person { - fn set_data(&mut self, data: T) { - self.data = data; - } -}"#, - ); - } - - #[test] - fn test_generate_setter_already_implemented() { - check_not_applicable( - r#" -struct Person { - dat$0a: T, -} - -impl Person { - fn set_data(&mut self, data: T) { - self.data = data; - } -}"#, - ); - } - - #[test] - fn test_generate_setter_from_field_with_visibility_marker() { - check_assist( - generate_setter, - r#" -pub(crate) struct Person { - dat$0a: T, -}"#, - r#" -pub(crate) struct Person { - data: T, -} - -impl Person { - pub(crate) fn set_data(&mut self, data: T) { - self.data = data; - } -}"#, - ); - } - - #[test] - fn test_multiple_generate_setter() { - check_assist( - generate_setter, - r#" -struct Context { - data: T, - cou$0nt: usize, -} - -impl Context { - fn set_data(&mut self, data: T) { - self.data = data; - } -}"#, - r#" -struct Context { - data: T, - count: usize, -} - -impl Context { - fn set_data(&mut self, data: T) { - self.data = data; - } - - fn set_count(&mut self, count: usize) { - self.count = count; - } -}"#, - ); - } -} diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs index dc0a69971ef7..f23bb73ffc86 100644 --- a/crates/ide-assists/src/lib.rs +++ b/crates/ide-assists/src/lib.rs @@ -154,11 +154,10 @@ mod handlers { mod generate_enum_variant; mod generate_from_impl_for_enum; mod generate_function; - mod generate_getter; + mod generate_getter_or_setter; mod generate_impl; mod generate_is_empty_from_len; mod generate_new; - mod generate_setter; mod generate_delegate_methods; mod add_return_type; mod inline_call; @@ -336,9 +335,9 @@ mod handlers { extract_function::extract_function, extract_module::extract_module, // - generate_getter::generate_getter, - generate_getter::generate_getter_mut, - generate_setter::generate_setter, + generate_getter_or_setter::generate_getter, + generate_getter_or_setter::generate_getter_mut, + generate_getter_or_setter::generate_setter, generate_delegate_methods::generate_delegate_methods, generate_deref::generate_deref, // diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index c6c70cc64a65..4492b48e418d 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -1492,7 +1492,7 @@ struct Person { } impl Person { - fn set_name(&mut self, name: String) { + fn $0set_name(&mut self, name: String) { self.name = name; } } From 827a0530bc1ec9ab6f3b990af65819deece0b824 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Thu, 6 Jul 2023 20:35:54 +0900 Subject: [PATCH 173/324] Don't show `unresolved-field` diagnostic for missing names --- crates/hir-expand/src/name.rs | 9 +++++++++ crates/hir-ty/src/infer/expr.rs | 7 +++++++ .../ide-diagnostics/src/handlers/unresolved_field.rs | 12 +++++++++++- 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/crates/hir-expand/src/name.rs b/crates/hir-expand/src/name.rs index 01e499f2ae83..0ffce333f1d9 100644 --- a/crates/hir-expand/src/name.rs +++ b/crates/hir-expand/src/name.rs @@ -96,6 +96,15 @@ impl Name { Name::new_inline("[missing name]") } + /// Returns true if this is a fake name for things missing in the source code. See + /// [`missing()`][Self::missing] for details. + /// + /// Use this method instead of comparing with `Self::missing()` as missing names + /// (ideally should) have a `gensym` semantics. + pub fn is_missing(&self) -> bool { + self == &Name::missing() + } + /// Generates a new name which is only equal to itself, by incrementing a counter. Due /// its implementation, it should not be used in things that salsa considers, like /// type names or field names, and it should be only used in names of local variables diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index 8377eb2349fb..fd9522e86af1 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -1449,6 +1449,13 @@ impl InferenceContext<'_> { fn infer_field_access(&mut self, tgt_expr: ExprId, receiver: ExprId, name: &Name) -> Ty { let receiver_ty = self.infer_expr_inner(receiver, &Expectation::none()); + + if name.is_missing() { + // Bail out early, don't even try to look up field. Also, we don't issue an unresolved + // field diagnostic because this is a syntax error rather than a semantic error. + return self.err_ty(); + } + match self.lookup_field(&receiver_ty, name) { Some((ty, field_id, adjustments, is_public)) => { self.write_expr_adj(receiver, adjustments); diff --git a/crates/ide-diagnostics/src/handlers/unresolved_field.rs b/crates/ide-diagnostics/src/handlers/unresolved_field.rs index 94d49d4d48b2..0758706e45a2 100644 --- a/crates/ide-diagnostics/src/handlers/unresolved_field.rs +++ b/crates/ide-diagnostics/src/handlers/unresolved_field.rs @@ -68,7 +68,10 @@ fn method_fix( } #[cfg(test)] mod tests { - use crate::tests::check_diagnostics; + use crate::{ + tests::{check_diagnostics, check_diagnostics_with_config}, + DiagnosticsConfig, + }; #[test] fn smoke_test() { @@ -146,4 +149,11 @@ fn foo() { "#, ); } + + #[test] + fn no_diagnostic_for_missing_name() { + let mut config = DiagnosticsConfig::test_sample(); + config.disabled.insert("syntax-error".to_owned()); + check_diagnostics_with_config(config, "fn foo() { (). }"); + } } From 171ae2ee5d3256ac59412138a5566515cd785252 Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Thu, 6 Jul 2023 15:41:52 +0330 Subject: [PATCH 174/324] Fix size_of_val and support min_align_of_val --- crates/hir-expand/src/name.rs | 5 + crates/hir-ty/src/consteval/tests.rs | 14 -- .../hir-ty/src/consteval/tests/intrinsics.rs | 75 ++++++++ crates/hir-ty/src/layout/adt.rs | 2 +- crates/hir-ty/src/mir/eval/shim.rs | 162 +++++++++++------- crates/hir-ty/src/mir/eval/shim/simd.rs | 50 ++++-- crates/ide/src/hover/tests.rs | 2 +- 7 files changed, 221 insertions(+), 89 deletions(-) diff --git a/crates/hir-expand/src/name.rs b/crates/hir-expand/src/name.rs index 01e499f2ae83..581ac40eb405 100644 --- a/crates/hir-expand/src/name.rs +++ b/crates/hir-expand/src/name.rs @@ -282,8 +282,10 @@ pub mod known { alloc, iter, ops, + fmt, future, result, + string, boxed, option, prelude, @@ -311,6 +313,7 @@ pub mod known { RangeToInclusive, RangeTo, Range, + String, Neg, Not, None, @@ -321,6 +324,7 @@ pub mod known { iter_mut, len, is_empty, + as_str, new, // Builtin macros asm, @@ -334,6 +338,7 @@ pub mod known { core_panic, env, file, + format, format_args_nl, format_args, global_asm, diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs index c37c5912f280..d5feb6c7fefd 100644 --- a/crates/hir-ty/src/consteval/tests.rs +++ b/crates/hir-ty/src/consteval/tests.rs @@ -2456,20 +2456,6 @@ fn const_trait_assoc() { ); } -#[test] -fn panic_messages() { - check_fail( - r#" - //- minicore: panic - const GOAL: u8 = { - let x: u16 = 2; - panic!("hello"); - }; - "#, - |e| e == ConstEvalError::MirEvalError(MirEvalError::Panic("hello".to_string())), - ); -} - #[test] fn exec_limits() { check_fail( diff --git a/crates/hir-ty/src/consteval/tests/intrinsics.rs b/crates/hir-ty/src/consteval/tests/intrinsics.rs index bb8fca178a28..f51aceb87a8d 100644 --- a/crates/hir-ty/src/consteval/tests/intrinsics.rs +++ b/crates/hir-ty/src/consteval/tests/intrinsics.rs @@ -43,6 +43,50 @@ fn size_of_val() { "#, 12, ); + check_number( + r#" + //- minicore: coerce_unsized, transmute + use core::mem::transmute; + + extern "rust-intrinsic" { + pub fn size_of_val(_: *const T) -> usize; + } + + struct X { + x: i64, + y: u8, + t: [i32], + } + + const GOAL: usize = unsafe { + let y: &X = transmute([0usize, 3]); + size_of_val(y) + }; + "#, + 24, + ); + check_number( + r#" + //- minicore: coerce_unsized, transmute + use core::mem::transmute; + + extern "rust-intrinsic" { + pub fn size_of_val(_: *const T) -> usize; + } + + struct X { + x: i32, + y: i64, + t: [u8], + } + + const GOAL: usize = unsafe { + let y: &X = transmute([0usize, 15]); + size_of_val(y) + }; + "#, + 32, + ); check_number( r#" //- minicore: coerce_unsized, fmt, builtin_impls @@ -74,6 +118,37 @@ fn size_of_val() { ); } +#[test] +fn min_align_of_val() { + check_number( + r#" + //- minicore: coerce_unsized + extern "rust-intrinsic" { + pub fn min_align_of_val(_: *const T) -> usize; + } + + struct X(i32, u8); + + const GOAL: usize = min_align_of_val(&X(1, 2)); + "#, + 4, + ); + check_number( + r#" + //- minicore: coerce_unsized + extern "rust-intrinsic" { + pub fn min_align_of_val(_: *const T) -> usize; + } + + const GOAL: usize = { + let x: &[i32] = &[1, 2, 3]; + min_align_of_val(x) + }; + "#, + 4, + ); +} + #[test] fn transmute() { check_number( diff --git a/crates/hir-ty/src/layout/adt.rs b/crates/hir-ty/src/layout/adt.rs index 0012b4179d77..186b8e2bc68d 100644 --- a/crates/hir-ty/src/layout/adt.rs +++ b/crates/hir-ty/src/layout/adt.rs @@ -105,7 +105,7 @@ pub fn layout_of_adt_query( && variants .iter() .next() - .and_then(|x| x.last().map(|x| x.is_unsized())) + .and_then(|x| x.last().map(|x| !x.is_unsized())) .unwrap_or(true), ) .ok_or(LayoutError::SizeOverflow)? diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs index 73ed52f3b325..8fc93c85d8cd 100644 --- a/crates/hir-ty/src/mir/eval/shim.rs +++ b/crates/hir-ty/src/mir/eval/shim.rs @@ -3,6 +3,10 @@ use std::cmp; +use chalk_ir::TyKind; +use hir_def::resolver::HasResolver; +use hir_expand::mod_path::ModPath; + use super::*; mod simd; @@ -186,44 +190,24 @@ impl Evaluator<'_> { BeginPanic => Err(MirEvalError::Panic("".to_string())), PanicFmt => { let message = (|| { - let arguments_struct = - self.db.lang_item(self.crate_id, LangItem::FormatArguments)?.as_struct()?; - let arguments_layout = self - .layout_adt(arguments_struct.into(), Substitution::empty(Interner)) - .ok()?; - let arguments_field_pieces = - self.db.struct_data(arguments_struct).variant_data.field(&name![pieces])?; - let pieces_offset = arguments_layout - .fields - .offset(u32::from(arguments_field_pieces.into_raw()) as usize) - .bytes_usize(); - let ptr_size = self.ptr_size(); - let arg = args.next()?; - let pieces_array_addr = - Address::from_bytes(&arg[pieces_offset..pieces_offset + ptr_size]).ok()?; - let pieces_array_len = usize::from_le_bytes( - (&arg[pieces_offset + ptr_size..pieces_offset + 2 * ptr_size]) - .try_into() - .ok()?, - ); - let mut message = "".to_string(); - for i in 0..pieces_array_len { - let piece_ptr_addr = pieces_array_addr.offset(2 * i * ptr_size); - let piece_addr = - Address::from_bytes(self.read_memory(piece_ptr_addr, ptr_size).ok()?) - .ok()?; - let piece_len = usize::from_le_bytes( - self.read_memory(piece_ptr_addr.offset(ptr_size), ptr_size) - .ok()? - .try_into() - .ok()?, - ); - let piece_data = self.read_memory(piece_addr, piece_len).ok()?; - message += &std::string::String::from_utf8_lossy(piece_data); - } - Some(message) + let x = self.db.crate_def_map(self.crate_id).crate_root(); + let resolver = x.resolver(self.db.upcast()); + let Some(format_fn) = resolver.resolve_path_in_value_ns_fully( + self.db.upcast(), + &hir_def::path::Path::from_known_path_with_no_generic(ModPath::from_segments( + hir_expand::mod_path::PathKind::Abs, + [name![std], name![fmt], name![format]].into_iter(), + )), + ) else { + not_supported!("std::fmt::format not found"); + }; + let hir_def::resolver::ValueNs::FunctionId(format_fn) = format_fn else { not_supported!("std::fmt::format is not a function") }; + let message_string = self.interpret_mir(&*self.db.mir_body(format_fn.into()).map_err(|e| MirEvalError::MirLowerError(format_fn, e))?, args.cloned())?; + let addr = Address::from_bytes(&message_string[self.ptr_size()..2 * self.ptr_size()])?; + let size = from_bytes!(usize, message_string[2 * self.ptr_size()..]); + Ok(std::string::String::from_utf8_lossy(self.read_memory(addr, size)?).into_owned()) })() - .unwrap_or_else(|| "".to_string()); + .unwrap_or_else(|e| format!("Failed to render panic format args: {e:?}")); Err(MirEvalError::Panic(message)) } SliceLen => { @@ -544,6 +528,13 @@ impl Evaluator<'_> { let size = self.size_of_sized(ty, locals, "size_of arg")?; destination.write_from_bytes(self, &size.to_le_bytes()[0..destination.size]) } + "min_align_of" | "pref_align_of" => { + let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) else { + return Err(MirEvalError::TypeError("align_of generic arg is not provided")); + }; + let align = self.layout(ty)?.align.abi.bytes(); + destination.write_from_bytes(self, &align.to_le_bytes()[0..destination.size]) + } "size_of_val" => { let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) else { @@ -552,33 +543,28 @@ impl Evaluator<'_> { let [arg] = args else { return Err(MirEvalError::TypeError("size_of_val args are not provided")); }; - let metadata = arg.interval.slice(self.ptr_size()..self.ptr_size() * 2); - let size = match ty.kind(Interner) { - TyKind::Str => return destination.write_from_interval(self, metadata), - TyKind::Slice(inner) => { - let len = from_bytes!(usize, metadata.get(self)?); - len * self.size_of_sized(inner, locals, "slice inner type")? - } - TyKind::Dyn(_) => self.size_of_sized( - self.vtable_map.ty_of_bytes(metadata.get(self)?)?, - locals, - "dyn concrete type", - )?, - _ => self.size_of_sized( - ty, - locals, - "unsized type other than str, slice, and dyn", - )?, - }; - destination.write_from_bytes(self, &size.to_le_bytes()) + if let Some((size, _)) = self.size_align_of(ty, locals)? { + destination.write_from_bytes(self, &size.to_le_bytes()) + } else { + let metadata = arg.interval.slice(self.ptr_size()..self.ptr_size() * 2); + let (size, _) = self.size_align_of_unsized(ty, metadata, locals)?; + destination.write_from_bytes(self, &size.to_le_bytes()) + } } - "min_align_of" | "pref_align_of" => { - let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) - else { - return Err(MirEvalError::TypeError("align_of generic arg is not provided")); + "min_align_of_val" => { + let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) else { + return Err(MirEvalError::TypeError("min_align_of_val generic arg is not provided")); }; - let align = self.layout(ty)?.align.abi.bytes(); - destination.write_from_bytes(self, &align.to_le_bytes()[0..destination.size]) + let [arg] = args else { + return Err(MirEvalError::TypeError("min_align_of_val args are not provided")); + }; + if let Some((_, align)) = self.size_align_of(ty, locals)? { + destination.write_from_bytes(self, &align.to_le_bytes()) + } else { + let metadata = arg.interval.slice(self.ptr_size()..self.ptr_size() * 2); + let (_, align) = self.size_align_of_unsized(ty, metadata, locals)?; + destination.write_from_bytes(self, &align.to_le_bytes()) + } } "needs_drop" => { let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) @@ -905,6 +891,58 @@ impl Evaluator<'_> { } } + fn size_align_of_unsized( + &mut self, + ty: &Ty, + metadata: Interval, + locals: &Locals<'_>, + ) -> Result<(usize, usize)> { + Ok(match ty.kind(Interner) { + TyKind::Str => (from_bytes!(usize, metadata.get(self)?), 1), + TyKind::Slice(inner) => { + let len = from_bytes!(usize, metadata.get(self)?); + let (size, align) = self.size_align_of_sized(inner, locals, "slice inner type")?; + (size * len, align) + } + TyKind::Dyn(_) => self.size_align_of_sized( + self.vtable_map.ty_of_bytes(metadata.get(self)?)?, + locals, + "dyn concrete type", + )?, + TyKind::Adt(id, subst) => { + let id = id.0; + let layout = self.layout_adt(id, subst.clone())?; + let id = match id { + AdtId::StructId(s) => s, + _ => not_supported!("unsized enum or union"), + }; + let field_types = &self.db.field_types(id.into()); + let last_field_ty = + field_types.iter().rev().next().unwrap().1.clone().substitute(Interner, subst); + let sized_part_size = + layout.fields.offset(field_types.iter().count() - 1).bytes_usize(); + let sized_part_align = layout.align.abi.bytes() as usize; + let (unsized_part_size, unsized_part_align) = + self.size_align_of_unsized(&last_field_ty, metadata, locals)?; + let align = sized_part_align.max(unsized_part_align) as isize; + let size = (sized_part_size + unsized_part_size) as isize; + // Must add any necessary padding to `size` + // (to make it a multiple of `align`) before returning it. + // + // Namely, the returned size should be, in C notation: + // + // `size + ((size & (align-1)) ? align : 0)` + // + // emulated via the semi-standard fast bit trick: + // + // `(size + (align-1)) & -align` + let size = (size + (align - 1)) & (-align); + (size as usize, align as usize) + } + _ => not_supported!("unsized type other than str, slice, struct and dyn"), + }) + } + fn exec_atomic_intrinsic( &mut self, name: &str, diff --git a/crates/hir-ty/src/mir/eval/shim/simd.rs b/crates/hir-ty/src/mir/eval/shim/simd.rs index 89b04eb36bb0..8ba6e18b9a51 100644 --- a/crates/hir-ty/src/mir/eval/shim/simd.rs +++ b/crates/hir-ty/src/mir/eval/shim/simd.rs @@ -1,5 +1,7 @@ //! Shim implementation for simd intrinsics +use std::cmp::Ordering; + use crate::TyKind; use super::*; @@ -22,10 +24,15 @@ macro_rules! not_supported { impl Evaluator<'_> { fn detect_simd_ty(&self, ty: &Ty) -> Result { match ty.kind(Interner) { - TyKind::Adt(_, subst) => { - let Some(len) = subst.as_slice(Interner).get(1).and_then(|x| x.constant(Interner)) - else { - return Err(MirEvalError::TypeError("simd type without len param")); + TyKind::Adt(id, subst) => { + let len = match subst.as_slice(Interner).get(1).and_then(|x| x.constant(Interner)) { + Some(len) => len, + _ => { + if let AdtId::StructId(id) = id.0 { + return Ok(self.db.struct_data(id).variant_data.fields().len()); + } + return Err(MirEvalError::TypeError("simd type with no len param")); + } }; match try_const_usize(self.db, len) { Some(x) => Ok(x as usize), @@ -63,13 +70,34 @@ impl Evaluator<'_> { .collect::>(); destination.write_from_bytes(self, &result) } - "eq" | "ne" => { + "eq" | "ne" | "lt" | "le" | "gt" | "ge" => { let [left, right] = args else { - return Err(MirEvalError::TypeError("simd_eq args are not provided")); + return Err(MirEvalError::TypeError("simd args are not provided")); }; - let result = left.get(self)? == right.get(self)?; - let result = result ^ (name == "ne"); - destination.write_from_bytes(self, &[u8::from(result)]) + let len = self.detect_simd_ty(&left.ty)?; + let size = left.interval.size / len; + let dest_size = destination.size / len; + let mut destination_bytes = vec![]; + let vector = left.get(self)?.chunks(size).zip(right.get(self)?.chunks(size)); + for (l, r) in vector { + let mut result = Ordering::Equal; + for (l, r) in l.iter().zip(r).rev() { + let x = l.cmp(r); + if x != Ordering::Equal { + result = x; + break; + } + } + let result = match result { + Ordering::Less => ["lt", "le", "ne"].contains(&name), + Ordering::Equal => ["ge", "le", "eq"].contains(&name), + Ordering::Greater => ["ge", "gt", "ne"].contains(&name), + }; + let result = if result { 255 } else { 0 }; + destination_bytes.extend(std::iter::repeat(result).take(dest_size)); + } + + destination.write_from_bytes(self, &destination_bytes) } "bitmask" => { let [op] = args else { @@ -103,9 +131,9 @@ impl Evaluator<'_> { } }; let left_len = self.detect_simd_ty(&left.ty)?; - let left_count = left.interval.size / left_len; + let left_size = left.interval.size / left_len; let vector = - left.get(self)?.chunks(left_count).chain(right.get(self)?.chunks(left_count)); + left.get(self)?.chunks(left_size).chain(right.get(self)?.chunks(left_size)); let mut result = vec![]; for index in index.get(self)?.chunks(index.interval.size / index_len) { let index = from_bytes!(u32, index) as usize; diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index 2070386e9844..00e21433daae 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -674,7 +674,7 @@ struct Foo { fiel$0d_a: u8, field_b: i32, field_c: i16 } ``` ```rust - field_a: u8 // size = 1, align = 1, offset = 4 + field_a: u8 // size = 1, align = 1, offset = 6 ``` "#]], ); From 3a1054fc1c76a51b7195bf146f856270b32cc2e7 Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Thu, 6 Jul 2023 17:33:17 +0330 Subject: [PATCH 175/324] Replace `x` with `it` --- crates/base-db/src/fixture.rs | 2 +- crates/cfg/src/lib.rs | 4 +- crates/hir-def/src/attr.rs | 8 +- crates/hir-def/src/body.rs | 4 +- crates/hir-def/src/body/lower.rs | 28 +-- crates/hir-def/src/generics.rs | 16 +- crates/hir-def/src/hir/type_ref.rs | 4 +- crates/hir-def/src/lib.rs | 84 +++---- crates/hir-def/src/path.rs | 2 +- crates/hir-def/src/pretty.rs | 4 +- crates/hir-def/src/resolver.rs | 48 ++-- crates/hir-expand/src/builtin_derive_macro.rs | 84 +++---- crates/hir-expand/src/builtin_fn_macro.rs | 10 +- crates/hir-expand/src/fixup.rs | 12 +- crates/hir-ty/src/chalk_ext.rs | 2 +- crates/hir-ty/src/consteval.rs | 8 +- .../hir-ty/src/consteval/tests/intrinsics.rs | 4 +- crates/hir-ty/src/display.rs | 33 +-- crates/hir-ty/src/infer.rs | 6 +- crates/hir-ty/src/infer/closure.rs | 50 ++-- crates/hir-ty/src/infer/expr.rs | 2 +- crates/hir-ty/src/infer/mutability.rs | 14 +- crates/hir-ty/src/infer/pat.rs | 2 +- crates/hir-ty/src/infer/unify.rs | 8 +- crates/hir-ty/src/layout.rs | 16 +- crates/hir-ty/src/layout/adt.rs | 12 +- crates/hir-ty/src/method_resolution.rs | 16 +- crates/hir-ty/src/mir/borrowck.rs | 14 +- crates/hir-ty/src/mir/eval.rs | 234 +++++++++--------- crates/hir-ty/src/mir/eval/shim.rs | 53 ++-- crates/hir-ty/src/mir/eval/shim/simd.rs | 31 +-- crates/hir-ty/src/mir/lower.rs | 123 ++++----- crates/hir-ty/src/mir/lower/as_place.rs | 18 +- crates/hir-ty/src/mir/monomorphization.rs | 22 +- crates/hir-ty/src/mir/pretty.rs | 38 +-- crates/hir/src/display.rs | 8 +- crates/hir/src/lib.rs | 44 ++-- crates/hir/src/semantics/source_to_def.rs | 7 +- crates/ide-completion/src/context/analysis.rs | 2 +- crates/ide/src/hover/render.rs | 8 +- crates/ide/src/static_index.rs | 53 ++-- crates/rust-analyzer/src/cli/lsif.rs | 34 +-- 42 files changed, 590 insertions(+), 582 deletions(-) diff --git a/crates/base-db/src/fixture.rs b/crates/base-db/src/fixture.rs index 1aa7b92645c8..6bfdf402c448 100644 --- a/crates/base-db/src/fixture.rs +++ b/crates/base-db/src/fixture.rs @@ -224,7 +224,7 @@ impl ChangeFixture { false, CrateOrigin::Local { repo: None, name: None }, default_target_data_layout - .map(|x| x.into()) + .map(|it| it.into()) .ok_or_else(|| "target_data_layout unset".into()), Some(toolchain), ); diff --git a/crates/cfg/src/lib.rs b/crates/cfg/src/lib.rs index 495119d5519c..183b9b7d278c 100644 --- a/crates/cfg/src/lib.rs +++ b/crates/cfg/src/lib.rs @@ -69,7 +69,7 @@ impl CfgOptions { } pub fn get_cfg_keys(&self) -> impl Iterator { - self.enabled.iter().map(|x| match x { + self.enabled.iter().map(|it| match it { CfgAtom::Flag(key) => key, CfgAtom::KeyValue { key, .. } => key, }) @@ -79,7 +79,7 @@ impl CfgOptions { &'a self, cfg_key: &'a str, ) -> impl Iterator + 'a { - self.enabled.iter().filter_map(move |x| match x { + self.enabled.iter().filter_map(move |it| match it { CfgAtom::KeyValue { key, value } if cfg_key == key => Some(value), _ => None, }) diff --git a/crates/hir-def/src/attr.rs b/crates/hir-def/src/attr.rs index a16670b244a8..c29446d8235a 100644 --- a/crates/hir-def/src/attr.rs +++ b/crates/hir-def/src/attr.rs @@ -276,13 +276,13 @@ impl Attrs { } pub fn is_test(&self) -> bool { - self.iter().any(|x| { - x.path() + self.iter().any(|it| { + it.path() .segments() .iter() .rev() .zip(["core", "prelude", "v1", "test"].iter().rev()) - .all(|x| x.0.as_str() == Some(x.1)) + .all(|it| it.0.as_str() == Some(it.1)) }) } @@ -304,7 +304,7 @@ use std::slice::Iter as SliceIter; pub enum DocAtom { /// eg. `#[doc(hidden)]` Flag(SmolStr), - /// eg. `#[doc(alias = "x")]` + /// eg. `#[doc(alias = "it")]` /// /// Note that a key can have multiple values that are all considered "active" at the same time. /// For example, `#[doc(alias = "x")]` and `#[doc(alias = "y")]`. diff --git a/crates/hir-def/src/body.rs b/crates/hir-def/src/body.rs index 94dc39b11755..f8d492d0e525 100644 --- a/crates/hir-def/src/body.rs +++ b/crates/hir-def/src/body.rs @@ -273,10 +273,10 @@ impl Body { pub fn is_binding_upvar(&self, binding: BindingId, relative_to: ExprId) -> bool { match self.binding_owners.get(&binding) { - Some(x) => { + Some(it) => { // We assign expression ids in a way that outer closures will receive // a lower id - x.into_raw() < relative_to.into_raw() + it.into_raw() < relative_to.into_raw() } None => true, } diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs index b89eb9fe6238..152c02743f77 100644 --- a/crates/hir-def/src/body/lower.rs +++ b/crates/hir-def/src/body/lower.rs @@ -297,11 +297,11 @@ impl ExprCollector<'_> { let (result_expr_id, prev_binding_owner) = this.initialize_binding_owner(syntax_ptr); let inner_expr = this.collect_block(e); - let x = this.db.intern_anonymous_const(ConstBlockLoc { + let it = this.db.intern_anonymous_const(ConstBlockLoc { parent: this.owner, root: inner_expr, }); - this.body.exprs[result_expr_id] = Expr::Const(x); + this.body.exprs[result_expr_id] = Expr::Const(it); this.current_binding_owner = prev_binding_owner; result_expr_id }) @@ -324,10 +324,10 @@ impl ExprCollector<'_> { ast::Expr::CallExpr(e) => { let is_rustc_box = { let attrs = e.attrs(); - attrs.filter_map(|x| x.as_simple_atom()).any(|x| x == "rustc_box") + attrs.filter_map(|it| it.as_simple_atom()).any(|it| it == "rustc_box") }; if is_rustc_box { - let expr = self.collect_expr_opt(e.arg_list().and_then(|x| x.args().next())); + let expr = self.collect_expr_opt(e.arg_list().and_then(|it| it.args().next())); self.alloc_expr(Expr::Box { expr }, syntax_ptr) } else { let callee = self.collect_expr_opt(e.expr()); @@ -781,7 +781,7 @@ impl ExprCollector<'_> { pat: self.alloc_pat_desugared(some_pat), guard: None, expr: self.with_opt_labeled_rib(label, |this| { - this.collect_expr_opt(e.loop_body().map(|x| x.into())) + this.collect_expr_opt(e.loop_body().map(|it| it.into())) }), }; let iter_name = Name::generate_new_name(); @@ -874,10 +874,10 @@ impl ExprCollector<'_> { }), guard: None, expr: { - let x = self.alloc_expr(Expr::Path(Path::from(break_name)), syntax_ptr.clone()); + let it = self.alloc_expr(Expr::Path(Path::from(break_name)), syntax_ptr.clone()); let callee = self.alloc_expr(Expr::Path(try_from_residual), syntax_ptr.clone()); let result = self.alloc_expr( - Expr::Call { callee, args: Box::new([x]), is_assignee_expr: false }, + Expr::Call { callee, args: Box::new([it]), is_assignee_expr: false }, syntax_ptr.clone(), ); self.alloc_expr( @@ -1240,12 +1240,12 @@ impl ExprCollector<'_> { pats.push(self.collect_pat(first, binding_list)); binding_list.reject_new = true; for rest in it { - for (_, x) in binding_list.is_used.iter_mut() { - *x = false; + for (_, it) in binding_list.is_used.iter_mut() { + *it = false; } pats.push(self.collect_pat(rest, binding_list)); - for (&id, &x) in binding_list.is_used.iter() { - if !x { + for (&id, &is_used) in binding_list.is_used.iter() { + if !is_used { self.body.bindings[id].problems = Some(BindingProblems::NotBoundAcrossAll); } @@ -1352,9 +1352,9 @@ impl ExprCollector<'_> { // FIXME: implement in a way that also builds source map and calculates assoc resolutions in type inference. ast::Pat::RangePat(p) => { let mut range_part_lower = |p: Option| { - p.and_then(|x| match &x { - ast::Pat::LiteralPat(x) => { - Some(Box::new(LiteralOrConst::Literal(pat_literal_to_hir(x)?.0))) + p.and_then(|it| match &it { + ast::Pat::LiteralPat(it) => { + Some(Box::new(LiteralOrConst::Literal(pat_literal_to_hir(it)?.0))) } ast::Pat::IdentPat(p) => { let name = diff --git a/crates/hir-def/src/generics.rs b/crates/hir-def/src/generics.rs index f19c3f028f42..d7d44e413880 100644 --- a/crates/hir-def/src/generics.rs +++ b/crates/hir-def/src/generics.rs @@ -67,21 +67,21 @@ pub enum TypeOrConstParamData { impl TypeOrConstParamData { pub fn name(&self) -> Option<&Name> { match self { - TypeOrConstParamData::TypeParamData(x) => x.name.as_ref(), - TypeOrConstParamData::ConstParamData(x) => Some(&x.name), + TypeOrConstParamData::TypeParamData(it) => it.name.as_ref(), + TypeOrConstParamData::ConstParamData(it) => Some(&it.name), } } pub fn has_default(&self) -> bool { match self { - TypeOrConstParamData::TypeParamData(x) => x.default.is_some(), - TypeOrConstParamData::ConstParamData(x) => x.has_default, + TypeOrConstParamData::TypeParamData(it) => it.default.is_some(), + TypeOrConstParamData::ConstParamData(it) => it.has_default, } } pub fn type_param(&self) -> Option<&TypeParamData> { match self { - TypeOrConstParamData::TypeParamData(x) => Some(x), + TypeOrConstParamData::TypeParamData(it) => Some(it), TypeOrConstParamData::ConstParamData(_) => None, } } @@ -89,14 +89,14 @@ impl TypeOrConstParamData { pub fn const_param(&self) -> Option<&ConstParamData> { match self { TypeOrConstParamData::TypeParamData(_) => None, - TypeOrConstParamData::ConstParamData(x) => Some(x), + TypeOrConstParamData::ConstParamData(it) => Some(it), } } pub fn is_trait_self(&self) -> bool { match self { - TypeOrConstParamData::TypeParamData(x) => { - x.provenance == TypeParamProvenance::TraitSelf + TypeOrConstParamData::TypeParamData(it) => { + it.provenance == TypeParamProvenance::TraitSelf } TypeOrConstParamData::ConstParamData(_) => false, } diff --git a/crates/hir-def/src/hir/type_ref.rs b/crates/hir-def/src/hir/type_ref.rs index fa1f4933a266..57f023ef35d4 100644 --- a/crates/hir-def/src/hir/type_ref.rs +++ b/crates/hir-def/src/hir/type_ref.rs @@ -425,8 +425,8 @@ impl ConstRef { } match expr { ast::Expr::PathExpr(p) if is_path_ident(&p) => { - match p.path().and_then(|x| x.segment()).and_then(|x| x.name_ref()) { - Some(x) => Self::Path(x.as_name()), + match p.path().and_then(|it| it.segment()).and_then(|it| it.name_ref()) { + Some(it) => Self::Path(it.as_name()), None => Self::Scalar(LiteralConstRef::Unknown), } } diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index c0701e2576a1..1e74e2dfcb4c 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -406,14 +406,14 @@ impl TypeParamId { impl TypeParamId { /// Caller should check if this toc id really belongs to a type - pub fn from_unchecked(x: TypeOrConstParamId) -> Self { - Self(x) + pub fn from_unchecked(it: TypeOrConstParamId) -> Self { + Self(it) } } impl From for TypeOrConstParamId { - fn from(x: TypeParamId) -> Self { - x.0 + fn from(it: TypeParamId) -> Self { + it.0 } } @@ -432,14 +432,14 @@ impl ConstParamId { impl ConstParamId { /// Caller should check if this toc id really belongs to a const - pub fn from_unchecked(x: TypeOrConstParamId) -> Self { - Self(x) + pub fn from_unchecked(it: TypeOrConstParamId) -> Self { + Self(it) } } impl From for TypeOrConstParamId { - fn from(x: ConstParamId) -> Self { - x.0 + fn from(it: ConstParamId) -> Self { + it.0 } } @@ -562,14 +562,14 @@ pub enum TypeOwnerId { impl TypeOwnerId { fn as_generic_def_id(self) -> Option { Some(match self { - TypeOwnerId::FunctionId(x) => GenericDefId::FunctionId(x), - TypeOwnerId::ConstId(x) => GenericDefId::ConstId(x), - TypeOwnerId::AdtId(x) => GenericDefId::AdtId(x), - TypeOwnerId::TraitId(x) => GenericDefId::TraitId(x), - TypeOwnerId::TraitAliasId(x) => GenericDefId::TraitAliasId(x), - TypeOwnerId::TypeAliasId(x) => GenericDefId::TypeAliasId(x), - TypeOwnerId::ImplId(x) => GenericDefId::ImplId(x), - TypeOwnerId::EnumVariantId(x) => GenericDefId::EnumVariantId(x), + TypeOwnerId::FunctionId(it) => GenericDefId::FunctionId(it), + TypeOwnerId::ConstId(it) => GenericDefId::ConstId(it), + TypeOwnerId::AdtId(it) => GenericDefId::AdtId(it), + TypeOwnerId::TraitId(it) => GenericDefId::TraitId(it), + TypeOwnerId::TraitAliasId(it) => GenericDefId::TraitAliasId(it), + TypeOwnerId::TypeAliasId(it) => GenericDefId::TypeAliasId(it), + TypeOwnerId::ImplId(it) => GenericDefId::ImplId(it), + TypeOwnerId::EnumVariantId(it) => GenericDefId::EnumVariantId(it), TypeOwnerId::InTypeConstId(_) | TypeOwnerId::ModuleId(_) | TypeOwnerId::StaticId(_) => { return None } @@ -592,15 +592,15 @@ impl_from!( for TypeOwnerId ); -// Every `DefWithBodyId` is a type owner, since bodies can contain type (e.g. `{ let x: Type = _; }`) +// Every `DefWithBodyId` is a type owner, since bodies can contain type (e.g. `{ let it: Type = _; }`) impl From for TypeOwnerId { fn from(value: DefWithBodyId) -> Self { match value { - DefWithBodyId::FunctionId(x) => x.into(), - DefWithBodyId::StaticId(x) => x.into(), - DefWithBodyId::ConstId(x) => x.into(), - DefWithBodyId::InTypeConstId(x) => x.into(), - DefWithBodyId::VariantId(x) => x.into(), + DefWithBodyId::FunctionId(it) => it.into(), + DefWithBodyId::StaticId(it) => it.into(), + DefWithBodyId::ConstId(it) => it.into(), + DefWithBodyId::InTypeConstId(it) => it.into(), + DefWithBodyId::VariantId(it) => it.into(), } } } @@ -608,14 +608,14 @@ impl From for TypeOwnerId { impl From for TypeOwnerId { fn from(value: GenericDefId) -> Self { match value { - GenericDefId::FunctionId(x) => x.into(), - GenericDefId::AdtId(x) => x.into(), - GenericDefId::TraitId(x) => x.into(), - GenericDefId::TraitAliasId(x) => x.into(), - GenericDefId::TypeAliasId(x) => x.into(), - GenericDefId::ImplId(x) => x.into(), - GenericDefId::EnumVariantId(x) => x.into(), - GenericDefId::ConstId(x) => x.into(), + GenericDefId::FunctionId(it) => it.into(), + GenericDefId::AdtId(it) => it.into(), + GenericDefId::TraitId(it) => it.into(), + GenericDefId::TraitAliasId(it) => it.into(), + GenericDefId::TypeAliasId(it) => it.into(), + GenericDefId::ImplId(it) => it.into(), + GenericDefId::EnumVariantId(it) => it.into(), + GenericDefId::ConstId(it) => it.into(), } } } @@ -730,7 +730,7 @@ impl GeneralConstId { .const_data(const_id) .name .as_ref() - .and_then(|x| x.as_str()) + .and_then(|it| it.as_str()) .unwrap_or("_") .to_owned(), GeneralConstId::ConstBlockId(id) => format!("{{anonymous const {id:?}}}"), @@ -972,17 +972,17 @@ impl HasModule for MacroId { impl HasModule for TypeOwnerId { fn module(&self, db: &dyn db::DefDatabase) -> ModuleId { match self { - TypeOwnerId::FunctionId(x) => x.lookup(db).module(db), - TypeOwnerId::StaticId(x) => x.lookup(db).module(db), - TypeOwnerId::ConstId(x) => x.lookup(db).module(db), - TypeOwnerId::InTypeConstId(x) => x.lookup(db).owner.module(db), - TypeOwnerId::AdtId(x) => x.module(db), - TypeOwnerId::TraitId(x) => x.lookup(db).container, - TypeOwnerId::TraitAliasId(x) => x.lookup(db).container, - TypeOwnerId::TypeAliasId(x) => x.lookup(db).module(db), - TypeOwnerId::ImplId(x) => x.lookup(db).container, - TypeOwnerId::EnumVariantId(x) => x.parent.lookup(db).container, - TypeOwnerId::ModuleId(x) => *x, + TypeOwnerId::FunctionId(it) => it.lookup(db).module(db), + TypeOwnerId::StaticId(it) => it.lookup(db).module(db), + TypeOwnerId::ConstId(it) => it.lookup(db).module(db), + TypeOwnerId::InTypeConstId(it) => it.lookup(db).owner.module(db), + TypeOwnerId::AdtId(it) => it.module(db), + TypeOwnerId::TraitId(it) => it.lookup(db).container, + TypeOwnerId::TraitAliasId(it) => it.lookup(db).container, + TypeOwnerId::TypeAliasId(it) => it.lookup(db).module(db), + TypeOwnerId::ImplId(it) => it.lookup(db).container, + TypeOwnerId::EnumVariantId(it) => it.parent.lookup(db).container, + TypeOwnerId::ModuleId(it) => *it, } } } diff --git a/crates/hir-def/src/path.rs b/crates/hir-def/src/path.rs index 409c9f874853..06530cc7ebd7 100644 --- a/crates/hir-def/src/path.rs +++ b/crates/hir-def/src/path.rs @@ -45,7 +45,7 @@ pub enum Path { /// Invariant: the same len as `self.mod_path.segments` or `None` if all segments are `None`. generic_args: Option>]>>, }, - /// A link to a lang item. It is used in desugaring of things like `x?`. We can show these + /// A link to a lang item. It is used in desugaring of things like `it?`. We can show these /// links via a normal path since they might be private and not accessible in the usage place. LangItem(LangItemTarget), } diff --git a/crates/hir-def/src/pretty.rs b/crates/hir-def/src/pretty.rs index 0aead6f37f73..11d58a6ba09c 100644 --- a/crates/hir-def/src/pretty.rs +++ b/crates/hir-def/src/pretty.rs @@ -12,8 +12,8 @@ use crate::{ }; pub(crate) fn print_path(db: &dyn ExpandDatabase, path: &Path, buf: &mut dyn Write) -> fmt::Result { - if let Path::LangItem(x) = path { - return write!(buf, "$lang_item::{x:?}"); + if let Path::LangItem(it) = path { + return write!(buf, "$lang_item::{it:?}"); } match path.type_anchor() { Some(anchor) => { diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs index 423bd00901d1..10f5702845e2 100644 --- a/crates/hir-def/src/resolver.rs +++ b/crates/hir-def/src/resolver.rs @@ -186,12 +186,12 @@ impl Resolver { Path::LangItem(l) => { return Some(( match *l { - LangItemTarget::Union(x) => TypeNs::AdtId(x.into()), - LangItemTarget::TypeAlias(x) => TypeNs::TypeAliasId(x), - LangItemTarget::Struct(x) => TypeNs::AdtId(x.into()), - LangItemTarget::EnumVariant(x) => TypeNs::EnumVariantId(x), - LangItemTarget::EnumId(x) => TypeNs::AdtId(x.into()), - LangItemTarget::Trait(x) => TypeNs::TraitId(x), + LangItemTarget::Union(it) => TypeNs::AdtId(it.into()), + LangItemTarget::TypeAlias(it) => TypeNs::TypeAliasId(it), + LangItemTarget::Struct(it) => TypeNs::AdtId(it.into()), + LangItemTarget::EnumVariant(it) => TypeNs::EnumVariantId(it), + LangItemTarget::EnumId(it) => TypeNs::AdtId(it.into()), + LangItemTarget::Trait(it) => TypeNs::TraitId(it), LangItemTarget::Function(_) | LangItemTarget::ImplDef(_) | LangItemTarget::Static(_) => return None, @@ -273,10 +273,10 @@ impl Resolver { Path::Normal { mod_path, .. } => mod_path, Path::LangItem(l) => { return Some(ResolveValueResult::ValueNs(match *l { - LangItemTarget::Function(x) => ValueNs::FunctionId(x), - LangItemTarget::Static(x) => ValueNs::StaticId(x), - LangItemTarget::Struct(x) => ValueNs::StructId(x), - LangItemTarget::EnumVariant(x) => ValueNs::EnumVariantId(x), + LangItemTarget::Function(it) => ValueNs::FunctionId(it), + LangItemTarget::Static(it) => ValueNs::StaticId(it), + LangItemTarget::Struct(it) => ValueNs::StructId(it), + LangItemTarget::EnumVariant(it) => ValueNs::EnumVariantId(it), LangItemTarget::Union(_) | LangItemTarget::ImplDef(_) | LangItemTarget::TypeAlias(_) @@ -425,14 +425,14 @@ impl Resolver { /// The shadowing is accounted for: in /// /// ``` - /// let x = 92; + /// let it = 92; /// { - /// let x = 92; + /// let it = 92; /// $0 /// } /// ``` /// - /// there will be only one entry for `x` in the result. + /// there will be only one entry for `it` in the result. /// /// The result is ordered *roughly* from the innermost scope to the /// outermost: when the name is introduced in two namespaces in two scopes, @@ -1027,17 +1027,17 @@ impl HasResolver for ExternCrateId { impl HasResolver for TypeOwnerId { fn resolver(self, db: &dyn DefDatabase) -> Resolver { match self { - TypeOwnerId::FunctionId(x) => x.resolver(db), - TypeOwnerId::StaticId(x) => x.resolver(db), - TypeOwnerId::ConstId(x) => x.resolver(db), - TypeOwnerId::InTypeConstId(x) => x.lookup(db).owner.resolver(db), - TypeOwnerId::AdtId(x) => x.resolver(db), - TypeOwnerId::TraitId(x) => x.resolver(db), - TypeOwnerId::TraitAliasId(x) => x.resolver(db), - TypeOwnerId::TypeAliasId(x) => x.resolver(db), - TypeOwnerId::ImplId(x) => x.resolver(db), - TypeOwnerId::EnumVariantId(x) => x.resolver(db), - TypeOwnerId::ModuleId(x) => x.resolver(db), + TypeOwnerId::FunctionId(it) => it.resolver(db), + TypeOwnerId::StaticId(it) => it.resolver(db), + TypeOwnerId::ConstId(it) => it.resolver(db), + TypeOwnerId::InTypeConstId(it) => it.lookup(db).owner.resolver(db), + TypeOwnerId::AdtId(it) => it.resolver(db), + TypeOwnerId::TraitId(it) => it.resolver(db), + TypeOwnerId::TraitAliasId(it) => it.resolver(db), + TypeOwnerId::TypeAliasId(it) => it.resolver(db), + TypeOwnerId::ImplId(it) => it.resolver(db), + TypeOwnerId::EnumVariantId(it) => it.resolver(db), + TypeOwnerId::ModuleId(it) => it.resolver(db), } } } diff --git a/crates/hir-expand/src/builtin_derive_macro.rs b/crates/hir-expand/src/builtin_derive_macro.rs index 3d1e272b9006..78218a83452c 100644 --- a/crates/hir-expand/src/builtin_derive_macro.rs +++ b/crates/hir-expand/src/builtin_derive_macro.rs @@ -72,12 +72,12 @@ enum VariantShape { } fn tuple_field_iterator(n: usize) -> impl Iterator { - (0..n).map(|x| Ident::new(format!("f{x}"), tt::TokenId::unspecified())) + (0..n).map(|it| Ident::new(format!("f{it}"), tt::TokenId::unspecified())) } impl VariantShape { fn as_pattern(&self, path: tt::Subtree) -> tt::Subtree { - self.as_pattern_map(path, |x| quote!(#x)) + self.as_pattern_map(path, |it| quote!(#it)) } fn field_names(&self) -> Vec { @@ -95,17 +95,17 @@ impl VariantShape { ) -> tt::Subtree { match self { VariantShape::Struct(fields) => { - let fields = fields.iter().map(|x| { - let mapped = field_map(x); - quote! { #x : #mapped , } + let fields = fields.iter().map(|it| { + let mapped = field_map(it); + quote! { #it : #mapped , } }); quote! { #path { ##fields } } } &VariantShape::Tuple(n) => { - let fields = tuple_field_iterator(n).map(|x| { - let mapped = field_map(&x); + let fields = tuple_field_iterator(n).map(|it| { + let mapped = field_map(&it); quote! { #mapped , } @@ -121,13 +121,13 @@ impl VariantShape { fn from(value: Option, token_map: &TokenMap) -> Result { let r = match value { None => VariantShape::Unit, - Some(FieldList::RecordFieldList(x)) => VariantShape::Struct( - x.fields() - .map(|x| x.name()) - .map(|x| name_to_token(token_map, x)) + Some(FieldList::RecordFieldList(it)) => VariantShape::Struct( + it.fields() + .map(|it| it.name()) + .map(|it| name_to_token(token_map, it)) .collect::>()?, ), - Some(FieldList::TupleFieldList(x)) => VariantShape::Tuple(x.fields().count()), + Some(FieldList::TupleFieldList(it)) => VariantShape::Tuple(it.fields().count()), }; Ok(r) } @@ -141,7 +141,7 @@ enum AdtShape { impl AdtShape { fn as_pattern(&self, name: &tt::Ident) -> Vec { - self.as_pattern_map(name, |x| quote!(#x)) + self.as_pattern_map(name, |it| quote!(#it)) } fn field_names(&self) -> Vec> { @@ -214,8 +214,8 @@ fn parse_adt(tt: &tt::Subtree) -> Result { let default_variant = it .variant_list() .into_iter() - .flat_map(|x| x.variants()) - .position(|x| x.attrs().any(|x| x.simple_name() == Some("default".into()))); + .flat_map(|it| it.variants()) + .position(|it| it.attrs().any(|it| it.simple_name() == Some("default".into()))); ( it.name(), it.generic_param_list(), @@ -224,11 +224,11 @@ fn parse_adt(tt: &tt::Subtree) -> Result { variants: it .variant_list() .into_iter() - .flat_map(|x| x.variants()) - .map(|x| { + .flat_map(|it| it.variants()) + .map(|it| { Ok(( - name_to_token(&token_map, x.name())?, - VariantShape::from(x.field_list(), &token_map)?, + name_to_token(&token_map, it.name())?, + VariantShape::from(it.field_list(), &token_map)?, )) }) .collect::>()?, @@ -246,16 +246,16 @@ fn parse_adt(tt: &tt::Subtree) -> Result { let name = { let this = param.name(); match this { - Some(x) => { - param_type_set.insert(x.as_name()); - mbe::syntax_node_to_token_tree(x.syntax()).0 + Some(it) => { + param_type_set.insert(it.as_name()); + mbe::syntax_node_to_token_tree(it.syntax()).0 } None => tt::Subtree::empty(), } }; let bounds = match ¶m { - ast::TypeOrConstParam::Type(x) => { - x.type_bound_list().map(|x| mbe::syntax_node_to_token_tree(x.syntax()).0) + ast::TypeOrConstParam::Type(it) => { + it.type_bound_list().map(|it| mbe::syntax_node_to_token_tree(it.syntax()).0) } ast::TypeOrConstParam::Const(_) => None, }; @@ -296,7 +296,7 @@ fn parse_adt(tt: &tt::Subtree) -> Result { let name = p.path()?.qualifier()?.as_single_name_ref()?.as_name(); param_type_set.contains(&name).then_some(p) }) - .map(|x| mbe::syntax_node_to_token_tree(x.syntax()).0) + .map(|it| mbe::syntax_node_to_token_tree(it.syntax()).0) .collect(); let name_token = name_to_token(&token_map, name)?; Ok(BasicAdtInfo { name: name_token, shape, param_types, associated_types }) @@ -373,10 +373,10 @@ fn expand_simple_derive( }) .unzip(); - where_block.extend(info.associated_types.iter().map(|x| { - let x = x.clone(); + where_block.extend(info.associated_types.iter().map(|it| { + let it = it.clone(); let bound = trait_path.clone(); - quote! { #x : #bound , } + quote! { #it : #bound , } })); let name = info.name; @@ -444,7 +444,7 @@ fn clone_expand( } let name = &adt.name; let patterns = adt.shape.as_pattern(name); - let exprs = adt.shape.as_pattern_map(name, |x| quote! { #x .clone() }); + let exprs = adt.shape.as_pattern_map(name, |it| quote! { #it .clone() }); let arms = patterns.into_iter().zip(exprs.into_iter()).map(|(pat, expr)| { let fat_arrow = fat_arrow(); quote! { @@ -524,10 +524,10 @@ fn debug_expand( expand_simple_derive(tt, quote! { #krate::fmt::Debug }, |adt| { let for_variant = |name: String, v: &VariantShape| match v { VariantShape::Struct(fields) => { - let for_fields = fields.iter().map(|x| { - let x_string = x.to_string(); + let for_fields = fields.iter().map(|it| { + let x_string = it.to_string(); quote! { - .field(#x_string, & #x) + .field(#x_string, & #it) } }); quote! { @@ -535,9 +535,9 @@ fn debug_expand( } } VariantShape::Tuple(n) => { - let for_fields = tuple_field_iterator(*n).map(|x| { + let for_fields = tuple_field_iterator(*n).map(|it| { quote! { - .field( & #x) + .field( & #it) } }); quote! { @@ -621,7 +621,7 @@ fn hash_expand( let arms = adt.shape.as_pattern(&adt.name).into_iter().zip(adt.shape.field_names()).map( |(pat, names)| { let expr = { - let it = names.iter().map(|x| quote! { #x . hash(ra_expand_state); }); + let it = names.iter().map(|it| quote! { #it . hash(ra_expand_state); }); quote! { { ##it } } @@ -674,9 +674,9 @@ fn partial_eq_expand( quote!(true) } [first, rest @ ..] => { - let rest = rest.iter().map(|x| { - let t1 = Ident::new(format!("{}_self", x.text), x.span); - let t2 = Ident::new(format!("{}_other", x.text), x.span); + let rest = rest.iter().map(|it| { + let t1 = Ident::new(format!("{}_self", it.text), it.span); + let t2 = Ident::new(format!("{}_other", it.text), it.span); let and_and = and_and(); quote!(#and_and #t1 .eq( #t2 )) }); @@ -708,12 +708,12 @@ fn self_and_other_patterns( adt: &BasicAdtInfo, name: &tt::Ident, ) -> (Vec, Vec) { - let self_patterns = adt.shape.as_pattern_map(name, |x| { - let t = Ident::new(format!("{}_self", x.text), x.span); + let self_patterns = adt.shape.as_pattern_map(name, |it| { + let t = Ident::new(format!("{}_self", it.text), it.span); quote!(#t) }); - let other_patterns = adt.shape.as_pattern_map(name, |x| { - let t = Ident::new(format!("{}_other", x.text), x.span); + let other_patterns = adt.shape.as_pattern_map(name, |it| { + let t = Ident::new(format!("{}_other", it.text), it.span); quote!(#t) }); (self_patterns, other_patterns) diff --git a/crates/hir-expand/src/builtin_fn_macro.rs b/crates/hir-expand/src/builtin_fn_macro.rs index 306bae45b429..7370f07a52b8 100644 --- a/crates/hir-expand/src/builtin_fn_macro.rs +++ b/crates/hir-expand/src/builtin_fn_macro.rs @@ -339,7 +339,7 @@ fn format_args_expand_general( parts.push(mem::take(&mut last_part)); let arg_tree = if argument.is_empty() { match args.next() { - Some(x) => x, + Some(it) => it, None => { err = Some(mbe::ExpandError::NoMatchingRule.into()); tt::Subtree::empty() @@ -378,11 +378,11 @@ fn format_args_expand_general( if !last_part.is_empty() { parts.push(last_part); } - let part_tts = parts.into_iter().map(|x| { + let part_tts = parts.into_iter().map(|it| { let text = if let Some(raw) = &raw_sharps { - format!("r{raw}\"{}\"{raw}", x).into() + format!("r{raw}\"{}\"{raw}", it).into() } else { - format!("\"{}\"", x).into() + format!("\"{}\"", it).into() }; let l = tt::Literal { span: tt::TokenId::unspecified(), text }; quote!(#l ,) @@ -574,7 +574,7 @@ fn concat_bytes_expand( syntax::SyntaxKind::BYTE => bytes.push(token.text().to_string()), syntax::SyntaxKind::BYTE_STRING => { let components = unquote_byte_string(lit).unwrap_or_default(); - components.into_iter().for_each(|x| bytes.push(x.to_string())); + components.into_iter().for_each(|it| bytes.push(it.to_string())); } _ => { err.get_or_insert(mbe::ExpandError::UnexpectedToken.into()); diff --git a/crates/hir-expand/src/fixup.rs b/crates/hir-expand/src/fixup.rs index 00796e7c0dbb..af9d2d78dd78 100644 --- a/crates/hir-expand/src/fixup.rs +++ b/crates/hir-expand/src/fixup.rs @@ -472,13 +472,13 @@ fn foo () {match __ra_fixup {}} check( r#" fn foo() { - match x { + match it { } } "#, expect![[r#" -fn foo () {match x {}} +fn foo () {match it {}} "#]], ) } @@ -547,11 +547,11 @@ fn foo () {a . __ra_fixup ; bar () ;} check( r#" fn foo() { - let x = a + let it = a } "#, expect![[r#" -fn foo () {let x = a ;} +fn foo () {let it = a ;} "#]], ) } @@ -561,11 +561,11 @@ fn foo () {let x = a ;} check( r#" fn foo() { - let x = a. + let it = a. } "#, expect![[r#" -fn foo () {let x = a . __ra_fixup ;} +fn foo () {let it = a . __ra_fixup ;} "#]], ) } diff --git a/crates/hir-ty/src/chalk_ext.rs b/crates/hir-ty/src/chalk_ext.rs index 0e33b63939eb..c0b243ea2485 100644 --- a/crates/hir-ty/src/chalk_ext.rs +++ b/crates/hir-ty/src/chalk_ext.rs @@ -343,7 +343,7 @@ impl TyExt for Ty { fn is_copy(self, db: &dyn HirDatabase, owner: DefWithBodyId) -> bool { let crate_id = owner.module(db.upcast()).krate(); - let Some(copy_trait) = db.lang_item(crate_id, LangItem::Copy).and_then(|x| x.as_trait()) + let Some(copy_trait) = db.lang_item(crate_id, LangItem::Copy).and_then(|it| it.as_trait()) else { return false; }; diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs index 262341c6e9ee..537e28894a88 100644 --- a/crates/hir-ty/src/consteval.rs +++ b/crates/hir-ty/src/consteval.rs @@ -88,7 +88,7 @@ pub(crate) fn path_to_const( ConstValue::Placeholder(to_placeholder_idx(db, p.into())) } ParamLoweringMode::Variable => match args.param_idx(p.into()) { - Some(x) => ConstValue::BoundVar(BoundVar::new(debruijn, x)), + Some(it) => ConstValue::BoundVar(BoundVar::new(debruijn, it)), None => { never!( "Generic list doesn't contain this param: {:?}, {:?}, {:?}", @@ -139,11 +139,11 @@ pub fn intern_const_ref( let bytes = match value { LiteralConstRef::Int(i) => { // FIXME: We should handle failure of layout better. - let size = layout.map(|x| x.size.bytes_usize()).unwrap_or(16); + let size = layout.map(|it| it.size.bytes_usize()).unwrap_or(16); ConstScalar::Bytes(i.to_le_bytes()[0..size].to_vec(), MemoryMap::default()) } LiteralConstRef::UInt(i) => { - let size = layout.map(|x| x.size.bytes_usize()).unwrap_or(16); + let size = layout.map(|it| it.size.bytes_usize()).unwrap_or(16); ConstScalar::Bytes(i.to_le_bytes()[0..size].to_vec(), MemoryMap::default()) } LiteralConstRef::Bool(b) => ConstScalar::Bytes(vec![*b as u8], MemoryMap::default()), @@ -171,7 +171,7 @@ pub fn try_const_usize(db: &dyn HirDatabase, c: &Const) -> Option { chalk_ir::ConstValue::InferenceVar(_) => None, chalk_ir::ConstValue::Placeholder(_) => None, chalk_ir::ConstValue::Concrete(c) => match &c.interned { - ConstScalar::Bytes(x, _) => Some(u128::from_le_bytes(pad16(&x, false))), + ConstScalar::Bytes(it, _) => Some(u128::from_le_bytes(pad16(&it, false))), ConstScalar::UnevaluatedConst(c, subst) => { let ec = db.const_eval(*c, subst.clone()).ok()?; try_const_usize(db, &ec) diff --git a/crates/hir-ty/src/consteval/tests/intrinsics.rs b/crates/hir-ty/src/consteval/tests/intrinsics.rs index f51aceb87a8d..b74133e24f10 100644 --- a/crates/hir-ty/src/consteval/tests/intrinsics.rs +++ b/crates/hir-ty/src/consteval/tests/intrinsics.rs @@ -37,8 +37,8 @@ fn size_of_val() { } const GOAL: usize = { - let x: &[i32] = &[1, 2, 3]; - size_of_val(x) + let it: &[i32] = &[1, 2, 3]; + size_of_val(it) }; "#, 12, diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs index 7405b51e6e09..b87047718d01 100644 --- a/crates/hir-ty/src/display.rs +++ b/crates/hir-ty/src/display.rs @@ -481,28 +481,28 @@ fn render_const_scalar( TyKind::Scalar(s) => match s { Scalar::Bool => write!(f, "{}", if b[0] == 0 { false } else { true }), Scalar::Char => { - let x = u128::from_le_bytes(pad16(b, false)) as u32; - let Ok(c) = char::try_from(x) else { + let it = u128::from_le_bytes(pad16(b, false)) as u32; + let Ok(c) = char::try_from(it) else { return f.write_str(""); }; write!(f, "{c:?}") } Scalar::Int(_) => { - let x = i128::from_le_bytes(pad16(b, true)); - write!(f, "{x}") + let it = i128::from_le_bytes(pad16(b, true)); + write!(f, "{it}") } Scalar::Uint(_) => { - let x = u128::from_le_bytes(pad16(b, false)); - write!(f, "{x}") + let it = u128::from_le_bytes(pad16(b, false)); + write!(f, "{it}") } Scalar::Float(fl) => match fl { chalk_ir::FloatTy::F32 => { - let x = f32::from_le_bytes(b.try_into().unwrap()); - write!(f, "{x:?}") + let it = f32::from_le_bytes(b.try_into().unwrap()); + write!(f, "{it:?}") } chalk_ir::FloatTy::F64 => { - let x = f64::from_le_bytes(b.try_into().unwrap()); - write!(f, "{x:?}") + let it = f64::from_le_bytes(b.try_into().unwrap()); + write!(f, "{it:?}") } }, }, @@ -659,8 +659,8 @@ fn render_const_scalar( } TyKind::FnDef(..) => ty.hir_fmt(f), TyKind::Function(_) | TyKind::Raw(_, _) => { - let x = u128::from_le_bytes(pad16(b, false)); - write!(f, "{:#X} as ", x)?; + let it = u128::from_le_bytes(pad16(b, false)); + write!(f, "{:#X} as ", it)?; ty.hir_fmt(f) } TyKind::Array(ty, len) => { @@ -736,7 +736,7 @@ fn render_variant_after_name( } write!(f, " }}")?; } else { - let mut it = it.map(|x| x.0); + let mut it = it.map(|it| it.0); write!(f, "(")?; if let Some(id) = it.next() { render_field(f, id)?; @@ -1278,19 +1278,20 @@ fn hir_fmt_generics( i: usize, parameters: &Substitution, ) -> bool { - if parameter.ty(Interner).map(|x| x.kind(Interner)) == Some(&TyKind::Error) + if parameter.ty(Interner).map(|it| it.kind(Interner)) + == Some(&TyKind::Error) { return true; } if let Some(ConstValue::Concrete(c)) = - parameter.constant(Interner).map(|x| &x.data(Interner).value) + parameter.constant(Interner).map(|it| &it.data(Interner).value) { if c.interned == ConstScalar::Unknown { return true; } } let default_parameter = match default_parameters.get(i) { - Some(x) => x, + Some(it) => it, None => return true, }; let actual_default = diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index d53644e2798c..0a617dae7d43 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -290,7 +290,7 @@ impl Default for InternedStandardTypes { /// ``` /// /// Note that for a struct, the 'deep' unsizing of the struct is not recorded. -/// E.g., `struct Foo { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]> +/// E.g., `struct Foo { it: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]> /// The autoderef and -ref are the same as in the above example, but the type /// stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about /// the underlying conversions from `[i32; 4]` to `[i32]`. @@ -1172,7 +1172,7 @@ impl<'a> InferenceContext<'a> { unresolved: Option, path: &ModPath, ) -> (Ty, Option) { - let remaining = unresolved.map(|x| path.segments()[x..].len()).filter(|x| x > &0); + let remaining = unresolved.map(|it| path.segments()[it..].len()).filter(|it| it > &0); match remaining { None => { let variant = ty.as_adt().and_then(|(adt_id, _)| match adt_id { @@ -1324,7 +1324,7 @@ impl Expectation { /// The primary use case is where the expected type is a fat pointer, /// like `&[isize]`. For example, consider the following statement: /// - /// let x: &[isize] = &[1, 2, 3]; + /// let it: &[isize] = &[1, 2, 3]; /// /// In this case, the expected type for the `&[1, 2, 3]` expression is /// `&[isize]`. If however we were to say that `[1, 2, 3]` has the diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs index ff64ae252bce..972e5321a475 100644 --- a/crates/hir-ty/src/infer/closure.rs +++ b/crates/hir-ty/src/infer/closure.rs @@ -139,7 +139,7 @@ impl HirPlace { ) -> CaptureKind { match current_capture { CaptureKind::ByRef(BorrowKind::Mut { .. }) => { - if self.projections[len..].iter().any(|x| *x == ProjectionElem::Deref) { + if self.projections[len..].iter().any(|it| *it == ProjectionElem::Deref) { current_capture = CaptureKind::ByRef(BorrowKind::Unique); } } @@ -199,7 +199,7 @@ impl CapturedItem { .to_string(), VariantData::Tuple(fields) => fields .iter() - .position(|x| x.0 == f.local_id) + .position(|it| it.0 == f.local_id) .unwrap_or_default() .to_string(), VariantData::Unit => "[missing field]".to_string(), @@ -439,10 +439,10 @@ impl InferenceContext<'_> { } fn walk_expr(&mut self, tgt_expr: ExprId) { - if let Some(x) = self.result.expr_adjustments.get_mut(&tgt_expr) { + if let Some(it) = self.result.expr_adjustments.get_mut(&tgt_expr) { // FIXME: this take is completely unneeded, and just is here to make borrow checker // happy. Remove it if you can. - let x_taken = mem::take(x); + let x_taken = mem::take(it); self.walk_expr_with_adjust(tgt_expr, &x_taken); *self.result.expr_adjustments.get_mut(&tgt_expr).unwrap() = x_taken; } else { @@ -536,7 +536,7 @@ impl InferenceContext<'_> { if let &Some(expr) = spread { self.consume_expr(expr); } - self.consume_exprs(fields.iter().map(|x| x.expr)); + self.consume_exprs(fields.iter().map(|it| it.expr)); } Expr::Field { expr, name: _ } => self.select_from_expr(*expr), Expr::UnaryOp { expr, op: UnaryOp::Deref } => { @@ -548,7 +548,7 @@ impl InferenceContext<'_> { } else if let Some((f, _)) = self.result.method_resolution(tgt_expr) { let mutability = 'b: { if let Some(deref_trait) = - self.resolve_lang_item(LangItem::DerefMut).and_then(|x| x.as_trait()) + self.resolve_lang_item(LangItem::DerefMut).and_then(|it| it.as_trait()) { if let Some(deref_fn) = self.db.trait_data(deref_trait).method_by_name(&name![deref_mut]) @@ -615,8 +615,8 @@ impl InferenceContext<'_> { "We sort closures, so we should always have data for inner closures", ); let mut cc = mem::take(&mut self.current_captures); - cc.extend(captures.iter().filter(|x| self.is_upvar(&x.place)).map(|x| { - CapturedItemWithoutTy { place: x.place.clone(), kind: x.kind, span: x.span } + cc.extend(captures.iter().filter(|it| self.is_upvar(&it.place)).map(|it| { + CapturedItemWithoutTy { place: it.place.clone(), kind: it.kind, span: it.span } })); self.current_captures = cc; } @@ -694,7 +694,7 @@ impl InferenceContext<'_> { }, }, } - if self.result.pat_adjustments.get(&p).map_or(false, |x| !x.is_empty()) { + if self.result.pat_adjustments.get(&p).map_or(false, |it| !it.is_empty()) { for_mut = BorrowKind::Unique; } self.body.walk_pats_shallow(p, |p| self.walk_pat_inner(p, update_result, for_mut)); @@ -706,9 +706,9 @@ impl InferenceContext<'_> { fn expr_ty_after_adjustments(&self, e: ExprId) -> Ty { let mut ty = None; - if let Some(x) = self.result.expr_adjustments.get(&e) { - if let Some(x) = x.last() { - ty = Some(x.target.clone()); + if let Some(it) = self.result.expr_adjustments.get(&e) { + if let Some(it) = it.last() { + ty = Some(it.target.clone()); } } ty.unwrap_or_else(|| self.expr_ty(e)) @@ -727,7 +727,7 @@ impl InferenceContext<'_> { // FIXME: We handle closure as a special case, since chalk consider every closure as copy. We // should probably let chalk know which closures are copy, but I don't know how doing it // without creating query cycles. - return self.result.closure_info.get(id).map(|x| x.1 == FnTrait::Fn).unwrap_or(true); + return self.result.closure_info.get(id).map(|it| it.1 == FnTrait::Fn).unwrap_or(true); } self.table.resolve_completely(ty).is_copy(self.db, self.owner) } @@ -748,7 +748,7 @@ impl InferenceContext<'_> { } fn minimize_captures(&mut self) { - self.current_captures.sort_by_key(|x| x.place.projections.len()); + self.current_captures.sort_by_key(|it| it.place.projections.len()); let mut hash_map = HashMap::::new(); let result = mem::take(&mut self.current_captures); for item in result { @@ -759,7 +759,7 @@ impl InferenceContext<'_> { break Some(*k); } match it.next() { - Some(x) => lookup_place.projections.push(x.clone()), + Some(it) => lookup_place.projections.push(it.clone()), None => break None, } }; @@ -780,7 +780,7 @@ impl InferenceContext<'_> { } fn consume_with_pat(&mut self, mut place: HirPlace, pat: PatId) { - let cnt = self.result.pat_adjustments.get(&pat).map(|x| x.len()).unwrap_or_default(); + let cnt = self.result.pat_adjustments.get(&pat).map(|it| it.len()).unwrap_or_default(); place.projections = place .projections .iter() @@ -894,10 +894,10 @@ impl InferenceContext<'_> { fn closure_kind(&self) -> FnTrait { let mut r = FnTrait::Fn; - for x in &self.current_captures { + for it in &self.current_captures { r = cmp::min( r, - match &x.kind { + match &it.kind { CaptureKind::ByRef(BorrowKind::Unique | BorrowKind::Mut { .. }) => { FnTrait::FnMut } @@ -933,7 +933,7 @@ impl InferenceContext<'_> { } self.minimize_captures(); let result = mem::take(&mut self.current_captures); - let captures = result.into_iter().map(|x| x.with_ty(self)).collect::>(); + let captures = result.into_iter().map(|it| it.with_ty(self)).collect::>(); self.result.closure_info.insert(closure, (captures, closure_kind)); closure_kind } @@ -973,20 +973,20 @@ impl InferenceContext<'_> { fn sort_closures(&mut self) -> Vec<(ClosureId, Vec<(Ty, Ty, Vec, ExprId)>)> { let mut deferred_closures = mem::take(&mut self.deferred_closures); let mut dependents_count: FxHashMap = - deferred_closures.keys().map(|x| (*x, 0)).collect(); + deferred_closures.keys().map(|it| (*it, 0)).collect(); for (_, deps) in &self.closure_dependencies { for dep in deps { *dependents_count.entry(*dep).or_default() += 1; } } let mut queue: Vec<_> = - deferred_closures.keys().copied().filter(|x| dependents_count[x] == 0).collect(); + deferred_closures.keys().copied().filter(|it| dependents_count[it] == 0).collect(); let mut result = vec![]; - while let Some(x) = queue.pop() { - if let Some(d) = deferred_closures.remove(&x) { - result.push((x, d)); + while let Some(it) = queue.pop() { + if let Some(d) = deferred_closures.remove(&it) { + result.push((it, d)); } - for dep in self.closure_dependencies.get(&x).into_iter().flat_map(|x| x.iter()) { + for dep in self.closure_dependencies.get(&it).into_iter().flat_map(|it| it.iter()) { let cnt = dependents_count.get_mut(dep).unwrap(); *cnt -= 1; if *cnt == 0 { diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index fd9522e86af1..4b14345aa39f 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -928,7 +928,7 @@ impl InferenceContext<'_> { if let TyKind::Ref(Mutability::Mut, _, inner) = derefed_callee.kind(Interner) { if adjustments .last() - .map(|x| matches!(x.kind, Adjust::Borrow(_))) + .map(|it| matches!(it.kind, Adjust::Borrow(_))) .unwrap_or(true) { // prefer reborrow to move diff --git a/crates/hir-ty/src/infer/mutability.rs b/crates/hir-ty/src/infer/mutability.rs index 2f307408c627..f517bc2c09f1 100644 --- a/crates/hir-ty/src/infer/mutability.rs +++ b/crates/hir-ty/src/infer/mutability.rs @@ -73,12 +73,12 @@ impl InferenceContext<'_> { self.infer_mut_expr(c, Mutability::Not); self.infer_mut_expr(body, Mutability::Not); } - Expr::MethodCall { receiver: x, method_name: _, args, generic_args: _ } - | Expr::Call { callee: x, args, is_assignee_expr: _ } => { - self.infer_mut_not_expr_iter(args.iter().copied().chain(Some(*x))); + Expr::MethodCall { receiver: it, method_name: _, args, generic_args: _ } + | Expr::Call { callee: it, args, is_assignee_expr: _ } => { + self.infer_mut_not_expr_iter(args.iter().copied().chain(Some(*it))); } Expr::Match { expr, arms } => { - let m = self.pat_iter_bound_mutability(arms.iter().map(|x| x.pat)); + let m = self.pat_iter_bound_mutability(arms.iter().map(|it| it.pat)); self.infer_mut_expr(*expr, m); for arm in arms.iter() { self.infer_mut_expr(arm.expr, Mutability::Not); @@ -96,7 +96,7 @@ impl InferenceContext<'_> { } } Expr::RecordLit { path: _, fields, spread, ellipsis: _, is_assignee_expr: _ } => { - self.infer_mut_not_expr_iter(fields.iter().map(|x| x.expr).chain(*spread)) + self.infer_mut_not_expr_iter(fields.iter().map(|it| it.expr).chain(*spread)) } &Expr::Index { base, index } => { if mutability == Mutability::Mut { @@ -204,8 +204,8 @@ impl InferenceContext<'_> { } /// Checks if the pat contains a `ref mut` binding. Such paths makes the context of bounded expressions - /// mutable. For example in `let (ref mut x0, ref x1) = *x;` we need to use `DerefMut` for `*x` but in - /// `let (ref x0, ref x1) = *x;` we should use `Deref`. + /// mutable. For example in `let (ref mut x0, ref x1) = *it;` we need to use `DerefMut` for `*it` but in + /// `let (ref x0, ref x1) = *it;` we should use `Deref`. fn pat_bound_mutability(&self, pat: PatId) -> Mutability { let mut r = Mutability::Not; self.body.walk_bindings_in_pat(pat, |b| { diff --git a/crates/hir-ty/src/infer/pat.rs b/crates/hir-ty/src/infer/pat.rs index 415b4e1d9f17..5da0ab76b880 100644 --- a/crates/hir-ty/src/infer/pat.rs +++ b/crates/hir-ty/src/infer/pat.rs @@ -306,7 +306,7 @@ impl InferenceContext<'_> { self.result .pat_adjustments .get(&pat) - .and_then(|x| x.first()) + .and_then(|it| it.first()) .unwrap_or(&self.result.type_of_pat[pat]) .clone() } diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs index e322c5dbfece..385f39f5374d 100644 --- a/crates/hir-ty/src/infer/unify.rs +++ b/crates/hir-ty/src/infer/unify.rs @@ -91,7 +91,7 @@ pub(crate) fn unify( let mut table = InferenceTable::new(db, env); let vars = Substitution::from_iter( Interner, - tys.binders.iter(Interner).map(|x| match &x.kind { + tys.binders.iter(Interner).map(|it| match &it.kind { chalk_ir::VariableKind::Ty(_) => { GenericArgData::Ty(table.new_type_var()).intern(Interner) } @@ -686,8 +686,8 @@ impl<'a> InferenceTable<'a> { let mut arg_tys = vec![]; let arg_ty = TyBuilder::tuple(num_args) - .fill(|x| { - let arg = match x { + .fill(|it| { + let arg = match it { ParamKind::Type => self.new_type_var(), ParamKind::Const(ty) => { never!("Tuple with const parameter"); @@ -753,7 +753,7 @@ impl<'a> InferenceTable<'a> { { fold_tys_and_consts( ty, - |x, _| match x { + |it, _| match it { Either::Left(ty) => Either::Left(self.insert_type_vars_shallow(ty)), Either::Right(c) => Either::Right(self.insert_const_vars_shallow(c)), }, diff --git a/crates/hir-ty/src/layout.rs b/crates/hir-ty/src/layout.rs index 06be1f80ad3a..72e2bcc55590 100644 --- a/crates/hir-ty/src/layout.rs +++ b/crates/hir-ty/src/layout.rs @@ -24,8 +24,8 @@ pub use self::{ }; macro_rules! user_error { - ($x: expr) => { - return Err(LayoutError::UserError(format!($x))) + ($it: expr) => { + return Err(LayoutError::UserError(format!($it))) }; } @@ -90,13 +90,13 @@ fn layout_of_simd_ty( // Supported SIMD vectors are homogeneous ADTs with at least one field: // // * #[repr(simd)] struct S(T, T, T, T); - // * #[repr(simd)] struct S { x: T, y: T, z: T, w: T } + // * #[repr(simd)] struct S { it: T, y: T, z: T, w: T } // * #[repr(simd)] struct S([T; 4]) // // where T is a primitive scalar (integer/float/pointer). let f0_ty = match fields.iter().next() { - Some(x) => x.1.clone().substitute(Interner, subst), + Some(it) => it.1.clone().substitute(Interner, subst), None => { user_error!("simd type with zero fields"); } @@ -230,7 +230,7 @@ pub fn layout_of_ty_query( .iter(Interner) .map(|k| db.layout_of_ty(k.assert_ty_ref(Interner).clone(), krate)) .collect::, _>>()?; - let fields = fields.iter().map(|x| &**x).collect::>(); + let fields = fields.iter().map(|it| &**it).collect::>(); let fields = fields.iter().collect::>(); cx.univariant(dl, &fields, &ReprOptions::default(), kind).ok_or(LayoutError::Unknown)? } @@ -348,14 +348,14 @@ pub fn layout_of_ty_query( let (captures, _) = infer.closure_info(c); let fields = captures .iter() - .map(|x| { + .map(|it| { db.layout_of_ty( - x.ty.clone().substitute(Interner, ClosureSubst(subst).parent_subst()), + it.ty.clone().substitute(Interner, ClosureSubst(subst).parent_subst()), krate, ) }) .collect::, _>>()?; - let fields = fields.iter().map(|x| &**x).collect::>(); + let fields = fields.iter().map(|it| &**it).collect::>(); let fields = fields.iter().collect::>(); cx.univariant(dl, &fields, &ReprOptions::default(), StructKind::AlwaysSized) .ok_or(LayoutError::Unknown)? diff --git a/crates/hir-ty/src/layout/adt.rs b/crates/hir-ty/src/layout/adt.rs index 186b8e2bc68d..19d5e98e7389 100644 --- a/crates/hir-ty/src/layout/adt.rs +++ b/crates/hir-ty/src/layout/adt.rs @@ -72,9 +72,9 @@ pub fn layout_of_adt_query( }; let variants = variants .iter() - .map(|x| x.iter().map(|x| &**x).collect::>()) + .map(|it| it.iter().map(|it| &**it).collect::>()) .collect::>(); - let variants = variants.iter().map(|x| x.iter().collect()).collect(); + let variants = variants.iter().map(|it| it.iter().collect()).collect(); let result = if matches!(def, AdtId::UnionId(..)) { cx.layout_of_union(&repr, &variants).ok_or(LayoutError::Unknown)? } else { @@ -105,7 +105,7 @@ pub fn layout_of_adt_query( && variants .iter() .next() - .and_then(|x| x.last().map(|x| !x.is_unsized())) + .and_then(|it| it.last().map(|it| !it.is_unsized())) .unwrap_or(true), ) .ok_or(LayoutError::SizeOverflow)? @@ -118,9 +118,9 @@ fn layout_scalar_valid_range(db: &dyn HirDatabase, def: AdtId) -> (Bound, let get = |name| { let attr = attrs.by_key(name).tt_values(); for tree in attr { - if let Some(x) = tree.token_trees.first() { - if let Ok(x) = x.to_string().parse() { - return Bound::Included(x); + if let Some(it) = tree.token_trees.first() { + if let Ok(it) = it.to_string().parse() { + return Bound::Included(it); } } } diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index c86d617fb54a..5781ea48ee22 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -559,10 +559,10 @@ impl ReceiverAdjustments { adjust.push(a); } if self.unsize_array { - ty = 'x: { + ty = 'it: { if let TyKind::Ref(m, l, inner) = ty.kind(Interner) { if let TyKind::Array(inner, _) = inner.kind(Interner) { - break 'x TyKind::Ref( + break 'it TyKind::Ref( m.clone(), l.clone(), TyKind::Slice(inner.clone()).intern(Interner), @@ -666,7 +666,7 @@ pub fn is_dyn_method( let self_ty = trait_ref.self_type_parameter(Interner); if let TyKind::Dyn(d) = self_ty.kind(Interner) { let is_my_trait_in_bounds = - d.bounds.skip_binders().as_slice(Interner).iter().any(|x| match x.skip_binders() { + d.bounds.skip_binders().as_slice(Interner).iter().any(|it| match it.skip_binders() { // rustc doesn't accept `impl Foo<2> for dyn Foo<5>`, so if the trait id is equal, no matter // what the generics are, we are sure that the method is come from the vtable. WhereClause::Implemented(tr) => tr.trait_id == trait_ref.trait_id, @@ -731,7 +731,7 @@ fn lookup_impl_assoc_item_for_trait_ref( let impls = db.trait_impls_in_deps(env.krate); let self_impls = match self_ty.kind(Interner) { TyKind::Adt(id, _) => { - id.0.module(db.upcast()).containing_block().map(|x| db.trait_impls_in_block(x)) + id.0.module(db.upcast()).containing_block().map(|it| db.trait_impls_in_block(it)) } _ => None, }; @@ -895,8 +895,8 @@ pub fn iterate_method_candidates_dyn( // (just as rustc does an autoderef and then autoref again). // We have to be careful about the order we're looking at candidates - // in here. Consider the case where we're resolving `x.clone()` - // where `x: &Vec<_>`. This resolves to the clone method with self + // in here. Consider the case where we're resolving `it.clone()` + // where `it: &Vec<_>`. This resolves to the clone method with self // type `Vec<_>`, *not* `&_`. I.e. we need to consider methods where // the receiver type exactly matches before cases where we have to // do autoref. But in the autoderef steps, the `&_` self type comes @@ -1480,8 +1480,8 @@ fn generic_implements_goal( .push(self_ty.value.clone()) .fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len()) .build(); - kinds.extend(trait_ref.substitution.iter(Interner).skip(1).map(|x| { - let vk = match x.data(Interner) { + kinds.extend(trait_ref.substitution.iter(Interner).skip(1).map(|it| { + let vk = match it.data(Interner) { chalk_ir::GenericArgData::Ty(_) => { chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General) } diff --git a/crates/hir-ty/src/mir/borrowck.rs b/crates/hir-ty/src/mir/borrowck.rs index 0e6a63df4109..ad98e8fa1810 100644 --- a/crates/hir-ty/src/mir/borrowck.rs +++ b/crates/hir-ty/src/mir/borrowck.rs @@ -52,7 +52,7 @@ fn all_mir_bodies( let closures = body.closures.clone(); Box::new( iter::once(Ok(body)) - .chain(closures.into_iter().flat_map(|x| for_closure(db, x))), + .chain(closures.into_iter().flat_map(|it| for_closure(db, it))), ) } Err(e) => Box::new(iter::once(Err(e))), @@ -62,7 +62,7 @@ fn all_mir_bodies( Ok(body) => { let closures = body.closures.clone(); Box::new( - iter::once(Ok(body)).chain(closures.into_iter().flat_map(|x| for_closure(db, x))), + iter::once(Ok(body)).chain(closures.into_iter().flat_map(|it| for_closure(db, it))), ) } Err(e) => Box::new(iter::once(Err(e))), @@ -171,7 +171,7 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec } TerminatorKind::Call { func, args, .. } => { for_operand(func, terminator.span); - args.iter().for_each(|x| for_operand(x, terminator.span)); + args.iter().for_each(|it| for_operand(it, terminator.span)); } TerminatorKind::Assert { cond, .. } => { for_operand(cond, terminator.span); @@ -245,7 +245,7 @@ fn ever_initialized_map( body: &MirBody, ) -> ArenaMap> { let mut result: ArenaMap> = - body.basic_blocks.iter().map(|x| (x.0, ArenaMap::default())).collect(); + body.basic_blocks.iter().map(|it| (it.0, ArenaMap::default())).collect(); fn dfs( db: &dyn HirDatabase, body: &MirBody, @@ -314,7 +314,7 @@ fn ever_initialized_map( result[body.start_block].insert(l, true); dfs(db, body, body.start_block, l, &mut result); } - for l in body.locals.iter().map(|x| x.0) { + for l in body.locals.iter().map(|it| it.0) { if !result[body.start_block].contains_idx(l) { result[body.start_block].insert(l, false); dfs(db, body, body.start_block, l, &mut result); @@ -328,10 +328,10 @@ fn mutability_of_locals( body: &MirBody, ) -> ArenaMap { let mut result: ArenaMap = - body.locals.iter().map(|x| (x.0, MutabilityReason::Not)).collect(); + body.locals.iter().map(|it| (it.0, MutabilityReason::Not)).collect(); let mut push_mut_span = |local, span| match &mut result[local] { MutabilityReason::Mut { spans } => spans.push(span), - x @ MutabilityReason::Not => *x = MutabilityReason::Mut { spans: vec![span] }, + it @ MutabilityReason::Not => *it = MutabilityReason::Mut { spans: vec![span] }, }; let ever_init_maps = ever_initialized_map(db, body); for (block_id, mut ever_init_map) in ever_init_maps.into_iter() { diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index 51a75cbbff2e..299efb714549 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -48,15 +48,15 @@ mod tests; macro_rules! from_bytes { ($ty:tt, $value:expr) => { ($ty::from_le_bytes(match ($value).try_into() { - Ok(x) => x, + Ok(it) => it, Err(_) => return Err(MirEvalError::TypeError(stringify!(mismatched size in constructing $ty))), })) }; } macro_rules! not_supported { - ($x: expr) => { - return Err(MirEvalError::NotSupported(format!($x))) + ($it: expr) => { + return Err(MirEvalError::NotSupported(format!($it))) }; } @@ -68,8 +68,8 @@ pub struct VTableMap { impl VTableMap { fn id(&mut self, ty: Ty) -> usize { - if let Some(x) = self.ty_to_id.get(&ty) { - return *x; + if let Some(it) = self.ty_to_id.get(&ty) { + return *it; } let id = self.id_to_ty.len(); self.id_to_ty.push(ty.clone()); @@ -237,17 +237,17 @@ const STACK_OFFSET: usize = 1 << 30; const HEAP_OFFSET: usize = 1 << 29; impl Address { - fn from_bytes(x: &[u8]) -> Result { - Ok(Address::from_usize(from_bytes!(usize, x))) + fn from_bytes(it: &[u8]) -> Result { + Ok(Address::from_usize(from_bytes!(usize, it))) } - fn from_usize(x: usize) -> Self { - if x > STACK_OFFSET { - Stack(x - STACK_OFFSET) - } else if x > HEAP_OFFSET { - Heap(x - HEAP_OFFSET) + fn from_usize(it: usize) -> Self { + if it > STACK_OFFSET { + Stack(it - STACK_OFFSET) + } else if it > HEAP_OFFSET { + Heap(it - HEAP_OFFSET) } else { - Invalid(x) + Invalid(it) } } @@ -257,23 +257,23 @@ impl Address { fn to_usize(&self) -> usize { let as_num = match self { - Stack(x) => *x + STACK_OFFSET, - Heap(x) => *x + HEAP_OFFSET, - Invalid(x) => *x, + Stack(it) => *it + STACK_OFFSET, + Heap(it) => *it + HEAP_OFFSET, + Invalid(it) => *it, }; as_num } fn map(&self, f: impl FnOnce(usize) -> usize) -> Address { match self { - Stack(x) => Stack(f(*x)), - Heap(x) => Heap(f(*x)), - Invalid(x) => Invalid(f(*x)), + Stack(it) => Stack(f(*it)), + Heap(it) => Heap(f(*it)), + Invalid(it) => Invalid(f(*it)), } } fn offset(&self, offset: usize) -> Address { - self.map(|x| x + offset) + self.map(|it| it + offset) } } @@ -329,11 +329,11 @@ impl MirEvalError { let source_map = db.body_with_source_map(*def).1; let span: InFile = match span { MirSpan::ExprId(e) => match source_map.expr_syntax(*e) { - Ok(s) => s.map(|x| x.into()), + Ok(s) => s.map(|it| it.into()), Err(_) => continue, }, MirSpan::PatId(p) => match source_map.pat_syntax(*p) { - Ok(s) => s.map(|x| match x { + Ok(s) => s.map(|it| match it { Either::Left(e) => e.into(), Either::Right(e) => e.into(), }), @@ -445,10 +445,10 @@ struct DropFlags { impl DropFlags { fn add_place(&mut self, p: Place) { - if p.iterate_over_parents().any(|x| self.need_drop.contains(&x)) { + if p.iterate_over_parents().any(|it| self.need_drop.contains(&it)) { return; } - self.need_drop.retain(|x| !p.is_parent(x)); + self.need_drop.retain(|it| !p.is_parent(it)); self.need_drop.insert(p); } @@ -477,7 +477,7 @@ pub fn interpret_mir( ) -> (Result, String, String) { let ty = body.locals[return_slot()].ty.clone(); let mut evaluator = Evaluator::new(db, body, assert_placeholder_ty_is_unused); - let x: Result = (|| { + let it: Result = (|| { if evaluator.ptr_size() != std::mem::size_of::() { not_supported!("targets with different pointer size from host"); } @@ -491,7 +491,7 @@ pub fn interpret_mir( return Ok(intern_const_scalar(ConstScalar::Bytes(bytes, memory_map), ty)); })(); ( - x, + it, String::from_utf8_lossy(&evaluator.stdout).into_owned(), String::from_utf8_lossy(&evaluator.stderr).into_owned(), ) @@ -540,7 +540,7 @@ impl Evaluator<'_> { fn ptr_size(&self) -> usize { match self.db.target_data_layout(self.crate_id) { - Some(x) => x.pointer_size.bytes_usize(), + Some(it) => it.pointer_size.bytes_usize(), None => 8, } } @@ -582,8 +582,8 @@ impl Evaluator<'_> { } else { None }; - let x = from_bytes!(usize, self.read_memory(addr, self.ptr_size())?); - addr = Address::from_usize(x); + let it = from_bytes!(usize, self.read_memory(addr, self.ptr_size())?); + addr = Address::from_usize(it); } ProjectionElem::Index(op) => { let offset = from_bytes!( @@ -599,13 +599,13 @@ impl Evaluator<'_> { let offset = if from_end { let len = match prev_ty.kind(Interner) { TyKind::Array(_, c) => match try_const_usize(self.db, c) { - Some(x) => x as u64, + Some(it) => it as u64, None => { not_supported!("indexing array with unknown const from end") } }, TyKind::Slice(_) => match metadata { - Some(x) => from_bytes!(u64, x.get(self)?), + Some(it) => from_bytes!(u64, it.get(self)?), None => not_supported!("slice place without metadata"), }, _ => not_supported!("bad type for const index"), @@ -625,8 +625,8 @@ impl Evaluator<'_> { _ => TyKind::Error.intern(Interner), }; metadata = match metadata { - Some(x) => { - let prev_len = from_bytes!(u64, x.get(self)?); + Some(it) => { + let prev_len = from_bytes!(u64, it.get(self)?); Some(IntervalOrOwned::Owned( (prev_len - from - to).to_le_bytes().to_vec(), )) @@ -649,8 +649,8 @@ impl Evaluator<'_> { Variants::Single { .. } => &layout, Variants::Multiple { variants, .. } => { &variants[match f.parent { - hir_def::VariantId::EnumVariantId(x) => { - RustcEnumVariantIdx(x.local_id) + hir_def::VariantId::EnumVariantId(it) => { + RustcEnumVariantIdx(it.local_id) } _ => { return Err(MirEvalError::TypeError( @@ -717,8 +717,8 @@ impl Evaluator<'_> { body: &MirBody, args: impl Iterator>, ) -> Result> { - if let Some(x) = self.stack_depth_limit.checked_sub(1) { - self.stack_depth_limit = x; + if let Some(it) = self.stack_depth_limit.checked_sub(1) { + self.stack_depth_limit = it; } else { return Err(MirEvalError::StackOverflow); } @@ -730,9 +730,9 @@ impl Evaluator<'_> { let addr = body .locals .iter() - .map(|(id, x)| { + .map(|(id, it)| { let (size, align) = self.size_align_of_sized( - &x.ty, + &it.ty, &locals, "no unsized local in extending stack", )?; @@ -763,8 +763,8 @@ impl Evaluator<'_> { } loop { let current_block = &body.basic_blocks[current_block_idx]; - if let Some(x) = self.execution_limit.checked_sub(1) { - self.execution_limit = x; + if let Some(it) = self.execution_limit.checked_sub(1) { + self.execution_limit = it; } else { return Err(MirEvalError::ExecutionLimitExceeded); } @@ -801,7 +801,7 @@ impl Evaluator<'_> { let fn_ty = self.operand_ty(func, &locals)?; let args = args .iter() - .map(|x| self.operand_ty_and_eval(x, &mut locals)) + .map(|it| self.operand_ty_and_eval(it, &mut locals)) .collect::>>()?; match &fn_ty.data(Interner).kind { TyKind::Function(_) => { @@ -824,7 +824,7 @@ impl Evaluator<'_> { terminator.span, )?; } - x => not_supported!("unknown function type {x:?}"), + it => not_supported!("unknown function type {it:?}"), } locals.drop_flags.add_place(destination.clone()); current_block_idx = target.expect("broken mir, function without target"); @@ -855,7 +855,7 @@ impl Evaluator<'_> { fn eval_rvalue(&mut self, r: &Rvalue, locals: &mut Locals<'_>) -> Result { use IntervalOrOwned::*; Ok(match r { - Rvalue::Use(x) => Borrowed(self.eval_operand(x, locals)?), + Rvalue::Use(it) => Borrowed(self.eval_operand(it, locals)?), Rvalue::Ref(_, p) => { let (addr, _, metadata) = self.place_addr_and_ty_and_metadata(p, locals)?; let mut r = addr.to_bytes(); @@ -900,9 +900,9 @@ impl Evaluator<'_> { c[0] = 1 - c[0]; } else { match op { - UnOp::Not => c.iter_mut().for_each(|x| *x = !*x), + UnOp::Not => c.iter_mut().for_each(|it| *it = !*it), UnOp::Neg => { - c.iter_mut().for_each(|x| *x = !*x); + c.iter_mut().for_each(|it| *it = !*it); for k in c.iter_mut() { let o; (*k, o) = k.overflowing_add(1); @@ -967,8 +967,8 @@ impl Evaluator<'_> { }; Owned(r.to_le_bytes().into()) } - x => not_supported!( - "invalid binop {x:?} on floating point operators" + it => not_supported!( + "invalid binop {it:?} on floating point operators" ), } } @@ -995,8 +995,8 @@ impl Evaluator<'_> { }; Owned(r.to_le_bytes().into()) } - x => not_supported!( - "invalid binop {x:?} on floating point operators" + it => not_supported!( + "invalid binop {it:?} on floating point operators" ), } } @@ -1076,12 +1076,12 @@ impl Evaluator<'_> { let result = self.compute_discriminant(ty, bytes)?; Owned(result.to_le_bytes().to_vec()) } - Rvalue::Repeat(x, len) => { + Rvalue::Repeat(it, len) => { let len = match try_const_usize(self.db, &len) { - Some(x) => x as usize, + Some(it) => it as usize, None => not_supported!("non evaluatable array len in repeat Rvalue"), }; - let val = self.eval_operand(x, locals)?.get(self)?; + let val = self.eval_operand(it, locals)?.get(self)?; let size = len * val.len(); Owned(val.iter().copied().cycle().take(size).collect()) } @@ -1097,13 +1097,13 @@ impl Evaluator<'_> { Rvalue::Aggregate(kind, values) => { let values = values .iter() - .map(|x| self.eval_operand(x, locals)) + .map(|it| self.eval_operand(it, locals)) .collect::>>()?; match kind { AggregateKind::Array(_) => { let mut r = vec![]; - for x in values { - let value = x.get(&self)?; + for it in values { + let value = it.get(&self)?; r.extend(value); } Owned(r) @@ -1114,11 +1114,12 @@ impl Evaluator<'_> { layout.size.bytes_usize(), &layout, None, - values.iter().map(|&x| x.into()), + values.iter().map(|&it| it.into()), )?) } - AggregateKind::Union(x, f) => { - let layout = self.layout_adt((*x).into(), Substitution::empty(Interner))?; + AggregateKind::Union(it, f) => { + let layout = + self.layout_adt((*it).into(), Substitution::empty(Interner))?; let offset = layout .fields .offset(u32::from(f.local_id.into_raw()) as usize) @@ -1128,14 +1129,14 @@ impl Evaluator<'_> { result[offset..offset + op.len()].copy_from_slice(op); Owned(result) } - AggregateKind::Adt(x, subst) => { + AggregateKind::Adt(it, subst) => { let (size, variant_layout, tag) = - self.layout_of_variant(*x, subst.clone(), locals)?; + self.layout_of_variant(*it, subst.clone(), locals)?; Owned(self.make_by_layout( size, &variant_layout, tag, - values.iter().map(|&x| x.into()), + values.iter().map(|&it| it.into()), )?) } AggregateKind::Closure(ty) => { @@ -1144,7 +1145,7 @@ impl Evaluator<'_> { layout.size.bytes_usize(), &layout, None, - values.iter().map(|&x| x.into()), + values.iter().map(|&it| it.into()), )?) } } @@ -1242,8 +1243,8 @@ impl Evaluator<'_> { as usize; let variant = variants .iter_enumerated() - .map(|(x, _)| x) - .filter(|x| x != untagged_variant) + .map(|(it, _)| it) + .filter(|it| it != untagged_variant) .nth(candidate_tag) .unwrap_or(*untagged_variant) .0; @@ -1264,15 +1265,15 @@ impl Evaluator<'_> { goal: impl Fn(&TyKind) -> Option, ) -> Result { let kind = ty.kind(Interner); - if let Some(x) = goal(kind) { - return Ok(x); + if let Some(it) = goal(kind) { + return Ok(it); } if let TyKind::Adt(id, subst) = kind { if let AdtId::StructId(struct_id) = id.0 { let field_types = self.db.field_types(struct_id.into()); let mut field_types = field_types.iter(); if let Some(ty) = - field_types.next().map(|x| x.1.clone().substitute(Interner, subst)) + field_types.next().map(|it| it.1.clone().substitute(Interner, subst)) { return self.coerce_unsized_look_through_fields(&ty, goal); } @@ -1287,8 +1288,8 @@ impl Evaluator<'_> { current_ty: &Ty, target_ty: &Ty, ) -> Result { - fn for_ptr(x: &TyKind) -> Option { - match x { + fn for_ptr(it: &TyKind) -> Option { + match it { TyKind::Raw(_, ty) | TyKind::Ref(_, _, ty) => Some(ty.clone()), _ => None, } @@ -1314,7 +1315,7 @@ impl Evaluator<'_> { None => { not_supported!("unevaluatble len of array in coerce unsized") } - Some(x) => x as usize, + Some(it) => it as usize, }; let mut r = Vec::with_capacity(16); let addr = addr.get(self)?; @@ -1369,17 +1370,17 @@ impl Evaluator<'_> { fn layout_of_variant( &mut self, - x: VariantId, + it: VariantId, subst: Substitution, locals: &Locals<'_>, ) -> Result<(usize, Arc, Option<(usize, usize, i128)>)> { - let adt = x.adt_id(); + let adt = it.adt_id(); if let DefWithBodyId::VariantId(f) = locals.body.owner { - if let VariantId::EnumVariantId(x) = x { + if let VariantId::EnumVariantId(it) = it { if AdtId::from(f.parent) == adt { // Computing the exact size of enums require resolving the enum discriminants. In order to prevent loops (and // infinite sized type errors) we use a dummy layout - let i = self.const_eval_discriminant(x)?; + let i = self.const_eval_discriminant(it)?; return Ok((16, self.layout(&TyBuilder::unit())?, Some((0, 16, i)))); } } @@ -1392,8 +1393,8 @@ impl Evaluator<'_> { .db .target_data_layout(self.crate_id) .ok_or(MirEvalError::TargetDataLayoutNotAvailable)?; - let enum_variant_id = match x { - VariantId::EnumVariantId(x) => x, + let enum_variant_id = match it { + VariantId::EnumVariantId(it) => it, _ => not_supported!("multi variant layout for non-enums"), }; let rustc_enum_variant_idx = RustcEnumVariantIdx(enum_variant_id.local_id); @@ -1407,8 +1408,8 @@ impl Evaluator<'_> { } else { discriminant = (variants .iter_enumerated() - .filter(|(x, _)| x != untagged_variant) - .position(|(x, _)| x == rustc_enum_variant_idx) + .filter(|(it, _)| it != untagged_variant) + .position(|(it, _)| it == rustc_enum_variant_idx) .unwrap() as i128) .wrapping_add(*niche_start as i128); true @@ -1451,8 +1452,8 @@ impl Evaluator<'_> { Ok(result) } - fn eval_operand(&mut self, x: &Operand, locals: &mut Locals<'_>) -> Result { - Ok(match x { + fn eval_operand(&mut self, it: &Operand, locals: &mut Locals<'_>) -> Result { + Ok(match it { Operand::Copy(p) | Operand::Move(p) => { locals.drop_flags.remove_place(p); self.eval_place(p, locals)? @@ -1528,11 +1529,11 @@ impl Evaluator<'_> { return Ok(&[]); } let (mem, pos) = match addr { - Stack(x) => (&self.stack, x), - Heap(x) => (&self.heap, x), - Invalid(x) => { + Stack(it) => (&self.stack, it), + Heap(it) => (&self.heap, it), + Invalid(it) => { return Err(MirEvalError::UndefinedBehavior(format!( - "read invalid memory address {x} with size {size}" + "read invalid memory address {it} with size {size}" ))); } }; @@ -1545,11 +1546,11 @@ impl Evaluator<'_> { return Ok(()); } let (mem, pos) = match addr { - Stack(x) => (&mut self.stack, x), - Heap(x) => (&mut self.heap, x), - Invalid(x) => { + Stack(it) => (&mut self.stack, it), + Heap(it) => (&mut self.heap, it), + Invalid(it) => { return Err(MirEvalError::UndefinedBehavior(format!( - "write invalid memory address {x} with content {r:?}" + "write invalid memory address {it} with content {r:?}" ))); } }; @@ -1587,7 +1588,7 @@ impl Evaluator<'_> { /// be something that complete this: `error: type {ty} was unsized. {what} should be sized` fn size_of_sized(&self, ty: &Ty, locals: &Locals<'_>, what: &'static str) -> Result { match self.size_align_of(ty, locals)? { - Some(x) => Ok(x.0), + Some(it) => Ok(it.0), None => Err(MirEvalError::TypeIsUnsized(ty.clone(), what)), } } @@ -1601,7 +1602,7 @@ impl Evaluator<'_> { what: &'static str, ) -> Result<(usize, usize)> { match self.size_align_of(ty, locals)? { - Some(x) => Ok(x), + Some(it) => Ok(it), None => Err(MirEvalError::TypeIsUnsized(ty.clone(), what)), } } @@ -1751,14 +1752,14 @@ impl Evaluator<'_> { match size { Some(_) => { let current = from_bytes!(usize, self.read_memory(addr, my_size)?); - if let Some(x) = patch_map.get(¤t) { - self.write_memory(addr, &x.to_le_bytes())?; + if let Some(it) = patch_map.get(¤t) { + self.write_memory(addr, &it.to_le_bytes())?; } } None => { let current = from_bytes!(usize, self.read_memory(addr, my_size / 2)?); - if let Some(x) = patch_map.get(¤t) { - self.write_memory(addr, &x.to_le_bytes())?; + if let Some(it) = patch_map.get(¤t) { + self.write_memory(addr, &it.to_le_bytes())?; } } } @@ -1848,7 +1849,7 @@ impl Evaluator<'_> { generic_args.clone(), self.trait_env.clone(), ) - .map_err(|x| MirEvalError::MirLowerErrorForClosure(closure, x))?; + .map_err(|it| MirEvalError::MirLowerErrorForClosure(closure, it))?; let closure_data = if mir_body.locals[mir_body.param_locals[0]].ty.as_reference().is_some() { closure_data.addr.to_bytes() @@ -1856,7 +1857,7 @@ impl Evaluator<'_> { closure_data.get(self)?.to_owned() }; let arg_bytes = iter::once(Ok(closure_data)) - .chain(args.iter().map(|x| Ok(x.get(&self)?.to_owned()))) + .chain(args.iter().map(|it| Ok(it.get(&self)?.to_owned()))) .collect::>>()?; let bytes = self.interpret_mir(&mir_body, arg_bytes.into_iter()).map_err(|e| { MirEvalError::InFunction(Either::Right(closure), Box::new(e), span, locals.body.owner) @@ -1890,7 +1891,7 @@ impl Evaluator<'_> { size, &variant_layout, tag, - args.iter().map(|x| x.interval.into()), + args.iter().map(|it| it.interval.into()), )?; destination.write_from_bytes(self, &result)?; } @@ -1901,7 +1902,7 @@ impl Evaluator<'_> { size, &variant_layout, tag, - args.iter().map(|x| x.interval.into()), + args.iter().map(|it| it.interval.into()), )?; destination.write_from_bytes(self, &result)?; } @@ -1929,7 +1930,7 @@ impl Evaluator<'_> { return Ok(()); } let arg_bytes = - args.iter().map(|x| Ok(x.get(&self)?.to_owned())).collect::>>()?; + args.iter().map(|it| Ok(it.get(&self)?.to_owned())).collect::>>()?; if let Some(self_ty_idx) = is_dyn_method(self.db, self.trait_env.clone(), def, generic_args.clone()) { @@ -1945,17 +1946,16 @@ impl Evaluator<'_> { ty: ty.clone(), }; let ty = GenericArgData::Ty(ty.clone()).intern(Interner); - let generics_for_target = - Substitution::from_iter( - Interner, - generic_args.iter(Interner).enumerate().map(|(i, x)| { - if i == self_ty_idx { - &ty - } else { - x - } - }), - ); + let generics_for_target = Substitution::from_iter( + Interner, + generic_args.iter(Interner).enumerate().map(|(i, it)| { + if i == self_ty_idx { + &ty + } else { + it + } + }), + ); return self.exec_fn_with_args( def, &args_for_target, @@ -2046,7 +2046,7 @@ impl Evaluator<'_> { let arg1 = { let ty = TyKind::Tuple( args.len(), - Substitution::from_iter(Interner, args.iter().map(|x| x.ty.clone())), + Substitution::from_iter(Interner, args.iter().map(|it| it.ty.clone())), ) .intern(Interner); let layout = self.layout(&ty)?; @@ -2054,7 +2054,7 @@ impl Evaluator<'_> { layout.size.bytes_usize(), &layout, None, - args.iter().map(|x| IntervalOrOwned::Borrowed(x.interval)), + args.iter().map(|it| IntervalOrOwned::Borrowed(it.interval)), )?; // FIXME: there is some leak here let size = layout.size.bytes_usize(); @@ -2129,7 +2129,7 @@ impl Evaluator<'_> { return Ok(()); } let metadata = match metadata { - Some(x) => x.get(self)?.to_vec(), + Some(it) => it.get(self)?.to_vec(), None => vec![], }; self.run_drop_glue_deep(ty, locals, addr, &metadata, span) @@ -2233,10 +2233,10 @@ impl Evaluator<'_> { } } -pub fn pad16(x: &[u8], is_signed: bool) -> [u8; 16] { - let is_negative = is_signed && x.last().unwrap_or(&0) > &127; +pub fn pad16(it: &[u8], is_signed: bool) -> [u8; 16] { + let is_negative = is_signed && it.last().unwrap_or(&0) > &127; let fill_with = if is_negative { 255 } else { 0 }; - x.iter() + it.iter() .copied() .chain(iter::repeat(fill_with)) .take(16) diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs index 8fc93c85d8cd..ab8ecdcf177b 100644 --- a/crates/hir-ty/src/mir/eval/shim.rs +++ b/crates/hir-ty/src/mir/eval/shim.rs @@ -14,15 +14,15 @@ mod simd; macro_rules! from_bytes { ($ty:tt, $value:expr) => { ($ty::from_le_bytes(match ($value).try_into() { - Ok(x) => x, + Ok(it) => it, Err(_) => return Err(MirEvalError::TypeError("mismatched size")), })) }; } macro_rules! not_supported { - ($x: expr) => { - return Err(MirEvalError::NotSupported(format!($x))) + ($it: expr) => { + return Err(MirEvalError::NotSupported(format!($it))) }; } @@ -102,25 +102,25 @@ impl Evaluator<'_> { let alloc_fn = function_data .attrs .iter() - .filter_map(|x| x.path().as_ident()) - .filter_map(|x| x.as_str()) - .find(|x| { + .filter_map(|it| it.path().as_ident()) + .filter_map(|it| it.as_str()) + .find(|it| { [ "rustc_allocator", "rustc_deallocator", "rustc_reallocator", "rustc_allocator_zeroed", ] - .contains(x) + .contains(it) }); if let Some(alloc_fn) = alloc_fn { self.exec_alloc_fn(alloc_fn, args, destination)?; return Ok(true); } - if let Some(x) = self.detect_lang_function(def) { + if let Some(it) = self.detect_lang_function(def) { let arg_bytes = - args.iter().map(|x| Ok(x.get(&self)?.to_owned())).collect::>>()?; - let result = self.exec_lang_item(x, generic_args, &arg_bytes, locals, span)?; + args.iter().map(|it| Ok(it.get(&self)?.to_owned())).collect::>>()?; + let result = self.exec_lang_item(it, generic_args, &arg_bytes, locals, span)?; destination.write_from_bytes(self, &result)?; return Ok(true); } @@ -178,7 +178,7 @@ impl Evaluator<'_> { fn exec_lang_item( &mut self, - x: LangItem, + it: LangItem, generic_args: &Substitution, args: &[Vec], locals: &Locals<'_>, @@ -186,12 +186,11 @@ impl Evaluator<'_> { ) -> Result> { use LangItem::*; let mut args = args.iter(); - match x { + match it { BeginPanic => Err(MirEvalError::Panic("".to_string())), PanicFmt => { let message = (|| { - let x = self.db.crate_def_map(self.crate_id).crate_root(); - let resolver = x.resolver(self.db.upcast()); + let resolver = self.db.crate_def_map(self.crate_id).crate_root().resolver(self.db.upcast()); let Some(format_fn) = resolver.resolve_path_in_value_ns_fully( self.db.upcast(), &hir_def::path::Path::from_known_path_with_no_generic(ModPath::from_segments( @@ -219,7 +218,7 @@ impl Evaluator<'_> { } DropInPlace => { let ty = - generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)).ok_or( + generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)).ok_or( MirEvalError::TypeError( "generic argument of drop_in_place is not provided", ), @@ -236,7 +235,7 @@ impl Evaluator<'_> { )?; Ok(vec![]) } - x => not_supported!("Executing lang item {x:?}"), + it => not_supported!("Executing lang item {it:?}"), } } @@ -521,7 +520,7 @@ impl Evaluator<'_> { } match name { "size_of" => { - let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) + let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) else { return Err(MirEvalError::TypeError("size_of generic arg is not provided")); }; @@ -529,14 +528,14 @@ impl Evaluator<'_> { destination.write_from_bytes(self, &size.to_le_bytes()[0..destination.size]) } "min_align_of" | "pref_align_of" => { - let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) else { + let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) else { return Err(MirEvalError::TypeError("align_of generic arg is not provided")); }; let align = self.layout(ty)?.align.abi.bytes(); destination.write_from_bytes(self, &align.to_le_bytes()[0..destination.size]) } "size_of_val" => { - let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) + let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) else { return Err(MirEvalError::TypeError("size_of_val generic arg is not provided")); }; @@ -552,7 +551,7 @@ impl Evaluator<'_> { } } "min_align_of_val" => { - let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) else { + let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) else { return Err(MirEvalError::TypeError("min_align_of_val generic arg is not provided")); }; let [arg] = args else { @@ -567,7 +566,7 @@ impl Evaluator<'_> { } } "needs_drop" => { - let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) + let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) else { return Err(MirEvalError::TypeError("size_of generic arg is not provided")); }; @@ -694,7 +693,7 @@ impl Evaluator<'_> { _ => unreachable!(), }; let is_overflow = u128overflow - || ans.to_le_bytes()[op_size..].iter().any(|&x| x != 0 && x != 255); + || ans.to_le_bytes()[op_size..].iter().any(|&it| it != 0 && it != 255); let is_overflow = vec![u8::from(is_overflow)]; let layout = self.layout(&result_ty)?; let result = self.make_by_layout( @@ -713,7 +712,7 @@ impl Evaluator<'_> { "copy_nonoverlapping args are not provided", )); }; - let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) + let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) else { return Err(MirEvalError::TypeError( "copy_nonoverlapping generic arg is not provided", @@ -732,7 +731,7 @@ impl Evaluator<'_> { let [ptr, offset] = args else { return Err(MirEvalError::TypeError("offset args are not provided")); }; - let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) + let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) else { return Err(MirEvalError::TypeError("offset generic arg is not provided")); }; @@ -842,7 +841,7 @@ impl Evaluator<'_> { let [arg] = args else { return Err(MirEvalError::TypeError("discriminant_value arg is not provided")); }; - let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) + let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) else { return Err(MirEvalError::TypeError( "discriminant_value generic arg is not provided", @@ -872,7 +871,7 @@ impl Evaluator<'_> { if let Some(target) = self.db.lang_item(self.crate_id, LangItem::FnOnce) { if let Some(def) = target .as_trait() - .and_then(|x| self.db.trait_data(x).method_by_name(&name![call_once])) + .and_then(|it| self.db.trait_data(it).method_by_name(&name![call_once])) { return self.exec_fn_trait( def, @@ -954,7 +953,7 @@ impl Evaluator<'_> { ) -> Result<()> { // We are a single threaded runtime with no UB checking and no optimization, so // we can implement these as normal functions. - let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|x| x.ty(Interner)) else { + let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) else { return Err(MirEvalError::TypeError("atomic intrinsic generic arg is not provided")); }; let Some(arg0) = args.get(0) else { diff --git a/crates/hir-ty/src/mir/eval/shim/simd.rs b/crates/hir-ty/src/mir/eval/shim/simd.rs index 8ba6e18b9a51..4c2e56fe2bf5 100644 --- a/crates/hir-ty/src/mir/eval/shim/simd.rs +++ b/crates/hir-ty/src/mir/eval/shim/simd.rs @@ -9,15 +9,15 @@ use super::*; macro_rules! from_bytes { ($ty:tt, $value:expr) => { ($ty::from_le_bytes(match ($value).try_into() { - Ok(x) => x, + Ok(it) => it, Err(_) => return Err(MirEvalError::TypeError("mismatched size")), })) }; } macro_rules! not_supported { - ($x: expr) => { - return Err(MirEvalError::NotSupported(format!($x))) + ($it: expr) => { + return Err(MirEvalError::NotSupported(format!($it))) }; } @@ -25,7 +25,8 @@ impl Evaluator<'_> { fn detect_simd_ty(&self, ty: &Ty) -> Result { match ty.kind(Interner) { TyKind::Adt(id, subst) => { - let len = match subst.as_slice(Interner).get(1).and_then(|x| x.constant(Interner)) { + let len = match subst.as_slice(Interner).get(1).and_then(|it| it.constant(Interner)) + { Some(len) => len, _ => { if let AdtId::StructId(id) = id.0 { @@ -35,7 +36,7 @@ impl Evaluator<'_> { } }; match try_const_usize(self.db, len) { - Some(x) => Ok(x as usize), + Some(it) => Ok(it as usize), None => Err(MirEvalError::TypeError("simd type with unevaluatable len param")), } } @@ -61,10 +62,10 @@ impl Evaluator<'_> { .get(self)? .iter() .zip(right.get(self)?) - .map(|(&x, &y)| match name { - "and" => x & y, - "or" => x | y, - "xor" => x ^ y, + .map(|(&it, &y)| match name { + "and" => it & y, + "or" => it | y, + "xor" => it ^ y, _ => unreachable!(), }) .collect::>(); @@ -82,9 +83,9 @@ impl Evaluator<'_> { for (l, r) in vector { let mut result = Ordering::Equal; for (l, r) in l.iter().zip(r).rev() { - let x = l.cmp(r); - if x != Ordering::Equal { - result = x; + let it = l.cmp(r); + if it != Ordering::Equal { + result = it; break; } } @@ -107,7 +108,7 @@ impl Evaluator<'_> { let op_count = op.interval.size / op_len; let mut result: u64 = 0; for (i, val) in op.get(self)?.chunks(op_count).enumerate() { - if !val.iter().all(|&x| x == 0) { + if !val.iter().all(|&it| it == 0) { result |= 1 << i; } } @@ -123,7 +124,7 @@ impl Evaluator<'_> { )); }; let index_len = match try_const_usize(self.db, index_len) { - Some(x) => x as usize, + Some(it) => it as usize, None => { return Err(MirEvalError::TypeError( "simd type with unevaluatable len param", @@ -138,7 +139,7 @@ impl Evaluator<'_> { for index in index.get(self)?.chunks(index.interval.size / index_len) { let index = from_bytes!(u32, index) as usize; let val = match vector.clone().nth(index) { - Some(x) => x, + Some(it) => it, None => { return Err(MirEvalError::TypeError( "out of bound access in simd shuffle", diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index 41a773835713..d8fa8cf01a99 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -146,12 +146,12 @@ impl MirLowerError { ConstEvalError::MirEvalError(e) => e.pretty_print(f, db, span_formatter)?, } } - MirLowerError::MissingFunctionDefinition(owner, x) => { + MirLowerError::MissingFunctionDefinition(owner, it) => { let body = db.body(*owner); writeln!( f, "Missing function definition for {}", - body.pretty_print_expr(db.upcast(), *owner, *x) + body.pretty_print_expr(db.upcast(), *owner, *it) )?; } MirLowerError::TypeMismatch(e) => { @@ -202,15 +202,15 @@ impl MirLowerError { } macro_rules! not_supported { - ($x: expr) => { - return Err(MirLowerError::NotSupported(format!($x))) + ($it: expr) => { + return Err(MirLowerError::NotSupported(format!($it))) }; } macro_rules! implementation_error { - ($x: expr) => {{ - ::stdx::never!("MIR lower implementation bug: {}", format!($x)); - return Err(MirLowerError::ImplementationError(format!($x))); + ($it: expr) => {{ + ::stdx::never!("MIR lower implementation bug: {}", format!($it)); + return Err(MirLowerError::ImplementationError(format!($it))); }}; } @@ -490,8 +490,8 @@ impl<'ctx> MirLowerCtx<'ctx> { // It's probably a unit struct or a zero sized function, so no action is needed. Ok(Some(current)) } - x => { - not_supported!("unknown name {x:?} in value name space"); + it => { + not_supported!("unknown name {it:?} in value name space"); } } } @@ -799,8 +799,8 @@ impl<'ctx> MirLowerCtx<'ctx> { Expr::Yield { .. } => not_supported!("yield"), Expr::RecordLit { fields, path, spread, ellipsis: _, is_assignee_expr: _ } => { let spread_place = match spread { - &Some(x) => { - let Some((p, c)) = self.lower_expr_as_place(current, x, true)? else { + &Some(it) => { + let Some((p, c)) = self.lower_expr_as_place(current, it, true)? else { return Ok(None); }; current = c; @@ -840,8 +840,8 @@ impl<'ctx> MirLowerCtx<'ctx> { Some(sp) => operands .into_iter() .enumerate() - .map(|(i, x)| match x { - Some(x) => x, + .map(|(i, it)| match it { + Some(it) => it, None => { let p = sp.project(ProjectionElem::Field(FieldId { @@ -893,7 +893,7 @@ impl<'ctx> MirLowerCtx<'ctx> { Ok(Some(current)) } Expr::Cast { expr, type_ref: _ } => { - let Some((x, current)) = self.lower_expr_to_some_operand(*expr, current)? else { + let Some((it, current)) = self.lower_expr_to_some_operand(*expr, current)? else { return Ok(None); }; let source_ty = self.infer[*expr].clone(); @@ -901,7 +901,7 @@ impl<'ctx> MirLowerCtx<'ctx> { self.push_assignment( current, place, - Rvalue::Cast(cast_kind(&source_ty, &target_ty)?, x, target_ty), + Rvalue::Cast(cast_kind(&source_ty, &target_ty)?, it, target_ty), expr_id.into(), ); Ok(Some(current)) @@ -1003,8 +1003,8 @@ impl<'ctx> MirLowerCtx<'ctx> { .infer .expr_adjustments .get(lhs) - .and_then(|x| x.split_last()) - .map(|x| x.1) + .and_then(|it| it.split_last()) + .map(|it| it.1) .ok_or(MirLowerError::TypeError( "adjustment of binary op was missing", ))?; @@ -1107,15 +1107,15 @@ impl<'ctx> MirLowerCtx<'ctx> { }; let mut lp = None; let mut rp = None; - if let Some(x) = lhs { - let Some((o, c)) = self.lower_expr_to_some_operand(x, current)? else { + if let Some(it) = lhs { + let Some((o, c)) = self.lower_expr_to_some_operand(it, current)? else { return Ok(None); }; lp = Some(o); current = c; } - if let Some(x) = rhs { - let Some((o, c)) = self.lower_expr_to_some_operand(x, current)? else { + if let Some(it) = rhs { + let Some((o, c)) = self.lower_expr_to_some_operand(it, current)? else { return Ok(None); }; rp = Some(o); @@ -1131,8 +1131,8 @@ impl<'ctx> MirLowerCtx<'ctx> { .variant_data .fields() .iter() - .map(|x| { - let o = match x.1.name.as_str() { + .map(|it| { + let o = match it.1.name.as_str() { Some("start") => lp.take(), Some("end") => rp.take(), Some("exhausted") => { @@ -1164,11 +1164,11 @@ impl<'ctx> MirLowerCtx<'ctx> { .projections .clone() .into_iter() - .map(|x| match x { + .map(|it| match it { ProjectionElem::Deref => ProjectionElem::Deref, - ProjectionElem::Field(x) => ProjectionElem::Field(x), - ProjectionElem::TupleOrClosureField(x) => { - ProjectionElem::TupleOrClosureField(x) + ProjectionElem::Field(it) => ProjectionElem::Field(it), + ProjectionElem::TupleOrClosureField(it) => { + ProjectionElem::TupleOrClosureField(it) } ProjectionElem::ConstantIndex { offset, from_end } => { ProjectionElem::ConstantIndex { offset, from_end } @@ -1176,8 +1176,8 @@ impl<'ctx> MirLowerCtx<'ctx> { ProjectionElem::Subslice { from, to } => { ProjectionElem::Subslice { from, to } } - ProjectionElem::OpaqueCast(x) => ProjectionElem::OpaqueCast(x), - ProjectionElem::Index(x) => match x {}, + ProjectionElem::OpaqueCast(it) => ProjectionElem::OpaqueCast(it), + ProjectionElem::Index(it) => match it {}, }) .collect(), }; @@ -1209,8 +1209,8 @@ impl<'ctx> MirLowerCtx<'ctx> { Expr::Tuple { exprs, is_assignee_expr: _ } => { let Some(values) = exprs .iter() - .map(|x| { - let Some((o, c)) = self.lower_expr_to_some_operand(*x, current)? else { + .map(|it| { + let Some((o, c)) = self.lower_expr_to_some_operand(*it, current)? else { return Ok(None); }; current = c; @@ -1239,8 +1239,8 @@ impl<'ctx> MirLowerCtx<'ctx> { }; let Some(values) = elements .iter() - .map(|x| { - let Some((o, c)) = self.lower_expr_to_some_operand(*x, current)? else { + .map(|it| { + let Some((o, c)) = self.lower_expr_to_some_operand(*it, current)? else { return Ok(None); }; current = c; @@ -1285,7 +1285,7 @@ impl<'ctx> MirLowerCtx<'ctx> { fn placeholder_subst(&mut self) -> Substitution { let placeholder_subst = match self.owner.as_generic_def_id() { - Some(x) => TyBuilder::placeholder_subst(self.db, x), + Some(it) => TyBuilder::placeholder_subst(self.db, it), None => Substitution::empty(Interner), }; placeholder_subst @@ -1375,8 +1375,8 @@ impl<'ctx> MirLowerCtx<'ctx> { } hir_def::hir::Literal::Char(c) => u32::from(*c).to_le_bytes().into(), hir_def::hir::Literal::Bool(b) => vec![*b as u8], - hir_def::hir::Literal::Int(x, _) => x.to_le_bytes()[0..size].into(), - hir_def::hir::Literal::Uint(x, _) => x.to_le_bytes()[0..size].into(), + hir_def::hir::Literal::Int(it, _) => it.to_le_bytes()[0..size].into(), + hir_def::hir::Literal::Uint(it, _) => it.to_le_bytes()[0..size].into(), hir_def::hir::Literal::Float(f, _) => match size { 8 => f.into_f64().to_le_bytes().into(), 4 => f.into_f32().to_le_bytes().into(), @@ -1526,9 +1526,9 @@ impl<'ctx> MirLowerCtx<'ctx> { fn expr_ty_after_adjustments(&self, e: ExprId) -> Ty { let mut ty = None; - if let Some(x) = self.infer.expr_adjustments.get(&e) { - if let Some(x) = x.last() { - ty = Some(x.target.clone()); + if let Some(it) = self.infer.expr_adjustments.get(&e) { + if let Some(it) = it.last() { + ty = Some(it.target.clone()); } } ty.unwrap_or_else(|| self.expr_ty_without_adjust(e)) @@ -1550,7 +1550,7 @@ impl<'ctx> MirLowerCtx<'ctx> { fn discr_temp_place(&mut self, current: BasicBlockId) -> Place { match &self.discr_temp { - Some(x) => x.clone(), + Some(it) => it.clone(), None => { let tmp: Place = self .temp(TyBuilder::discr_ty(), current, MirSpan::Unknown) @@ -1597,7 +1597,7 @@ impl<'ctx> MirLowerCtx<'ctx> { } fn has_adjustments(&self, expr_id: ExprId) -> bool { - !self.infer.expr_adjustments.get(&expr_id).map(|x| x.is_empty()).unwrap_or(true) + !self.infer.expr_adjustments.get(&expr_id).map(|it| it.is_empty()).unwrap_or(true) } fn merge_blocks( @@ -1627,7 +1627,7 @@ impl<'ctx> MirLowerCtx<'ctx> { ))? .end { - Some(x) => x, + Some(it) => it, None => { let s = self.new_basic_block(); self.current_loop_blocks @@ -1751,10 +1751,10 @@ impl<'ctx> MirLowerCtx<'ctx> { pick_binding: impl Fn(BindingId) -> bool, ) -> Result { let base_param_count = self.result.param_locals.len(); - self.result.param_locals.extend(params.clone().map(|(x, ty)| { + self.result.param_locals.extend(params.clone().map(|(it, ty)| { let local_id = self.result.locals.alloc(Local { ty }); self.drop_scopes.last_mut().unwrap().locals.push(local_id); - if let Pat::Bind { id, subpat: None } = self.body[x] { + if let Pat::Bind { id, subpat: None } = self.body[it] { if matches!( self.body.bindings[id].mode, BindingAnnotation::Unannotated | BindingAnnotation::Mutable @@ -1795,7 +1795,7 @@ impl<'ctx> MirLowerCtx<'ctx> { fn binding_local(&self, b: BindingId) -> Result { match self.result.binding_locals.get(b) { - Some(x) => Ok(*x), + Some(it) => Ok(*it), None => { // FIXME: It should never happens, but currently it will happen in `const_dependent_on_local` test, which // is a hir lowering problem IMO. @@ -1945,7 +1945,7 @@ pub fn mir_body_for_closure_query( implementation_error!("closure has not callable sig"); }; let current = ctx.lower_params_and_bindings( - args.iter().zip(sig.params().iter()).map(|(x, y)| (*x, y.clone())), + args.iter().zip(sig.params().iter()).map(|(it, y)| (*it, y.clone())), |_| true, )?; if let Some(current) = ctx.lower_expr_to_place(*root, return_slot().into(), current)? { @@ -1964,34 +1964,35 @@ pub fn mir_body_for_closure_query( FnTrait::FnMut | FnTrait::Fn => vec![ProjectionElem::Deref], }; ctx.result.walk_places(|p| { - if let Some(x) = upvar_map.get(&p.local) { - let r = x.iter().find(|x| { - if p.projection.len() < x.0.place.projections.len() { + if let Some(it) = upvar_map.get(&p.local) { + let r = it.iter().find(|it| { + if p.projection.len() < it.0.place.projections.len() { return false; } - for (x, y) in p.projection.iter().zip(x.0.place.projections.iter()) { - match (x, y) { + for (it, y) in p.projection.iter().zip(it.0.place.projections.iter()) { + match (it, y) { (ProjectionElem::Deref, ProjectionElem::Deref) => (), - (ProjectionElem::Field(x), ProjectionElem::Field(y)) if x == y => (), + (ProjectionElem::Field(it), ProjectionElem::Field(y)) if it == y => (), ( - ProjectionElem::TupleOrClosureField(x), + ProjectionElem::TupleOrClosureField(it), ProjectionElem::TupleOrClosureField(y), - ) if x == y => (), + ) if it == y => (), _ => return false, } } true }); match r { - Some(x) => { + Some(it) => { p.local = closure_local; let mut next_projs = closure_projection.clone(); - next_projs.push(PlaceElem::TupleOrClosureField(x.1)); + next_projs.push(PlaceElem::TupleOrClosureField(it.1)); let prev_projs = mem::take(&mut p.projection); - if x.0.kind != CaptureKind::ByValue { + if it.0.kind != CaptureKind::ByValue { next_projs.push(ProjectionElem::Deref); } - next_projs.extend(prev_projs.iter().cloned().skip(x.0.place.projections.len())); + next_projs + .extend(prev_projs.iter().cloned().skip(it.0.place.projections.len())); p.projection = next_projs.into(); } None => err = Some(p.clone()), @@ -2051,8 +2052,8 @@ pub fn lower_to_mir( // need to take this input explicitly. root_expr: ExprId, ) -> Result { - if let Some((_, x)) = infer.type_mismatches().next() { - return Err(MirLowerError::TypeMismatch(x.clone())); + if let Some((_, it)) = infer.type_mismatches().next() { + return Err(MirLowerError::TypeMismatch(it.clone())); } let mut ctx = MirLowerCtx::new(db, owner, body, infer); // 0 is return local @@ -2078,7 +2079,7 @@ pub fn lower_to_mir( body.params .iter() .zip(callable_sig.params().iter()) - .map(|(x, y)| (*x, y.clone())), + .map(|(it, y)| (*it, y.clone())), binding_picker, )?; } diff --git a/crates/hir-ty/src/mir/lower/as_place.rs b/crates/hir-ty/src/mir/lower/as_place.rs index 79f6da48ce56..d58777e2b64e 100644 --- a/crates/hir-ty/src/mir/lower/as_place.rs +++ b/crates/hir-ty/src/mir/lower/as_place.rs @@ -5,8 +5,8 @@ use hir_def::{lang_item::lang_attr, FunctionId}; use hir_expand::name; macro_rules! not_supported { - ($x: expr) => { - return Err(MirLowerError::NotSupported(format!($x))) + ($it: expr) => { + return Err(MirLowerError::NotSupported(format!($it))) }; } @@ -34,7 +34,7 @@ impl MirLowerCtx<'_> { ) -> Result> { let ty = adjustments .last() - .map(|x| x.target.clone()) + .map(|it| it.target.clone()) .unwrap_or_else(|| self.expr_ty_without_adjust(expr_id)); let place = self.temp(ty, prev_block, expr_id.into())?; let Some(current) = @@ -61,7 +61,7 @@ impl MirLowerCtx<'_> { if let Some((last, rest)) = adjustments.split_last() { match last.kind { Adjust::Deref(None) => { - let Some(mut x) = self.lower_expr_as_place_with_adjust( + let Some(mut it) = self.lower_expr_as_place_with_adjust( current, expr_id, upgrade_rvalue, @@ -70,8 +70,8 @@ impl MirLowerCtx<'_> { else { return Ok(None); }; - x.0 = x.0.project(ProjectionElem::Deref); - Ok(Some(x)) + it.0 = it.0.project(ProjectionElem::Deref); + Ok(Some(it)) } Adjust::Deref(Some(od)) => { let Some((r, current)) = self.lower_expr_as_place_with_adjust( @@ -87,7 +87,7 @@ impl MirLowerCtx<'_> { current, r, rest.last() - .map(|x| x.target.clone()) + .map(|it| it.target.clone()) .unwrap_or_else(|| self.expr_ty_without_adjust(expr_id)), last.target.clone(), expr_id.into(), @@ -253,8 +253,8 @@ impl MirLowerCtx<'_> { .infer .expr_adjustments .get(base) - .and_then(|x| x.split_last()) - .map(|x| x.1) + .and_then(|it| it.split_last()) + .map(|it| it.1) .unwrap_or(&[]); let Some((mut p_base, current)) = self.lower_expr_as_place_with_adjust(current, *base, true, adjusts)? diff --git a/crates/hir-ty/src/mir/monomorphization.rs b/crates/hir-ty/src/mir/monomorphization.rs index ce3f7a8e5102..e4574c77e234 100644 --- a/crates/hir-ty/src/mir/monomorphization.rs +++ b/crates/hir-ty/src/mir/monomorphization.rs @@ -29,8 +29,8 @@ use crate::{ use super::{MirBody, MirLowerError, Operand, Rvalue, StatementKind, TerminatorKind}; macro_rules! not_supported { - ($x: expr) => { - return Err(MirLowerError::NotSupported(format!($x))) + ($it: expr) => { + return Err(MirLowerError::NotSupported(format!($it))) }; } @@ -97,16 +97,16 @@ impl FallibleTypeFolder for Filler<'_> { idx: chalk_ir::PlaceholderIndex, _outer_binder: DebruijnIndex, ) -> std::result::Result, Self::Error> { - let x = from_placeholder_idx(self.db, idx); - let Some(idx) = self.generics.as_ref().and_then(|g| g.param_idx(x)) else { + let it = from_placeholder_idx(self.db, idx); + let Some(idx) = self.generics.as_ref().and_then(|g| g.param_idx(it)) else { not_supported!("missing idx in generics"); }; Ok(self .subst .as_slice(Interner) .get(idx) - .and_then(|x| x.constant(Interner)) - .ok_or_else(|| MirLowerError::GenericArgNotProvided(x, self.subst.clone()))? + .and_then(|it| it.constant(Interner)) + .ok_or_else(|| MirLowerError::GenericArgNotProvided(it, self.subst.clone()))? .clone()) } @@ -115,16 +115,16 @@ impl FallibleTypeFolder for Filler<'_> { idx: chalk_ir::PlaceholderIndex, _outer_binder: DebruijnIndex, ) -> std::result::Result { - let x = from_placeholder_idx(self.db, idx); - let Some(idx) = self.generics.as_ref().and_then(|g| g.param_idx(x)) else { + let it = from_placeholder_idx(self.db, idx); + let Some(idx) = self.generics.as_ref().and_then(|g| g.param_idx(it)) else { not_supported!("missing idx in generics"); }; Ok(self .subst .as_slice(Interner) .get(idx) - .and_then(|x| x.ty(Interner)) - .ok_or_else(|| MirLowerError::GenericArgNotProvided(x, self.subst.clone()))? + .and_then(|it| it.ty(Interner)) + .ok_or_else(|| MirLowerError::GenericArgNotProvided(it, self.subst.clone()))? .clone()) } @@ -180,7 +180,7 @@ impl Filler<'_> { MirLowerError::GenericArgNotProvided( self.generics .as_ref() - .and_then(|x| x.iter().nth(b.index)) + .and_then(|it| it.iter().nth(b.index)) .unwrap() .0, self.subst.clone(), diff --git a/crates/hir-ty/src/mir/pretty.rs b/crates/hir-ty/src/mir/pretty.rs index ac23e77bd2bb..781ffaecad56 100644 --- a/crates/hir-ty/src/mir/pretty.rs +++ b/crates/hir-ty/src/mir/pretty.rs @@ -135,7 +135,7 @@ impl<'a> MirPrettyCtx<'a> { fn for_closure(&mut self, closure: ClosureId) { let body = match self.db.mir_body_for_closure(closure) { - Ok(x) => x, + Ok(it) => it, Err(e) => { wln!(self, "// error in {closure:?}: {e:?}"); return; @@ -145,7 +145,7 @@ impl<'a> MirPrettyCtx<'a> { let indent = mem::take(&mut self.indent); let mut ctx = MirPrettyCtx { body: &body, - local_to_binding: body.binding_locals.iter().map(|(x, y)| (*y, x)).collect(), + local_to_binding: body.binding_locals.iter().map(|(it, y)| (*y, it)).collect(), result, indent, ..*self @@ -167,7 +167,7 @@ impl<'a> MirPrettyCtx<'a> { } fn new(body: &'a MirBody, hir_body: &'a Body, db: &'a dyn HirDatabase) -> Self { - let local_to_binding = body.binding_locals.iter().map(|(x, y)| (*y, x)).collect(); + let local_to_binding = body.binding_locals.iter().map(|(it, y)| (*y, it)).collect(); MirPrettyCtx { body, db, @@ -315,17 +315,17 @@ impl<'a> MirPrettyCtx<'a> { } } } - ProjectionElem::TupleOrClosureField(x) => { + ProjectionElem::TupleOrClosureField(it) => { f(this, local, head); - w!(this, ".{}", x); + w!(this, ".{}", it); } ProjectionElem::Index(l) => { f(this, local, head); w!(this, "[{}]", this.local_name(*l).display(this.db)); } - x => { + it => { f(this, local, head); - w!(this, ".{:?}", x); + w!(this, ".{:?}", it); } } } @@ -356,14 +356,14 @@ impl<'a> MirPrettyCtx<'a> { } self.place(p); } - Rvalue::Aggregate(AggregateKind::Tuple(_), x) => { + Rvalue::Aggregate(AggregateKind::Tuple(_), it) => { w!(self, "("); - self.operand_list(x); + self.operand_list(it); w!(self, ")"); } - Rvalue::Aggregate(AggregateKind::Array(_), x) => { + Rvalue::Aggregate(AggregateKind::Array(_), it) => { w!(self, "["); - self.operand_list(x); + self.operand_list(it); w!(self, "]"); } Rvalue::Repeat(op, len) => { @@ -371,19 +371,19 @@ impl<'a> MirPrettyCtx<'a> { self.operand(op); w!(self, "; {}]", len.display(self.db)); } - Rvalue::Aggregate(AggregateKind::Adt(_, _), x) => { + Rvalue::Aggregate(AggregateKind::Adt(_, _), it) => { w!(self, "Adt("); - self.operand_list(x); + self.operand_list(it); w!(self, ")"); } - Rvalue::Aggregate(AggregateKind::Closure(_), x) => { + Rvalue::Aggregate(AggregateKind::Closure(_), it) => { w!(self, "Closure("); - self.operand_list(x); + self.operand_list(it); w!(self, ")"); } - Rvalue::Aggregate(AggregateKind::Union(_, _), x) => { + Rvalue::Aggregate(AggregateKind::Union(_, _), it) => { w!(self, "Union("); - self.operand_list(x); + self.operand_list(it); w!(self, ")"); } Rvalue::Len(p) => { @@ -428,8 +428,8 @@ impl<'a> MirPrettyCtx<'a> { } } - fn operand_list(&mut self, x: &[Operand]) { - let mut it = x.iter(); + fn operand_list(&mut self, it: &[Operand]) { + let mut it = it.iter(); if let Some(first) = it.next() { self.operand(first); for op in it { diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs index 9a2090ab79a2..4de9c872ad6f 100644 --- a/crates/hir/src/display.rs +++ b/crates/hir/src/display.rs @@ -251,8 +251,8 @@ impl HirDisplay for GenericParam { impl HirDisplay for TypeOrConstParam { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { match self.split(f.db) { - either::Either::Left(x) => x.hir_fmt(f), - either::Either::Right(x) => x.hir_fmt(f), + either::Either::Left(it) => it.hir_fmt(f), + either::Either::Right(it) => it.hir_fmt(f), } } } @@ -303,11 +303,11 @@ fn write_generic_params( ) -> Result<(), HirDisplayError> { let params = f.db.generic_params(def); if params.lifetimes.is_empty() - && params.type_or_consts.iter().all(|x| x.1.const_param().is_none()) + && params.type_or_consts.iter().all(|it| it.1.const_param().is_none()) && params .type_or_consts .iter() - .filter_map(|x| x.1.type_param()) + .filter_map(|it| it.1.type_param()) .all(|param| !matches!(param.provenance, TypeParamProvenance::TypeParamList)) { return Ok(()); diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 3688fd0e837d..4eaf99b0b82e 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -1235,7 +1235,7 @@ impl Adt { pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool { let subst = db.generic_defaults(self.into()); subst.iter().any(|ty| match ty.skip_binders().data(Interner) { - GenericArgData::Ty(x) => x.is_unknown(), + GenericArgData::Ty(it) => it.is_unknown(), _ => false, }) } @@ -1636,11 +1636,11 @@ impl DefWithBody { for moof in &borrowck_result.moved_out_of_ref { let span: InFile = match moof.span { mir::MirSpan::ExprId(e) => match source_map.expr_syntax(e) { - Ok(s) => s.map(|x| x.into()), + Ok(s) => s.map(|it| it.into()), Err(_) => continue, }, mir::MirSpan::PatId(p) => match source_map.pat_syntax(p) { - Ok(s) => s.map(|x| match x { + Ok(s) => s.map(|it| match it { Either::Left(e) => e.into(), Either::Right(e) => e.into(), }), @@ -1679,11 +1679,11 @@ impl DefWithBody { for span in spans { let span: InFile = match span { mir::MirSpan::ExprId(e) => match source_map.expr_syntax(*e) { - Ok(s) => s.map(|x| x.into()), + Ok(s) => s.map(|it| it.into()), Err(_) => continue, }, mir::MirSpan::PatId(p) => match source_map.pat_syntax(*p) { - Ok(s) => s.map(|x| match x { + Ok(s) => s.map(|it| match it { Either::Left(e) => e.into(), Either::Right(e) => e.into(), }), @@ -1696,7 +1696,7 @@ impl DefWithBody { } (mir::MutabilityReason::Not, true) => { if !infer.mutated_bindings_in_closure.contains(&binding_id) { - let should_ignore = matches!(body[binding_id].name.as_str(), Some(x) if x.starts_with("_")); + let should_ignore = matches!(body[binding_id].name.as_str(), Some(it) if it.starts_with("_")); if !should_ignore { acc.push(UnusedMut { local }.into()) } @@ -2294,7 +2294,7 @@ impl TypeAlias { pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool { let subst = db.generic_defaults(self.id.into()); subst.iter().any(|ty| match ty.skip_binders().data(Interner) { - GenericArgData::Ty(x) => x.is_unknown(), + GenericArgData::Ty(it) => it.is_unknown(), _ => false, }) } @@ -2684,8 +2684,8 @@ impl GenericDef { let ty_params = generics.type_or_consts.iter().map(|(local_id, _)| { let toc = TypeOrConstParam { id: TypeOrConstParamId { parent: self.into(), local_id } }; match toc.split(db) { - Either::Left(x) => GenericParam::ConstParam(x), - Either::Right(x) => GenericParam::TypeParam(x), + Either::Left(it) => GenericParam::ConstParam(it), + Either::Right(it) => GenericParam::TypeParam(it), } }); self.lifetime_params(db) @@ -2733,14 +2733,14 @@ pub struct LocalSource { impl LocalSource { pub fn as_ident_pat(&self) -> Option<&ast::IdentPat> { match &self.source.value { - Either::Left(x) => Some(x), + Either::Left(it) => Some(it), Either::Right(_) => None, } } pub fn into_ident_pat(self) -> Option { match self.source.value { - Either::Left(x) => Some(x), + Either::Left(it) => Some(it), Either::Right(_) => None, } } @@ -2762,7 +2762,7 @@ impl LocalSource { } pub fn syntax_ptr(self) -> InFile { - self.source.map(|x| SyntaxNodePtr::new(x.syntax())) + self.source.map(|it| SyntaxNodePtr::new(it.syntax())) } } @@ -2821,13 +2821,13 @@ impl Local { Type::new(db, def, ty) } - /// All definitions for this local. Example: `let (a$0, _) | (_, a$0) = x;` + /// All definitions for this local. Example: `let (a$0, _) | (_, a$0) = it;` pub fn sources(self, db: &dyn HirDatabase) -> Vec { let (body, source_map) = db.body_with_source_map(self.parent); self.sources_(db, &body, &source_map).collect() } - /// The leftmost definition for this local. Example: `let (a$0, _) | (_, a) = x;` + /// The leftmost definition for this local. Example: `let (a$0, _) | (_, a) = it;` pub fn primary_source(self, db: &dyn HirDatabase) -> LocalSource { let (body, source_map) = db.body_with_source_map(self.parent); let src = self.sources_(db, &body, &source_map).next().unwrap(); @@ -3081,7 +3081,9 @@ impl TypeParam { let subst = TyBuilder::placeholder_subst(db, self.id.parent()); let ty = ty.substitute(Interner, &subst); match ty.data(Interner) { - GenericArgData::Ty(x) => Some(Type::new_with_resolver_inner(db, &resolver, x.clone())), + GenericArgData::Ty(it) => { + Some(Type::new_with_resolver_inner(db, &resolver, it.clone())) + } _ => None, } } @@ -3120,7 +3122,7 @@ impl ConstParam { pub fn name(self, db: &dyn HirDatabase) -> Name { let params = db.generic_params(self.id.parent()); match params.type_or_consts[self.id.local_id()].name() { - Some(x) => x.clone(), + Some(it) => it.clone(), None => { never!(); Name::missing() @@ -3177,8 +3179,8 @@ impl TypeOrConstParam { pub fn ty(self, db: &dyn HirDatabase) -> Type { match self.split(db) { - Either::Left(x) => x.ty(db), - Either::Right(x) => x.ty(db), + Either::Left(it) => it.ty(db), + Either::Right(it) => it.ty(db), } } } @@ -3676,9 +3678,9 @@ impl Type { }; let parent_subst = TyBuilder::subst_for_def(db, trait_id, None) .push(self.ty.clone()) - .fill(|x| { + .fill(|it| { // FIXME: this code is not covered in tests. - match x { + match it { ParamKind::Type => { GenericArgData::Ty(args.next().unwrap().ty.clone()).intern(Interner) } @@ -3845,7 +3847,7 @@ impl Type { pub fn as_array(&self, db: &dyn HirDatabase) -> Option<(Type, usize)> { if let TyKind::Array(ty, len) = &self.ty.kind(Interner) { - try_const_usize(db, len).map(|x| (self.derived(ty.clone()), x as usize)) + try_const_usize(db, len).map(|it| (self.derived(ty.clone()), it as usize)) } else { None } diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs index c50ffa4f8b70..b971ca62387e 100644 --- a/crates/hir/src/semantics/source_to_def.rs +++ b/crates/hir/src/semantics/source_to_def.rs @@ -298,7 +298,7 @@ impl SourceToDefCtx<'_, '_> { pub(super) fn type_param_to_def(&mut self, src: InFile) -> Option { let container: ChildContainer = self.find_generic_param_container(src.syntax())?.into(); let dyn_map = self.cache_for(container, src.file_id); - dyn_map[keys::TYPE_PARAM].get(&src.value).copied().map(|x| TypeParamId::from_unchecked(x)) + dyn_map[keys::TYPE_PARAM].get(&src.value).copied().map(|it| TypeParamId::from_unchecked(it)) } pub(super) fn lifetime_param_to_def( @@ -316,7 +316,10 @@ impl SourceToDefCtx<'_, '_> { ) -> Option { let container: ChildContainer = self.find_generic_param_container(src.syntax())?.into(); let dyn_map = self.cache_for(container, src.file_id); - dyn_map[keys::CONST_PARAM].get(&src.value).copied().map(|x| ConstParamId::from_unchecked(x)) + dyn_map[keys::CONST_PARAM] + .get(&src.value) + .copied() + .map(|it| ConstParamId::from_unchecked(it)) } pub(super) fn generic_param_to_def( diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs index 932233ad63b6..3ea50659030c 100644 --- a/crates/ide-completion/src/context/analysis.rs +++ b/crates/ide-completion/src/context/analysis.rs @@ -733,7 +733,7 @@ fn classify_name_ref( return None; } let parent = match ast::Fn::cast(parent.parent()?) { - Some(x) => x.param_list(), + Some(it) => it.param_list(), None => ast::ClosureExpr::cast(parent.parent()?)?.param_list(), }; diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index 1362146413e0..ef33386a7e91 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -422,10 +422,10 @@ pub(super) fn definition( |&it| { if !it.parent_enum(db).is_data_carrying(db) { match it.eval(db) { - Ok(x) => { - Some(if x >= 10 { format!("{x} ({x:#X})") } else { format!("{x}") }) + Ok(it) => { + Some(if it >= 10 { format!("{it} ({it:#X})") } else { format!("{it}") }) } - Err(_) => it.value(db).map(|x| format!("{x:?}")), + Err(_) => it.value(db).map(|it| format!("{it:?}")), } } else { None @@ -437,7 +437,7 @@ pub(super) fn definition( Definition::Const(it) => label_value_and_docs(db, it, |it| { let body = it.render_eval(db); match body { - Ok(x) => Some(x), + Ok(it) => Some(it), Err(_) => { let source = it.source(db)?; let mut body = source.value.body()?.syntax().clone(); diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs index 03c7ee478a61..7101e8ed2037 100644 --- a/crates/ide/src/static_index.rs +++ b/crates/ide/src/static_index.rs @@ -73,7 +73,7 @@ impl TokenStore { } pub fn iter(self) -> impl Iterator { - self.0.into_iter().enumerate().map(|(i, x)| (TokenId(i), x)) + self.0.into_iter().enumerate().map(|(id, data)| (TokenId(id), data)) } } @@ -132,9 +132,9 @@ impl StaticIndex<'_> { // hovers let sema = hir::Semantics::new(self.db); let tokens_or_nodes = sema.parse(file_id).syntax().clone(); - let tokens = tokens_or_nodes.descendants_with_tokens().filter_map(|x| match x { + let tokens = tokens_or_nodes.descendants_with_tokens().filter_map(|it| match it { syntax::NodeOrToken::Node(_) => None, - syntax::NodeOrToken::Token(x) => Some(x), + syntax::NodeOrToken::Token(it) => Some(it), }); let hover_config = HoverConfig { links_in_hover: true, @@ -154,28 +154,29 @@ impl StaticIndex<'_> { let range = token.text_range(); let node = token.parent().unwrap(); let def = match get_definition(&sema, token.clone()) { - Some(x) => x, + Some(it) => it, None => continue, }; - let id = if let Some(x) = self.def_map.get(&def) { - *x + let id = if let Some(it) = self.def_map.get(&def) { + *it } else { - let x = self.tokens.insert(TokenStaticData { + let it = self.tokens.insert(TokenStaticData { hover: hover_for_definition(&sema, file_id, def, &node, &hover_config), - definition: def - .try_to_nav(self.db) - .map(|x| FileRange { file_id: x.file_id, range: x.focus_or_full_range() }), + definition: def.try_to_nav(self.db).map(|it| FileRange { + file_id: it.file_id, + range: it.focus_or_full_range(), + }), references: vec![], moniker: current_crate.and_then(|cc| def_to_moniker(self.db, def, cc)), }); - self.def_map.insert(def, x); - x + self.def_map.insert(def, it); + it }; let token = self.tokens.get_mut(id).unwrap(); token.references.push(ReferenceData { range: FileRange { range, file_id }, is_definition: match def.try_to_nav(self.db) { - Some(x) => x.file_id == file_id && x.focus_or_full_range() == range, + Some(it) => it.file_id == file_id && it.focus_or_full_range() == range, None => false, }, }); @@ -216,8 +217,8 @@ impl StaticIndex<'_> { fn get_definition(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> Option { for token in sema.descend_into_macros(token) { let def = IdentClass::classify_token(sema, &token).map(IdentClass::definitions_no_ops); - if let Some(&[x]) = def.as_deref() { - return Some(x); + if let Some(&[it]) = def.as_deref() { + return Some(it); } } None @@ -233,14 +234,14 @@ mod tests { fn check_all_ranges(ra_fixture: &str) { let (analysis, ranges) = fixture::annotations_without_marker(ra_fixture); let s = StaticIndex::compute(&analysis); - let mut range_set: HashSet<_> = ranges.iter().map(|x| x.0).collect(); + let mut range_set: HashSet<_> = ranges.iter().map(|it| it.0).collect(); for f in s.files { for (range, _) in f.tokens { - let x = FileRange { file_id: f.file_id, range }; - if !range_set.contains(&x) { - panic!("additional range {x:?}"); + let it = FileRange { file_id: f.file_id, range }; + if !range_set.contains(&it) { + panic!("additional range {it:?}"); } - range_set.remove(&x); + range_set.remove(&it); } } if !range_set.is_empty() { @@ -251,17 +252,17 @@ mod tests { fn check_definitions(ra_fixture: &str) { let (analysis, ranges) = fixture::annotations_without_marker(ra_fixture); let s = StaticIndex::compute(&analysis); - let mut range_set: HashSet<_> = ranges.iter().map(|x| x.0).collect(); + let mut range_set: HashSet<_> = ranges.iter().map(|it| it.0).collect(); for (_, t) in s.tokens.iter() { - if let Some(x) = t.definition { - if x.range.start() == TextSize::from(0) { + if let Some(t) = t.definition { + if t.range.start() == TextSize::from(0) { // ignore definitions that are whole of file continue; } - if !range_set.contains(&x) { - panic!("additional definition {x:?}"); + if !range_set.contains(&t) { + panic!("additional definition {t:?}"); } - range_set.remove(&x); + range_set.remove(&t); } } if !range_set.is_empty() { diff --git a/crates/rust-analyzer/src/cli/lsif.rs b/crates/rust-analyzer/src/cli/lsif.rs index bb5016349abe..42d180114e52 100644 --- a/crates/rust-analyzer/src/cli/lsif.rs +++ b/crates/rust-analyzer/src/cli/lsif.rs @@ -48,8 +48,8 @@ struct LsifManager<'a> { struct Id(i32); impl From for lsp_types::NumberOrString { - fn from(Id(x): Id) -> Self { - lsp_types::NumberOrString::Number(x) + fn from(Id(it): Id) -> Self { + lsp_types::NumberOrString::Number(it) } } @@ -88,8 +88,8 @@ impl LsifManager<'_> { } fn get_token_id(&mut self, id: TokenId) -> Id { - if let Some(x) = self.token_map.get(&id) { - return *x; + if let Some(it) = self.token_map.get(&id) { + return *it; } let result_set_id = self.add_vertex(lsif::Vertex::ResultSet(lsif::ResultSet { key: None })); self.token_map.insert(id, result_set_id); @@ -97,8 +97,8 @@ impl LsifManager<'_> { } fn get_package_id(&mut self, package_information: PackageInformation) -> Id { - if let Some(x) = self.package_map.get(&package_information) { - return *x; + if let Some(it) = self.package_map.get(&package_information) { + return *it; } let pi = package_information.clone(); let result_set_id = @@ -119,8 +119,8 @@ impl LsifManager<'_> { } fn get_range_id(&mut self, id: FileRange) -> Id { - if let Some(x) = self.range_map.get(&id) { - return *x; + if let Some(it) = self.range_map.get(&id) { + return *it; } let file_id = id.file_id; let doc_id = self.get_file_id(file_id); @@ -142,8 +142,8 @@ impl LsifManager<'_> { } fn get_file_id(&mut self, id: FileId) -> Id { - if let Some(x) = self.file_map.get(&id) { - return *x; + if let Some(it) = self.file_map.get(&id) { + return *it; } let path = self.vfs.file_path(id); let path = path.as_path().unwrap(); @@ -216,18 +216,18 @@ impl LsifManager<'_> { })); let mut edges = token.references.iter().fold( HashMap::<_, Vec>::new(), - |mut edges, x| { + |mut edges, it| { let entry = - edges.entry((x.range.file_id, x.is_definition)).or_insert_with(Vec::new); - entry.push((*self.range_map.get(&x.range).unwrap()).into()); + edges.entry((it.range.file_id, it.is_definition)).or_insert_with(Vec::new); + entry.push((*self.range_map.get(&it.range).unwrap()).into()); edges }, ); - for x in token.references { - if let Some(vertices) = edges.remove(&(x.range.file_id, x.is_definition)) { + for it in token.references { + if let Some(vertices) = edges.remove(&(it.range.file_id, it.is_definition)) { self.add_edge(lsif::Edge::Item(lsif::Item { - document: (*self.file_map.get(&x.range.file_id).unwrap()).into(), - property: Some(if x.is_definition { + document: (*self.file_map.get(&it.range.file_id).unwrap()).into(), + property: Some(if it.is_definition { lsif::ItemKind::Definitions } else { lsif::ItemKind::References From d2693aabd6bc32683808b21e15a7ab20c62a8fa5 Mon Sep 17 00:00:00 2001 From: Ali Bektas Date: Thu, 6 Jul 2023 17:20:01 +0200 Subject: [PATCH 176/324] assist : add enum to glob_import_expand --- .../src/handlers/expand_glob_import.rs | 162 ++++++++++++++++-- 1 file changed, 149 insertions(+), 13 deletions(-) diff --git a/crates/ide-assists/src/handlers/expand_glob_import.rs b/crates/ide-assists/src/handlers/expand_glob_import.rs index 5c435dd9c296..3aff5c9144fe 100644 --- a/crates/ide-assists/src/handlers/expand_glob_import.rs +++ b/crates/ide-assists/src/handlers/expand_glob_import.rs @@ -1,5 +1,5 @@ use either::Either; -use hir::{AssocItem, HasVisibility, Module, ModuleDef, Name, PathResolution, ScopeDef}; +use hir::{AssocItem, Enum, HasVisibility, Module, ModuleDef, Name, PathResolution, ScopeDef}; use ide_db::{ defs::{Definition, NameRefClass}, search::SearchScope, @@ -45,7 +45,8 @@ pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> let use_tree = star.parent().and_then(ast::UseTree::cast)?; let (parent, mod_path) = find_parent_and_path(&star)?; let target_module = match ctx.sema.resolve_path(&mod_path)? { - PathResolution::Def(ModuleDef::Module(it)) => it, + PathResolution::Def(ModuleDef::Module(it)) => Expandable::Module(it), + PathResolution::Def(ModuleDef::Adt(hir::Adt::Enum(e))) => Expandable::Enum(e), _ => return None, }; @@ -90,6 +91,11 @@ pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> ) } +enum Expandable { + Module(Module), + Enum(Enum), +} + fn find_parent_and_path( star: &SyntaxToken, ) -> Option<(Either, ast::Path)> { @@ -168,23 +174,59 @@ impl Refs { } } -fn find_refs_in_mod(ctx: &AssistContext<'_>, module: Module, visible_from: Module) -> Option { - if !is_mod_visible_from(ctx, module, visible_from) { +fn find_refs_in_mod( + ctx: &AssistContext<'_>, + expandable: Expandable, + visible_from: Module, +) -> Option { + if !is_expandable_visible_from(ctx, &expandable, visible_from) { return None; } - let module_scope = module.scope(ctx.db(), Some(visible_from)); - let refs = module_scope.into_iter().filter_map(|(n, d)| Ref::from_scope_def(n, d)).collect(); - Some(Refs(refs)) + match expandable { + Expandable::Module(module) => { + let module_scope = module.scope(ctx.db(), Some(visible_from)); + let refs = + module_scope.into_iter().filter_map(|(n, d)| Ref::from_scope_def(n, d)).collect(); + Some(Refs(refs)) + } + Expandable::Enum(enm) => Some(Refs( + enm.variants(ctx.db()) + .into_iter() + .map(|v| Ref { visible_name: v.name(ctx.db()), def: Definition::Variant(v) }) + .collect(), + )), + } } -fn is_mod_visible_from(ctx: &AssistContext<'_>, module: Module, from: Module) -> bool { - match module.parent(ctx.db()) { - Some(parent) => { - module.visibility(ctx.db()).is_visible_from(ctx.db(), from.into()) - && is_mod_visible_from(ctx, parent, from) +fn is_expandable_visible_from( + ctx: &AssistContext<'_>, + expandable: &Expandable, + from: Module, +) -> bool { + fn is_mod_visible_from(ctx: &AssistContext<'_>, module: Module, from: Module) -> bool { + match module.parent(ctx.db()) { + Some(parent) => { + module.visibility(ctx.db()).is_visible_from(ctx.db(), from.into()) + && is_mod_visible_from(ctx, parent, from) + } + None => true, + } + } + + match expandable { + Expandable::Module(module) => match module.parent(ctx.db()) { + Some(parent) => { + module.visibility(ctx.db()).is_visible_from(ctx.db(), from.into()) + && is_mod_visible_from(ctx, parent, from) + } + None => true, + }, + Expandable::Enum(enm) => { + let module = enm.module(ctx.db()); + enm.visibility(ctx.db()).is_visible_from(ctx.db(), from.into()) + && is_mod_visible_from(ctx, module, from) } - None => true, } } @@ -897,4 +939,98 @@ struct Baz { ", ); } + + #[test] + fn test_support_for_enums() { + check_assist( + expand_glob_import, + r#" +mod foo { + pub enum Foo { + Bar, + Baz, + } +} + +use foo::Foo; +use foo::Foo::*$0; + +struct Strukt { + bar: Foo, +} + +fn main() { + let s: Strukt = Strukt { bar: Bar }; +}"#, + r#" +mod foo { + pub enum Foo { + Bar, + Baz, + } +} + +use foo::Foo; +use foo::Foo::Bar; + +struct Strukt { + bar: Foo, +} + +fn main() { + let s: Strukt = Strukt { bar: Bar }; +}"#, + ) + } + + #[test] + fn test_expanding_multiple_variants_at_once() { + check_assist( + expand_glob_import, + r#" +mod foo { + pub enum Foo { + Bar, + Baz, + } +} + +mod abc { + use super::foo; + use super::foo::Foo::*$0; + + struct Strukt { + baz: foo::Foo, + bar: foo::Foo, + } + + fn trying_calling() { + let s: Strukt = Strukt { bar: Bar , baz : Baz }; + } + +}"#, + r#" +mod foo { + pub enum Foo { + Bar, + Baz, + } +} + +mod abc { + use super::foo; + use super::foo::Foo::{Bar, Baz}; + + struct Strukt { + baz: foo::Foo, + bar: foo::Foo, + } + + fn trying_calling() { + let s: Strukt = Strukt { bar: Bar , baz : Baz }; + } + +}"#, + ) + } } From f12edfdb53b13008dcff9eba2a3fd9a19370d2ee Mon Sep 17 00:00:00 2001 From: Catherine <114838443+Centri3@users.noreply.github.com> Date: Fri, 30 Jun 2023 11:31:08 -0500 Subject: [PATCH 177/324] `manual_float_methods` --- CHANGELOG.md | 2 + clippy_lints/src/declared_lints.rs | 2 + clippy_lints/src/lib.rs | 2 + clippy_lints/src/manual_float_methods.rs | 106 +++++++++++++++++++++++ clippy_utils/src/consts.rs | 11 +++ tests/ui/manual_float_methods.fixed | 37 ++++++++ tests/ui/manual_float_methods.rs | 37 ++++++++ tests/ui/manual_float_methods.stderr | 42 +++++++++ 8 files changed, 239 insertions(+) create mode 100644 clippy_lints/src/manual_float_methods.rs create mode 100644 tests/ui/manual_float_methods.fixed create mode 100644 tests/ui/manual_float_methods.rs create mode 100644 tests/ui/manual_float_methods.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index e2004c2931d5..59719080e440 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4941,6 +4941,8 @@ Released 2018-09-13 [`manual_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten [`manual_instant_elapsed`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_instant_elapsed [`manual_is_ascii_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check +[`manual_is_finite`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_finite +[`manual_is_infinite`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_infinite [`manual_let_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else [`manual_main_separator_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_main_separator_str [`manual_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_map diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index ca97db040792..f8b8b94dd29a 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -273,6 +273,8 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::manual_async_fn::MANUAL_ASYNC_FN_INFO, crate::manual_bits::MANUAL_BITS_INFO, crate::manual_clamp::MANUAL_CLAMP_INFO, + crate::manual_float_methods::MANUAL_IS_FINITE_INFO, + crate::manual_float_methods::MANUAL_IS_INFINITE_INFO, crate::manual_is_ascii_check::MANUAL_IS_ASCII_CHECK_INFO, crate::manual_let_else::MANUAL_LET_ELSE_INFO, crate::manual_main_separator_str::MANUAL_MAIN_SEPARATOR_STR_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 00d46025caa8..9abcbe01176d 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -184,6 +184,7 @@ mod manual_assert; mod manual_async_fn; mod manual_bits; mod manual_clamp; +mod manual_float_methods; mod manual_is_ascii_check; mod manual_let_else; mod manual_main_separator_str; @@ -1073,6 +1074,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(manual_range_patterns::ManualRangePatterns)); store.register_early_pass(|| Box::new(visibility::Visibility)); store.register_late_pass(move |_| Box::new(tuple_array_conversions::TupleArrayConversions { msrv: msrv() })); + store.register_late_pass(|_| Box::new(manual_float_methods::ManualFloatMethods)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/manual_float_methods.rs b/clippy_lints/src/manual_float_methods.rs new file mode 100644 index 000000000000..abf1eb788dd0 --- /dev/null +++ b/clippy_lints/src/manual_float_methods.rs @@ -0,0 +1,106 @@ +use clippy_utils::{ + consts::constant, diagnostics::span_lint_and_sugg, is_from_proc_macro, path_to_local, source::snippet_opt, +}; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for `x == ::INFINITY || x == ::NEG_INFINITY`. + /// + /// ### Why is this bad? + /// This should use the dedicated method instead, `is_infinite`. + /// + /// ### Example + /// ```rust + /// # let x = 1.0f32; + /// if x == f32::INFINITY || x == f32::NEG_INFINITY {} + /// ``` + /// Use instead: + /// ```rust + /// # let x = 1.0f32; + /// if x.is_infinite() {} + /// ``` + #[clippy::version = "1.72.0"] + pub MANUAL_IS_INFINITE, + style, + "use dedicated method to check if a float is infinite" +} +declare_clippy_lint! { + /// ### What it does + /// Checks for `x != ::INFINITY && x != ::NEG_INFINITY`. + /// + /// ### Why is this bad? + /// This should use the dedicated method instead, `is_finite`. + /// + /// ### Example + /// ```rust + /// # let x = 1.0f32; + /// if x != f32::INFINITY && x != f32::NEG_INFINITY {} + /// ``` + /// Use instead: + /// ```rust + /// # let x = 1.0f32; + /// if x.is_finite() {} + /// ``` + #[clippy::version = "1.72.0"] + pub MANUAL_IS_FINITE, + style, + "use dedicated method to check if a float is finite" +} +declare_lint_pass!(ManualFloatMethods => [MANUAL_IS_INFINITE, MANUAL_IS_FINITE]); + +impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if !in_external_macro(cx.sess(), expr.span) + && let ExprKind::Binary(kind, lhs, rhs) = expr.kind + && let ExprKind::Binary(lhs_kind, lhs_lhs, lhs_rhs) = lhs.kind + && let ExprKind::Binary(rhs_kind, rhs_lhs, rhs_rhs) = rhs.kind + && let (operands, consts) = [lhs_lhs, lhs_rhs, rhs_lhs, rhs_rhs] + .into_iter() + .partition::>, _>(|i| path_to_local(i).is_some()) + && let [first, second] = &*operands + && let Some([const_1, const_2]) = consts + .into_iter() + .map(|i| constant(cx, cx.typeck_results(), i).and_then(|c| c.to_bits())) + .collect::>>() + .as_deref() + && path_to_local(first).is_some_and(|f| path_to_local(second).is_some_and(|s| f == s)) + && (is_infinity(*const_1) && is_neg_infinity(*const_2) + || is_neg_infinity(*const_1) && is_infinity(*const_2)) + && let Some(local_snippet) = snippet_opt(cx, first.span) + && !is_from_proc_macro(cx, expr) + { + let (msg, lint, sugg_fn) = match (kind.node, lhs_kind.node, rhs_kind.node) { + (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Eq) => { + ("manually checking if a float is infinite", MANUAL_IS_INFINITE, "is_infinite") + }, + (BinOpKind::And, BinOpKind::Ne, BinOpKind::Ne) => { + ("manually checking if a float is finite", MANUAL_IS_FINITE, "is_finite") + }, + _ => return, + }; + + span_lint_and_sugg( + cx, + lint, + expr.span, + msg, + "try", + format!("{local_snippet}.{sugg_fn}()"), + Applicability::MachineApplicable, + ); + } + } +} + +fn is_infinity(bits: u128) -> bool { + bits == 0x7f80_0000 || bits == 0x7ff0_0000_0000_0000 +} + +fn is_neg_infinity(bits: u128) -> bool { + bits == 0xff80_0000 || bits == 0xfff0_0000_0000_0000 +} diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 87d85d742ce4..b9f8eefeb8e7 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -190,6 +190,17 @@ impl<'tcx> Constant<'tcx> { } } + /// Returns the bit representation if `self` is a bool, integer, or float. + pub fn to_bits(&self) -> Option { + match self { + Constant::Int(int) => Some(*int), + Constant::F32(float) => Some(u128::from(float.to_bits())), + Constant::F64(float) => Some(u128::from(float.to_bits())), + Constant::Bool(bool) => Some(u128::from(*bool)), + _ => None, + } + } + /// Returns the integer value or `None` if `self` or `val_type` is not integer type. pub fn int_value(&self, cx: &LateContext<'_>, val_type: Ty<'_>) -> Option { if let Constant::Int(const_int) = *self { diff --git a/tests/ui/manual_float_methods.fixed b/tests/ui/manual_float_methods.fixed new file mode 100644 index 000000000000..87a23b5a75b7 --- /dev/null +++ b/tests/ui/manual_float_methods.fixed @@ -0,0 +1,37 @@ +//@run-rustfix +//@aux-build:proc_macros.rs:proc-macro +#![allow(clippy::needless_if, unused)] +#![warn(clippy::manual_is_infinite, clippy::manual_is_finite)] + +#[macro_use] +extern crate proc_macros; + +const INFINITE: f32 = f32::INFINITY; +const NEG_INFINITE: f32 = f32::NEG_INFINITY; + +fn main() { + let x = 1.0f32; + if x.is_infinite() {} + if x.is_finite() {} + if x.is_infinite() {} + if x.is_finite() {} + let x = 1.0f64; + if x.is_infinite() {} + if x.is_finite() {} + // Don't lint + if x.is_infinite() {} + if x.is_finite() {} + // If they're doing it this way, they probably know what they're doing + if x.abs() < f64::INFINITY {} + external! { + let x = 1.0; + if x == f32::INFINITY || x == f32::NEG_INFINITY {} + if x != f32::INFINITY && x != f32::NEG_INFINITY {} + } + with_span! { + span + let x = 1.0; + if x == f32::INFINITY || x == f32::NEG_INFINITY {} + if x != f32::INFINITY && x != f32::NEG_INFINITY {} + } +} diff --git a/tests/ui/manual_float_methods.rs b/tests/ui/manual_float_methods.rs new file mode 100644 index 000000000000..9255bf934187 --- /dev/null +++ b/tests/ui/manual_float_methods.rs @@ -0,0 +1,37 @@ +//@run-rustfix +//@aux-build:proc_macros.rs:proc-macro +#![allow(clippy::needless_if, unused)] +#![warn(clippy::manual_is_infinite, clippy::manual_is_finite)] + +#[macro_use] +extern crate proc_macros; + +const INFINITE: f32 = f32::INFINITY; +const NEG_INFINITE: f32 = f32::NEG_INFINITY; + +fn main() { + let x = 1.0f32; + if x == f32::INFINITY || x == f32::NEG_INFINITY {} + if x != f32::INFINITY && x != f32::NEG_INFINITY {} + if x == INFINITE || x == NEG_INFINITE {} + if x != INFINITE && x != NEG_INFINITE {} + let x = 1.0f64; + if x == f64::INFINITY || x == f64::NEG_INFINITY {} + if x != f64::INFINITY && x != f64::NEG_INFINITY {} + // Don't lint + if x.is_infinite() {} + if x.is_finite() {} + // If they're doing it this way, they probably know what they're doing + if x.abs() < f64::INFINITY {} + external! { + let x = 1.0; + if x == f32::INFINITY || x == f32::NEG_INFINITY {} + if x != f32::INFINITY && x != f32::NEG_INFINITY {} + } + with_span! { + span + let x = 1.0; + if x == f32::INFINITY || x == f32::NEG_INFINITY {} + if x != f32::INFINITY && x != f32::NEG_INFINITY {} + } +} diff --git a/tests/ui/manual_float_methods.stderr b/tests/ui/manual_float_methods.stderr new file mode 100644 index 000000000000..00227593a9ea --- /dev/null +++ b/tests/ui/manual_float_methods.stderr @@ -0,0 +1,42 @@ +error: manually checking if a float is infinite + --> $DIR/manual_float_methods.rs:14:8 + | +LL | if x == f32::INFINITY || x == f32::NEG_INFINITY {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.is_infinite()` + | + = note: `-D clippy::manual-is-infinite` implied by `-D warnings` + +error: manually checking if a float is finite + --> $DIR/manual_float_methods.rs:15:8 + | +LL | if x != f32::INFINITY && x != f32::NEG_INFINITY {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.is_finite()` + | + = note: `-D clippy::manual-is-finite` implied by `-D warnings` + +error: manually checking if a float is infinite + --> $DIR/manual_float_methods.rs:16:8 + | +LL | if x == INFINITE || x == NEG_INFINITE {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.is_infinite()` + +error: manually checking if a float is finite + --> $DIR/manual_float_methods.rs:17:8 + | +LL | if x != INFINITE && x != NEG_INFINITE {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.is_finite()` + +error: manually checking if a float is infinite + --> $DIR/manual_float_methods.rs:19:8 + | +LL | if x == f64::INFINITY || x == f64::NEG_INFINITY {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.is_infinite()` + +error: manually checking if a float is finite + --> $DIR/manual_float_methods.rs:20:8 + | +LL | if x != f64::INFINITY && x != f64::NEG_INFINITY {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.is_finite()` + +error: aborting due to 6 previous errors + From 5949f762bfa15e62657771e556c160abe4caee8b Mon Sep 17 00:00:00 2001 From: Catherine <114838443+Centri3@users.noreply.github.com> Date: Sun, 2 Jul 2023 11:43:05 -0500 Subject: [PATCH 178/324] Make suggestion give multiple alternatives --- clippy_lints/src/manual_float_methods.rs | 82 +++++++++++++++++++----- tests/ui/manual_float_methods.fixed | 37 ----------- tests/ui/manual_float_methods.rs | 1 - tests/ui/manual_float_methods.stderr | 62 ++++++++++++++---- 4 files changed, 117 insertions(+), 65 deletions(-) delete mode 100644 tests/ui/manual_float_methods.fixed diff --git a/clippy_lints/src/manual_float_methods.rs b/clippy_lints/src/manual_float_methods.rs index abf1eb788dd0..0f488627b4e9 100644 --- a/clippy_lints/src/manual_float_methods.rs +++ b/clippy_lints/src/manual_float_methods.rs @@ -1,9 +1,9 @@ use clippy_utils::{ - consts::constant, diagnostics::span_lint_and_sugg, is_from_proc_macro, path_to_local, source::snippet_opt, + consts::constant, diagnostics::span_lint_and_then, is_from_proc_macro, path_to_local, source::snippet_opt, }; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_lint::{LateContext, LateLintPass, Lint, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -53,12 +53,37 @@ declare_clippy_lint! { } declare_lint_pass!(ManualFloatMethods => [MANUAL_IS_INFINITE, MANUAL_IS_FINITE]); +#[derive(Clone, Copy)] +enum Variant { + ManualIsInfinite, + ManualIsFinite, +} + +impl Variant { + pub fn lint(self) -> &'static Lint { + match self { + Self::ManualIsInfinite => MANUAL_IS_INFINITE, + Self::ManualIsFinite => MANUAL_IS_FINITE, + } + } + + pub fn msg(self) -> &'static str { + match self { + Self::ManualIsInfinite => "manually checking if a float is infinite", + Self::ManualIsFinite => "manually checking if a float is finite", + } + } +} + impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if !in_external_macro(cx.sess(), expr.span) + && (!cx.param_env.is_const() || cx.tcx.features().active(sym!(const_float_classify))) && let ExprKind::Binary(kind, lhs, rhs) = expr.kind && let ExprKind::Binary(lhs_kind, lhs_lhs, lhs_rhs) = lhs.kind && let ExprKind::Binary(rhs_kind, rhs_lhs, rhs_rhs) = rhs.kind + // Checking all possible scenarios using a function would be a hopeless task, as we have + // 16 possible alignments of constants/operands. For now, let's use `partition`. && let (operands, consts) = [lhs_lhs, lhs_rhs, rhs_lhs, rhs_rhs] .into_iter() .partition::>, _>(|i| path_to_local(i).is_some()) @@ -74,24 +99,51 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods { && let Some(local_snippet) = snippet_opt(cx, first.span) && !is_from_proc_macro(cx, expr) { - let (msg, lint, sugg_fn) = match (kind.node, lhs_kind.node, rhs_kind.node) { - (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Eq) => { - ("manually checking if a float is infinite", MANUAL_IS_INFINITE, "is_infinite") - }, - (BinOpKind::And, BinOpKind::Ne, BinOpKind::Ne) => { - ("manually checking if a float is finite", MANUAL_IS_FINITE, "is_finite") - }, + let variant = match (kind.node, lhs_kind.node, rhs_kind.node) { + (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Eq) => Variant::ManualIsInfinite, + (BinOpKind::And, BinOpKind::Ne, BinOpKind::Ne) => Variant::ManualIsFinite, _ => return, }; - span_lint_and_sugg( + span_lint_and_then( cx, - lint, + variant.lint(), expr.span, - msg, - "try", - format!("{local_snippet}.{sugg_fn}()"), - Applicability::MachineApplicable, + variant.msg(), + |diag| { + match variant { + Variant::ManualIsInfinite => { + diag.span_suggestion( + expr.span, + "use the dedicated method instead", + format!("{local_snippet}.is_infinite()"), + Applicability::MachineApplicable, + ); + }, + Variant::ManualIsFinite => { + // TODO: There's probably some better way to do this, i.e., create + // multiple suggestions with notes between each of them + diag.span_suggestion_verbose( + expr.span, + "use the dedicated method instead", + format!("{local_snippet}.is_finite()"), + Applicability::MaybeIncorrect, + ); + diag.span_suggestion_verbose( + expr.span, + "this will alter how it handles NaN; if that is a problem, use instead", + format!("{local_snippet}.is_finite() || {local_snippet}.is_nan()"), + Applicability::MaybeIncorrect, + ); + diag.span_suggestion_verbose( + expr.span, + "or, for conciseness", + format!("!{local_snippet}.is_infinite()"), + Applicability::MaybeIncorrect, + ); + } + } + } ); } } diff --git a/tests/ui/manual_float_methods.fixed b/tests/ui/manual_float_methods.fixed deleted file mode 100644 index 87a23b5a75b7..000000000000 --- a/tests/ui/manual_float_methods.fixed +++ /dev/null @@ -1,37 +0,0 @@ -//@run-rustfix -//@aux-build:proc_macros.rs:proc-macro -#![allow(clippy::needless_if, unused)] -#![warn(clippy::manual_is_infinite, clippy::manual_is_finite)] - -#[macro_use] -extern crate proc_macros; - -const INFINITE: f32 = f32::INFINITY; -const NEG_INFINITE: f32 = f32::NEG_INFINITY; - -fn main() { - let x = 1.0f32; - if x.is_infinite() {} - if x.is_finite() {} - if x.is_infinite() {} - if x.is_finite() {} - let x = 1.0f64; - if x.is_infinite() {} - if x.is_finite() {} - // Don't lint - if x.is_infinite() {} - if x.is_finite() {} - // If they're doing it this way, they probably know what they're doing - if x.abs() < f64::INFINITY {} - external! { - let x = 1.0; - if x == f32::INFINITY || x == f32::NEG_INFINITY {} - if x != f32::INFINITY && x != f32::NEG_INFINITY {} - } - with_span! { - span - let x = 1.0; - if x == f32::INFINITY || x == f32::NEG_INFINITY {} - if x != f32::INFINITY && x != f32::NEG_INFINITY {} - } -} diff --git a/tests/ui/manual_float_methods.rs b/tests/ui/manual_float_methods.rs index 9255bf934187..b772202c003f 100644 --- a/tests/ui/manual_float_methods.rs +++ b/tests/ui/manual_float_methods.rs @@ -1,4 +1,3 @@ -//@run-rustfix //@aux-build:proc_macros.rs:proc-macro #![allow(clippy::needless_if, unused)] #![warn(clippy::manual_is_infinite, clippy::manual_is_finite)] diff --git a/tests/ui/manual_float_methods.stderr b/tests/ui/manual_float_methods.stderr index 00227593a9ea..7f4a4d2e95b3 100644 --- a/tests/ui/manual_float_methods.stderr +++ b/tests/ui/manual_float_methods.stderr @@ -1,42 +1,80 @@ error: manually checking if a float is infinite - --> $DIR/manual_float_methods.rs:14:8 + --> $DIR/manual_float_methods.rs:13:8 | LL | if x == f32::INFINITY || x == f32::NEG_INFINITY {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.is_infinite()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()` | = note: `-D clippy::manual-is-infinite` implied by `-D warnings` error: manually checking if a float is finite - --> $DIR/manual_float_methods.rs:15:8 + --> $DIR/manual_float_methods.rs:14:8 | LL | if x != f32::INFINITY && x != f32::NEG_INFINITY {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.is_finite()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::manual-is-finite` implied by `-D warnings` +help: use the dedicated method instead + | +LL | if x.is_finite() {} + | ~~~~~~~~~~~~~ +help: this will alter how it handles NaN; if that is a problem, use instead + | +LL | if x.is_finite() || x.is_nan() {} + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +help: or, for conciseness + | +LL | if !x.is_infinite() {} + | ~~~~~~~~~~~~~~~~ error: manually checking if a float is infinite - --> $DIR/manual_float_methods.rs:16:8 + --> $DIR/manual_float_methods.rs:15:8 | LL | if x == INFINITE || x == NEG_INFINITE {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.is_infinite()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()` error: manually checking if a float is finite - --> $DIR/manual_float_methods.rs:17:8 + --> $DIR/manual_float_methods.rs:16:8 | LL | if x != INFINITE && x != NEG_INFINITE {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.is_finite()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use the dedicated method instead + | +LL | if x.is_finite() {} + | ~~~~~~~~~~~~~ +help: this will alter how it handles NaN; if that is a problem, use instead + | +LL | if x.is_finite() || x.is_nan() {} + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +help: or, for conciseness + | +LL | if !x.is_infinite() {} + | ~~~~~~~~~~~~~~~~ error: manually checking if a float is infinite - --> $DIR/manual_float_methods.rs:19:8 + --> $DIR/manual_float_methods.rs:18:8 | LL | if x == f64::INFINITY || x == f64::NEG_INFINITY {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.is_infinite()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()` error: manually checking if a float is finite - --> $DIR/manual_float_methods.rs:20:8 + --> $DIR/manual_float_methods.rs:19:8 | LL | if x != f64::INFINITY && x != f64::NEG_INFINITY {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.is_finite()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use the dedicated method instead + | +LL | if x.is_finite() {} + | ~~~~~~~~~~~~~ +help: this will alter how it handles NaN; if that is a problem, use instead + | +LL | if x.is_finite() || x.is_nan() {} + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +help: or, for conciseness + | +LL | if !x.is_infinite() {} + | ~~~~~~~~~~~~~~~~ error: aborting due to 6 previous errors From ebaf8c8135dfc0d655fe26fe38b5282df39fff26 Mon Sep 17 00:00:00 2001 From: DropDemBits Date: Thu, 6 Jul 2023 23:25:02 -0400 Subject: [PATCH 179/324] fix: Indent after pressing enter on a blank line --- editors/code/src/config.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index da7c74c28bae..5c63823321ce 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts @@ -99,7 +99,8 @@ export class Config { let onEnterRules: vscode.OnEnterRule[] = [ { // Carry indentation from the previous line - beforeText: /^\s*$/, + // if it's only whitespace + beforeText: /^\s+$/, action: { indentAction: vscode.IndentAction.None }, }, { From 4a444e768c05c288725143fd2ec3a7e0abb79324 Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Fri, 7 Jul 2023 15:07:29 +0330 Subject: [PATCH 180/324] Implement recursion in mir interpreter without recursion --- crates/hir-def/src/db.rs | 5 +- crates/hir-def/src/lang_item.rs | 8 +- crates/hir-ty/src/chalk_db.rs | 4 +- crates/hir-ty/src/consteval.rs | 8 +- crates/hir-ty/src/consteval/tests.rs | 4 +- crates/hir-ty/src/db.rs | 8 + crates/hir-ty/src/lower.rs | 4 +- crates/hir-ty/src/method_resolution.rs | 2 +- crates/hir-ty/src/mir/eval.rs | 617 +++++++++++++++--------- crates/hir-ty/src/mir/eval/shim.rs | 24 +- crates/hir-ty/src/mir/eval/shim/simd.rs | 2 +- crates/hir-ty/src/mir/eval/tests.rs | 2 +- crates/hir-ty/src/mir/lower/as_place.rs | 4 +- crates/hir/src/lib.rs | 2 +- crates/hir/src/source_analyzer.rs | 2 +- 15 files changed, 432 insertions(+), 264 deletions(-) diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs index 33c3a59db220..82e6dfb30c81 100644 --- a/crates/hir-def/src/db.rs +++ b/crates/hir-def/src/db.rs @@ -18,7 +18,7 @@ use crate::{ generics::GenericParams, import_map::ImportMap, item_tree::{AttrOwner, ItemTree}, - lang_item::{LangItem, LangItemTarget, LangItems}, + lang_item::{self, LangItem, LangItemTarget, LangItems}, nameres::{diagnostics::DefDiagnostic, DefMap}, visibility::{self, Visibility}, AttrDefId, BlockId, BlockLoc, ConstBlockId, ConstBlockLoc, ConstId, ConstLoc, DefWithBodyId, @@ -204,6 +204,9 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast Attrs; + #[salsa::invoke(lang_item::lang_attr_query)] + fn lang_attr(&self, def: AttrDefId) -> Option; + #[salsa::transparent] #[salsa::invoke(AttrsWithOwner::attrs_with_owner)] fn attrs_with_owner(&self, def: AttrDefId) -> AttrsWithOwner; diff --git a/crates/hir-def/src/lang_item.rs b/crates/hir-def/src/lang_item.rs index 0e9ac58fbaaa..627479bb7c1b 100644 --- a/crates/hir-def/src/lang_item.rs +++ b/crates/hir-def/src/lang_item.rs @@ -180,15 +180,15 @@ impl LangItems { T: Into + Copy, { let _p = profile::span("collect_lang_item"); - if let Some(lang_item) = lang_attr(db, item) { + if let Some(lang_item) = db.lang_attr(item.into()) { self.items.entry(lang_item).or_insert_with(|| constructor(item)); } } } -pub fn lang_attr(db: &dyn DefDatabase, item: impl Into + Copy) -> Option { - let attrs = db.attrs(item.into()); - attrs.by_key("lang").string_value().cloned().and_then(|it| LangItem::from_str(&it)) +pub(crate) fn lang_attr_query(db: &dyn DefDatabase, item: AttrDefId) -> Option { + let attrs = db.attrs(item); + attrs.by_key("lang").string_value().and_then(|it| LangItem::from_str(&it)) } pub enum GenericRequirement { diff --git a/crates/hir-ty/src/chalk_db.rs b/crates/hir-ty/src/chalk_db.rs index 0038b0d18365..50eabc867b8a 100644 --- a/crates/hir-ty/src/chalk_db.rs +++ b/crates/hir-ty/src/chalk_db.rs @@ -11,7 +11,7 @@ use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait}; use base_db::CrateId; use hir_def::{ hir::Movability, - lang_item::{lang_attr, LangItem, LangItemTarget}, + lang_item::{LangItem, LangItemTarget}, AssocItemId, BlockId, GenericDefId, HasModule, ItemContainerId, Lookup, TypeAliasId, }; use hir_expand::name::name; @@ -565,7 +565,7 @@ pub(crate) fn trait_datum_query( let where_clauses = convert_where_clauses(db, trait_.into(), &bound_vars); let associated_ty_ids = trait_data.associated_types().map(to_assoc_type_id).collect(); let trait_datum_bound = rust_ir::TraitDatumBound { where_clauses }; - let well_known = lang_attr(db.upcast(), trait_).and_then(well_known_trait_from_lang_item); + let well_known = db.lang_attr(trait_.into()).and_then(well_known_trait_from_lang_item); let trait_datum = TraitDatum { id: trait_id, binders: make_binders(db, &generic_params, trait_datum_bound), diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs index 537e28894a88..4de90d40a7c7 100644 --- a/crates/hir-ty/src/consteval.rs +++ b/crates/hir-ty/src/consteval.rs @@ -228,7 +228,7 @@ pub(crate) fn const_eval_query( } GeneralConstId::InTypeConstId(c) => db.mir_body(c.into())?, }; - let c = interpret_mir(db, &body, false).0?; + let c = interpret_mir(db, body, false).0?; Ok(c) } @@ -241,7 +241,7 @@ pub(crate) fn const_eval_static_query( Substitution::empty(Interner), db.trait_environment_for_body(def.into()), )?; - let c = interpret_mir(db, &body, false).0?; + let c = interpret_mir(db, body, false).0?; Ok(c) } @@ -268,7 +268,7 @@ pub(crate) fn const_eval_discriminant_variant( Substitution::empty(Interner), db.trait_environment_for_body(def), )?; - let c = interpret_mir(db, &mir_body, false).0?; + let c = interpret_mir(db, mir_body, false).0?; let c = try_const_usize(db, &c).unwrap() as i128; Ok(c) } @@ -293,7 +293,7 @@ pub(crate) fn eval_to_const( } let infer = ctx.clone().resolve_all(); if let Ok(mir_body) = lower_to_mir(ctx.db, ctx.owner, &ctx.body, &infer, expr) { - if let Ok(result) = interpret_mir(db, &mir_body, true).0 { + if let Ok(result) = interpret_mir(db, Arc::new(mir_body), true).0 { return result; } } diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs index d5feb6c7fefd..35ecb898245f 100644 --- a/crates/hir-ty/src/consteval/tests.rs +++ b/crates/hir-ty/src/consteval/tests.rs @@ -16,7 +16,7 @@ mod intrinsics; fn simplify(e: ConstEvalError) -> ConstEvalError { match e { - ConstEvalError::MirEvalError(MirEvalError::InFunction(_, e, _, _)) => { + ConstEvalError::MirEvalError(MirEvalError::InFunction(e, _)) => { simplify(ConstEvalError::MirEvalError(*e)) } _ => e, @@ -2471,7 +2471,7 @@ fn exec_limits() { } const GOAL: i32 = f(0); "#, - |e| e == ConstEvalError::MirEvalError(MirEvalError::StackOverflow), + |e| e == ConstEvalError::MirEvalError(MirEvalError::ExecutionLimitExceeded), ); // Reasonable code should still work check_number( diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs index 9dd810f844d4..14b719ea4124 100644 --- a/crates/hir-ty/src/db.rs +++ b/crates/hir-ty/src/db.rs @@ -110,6 +110,14 @@ pub trait HirDatabase: DefDatabase + Upcast { #[salsa::invoke(crate::layout::target_data_layout_query)] fn target_data_layout(&self, krate: CrateId) -> Option>; + #[salsa::invoke(crate::method_resolution::lookup_impl_method_query)] + fn lookup_impl_method( + &self, + env: Arc, + func: FunctionId, + fn_subst: Substitution, + ) -> (FunctionId, Substitution); + #[salsa::invoke(crate::lower::callable_item_sig)] fn callable_item_signature(&self, def: CallableDefId) -> PolyFnSig; diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index e21f77a2d748..2837f400bceb 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -23,7 +23,7 @@ use hir_def::{ generics::{ TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget, }, - lang_item::{lang_attr, LangItem}, + lang_item::LangItem, nameres::MacroSubNs, path::{GenericArg, GenericArgs, ModPath, Path, PathKind, PathSegment, PathSegments}, resolver::{HasResolver, Resolver, TypeNs}, @@ -1012,7 +1012,7 @@ impl<'a> TyLoweringContext<'a> { // (So ideally, we'd only ignore `~const Drop` here) // - `Destruct` impls are built-in in 1.62 (current nightly as of 08-04-2022), so until // the builtin impls are supported by Chalk, we ignore them here. - if let Some(lang) = lang_attr(self.db.upcast(), tr.hir_trait_id()) { + if let Some(lang) = self.db.lang_attr(tr.hir_trait_id().into()) { if matches!(lang, LangItem::Drop | LangItem::Destruct) { return false; } diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index 5781ea48ee22..5e1040bc6aac 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -682,7 +682,7 @@ pub fn is_dyn_method( /// Looks up the impl method that actually runs for the trait method `func`. /// /// Returns `func` if it's not a method defined in a trait or the lookup failed. -pub fn lookup_impl_method( +pub(crate) fn lookup_impl_method_query( db: &dyn HirDatabase, env: Arc, func: FunctionId, diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index 299efb714549..c76d066232c9 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -1,6 +1,6 @@ //! This module provides a MIR interpreter, which is used in const eval. -use std::{borrow::Cow, collections::HashMap, fmt::Write, iter, ops::Range}; +use std::{borrow::Cow, cell::RefCell, collections::HashMap, fmt::Write, iter, mem, ops::Range}; use base_db::{CrateId, FileId}; use chalk_ir::Mutability; @@ -8,7 +8,7 @@ use either::Either; use hir_def::{ builtin_type::BuiltinType, data::adt::{StructFlags, VariantData}, - lang_item::{lang_attr, LangItem}, + lang_item::LangItem, layout::{TagEncoding, Variants}, AdtId, DefWithBodyId, EnumVariantId, FunctionId, HasModule, ItemContainerId, Lookup, StaticId, VariantId, @@ -28,7 +28,7 @@ use crate::{ infer::PointerCast, layout::{Layout, LayoutError, RustcEnumVariantIdx}, mapping::from_chalk, - method_resolution::{is_dyn_method, lookup_impl_method}, + method_resolution::is_dyn_method, name, static_lifetime, traits::FnTrait, utils::{detect_variant_from_bytes, ClosureSubst}, @@ -37,8 +37,8 @@ use crate::{ }; use super::{ - return_slot, AggregateKind, BinOp, CastKind, LocalId, MirBody, MirLowerError, MirSpan, Operand, - Place, ProjectionElem, Rvalue, StatementKind, TerminatorKind, UnOp, + return_slot, AggregateKind, BasicBlockId, BinOp, CastKind, LocalId, MirBody, MirLowerError, + MirSpan, Operand, Place, ProjectionElem, Rvalue, StatementKind, TerminatorKind, UnOp, }; mod shim; @@ -114,11 +114,20 @@ impl TlsData { } } +struct StackFrame { + body: Arc, + locals: Locals, + destination: Option, + prev_stack_ptr: usize, + span: (MirSpan, DefWithBodyId), +} + pub struct Evaluator<'a> { db: &'a dyn HirDatabase, trait_env: Arc, stack: Vec, heap: Vec, + code_stack: Vec, /// Stores the global location of the statics. We const evaluate every static first time we need it /// and see it's missing, then we add it to this to reuse. static_locations: FxHashMap, @@ -129,6 +138,7 @@ pub struct Evaluator<'a> { thread_local_storage: TlsData, stdout: Vec, stderr: Vec, + layout_cache: RefCell>>, crate_id: CrateId, // FIXME: This is a workaround, see the comment on `interpret_mir` assert_placeholder_ty_is_unused: bool, @@ -192,7 +202,7 @@ impl IntervalAndTy { addr: Address, ty: Ty, evaluator: &Evaluator<'_>, - locals: &Locals<'_>, + locals: &Locals, ) -> Result { let size = evaluator.size_of_sized(&ty, locals, "type of interval")?; Ok(IntervalAndTy { interval: Interval { addr, size }, ty }) @@ -292,7 +302,7 @@ pub enum MirEvalError { TypeIsUnsized(Ty, &'static str), NotSupported(String), InvalidConst(Const), - InFunction(Either, Box, MirSpan, DefWithBodyId), + InFunction(Box, Vec<(Either, MirSpan, DefWithBodyId)>), ExecutionLimitExceeded, StackOverflow, TargetDataLayoutNotAvailable, @@ -310,40 +320,42 @@ impl MirEvalError { ) -> std::result::Result<(), std::fmt::Error> { writeln!(f, "Mir eval error:")?; let mut err = self; - while let MirEvalError::InFunction(func, e, span, def) = err { + while let MirEvalError::InFunction(e, stack) = err { err = e; - match func { - Either::Left(func) => { - let function_name = db.function_data(*func); - writeln!( - f, - "In function {} ({:?})", - function_name.name.display(db.upcast()), - func - )?; - } - Either::Right(clos) => { - writeln!(f, "In {:?}", clos)?; + for (func, span, def) in stack.iter().take(30).rev() { + match func { + Either::Left(func) => { + let function_name = db.function_data(*func); + writeln!( + f, + "In function {} ({:?})", + function_name.name.display(db.upcast()), + func + )?; + } + Either::Right(clos) => { + writeln!(f, "In {:?}", clos)?; + } } + let source_map = db.body_with_source_map(*def).1; + let span: InFile = match span { + MirSpan::ExprId(e) => match source_map.expr_syntax(*e) { + Ok(s) => s.map(|it| it.into()), + Err(_) => continue, + }, + MirSpan::PatId(p) => match source_map.pat_syntax(*p) { + Ok(s) => s.map(|it| match it { + Either::Left(e) => e.into(), + Either::Right(e) => e.into(), + }), + Err(_) => continue, + }, + MirSpan::Unknown => continue, + }; + let file_id = span.file_id.original_file(db.upcast()); + let text_range = span.value.text_range(); + writeln!(f, "{}", span_formatter(file_id, text_range))?; } - let source_map = db.body_with_source_map(*def).1; - let span: InFile = match span { - MirSpan::ExprId(e) => match source_map.expr_syntax(*e) { - Ok(s) => s.map(|it| it.into()), - Err(_) => continue, - }, - MirSpan::PatId(p) => match source_map.pat_syntax(*p) { - Ok(s) => s.map(|it| match it { - Either::Left(e) => e.into(), - Either::Right(e) => e.into(), - }), - Err(_) => continue, - }, - MirSpan::Unknown => continue, - }; - let file_id = span.file_id.original_file(db.upcast()); - let text_range = span.value.text_range(); - writeln!(f, "{}", span_formatter(file_id, text_range))?; } match err { MirEvalError::InFunction(..) => unreachable!(), @@ -423,13 +435,7 @@ impl std::fmt::Debug for MirEvalError { let data = &arg0.data(Interner); f.debug_struct("InvalidConst").field("ty", &data.ty).field("value", &arg0).finish() } - Self::InFunction(func, e, span, _) => { - let mut e = &**e; - let mut stack = vec![(*func, *span)]; - while let Self::InFunction(f, next_e, span, _) = e { - e = &next_e; - stack.push((*f, *span)); - } + Self::InFunction(e, stack) => { f.debug_struct("WithStack").field("error", e).field("stack", &stack).finish() } } @@ -459,15 +465,15 @@ impl DropFlags { } #[derive(Debug)] -struct Locals<'a> { - ptr: &'a ArenaMap, - body: &'a MirBody, +struct Locals { + ptr: ArenaMap, + body: Arc, drop_flags: DropFlags, } pub fn interpret_mir( db: &dyn HirDatabase, - body: &MirBody, + body: Arc, // FIXME: This is workaround. Ideally, const generics should have a separate body (issue #7434), but now // they share their body with their parent, so in MIR lowering we have locals of the parent body, which // might have placeholders. With this argument, we (wrongly) assume that every placeholder type has @@ -476,16 +482,16 @@ pub fn interpret_mir( assert_placeholder_ty_is_unused: bool, ) -> (Result, String, String) { let ty = body.locals[return_slot()].ty.clone(); - let mut evaluator = Evaluator::new(db, body, assert_placeholder_ty_is_unused); + let mut evaluator = Evaluator::new(db, &body, assert_placeholder_ty_is_unused); let it: Result = (|| { if evaluator.ptr_size() != std::mem::size_of::() { not_supported!("targets with different pointer size from host"); } - let bytes = evaluator.interpret_mir(&body, None.into_iter())?; + let bytes = evaluator.interpret_mir(body.clone(), None.into_iter())?; let mut memory_map = evaluator.create_memory_map( &bytes, &ty, - &Locals { ptr: &ArenaMap::new(), body: &body, drop_flags: DropFlags::default() }, + &Locals { ptr: ArenaMap::new(), body, drop_flags: DropFlags::default() }, )?; memory_map.vtable = evaluator.vtable_map.clone(); return Ok(intern_const_scalar(ConstScalar::Bytes(bytes, memory_map), ty)); @@ -508,6 +514,7 @@ impl Evaluator<'_> { Evaluator { stack: vec![0], heap: vec![0], + code_stack: vec![], vtable_map: VTableMap::default(), thread_local_storage: TlsData::default(), static_locations: HashMap::default(), @@ -519,14 +526,15 @@ impl Evaluator<'_> { assert_placeholder_ty_is_unused, stack_depth_limit: 100, execution_limit: 1000_000, + layout_cache: RefCell::new(HashMap::default()), } } - fn place_addr(&self, p: &Place, locals: &Locals<'_>) -> Result
{ + fn place_addr(&self, p: &Place, locals: &Locals) -> Result
{ Ok(self.place_addr_and_ty_and_metadata(p, locals)?.0) } - fn place_interval(&self, p: &Place, locals: &Locals<'_>) -> Result { + fn place_interval(&self, p: &Place, locals: &Locals) -> Result { let place_addr_and_ty = self.place_addr_and_ty_and_metadata(p, locals)?; Ok(Interval { addr: place_addr_and_ty.0, @@ -548,7 +556,7 @@ impl Evaluator<'_> { fn place_addr_and_ty_and_metadata<'a>( &'a self, p: &Place, - locals: &'a Locals<'a>, + locals: &'a Locals, ) -> Result<(Address, Ty, Option)> { let mut addr = locals.ptr[p.local].addr; let mut ty: Ty = locals.body.locals[p.local].ty.clone(); @@ -675,9 +683,15 @@ impl Evaluator<'_> { } fn layout(&self, ty: &Ty) -> Result> { - self.db + if let Some(x) = self.layout_cache.borrow().get(ty) { + return Ok(x.clone()); + } + let r = self + .db .layout_of_ty(ty.clone(), self.crate_id) - .map_err(|e| MirEvalError::LayoutError(e, ty.clone())) + .map_err(|e| MirEvalError::LayoutError(e, ty.clone()))?; + self.layout_cache.borrow_mut().insert(ty.clone(), r.clone()); + Ok(r) } fn layout_adt(&self, adt: AdtId, subst: Substitution) -> Result> { @@ -686,11 +700,11 @@ impl Evaluator<'_> { }) } - fn place_ty<'a>(&'a self, p: &Place, locals: &'a Locals<'a>) -> Result { + fn place_ty<'a>(&'a self, p: &Place, locals: &'a Locals) -> Result { Ok(self.place_addr_and_ty_and_metadata(p, locals)?.1) } - fn operand_ty(&self, o: &Operand, locals: &Locals<'_>) -> Result { + fn operand_ty(&self, o: &Operand, locals: &Locals) -> Result { Ok(match o { Operand::Copy(p) | Operand::Move(p) => self.place_ty(p, locals)?, Operand::Constant(c) => c.data(Interner).ty.clone(), @@ -701,11 +715,7 @@ impl Evaluator<'_> { }) } - fn operand_ty_and_eval( - &mut self, - o: &Operand, - locals: &mut Locals<'_>, - ) -> Result { + fn operand_ty_and_eval(&mut self, o: &Operand, locals: &mut Locals) -> Result { Ok(IntervalAndTy { interval: self.eval_operand(o, locals)?, ty: self.operand_ty(o, locals)?, @@ -714,8 +724,8 @@ impl Evaluator<'_> { fn interpret_mir( &mut self, - body: &MirBody, - args: impl Iterator>, + body: Arc, + args: impl Iterator, ) -> Result> { if let Some(it) = self.stack_depth_limit.checked_sub(1) { self.stack_depth_limit = it; @@ -723,14 +733,192 @@ impl Evaluator<'_> { return Err(MirEvalError::StackOverflow); } let mut current_block_idx = body.start_block; + let (mut locals, prev_stack_ptr) = self.create_locals_for_body(body.clone(), None)?; + self.fill_locals_for_body(&body, &mut locals, args)?; + let prev_code_stack = mem::take(&mut self.code_stack); + let span = (MirSpan::Unknown, body.owner); + self.code_stack.push(StackFrame { body, locals, destination: None, prev_stack_ptr, span }); + 'stack: loop { + let Some(mut my_stack_frame) = self.code_stack.pop() else { + not_supported!("missing stack frame"); + }; + let e = (|| { + let mut locals = &mut my_stack_frame.locals; + let body = &*my_stack_frame.body; + loop { + let current_block = &body.basic_blocks[current_block_idx]; + if let Some(it) = self.execution_limit.checked_sub(1) { + self.execution_limit = it; + } else { + return Err(MirEvalError::ExecutionLimitExceeded); + } + for statement in ¤t_block.statements { + match &statement.kind { + StatementKind::Assign(l, r) => { + let addr = self.place_addr(l, &locals)?; + let result = self.eval_rvalue(r, &mut locals)?.to_vec(&self)?; + self.write_memory(addr, &result)?; + locals.drop_flags.add_place(l.clone()); + } + StatementKind::Deinit(_) => not_supported!("de-init statement"), + StatementKind::StorageLive(_) + | StatementKind::StorageDead(_) + | StatementKind::Nop => (), + } + } + let Some(terminator) = current_block.terminator.as_ref() else { + not_supported!("block without terminator"); + }; + match &terminator.kind { + TerminatorKind::Goto { target } => { + current_block_idx = *target; + } + TerminatorKind::Call { + func, + args, + destination, + target, + cleanup: _, + from_hir_call: _, + } => { + let destination_interval = self.place_interval(destination, &locals)?; + let fn_ty = self.operand_ty(func, &locals)?; + let args = args + .iter() + .map(|it| self.operand_ty_and_eval(it, &mut locals)) + .collect::>>()?; + let stack_frame = match &fn_ty.data(Interner).kind { + TyKind::Function(_) => { + let bytes = self.eval_operand(func, &mut locals)?; + self.exec_fn_pointer( + bytes, + destination_interval, + &args, + &locals, + *target, + terminator.span, + )? + } + TyKind::FnDef(def, generic_args) => self.exec_fn_def( + *def, + generic_args, + destination_interval, + &args, + &locals, + *target, + terminator.span, + )?, + it => not_supported!("unknown function type {it:?}"), + }; + locals.drop_flags.add_place(destination.clone()); + if let Some(stack_frame) = stack_frame { + self.code_stack.push(my_stack_frame); + current_block_idx = stack_frame.body.start_block; + self.code_stack.push(stack_frame); + return Ok(None); + } else { + current_block_idx = + target.ok_or(MirEvalError::UndefinedBehavior( + "Diverging function returned".to_owned(), + ))?; + } + } + TerminatorKind::SwitchInt { discr, targets } => { + let val = u128::from_le_bytes(pad16( + self.eval_operand(discr, &mut locals)?.get(&self)?, + false, + )); + current_block_idx = targets.target_for_value(val); + } + TerminatorKind::Return => { + break; + } + TerminatorKind::Unreachable => { + return Err(MirEvalError::UndefinedBehavior( + "unreachable executed".to_owned(), + )); + } + TerminatorKind::Drop { place, target, unwind: _ } => { + self.drop_place(place, &mut locals, terminator.span)?; + current_block_idx = *target; + } + _ => not_supported!("unknown terminator"), + } + } + Ok(Some(my_stack_frame)) + })(); + let my_stack_frame = match e { + Ok(None) => continue 'stack, + Ok(Some(x)) => x, + Err(e) => { + let my_code_stack = mem::replace(&mut self.code_stack, prev_code_stack); + let mut error_stack = vec![]; + for frame in my_code_stack.into_iter().rev() { + if let DefWithBodyId::FunctionId(f) = frame.body.owner { + error_stack.push((Either::Left(f), frame.span.0, frame.span.1)); + } + } + return Err(MirEvalError::InFunction(Box::new(e), error_stack)); + } + }; + match my_stack_frame.destination { + None => { + self.code_stack = prev_code_stack; + self.stack_depth_limit += 1; + return Ok(my_stack_frame.locals.ptr[return_slot()].get(self)?.to_vec()); + } + Some(bb) => { + // We don't support const promotion, so we can't truncate the stack yet. + let _ = my_stack_frame.prev_stack_ptr; + // self.stack.truncate(my_stack_frame.prev_stack_ptr); + current_block_idx = bb; + } + } + } + } + + fn fill_locals_for_body( + &mut self, + body: &MirBody, + locals: &mut Locals, + args: impl Iterator, + ) -> Result<()> { + let mut remain_args = body.param_locals.len(); + for ((l, interval), value) in locals.ptr.iter().skip(1).zip(args) { + locals.drop_flags.add_place(l.into()); + match value { + IntervalOrOwned::Owned(value) => interval.write_from_bytes(self, &value)?, + IntervalOrOwned::Borrowed(value) => interval.write_from_interval(self, value)?, + } + if remain_args == 0 { + return Err(MirEvalError::TypeError("more arguments provided")); + } + remain_args -= 1; + } + if remain_args > 0 { + return Err(MirEvalError::TypeError("not enough arguments provided")); + } + Ok(()) + } + + fn create_locals_for_body( + &mut self, + body: Arc, + destination: Option, + ) -> Result<(Locals, usize)> { let mut locals = - Locals { ptr: &ArenaMap::new(), body: &body, drop_flags: DropFlags::default() }; + Locals { ptr: ArenaMap::new(), body: body.clone(), drop_flags: DropFlags::default() }; let (locals_ptr, stack_size) = { let mut stack_ptr = self.stack.len(); let addr = body .locals .iter() .map(|(id, it)| { + if id == return_slot() { + if let Some(destination) = destination { + return Ok((id, destination)); + } + } let (size, align) = self.size_align_of_sized( &it.ty, &locals, @@ -747,112 +935,13 @@ impl Evaluator<'_> { let stack_size = stack_ptr - self.stack.len(); (addr, stack_size) }; - locals.ptr = &locals_ptr; + locals.ptr = locals_ptr; + let prev_stack_pointer = self.stack.len(); self.stack.extend(iter::repeat(0).take(stack_size)); - let mut remain_args = body.param_locals.len(); - for ((l, interval), value) in locals_ptr.iter().skip(1).zip(args) { - locals.drop_flags.add_place(l.into()); - interval.write_from_bytes(self, &value)?; - if remain_args == 0 { - return Err(MirEvalError::TypeError("more arguments provided")); - } - remain_args -= 1; - } - if remain_args > 0 { - return Err(MirEvalError::TypeError("not enough arguments provided")); - } - loop { - let current_block = &body.basic_blocks[current_block_idx]; - if let Some(it) = self.execution_limit.checked_sub(1) { - self.execution_limit = it; - } else { - return Err(MirEvalError::ExecutionLimitExceeded); - } - for statement in ¤t_block.statements { - match &statement.kind { - StatementKind::Assign(l, r) => { - let addr = self.place_addr(l, &locals)?; - let result = self.eval_rvalue(r, &mut locals)?.to_vec(&self)?; - self.write_memory(addr, &result)?; - locals.drop_flags.add_place(l.clone()); - } - StatementKind::Deinit(_) => not_supported!("de-init statement"), - StatementKind::StorageLive(_) - | StatementKind::StorageDead(_) - | StatementKind::Nop => (), - } - } - let Some(terminator) = current_block.terminator.as_ref() else { - not_supported!("block without terminator"); - }; - match &terminator.kind { - TerminatorKind::Goto { target } => { - current_block_idx = *target; - } - TerminatorKind::Call { - func, - args, - destination, - target, - cleanup: _, - from_hir_call: _, - } => { - let destination_interval = self.place_interval(destination, &locals)?; - let fn_ty = self.operand_ty(func, &locals)?; - let args = args - .iter() - .map(|it| self.operand_ty_and_eval(it, &mut locals)) - .collect::>>()?; - match &fn_ty.data(Interner).kind { - TyKind::Function(_) => { - let bytes = self.eval_operand(func, &mut locals)?; - self.exec_fn_pointer( - bytes, - destination_interval, - &args, - &locals, - terminator.span, - )?; - } - TyKind::FnDef(def, generic_args) => { - self.exec_fn_def( - *def, - generic_args, - destination_interval, - &args, - &locals, - terminator.span, - )?; - } - it => not_supported!("unknown function type {it:?}"), - } - locals.drop_flags.add_place(destination.clone()); - current_block_idx = target.expect("broken mir, function without target"); - } - TerminatorKind::SwitchInt { discr, targets } => { - let val = u128::from_le_bytes(pad16( - self.eval_operand(discr, &mut locals)?.get(&self)?, - false, - )); - current_block_idx = targets.target_for_value(val); - } - TerminatorKind::Return => { - self.stack_depth_limit += 1; - return Ok(locals.ptr[return_slot()].get(self)?.to_vec()); - } - TerminatorKind::Unreachable => { - return Err(MirEvalError::UndefinedBehavior("unreachable executed".to_owned())); - } - TerminatorKind::Drop { place, target, unwind: _ } => { - self.drop_place(place, &mut locals, terminator.span)?; - current_block_idx = *target; - } - _ => not_supported!("unknown terminator"), - } - } + Ok((locals, prev_stack_pointer)) } - fn eval_rvalue(&mut self, r: &Rvalue, locals: &mut Locals<'_>) -> Result { + fn eval_rvalue(&mut self, r: &Rvalue, locals: &mut Locals) -> Result { use IntervalOrOwned::*; Ok(match r { Rvalue::Use(it) => Borrowed(self.eval_operand(it, locals)?), @@ -1372,7 +1461,7 @@ impl Evaluator<'_> { &mut self, it: VariantId, subst: Substitution, - locals: &Locals<'_>, + locals: &Locals, ) -> Result<(usize, Arc, Option<(usize, usize, i128)>)> { let adt = it.adt_id(); if let DefWithBodyId::VariantId(f) = locals.body.owner { @@ -1452,7 +1541,7 @@ impl Evaluator<'_> { Ok(result) } - fn eval_operand(&mut self, it: &Operand, locals: &mut Locals<'_>) -> Result { + fn eval_operand(&mut self, it: &Operand, locals: &mut Locals) -> Result { Ok(match it { Operand::Copy(p) | Operand::Move(p) => { locals.drop_flags.remove_place(p); @@ -1482,7 +1571,7 @@ impl Evaluator<'_> { &mut self, c: &chalk_ir::ConcreteConst, ty: &Ty, - locals: &Locals<'_>, + locals: &Locals, konst: &chalk_ir::Const, ) -> Result { Ok(match &c.interned { @@ -1516,7 +1605,7 @@ impl Evaluator<'_> { }) } - fn eval_place(&mut self, p: &Place, locals: &Locals<'_>) -> Result { + fn eval_place(&mut self, p: &Place, locals: &Locals) -> Result { let addr = self.place_addr(p, locals)?; Ok(Interval::new( addr, @@ -1562,7 +1651,7 @@ impl Evaluator<'_> { Ok(()) } - fn size_align_of(&self, ty: &Ty, locals: &Locals<'_>) -> Result> { + fn size_align_of(&self, ty: &Ty, locals: &Locals) -> Result> { if let DefWithBodyId::VariantId(f) = locals.body.owner { if let Some((adt, _)) = ty.as_adt() { if AdtId::from(f.parent) == adt { @@ -1586,7 +1675,7 @@ impl Evaluator<'_> { /// A version of `self.size_of` which returns error if the type is unsized. `what` argument should /// be something that complete this: `error: type {ty} was unsized. {what} should be sized` - fn size_of_sized(&self, ty: &Ty, locals: &Locals<'_>, what: &'static str) -> Result { + fn size_of_sized(&self, ty: &Ty, locals: &Locals, what: &'static str) -> Result { match self.size_align_of(ty, locals)? { Some(it) => Ok(it.0), None => Err(MirEvalError::TypeIsUnsized(ty.clone(), what)), @@ -1598,7 +1687,7 @@ impl Evaluator<'_> { fn size_align_of_sized( &self, ty: &Ty, - locals: &Locals<'_>, + locals: &Locals, what: &'static str, ) -> Result<(usize, usize)> { match self.size_align_of(ty, locals)? { @@ -1621,7 +1710,7 @@ impl Evaluator<'_> { let ItemContainerId::TraitId(parent) = self.db.lookup_intern_function(def).container else { return None; }; - let l = lang_attr(self.db.upcast(), parent)?; + let l = self.db.lang_attr(parent.into())?; match l { FnOnce => Some(FnTrait::FnOnce), FnMut => Some(FnTrait::FnMut), @@ -1630,12 +1719,12 @@ impl Evaluator<'_> { } } - fn create_memory_map(&self, bytes: &[u8], ty: &Ty, locals: &Locals<'_>) -> Result { + fn create_memory_map(&self, bytes: &[u8], ty: &Ty, locals: &Locals) -> Result { fn rec( this: &Evaluator<'_>, bytes: &[u8], ty: &Ty, - locals: &Locals<'_>, + locals: &Locals, mm: &mut MemoryMap, ) -> Result<()> { match ty.kind(Interner) { @@ -1741,7 +1830,7 @@ impl Evaluator<'_> { old_vtable: &VTableMap, addr: Address, ty: &Ty, - locals: &Locals<'_>, + locals: &Locals, ) -> Result<()> { // FIXME: support indirect references let layout = self.layout(ty)?; @@ -1815,21 +1904,21 @@ impl Evaluator<'_> { bytes: Interval, destination: Interval, args: &[IntervalAndTy], - locals: &Locals<'_>, + locals: &Locals, + target_bb: Option, span: MirSpan, - ) -> Result<()> { + ) -> Result> { let id = from_bytes!(usize, bytes.get(self)?); let next_ty = self.vtable_map.ty(id)?.clone(); match &next_ty.data(Interner).kind { TyKind::FnDef(def, generic_args) => { - self.exec_fn_def(*def, generic_args, destination, args, &locals, span)?; + self.exec_fn_def(*def, generic_args, destination, args, &locals, target_bb, span) } TyKind::Closure(id, subst) => { - self.exec_closure(*id, bytes.slice(0..0), subst, destination, args, locals, span)?; + self.exec_closure(*id, bytes.slice(0..0), subst, destination, args, locals, span) } - _ => return Err(MirEvalError::TypeError("function pointer to non function")), + _ => Err(MirEvalError::TypeError("function pointer to non function")), } - Ok(()) } fn exec_closure( @@ -1839,9 +1928,9 @@ impl Evaluator<'_> { generic_args: &Substitution, destination: Interval, args: &[IntervalAndTy], - locals: &Locals<'_>, + locals: &Locals, span: MirSpan, - ) -> Result<()> { + ) -> Result> { let mir_body = self .db .monomorphized_mir_body_for_closure( @@ -1859,10 +1948,16 @@ impl Evaluator<'_> { let arg_bytes = iter::once(Ok(closure_data)) .chain(args.iter().map(|it| Ok(it.get(&self)?.to_owned()))) .collect::>>()?; - let bytes = self.interpret_mir(&mir_body, arg_bytes.into_iter()).map_err(|e| { - MirEvalError::InFunction(Either::Right(closure), Box::new(e), span, locals.body.owner) - })?; - destination.write_from_bytes(self, &bytes) + let bytes = self + .interpret_mir(mir_body, arg_bytes.into_iter().map(IntervalOrOwned::Owned)) + .map_err(|e| { + MirEvalError::InFunction( + Box::new(e), + vec![(Either::Right(closure), span, locals.body.owner)], + ) + })?; + destination.write_from_bytes(self, &bytes)?; + Ok(None) } fn exec_fn_def( @@ -1871,18 +1966,34 @@ impl Evaluator<'_> { generic_args: &Substitution, destination: Interval, args: &[IntervalAndTy], - locals: &Locals<'_>, + locals: &Locals, + target_bb: Option, span: MirSpan, - ) -> Result<()> { + ) -> Result> { let def: CallableDefId = from_chalk(self.db, def); let generic_args = generic_args.clone(); match def { CallableDefId::FunctionId(def) => { if let Some(_) = self.detect_fn_trait(def) { - self.exec_fn_trait(def, args, generic_args, locals, destination, span)?; - return Ok(()); + return self.exec_fn_trait( + def, + args, + generic_args, + locals, + destination, + target_bb, + span, + ); } - self.exec_fn_with_args(def, args, generic_args, locals, destination, span)?; + self.exec_fn_with_args( + def, + args, + generic_args, + locals, + destination, + target_bb, + span, + ) } CallableDefId::StructId(id) => { let (size, variant_layout, tag) = @@ -1894,6 +2005,7 @@ impl Evaluator<'_> { args.iter().map(|it| it.interval.into()), )?; destination.write_from_bytes(self, &result)?; + Ok(None) } CallableDefId::EnumVariantId(id) => { let (size, variant_layout, tag) = @@ -1905,9 +2017,9 @@ impl Evaluator<'_> { args.iter().map(|it| it.interval.into()), )?; destination.write_from_bytes(self, &result)?; + Ok(None) } } - Ok(()) } fn exec_fn_with_args( @@ -1915,10 +2027,11 @@ impl Evaluator<'_> { def: FunctionId, args: &[IntervalAndTy], generic_args: Substitution, - locals: &Locals<'_>, + locals: &Locals, destination: Interval, + target_bb: Option, span: MirSpan, - ) -> Result<()> { + ) -> Result> { if self.detect_and_exec_special_function( def, args, @@ -1927,10 +2040,9 @@ impl Evaluator<'_> { destination, span, )? { - return Ok(()); + return Ok(None); } - let arg_bytes = - args.iter().map(|it| Ok(it.get(&self)?.to_owned())).collect::>>()?; + let arg_bytes = args.iter().map(|it| IntervalOrOwned::Borrowed(it.interval)); if let Some(self_ty_idx) = is_dyn_method(self.db, self.trait_env.clone(), def, generic_args.clone()) { @@ -1938,8 +2050,10 @@ impl Evaluator<'_> { // `&T`, `&mut T`, `Box`, `Rc`, `Arc`, and `Pin

` where `P` is one of possible recievers, // the vtable is exactly in the `[ptr_size..2*ptr_size]` bytes. So we can use it without branching on // the type. + let first_arg = arg_bytes.clone().next().unwrap(); + let first_arg = first_arg.get(self)?; let ty = - self.vtable_map.ty_of_bytes(&arg_bytes[0][self.ptr_size()..self.ptr_size() * 2])?; + self.vtable_map.ty_of_bytes(&first_arg[self.ptr_size()..self.ptr_size() * 2])?; let mut args_for_target = args.to_vec(); args_for_target[0] = IntervalAndTy { interval: args_for_target[0].interval.slice(0..self.ptr_size()), @@ -1962,40 +2076,65 @@ impl Evaluator<'_> { generics_for_target, locals, destination, + target_bb, span, ); } let (imp, generic_args) = - lookup_impl_method(self.db, self.trait_env.clone(), def, generic_args); - self.exec_looked_up_function(generic_args, locals, imp, arg_bytes, span, destination) + self.db.lookup_impl_method(self.trait_env.clone(), def, generic_args); + self.exec_looked_up_function( + generic_args, + locals, + imp, + arg_bytes, + span, + destination, + target_bb, + ) } fn exec_looked_up_function( &mut self, generic_args: Substitution, - locals: &Locals<'_>, + locals: &Locals, imp: FunctionId, - arg_bytes: Vec>, + arg_bytes: impl Iterator, span: MirSpan, destination: Interval, - ) -> Result<()> { + target_bb: Option, + ) -> Result> { let def = imp.into(); let mir_body = self .db .monomorphized_mir_body(def, generic_args, self.trait_env.clone()) .map_err(|e| { MirEvalError::InFunction( - Either::Left(imp), Box::new(MirEvalError::MirLowerError(imp, e)), - span, - locals.body.owner, + vec![(Either::Left(imp), span, locals.body.owner)], ) })?; - let result = self.interpret_mir(&mir_body, arg_bytes.iter().cloned()).map_err(|e| { - MirEvalError::InFunction(Either::Left(imp), Box::new(e), span, locals.body.owner) - })?; - destination.write_from_bytes(self, &result)?; - Ok(()) + Ok(if let Some(target_bb) = target_bb { + let (mut locals, prev_stack_ptr) = + self.create_locals_for_body(mir_body.clone(), Some(destination))?; + self.fill_locals_for_body(&mir_body, &mut locals, arg_bytes.into_iter())?; + let span = (span, locals.body.owner); + Some(StackFrame { + body: mir_body, + locals, + destination: Some(target_bb), + prev_stack_ptr, + span, + }) + } else { + let result = self.interpret_mir(mir_body, arg_bytes).map_err(|e| { + MirEvalError::InFunction( + Box::new(e), + vec![(Either::Left(imp), span, locals.body.owner)], + ) + })?; + destination.write_from_bytes(self, &result)?; + None + }) } fn exec_fn_trait( @@ -2003,10 +2142,11 @@ impl Evaluator<'_> { def: FunctionId, args: &[IntervalAndTy], generic_args: Substitution, - locals: &Locals<'_>, + locals: &Locals, destination: Interval, + target_bb: Option, span: MirSpan, - ) -> Result<()> { + ) -> Result> { let func = args.get(0).ok_or(MirEvalError::TypeError("fn trait with no arg"))?; let mut func_ty = func.ty.clone(); let mut func_data = func.interval; @@ -2023,13 +2163,28 @@ impl Evaluator<'_> { } match &func_ty.data(Interner).kind { TyKind::FnDef(def, subst) => { - self.exec_fn_def(*def, subst, destination, &args[1..], locals, span)?; + return self.exec_fn_def( + *def, + subst, + destination, + &args[1..], + locals, + target_bb, + span, + ); } TyKind::Function(_) => { - self.exec_fn_pointer(func_data, destination, &args[1..], locals, span)?; + return self.exec_fn_pointer( + func_data, + destination, + &args[1..], + locals, + target_bb, + span, + ); } TyKind::Closure(closure, subst) => { - self.exec_closure( + return self.exec_closure( *closure, func_data, &Substitution::from_iter(Interner, ClosureSubst(subst).parent_subst()), @@ -2037,7 +2192,7 @@ impl Evaluator<'_> { &args[1..], locals, span, - )?; + ); } _ => { // try to execute the manual impl of `FnTrait` for structs (nightly feature used in std) @@ -2068,14 +2223,14 @@ impl Evaluator<'_> { generic_args, locals, destination, + target_bb, span, ); } } - Ok(()) } - fn eval_static(&mut self, st: StaticId, locals: &Locals<'_>) -> Result

{ + fn eval_static(&mut self, st: StaticId, locals: &Locals) -> Result
{ if let Some(o) = self.static_locations.get(&st) { return Ok(*o); }; @@ -2123,7 +2278,7 @@ impl Evaluator<'_> { } } - fn drop_place(&mut self, place: &Place, locals: &mut Locals<'_>, span: MirSpan) -> Result<()> { + fn drop_place(&mut self, place: &Place, locals: &mut Locals, span: MirSpan) -> Result<()> { let (addr, ty, metadata) = self.place_addr_and_ty_and_metadata(place, locals)?; if !locals.drop_flags.remove_place(place) { return Ok(()); @@ -2138,7 +2293,7 @@ impl Evaluator<'_> { fn run_drop_glue_deep( &mut self, ty: Ty, - locals: &Locals<'_>, + locals: &Locals, addr: Address, _metadata: &[u8], span: MirSpan, @@ -2151,8 +2306,7 @@ impl Evaluator<'_> { // we can ignore drop in them. return Ok(()); }; - let (impl_drop_candidate, subst) = lookup_impl_method( - self.db, + let (impl_drop_candidate, subst) = self.db.lookup_impl_method( self.trait_env.clone(), drop_fn, Substitution::from1(Interner, ty.clone()), @@ -2162,9 +2316,10 @@ impl Evaluator<'_> { subst, locals, impl_drop_candidate, - vec![addr.to_bytes()], + [IntervalOrOwned::Owned(addr.to_bytes())].into_iter(), span, Interval { addr: Address::Invalid(0), size: 0 }, + None, )?; } match ty.kind(Interner) { diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs index ab8ecdcf177b..6cdf9f03c91f 100644 --- a/crates/hir-ty/src/mir/eval/shim.rs +++ b/crates/hir-ty/src/mir/eval/shim.rs @@ -32,7 +32,7 @@ impl Evaluator<'_> { def: FunctionId, args: &[IntervalAndTy], generic_args: &Substitution, - locals: &Locals<'_>, + locals: &Locals, destination: Interval, span: MirSpan, ) -> Result { @@ -168,7 +168,7 @@ impl Evaluator<'_> { fn detect_lang_function(&self, def: FunctionId) -> Option { use LangItem::*; - let candidate = lang_attr(self.db.upcast(), def)?; + let candidate = self.db.lang_attr(def.into())?; // We want to execute these functions with special logic if [PanicFmt, BeginPanic, SliceLen, DropInPlace].contains(&candidate) { return Some(candidate); @@ -181,7 +181,7 @@ impl Evaluator<'_> { it: LangItem, generic_args: &Substitution, args: &[Vec], - locals: &Locals<'_>, + locals: &Locals, span: MirSpan, ) -> Result> { use LangItem::*; @@ -201,7 +201,7 @@ impl Evaluator<'_> { not_supported!("std::fmt::format not found"); }; let hir_def::resolver::ValueNs::FunctionId(format_fn) = format_fn else { not_supported!("std::fmt::format is not a function") }; - let message_string = self.interpret_mir(&*self.db.mir_body(format_fn.into()).map_err(|e| MirEvalError::MirLowerError(format_fn, e))?, args.cloned())?; + let message_string = self.interpret_mir(self.db.mir_body(format_fn.into()).map_err(|e| MirEvalError::MirLowerError(format_fn, e))?, args.map(|x| IntervalOrOwned::Owned(x.clone())))?; let addr = Address::from_bytes(&message_string[self.ptr_size()..2 * self.ptr_size()])?; let size = from_bytes!(usize, message_string[2 * self.ptr_size()..]); Ok(std::string::String::from_utf8_lossy(self.read_memory(addr, size)?).into_owned()) @@ -245,7 +245,7 @@ impl Evaluator<'_> { args: &[IntervalAndTy], _generic_args: &Substitution, destination: Interval, - locals: &Locals<'_>, + locals: &Locals, _span: MirSpan, ) -> Result<()> { match as_str { @@ -353,7 +353,7 @@ impl Evaluator<'_> { args: &[IntervalAndTy], generic_args: &Substitution, destination: Interval, - locals: &Locals<'_>, + locals: &Locals, span: MirSpan, ) -> Result<()> { if let Some(name) = name.strip_prefix("simd_") { @@ -368,7 +368,7 @@ impl Evaluator<'_> { args: &[IntervalAndTy], generic_args: &Substitution, destination: Interval, - locals: &Locals<'_>, + locals: &Locals, span: MirSpan, ) -> Result<()> { if let Some(name) = name.strip_prefix("atomic_") { @@ -873,15 +873,17 @@ impl Evaluator<'_> { .as_trait() .and_then(|it| self.db.trait_data(it).method_by_name(&name![call_once])) { - return self.exec_fn_trait( + self.exec_fn_trait( def, &args, // FIXME: wrong for manual impls of `FnOnce` Substitution::empty(Interner), locals, destination, + None, span, - ); + )?; + return Ok(()); } } not_supported!("FnOnce was not available for executing const_eval_select"); @@ -894,7 +896,7 @@ impl Evaluator<'_> { &mut self, ty: &Ty, metadata: Interval, - locals: &Locals<'_>, + locals: &Locals, ) -> Result<(usize, usize)> { Ok(match ty.kind(Interner) { TyKind::Str => (from_bytes!(usize, metadata.get(self)?), 1), @@ -948,7 +950,7 @@ impl Evaluator<'_> { args: &[IntervalAndTy], generic_args: &Substitution, destination: Interval, - locals: &Locals<'_>, + locals: &Locals, _span: MirSpan, ) -> Result<()> { // We are a single threaded runtime with no UB checking and no optimization, so diff --git a/crates/hir-ty/src/mir/eval/shim/simd.rs b/crates/hir-ty/src/mir/eval/shim/simd.rs index 4c2e56fe2bf5..64fd13018296 100644 --- a/crates/hir-ty/src/mir/eval/shim/simd.rs +++ b/crates/hir-ty/src/mir/eval/shim/simd.rs @@ -50,7 +50,7 @@ impl Evaluator<'_> { args: &[IntervalAndTy], _generic_args: &Substitution, destination: Interval, - _locals: &Locals<'_>, + _locals: &Locals, _span: MirSpan, ) -> Result<()> { match name { diff --git a/crates/hir-ty/src/mir/eval/tests.rs b/crates/hir-ty/src/mir/eval/tests.rs index ca4268b8fb00..1129eaa54991 100644 --- a/crates/hir-ty/src/mir/eval/tests.rs +++ b/crates/hir-ty/src/mir/eval/tests.rs @@ -30,7 +30,7 @@ fn eval_main(db: &TestDB, file_id: FileId) -> Result<(String, String), MirEvalEr db.trait_environment(func_id.into()), ) .map_err(|e| MirEvalError::MirLowerError(func_id.into(), e))?; - let (result, stdout, stderr) = interpret_mir(db, &body, false); + let (result, stdout, stderr) = interpret_mir(db, body, false); result?; Ok((stdout, stderr)) } diff --git a/crates/hir-ty/src/mir/lower/as_place.rs b/crates/hir-ty/src/mir/lower/as_place.rs index d58777e2b64e..213f151ab676 100644 --- a/crates/hir-ty/src/mir/lower/as_place.rs +++ b/crates/hir-ty/src/mir/lower/as_place.rs @@ -1,7 +1,7 @@ //! MIR lowering for places use super::*; -use hir_def::{lang_item::lang_attr, FunctionId}; +use hir_def::FunctionId; use hir_expand::name; macro_rules! not_supported { @@ -162,7 +162,7 @@ impl MirLowerCtx<'_> { let is_builtin = match self.expr_ty_without_adjust(*expr).kind(Interner) { TyKind::Ref(..) | TyKind::Raw(..) => true, TyKind::Adt(id, _) => { - if let Some(lang_item) = lang_attr(self.db.upcast(), id.0) { + if let Some(lang_item) = self.db.lang_attr(id.0.into()) { lang_item == LangItem::OwnedBox } else { false diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 4eaf99b0b82e..337cfbfb625b 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -1986,7 +1986,7 @@ impl Function { return r; } }; - let (result, stdout, stderr) = interpret_mir(db, &body, false); + let (result, stdout, stderr) = interpret_mir(db, body, false); let mut text = match result { Ok(_) => "pass".to_string(), Err(e) => { diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index ecb1b306a668..3499daf11403 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -832,7 +832,7 @@ impl SourceAnalyzer { None => return func, }; let env = db.trait_environment_for_body(owner); - method_resolution::lookup_impl_method(db, env, func, substs).0 + db.lookup_impl_method(env, func, substs).0 } fn resolve_impl_const_or_trait_def( From 4939a716e80214edd19dab6b678fce3e769388f5 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Tue, 4 Jul 2023 16:58:02 +0000 Subject: [PATCH 181/324] arc_with_non_send_sync: reword and move to suspicious --- clippy_lints/src/arc_with_non_send_sync.rs | 71 +++++++++++----------- tests/ui/arc_with_non_send_sync.rs | 12 ++-- tests/ui/arc_with_non_send_sync.stderr | 33 ++++++++-- 3 files changed, 73 insertions(+), 43 deletions(-) diff --git a/clippy_lints/src/arc_with_non_send_sync.rs b/clippy_lints/src/arc_with_non_send_sync.rs index 62313df9f90e..98ee8a9a8806 100644 --- a/clippy_lints/src/arc_with_non_send_sync.rs +++ b/clippy_lints/src/arc_with_non_send_sync.rs @@ -1,12 +1,11 @@ -use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::last_path_segment; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; -use if_chain::if_chain; - use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_lint::LateLintPass; use rustc_middle::ty; +use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_middle::ty::GenericArgKind; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::sym; @@ -16,8 +15,8 @@ declare_clippy_lint! { /// This lint warns when you use `Arc` with a type that does not implement `Send` or `Sync`. /// /// ### Why is this bad? - /// Wrapping a type in Arc doesn't add thread safety to the underlying data, so data races - /// could occur when touching the underlying data. + /// `Arc` is only `Send`/`Sync` when `T` is [both `Send` and `Sync`](https://doc.rust-lang.org/std/sync/struct.Arc.html#impl-Send-for-Arc%3CT%3E), + /// either `T` should be made `Send + Sync` or an `Rc` should be used instead of an `Arc` /// /// ### Example /// ```rust @@ -25,16 +24,17 @@ declare_clippy_lint! { /// # use std::sync::Arc; /// /// fn main() { - /// // This is safe, as `i32` implements `Send` and `Sync`. + /// // This is fine, as `i32` implements `Send` and `Sync`. /// let a = Arc::new(42); /// - /// // This is not safe, as `RefCell` does not implement `Sync`. + /// // `RefCell` is `!Sync`, so either the `Arc` should be replaced with an `Rc` + /// // or the `RefCell` replaced with something like a `RwLock` /// let b = Arc::new(RefCell::new(42)); /// } /// ``` #[clippy::version = "1.72.0"] pub ARC_WITH_NON_SEND_SYNC, - correctness, + suspicious, "using `Arc` with a type that does not implement `Send` or `Sync`" } declare_lint_pass!(ArcWithNonSendSync => [ARC_WITH_NON_SEND_SYNC]); @@ -42,35 +42,38 @@ declare_lint_pass!(ArcWithNonSendSync => [ARC_WITH_NON_SEND_SYNC]); impl LateLintPass<'_> for ArcWithNonSendSync { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { let ty = cx.typeck_results().expr_ty(expr); - if_chain! { - if is_type_diagnostic_item(cx, ty, sym::Arc); - if let ExprKind::Call(func, [arg]) = expr.kind; - if let ExprKind::Path(func_path) = func.kind; - if last_path_segment(&func_path).ident.name == sym::new; - if let arg_ty = cx.typeck_results().expr_ty(arg); + if is_type_diagnostic_item(cx, ty, sym::Arc) + && let ExprKind::Call(func, [arg]) = expr.kind + && let ExprKind::Path(func_path) = func.kind + && last_path_segment(&func_path).ident.name == sym::new + && let arg_ty = cx.typeck_results().expr_ty(arg) // make sure that the type is not and does not contain any type parameters - if arg_ty.walk().all(|arg| { + && arg_ty.walk().all(|arg| { !matches!(arg.unpack(), GenericArgKind::Type(ty) if matches!(ty.kind(), ty::Param(_))) - }); - if !cx.tcx - .lang_items() - .sync_trait() - .map_or(false, |id| implements_trait(cx, arg_ty, id, &[])) || - !cx.tcx - .get_diagnostic_item(sym::Send) - .map_or(false, |id| implements_trait(cx, arg_ty, id, &[])); + }) + && let Some(send) = cx.tcx.get_diagnostic_item(sym::Send) + && let Some(sync) = cx.tcx.lang_items().sync_trait() + && let [is_send, is_sync] = [send, sync].map(|id| implements_trait(cx, arg_ty, id, &[])) + && !(is_send && is_sync) + { + span_lint_and_then( + cx, + ARC_WITH_NON_SEND_SYNC, + expr.span, + "usage of an `Arc` that is not `Send` or `Sync`", + |diag| with_forced_trimmed_paths!({ + if !is_send { + diag.note(format!("the trait `Send` is not implemented for `{arg_ty}`")); + } + if !is_sync { + diag.note(format!("the trait `Sync` is not implemented for `{arg_ty}`")); + } - then { - span_lint_and_help( - cx, - ARC_WITH_NON_SEND_SYNC, - expr.span, - "usage of `Arc` where `T` is not `Send` or `Sync`", - None, - "consider using `Rc` instead or wrapping `T` in a std::sync type like \ - `Mutex`", - ); - } + diag.note(format!("required for `{ty}` to implement `Send` and `Sync`")); + + diag.help("consider using an `Rc` instead or wrapping the inner type with a `Mutex`"); + } + )); } } } diff --git a/tests/ui/arc_with_non_send_sync.rs b/tests/ui/arc_with_non_send_sync.rs index 9d5849277c20..b6fcca0a7919 100644 --- a/tests/ui/arc_with_non_send_sync.rs +++ b/tests/ui/arc_with_non_send_sync.rs @@ -12,9 +12,13 @@ fn issue11076() { } fn main() { - // This is safe, as `i32` implements `Send` and `Sync`. - let a = Arc::new(42); + let _ = Arc::new(42); - // This is not safe, as `RefCell` does not implement `Sync`. - let b = Arc::new(RefCell::new(42)); + // !Sync + let _ = Arc::new(RefCell::new(42)); + let mutex = Mutex::new(1); + // !Send + let _ = Arc::new(mutex.lock().unwrap()); + // !Send + !Sync + let _ = Arc::new(&42 as *const i32); } diff --git a/tests/ui/arc_with_non_send_sync.stderr b/tests/ui/arc_with_non_send_sync.stderr index 520c21b565ba..7633b38dfb59 100644 --- a/tests/ui/arc_with_non_send_sync.stderr +++ b/tests/ui/arc_with_non_send_sync.stderr @@ -1,11 +1,34 @@ -error: usage of `Arc` where `T` is not `Send` or `Sync` - --> $DIR/arc_with_non_send_sync.rs:19:13 +error: usage of an `Arc` that is not `Send` or `Sync` + --> $DIR/arc_with_non_send_sync.rs:18:13 | -LL | let b = Arc::new(RefCell::new(42)); +LL | let _ = Arc::new(RefCell::new(42)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider using `Rc` instead or wrapping `T` in a std::sync type like `Mutex` + = note: the trait `Sync` is not implemented for `RefCell` + = note: required for `Arc>` to implement `Send` and `Sync` + = help: consider using an `Rc` instead or wrapping the inner type with a `Mutex` = note: `-D clippy::arc-with-non-send-sync` implied by `-D warnings` -error: aborting due to previous error +error: usage of an `Arc` that is not `Send` or `Sync` + --> $DIR/arc_with_non_send_sync.rs:21:13 + | +LL | let _ = Arc::new(mutex.lock().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the trait `Send` is not implemented for `MutexGuard<'_, i32>` + = note: required for `Arc>` to implement `Send` and `Sync` + = help: consider using an `Rc` instead or wrapping the inner type with a `Mutex` + +error: usage of an `Arc` that is not `Send` or `Sync` + --> $DIR/arc_with_non_send_sync.rs:23:13 + | +LL | let _ = Arc::new(&42 as *const i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the trait `Send` is not implemented for `*const i32` + = note: the trait `Sync` is not implemented for `*const i32` + = note: required for `Arc<*const i32>` to implement `Send` and `Sync` + = help: consider using an `Rc` instead or wrapping the inner type with a `Mutex` + +error: aborting due to 3 previous errors From 28655266b5797292a23dc10027d37b4a598662d8 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Thu, 6 Jul 2023 14:43:21 +0000 Subject: [PATCH 182/324] Fix changelog PR listings, create them automatically in `fetch_prs_between.sh` --- CHANGELOG.md | 109 +++++++----------- .../infrastructure/changelog_update.md | 22 ---- util/fetch_prs_between.sh | 22 +++- 3 files changed, 60 insertions(+), 93 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2004c2931d5..da070adb8086 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ document. Current stable, released 2023-06-01 -[**View 85 PRs merged since 1.69**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2023-04-20..2023-06-01+base%3Amaster+sort%3Amerged-desc+) +[View all 91 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2023-02-26T01%3A05%3A43Z..2023-04-11T13%3A27%3A30Z+base%3Amaster) ### New Lints @@ -137,7 +137,7 @@ Current stable, released 2023-06-01 Released 2023-04-20 -[**View 86 PRs merged since 1.68**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2023-03-09..2023-04-20+base%3Amaster+sort%3Amerged-desc+) +[View all 72 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2023-01-13T06%3A12%3A46Z..2023-02-25T23%3A48%3A10Z+base%3Amaster) ### New Lints @@ -252,7 +252,7 @@ Released 2023-04-20 Released 2023-03-09 -[**View 85 PRs merged since 1.67**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2023-01-26..2023-03-09+base%3Amaster+sort%3Amerged-desc+) +[View all 76 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2022-12-01T20%3A40%3A04Z..2023-01-12T18%3A58%3A59Z+base%3Amaster) ### New Lints @@ -399,7 +399,7 @@ Released 2023-03-09 Released 2023-01-26 -[**View 68 PRs merged since 1.66**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2022-12-15..2023-01-26+base%3Amaster+sort%3Amerged-desc+) +[View all 104 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2022-10-23T13%3A35%3A19Z..2022-12-01T13%3A34%3A39Z+base%3Amaster) ### New Lints @@ -590,8 +590,7 @@ Released 2023-01-26 Released 2022-12-15 -[**View 93 PRs merged since 1.65**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2022-11-03..2022-12-15+base%3Amaster+sort%3Amerged-desc+) - +[View all 116 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2022-09-09T17%3A32%3A39Z..2022-10-23T11%3A27%3A24Z+base%3Amaster) ### New Lints @@ -762,8 +761,7 @@ Released 2022-12-15 Released 2022-11-03 -[**View 129 PRs merged since 1.64**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2022-09-22..2022-11-03+base%3Amaster+sort%3Amerged-desc+) - +[View all 86 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2022-07-29T01%3A09%3A31Z..2022-09-09T00%3A01%3A54Z+base%3Amaster) ### Important Changes @@ -907,8 +905,7 @@ Released 2022-11-03 Released 2022-09-22 -[**View 92 PRs merged since 1.63**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2022-08-11..2022-09-22+base%3Amaster+sort%3Amerged-desc+) - +[View all 110 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2022-06-17T21%3A25%3A31Z..2022-07-28T17%3A11%3A18Z+base%3Amaster) ### New Lints @@ -1058,8 +1055,7 @@ Released 2022-09-22 Released 2022-08-11 -[**View 100 PRs merged since 1.62**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2022-06-30..2022-08-11+base%3Amaster+sort%3Amerged-desc+) - +[View all 91 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2022-05-05T17%3A24%3A22Z..2022-06-16T14%3A24%3A48Z+base%3Amaster) ### New Lints @@ -1205,8 +1201,7 @@ Released 2022-08-11 Released 2022-06-30 -[**View 104 PRs merged since 1.61**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2022-05-19..2022-06-30+base%3Amaster+sort%3Amerged-desc+) - +[View all 90 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2022-03-25T17%3A22%3A30Z..2022-05-05T13%3A29%3A44Z+base%3Amaster) ### New Lints @@ -1363,8 +1358,7 @@ Released 2022-06-30 Released 2022-05-19 -[**View 93 PRs merged since 1.60**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2022-04-07..2022-05-19+base%3Amaster+sort%3Amerged-desc+) - +[View all 60 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2022-02-11T16%3A54%3A41Z..2022-03-24T13%3A42%3A25Z+base%3Amaster) ### New Lints @@ -1465,8 +1459,7 @@ Released 2022-05-19 Released 2022-04-07 -[**View 75 PRs merged since 1.59**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2022-02-24..2022-04-07+base%3Amaster+sort%3Amerged-desc+) - +[View all 73 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2021-12-31T17%3A53%3A37Z..2022-02-10T17%3A31%3A37Z+base%3Amaster) ### New Lints @@ -1598,8 +1591,7 @@ Released 2022-04-07 Released 2022-02-24 -[**View 63 PRs merged since 1.58**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2022-01-13..2022-02-24+base%3Amaster+sort%3Amerged-desc+) - +[View all 94 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2021-11-04T12%3A40%3A18Z..2021-12-30T13%3A36%3A20Z+base%3Amaster) ### New Lints @@ -1763,8 +1755,7 @@ Released 2022-02-24 Released 2022-01-13 -[**View 73 PRs merged since 1.57**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2021-12-02..2022-01-13+base%3Amaster+sort%3Amerged-desc+) - +[View all 68 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2021-10-07T09%3A49%3A18Z..2021-11-04T12%3A20%3A12Z+base%3Amaster) ### Rust 1.58.1 @@ -1885,8 +1876,7 @@ Released 2022-01-13 Released 2021-12-02 -[**View 92 PRs merged since 1.56**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2021-10-21..2021-12-02+base%3Amaster+sort%3Amerged-desc+) - +[View all 148 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2021-08-12T20%3A36%3A04Z..2021-11-03T17%3A57%3A59Z+base%3Amaster) ### New Lints @@ -2037,7 +2027,7 @@ Released 2021-12-02 Released 2021-10-21 -[**View 92 PRs merged since 1.55**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2021-09-09..2021-10-21+base%3Amaster+sort%3Amerged-desc+) +[View all 38 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2021-07-19T14%3A33%3A33Z..2021-08-12T09%3A28%3A38Z+base%3Amaster) ### New Lints @@ -2103,7 +2093,7 @@ Released 2021-10-21 Released 2021-09-09 -[**View 61 PRs merged since 1.54**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2021-07-29..2021-09-09+base%3Amaster+sort%3Amerged-desc+) +[View all 83 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2021-06-03T07%3A23%3A59Z..2021-07-29T11%3A47%3A32Z+base%3Amaster) ### Important Changes @@ -2221,8 +2211,7 @@ Released 2021-09-09 Released 2021-07-29 -[**View 68 PRs merged since 1.53**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2021-06-17..2021-07-29+base%3Amaster+sort%3Amerged-desc+) - +[View all 74 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2021-04-27T23%3A51%3A18Z..2021-06-03T06%3A54%3A07Z+base%3Amaster) ### New Lints @@ -2350,7 +2339,7 @@ Released 2021-07-29 Released 2021-06-17 -[**View 80 PRs merged since 1.52**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2021-05-06..2021-06-17+base%3Amaster+sort%3Amerged-desc+) +[View all 126 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2021-03-12T22%3A49%3A20Z..2021-04-27T14%3A38%3A20Z+base%3Amaster) ### New Lints @@ -2534,8 +2523,7 @@ Released 2021-06-17 Released 2021-05-06 -[**View 113 PRs merged since 1.51**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2021-03-25..2021-05-06+base%3Amaster+sort%3Amerged-desc+) - +[View all 102 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2021-02-03T15%3A59%3A06Z..2021-03-11T20%3A06%3A43Z+base%3Amaster) ### New Lints @@ -2670,8 +2658,7 @@ Released 2021-05-06 Released 2021-03-25 -[**View 117 PRs merged since 1.50**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2021-02-11..2021-03-25+base%3Amaster+sort%3Amerged-desc+) - +[View all 78 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2020-12-21T15%3A43%3A04Z..2021-02-03T04%3A21%3A10Z+base%3Amaster) ### New Lints @@ -2786,8 +2773,7 @@ Released 2021-03-25 Released 2021-02-11 -[**View 90 PRs merged since 1.49**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2020-12-31..2021-02-11+base%3Amaster+sort%3Amerged-desc+) - +[View all 119 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2020-11-06T18%3A32%3A40Z..2021-01-03T14%3A51%3A18Z+base%3Amaster) ### New Lints @@ -2916,8 +2902,7 @@ Released 2021-02-11 Released 2020-12-31 -[**View 85 PRs merged since 1.48**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2020-11-19..2020-12-31+base%3Amaster+sort%3Amerged-desc+) - +[View all 107 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2020-09-24T14%3A05%3A12Z..2020-11-05T13%3A35%3A44Z+base%3Amaster) ### New Lints @@ -3023,7 +3008,7 @@ Released 2020-12-31 Released 2020-11-19 -[**View 112 PRs merged since 1.47**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2020-10-08..2020-11-19+base%3Amaster+sort%3Amerged-desc+) +[View all 99 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2020-08-11T13%3A14%3A38Z..2020-09-23T18%3A55%3A22Z+base%3Amaster) ### New lints @@ -3141,8 +3126,7 @@ Released 2020-11-19 Released 2020-10-08 -[**View 80 PRs merged since 1.46**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2020-08-27..2020-10-08+base%3Amaster+sort%3Amerged-desc+) - +[View all 76 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2020-06-23T16%3A27%3A11Z..2020-08-11T12%3A52%3A41Z+base%3Amaster) ### New lints @@ -3244,8 +3228,7 @@ Released 2020-10-08 Released 2020-08-27 -[**View 93 PRs merged since 1.45**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2020-07-16..2020-08-27+base%3Amaster+sort%3Amerged-desc+) - +[View all 48 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2020-05-31T12%3A50%3A53Z..2020-06-23T15%3A00%3A32Z+base%3Amaster) ### New lints @@ -3307,8 +3290,7 @@ Released 2020-08-27 Released 2020-07-16 -[**View 65 PRs merged since 1.44**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2020-06-04..2020-07-16+base%3Amaster+sort%3Amerged-desc+) - +[View all 81 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2020-04-18T20%3A18%3A04Z..2020-05-27T19%3A25%3A04Z+base%3Amaster) ### New lints @@ -3385,8 +3367,7 @@ and [`similar_names`]. [#5651](https://github.com/rust-lang/rust-clippy/pull/565 Released 2020-06-04 -[**View 88 PRs merged since 1.43**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2020-04-23..2020-06-04+base%3Amaster+sort%3Amerged-desc+) - +[View all 124 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2020-03-05T17%3A30%3A53Z..2020-04-18T09%3A20%3A51Z+base%3Amaster) ### New lints @@ -3469,8 +3450,7 @@ Released 2020-06-04 Released 2020-04-23 -[**View 121 PRs merged since 1.42**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2020-03-12..2020-04-23+base%3Amaster+sort%3Amerged-desc+) - +[View all 91 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2020-01-26T16%3A01%3A11Z..2020-03-04T16%3A45%3A37Z+base%3Amaster) ### New lints @@ -3528,7 +3508,7 @@ Released 2020-04-23 Released 2020-03-12 -[**View 106 PRs merged since 1.41**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2020-01-30..2020-03-12+base%3Amaster+sort%3Amerged-desc+) +[View all 101 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2019-12-15T01%3A40%3A34Z..2020-01-26T11%3A22%3A13Z+base%3Amaster) ### New lints @@ -3595,7 +3575,7 @@ Released 2020-03-12 Released 2020-01-30 -[**View 107 PRs merged since 1.40**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2019-12-19..2020-01-30+base%3Amaster+sort%3Amerged-desc+) +[View all 74 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2019-10-28T20%3A50%3A24Z..2019-12-12T00%3A53%3A03Z+base%3Amaster) * New Lints: * [`exit`] [#4697](https://github.com/rust-lang/rust-clippy/pull/4697) @@ -3640,8 +3620,7 @@ Released 2020-01-30 Released 2019-12-19 -[**View 69 😺 PRs merged since 1.39**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2019-11-07..2019-12-19+base%3Amaster+sort%3Amerged-desc+) - +[View all 76 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2019-09-23T06%3A18%3A04Z..2019-10-28T17%3A34%3A55Z+base%3Amaster) * New Lints: * [`unneeded_wildcard_pattern`] [#4537](https://github.com/rust-lang/rust-clippy/pull/4537) @@ -3683,7 +3662,7 @@ Released 2019-12-19 Released 2019-11-07 -[**View 84 PRs merged since 1.38**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2019-09-26..2019-11-07+base%3Amaster+sort%3Amerged-desc+) +[View all 100 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2019-08-11T19%3A21%3A38Z..2019-09-22T12%3A07%3A39Z+base%3Amaster) * New Lints: * [`uninit_assumed_init`] [#4479](https://github.com/rust-lang/rust-clippy/pull/4479) @@ -3727,7 +3706,7 @@ Released 2019-11-07 Released 2019-09-26 -[**View 102 PRs merged since 1.37**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2019-08-15..2019-09-26+base%3Amaster+sort%3Amerged-desc+) +[View all 76 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2019-06-30T13%3A40%3A26Z..2019-08-11T09%3A47%3A27Z+base%3Amaster) * New Lints: * [`main_recursion`] [#4203](https://github.com/rust-lang/rust-clippy/pull/4203) @@ -3757,7 +3736,7 @@ Released 2019-09-26 Released 2019-08-15 -[**View 83 PRs merged since 1.36**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2019-07-04..2019-08-15+base%3Amaster+sort%3Amerged-desc+) +[View all 72 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2019-05-19T08%3A11%3A23Z..2019-06-25T23%3A22%3A22Z+base%3Amaster) * New Lints: * [`checked_conversions`] [#4088](https://github.com/rust-lang/rust-clippy/pull/4088) @@ -3781,8 +3760,7 @@ Released 2019-08-15 Released 2019-07-04 -[**View 75 PRs merged since 1.35**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2019-05-20..2019-07-04+base%3Amaster+sort%3Amerged-desc+) - +[View all 81 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2019-04-10T09%3A41%3A56Z..2019-05-18T00%3A29%3A40Z+base%3Amaster) * New lints: [`find_map`], [`filter_map_next`] [#4039](https://github.com/rust-lang/rust-clippy/pull/4039) * New lint: [`path_buf_push_overwrite`] [#3954](https://github.com/rust-lang/rust-clippy/pull/3954) @@ -3813,8 +3791,7 @@ Released 2019-07-04 Released 2019-05-20 -[**View 90 PRs merged since 1.34**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2019-04-10..2019-05-20+base%3Amaster+sort%3Amerged-desc+) - +[1fac380..37f5c1e](https://github.com/rust-lang/rust-clippy/compare/1fac380...37f5c1e) * New lint: `drop_bounds` to detect `T: Drop` bounds * Split [`redundant_closure`] into [`redundant_closure`] and [`redundant_closure_for_method_calls`] [#4110](https://github.com/rust-lang/rust-clippy/pull/4101) @@ -3842,8 +3819,7 @@ Released 2019-05-20 Released 2019-04-10 -[**View 66 PRs merged since 1.33**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2019-02-26..2019-04-10+base%3Amaster+sort%3Amerged-desc+) - +[View all 61 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2019-01-17T17%3A45%3A39Z..2019-02-19T08%3A24%3A05Z+base%3Amaster) * New lint: [`assertions_on_constants`] to detect for example `assert!(true)` * New lint: [`dbg_macro`] to detect uses of the `dbg!` macro @@ -3873,7 +3849,7 @@ Released 2019-04-10 Released 2019-02-26 -[**View 83 PRs merged since 1.32**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2019-01-17..2019-02-26+base%3Amaster+sort%3Amerged-desc+) +[View all 120 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2018-11-28T06%3A19%3A50Z..2019-01-15T09%3A27%3A02Z+base%3Amaster) * New lints: [`implicit_return`], [`vec_box`], [`cast_ref_to_mut`] * The `rust-clippy` repository is now part of the `rust-lang` org. @@ -3906,7 +3882,7 @@ Released 2019-02-26 Released 2019-01-17 -[**View 106 PRs merged since 1.31**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2018-12-06..2019-01-17+base%3Amaster+sort%3Amerged-desc+) +[View all 71 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2018-10-24T05%3A02%3A21Z..2018-11-27T17%3A29%3A34Z+base%3Amaster) * New lints: [`slow_vector_initialization`], `mem_discriminant_non_enum`, [`redundant_clone`], [`wildcard_dependencies`], @@ -3936,8 +3912,7 @@ Released 2019-01-17 Released 2018-12-06 -[**View 85 PRs merged since 1.30**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2018-10-25..2018-12-06+base%3Amaster+sort%3Amerged-desc+) - +[125907ad..2e26fdc2](https://github.com/rust-lang/rust-clippy/compare/125907ad..2e26fdc2) * Clippy has been relicensed under a dual MIT / Apache license. See [#3093](https://github.com/rust-lang/rust-clippy/issues/3093) for more @@ -3977,9 +3952,7 @@ Released 2018-12-06 Released 2018-10-25 -[**View 106 PRs merged since 1.29**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2018-09-13..2018-10-25+base%3Amaster+sort%3Amerged-desc+) - - +[View all 88 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2018-08-02T16%3A54%3A12Z..2018-09-17T09%3A44%3A06Z+base%3Amaster) * Deprecate `assign_ops` lint * New lints: [`mistyped_literal_suffixes`], [`ptr_offset_with_cast`], [`needless_collect`], [`copy_iterator`] diff --git a/book/src/development/infrastructure/changelog_update.md b/book/src/development/infrastructure/changelog_update.md index 52445494436c..df9b1bbe18f3 100644 --- a/book/src/development/infrastructure/changelog_update.md +++ b/book/src/development/infrastructure/changelog_update.md @@ -56,28 +56,6 @@ and open that file in your editor of choice. When updating the changelog it's also a good idea to make sure that `commit1` is already correct in the current changelog. -#### PR ranges - -We developed the concept of PR ranges to help the user understand the size of a new update. To create a PR range, -get the current release date and the date that the last version was released (YYYY-MM-DD) and use the following link: - -``` -[**View PRs merged since 1.**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A..+base%3Amaster+sort%3Amerged-desc+) -``` - -> Note: Be sure to check click the link and check how many PRs got merged between - -Example: - -``` -[**View 85 PRs merged since 1.69**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2023-04-20..2023-06-01+base%3Amaster+sort%3Amerged-desc+) -``` - -Which renders to: -[**View 85 PRs merged since 1.69**](https://github.com/rust-lang/rust-clippy/pulls?q=is%3Apr+is%3Aclosed+merged%3A2023-04-20..2023-06-01+base%3Amaster+sort%3Amerged-desc+) - -Note that **commit ranges should not be included**, only PR ranges. - ### 3. Authoring the final changelog The above script should have dumped all the relevant PRs to the file you diff --git a/util/fetch_prs_between.sh b/util/fetch_prs_between.sh index 6865abf971b2..fa7560b6929d 100755 --- a/util/fetch_prs_between.sh +++ b/util/fetch_prs_between.sh @@ -6,15 +6,20 @@ # If you want to use this to update the Clippy changelog, be sure to manually # exclude the non-user facing changes like 'rustup' PRs, typo fixes, etc. -first=$1 -last=$2 +set -e IFS=' ' -for pr in $(git log --oneline --grep "Merge #" --grep "Merge pull request" --grep "Auto merge of" --grep "Rollup merge of" "$first...$last" | sort -rn | uniq); do +for pr in $(git log --oneline --merges --first-parent "$1...$2"); do id=$(echo "$pr" | rg -o '#[0-9]{3,5}' | cut -c 2-) commit=$(echo "$pr" | cut -d' ' -f 1) message=$(git --no-pager show --pretty=medium "$commit") + + if [[ -z "$newest_pr" ]]; then + newest_pr="$id" + fi + oldest_pr="$id" + if [[ -n $(echo "$message" | rg "^[\s]{4}changelog: [nN]one\.*$") ]]; then continue fi @@ -25,3 +30,14 @@ for pr in $(git log --oneline --grep "Merge #" --grep "Merge pull request" --gre echo "---------------------------------------------------------" echo done + +newest_merged_at="$(gh pr view -R rust-lang/rust-clippy --json mergedAt $newest_pr -q .mergedAt)" +oldest_merged_at="$(gh pr view -R rust-lang/rust-clippy --json mergedAt $oldest_pr -q .mergedAt)" + +query="merged:$oldest_merged_at..$newest_merged_at base:master" +encoded_query="$(echo $query | sed 's/ /+/g; s/:/%3A/g')" + +pr_link="https://github.com/rust-lang/rust-clippy/pulls?q=$encoded_query" +count="$(gh api -X GET search/issues -f "q=$query repo:rust-lang/rust-clippy" -q .total_count)" + +echo "[View all $count merged pull requests]($pr_link)" From 5cc0c048264779509800a7b029e79454c48987a8 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Mon, 3 Jul 2023 20:24:14 +0200 Subject: [PATCH 183/324] [`manual_range_patterns`]: lint negative values --- clippy_lints/src/manual_range_patterns.rs | 19 +++++++++++-------- tests/ui/manual_range_patterns.fixed | 4 ++++ tests/ui/manual_range_patterns.rs | 4 ++++ tests/ui/manual_range_patterns.stderr | 16 ++++++++++++++-- 4 files changed, 33 insertions(+), 10 deletions(-) diff --git a/clippy_lints/src/manual_range_patterns.rs b/clippy_lints/src/manual_range_patterns.rs index 65ff555209a6..eb9576992a32 100644 --- a/clippy_lints/src/manual_range_patterns.rs +++ b/clippy_lints/src/manual_range_patterns.rs @@ -6,6 +6,7 @@ use rustc_hir::Expr; use rustc_hir::ExprKind; use rustc_hir::PatKind; use rustc_hir::RangeEnd; +use rustc_hir::UnOp; use rustc_lint::LintContext; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; @@ -36,11 +37,13 @@ declare_clippy_lint! { } declare_lint_pass!(ManualRangePatterns => [MANUAL_RANGE_PATTERNS]); -fn expr_as_u128(expr: &Expr<'_>) -> Option { - if let ExprKind::Lit(lit) = expr.kind +fn expr_as_i128(expr: &Expr<'_>) -> Option { + if let ExprKind::Unary(UnOp::Neg, expr) = expr.kind { + expr_as_i128(expr).map(|num| -num) + } else if let ExprKind::Lit(lit) = expr.kind && let LitKind::Int(num, _) = lit.node { - Some(num) + Some(num as i128) } else { None } @@ -56,22 +59,22 @@ impl LateLintPass<'_> for ManualRangePatterns { if let PatKind::Or(pats) = pat.kind && pats.len() >= 3 { - let mut min = u128::MAX; - let mut max = 0; + let mut min = i128::MAX; + let mut max = i128::MIN; let mut numbers_found = FxHashSet::default(); let mut ranges_found = Vec::new(); for pat in pats { if let PatKind::Lit(lit) = pat.kind - && let Some(num) = expr_as_u128(lit) + && let Some(num) = expr_as_i128(lit) { numbers_found.insert(num); min = min.min(num); max = max.max(num); } else if let PatKind::Range(Some(left), Some(right), end) = pat.kind - && let Some(left) = expr_as_u128(left) - && let Some(right) = expr_as_u128(right) + && let Some(left) = expr_as_i128(left) + && let Some(right) = expr_as_i128(right) && right >= left { min = min.min(left); diff --git a/tests/ui/manual_range_patterns.fixed b/tests/ui/manual_range_patterns.fixed index 9eee8f371874..6bfcf263aa5e 100644 --- a/tests/ui/manual_range_patterns.fixed +++ b/tests/ui/manual_range_patterns.fixed @@ -25,6 +25,10 @@ fn main() { 1..=10 => true, _ => false, }; + let _ = matches!(f, -5..=3); + let _ = matches!(f, -1 | -5 | 3 | -2 | -4 | -3 | 0 | 1); // 2 is missing + let _ = matches!(f, -1000001..=1000001); + let _ = matches!(f, -1_000_000..=1_000_000 | -1_000_001 | 1_000_002); macro_rules! mac { ($e:expr) => { diff --git a/tests/ui/manual_range_patterns.rs b/tests/ui/manual_range_patterns.rs index 10743a7d04c6..4a429bb2aed3 100644 --- a/tests/ui/manual_range_patterns.rs +++ b/tests/ui/manual_range_patterns.rs @@ -25,6 +25,10 @@ fn main() { 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 => true, _ => false, }; + let _ = matches!(f, -1 | -5 | 3 | -2 | -4 | -3 | 0 | 1 | 2); + let _ = matches!(f, -1 | -5 | 3 | -2 | -4 | -3 | 0 | 1); // 2 is missing + let _ = matches!(f, -1_000_000..=1_000_000 | -1_000_001 | 1_000_001); + let _ = matches!(f, -1_000_000..=1_000_000 | -1_000_001 | 1_000_002); macro_rules! mac { ($e:expr) => { diff --git a/tests/ui/manual_range_patterns.stderr b/tests/ui/manual_range_patterns.stderr index bc9e33501645..b1b55d483e72 100644 --- a/tests/ui/manual_range_patterns.stderr +++ b/tests/ui/manual_range_patterns.stderr @@ -37,7 +37,19 @@ LL | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 => true, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1..=10` error: this OR pattern can be rewritten using a range - --> $DIR/manual_range_patterns.rs:31:26 + --> $DIR/manual_range_patterns.rs:28:25 + | +LL | let _ = matches!(f, -1 | -5 | 3 | -2 | -4 | -3 | 0 | 1 | 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `-5..=3` + +error: this OR pattern can be rewritten using a range + --> $DIR/manual_range_patterns.rs:30:25 + | +LL | let _ = matches!(f, -1_000_000..=1_000_000 | -1_000_001 | 1_000_001); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `-1000001..=1000001` + +error: this OR pattern can be rewritten using a range + --> $DIR/manual_range_patterns.rs:35:26 | LL | matches!($e, 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1..=10` @@ -47,5 +59,5 @@ LL | mac!(f); | = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 7 previous errors +error: aborting due to 9 previous errors From c927912c5bc7aa511ca70e5c3786fa0ac8442774 Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Thu, 6 Jul 2023 17:05:26 +0200 Subject: [PATCH 184/324] [`manual_range_patterns`]: document what range we don't lint --- clippy_lints/src/manual_range_patterns.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/manual_range_patterns.rs b/clippy_lints/src/manual_range_patterns.rs index eb9576992a32..64d4c8e45665 100644 --- a/clippy_lints/src/manual_range_patterns.rs +++ b/clippy_lints/src/manual_range_patterns.rs @@ -20,6 +20,10 @@ declare_clippy_lint! { /// ### Why is this bad? /// Using an explicit range is more concise and easier to read. /// + /// ### Known issues + /// This lint intentionally does not handle numbers greater than `i128::MAX` for `u128` literals + /// in order to support negative numbers. + /// /// ### Example /// ```rust /// let x = 6; @@ -43,7 +47,8 @@ fn expr_as_i128(expr: &Expr<'_>) -> Option { } else if let ExprKind::Lit(lit) = expr.kind && let LitKind::Int(num, _) = lit.node { - Some(num as i128) + // Intentionally not handling numbers greater than i128::MAX (for u128 literals) for now. + num.try_into().ok() } else { None } From b5ac726ed348430ee25a04d7de6569cb4627e726 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Wed, 5 Jul 2023 20:07:03 +0200 Subject: [PATCH 185/324] Rename `adjustment::PointerCast` and variants using it to `PointerCoercion` It makes it sound like the `ExprKind` and `Rvalue` are supposed to represent all pointer related casts, when in reality their just used to share a some enum variants. Make it clear there these are only coercion to make it clear why only some pointer related "casts" are in the enum. --- clippy_lints/src/derivable_impls.rs | 4 ++-- clippy_lints/src/pass_by_ref_or_value.rs | 4 ++-- clippy_utils/src/qualify_min_const_fn.rs | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs index ec0ca50cfec7..020ffe7f8fa2 100644 --- a/clippy_lints/src/derivable_impls.rs +++ b/clippy_lints/src/derivable_impls.rs @@ -9,7 +9,7 @@ use rustc_hir::{ Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::adjustment::{Adjust, PointerCast}; +use rustc_middle::ty::adjustment::{Adjust, PointerCoercion}; use rustc_middle::ty::{self, Adt, AdtDef, SubstsRef, Ty, TypeckResults}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::sym; @@ -116,7 +116,7 @@ fn check_struct<'tcx>( let is_default_without_adjusts = |expr| { is_default_equivalent(cx, expr) && typeck_results.expr_adjustments(expr).iter().all(|adj| { - !matches!(adj.kind, Adjust::Pointer(PointerCast::Unsize) + !matches!(adj.kind, Adjust::Pointer(PointerCoercion::Unsize) if contains_trait_object(adj.target)) }) }; diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index 0d78c3048ba1..eab725de17f6 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -14,7 +14,7 @@ use rustc_hir as hir; use rustc_hir::intravisit::FnKind; use rustc_hir::{BindingAnnotation, Body, FnDecl, Impl, ItemKind, MutTy, Mutability, Node, PatKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::adjustment::{Adjust, PointerCast}; +use rustc_middle::ty::adjustment::{Adjust, PointerCoercion}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, RegionKind}; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -195,7 +195,7 @@ impl<'tcx> PassByRefOrValue { .adjustments() .items() .flat_map(|(_, a)| a) - .any(|a| matches!(a.kind, Adjust::Pointer(PointerCast::UnsafeFnPointer))) + .any(|a| matches!(a.kind, Adjust::Pointer(PointerCoercion::UnsafeFnPointer))) { continue; } diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index c9938caefb06..fbf4ab2722e6 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -16,7 +16,7 @@ use rustc_middle::mir::{ }; use rustc_middle::traits::{ImplSource, ObligationCause}; use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt}; +use rustc_middle::ty::{self, adjustment::PointerCoercion, Ty, TyCtxt}; use rustc_middle::ty::{BoundConstness, TraitRef}; use rustc_semver::RustcVersion; use rustc_span::symbol::sym; @@ -119,18 +119,18 @@ fn check_rvalue<'tcx>( | CastKind::FloatToFloat | CastKind::FnPtrToPtr | CastKind::PtrToPtr - | CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer), + | CastKind::PointerCoercion(PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer), operand, _, ) => check_operand(tcx, operand, span, body), Rvalue::Cast( - CastKind::Pointer( - PointerCast::UnsafeFnPointer | PointerCast::ClosureFnPointer(_) | PointerCast::ReifyFnPointer, + CastKind::PointerCoercion( + PointerCoercion::UnsafeFnPointer | PointerCoercion::ClosureFnPointer(_) | PointerCoercion::ReifyFnPointer, ), _, _, ) => Err((span, "function pointer casts are not allowed in const fn".into())), - Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), op, cast_ty) => { + Rvalue::Cast(CastKind::PointerCoercion(PointerCoercion::Unsize), op, cast_ty) => { let pointee_ty = if let Some(deref_ty) = cast_ty.builtin_deref(true) { deref_ty.ty } else { From 87373d7f522031c0adc66eb87864ae86868e4fed Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Fri, 7 Jul 2023 18:18:25 +0000 Subject: [PATCH 186/324] Fix failing clippy tests Comments out the C string literals due to https://github.com/rust-lang/rust/pull/113334 Fixes https://github.com/rust-lang/rust-clippy/issues/11121 --- clippy_lints/src/incorrect_impls.rs | 2 +- tests/ui/needless_raw_string.fixed | 7 ++++--- tests/ui/needless_raw_string.rs | 7 ++++--- tests/ui/needless_raw_string.stderr | 8 +------- tests/ui/needless_raw_string_hashes.fixed | 9 +++++---- tests/ui/needless_raw_string_hashes.rs | 9 +++++---- tests/ui/needless_raw_string_hashes.stderr | 20 +------------------- 7 files changed, 21 insertions(+), 41 deletions(-) diff --git a/clippy_lints/src/incorrect_impls.rs b/clippy_lints/src/incorrect_impls.rs index 13cc0b23ba33..7b95116ee4e3 100644 --- a/clippy_lints/src/incorrect_impls.rs +++ b/clippy_lints/src/incorrect_impls.rs @@ -82,7 +82,7 @@ impl LateLintPass<'_> for IncorrectImpls { cx, hir_ty_to_ty(cx.tcx, imp.self_ty), copy_def_id, - trait_impl.substs, + &[], ) { if impl_item.ident.name == sym::clone { diff --git a/tests/ui/needless_raw_string.fixed b/tests/ui/needless_raw_string.fixed index 6438e46977bb..b36912efbb2d 100644 --- a/tests/ui/needless_raw_string.fixed +++ b/tests/ui/needless_raw_string.fixed @@ -10,7 +10,8 @@ fn main() { b"aaa"; br#""aaa""#; br#"\s"#; - c"aaa"; - cr#""aaa""#; - cr#"\s"#; + // currently disabled: https://github.com/rust-lang/rust/issues/113333 + // cr#"aaa"#; + // cr#""aaa""#; + // cr#"\s"#; } diff --git a/tests/ui/needless_raw_string.rs b/tests/ui/needless_raw_string.rs index f7ddc68265ed..8f48e7dab2a6 100644 --- a/tests/ui/needless_raw_string.rs +++ b/tests/ui/needless_raw_string.rs @@ -10,7 +10,8 @@ fn main() { br#"aaa"#; br#""aaa""#; br#"\s"#; - cr#"aaa"#; - cr#""aaa""#; - cr#"\s"#; + // currently disabled: https://github.com/rust-lang/rust/issues/113333 + // cr#"aaa"#; + // cr#""aaa""#; + // cr#"\s"#; } diff --git a/tests/ui/needless_raw_string.stderr b/tests/ui/needless_raw_string.stderr index 0179978b7b08..cfb07b647d7c 100644 --- a/tests/ui/needless_raw_string.stderr +++ b/tests/ui/needless_raw_string.stderr @@ -12,11 +12,5 @@ error: unnecessary raw string literal LL | br#"aaa"#; | ^^^^^^^^^ help: try: `b"aaa"` -error: unnecessary raw string literal - --> $DIR/needless_raw_string.rs:13:5 - | -LL | cr#"aaa"#; - | ^^^^^^^^^ help: try: `c"aaa"` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/needless_raw_string_hashes.fixed b/tests/ui/needless_raw_string_hashes.fixed index e4d7d8fb017a..c8507c727151 100644 --- a/tests/ui/needless_raw_string_hashes.fixed +++ b/tests/ui/needless_raw_string_hashes.fixed @@ -12,8 +12,9 @@ fn main() { br#"Hello "world"!"#; br####" "### "## "# "####; br###" "aa" "# "## "###; - cr#"aaa"#; - cr#"Hello "world"!"#; - cr####" "### "## "# "####; - cr###" "aa" "# "## "###; + // currently disabled: https://github.com/rust-lang/rust/issues/113333 + // cr#"aaa"#; + // cr##"Hello "world"!"##; + // cr######" "### "## "# "######; + // cr######" "aa" "# "## "######; } diff --git a/tests/ui/needless_raw_string_hashes.rs b/tests/ui/needless_raw_string_hashes.rs index e2d85c52e78c..912fbde1679d 100644 --- a/tests/ui/needless_raw_string_hashes.rs +++ b/tests/ui/needless_raw_string_hashes.rs @@ -12,8 +12,9 @@ fn main() { br##"Hello "world"!"##; br######" "### "## "# "######; br######" "aa" "# "## "######; - cr#"aaa"#; - cr##"Hello "world"!"##; - cr######" "### "## "# "######; - cr######" "aa" "# "## "######; + // currently disabled: https://github.com/rust-lang/rust/issues/113333 + // cr#"aaa"#; + // cr##"Hello "world"!"##; + // cr######" "### "## "# "######; + // cr######" "aa" "# "## "######; } diff --git a/tests/ui/needless_raw_string_hashes.stderr b/tests/ui/needless_raw_string_hashes.stderr index dff47a2d0421..30e6783a38e8 100644 --- a/tests/ui/needless_raw_string_hashes.stderr +++ b/tests/ui/needless_raw_string_hashes.stderr @@ -36,23 +36,5 @@ error: unnecessary hashes around raw string literal LL | br######" "aa" "# "## "######; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `br###" "aa" "# "## "###` -error: unnecessary hashes around raw string literal - --> $DIR/needless_raw_string_hashes.rs:16:5 - | -LL | cr##"Hello "world"!"##; - | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `cr#"Hello "world"!"#` - -error: unnecessary hashes around raw string literal - --> $DIR/needless_raw_string_hashes.rs:17:5 - | -LL | cr######" "### "## "# "######; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cr####" "### "## "# "####` - -error: unnecessary hashes around raw string literal - --> $DIR/needless_raw_string_hashes.rs:18:5 - | -LL | cr######" "aa" "# "## "######; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cr###" "aa" "# "## "###` - -error: aborting due to 9 previous errors +error: aborting due to 6 previous errors From 5df1f6681dca1a2028a4e6b60d3ab789c00b4cf8 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Fri, 7 Jul 2023 20:28:51 +0200 Subject: [PATCH 187/324] Pass correct substs to `implements_trait` in `incorrect_impls` `Copy` does in fact not exist. The substs on the trait_ref contain the `Self` type of the impl as the first parameter, so passing that to `implements_trait`, which then nicely prepends the `Self` type for us does not end will. --- clippy_lints/src/incorrect_impls.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/incorrect_impls.rs b/clippy_lints/src/incorrect_impls.rs index 13cc0b23ba33..ed21df4ff884 100644 --- a/clippy_lints/src/incorrect_impls.rs +++ b/clippy_lints/src/incorrect_impls.rs @@ -1,7 +1,6 @@ use clippy_utils::{diagnostics::span_lint_and_sugg, get_parent_node, last_path_segment, ty::implements_trait}; use rustc_errors::Applicability; -use rustc_hir::{ExprKind, ImplItem, ImplItemKind, ItemKind, Node, UnOp}; -use rustc_hir_analysis::hir_ty_to_ty; +use rustc_hir::{ExprKind, ImplItem, ImplItemKind, Node, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::EarlyBinder; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -55,9 +54,6 @@ impl LateLintPass<'_> for IncorrectImpls { let Some(Node::Item(item)) = node else { return; }; - let ItemKind::Impl(imp) = item.kind else { - return; - }; let Some(trait_impl) = cx.tcx.impl_trait_ref(item.owner_id).map(EarlyBinder::skip_binder) else { return; }; @@ -80,9 +76,9 @@ impl LateLintPass<'_> for IncorrectImpls { && let Some(copy_def_id) = cx.tcx.get_diagnostic_item(sym::Copy) && implements_trait( cx, - hir_ty_to_ty(cx.tcx, imp.self_ty), + trait_impl.self_ty(), copy_def_id, - trait_impl.substs, + &[], ) { if impl_item.ident.name == sym::clone { From f0ba0dbe8aee408322f6e675549b446847c6442b Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Sat, 8 Jul 2023 01:07:38 +0330 Subject: [PATCH 188/324] Use debug impl in rendering const eval result --- crates/hir-ty/src/display.rs | 22 ------- crates/hir-ty/src/mir.rs | 4 +- crates/hir-ty/src/mir/eval.rs | 115 ++++++++++++++++++++++++---------- crates/hir/src/lib.rs | 23 ++++++- 4 files changed, 106 insertions(+), 58 deletions(-) diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs index b87047718d01..8cffdef289ea 100644 --- a/crates/hir-ty/src/display.rs +++ b/crates/hir-ty/src/display.rs @@ -446,28 +446,6 @@ impl HirDisplay for Const { } } -pub struct HexifiedConst(pub Const); - -impl HirDisplay for HexifiedConst { - fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - let data = &self.0.data(Interner); - if let TyKind::Scalar(s) = data.ty.kind(Interner) { - if matches!(s, Scalar::Int(_) | Scalar::Uint(_)) { - if let ConstValue::Concrete(c) = &data.value { - if let ConstScalar::Bytes(b, m) = &c.interned { - let value = u128::from_le_bytes(pad16(b, false)); - if value >= 10 { - render_const_scalar(f, &b, m, &data.ty)?; - return write!(f, " ({:#X})", value); - } - } - } - } - } - self.0.hir_fmt(f) - } -} - fn render_const_scalar( f: &mut HirFormatter<'_>, b: &[u8], diff --git a/crates/hir-ty/src/mir.rs b/crates/hir-ty/src/mir.rs index 2345bab0bb4d..5e92b350a3ce 100644 --- a/crates/hir-ty/src/mir.rs +++ b/crates/hir-ty/src/mir.rs @@ -22,7 +22,9 @@ mod pretty; mod monomorphization; pub use borrowck::{borrowck_query, BorrowckResult, MutabilityReason}; -pub use eval::{interpret_mir, pad16, Evaluator, MirEvalError, VTableMap}; +pub use eval::{ + interpret_mir, pad16, render_const_using_debug_impl, Evaluator, MirEvalError, VTableMap, +}; pub use lower::{ lower_to_mir, mir_body_for_closure_query, mir_body_query, mir_body_recover, MirLowerError, }; diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index c76d066232c9..010ebcbd0688 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -10,10 +10,11 @@ use hir_def::{ data::adt::{StructFlags, VariantData}, lang_item::LangItem, layout::{TagEncoding, Variants}, - AdtId, DefWithBodyId, EnumVariantId, FunctionId, HasModule, ItemContainerId, Lookup, StaticId, - VariantId, + resolver::{HasResolver, TypeNs, ValueNs}, + AdtId, ConstId, DefWithBodyId, EnumVariantId, FunctionId, HasModule, ItemContainerId, Lookup, + StaticId, VariantId, }; -use hir_expand::InFile; +use hir_expand::{mod_path::ModPath, InFile}; use intern::Interned; use la_arena::ArenaMap; use rustc_hash::{FxHashMap, FxHashSet}; @@ -482,7 +483,7 @@ pub fn interpret_mir( assert_placeholder_ty_is_unused: bool, ) -> (Result, String, String) { let ty = body.locals[return_slot()].ty.clone(); - let mut evaluator = Evaluator::new(db, &body, assert_placeholder_ty_is_unused); + let mut evaluator = Evaluator::new(db, body.owner, assert_placeholder_ty_is_unused); let it: Result = (|| { if evaluator.ptr_size() != std::mem::size_of::() { not_supported!("targets with different pointer size from host"); @@ -506,11 +507,11 @@ pub fn interpret_mir( impl Evaluator<'_> { pub fn new<'a>( db: &'a dyn HirDatabase, - body: &MirBody, + owner: DefWithBodyId, assert_placeholder_ty_is_unused: bool, ) -> Evaluator<'a> { - let crate_id = body.owner.module(db.upcast()).krate(); - let trait_env = db.trait_environment_for_body(body.owner); + let crate_id = owner.module(db.upcast()).krate(); + let trait_env = db.trait_environment_for_body(owner); Evaluator { stack: vec![0], heap: vec![0], @@ -1551,29 +1552,15 @@ impl Evaluator<'_> { let addr = self.eval_static(*st, locals)?; Interval::new(addr, self.ptr_size()) } - Operand::Constant(konst) => { - let data = &konst.data(Interner); - match &data.value { - chalk_ir::ConstValue::BoundVar(_) => not_supported!("bound var constant"), - chalk_ir::ConstValue::InferenceVar(_) => { - not_supported!("inference var constant") - } - chalk_ir::ConstValue::Placeholder(_) => not_supported!("placeholder constant"), - chalk_ir::ConstValue::Concrete(c) => { - self.allocate_const_in_heap(c, &data.ty, locals, konst)? - } - } - } + Operand::Constant(konst) => self.allocate_const_in_heap(locals, konst)?, }) } - fn allocate_const_in_heap( - &mut self, - c: &chalk_ir::ConcreteConst, - ty: &Ty, - locals: &Locals, - konst: &chalk_ir::Const, - ) -> Result { + fn allocate_const_in_heap(&mut self, locals: &Locals, konst: &Const) -> Result { + let ty = &konst.data(Interner).ty; + let chalk_ir::ConstValue::Concrete(c) = &konst.data(Interner).value else { + not_supported!("evaluating non concrete constant"); + }; Ok(match &c.interned { ConstScalar::Bytes(v, memory_map) => { let mut v: Cow<'_, [u8]> = Cow::Borrowed(v); @@ -2242,12 +2229,7 @@ impl Evaluator<'_> { Box::new(e), ) })?; - let data = &konst.data(Interner); - if let chalk_ir::ConstValue::Concrete(c) = &data.value { - self.allocate_const_in_heap(&c, &data.ty, locals, &konst)? - } else { - not_supported!("unevaluatable static"); - } + self.allocate_const_in_heap(locals, &konst)? } else { let ty = &self.db.infer(st.into())[self.db.body(st.into()).body_expr]; let Some((size, align)) = self.size_align_of(&ty, locals)? else { @@ -2388,6 +2370,73 @@ impl Evaluator<'_> { } } +pub fn render_const_using_debug_impl( + db: &dyn HirDatabase, + owner: ConstId, + c: &Const, +) -> Result { + let mut evaluator = Evaluator::new(db, owner.into(), false); + let locals = &Locals { + ptr: ArenaMap::new(), + body: db + .mir_body(owner.into()) + .map_err(|_| MirEvalError::NotSupported("unreachable".to_string()))?, + drop_flags: DropFlags::default(), + }; + let data = evaluator.allocate_const_in_heap(locals, c)?; + let resolver = owner.resolver(db.upcast()); + let Some(TypeNs::TraitId(debug_trait)) = resolver.resolve_path_in_type_ns_fully( + db.upcast(), + &hir_def::path::Path::from_known_path_with_no_generic(ModPath::from_segments( + hir_expand::mod_path::PathKind::Abs, + [name![core], name![fmt], name![Debug]].into_iter(), + )), + ) else { + not_supported!("core::fmt::Debug not found"); + }; + let Some(debug_fmt_fn) = db.trait_data(debug_trait).method_by_name(&name![fmt]) else { + not_supported!("core::fmt::Debug::fmt not found"); + }; + // a1 = &[""] + let a1 = evaluator.heap_allocate(evaluator.ptr_size() * 2, evaluator.ptr_size()); + // a2 = &[::core::fmt::ArgumentV1::new(&(THE_CONST), ::core::fmt::Debug::fmt)] + // FIXME: we should call the said function, but since its name is going to break in the next rustc version + // and its ABI doesn't break yet, we put it in memory manually. + let a2 = evaluator.heap_allocate(evaluator.ptr_size() * 2, evaluator.ptr_size()); + evaluator.write_memory(a2, &data.addr.to_bytes())?; + let debug_fmt_fn_ptr = evaluator.vtable_map.id(TyKind::FnDef( + db.intern_callable_def(debug_fmt_fn.into()).into(), + Substitution::from1(Interner, c.data(Interner).ty.clone()), + ) + .intern(Interner)); + evaluator.write_memory(a2.offset(evaluator.ptr_size()), &debug_fmt_fn_ptr.to_le_bytes())?; + // a3 = ::core::fmt::Arguments::new_v1(a1, a2) + // FIXME: similarly, we should call function here, not directly working with memory. + let a3 = evaluator.heap_allocate(evaluator.ptr_size() * 6, evaluator.ptr_size()); + evaluator.write_memory(a3.offset(2 * evaluator.ptr_size()), &a1.to_bytes())?; + evaluator.write_memory(a3.offset(3 * evaluator.ptr_size()), &[1])?; + evaluator.write_memory(a3.offset(4 * evaluator.ptr_size()), &a2.to_bytes())?; + evaluator.write_memory(a3.offset(5 * evaluator.ptr_size()), &[1])?; + let Some(ValueNs::FunctionId(format_fn)) = resolver.resolve_path_in_value_ns_fully( + db.upcast(), + &hir_def::path::Path::from_known_path_with_no_generic(ModPath::from_segments( + hir_expand::mod_path::PathKind::Abs, + [name![std], name![fmt], name![format]].into_iter(), + )), + ) else { + not_supported!("std::fmt::format not found"); + }; + let message_string = evaluator.interpret_mir( + db.mir_body(format_fn.into()).map_err(|e| MirEvalError::MirLowerError(format_fn, e))?, + [IntervalOrOwned::Borrowed(Interval { addr: a3, size: evaluator.ptr_size() * 6 })] + .into_iter(), + )?; + let addr = + Address::from_bytes(&message_string[evaluator.ptr_size()..2 * evaluator.ptr_size()])?; + let size = from_bytes!(usize, message_string[2 * evaluator.ptr_size()..]); + Ok(std::string::String::from_utf8_lossy(evaluator.read_memory(addr, size)?).into_owned()) +} + pub fn pad16(it: &[u8], is_signed: bool) -> [u8; 16] { let is_negative = is_signed && it.last().unwrap_or(&0) > &127; let fill_with = if is_negative { 255 } else { 0 }; diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 337cfbfb625b..44f901fb3a39 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -62,7 +62,6 @@ use hir_ty::{ all_super_traits, autoderef, consteval::{try_const_usize, unknown_const_as_generic, ConstEvalError, ConstExt}, diagnostics::BodyValidationDiagnostic, - display::HexifiedConst, layout::{Layout as TyLayout, RustcEnumVariantIdx, TagEncoding}, method_resolution::{self, TyFingerprint}, mir::{self, interpret_mir}, @@ -2156,7 +2155,27 @@ impl Const { pub fn render_eval(self, db: &dyn HirDatabase) -> Result { let c = db.const_eval(self.id.into(), Substitution::empty(Interner))?; - let r = format!("{}", HexifiedConst(c).display(db)); + let data = &c.data(Interner); + if let TyKind::Scalar(s) = data.ty.kind(Interner) { + if matches!(s, Scalar::Int(_) | Scalar::Uint(_)) { + if let hir_ty::ConstValue::Concrete(c) = &data.value { + if let hir_ty::ConstScalar::Bytes(b, _) = &c.interned { + let value = u128::from_le_bytes(mir::pad16(b, false)); + let value_signed = + i128::from_le_bytes(mir::pad16(b, matches!(s, Scalar::Int(_)))); + if value >= 10 { + return Ok(format!("{} ({:#X})", value_signed, value)); + } else { + return Ok(format!("{}", value_signed)); + } + } + } + } + } + if let Ok(s) = mir::render_const_using_debug_impl(db, self.id, &c) { + return Ok(s); + } + let r = format!("{}", c.display(db)); return Ok(r); } } From 4de7cbe04c1e256984901bd40ac3c8739a9f3f78 Mon Sep 17 00:00:00 2001 From: DropDemBits Date: Sat, 24 Jun 2023 20:31:44 -0400 Subject: [PATCH 189/324] internal: add `add_tabstop_{before,after}_token` --- crates/ide-db/src/source_change.rs | 63 +++++++++++++++++++----------- 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/crates/ide-db/src/source_change.rs b/crates/ide-db/src/source_change.rs index 061fb0f05cfb..fad0ca51a025 100644 --- a/crates/ide-db/src/source_change.rs +++ b/crates/ide-db/src/source_change.rs @@ -9,7 +9,10 @@ use crate::SnippetCap; use base_db::{AnchoredPathBuf, FileId}; use nohash_hasher::IntMap; use stdx::never; -use syntax::{algo, ast, ted, AstNode, SyntaxNode, SyntaxNodePtr, TextRange, TextSize}; +use syntax::{ + algo, ast, ted, AstNode, SyntaxElement, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, + TextSize, +}; use text_edit::{TextEdit, TextEditBuilder}; #[derive(Default, Debug, Clone)] @@ -237,19 +240,31 @@ impl SourceChangeBuilder { /// Adds a tabstop snippet to place the cursor before `node` pub fn add_tabstop_before(&mut self, _cap: SnippetCap, node: impl AstNode) { assert!(node.syntax().parent().is_some()); - self.add_snippet(PlaceSnippet::Before(node.syntax().clone())); + self.add_snippet(PlaceSnippet::Before(node.syntax().clone().into())); } /// Adds a tabstop snippet to place the cursor after `node` pub fn add_tabstop_after(&mut self, _cap: SnippetCap, node: impl AstNode) { assert!(node.syntax().parent().is_some()); - self.add_snippet(PlaceSnippet::After(node.syntax().clone())); + self.add_snippet(PlaceSnippet::After(node.syntax().clone().into())); + } + + /// Adds a tabstop snippet to place the cursor before `token` + pub fn add_tabstop_before_token(&mut self, _cap: SnippetCap, token: SyntaxToken) { + assert!(token.parent().is_some()); + self.add_snippet(PlaceSnippet::Before(token.clone().into())); + } + + /// Adds a tabstop snippet to place the cursor after `token` + pub fn add_tabstop_after_token(&mut self, _cap: SnippetCap, token: SyntaxToken) { + assert!(token.parent().is_some()); + self.add_snippet(PlaceSnippet::After(token.clone().into())); } /// Adds a snippet to move the cursor selected over `node` pub fn add_placeholder_snippet(&mut self, _cap: SnippetCap, node: impl AstNode) { assert!(node.syntax().parent().is_some()); - self.add_snippet(PlaceSnippet::Over(node.syntax().clone())) + self.add_snippet(PlaceSnippet::Over(node.syntax().clone().into())) } fn add_snippet(&mut self, snippet: PlaceSnippet) { @@ -282,38 +297,40 @@ impl From for SourceChange { } enum PlaceSnippet { - /// Place a tabstop before a node - Before(SyntaxNode), - /// Place a tabstop before a node - After(SyntaxNode), - /// Place a placeholder snippet in place of the node - Over(SyntaxNode), + /// Place a tabstop before an element + Before(SyntaxElement), + /// Place a tabstop before an element + After(SyntaxElement), + /// Place a placeholder snippet in place of the element + Over(SyntaxElement), } impl PlaceSnippet { - /// Places the snippet before or over a node with the given tab stop index + /// Places the snippet before or over an element with the given tab stop index fn place(self, order: usize) { - // ensure the target node is still attached + // ensure the target element is still attached match &self { - PlaceSnippet::Before(node) | PlaceSnippet::After(node) | PlaceSnippet::Over(node) => { - // node should still be in the tree, but if it isn't + PlaceSnippet::Before(element) + | PlaceSnippet::After(element) + | PlaceSnippet::Over(element) => { + // element should still be in the tree, but if it isn't // then it's okay to just ignore this place - if stdx::never!(node.parent().is_none()) { + if stdx::never!(element.parent().is_none()) { return; } } } match self { - PlaceSnippet::Before(node) => { - ted::insert_raw(ted::Position::before(&node), Self::make_tab_stop(order)); + PlaceSnippet::Before(element) => { + ted::insert_raw(ted::Position::before(&element), Self::make_tab_stop(order)); } - PlaceSnippet::After(node) => { - ted::insert_raw(ted::Position::after(&node), Self::make_tab_stop(order)); + PlaceSnippet::After(element) => { + ted::insert_raw(ted::Position::after(&element), Self::make_tab_stop(order)); } - PlaceSnippet::Over(node) => { - let position = ted::Position::before(&node); - node.detach(); + PlaceSnippet::Over(element) => { + let position = ted::Position::before(&element); + element.detach(); let snippet = ast::SourceFile::parse(&format!("${{{order}:_}}")) .syntax_node() @@ -321,7 +338,7 @@ impl PlaceSnippet { let placeholder = snippet.descendants().find_map(ast::UnderscoreExpr::cast).unwrap(); - ted::replace(placeholder.syntax(), node); + ted::replace(placeholder.syntax(), element); ted::insert_raw(position, snippet); } From c0172333c2973add4c4a3575646733d31333df06 Mon Sep 17 00:00:00 2001 From: DropDemBits Date: Sat, 24 Jun 2023 21:20:13 -0400 Subject: [PATCH 190/324] add attr-related `make` functions --- crates/syntax/src/ast/make.rs | 37 +++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index 3facd90a11d9..4c6db0ef06cb 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs @@ -10,6 +10,8 @@ //! `parse(format!())` we use internally is an implementation detail -- long //! term, it will be replaced with direct tree manipulation. use itertools::Itertools; +use parser::T; +use rowan::NodeOrToken; use stdx::{format_to, never}; use crate::{ast, utils::is_raw_identifier, AstNode, SourceFile, SyntaxKind, SyntaxToken}; @@ -1030,6 +1032,41 @@ pub fn struct_( ast_from_text(&format!("{visibility}struct {strukt_name}{type_params}{field_list}{semicolon}",)) } +pub fn attr_outer(meta: ast::Meta) -> ast::Attr { + ast_from_text(&format!("#[{meta}]")) +} + +pub fn attr_inner(meta: ast::Meta) -> ast::Attr { + ast_from_text(&format!("#![{meta}]")) +} + +pub fn meta_expr(path: ast::Path, expr: ast::Expr) -> ast::Meta { + ast_from_text(&format!("#[{path} = {expr}]")) +} + +pub fn meta_token_tree(path: ast::Path, tt: ast::TokenTree) -> ast::Meta { + ast_from_text(&format!("#[{path}{tt}]")) +} + +pub fn meta_path(path: ast::Path) -> ast::Meta { + ast_from_text(&format!("#[{path}]")) +} + +pub fn token_tree( + delimiter: SyntaxKind, + tt: Vec>, +) -> ast::TokenTree { + let (l_delimiter, r_delimiter) = match delimiter { + T!['('] => ('(', ')'), + T!['['] => ('[', ']'), + T!['{'] => ('{', '}'), + _ => panic!("invalid delimiter `{delimiter:?}`"), + }; + let tt = tt.into_iter().join(""); + + ast_from_text(&format!("tt!{l_delimiter}{tt}{r_delimiter}")) +} + #[track_caller] fn ast_from_text(text: &str) -> N { let parse = SourceFile::parse(text); From 419f641d49beaf7db70aeea385dbfadc6283e906 Mon Sep 17 00:00:00 2001 From: DropDemBits Date: Sat, 24 Jun 2023 21:20:57 -0400 Subject: [PATCH 191/324] add `AttrsOwnerEdit::add_attr` --- crates/syntax/src/ast/edit_in_place.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs index 5919609d91ea..1f5ed206b4a9 100644 --- a/crates/syntax/src/ast/edit_in_place.rs +++ b/crates/syntax/src/ast/edit_in_place.rs @@ -213,6 +213,28 @@ pub trait AttrsOwnerEdit: ast::HasAttrs { } } } + + fn add_attr(&self, attr: ast::Attr) { + add_attr(self.syntax(), attr); + + fn add_attr(node: &SyntaxNode, attr: ast::Attr) { + let indent = IndentLevel::from_node(node); + attr.reindent_to(indent); + + let after_attrs_and_comments = node + .children_with_tokens() + .find(|it| !matches!(it.kind(), WHITESPACE | COMMENT | ATTR)) + .map_or(Position::first_child_of(node), |it| Position::before(it)); + + ted::insert_all( + after_attrs_and_comments, + vec![ + attr.syntax().clone().into(), + make::tokens::whitespace(&format!("\n{indent}")).into(), + ], + ) + } + } } impl AttrsOwnerEdit for T {} From 25088fca9d367acc8f124e3236beaae933a7364d Mon Sep 17 00:00:00 2001 From: DropDemBits Date: Sat, 24 Jun 2023 21:24:24 -0400 Subject: [PATCH 192/324] Migrate `generate_derive` to mutable ast --- .../src/handlers/generate_derive.rs | 74 ++++++++----------- 1 file changed, 31 insertions(+), 43 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_derive.rs b/crates/ide-assists/src/handlers/generate_derive.rs index 78ac2eb30e59..c8388e42370d 100644 --- a/crates/ide-assists/src/handlers/generate_derive.rs +++ b/crates/ide-assists/src/handlers/generate_derive.rs @@ -1,7 +1,6 @@ use syntax::{ - ast::{self, edit::IndentLevel, AstNode, HasAttrs}, - SyntaxKind::{COMMENT, WHITESPACE}, - TextSize, + ast::{self, edit_in_place::AttrsOwnerEdit, make, AstNode, HasAttrs}, + T, }; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -27,48 +26,37 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; pub(crate) fn generate_derive(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let cap = ctx.config.snippet_cap?; let nominal = ctx.find_node_at_offset::()?; - let node_start = derive_insertion_offset(&nominal)?; let target = nominal.syntax().text_range(); - acc.add( - AssistId("generate_derive", AssistKind::Generate), - "Add `#[derive]`", - target, - |builder| { - let derive_attr = nominal - .attrs() - .filter_map(|x| x.as_simple_call()) - .filter(|(name, _arg)| name == "derive") - .map(|(_name, arg)| arg) - .next(); - match derive_attr { - None => { - let indent_level = IndentLevel::from_node(nominal.syntax()); - builder.insert_snippet( - cap, - node_start, - format!("#[derive($0)]\n{indent_level}"), - ); - } - Some(tt) => { - // Just move the cursor. - builder.insert_snippet( - cap, - tt.syntax().text_range().end() - TextSize::of(')'), - "$0", - ) - } - }; - }, - ) -} + acc.add(AssistId("generate_derive", AssistKind::Generate), "Add `#[derive]`", target, |edit| { + let derive_attr = nominal + .attrs() + .filter_map(|x| x.as_simple_call()) + .filter(|(name, _arg)| name == "derive") + .map(|(_name, arg)| arg) + .next(); + match derive_attr { + None => { + let derive = make::attr_outer(make::meta_token_tree( + make::ext::ident_path("derive"), + make::token_tree(T!['('], vec![]).clone_for_update(), + )) + .clone_for_update(); -// Insert `derive` after doc comments. -fn derive_insertion_offset(nominal: &ast::Adt) -> Option { - let non_ws_child = nominal - .syntax() - .children_with_tokens() - .find(|it| it.kind() != COMMENT && it.kind() != WHITESPACE)?; - Some(non_ws_child.text_range().start()) + let nominal = edit.make_mut(nominal); + nominal.add_attr(derive.clone()); + + edit.add_tabstop_before_token( + cap, + derive.meta().unwrap().token_tree().unwrap().r_paren_token().unwrap(), + ); + } + Some(tt) => { + // Just move the cursor. + let tt = edit.make_mut(tt); + edit.add_tabstop_before_token(cap, tt.r_paren_token().unwrap()); + } + }; + }) } #[cfg(test)] From f8b6b4cc0b7d8e47dddf640c408dc3df02f5c88f Mon Sep 17 00:00:00 2001 From: DropDemBits Date: Sat, 24 Jun 2023 22:20:36 -0400 Subject: [PATCH 193/324] Migrate `wrap_return_type_in_result` to mutable ast --- .../handlers/wrap_return_type_in_result.rs | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/crates/ide-assists/src/handlers/wrap_return_type_in_result.rs b/crates/ide-assists/src/handlers/wrap_return_type_in_result.rs index b6c489eb62ee..24c3387457a3 100644 --- a/crates/ide-assists/src/handlers/wrap_return_type_in_result.rs +++ b/crates/ide-assists/src/handlers/wrap_return_type_in_result.rs @@ -6,7 +6,7 @@ use ide_db::{ }; use syntax::{ ast::{self, make, Expr}, - match_ast, AstNode, + match_ast, ted, AstNode, }; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -52,8 +52,8 @@ pub(crate) fn wrap_return_type_in_result(acc: &mut Assists, ctx: &AssistContext< AssistId("wrap_return_type_in_result", AssistKind::RefactorRewrite), "Wrap return type in Result", type_ref.syntax().text_range(), - |builder| { - let body = ast::Expr::BlockExpr(body); + |edit| { + let body = edit.make_mut(ast::Expr::BlockExpr(body)); let mut exprs_to_wrap = Vec::new(); let tail_cb = &mut |e: &_| tail_cb_impl(&mut exprs_to_wrap, e); @@ -70,17 +70,24 @@ pub(crate) fn wrap_return_type_in_result(acc: &mut Assists, ctx: &AssistContext< let ok_wrapped = make::expr_call( make::expr_path(make::ext::ident_path("Ok")), make::arg_list(iter::once(ret_expr_arg.clone())), - ); - builder.replace_ast(ret_expr_arg, ok_wrapped); + ) + .clone_for_update(); + ted::replace(ret_expr_arg.syntax(), ok_wrapped.syntax()); } - match ctx.config.snippet_cap { - Some(cap) => { - let snippet = format!("Result<{type_ref}, ${{0:_}}>"); - builder.replace_snippet(cap, type_ref.syntax().text_range(), snippet) - } - None => builder - .replace(type_ref.syntax().text_range(), format!("Result<{type_ref}, _>")), + let new_result_ty = + make::ext::ty_result(type_ref.clone(), make::ty_placeholder()).clone_for_update(); + let old_result_ty = edit.make_mut(type_ref.clone()); + + ted::replace(old_result_ty.syntax(), new_result_ty.syntax()); + + if let Some(cap) = ctx.config.snippet_cap { + let generic_args = new_result_ty + .syntax() + .descendants() + .find_map(ast::GenericArgList::cast) + .unwrap(); + edit.add_placeholder_snippet(cap, generic_args.generic_args().last().unwrap()); } }, ) From 58e2053327799313de2a5ccb4c50c57612993899 Mon Sep 17 00:00:00 2001 From: DropDemBits Date: Sun, 25 Jun 2023 00:06:30 -0400 Subject: [PATCH 194/324] Migrate `generate_delegate_methods` to mutable ast --- .../src/handlers/generate_delegate_methods.rs | 58 +++++++++---------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_delegate_methods.rs b/crates/ide-assists/src/handlers/generate_delegate_methods.rs index 1c2ec79809bd..bd21b7669a6b 100644 --- a/crates/ide-assists/src/handlers/generate_delegate_methods.rs +++ b/crates/ide-assists/src/handlers/generate_delegate_methods.rs @@ -1,13 +1,18 @@ use std::collections::HashSet; use hir::{self, HasCrate, HasSource, HasVisibility}; -use syntax::ast::{self, make, AstNode, HasGenericParams, HasName, HasVisibility as _}; +use syntax::{ + ast::{ + self, edit::IndentLevel, edit_in_place::Indent, make, AstNode, HasGenericParams, HasName, + HasVisibility as _, + }, + ted, +}; use crate::{ - utils::{convert_param_list_to_arg_list, find_struct_impl, render_snippet, Cursor}, + utils::{convert_param_list_to_arg_list, find_struct_impl}, AssistContext, AssistId, AssistKind, Assists, GroupLabel, }; -use syntax::ast::edit::AstNodeEdit; // Assist: generate_delegate_methods // @@ -96,7 +101,7 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' AssistId("generate_delegate_methods", AssistKind::Generate), format!("Generate delegate for `{field_name}.{name}()`",), target, - |builder| { + |edit| { // Create the function let method_source = match method.source(ctx.db()) { Some(source) => source.value, @@ -135,32 +140,25 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' is_const, is_unsafe, ) - .indent(ast::edit::IndentLevel(1)) .clone_for_update(); - - let cursor = Cursor::Before(f.syntax()); + f.reindent_to(IndentLevel(1)); // Create or update an impl block, attach the function to it, // then insert into our code. match impl_def { Some(impl_def) => { // Remember where in our source our `impl` block lives. - let impl_def = impl_def.clone_for_update(); - let old_range = impl_def.syntax().text_range(); + let impl_def = edit.make_mut(impl_def); - // Attach the function to the impl block + // Attach the function to the impl block. let assoc_items = impl_def.get_or_create_assoc_item_list(); assoc_items.add_item(f.clone().into()); // Update the impl block. - match ctx.config.snippet_cap { - Some(cap) => { - let snippet = render_snippet(cap, impl_def.syntax(), cursor); - builder.replace_snippet(cap, old_range, snippet); - } - None => { - builder.replace(old_range, impl_def.syntax().to_string()); - } + ted::replace(impl_def.syntax(), impl_def.syntax()); + + if let Some(cap) = ctx.config.snippet_cap { + edit.add_tabstop_before(cap, f); } } None => { @@ -178,22 +176,22 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' None, ) .clone_for_update(); + let assoc_items = impl_def.get_or_create_assoc_item_list(); assoc_items.add_item(f.clone().into()); // Insert the impl block. - match ctx.config.snippet_cap { - Some(cap) => { - let offset = strukt.syntax().text_range().end(); - let snippet = render_snippet(cap, impl_def.syntax(), cursor); - let snippet = format!("\n\n{snippet}"); - builder.insert_snippet(cap, offset, snippet); - } - None => { - let offset = strukt.syntax().text_range().end(); - let snippet = format!("\n\n{}", impl_def.syntax()); - builder.insert(offset, snippet); - } + let strukt = edit.make_mut(strukt.clone()); + ted::insert_all( + ted::Position::after(strukt.syntax()), + vec![ + make::tokens::blank_line().into(), + impl_def.syntax().clone().into(), + ], + ); + + if let Some(cap) = ctx.config.snippet_cap { + edit.add_tabstop_before(cap, f) } } } From 09a3bd58995079111dd59c0bd677521cceb28581 Mon Sep 17 00:00:00 2001 From: DropDemBits Date: Thu, 6 Jul 2023 21:43:34 -0400 Subject: [PATCH 195/324] Match indentation of generated delegate method --- .../src/handlers/generate_delegate_methods.rs | 96 ++++++++++++++++++- 1 file changed, 92 insertions(+), 4 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_delegate_methods.rs b/crates/ide-assists/src/handlers/generate_delegate_methods.rs index bd21b7669a6b..f0b9b01672a4 100644 --- a/crates/ide-assists/src/handlers/generate_delegate_methods.rs +++ b/crates/ide-assists/src/handlers/generate_delegate_methods.rs @@ -3,8 +3,7 @@ use std::collections::HashSet; use hir::{self, HasCrate, HasSource, HasVisibility}; use syntax::{ ast::{ - self, edit::IndentLevel, edit_in_place::Indent, make, AstNode, HasGenericParams, HasName, - HasVisibility as _, + self, edit_in_place::Indent, make, AstNode, HasGenericParams, HasName, HasVisibility as _, }, ted, }; @@ -141,7 +140,6 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' is_unsafe, ) .clone_for_update(); - f.reindent_to(IndentLevel(1)); // Create or update an impl block, attach the function to it, // then insert into our code. @@ -150,6 +148,9 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' // Remember where in our source our `impl` block lives. let impl_def = edit.make_mut(impl_def); + // Fixup function indentation. + f.reindent_to(impl_def.indent_level() + 1); + // Attach the function to the impl block. let assoc_items = impl_def.get_or_create_assoc_item_list(); assoc_items.add_item(f.clone().into()); @@ -177,15 +178,22 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' ) .clone_for_update(); + // Fixup function indentation. + f.reindent_to(impl_def.indent_level() + 1); + let assoc_items = impl_def.get_or_create_assoc_item_list(); assoc_items.add_item(f.clone().into()); + // Fixup impl_def indentation + let indent = strukt.indent_level(); + impl_def.reindent_to(indent); + // Insert the impl block. let strukt = edit.make_mut(strukt.clone()); ted::insert_all( ted::Position::after(strukt.syntax()), vec![ - make::tokens::blank_line().into(), + make::tokens::whitespace(&format!("\n\n{indent}")).into(), impl_def.syntax().clone().into(), ], ); @@ -242,6 +250,45 @@ impl Person { ); } + #[test] + fn test_generate_delegate_create_impl_block_match_indent() { + check_assist( + generate_delegate_methods, + r#" +mod indent { + struct Age(u8); + impl Age { + fn age(&self) -> u8 { + self.0 + } + } + + struct Person { + ag$0e: Age, + } +}"#, + r#" +mod indent { + struct Age(u8); + impl Age { + fn age(&self) -> u8 { + self.0 + } + } + + struct Person { + age: Age, + } + + impl Person { + $0fn age(&self) -> u8 { + self.age.age() + } + } +}"#, + ); + } + #[test] fn test_generate_delegate_update_impl_block() { check_assist( @@ -279,6 +326,47 @@ impl Person { ); } + #[test] + fn test_generate_delegate_update_impl_block_match_indent() { + check_assist( + generate_delegate_methods, + r#" +mod indent { + struct Age(u8); + impl Age { + fn age(&self) -> u8 { + self.0 + } + } + + struct Person { + ag$0e: Age, + } + + impl Person {} +}"#, + r#" +mod indent { + struct Age(u8); + impl Age { + fn age(&self) -> u8 { + self.0 + } + } + + struct Person { + age: Age, + } + + impl Person { + $0fn age(&self) -> u8 { + self.age.age() + } + } +}"#, + ); + } + #[test] fn test_generate_delegate_tuple_struct() { check_assist( From 2eb506462ef2baa7e6e63c0ef1ae7af1a998c750 Mon Sep 17 00:00:00 2001 From: DropDemBits Date: Thu, 6 Jul 2023 22:31:28 -0400 Subject: [PATCH 196/324] refactor: simplify `generate_delegate_method` Can actually split out adding the functions from getting the impl to update or create thanks to being able to refer to the impl ast node. FIXME Context: Unfortunately we can't adjust the indentation of the newly added function inside of `ast::AssocItemList::add_item` since for some reason the `todo!()` placeholder generated by `add_missing_impl_members` and `replace_derive_with_manual_impl` gets indented weirdly. --- .../src/handlers/generate_delegate_methods.rs | 46 ++++++------------- 1 file changed, 15 insertions(+), 31 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_delegate_methods.rs b/crates/ide-assists/src/handlers/generate_delegate_methods.rs index f0b9b01672a4..31fc69562c95 100644 --- a/crates/ide-assists/src/handlers/generate_delegate_methods.rs +++ b/crates/ide-assists/src/handlers/generate_delegate_methods.rs @@ -141,29 +141,10 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' ) .clone_for_update(); - // Create or update an impl block, attach the function to it, - // then insert into our code. - match impl_def { - Some(impl_def) => { - // Remember where in our source our `impl` block lives. - let impl_def = edit.make_mut(impl_def); - - // Fixup function indentation. - f.reindent_to(impl_def.indent_level() + 1); - - // Attach the function to the impl block. - let assoc_items = impl_def.get_or_create_assoc_item_list(); - assoc_items.add_item(f.clone().into()); - - // Update the impl block. - ted::replace(impl_def.syntax(), impl_def.syntax()); - - if let Some(cap) = ctx.config.snippet_cap { - edit.add_tabstop_before(cap, f); - } - } + // Get the impl to update, or create one if we need to. + let impl_def = match impl_def { + Some(impl_def) => edit.make_mut(impl_def), None => { - // Attach the function to the impl block let name = &strukt_name.to_string(); let params = strukt.generic_param_list(); let ty_params = params.clone(); @@ -178,12 +159,6 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' ) .clone_for_update(); - // Fixup function indentation. - f.reindent_to(impl_def.indent_level() + 1); - - let assoc_items = impl_def.get_or_create_assoc_item_list(); - assoc_items.add_item(f.clone().into()); - // Fixup impl_def indentation let indent = strukt.indent_level(); impl_def.reindent_to(indent); @@ -198,10 +173,19 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' ], ); - if let Some(cap) = ctx.config.snippet_cap { - edit.add_tabstop_before(cap, f) - } + impl_def } + }; + + // Fixup function indentation. + // FIXME: Should really be handled by `AssocItemList::add_item` + f.reindent_to(impl_def.indent_level() + 1); + + let assoc_items = impl_def.get_or_create_assoc_item_list(); + assoc_items.add_item(f.clone().into()); + + if let Some(cap) = ctx.config.snippet_cap { + edit.add_tabstop_before(cap, f) } }, )?; From cfa15d49aaff173a055617a347eda6f6caa9e915 Mon Sep 17 00:00:00 2001 From: Adenine Date: Sun, 18 Jun 2023 20:31:46 -0400 Subject: [PATCH 197/324] implement first pass of memory layout viewer --- crates/ide/src/lib.rs | 6 + crates/ide/src/view_memory_layout.rs | 170 +++++++++++ crates/rust-analyzer/src/handlers/request.rs | 28 ++ crates/rust-analyzer/src/lsp_ext.rs | 34 +++ crates/rust-analyzer/src/main_loop.rs | 1 + editors/code/package.json | 9 + editors/code/src/commands.ts | 283 +++++++++++++++++++ editors/code/src/lsp_ext.ts | 27 +- editors/code/src/main.ts | 9 +- 9 files changed, 561 insertions(+), 6 deletions(-) create mode 100644 crates/ide/src/view_memory_layout.rs diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index cb2a1140ba88..a9a8f6903b22 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -60,6 +60,7 @@ mod interpret_function; mod view_item_tree; mod shuffle_crate_graph; mod fetch_crates; +mod view_memory_layout; use std::ffi::OsStr; @@ -74,6 +75,7 @@ use ide_db::{ }; use syntax::SourceFile; use triomphe::Arc; +use view_memory_layout::{view_memory_layout, RecursiveMemoryLayout}; use crate::navigation_target::{ToNav, TryToNav}; @@ -724,6 +726,10 @@ impl Analysis { self.with_db(|db| move_item::move_item(db, range, direction)) } + pub fn get_recursive_memory_layout(&self, position: FilePosition) -> Cancellable> { + self.with_db(|db| view_memory_layout(db, position)) + } + /// Performs an operation on the database that may be canceled. /// /// rust-analyzer needs to be able to answer semantic questions about the diff --git a/crates/ide/src/view_memory_layout.rs b/crates/ide/src/view_memory_layout.rs new file mode 100644 index 000000000000..3b1b4968e777 --- /dev/null +++ b/crates/ide/src/view_memory_layout.rs @@ -0,0 +1,170 @@ +use hir::{Field, HirDisplay, Layout, Semantics, Type}; +use ide_db::{ + defs::{Definition, IdentClass}, + helpers::pick_best_token, + RootDatabase, +}; +use syntax::{AstNode, SyntaxKind, SyntaxToken}; + +use crate::FilePosition; + +pub struct MemoryLayoutNode { + pub item_name: String, + pub typename: String, + pub size: u64, + pub alignment: u64, + pub offset: u64, + pub parent_idx: i64, + pub children_start: i64, + pub children_len: u64, +} + +pub struct RecursiveMemoryLayout { + pub nodes: Vec, +} + +fn get_definition(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> Option { + for token in sema.descend_into_macros(token) { + let def = IdentClass::classify_token(sema, &token).map(IdentClass::definitions_no_ops); + if let Some(&[x]) = def.as_deref() { + return Some(x); + } + } + None +} + +pub(crate) fn view_memory_layout( + db: &RootDatabase, + position: FilePosition, +) -> Option { + let sema = Semantics::new(db); + let file = sema.parse(position.file_id); + let token = + pick_best_token(file.syntax().token_at_offset(position.offset), |kind| match kind { + SyntaxKind::IDENT => 3, + _ => 0, + })?; + + let def = get_definition(&sema, token)?; + + let ty = match def { + Definition::Adt(it) => it.ty(db), + Definition::TypeAlias(it) => it.ty(db), + Definition::BuiltinType(it) => it.ty(db), + Definition::SelfType(it) => it.self_ty(db), + Definition::Local(it) => it.ty(db), + _ => return None, + }; + + enum FieldOrTupleIdx { + Field(Field), + TupleIdx(usize), + } + + impl FieldOrTupleIdx { + fn name(&self, db: &RootDatabase) -> String { + match *self { + FieldOrTupleIdx::Field(f) => f + .name(db) + .as_str() + .map(|s| s.to_owned()) + .unwrap_or_else(|| format!("{:#?}", f.name(db).as_tuple_index().unwrap())), + FieldOrTupleIdx::TupleIdx(i) => format!(".{i}").to_owned(), + } + } + + fn index(&self) -> usize { + match *self { + FieldOrTupleIdx::Field(f) => f.index(), + FieldOrTupleIdx::TupleIdx(i) => i, + } + } + } + + fn read_layout( + nodes: &mut Vec, + db: &RootDatabase, + ty: &Type, + layout: &Layout, + parent_idx: usize, + ) { + let mut fields = ty + .fields(db) + .into_iter() + .map(|(f, ty)| (FieldOrTupleIdx::Field(f), ty)) + .chain( + ty.tuple_fields(db) + .into_iter() + .enumerate() + .map(|(i, ty)| (FieldOrTupleIdx::TupleIdx(i), ty)), + ) + .collect::>(); + + fields.sort_by_key(|(f, _)| layout.field_offset(f.index()).unwrap_or(u64::MAX)); + + if fields.len() == 0 { + return; + } + + let children_start = nodes.len(); + nodes[parent_idx].children_start = children_start as i64; + nodes[parent_idx].children_len = fields.len() as u64; + + for (field, child_ty) in fields.iter() { + if let Ok(child_layout) = child_ty.layout(db) { + nodes.push(MemoryLayoutNode { + item_name: field.name(db), + typename: child_ty.display(db).to_string(), + size: child_layout.size(), + alignment: child_layout.align(), + offset: layout.field_offset(field.index()).unwrap_or(0), + parent_idx: parent_idx as i64, + children_start: -1, + children_len: 0, + }); + } else { + nodes.push(MemoryLayoutNode { + item_name: field.name(db) + + format!("(no layout data: {:?})", child_ty.layout(db).unwrap_err()) + .as_ref(), + typename: child_ty.display(db).to_string(), + size: 0, + offset: 0, + alignment: 0, + parent_idx: parent_idx as i64, + children_start: -1, + children_len: 0, + }); + } + } + + for (i, (_, child_ty)) in fields.iter().enumerate() { + if let Ok(child_layout) = child_ty.layout(db) { + read_layout(nodes, db, &child_ty, &child_layout, children_start + i); + } + } + } + + ty.layout(db).map(|layout| { + let item_name = match def { + Definition::Local(l) => l.name(db).as_str().unwrap().to_owned(), + _ => "[ROOT]".to_owned(), + }; + + let typename = ty.display(db).to_string(); + + let mut nodes = vec![MemoryLayoutNode { + item_name, + typename: typename.clone(), + size: layout.size(), + offset: 0, + alignment: layout.align(), + parent_idx: -1, + children_start: -1, + children_len: 0, + }]; + read_layout(&mut nodes, db, &ty, &layout, 0); + + RecursiveMemoryLayout { nodes } + }) +} diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs index bb0c7ffa7289..2b901a601917 100644 --- a/crates/rust-analyzer/src/handlers/request.rs +++ b/crates/rust-analyzer/src/handlers/request.rs @@ -1689,6 +1689,34 @@ pub(crate) fn handle_move_item( } } +pub(crate) fn handle_view_recursive_memory_layout( + snap: GlobalStateSnapshot, + params: lsp_ext::ViewRecursiveMemoryLayoutParams, +) -> Result> { + let _p = profile::span("view_recursive_memory_layout"); + let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; + let line_index = snap.file_line_index(file_id)?; + let offset = from_proto::offset(&line_index, params.position)?; + + let res = snap.analysis.get_recursive_memory_layout(FilePosition { file_id, offset })?; + Ok(res.map(|it| lsp_ext::RecursiveMemoryLayout { + nodes: it + .nodes + .iter() + .map(|n| lsp_ext::MemoryLayoutNode { + item_name: n.item_name.clone(), + typename: n.typename.clone(), + size: n.size, + offset: n.offset, + alignment: n.alignment, + parent_idx: n.parent_idx, + children_start: n.children_start, + children_len: n.children_len, + }) + .collect(), + })) +} + fn to_command_link(command: lsp_types::Command, tooltip: String) -> lsp_ext::CommandLink { lsp_ext::CommandLink { tooltip: Some(tooltip), command } } diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index 4d67c8b305fe..39b8e840288f 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs @@ -182,6 +182,40 @@ pub struct ExpandedMacro { pub expansion: String, } +pub enum ViewRecursiveMemoryLayout {} + +impl Request for ViewRecursiveMemoryLayout { + type Params = ViewRecursiveMemoryLayoutParams; + type Result = Option; + const METHOD: &'static str = "rust-analyzer/viewRecursiveMemoryLayout"; +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct ViewRecursiveMemoryLayoutParams { + pub text_document: TextDocumentIdentifier, + pub position: Position, +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct RecursiveMemoryLayout { + pub nodes: Vec, +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct MemoryLayoutNode { + pub item_name: String, + pub typename: String, + pub size: u64, + pub offset: u64, + pub alignment: u64, + pub parent_idx: i64, + pub children_start: i64, + pub children_len: u64, +} + pub enum CancelFlycheck {} impl Notification for CancelFlycheck { diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 9eecf4957af4..74036710fa30 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -753,6 +753,7 @@ impl GlobalState { ) .on::(handlers::handle_will_rename_files) .on::(handlers::handle_ssr) + .on::(handlers::handle_view_recursive_memory_layout) .finish(); } diff --git a/editors/code/package.json b/editors/code/package.json index 1a1d76c69912..cd8b40e35575 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -284,6 +284,11 @@ "command": "rust-analyzer.revealDependency", "title": "Reveal File", "category": "rust-analyzer" + }, + { + "command": "rust-analyzer.viewMemoryLayout", + "title": "View Memory Layout", + "category": "rust-analyzer" } ], "keybindings": [ @@ -2067,6 +2072,10 @@ { "command": "rust-analyzer.openCargoToml", "when": "inRustProject" + }, + { + "command": "rust-analyzer.viewMemoryLayout", + "when": "inRustProject" } ], "editor/context": [ diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts index 3c6105e89fee..c0d68881c230 100644 --- a/editors/code/src/commands.ts +++ b/editors/code/src/commands.ts @@ -1129,3 +1129,286 @@ export function linkToCommand(_: Ctx): Cmd { } }; } + +export function viewMemoryLayout(ctx: CtxInit): Cmd { + return async () => { + + const editor = vscode.window.activeTextEditor; + if (!editor) return ""; + const client = ctx.client; + + const position = editor.selection.active; + const expanded = await client.sendRequest(ra.viewRecursiveMemoryLayout, { + textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier( + editor.document + ), + position, + }); + + // if (expanded == null) return "Not available"; + + + const document = vscode.window.createWebviewPanel( + "memory_layout", + "[Memory Layout]", + vscode.ViewColumn.Two, + { enableScripts: true, }); + + document.webview.html = ` + + + + + + Document + + + +
+ + +` + + ctx.pushExtCleanup(document); + }; +} diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts index b72804e510ce..4244098ae1d5 100644 --- a/editors/code/src/lsp_ext.ts +++ b/editors/code/src/lsp_ext.ts @@ -70,7 +70,7 @@ export const viewItemTree = new lc.RequestType export type AnalyzerStatusParams = { textDocument?: lc.TextDocumentIdentifier }; -export interface FetchDependencyListParams {} +export interface FetchDependencyListParams { } export interface FetchDependencyListResult { crates: { @@ -86,7 +86,7 @@ export const fetchDependencyList = new lc.RequestType< void >("rust-analyzer/fetchDependencyList"); -export interface FetchDependencyGraphParams {} +export interface FetchDependencyGraphParams { } export interface FetchDependencyGraphResult { crates: { @@ -150,6 +150,9 @@ export const serverStatus = new lc.NotificationType( "experimental/serverStatus" ); export const ssr = new lc.RequestType("experimental/ssr"); +export const viewRecursiveMemoryLayout = new lc.RequestType( + "rust-analyzer/viewRecursiveMemoryLayout" +); export type JoinLinesParams = { textDocument: lc.TextDocumentIdentifier; @@ -197,3 +200,23 @@ export type SsrParams = { position: lc.Position; selections: readonly lc.Range[]; }; + +export type ViewRecursiveMemoryLayoutParams = { + textDocument: lc.TextDocumentIdentifier; + position: lc.Position; +}; +export type RecursiveMemoryLayoutNode = { + item_name: string; + typename: string; + size: number; + alignment: number; + offset: number; + parent_idx: number; + children_start: number; + children_len: number; +}; +export type RecursiveMemoryLayout = { + name: string; + expansion: string; + nodes: RecursiveMemoryLayoutNode[]; +}; \ No newline at end of file diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index be9bc9d363ce..492275968f39 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts @@ -24,11 +24,11 @@ export async function activate( vscode.window .showWarningMessage( `You have both the rust-analyzer (rust-lang.rust-analyzer) and Rust (rust-lang.rust) ` + - "plugins enabled. These are known to conflict and cause various functions of " + - "both plugins to not work correctly. You should disable one of them.", + "plugins enabled. These are known to conflict and cause various functions of " + + "both plugins to not work correctly. You should disable one of them.", "Got it" ) - .then(() => {}, console.error); + .then(() => { }, console.error); } const ctx = new Ctx(context, createCommands(), fetchWorkspace()); @@ -144,7 +144,7 @@ function createCommands(): Record { health: "stopped", }); }, - disabled: (_) => async () => {}, + disabled: (_) => async () => { }, }, analyzerStatus: { enabled: commands.analyzerStatus }, @@ -179,6 +179,7 @@ function createCommands(): Record { runFlycheck: { enabled: commands.runFlycheck }, ssr: { enabled: commands.ssr }, serverVersion: { enabled: commands.serverVersion }, + viewMemoryLayout: { enabled: commands.viewMemoryLayout }, // Internal commands which are invoked by the server. applyActionGroup: { enabled: commands.applyActionGroup }, applySnippetWorkspaceEdit: { enabled: commands.applySnippetWorkspaceEditCommand }, From de5e3cf7459b955aa729bcbc6150655edf23e790 Mon Sep 17 00:00:00 2001 From: Adenine Date: Mon, 19 Jun 2023 00:24:42 -0400 Subject: [PATCH 198/324] fix incorrect committed rust and run prettier --- crates/ide/src/view_memory_layout.rs | 40 +++++++++++++++------------- editors/code/src/commands.ts | 11 +++----- editors/code/src/lsp_ext.ts | 14 +++++----- editors/code/src/main.ts | 8 +++--- 4 files changed, 37 insertions(+), 36 deletions(-) diff --git a/crates/ide/src/view_memory_layout.rs b/crates/ide/src/view_memory_layout.rs index 3b1b4968e777..9ed0d3f224ce 100644 --- a/crates/ide/src/view_memory_layout.rs +++ b/crates/ide/src/view_memory_layout.rs @@ -145,26 +145,28 @@ pub(crate) fn view_memory_layout( } } - ty.layout(db).map(|layout| { - let item_name = match def { - Definition::Local(l) => l.name(db).as_str().unwrap().to_owned(), - _ => "[ROOT]".to_owned(), - }; + ty.layout(db) + .map(|layout| { + let item_name = match def { + Definition::Local(l) => l.name(db).as_str().unwrap().to_owned(), + _ => "[ROOT]".to_owned(), + }; - let typename = ty.display(db).to_string(); + let typename = ty.display(db).to_string(); - let mut nodes = vec![MemoryLayoutNode { - item_name, - typename: typename.clone(), - size: layout.size(), - offset: 0, - alignment: layout.align(), - parent_idx: -1, - children_start: -1, - children_len: 0, - }]; - read_layout(&mut nodes, db, &ty, &layout, 0); + let mut nodes = vec![MemoryLayoutNode { + item_name, + typename: typename.clone(), + size: layout.size(), + offset: 0, + alignment: layout.align(), + parent_idx: -1, + children_start: -1, + children_len: 0, + }]; + read_layout(&mut nodes, db, &ty, &layout, 0); - RecursiveMemoryLayout { nodes } - }) + RecursiveMemoryLayout { nodes } + }) + .ok() } diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts index c0d68881c230..1e74158b8219 100644 --- a/editors/code/src/commands.ts +++ b/editors/code/src/commands.ts @@ -1132,27 +1132,24 @@ export function linkToCommand(_: Ctx): Cmd { export function viewMemoryLayout(ctx: CtxInit): Cmd { return async () => { - const editor = vscode.window.activeTextEditor; if (!editor) return ""; const client = ctx.client; const position = editor.selection.active; const expanded = await client.sendRequest(ra.viewRecursiveMemoryLayout, { - textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier( - editor.document - ), + textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document), position, }); // if (expanded == null) return "Not available"; - const document = vscode.window.createWebviewPanel( "memory_layout", "[Memory Layout]", vscode.ViewColumn.Two, - { enableScripts: true, }); + { enableScripts: true } + ); document.webview.html = ` @@ -1407,7 +1404,7 @@ locate() })() -` +`; ctx.pushExtCleanup(document); }; diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts index 4244098ae1d5..8a0c55a942fb 100644 --- a/editors/code/src/lsp_ext.ts +++ b/editors/code/src/lsp_ext.ts @@ -70,7 +70,7 @@ export const viewItemTree = new lc.RequestType export type AnalyzerStatusParams = { textDocument?: lc.TextDocumentIdentifier }; -export interface FetchDependencyListParams { } +export interface FetchDependencyListParams {} export interface FetchDependencyListResult { crates: { @@ -86,7 +86,7 @@ export const fetchDependencyList = new lc.RequestType< void >("rust-analyzer/fetchDependencyList"); -export interface FetchDependencyGraphParams { } +export interface FetchDependencyGraphParams {} export interface FetchDependencyGraphResult { crates: { @@ -150,9 +150,11 @@ export const serverStatus = new lc.NotificationType( "experimental/serverStatus" ); export const ssr = new lc.RequestType("experimental/ssr"); -export const viewRecursiveMemoryLayout = new lc.RequestType( - "rust-analyzer/viewRecursiveMemoryLayout" -); +export const viewRecursiveMemoryLayout = new lc.RequestType< + ViewRecursiveMemoryLayoutParams, + RecursiveMemoryLayout | null, + void +>("rust-analyzer/viewRecursiveMemoryLayout"); export type JoinLinesParams = { textDocument: lc.TextDocumentIdentifier; @@ -219,4 +221,4 @@ export type RecursiveMemoryLayout = { name: string; expansion: string; nodes: RecursiveMemoryLayoutNode[]; -}; \ No newline at end of file +}; diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index 492275968f39..64aea03394a6 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts @@ -24,11 +24,11 @@ export async function activate( vscode.window .showWarningMessage( `You have both the rust-analyzer (rust-lang.rust-analyzer) and Rust (rust-lang.rust) ` + - "plugins enabled. These are known to conflict and cause various functions of " + - "both plugins to not work correctly. You should disable one of them.", + "plugins enabled. These are known to conflict and cause various functions of " + + "both plugins to not work correctly. You should disable one of them.", "Got it" ) - .then(() => { }, console.error); + .then(() => {}, console.error); } const ctx = new Ctx(context, createCommands(), fetchWorkspace()); @@ -144,7 +144,7 @@ function createCommands(): Record { health: "stopped", }); }, - disabled: (_) => async () => { }, + disabled: (_) => async () => {}, }, analyzerStatus: { enabled: commands.analyzerStatus }, From c43cfefdd868c92f60d936e8958c0980428a0679 Mon Sep 17 00:00:00 2001 From: Adenine Date: Mon, 19 Jun 2023 00:27:53 -0400 Subject: [PATCH 199/324] fix typescript return path warning --- editors/code/src/commands.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts index 1e74158b8219..052e39182416 100644 --- a/editors/code/src/commands.ts +++ b/editors/code/src/commands.ts @@ -1133,7 +1133,7 @@ export function linkToCommand(_: Ctx): Cmd { export function viewMemoryLayout(ctx: CtxInit): Cmd { return async () => { const editor = vscode.window.activeTextEditor; - if (!editor) return ""; + if (!editor) return; const client = ctx.client; const position = editor.selection.active; From 4d5c66986ece98fb0015cbca5ee0de1f9870c800 Mon Sep 17 00:00:00 2001 From: Adenine Date: Fri, 7 Jul 2023 23:03:55 -0400 Subject: [PATCH 200/324] cleanup + docs + tests --- crates/ide-db/src/helpers.rs | 18 +- crates/ide/src/lib.rs | 5 +- crates/ide/src/static_index.rs | 17 +- crates/ide/src/view_memory_layout.rs | 281 +++++++++++++++++++++++---- docs/dev/lsp-extensions.md | 55 +++++- editors/code/src/commands.ts | 2 - editors/code/src/lsp_ext.ts | 2 - 7 files changed, 320 insertions(+), 60 deletions(-) diff --git a/crates/ide-db/src/helpers.rs b/crates/ide-db/src/helpers.rs index eba9d8afc40a..1eb8f00020b1 100644 --- a/crates/ide-db/src/helpers.rs +++ b/crates/ide-db/src/helpers.rs @@ -9,7 +9,10 @@ use syntax::{ AstToken, SyntaxKind, SyntaxToken, TokenAtOffset, }; -use crate::{defs::Definition, generated, RootDatabase}; +use crate::{ + defs::{Definition, IdentClass}, + generated, RootDatabase, +}; pub fn item_name(db: &RootDatabase, item: ItemInNs) -> Option { match item { @@ -109,3 +112,16 @@ pub fn is_editable_crate(krate: Crate, db: &RootDatabase) -> bool { let source_root_id = db.file_source_root(root_file); !db.source_root(source_root_id).is_library } + +pub fn get_definition( + sema: &Semantics<'_, RootDatabase>, + token: SyntaxToken, +) -> Option { + for token in sema.descend_into_macros(token) { + let def = IdentClass::classify_token(sema, &token).map(IdentClass::definitions_no_ops); + if let Some(&[x]) = def.as_deref() { + return Some(x); + } + } + None +} diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index a9a8f6903b22..0ad4c6c47e62 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -726,7 +726,10 @@ impl Analysis { self.with_db(|db| move_item::move_item(db, range, direction)) } - pub fn get_recursive_memory_layout(&self, position: FilePosition) -> Cancellable> { + pub fn get_recursive_memory_layout( + &self, + position: FilePosition, + ) -> Cancellable> { self.with_db(|db| view_memory_layout(db, position)) } diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs index 7101e8ed2037..59e8300dcdbe 100644 --- a/crates/ide/src/static_index.rs +++ b/crates/ide/src/static_index.rs @@ -3,13 +3,14 @@ use std::collections::HashMap; -use hir::{db::HirDatabase, Crate, Module, Semantics}; +use hir::{db::HirDatabase, Crate, Module}; +use ide_db::helpers::get_definition; use ide_db::{ base_db::{FileId, FileRange, SourceDatabaseExt}, - defs::{Definition, IdentClass}, + defs::Definition, FxHashSet, RootDatabase, }; -use syntax::{AstNode, SyntaxKind::*, SyntaxToken, TextRange, T}; +use syntax::{AstNode, SyntaxKind::*, TextRange, T}; use crate::{ hover::hover_for_definition, @@ -214,16 +215,6 @@ impl StaticIndex<'_> { } } -fn get_definition(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> Option { - for token in sema.descend_into_macros(token) { - let def = IdentClass::classify_token(sema, &token).map(IdentClass::definitions_no_ops); - if let Some(&[it]) = def.as_deref() { - return Some(it); - } - } - None -} - #[cfg(test)] mod tests { use crate::{fixture, StaticIndex}; diff --git a/crates/ide/src/view_memory_layout.rs b/crates/ide/src/view_memory_layout.rs index 9ed0d3f224ce..ae8dd504e3e0 100644 --- a/crates/ide/src/view_memory_layout.rs +++ b/crates/ide/src/view_memory_layout.rs @@ -1,10 +1,10 @@ use hir::{Field, HirDisplay, Layout, Semantics, Type}; use ide_db::{ - defs::{Definition, IdentClass}, - helpers::pick_best_token, + defs::Definition, + helpers::{get_definition, pick_best_token}, RootDatabase, }; -use syntax::{AstNode, SyntaxKind, SyntaxToken}; +use syntax::{AstNode, SyntaxKind}; use crate::FilePosition; @@ -23,16 +23,40 @@ pub struct RecursiveMemoryLayout { pub nodes: Vec, } -fn get_definition(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> Option { - for token in sema.descend_into_macros(token) { - let def = IdentClass::classify_token(sema, &token).map(IdentClass::definitions_no_ops); - if let Some(&[x]) = def.as_deref() { - return Some(x); - } - } - None +enum FieldOrTupleIdx { + Field(Field), + TupleIdx(usize), } +impl FieldOrTupleIdx { + fn name(&self, db: &RootDatabase) -> String { + match *self { + FieldOrTupleIdx::Field(f) => f + .name(db) + .as_str() + .map(|s| s.to_owned()) + .unwrap_or_else(|| format!(".{}", f.name(db).as_tuple_index().unwrap())), + FieldOrTupleIdx::TupleIdx(i) => format!(".{i}").to_owned(), + } + } + + fn index(&self) -> usize { + match *self { + FieldOrTupleIdx::Field(f) => f.index(), + FieldOrTupleIdx::TupleIdx(i) => i, + } + } +} + +// Feature: View Memory Layout +// +// Displays the recursive memory layout of a datatype. +// +// |=== +// | Editor | Action Name +// +// | VS Code | **rust-analyzer: View Memory Layout** +// |=== pub(crate) fn view_memory_layout( db: &RootDatabase, position: FilePosition, @@ -53,34 +77,12 @@ pub(crate) fn view_memory_layout( Definition::BuiltinType(it) => it.ty(db), Definition::SelfType(it) => it.self_ty(db), Definition::Local(it) => it.ty(db), + Definition::Field(it) => it.ty(db), + Definition::Const(it) => it.ty(db), + Definition::Static(it) => it.ty(db), _ => return None, }; - enum FieldOrTupleIdx { - Field(Field), - TupleIdx(usize), - } - - impl FieldOrTupleIdx { - fn name(&self, db: &RootDatabase) -> String { - match *self { - FieldOrTupleIdx::Field(f) => f - .name(db) - .as_str() - .map(|s| s.to_owned()) - .unwrap_or_else(|| format!("{:#?}", f.name(db).as_tuple_index().unwrap())), - FieldOrTupleIdx::TupleIdx(i) => format!(".{i}").to_owned(), - } - } - - fn index(&self) -> usize { - match *self { - FieldOrTupleIdx::Field(f) => f.index(), - FieldOrTupleIdx::TupleIdx(i) => i, - } - } - } - fn read_layout( nodes: &mut Vec, db: &RootDatabase, @@ -100,12 +102,12 @@ pub(crate) fn view_memory_layout( ) .collect::>(); - fields.sort_by_key(|(f, _)| layout.field_offset(f.index()).unwrap_or(u64::MAX)); - if fields.len() == 0 { return; } + fields.sort_by_key(|(f, _)| layout.field_offset(f.index()).unwrap()); + let children_start = nodes.len(); nodes[parent_idx].children_start = children_start as i64; nodes[parent_idx].children_len = fields.len() as u64; @@ -148,8 +150,21 @@ pub(crate) fn view_memory_layout( ty.layout(db) .map(|layout| { let item_name = match def { - Definition::Local(l) => l.name(db).as_str().unwrap().to_owned(), - _ => "[ROOT]".to_owned(), + // def is a datatype + Definition::Adt(_) + | Definition::TypeAlias(_) + | Definition::BuiltinType(_) + | Definition::SelfType(_) => "[ROOT]".to_owned(), + + // def is an item + def => def + .name(db) + .map(|n| { + n.as_str() + .map(|s| s.to_owned()) + .unwrap_or_else(|| format!(".{}", n.as_tuple_index().unwrap())) + }) + .unwrap_or("[ROOT]".to_owned()), }; let typename = ty.display(db).to_string(); @@ -170,3 +185,189 @@ pub(crate) fn view_memory_layout( }) .ok() } + +#[cfg(test)] +mod tests { + use super::*; + + use crate::fixture; + + fn make_memory_layout(ra_fixture: &str) -> Option { + let (analysis, position, _) = fixture::annotations(ra_fixture); + + view_memory_layout(&analysis.db, position) + } + + fn check_item_info(node: &MemoryLayoutNode, item_name: &str, check_typename: bool) { + assert_eq!(node.item_name, item_name); + assert_eq!(node.size, core::mem::size_of::() as u64); + assert_eq!(node.alignment, core::mem::align_of::() as u64); + if check_typename { + assert_eq!(node.typename, std::any::type_name::()); + } + } + + #[test] + fn view_memory_layout_none() { + assert!(make_memory_layout(r#"$0"#).is_none()); + assert!(make_memory_layout(r#"stru$0ct Blah {}"#).is_none()); + } + + #[test] + fn view_memory_layout_primitive() { + let ml = make_memory_layout( + r#" +fn main() { + let foo$0 = 109; // default i32 +} +"#, + ) + .unwrap(); + + assert_eq!(ml.nodes.len(), 1); + assert_eq!(ml.nodes[0].parent_idx, -1); + assert_eq!(ml.nodes[0].children_start, -1); + check_item_info::(&ml.nodes[0], "foo", true); + assert_eq!(ml.nodes[0].offset, 0); + } + + #[test] + fn view_memory_layout_constant() { + let ml = make_memory_layout( + r#" +const BLAH$0: bool = 0; +"#, + ) + .unwrap(); + + assert_eq!(ml.nodes.len(), 1); + assert_eq!(ml.nodes[0].parent_idx, -1); + assert_eq!(ml.nodes[0].children_start, -1); + check_item_info::(&ml.nodes[0], "BLAH", true); + assert_eq!(ml.nodes[0].offset, 0); + } + + #[test] + fn view_memory_layout_static() { + let ml = make_memory_layout( + r#" +static BLAH$0: bool = 0; +"#, + ) + .unwrap(); + + assert_eq!(ml.nodes.len(), 1); + assert_eq!(ml.nodes[0].parent_idx, -1); + assert_eq!(ml.nodes[0].children_start, -1); + check_item_info::(&ml.nodes[0], "BLAH", true); + assert_eq!(ml.nodes[0].offset, 0); + } + + #[test] + fn view_memory_layout_tuple() { + let ml = make_memory_layout( + r#" +fn main() { + let x$0 = (101.0, 111u8, 119i64); +} + "#, + ) + .unwrap(); + + assert_eq!(ml.nodes.len(), 4); + assert_eq!(ml.nodes[0].children_start, 1); + assert_eq!(ml.nodes[0].children_len, 3); + check_item_info::<(f64, u8, i64)>(&ml.nodes[0], "x", true); + } + + #[test] + fn view_memory_layout_struct() { + let ml = make_memory_layout( + r#" +#[repr(C)] +struct Blah$0 { + a: u32, + b: (i32, u8), + c: i8, +} +"#, + ) + .unwrap(); + + #[repr(C)] // repr C makes this testable, rustc doesn't enforce a layout otherwise ;-; + struct Blah { + a: u32, + b: (i32, u8), + c: i8, + } + + assert_eq!(ml.nodes.len(), 6); + check_item_info::(&ml.nodes[0], "[ROOT]", false); + assert_eq!(ml.nodes[0].offset, 0); + + check_item_info::(&ml.nodes[1], "a", true); + assert_eq!(ml.nodes[1].offset, 0); + + check_item_info::<(i32, u8)>(&ml.nodes[2], "b", true); + assert_eq!(ml.nodes[2].offset, 4); + + check_item_info::(&ml.nodes[3], "c", true); + assert_eq!(ml.nodes[3].offset, 12); + } + + #[test] + fn view_memory_layout_member() { + let ml = make_memory_layout( + r#" +struct Oof { + a$0: bool +} +"#, + ) + .unwrap(); + + assert_eq!(ml.nodes.len(), 1); + assert_eq!(ml.nodes[0].parent_idx, -1); + assert_eq!(ml.nodes[0].children_start, -1); + check_item_info::(&ml.nodes[0], "a", true); + // NOTE: this should not give the memory layout relative to the parent structure, but the type referred to by the member variable alone. + assert_eq!(ml.nodes[0].offset, 0); + } + + #[test] + fn view_memory_layout_alias() { + let ml_a = make_memory_layout( + r#" +struct X { + a: u32, + b: i8, + c: (f32, f32), +} + +type Foo$0 = X; + "#, + ) + .unwrap(); + let ml_b = make_memory_layout( + r#" +struct X$0 { + a: u32, + b: i8, + c: (f32, f32), +} + "#, + ) + .unwrap(); + + ml_a.nodes.iter().zip(ml_b.nodes.iter()).for_each(|(a, b)| { + assert_eq!(a.item_name, b.item_name); + assert_eq!(a.typename, b.typename); + assert_eq!(a.size, b.size); + assert_eq!(a.alignment, b.alignment); + assert_eq!(a.offset, b.offset); + assert_eq!(a.parent_idx, b.parent_idx); + assert_eq!(a.children_start, b.children_start); + assert_eq!(a.children_len, b.children_len); + }) + } +} diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md index bc58aa7220dc..8655e9546750 100644 --- a/docs/dev/lsp-extensions.md +++ b/docs/dev/lsp-extensions.md @@ -1,5 +1,5 @@ $DIR/to_string_in_format_args_incremental.rs:8:21 - | -LL | println!("{}", s.to_string()); - | ^^^^^^^^^^^^ help: remove this - | - = note: `-D clippy::to-string-in-format-args` implied by `-D warnings` - -error: aborting due to previous error - From 1dd54eb44ad7eacd450ad81a14ec35cadc15f856 Mon Sep 17 00:00:00 2001 From: Adenine Date: Sat, 8 Jul 2023 12:25:54 -0400 Subject: [PATCH 206/324] change viewMemoryLayoutParams to be textPositionParams --- crates/rust-analyzer/src/handlers/request.rs | 2 +- crates/rust-analyzer/src/lsp_ext.rs | 9 +-------- docs/dev/lsp-extensions.md | 14 +++----------- editors/code/src/lsp_ext.ts | 6 +----- 4 files changed, 6 insertions(+), 25 deletions(-) diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs index b191d8d36840..aad74b7466a2 100644 --- a/crates/rust-analyzer/src/handlers/request.rs +++ b/crates/rust-analyzer/src/handlers/request.rs @@ -1691,7 +1691,7 @@ pub(crate) fn handle_move_item( pub(crate) fn handle_view_recursive_memory_layout( snap: GlobalStateSnapshot, - params: lsp_ext::ViewRecursiveMemoryLayoutParams, + params: lsp_types::TextDocumentPositionParams, ) -> anyhow::Result> { let _p = profile::span("view_recursive_memory_layout"); let file_id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index 39b8e840288f..d0989b3230dc 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs @@ -185,18 +185,11 @@ pub struct ExpandedMacro { pub enum ViewRecursiveMemoryLayout {} impl Request for ViewRecursiveMemoryLayout { - type Params = ViewRecursiveMemoryLayoutParams; + type Params = lsp_types::TextDocumentPositionParams; type Result = Option; const METHOD: &'static str = "rust-analyzer/viewRecursiveMemoryLayout"; } -#[derive(Deserialize, Serialize, Debug)] -#[serde(rename_all = "camelCase")] -pub struct ViewRecursiveMemoryLayoutParams { - pub text_document: TextDocumentIdentifier, - pub position: Position, -} - #[derive(Deserialize, Serialize, Debug)] #[serde(rename_all = "camelCase")] pub struct RecursiveMemoryLayout { diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md index 8655e9546750..024acb877097 100644 --- a/docs/dev/lsp-extensions.md +++ b/docs/dev/lsp-extensions.md @@ -1,5 +1,5 @@ $DIR/manual_partial_ord_impl.rs:18:1 + | +LL | / impl PartialOrd for A { +LL | | fn partial_cmp(&self, other: &Self) -> Option { + | | _____________________________________________________________- +LL | || todo!(); +LL | || } + | ||_____- help: change this to: `{ Some(self.cmp(other)) }` +LL | | } + | |__^ + | + = note: `-D clippy::manual-partial-ord-impl` implied by `-D warnings` + +error: manual implementation of `PartialOrd` when `Ord` is already implemented + --> $DIR/manual_partial_ord_impl.rs:52:1 + | +LL | / impl PartialOrd for C { +LL | | fn partial_cmp(&self, _: &Self) -> Option { +LL | | todo!(); +LL | | } +LL | | } + | |_^ + | + = help: return the value of `self.cmp` wrapped in `Some` instead + +error: aborting due to 2 previous errors + From 004e89d4cfde749e9cb33d5ac26bdbe3001a1f3d Mon Sep 17 00:00:00 2001 From: Centri3 <114838443+Centri3@users.noreply.github.com> Date: Mon, 15 May 2023 18:41:41 -0500 Subject: [PATCH 209/324] rename to `manual_partial_ord_and_ord_impl` cargo dev fmt cargo test passes cargo test passes refactor a lil Update bool_comparison.stderr heavily refactor + bump `clippy::version` refactor refactor check bounds to increase accuracy, and add todos --- CHANGELOG.md | 2 +- clippy_lints/src/declared_lints.rs | 2 +- clippy_lints/src/lib.rs | 2 +- clippy_lints/src/manual_partial_ord_impl.rs | 132 ---------------- clippy_lints/src/needless_impls.rs | 145 ++++++++++++++++++ tests/ui/bool_comparison.fixed | 1 + tests/ui/bool_comparison.rs | 1 + tests/ui/bool_comparison.stderr | 44 +++--- tests/ui/derive_ord_xor_partial_ord.rs | 1 + tests/ui/derive_ord_xor_partial_ord.stderr | 16 +- tests/ui/manual_partial_ord_impl.stderr | 28 ---- tests/ui/needless_partial_ord_impl.fixed | 85 ++++++++++ ...d_impl.rs => needless_partial_ord_impl.rs} | 36 ++++- tests/ui/needless_partial_ord_impl.stderr | 28 ++++ 14 files changed, 328 insertions(+), 195 deletions(-) delete mode 100644 clippy_lints/src/manual_partial_ord_impl.rs create mode 100644 clippy_lints/src/needless_impls.rs delete mode 100644 tests/ui/manual_partial_ord_impl.stderr create mode 100644 tests/ui/needless_partial_ord_impl.fixed rename tests/ui/{manual_partial_ord_impl.rs => needless_partial_ord_impl.rs} (52%) create mode 100644 tests/ui/needless_partial_ord_impl.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 840a46aa83a8..fea11bba63f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4921,7 +4921,6 @@ Released 2018-09-13 [`manual_next_back`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_next_back [`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive [`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or -[`manual_partial_ord_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_partial_ord_impl [`manual_range_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains [`manual_range_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_patterns [`manual_rem_euclid`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_rem_euclid @@ -5021,6 +5020,7 @@ Released 2018-09-13 [`needless_option_as_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_option_as_deref [`needless_option_take`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_option_take [`needless_parens_on_range_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_parens_on_range_literals +[`needless_partial_ord_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_partial_ord_impl [`needless_pass_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_value [`needless_pub_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_pub_self [`needless_question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_question_mark diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 7764dd7391fe..a2231b8fb1db 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -277,7 +277,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::manual_let_else::MANUAL_LET_ELSE_INFO, crate::manual_main_separator_str::MANUAL_MAIN_SEPARATOR_STR_INFO, crate::manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE_INFO, - crate::manual_partial_ord_impl::MANUAL_PARTIAL_ORD_IMPL_INFO, crate::manual_range_patterns::MANUAL_RANGE_PATTERNS_INFO, crate::manual_rem_euclid::MANUAL_REM_EUCLID_INFO, crate::manual_retain::MANUAL_RETAIN_INFO, @@ -470,6 +469,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::needless_else::NEEDLESS_ELSE_INFO, crate::needless_for_each::NEEDLESS_FOR_EACH_INFO, crate::needless_if::NEEDLESS_IF_INFO, + crate::needless_impls::NEEDLESS_PARTIAL_ORD_IMPL_INFO, crate::needless_late_init::NEEDLESS_LATE_INIT_INFO, crate::needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS_INFO, crate::needless_pass_by_value::NEEDLESS_PASS_BY_VALUE_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 36a0cf860d72..1ec5b2e8b0aa 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -188,7 +188,6 @@ mod manual_is_ascii_check; mod manual_let_else; mod manual_main_separator_str; mod manual_non_exhaustive; -mod manual_partial_ord_impl; mod manual_range_patterns; mod manual_rem_euclid; mod manual_retain; @@ -228,6 +227,7 @@ mod needless_continue; mod needless_else; mod needless_for_each; mod needless_if; +mod needless_impls; mod needless_late_init; mod needless_parens_on_range_literals; mod needless_pass_by_value; diff --git a/clippy_lints/src/manual_partial_ord_impl.rs b/clippy_lints/src/manual_partial_ord_impl.rs deleted file mode 100644 index 4c43b5e52e85..000000000000 --- a/clippy_lints/src/manual_partial_ord_impl.rs +++ /dev/null @@ -1,132 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::{ - def_path_def_ids, diagnostics::span_lint_and_sugg, get_trait_def_id, match_def_path, path_res, ty::implements_trait, -}; -use rustc_errors::Applicability; -use rustc_hir::def::Res; -use rustc_hir::*; -use rustc_hir_analysis::hir_ty_to_ty; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::def_id::DefId; -use std::cell::OnceCell; - -declare_clippy_lint! { - /// ### What it does - /// Checks for manual implementations of both `PartialOrd` and `Ord` when only `Ord` is - /// necessary. - /// - /// ### Why is this bad? - /// If both `PartialOrd` and `Ord` are implemented, `PartialOrd` will wrap the returned value of - /// `Ord::cmp` in `Some`. Not doing this may silently introduce an error. - /// - /// ### Example - /// ```rust - /// #[derive(Eq, PartialEq)] - /// struct A(u32); - /// - /// impl Ord for A { - /// fn cmp(&self, other: &Self) -> Ordering { - /// todo!(); - /// } - /// } - /// - /// impl PartialOrd for A { - /// fn partial_cmp(&self, other: &Self) -> Option { - /// todo!(); - /// } - /// } - /// ``` - /// Use instead: - /// ```rust - /// #[derive(Eq, PartialEq)] - /// struct A(u32); - /// - /// impl Ord for A { - /// fn cmp(&self, other: &Self) -> Ordering { - /// todo!(); - /// } - /// } - /// - /// impl PartialOrd for A { - /// fn partial_cmp(&self, other: &Self) -> Option { - /// Some(self.cmp(other)) - /// } - /// } - /// ``` - #[clippy::version = "1.71.0"] - pub MANUAL_PARTIAL_ORD_IMPL, - nursery, - "default lint description" -} -impl_lint_pass!(ManualPartialOrdImpl => [MANUAL_PARTIAL_ORD_IMPL]); - -#[derive(Clone)] -pub struct ManualPartialOrdImpl { - pub ord_def_id: OnceCell, -} - -impl LateLintPass<'_> for ManualPartialOrdImpl { - fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { - if_chain! { - if let ItemKind::Impl(imp) = &item.kind; - if let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id); - if cx.tcx.is_diagnostic_item(sym!(PartialOrd), impl_trait_ref.skip_binder().def_id); - then { - lint_impl_body(self, cx, imp, item); - } - } - } -} - -fn lint_impl_body(conf: &mut ManualPartialOrdImpl, cx: &LateContext<'_>, imp: &Impl<'_>, item: &Item<'_>) { - for imp_item in imp.items { - if_chain! { - if imp_item.ident.name == sym!(partial_cmp); - if let ImplItemKind::Fn(_, id) = cx.tcx.hir().impl_item(imp_item.id).kind; - then { - let body = cx.tcx.hir().body(id); - let ord_def_id = conf.ord_def_id.get_or_init(|| get_trait_def_id(cx, &["core", "cmp", "Ord"]).unwrap()); - if let ExprKind::Block(block, ..) - = body.value.kind && implements_trait(cx, hir_ty_to_ty(cx.tcx, imp.self_ty), *ord_def_id, &[]) - { - if_chain! { - if block.stmts.is_empty(); - if let Some(expr) = block.expr; - if let ExprKind::Call(Expr { kind: ExprKind::Path(path), ..}, [cmp_expr]) = expr.kind; - if let QPath::Resolved(_, some_path) = path; - if let Some(some_seg_one) = some_path.segments.get(0); - if some_seg_one.ident.name == sym!(Some); - if let ExprKind::MethodCall(cmp_path, _, [other_expr], ..) = cmp_expr.kind; - if cmp_path.ident.name == sym!(cmp); - if let Res::Local(..) = path_res(cx, other_expr); - then {} - else { - span_lint_and_then( - cx, - MANUAL_PARTIAL_ORD_IMPL, - item.span, - "manual implementation of `PartialOrd` when `Ord` is already implemented", - |diag| { - if let Some(param) = body.params.get(1) - && let PatKind::Binding(_, _, param_ident, ..) = param.pat.kind - { - diag.span_suggestion( - block.span, - "change this to", - format!("{{ Some(self.cmp({})) }}", - param_ident.name), - Applicability::MaybeIncorrect - ); - } else { - diag.help("return the value of `self.cmp` wrapped in `Some` instead"); - }; - } - ); - } - } - } - } - } - } -} diff --git a/clippy_lints/src/needless_impls.rs b/clippy_lints/src/needless_impls.rs new file mode 100644 index 000000000000..4f8741bf3708 --- /dev/null +++ b/clippy_lints/src/needless_impls.rs @@ -0,0 +1,145 @@ +use clippy_utils::{ + diagnostics::span_lint_and_then, get_parent_node, is_res_lang_ctor, path_res, ty::implements_trait, +}; +use rustc_errors::Applicability; +use rustc_hir::{def::Res, Expr, ExprKind, ImplItem, ImplItemKind, ItemKind, LangItem, Node, PatKind}; +use rustc_hir_analysis::hir_ty_to_ty; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::EarlyBinder; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; +use std::borrow::Cow; + +declare_clippy_lint! { + /// ### What it does + /// Checks for manual implementations of both `PartialOrd` and `Ord` when only `Ord` is + /// necessary. + /// + /// ### Why is this bad? + /// If both `PartialOrd` and `Ord` are implemented, they must agree. This is commonly done by + /// wrapping the result of `cmp` in `Some` for `partial_cmp`. Not doing this may silently + /// introduce an error upon refactoring. + /// + /// ### Example + /// ```rust,ignore + /// #[derive(Eq, PartialEq)] + /// struct A(u32); + /// + /// impl Ord for A { + /// fn cmp(&self, other: &Self) -> Ordering { + /// todo!(); + /// } + /// } + /// + /// impl PartialOrd for A { + /// fn partial_cmp(&self, other: &Self) -> Option { + /// todo!(); + /// } + /// } + /// ``` + /// Use instead: + /// ```rust,ignore + /// #[derive(Eq, PartialEq)] + /// struct A(u32); + /// + /// impl Ord for A { + /// fn cmp(&self, other: &Self) -> Ordering { + /// todo!(); + /// } + /// } + /// + /// impl PartialOrd for A { + /// fn partial_cmp(&self, other: &Self) -> Option { + /// Some(self.cmp(other)) + /// } + /// } + /// ``` + #[clippy::version = "1.72.0"] + pub NEEDLESS_PARTIAL_ORD_IMPL, + correctness, + "manual implementation of `PartialOrd` when `Ord` is already implemented" +} +declare_lint_pass!(NeedlessImpls => [NEEDLESS_PARTIAL_ORD_IMPL]); + +impl LateLintPass<'_> for NeedlessImpls { + fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &ImplItem<'_>) { + let node = get_parent_node(cx.tcx, impl_item.hir_id()); + let Some(Node::Item(item)) = node else { + return; + }; + let ItemKind::Impl(imp) = item.kind else { + return; + }; + let Some(trait_impl) = cx.tcx.impl_trait_ref(item.owner_id).map(EarlyBinder::skip_binder) else { + return; + }; + let trait_impl_def_id = trait_impl.def_id; + if cx.tcx.is_automatically_derived(item.owner_id.to_def_id()) { + return; + } + let ImplItemKind::Fn(_, impl_item_id) = cx.tcx.hir().impl_item(impl_item.impl_item_id()).kind else { + return; + }; + let body = cx.tcx.hir().body(impl_item_id); + let ExprKind::Block(block, ..) = body.value.kind else { + return; + }; + + if cx.tcx.is_diagnostic_item(sym::PartialOrd, trait_impl_def_id) + && impl_item.ident.name == sym::partial_cmp + && let Some(ord_def_id) = cx + .tcx + .diagnostic_items(trait_impl.def_id.krate) + .name_to_id + .get(&sym::Ord) + && implements_trait( + cx, + hir_ty_to_ty(cx.tcx, imp.self_ty), + *ord_def_id, + trait_impl.substs, + ) + { + if block.stmts.is_empty() + && let Some(expr) = block.expr + && let ExprKind::Call( + Expr { + kind: ExprKind::Path(some_path), + hir_id: some_hir_id, + .. + }, + [cmp_expr], + ) = expr.kind + && is_res_lang_ctor(cx, cx.qpath_res(some_path, *some_hir_id), LangItem::OptionSome) + && let ExprKind::MethodCall(cmp_path, _, [other_expr], ..) = cmp_expr.kind + && cmp_path.ident.name == sym::cmp + && let Res::Local(..) = path_res(cx, other_expr) + {} else { + span_lint_and_then( + cx, + NEEDLESS_PARTIAL_ORD_IMPL, + item.span, + "manual implementation of `PartialOrd` when `Ord` is already implemented", + |diag| { + let (help, app) = if let Some(other) = body.params.get(0) + && let PatKind::Binding(_, _, other_ident, ..) = other.pat.kind + { + ( + Cow::Owned(format!("{{ Some(self.cmp({})) }}", other_ident.name)), + Applicability::Unspecified, + ) + } else { + (Cow::Borrowed("{ Some(self.cmp(...)) }"), Applicability::HasPlaceholders) + }; + + diag.span_suggestion( + block.span, + "change this to", + help, + app, + ); + } + ); + } + } + } +} diff --git a/tests/ui/bool_comparison.fixed b/tests/ui/bool_comparison.fixed index d6774c035984..33221c7777ea 100644 --- a/tests/ui/bool_comparison.fixed +++ b/tests/ui/bool_comparison.fixed @@ -2,6 +2,7 @@ #![allow(clippy::needless_if)] #![warn(clippy::bool_comparison)] +#![allow(clippy::needless_partial_ord_impl)] fn main() { let x = true; diff --git a/tests/ui/bool_comparison.rs b/tests/ui/bool_comparison.rs index c0483fd73748..5f909bd2a53f 100644 --- a/tests/ui/bool_comparison.rs +++ b/tests/ui/bool_comparison.rs @@ -2,6 +2,7 @@ #![allow(clippy::needless_if)] #![warn(clippy::bool_comparison)] +#![allow(clippy::needless_partial_ord_impl)] fn main() { let x = true; diff --git a/tests/ui/bool_comparison.stderr b/tests/ui/bool_comparison.stderr index f4dded365fba..19bdf3013580 100644 --- a/tests/ui/bool_comparison.stderr +++ b/tests/ui/bool_comparison.stderr @@ -1,5 +1,5 @@ error: equality checks against true are unnecessary - --> $DIR/bool_comparison.rs:8:8 + --> $DIR/bool_comparison.rs:9:8 | LL | if x == true { | ^^^^^^^^^ help: try simplifying it as shown: `x` @@ -7,127 +7,127 @@ LL | if x == true { = note: `-D clippy::bool-comparison` implied by `-D warnings` error: equality checks against false can be replaced by a negation - --> $DIR/bool_comparison.rs:13:8 + --> $DIR/bool_comparison.rs:14:8 | LL | if x == false { | ^^^^^^^^^^ help: try simplifying it as shown: `!x` error: equality checks against true are unnecessary - --> $DIR/bool_comparison.rs:18:8 + --> $DIR/bool_comparison.rs:19:8 | LL | if true == x { | ^^^^^^^^^ help: try simplifying it as shown: `x` error: equality checks against false can be replaced by a negation - --> $DIR/bool_comparison.rs:23:8 + --> $DIR/bool_comparison.rs:24:8 | LL | if false == x { | ^^^^^^^^^^ help: try simplifying it as shown: `!x` error: inequality checks against true can be replaced by a negation - --> $DIR/bool_comparison.rs:28:8 + --> $DIR/bool_comparison.rs:29:8 | LL | if x != true { | ^^^^^^^^^ help: try simplifying it as shown: `!x` error: inequality checks against false are unnecessary - --> $DIR/bool_comparison.rs:33:8 + --> $DIR/bool_comparison.rs:34:8 | LL | if x != false { | ^^^^^^^^^^ help: try simplifying it as shown: `x` error: inequality checks against true can be replaced by a negation - --> $DIR/bool_comparison.rs:38:8 + --> $DIR/bool_comparison.rs:39:8 | LL | if true != x { | ^^^^^^^^^ help: try simplifying it as shown: `!x` error: inequality checks against false are unnecessary - --> $DIR/bool_comparison.rs:43:8 + --> $DIR/bool_comparison.rs:44:8 | LL | if false != x { | ^^^^^^^^^^ help: try simplifying it as shown: `x` error: less than comparison against true can be replaced by a negation - --> $DIR/bool_comparison.rs:48:8 + --> $DIR/bool_comparison.rs:49:8 | LL | if x < true { | ^^^^^^^^ help: try simplifying it as shown: `!x` error: greater than checks against false are unnecessary - --> $DIR/bool_comparison.rs:53:8 + --> $DIR/bool_comparison.rs:54:8 | LL | if false < x { | ^^^^^^^^^ help: try simplifying it as shown: `x` error: greater than checks against false are unnecessary - --> $DIR/bool_comparison.rs:58:8 + --> $DIR/bool_comparison.rs:59:8 | LL | if x > false { | ^^^^^^^^^ help: try simplifying it as shown: `x` error: less than comparison against true can be replaced by a negation - --> $DIR/bool_comparison.rs:63:8 + --> $DIR/bool_comparison.rs:64:8 | LL | if true > x { | ^^^^^^^^ help: try simplifying it as shown: `!x` error: order comparisons between booleans can be simplified - --> $DIR/bool_comparison.rs:69:8 + --> $DIR/bool_comparison.rs:70:8 | LL | if x < y { | ^^^^^ help: try simplifying it as shown: `!x & y` error: order comparisons between booleans can be simplified - --> $DIR/bool_comparison.rs:74:8 + --> $DIR/bool_comparison.rs:75:8 | LL | if x > y { | ^^^^^ help: try simplifying it as shown: `x & !y` error: this comparison might be written more concisely - --> $DIR/bool_comparison.rs:122:8 + --> $DIR/bool_comparison.rs:123:8 | LL | if a == !b {}; | ^^^^^^^ help: try simplifying it as shown: `a != b` error: this comparison might be written more concisely - --> $DIR/bool_comparison.rs:123:8 + --> $DIR/bool_comparison.rs:124:8 | LL | if !a == b {}; | ^^^^^^^ help: try simplifying it as shown: `a != b` error: this comparison might be written more concisely - --> $DIR/bool_comparison.rs:127:8 + --> $DIR/bool_comparison.rs:128:8 | LL | if b == !a {}; | ^^^^^^^ help: try simplifying it as shown: `b != a` error: this comparison might be written more concisely - --> $DIR/bool_comparison.rs:128:8 + --> $DIR/bool_comparison.rs:129:8 | LL | if !b == a {}; | ^^^^^^^ help: try simplifying it as shown: `b != a` error: equality checks against false can be replaced by a negation - --> $DIR/bool_comparison.rs:152:8 + --> $DIR/bool_comparison.rs:153:8 | LL | if false == m!(func) {} | ^^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `!m!(func)` error: equality checks against false can be replaced by a negation - --> $DIR/bool_comparison.rs:153:8 + --> $DIR/bool_comparison.rs:154:8 | LL | if m!(func) == false {} | ^^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `!m!(func)` error: equality checks against true are unnecessary - --> $DIR/bool_comparison.rs:154:8 + --> $DIR/bool_comparison.rs:155:8 | LL | if true == m!(func) {} | ^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `m!(func)` error: equality checks against true are unnecessary - --> $DIR/bool_comparison.rs:155:8 + --> $DIR/bool_comparison.rs:156:8 | LL | if m!(func) == true {} | ^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `m!(func)` diff --git a/tests/ui/derive_ord_xor_partial_ord.rs b/tests/ui/derive_ord_xor_partial_ord.rs index 6f12d36d777d..5d1a693321e5 100644 --- a/tests/ui/derive_ord_xor_partial_ord.rs +++ b/tests/ui/derive_ord_xor_partial_ord.rs @@ -1,5 +1,6 @@ #![warn(clippy::derive_ord_xor_partial_ord)] #![allow(clippy::unnecessary_wraps)] +#![allow(clippy::needless_partial_ord_impl)] use std::cmp::Ordering; diff --git a/tests/ui/derive_ord_xor_partial_ord.stderr b/tests/ui/derive_ord_xor_partial_ord.stderr index 58efbb8541f6..bd1488348140 100644 --- a/tests/ui/derive_ord_xor_partial_ord.stderr +++ b/tests/ui/derive_ord_xor_partial_ord.stderr @@ -1,11 +1,11 @@ error: you are deriving `Ord` but have implemented `PartialOrd` explicitly - --> $DIR/derive_ord_xor_partial_ord.rs:21:10 + --> $DIR/derive_ord_xor_partial_ord.rs:22:10 | LL | #[derive(Ord, PartialEq, Eq)] | ^^^ | note: `PartialOrd` implemented here - --> $DIR/derive_ord_xor_partial_ord.rs:24:1 + --> $DIR/derive_ord_xor_partial_ord.rs:25:1 | LL | impl PartialOrd for DeriveOrd { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -13,20 +13,20 @@ LL | impl PartialOrd for DeriveOrd { = note: this error originates in the derive macro `Ord` (in Nightly builds, run with -Z macro-backtrace for more info) error: you are deriving `Ord` but have implemented `PartialOrd` explicitly - --> $DIR/derive_ord_xor_partial_ord.rs:30:10 + --> $DIR/derive_ord_xor_partial_ord.rs:31:10 | LL | #[derive(Ord, PartialEq, Eq)] | ^^^ | note: `PartialOrd` implemented here - --> $DIR/derive_ord_xor_partial_ord.rs:33:1 + --> $DIR/derive_ord_xor_partial_ord.rs:34:1 | LL | impl PartialOrd for DeriveOrdWithExplicitTypeVariable { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the derive macro `Ord` (in Nightly builds, run with -Z macro-backtrace for more info) error: you are implementing `Ord` explicitly but have derived `PartialOrd` - --> $DIR/derive_ord_xor_partial_ord.rs:42:1 + --> $DIR/derive_ord_xor_partial_ord.rs:43:1 | LL | / impl std::cmp::Ord for DerivePartialOrd { LL | | fn cmp(&self, other: &Self) -> Ordering { @@ -36,14 +36,14 @@ LL | | } | |_^ | note: `PartialOrd` implemented here - --> $DIR/derive_ord_xor_partial_ord.rs:39:10 + --> $DIR/derive_ord_xor_partial_ord.rs:40:10 | LL | #[derive(PartialOrd, PartialEq, Eq)] | ^^^^^^^^^^ = note: this error originates in the derive macro `PartialOrd` (in Nightly builds, run with -Z macro-backtrace for more info) error: you are implementing `Ord` explicitly but have derived `PartialOrd` - --> $DIR/derive_ord_xor_partial_ord.rs:62:5 + --> $DIR/derive_ord_xor_partial_ord.rs:63:5 | LL | / impl Ord for DerivePartialOrdInUseOrd { LL | | fn cmp(&self, other: &Self) -> Ordering { @@ -53,7 +53,7 @@ LL | | } | |_____^ | note: `PartialOrd` implemented here - --> $DIR/derive_ord_xor_partial_ord.rs:59:14 + --> $DIR/derive_ord_xor_partial_ord.rs:60:14 | LL | #[derive(PartialOrd, PartialEq, Eq)] | ^^^^^^^^^^ diff --git a/tests/ui/manual_partial_ord_impl.stderr b/tests/ui/manual_partial_ord_impl.stderr deleted file mode 100644 index 100ddb46e82f..000000000000 --- a/tests/ui/manual_partial_ord_impl.stderr +++ /dev/null @@ -1,28 +0,0 @@ -error: manual implementation of `PartialOrd` when `Ord` is already implemented - --> $DIR/manual_partial_ord_impl.rs:18:1 - | -LL | / impl PartialOrd for A { -LL | | fn partial_cmp(&self, other: &Self) -> Option { - | | _____________________________________________________________- -LL | || todo!(); -LL | || } - | ||_____- help: change this to: `{ Some(self.cmp(other)) }` -LL | | } - | |__^ - | - = note: `-D clippy::manual-partial-ord-impl` implied by `-D warnings` - -error: manual implementation of `PartialOrd` when `Ord` is already implemented - --> $DIR/manual_partial_ord_impl.rs:52:1 - | -LL | / impl PartialOrd for C { -LL | | fn partial_cmp(&self, _: &Self) -> Option { -LL | | todo!(); -LL | | } -LL | | } - | |_^ - | - = help: return the value of `self.cmp` wrapped in `Some` instead - -error: aborting due to 2 previous errors - diff --git a/tests/ui/needless_partial_ord_impl.fixed b/tests/ui/needless_partial_ord_impl.fixed new file mode 100644 index 000000000000..7b47773ad766 --- /dev/null +++ b/tests/ui/needless_partial_ord_impl.fixed @@ -0,0 +1,85 @@ +//@run-rustfix +#![allow(unused)] +#![no_main] + +use std::cmp::Ordering; + +// lint + +#[derive(Eq, PartialEq)] +struct A(u32); + +impl Ord for A { + fn cmp(&self, other: &Self) -> Ordering { + todo!(); + } +} + +impl PartialOrd for A { + fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(self)) } +} + +// do not lint + +#[derive(Eq, PartialEq)] +struct B(u32); + +impl Ord for B { + fn cmp(&self, other: &Self) -> Ordering { + todo!(); + } +} + +impl PartialOrd for B { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +// lint, but we can't give a suggestion since &Self is not named + +#[derive(Eq, PartialEq)] +struct C(u32); + +impl Ord for C { + fn cmp(&self, other: &Self) -> Ordering { + todo!(); + } +} + +impl PartialOrd for C { + fn partial_cmp(&self, _: &Self) -> Option { Some(self.cmp(self)) } +} + +// do not lint derived + +#[derive(Eq, Ord, PartialEq, PartialOrd)] +struct D(u32); + +// do not lint if ord is not manually implemented + +#[derive(Eq, PartialEq)] +struct E(u32); + +impl PartialOrd for E { + fn partial_cmp(&self, other: &Self) -> Option { + todo!(); + } +} + +// do not lint since ord has more restrictive bounds + +#[derive(Eq, PartialEq)] +struct Uwu
(A); + +impl Ord for Uwu { + fn cmp(&self, other: &Self) -> Ordering { + todo!(); + } +} + +impl PartialOrd for Uwu { + fn partial_cmp(&self, other: &Self) -> Option { + todo!(); + } +} diff --git a/tests/ui/manual_partial_ord_impl.rs b/tests/ui/needless_partial_ord_impl.rs similarity index 52% rename from tests/ui/manual_partial_ord_impl.rs rename to tests/ui/needless_partial_ord_impl.rs index 9e2c7e2ec516..8f5c1337369b 100644 --- a/tests/ui/manual_partial_ord_impl.rs +++ b/tests/ui/needless_partial_ord_impl.rs @@ -1,5 +1,5 @@ +//@run-rustfix #![allow(unused)] -#![warn(clippy::manual_partial_ord_impl)] #![no_main] use std::cmp::Ordering; @@ -38,7 +38,7 @@ impl PartialOrd for B { } } -// lint, but we cannot give a suggestion since &Self is not named +// lint, but we can't give a suggestion since &Self is not named #[derive(Eq, PartialEq)] struct C(u32); @@ -55,3 +55,35 @@ impl PartialOrd for C { } } +// do not lint derived + +#[derive(Eq, Ord, PartialEq, PartialOrd)] +struct D(u32); + +// do not lint if ord is not manually implemented + +#[derive(Eq, PartialEq)] +struct E(u32); + +impl PartialOrd for E { + fn partial_cmp(&self, other: &Self) -> Option { + todo!(); + } +} + +// do not lint since ord has more restrictive bounds + +#[derive(Eq, PartialEq)] +struct Uwu(A); + +impl Ord for Uwu { + fn cmp(&self, other: &Self) -> Ordering { + todo!(); + } +} + +impl PartialOrd for Uwu { + fn partial_cmp(&self, other: &Self) -> Option { + todo!(); + } +} diff --git a/tests/ui/needless_partial_ord_impl.stderr b/tests/ui/needless_partial_ord_impl.stderr new file mode 100644 index 000000000000..b8978462cc0c --- /dev/null +++ b/tests/ui/needless_partial_ord_impl.stderr @@ -0,0 +1,28 @@ +error: manual implementation of `PartialOrd` when `Ord` is already implemented + --> $DIR/needless_partial_ord_impl.rs:18:1 + | +LL | / impl PartialOrd for A { +LL | | fn partial_cmp(&self, other: &Self) -> Option { + | | _____________________________________________________________- +LL | || todo!(); +LL | || } + | ||_____- help: change this to: `{ Some(self.cmp(self)) }` +LL | | } + | |__^ + | + = note: `#[deny(clippy::needless_partial_ord_impl)]` on by default + +error: manual implementation of `PartialOrd` when `Ord` is already implemented + --> $DIR/needless_partial_ord_impl.rs:52:1 + | +LL | / impl PartialOrd for C { +LL | | fn partial_cmp(&self, _: &Self) -> Option { + | | _________________________________________________________- +LL | || todo!(); +LL | || } + | ||_____- help: change this to: `{ Some(self.cmp(self)) }` +LL | | } + | |__^ + +error: aborting due to 2 previous errors + From 844afbfebad063d335e30f01e7eab287535f6470 Mon Sep 17 00:00:00 2001 From: Centri3 <114838443+Centri3@users.noreply.github.com> Date: Thu, 15 Jun 2023 07:11:25 -0500 Subject: [PATCH 210/324] use `other` instead of `self` --- CHANGELOG.md | 2 +- clippy_lints/src/declared_lints.rs | 2 +- clippy_lints/src/incorrect_impls.rs | 130 +++++++++++++++- clippy_lints/src/lib.rs | 1 - clippy_lints/src/needless_impls.rs | 145 ------------------ tests/ui/bool_comparison.fixed | 2 +- tests/ui/bool_comparison.rs | 2 +- tests/ui/derive.rs | 6 +- tests/ui/derive.stderr | 20 +-- tests/ui/derive_ord_xor_partial_ord.rs | 2 +- ...incorrect_partial_ord_impl_on_ord_type.rs} | 32 +++- ...orrect_partial_ord_impl_on_ord_type.stderr | 28 ++++ tests/ui/needless_partial_ord_impl.fixed | 85 ---------- tests/ui/needless_partial_ord_impl.stderr | 28 ---- 14 files changed, 202 insertions(+), 283 deletions(-) delete mode 100644 clippy_lints/src/needless_impls.rs rename tests/ui/{needless_partial_ord_impl.rs => incorrect_partial_ord_impl_on_ord_type.rs} (72%) create mode 100644 tests/ui/incorrect_partial_ord_impl_on_ord_type.stderr delete mode 100644 tests/ui/needless_partial_ord_impl.fixed delete mode 100644 tests/ui/needless_partial_ord_impl.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index fea11bba63f9..57322887b86d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4834,6 +4834,7 @@ Released 2018-09-13 [`inconsistent_digit_grouping`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_digit_grouping [`inconsistent_struct_constructor`]: https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_struct_constructor [`incorrect_clone_impl_on_copy_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#incorrect_clone_impl_on_copy_type +[`incorrect_partial_ord_impl_on_ord_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#incorrect_partial_ord_impl_on_ord_type [`index_refutable_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice [`indexing_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#indexing_slicing [`ineffective_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#ineffective_bit_mask @@ -5020,7 +5021,6 @@ Released 2018-09-13 [`needless_option_as_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_option_as_deref [`needless_option_take`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_option_take [`needless_parens_on_range_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_parens_on_range_literals -[`needless_partial_ord_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_partial_ord_impl [`needless_pass_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_value [`needless_pub_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_pub_self [`needless_question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_question_mark diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index a2231b8fb1db..caff1c4b3be0 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -207,6 +207,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::implicit_saturating_sub::IMPLICIT_SATURATING_SUB_INFO, crate::inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR_INFO, crate::incorrect_impls::INCORRECT_CLONE_IMPL_ON_COPY_TYPE_INFO, + crate::incorrect_impls::INCORRECT_PARTIAL_ORD_IMPL_ON_ORD_TYPE_INFO, crate::index_refutable_slice::INDEX_REFUTABLE_SLICE_INFO, crate::indexing_slicing::INDEXING_SLICING_INFO, crate::indexing_slicing::OUT_OF_BOUNDS_INDEXING_INFO, @@ -469,7 +470,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::needless_else::NEEDLESS_ELSE_INFO, crate::needless_for_each::NEEDLESS_FOR_EACH_INFO, crate::needless_if::NEEDLESS_IF_INFO, - crate::needless_impls::NEEDLESS_PARTIAL_ORD_IMPL_INFO, crate::needless_late_init::NEEDLESS_LATE_INIT_INFO, crate::needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS_INFO, crate::needless_pass_by_value::NEEDLESS_PASS_BY_VALUE_INFO, diff --git a/clippy_lints/src/incorrect_impls.rs b/clippy_lints/src/incorrect_impls.rs index ed21df4ff884..f7894f9c17b0 100644 --- a/clippy_lints/src/incorrect_impls.rs +++ b/clippy_lints/src/incorrect_impls.rs @@ -1,10 +1,16 @@ -use clippy_utils::{diagnostics::span_lint_and_sugg, get_parent_node, last_path_segment, ty::implements_trait}; +use clippy_utils::{ + diagnostics::{span_lint_and_sugg, span_lint_and_then}, + get_parent_node, is_res_lang_ctor, last_path_segment, path_res, + ty::implements_trait, +}; use rustc_errors::Applicability; +use rustc_hir::{def::Res, Expr, ExprKind, ImplItem, ImplItemKind, ItemKind, LangItem, Node, PatKind, UnOp}; use rustc_hir::{ExprKind, ImplItem, ImplItemKind, Node, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::EarlyBinder; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{sym, symbol}; +use std::borrow::Cow; declare_clippy_lint! { /// ### What it does @@ -45,10 +51,59 @@ declare_clippy_lint! { correctness, "manual implementation of `Clone` on a `Copy` type" } -declare_lint_pass!(IncorrectImpls => [INCORRECT_CLONE_IMPL_ON_COPY_TYPE]); +declare_clippy_lint! { + /// ### What it does + /// Checks for manual implementations of both `PartialOrd` and `Ord` when only `Ord` is + /// necessary. + /// + /// ### Why is this bad? + /// If both `PartialOrd` and `Ord` are implemented, they must agree. This is commonly done by + /// wrapping the result of `cmp` in `Some` for `partial_cmp`. Not doing this may silently + /// introduce an error upon refactoring. + /// + /// ### Example + /// ```rust,ignore + /// #[derive(Eq, PartialEq)] + /// struct A(u32); + /// + /// impl Ord for A { + /// fn cmp(&self, other: &Self) -> Ordering { + /// todo!(); + /// } + /// } + /// + /// impl PartialOrd for A { + /// fn partial_cmp(&self, other: &Self) -> Option { + /// todo!(); + /// } + /// } + /// ``` + /// Use instead: + /// ```rust,ignore + /// #[derive(Eq, PartialEq)] + /// struct A(u32); + /// + /// impl Ord for A { + /// fn cmp(&self, other: &Self) -> Ordering { + /// todo!(); + /// } + /// } + /// + /// impl PartialOrd for A { + /// fn partial_cmp(&self, other: &Self) -> Option { + /// Some(self.cmp(other)) + /// } + /// } + /// ``` + #[clippy::version = "1.72.0"] + pub INCORRECT_PARTIAL_ORD_IMPL_ON_ORD_TYPE, + correctness, + "manual implementation of `PartialOrd` when `Ord` is already implemented" +} +declare_lint_pass!(IncorrectImpls => [INCORRECT_CLONE_IMPL_ON_COPY_TYPE, INCORRECT_PARTIAL_ORD_IMPL_ON_ORD_TYPE]); impl LateLintPass<'_> for IncorrectImpls { - #[expect(clippy::needless_return)] + #[expect(clippy::too_many_lines)] fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &ImplItem<'_>) { let node = get_parent_node(cx.tcx, impl_item.hir_id()); let Some(Node::Item(item)) = node else { @@ -68,10 +123,7 @@ impl LateLintPass<'_> for IncorrectImpls { let ExprKind::Block(block, ..) = body.value.kind else { return; }; - // Above is duplicated from the `duplicate_manual_partial_ord_impl` branch. - // Remove it while solving conflicts once that PR is merged. - // Actual implementation; remove this comment once aforementioned PR is merged if cx.tcx.is_diagnostic_item(sym::Clone, trait_impl_def_id) && let Some(copy_def_id) = cx.tcx.get_diagnostic_item(sym::Copy) && implements_trait( @@ -116,5 +168,71 @@ impl LateLintPass<'_> for IncorrectImpls { return; } } + + if cx.tcx.is_diagnostic_item(sym::PartialOrd, trait_impl_def_id) + && impl_item.ident.name == sym::partial_cmp + && let Some(ord_def_id) = cx + .tcx + .diagnostic_items(trait_impl.def_id.krate) + .name_to_id + .get(&sym::Ord) + && implements_trait( + cx, + hir_ty_to_ty(cx.tcx, imp.self_ty), + *ord_def_id, + trait_impl.substs, + ) + { + if block.stmts.is_empty() + && let Some(expr) = block.expr + && let ExprKind::Call( + Expr { + kind: ExprKind::Path(some_path), + hir_id: some_hir_id, + .. + }, + [cmp_expr], + ) = expr.kind + && is_res_lang_ctor(cx, cx.qpath_res(some_path, *some_hir_id), LangItem::OptionSome) + && let ExprKind::MethodCall(cmp_path, _, [other_expr], ..) = cmp_expr.kind + && cmp_path.ident.name == sym::cmp + && let Res::Local(..) = path_res(cx, other_expr) + {} else { + // If lhs and rhs are not the same type, bail. This makes creating a valid + // suggestion tons more complex. + if let Some(lhs) = trait_impl.substs.get(0) + && let Some(rhs) = trait_impl.substs.get(1) + && lhs != rhs + { + return; + } + + span_lint_and_then( + cx, + INCORRECT_PARTIAL_ORD_IMPL_ON_ORD_TYPE, + item.span, + "incorrect implementation of `partial_cmp` on an `Ord` type", + |diag| { + let (help, app) = if let Some(other) = body.params.get(1) + && let PatKind::Binding(_, _, other_ident, ..) = other.pat.kind + { + ( + Cow::Owned(format!("{{ Some(self.cmp({})) }}", other_ident.name)), + Applicability::Unspecified, + ) + } else { + (Cow::Borrowed("{ Some(self.cmp(...)) }"), Applicability::HasPlaceholders) + }; + + diag.span_suggestion( + block.span, + "change this to", + help, + app, + ); + } + ); + } + } } } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 1ec5b2e8b0aa..00d46025caa8 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -227,7 +227,6 @@ mod needless_continue; mod needless_else; mod needless_for_each; mod needless_if; -mod needless_impls; mod needless_late_init; mod needless_parens_on_range_literals; mod needless_pass_by_value; diff --git a/clippy_lints/src/needless_impls.rs b/clippy_lints/src/needless_impls.rs deleted file mode 100644 index 4f8741bf3708..000000000000 --- a/clippy_lints/src/needless_impls.rs +++ /dev/null @@ -1,145 +0,0 @@ -use clippy_utils::{ - diagnostics::span_lint_and_then, get_parent_node, is_res_lang_ctor, path_res, ty::implements_trait, -}; -use rustc_errors::Applicability; -use rustc_hir::{def::Res, Expr, ExprKind, ImplItem, ImplItemKind, ItemKind, LangItem, Node, PatKind}; -use rustc_hir_analysis::hir_ty_to_ty; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::EarlyBinder; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::sym; -use std::borrow::Cow; - -declare_clippy_lint! { - /// ### What it does - /// Checks for manual implementations of both `PartialOrd` and `Ord` when only `Ord` is - /// necessary. - /// - /// ### Why is this bad? - /// If both `PartialOrd` and `Ord` are implemented, they must agree. This is commonly done by - /// wrapping the result of `cmp` in `Some` for `partial_cmp`. Not doing this may silently - /// introduce an error upon refactoring. - /// - /// ### Example - /// ```rust,ignore - /// #[derive(Eq, PartialEq)] - /// struct A(u32); - /// - /// impl Ord for A { - /// fn cmp(&self, other: &Self) -> Ordering { - /// todo!(); - /// } - /// } - /// - /// impl PartialOrd for A { - /// fn partial_cmp(&self, other: &Self) -> Option { - /// todo!(); - /// } - /// } - /// ``` - /// Use instead: - /// ```rust,ignore - /// #[derive(Eq, PartialEq)] - /// struct A(u32); - /// - /// impl Ord for A { - /// fn cmp(&self, other: &Self) -> Ordering { - /// todo!(); - /// } - /// } - /// - /// impl PartialOrd for A { - /// fn partial_cmp(&self, other: &Self) -> Option { - /// Some(self.cmp(other)) - /// } - /// } - /// ``` - #[clippy::version = "1.72.0"] - pub NEEDLESS_PARTIAL_ORD_IMPL, - correctness, - "manual implementation of `PartialOrd` when `Ord` is already implemented" -} -declare_lint_pass!(NeedlessImpls => [NEEDLESS_PARTIAL_ORD_IMPL]); - -impl LateLintPass<'_> for NeedlessImpls { - fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &ImplItem<'_>) { - let node = get_parent_node(cx.tcx, impl_item.hir_id()); - let Some(Node::Item(item)) = node else { - return; - }; - let ItemKind::Impl(imp) = item.kind else { - return; - }; - let Some(trait_impl) = cx.tcx.impl_trait_ref(item.owner_id).map(EarlyBinder::skip_binder) else { - return; - }; - let trait_impl_def_id = trait_impl.def_id; - if cx.tcx.is_automatically_derived(item.owner_id.to_def_id()) { - return; - } - let ImplItemKind::Fn(_, impl_item_id) = cx.tcx.hir().impl_item(impl_item.impl_item_id()).kind else { - return; - }; - let body = cx.tcx.hir().body(impl_item_id); - let ExprKind::Block(block, ..) = body.value.kind else { - return; - }; - - if cx.tcx.is_diagnostic_item(sym::PartialOrd, trait_impl_def_id) - && impl_item.ident.name == sym::partial_cmp - && let Some(ord_def_id) = cx - .tcx - .diagnostic_items(trait_impl.def_id.krate) - .name_to_id - .get(&sym::Ord) - && implements_trait( - cx, - hir_ty_to_ty(cx.tcx, imp.self_ty), - *ord_def_id, - trait_impl.substs, - ) - { - if block.stmts.is_empty() - && let Some(expr) = block.expr - && let ExprKind::Call( - Expr { - kind: ExprKind::Path(some_path), - hir_id: some_hir_id, - .. - }, - [cmp_expr], - ) = expr.kind - && is_res_lang_ctor(cx, cx.qpath_res(some_path, *some_hir_id), LangItem::OptionSome) - && let ExprKind::MethodCall(cmp_path, _, [other_expr], ..) = cmp_expr.kind - && cmp_path.ident.name == sym::cmp - && let Res::Local(..) = path_res(cx, other_expr) - {} else { - span_lint_and_then( - cx, - NEEDLESS_PARTIAL_ORD_IMPL, - item.span, - "manual implementation of `PartialOrd` when `Ord` is already implemented", - |diag| { - let (help, app) = if let Some(other) = body.params.get(0) - && let PatKind::Binding(_, _, other_ident, ..) = other.pat.kind - { - ( - Cow::Owned(format!("{{ Some(self.cmp({})) }}", other_ident.name)), - Applicability::Unspecified, - ) - } else { - (Cow::Borrowed("{ Some(self.cmp(...)) }"), Applicability::HasPlaceholders) - }; - - diag.span_suggestion( - block.span, - "change this to", - help, - app, - ); - } - ); - } - } - } -} diff --git a/tests/ui/bool_comparison.fixed b/tests/ui/bool_comparison.fixed index 33221c7777ea..8689f89d2c33 100644 --- a/tests/ui/bool_comparison.fixed +++ b/tests/ui/bool_comparison.fixed @@ -2,7 +2,7 @@ #![allow(clippy::needless_if)] #![warn(clippy::bool_comparison)] -#![allow(clippy::needless_partial_ord_impl)] +#![allow(clippy::incorrect_partial_ord_impl_on_ord_type)] fn main() { let x = true; diff --git a/tests/ui/bool_comparison.rs b/tests/ui/bool_comparison.rs index 5f909bd2a53f..a1c94aff94b2 100644 --- a/tests/ui/bool_comparison.rs +++ b/tests/ui/bool_comparison.rs @@ -2,7 +2,7 @@ #![allow(clippy::needless_if)] #![warn(clippy::bool_comparison)] -#![allow(clippy::needless_partial_ord_impl)] +#![allow(clippy::incorrect_partial_ord_impl_on_ord_type)] fn main() { let x = true; diff --git a/tests/ui/derive.rs b/tests/ui/derive.rs index 44e18bff83fb..ff4dcbfa2f2d 100644 --- a/tests/ui/derive.rs +++ b/tests/ui/derive.rs @@ -1,4 +1,8 @@ -#![allow(clippy::incorrect_clone_impl_on_copy_type, dead_code)] +#![allow( + clippy::incorrect_clone_impl_on_copy_type, + clippy::incorrect_partial_ord_impl_on_ord_type, + dead_code +)] #![warn(clippy::expl_impl_clone_on_copy)] #[derive(Copy)] diff --git a/tests/ui/derive.stderr b/tests/ui/derive.stderr index d37f7fa73319..f7948e044b7e 100644 --- a/tests/ui/derive.stderr +++ b/tests/ui/derive.stderr @@ -1,5 +1,5 @@ error: you are implementing `Clone` explicitly on a `Copy` type - --> $DIR/derive.rs:7:1 + --> $DIR/derive.rs:11:1 | LL | / impl Clone for Qux { LL | | fn clone(&self) -> Self { @@ -9,7 +9,7 @@ LL | | } | |_^ | note: consider deriving `Clone` or removing `Copy` - --> $DIR/derive.rs:7:1 + --> $DIR/derive.rs:11:1 | LL | / impl Clone for Qux { LL | | fn clone(&self) -> Self { @@ -20,7 +20,7 @@ LL | | } = note: `-D clippy::expl-impl-clone-on-copy` implied by `-D warnings` error: you are implementing `Clone` explicitly on a `Copy` type - --> $DIR/derive.rs:31:1 + --> $DIR/derive.rs:35:1 | LL | / impl<'a> Clone for Lt<'a> { LL | | fn clone(&self) -> Self { @@ -30,7 +30,7 @@ LL | | } | |_^ | note: consider deriving `Clone` or removing `Copy` - --> $DIR/derive.rs:31:1 + --> $DIR/derive.rs:35:1 | LL | / impl<'a> Clone for Lt<'a> { LL | | fn clone(&self) -> Self { @@ -40,7 +40,7 @@ LL | | } | |_^ error: you are implementing `Clone` explicitly on a `Copy` type - --> $DIR/derive.rs:42:1 + --> $DIR/derive.rs:46:1 | LL | / impl Clone for BigArray { LL | | fn clone(&self) -> Self { @@ -50,7 +50,7 @@ LL | | } | |_^ | note: consider deriving `Clone` or removing `Copy` - --> $DIR/derive.rs:42:1 + --> $DIR/derive.rs:46:1 | LL | / impl Clone for BigArray { LL | | fn clone(&self) -> Self { @@ -60,7 +60,7 @@ LL | | } | |_^ error: you are implementing `Clone` explicitly on a `Copy` type - --> $DIR/derive.rs:53:1 + --> $DIR/derive.rs:57:1 | LL | / impl Clone for FnPtr { LL | | fn clone(&self) -> Self { @@ -70,7 +70,7 @@ LL | | } | |_^ | note: consider deriving `Clone` or removing `Copy` - --> $DIR/derive.rs:53:1 + --> $DIR/derive.rs:57:1 | LL | / impl Clone for FnPtr { LL | | fn clone(&self) -> Self { @@ -80,7 +80,7 @@ LL | | } | |_^ error: you are implementing `Clone` explicitly on a `Copy` type - --> $DIR/derive.rs:73:1 + --> $DIR/derive.rs:77:1 | LL | / impl Clone for Generic2 { LL | | fn clone(&self) -> Self { @@ -90,7 +90,7 @@ LL | | } | |_^ | note: consider deriving `Clone` or removing `Copy` - --> $DIR/derive.rs:73:1 + --> $DIR/derive.rs:77:1 | LL | / impl Clone for Generic2 { LL | | fn clone(&self) -> Self { diff --git a/tests/ui/derive_ord_xor_partial_ord.rs b/tests/ui/derive_ord_xor_partial_ord.rs index 5d1a693321e5..1fb3d51c46dc 100644 --- a/tests/ui/derive_ord_xor_partial_ord.rs +++ b/tests/ui/derive_ord_xor_partial_ord.rs @@ -1,6 +1,6 @@ #![warn(clippy::derive_ord_xor_partial_ord)] #![allow(clippy::unnecessary_wraps)] -#![allow(clippy::needless_partial_ord_impl)] +#![allow(clippy::incorrect_partial_ord_impl_on_ord_type)] use std::cmp::Ordering; diff --git a/tests/ui/needless_partial_ord_impl.rs b/tests/ui/incorrect_partial_ord_impl_on_ord_type.rs similarity index 72% rename from tests/ui/needless_partial_ord_impl.rs rename to tests/ui/incorrect_partial_ord_impl_on_ord_type.rs index 8f5c1337369b..25fe909a8d39 100644 --- a/tests/ui/needless_partial_ord_impl.rs +++ b/tests/ui/incorrect_partial_ord_impl_on_ord_type.rs @@ -1,4 +1,3 @@ -//@run-rustfix #![allow(unused)] #![no_main] @@ -51,7 +50,7 @@ impl Ord for C { impl PartialOrd for C { fn partial_cmp(&self, _: &Self) -> Option { - todo!(); + todo!(); // don't run rustfix, or else this will cause it to fail to compile } } @@ -87,3 +86,32 @@ impl PartialOrd for Uwu { todo!(); } } + +// do not lint since `Rhs` is not `Self` + +#[derive(Eq, PartialEq)] +struct F(u32); + +impl Ord for F { + fn cmp(&self, other: &Self) -> Ordering { + todo!(); + } +} + +impl PartialOrd for F { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl PartialEq for F { + fn eq(&self, other: &u32) -> bool { + todo!(); + } +} + +impl PartialOrd for F { + fn partial_cmp(&self, other: &u32) -> Option { + todo!(); + } +} diff --git a/tests/ui/incorrect_partial_ord_impl_on_ord_type.stderr b/tests/ui/incorrect_partial_ord_impl_on_ord_type.stderr new file mode 100644 index 000000000000..86b3d37241a7 --- /dev/null +++ b/tests/ui/incorrect_partial_ord_impl_on_ord_type.stderr @@ -0,0 +1,28 @@ +error: incorrect implementation of `partial_cmp` on an `Ord` type + --> $DIR/incorrect_partial_ord_impl_on_ord_type.rs:17:1 + | +LL | / impl PartialOrd for A { +LL | | fn partial_cmp(&self, other: &Self) -> Option { + | | _____________________________________________________________- +LL | || todo!(); +LL | || } + | ||_____- help: change this to: `{ Some(self.cmp(other)) }` +LL | | } + | |__^ + | + = note: `#[deny(clippy::incorrect_partial_ord_impl_on_ord_type)]` on by default + +error: incorrect implementation of `partial_cmp` on an `Ord` type + --> $DIR/incorrect_partial_ord_impl_on_ord_type.rs:51:1 + | +LL | / impl PartialOrd for C { +LL | | fn partial_cmp(&self, _: &Self) -> Option { + | | _________________________________________________________- +LL | || todo!(); // don't run rustfix, or else this will cause it to fail to compile +LL | || } + | ||_____- help: change this to: `{ Some(self.cmp(...)) }` +LL | | } + | |__^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/needless_partial_ord_impl.fixed b/tests/ui/needless_partial_ord_impl.fixed deleted file mode 100644 index 7b47773ad766..000000000000 --- a/tests/ui/needless_partial_ord_impl.fixed +++ /dev/null @@ -1,85 +0,0 @@ -//@run-rustfix -#![allow(unused)] -#![no_main] - -use std::cmp::Ordering; - -// lint - -#[derive(Eq, PartialEq)] -struct A(u32); - -impl Ord for A { - fn cmp(&self, other: &Self) -> Ordering { - todo!(); - } -} - -impl PartialOrd for A { - fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(self)) } -} - -// do not lint - -#[derive(Eq, PartialEq)] -struct B(u32); - -impl Ord for B { - fn cmp(&self, other: &Self) -> Ordering { - todo!(); - } -} - -impl PartialOrd for B { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -// lint, but we can't give a suggestion since &Self is not named - -#[derive(Eq, PartialEq)] -struct C(u32); - -impl Ord for C { - fn cmp(&self, other: &Self) -> Ordering { - todo!(); - } -} - -impl PartialOrd for C { - fn partial_cmp(&self, _: &Self) -> Option { Some(self.cmp(self)) } -} - -// do not lint derived - -#[derive(Eq, Ord, PartialEq, PartialOrd)] -struct D(u32); - -// do not lint if ord is not manually implemented - -#[derive(Eq, PartialEq)] -struct E(u32); - -impl PartialOrd for E { - fn partial_cmp(&self, other: &Self) -> Option { - todo!(); - } -} - -// do not lint since ord has more restrictive bounds - -#[derive(Eq, PartialEq)] -struct Uwu(A); - -impl Ord for Uwu { - fn cmp(&self, other: &Self) -> Ordering { - todo!(); - } -} - -impl PartialOrd for Uwu { - fn partial_cmp(&self, other: &Self) -> Option { - todo!(); - } -} diff --git a/tests/ui/needless_partial_ord_impl.stderr b/tests/ui/needless_partial_ord_impl.stderr deleted file mode 100644 index b8978462cc0c..000000000000 --- a/tests/ui/needless_partial_ord_impl.stderr +++ /dev/null @@ -1,28 +0,0 @@ -error: manual implementation of `PartialOrd` when `Ord` is already implemented - --> $DIR/needless_partial_ord_impl.rs:18:1 - | -LL | / impl PartialOrd for A { -LL | | fn partial_cmp(&self, other: &Self) -> Option { - | | _____________________________________________________________- -LL | || todo!(); -LL | || } - | ||_____- help: change this to: `{ Some(self.cmp(self)) }` -LL | | } - | |__^ - | - = note: `#[deny(clippy::needless_partial_ord_impl)]` on by default - -error: manual implementation of `PartialOrd` when `Ord` is already implemented - --> $DIR/needless_partial_ord_impl.rs:52:1 - | -LL | / impl PartialOrd for C { -LL | | fn partial_cmp(&self, _: &Self) -> Option { - | | _________________________________________________________- -LL | || todo!(); -LL | || } - | ||_____- help: change this to: `{ Some(self.cmp(self)) }` -LL | | } - | |__^ - -error: aborting due to 2 previous errors - From a5dfb68491505d8ad2aceb8cb14e1bd7272dcc2a Mon Sep 17 00:00:00 2001 From: Catherine <114838443+Centri3@users.noreply.github.com> Date: Fri, 30 Jun 2023 15:16:56 -0500 Subject: [PATCH 211/324] refactor --- clippy_lints/src/incorrect_impls.rs | 78 ++++++------ .../incorrect_clone_impl_on_copy_type.stderr | 4 +- ...correct_partial_ord_impl_on_ord_type.fixed | 114 ++++++++++++++++++ .../incorrect_partial_ord_impl_on_ord_type.rs | 5 +- ...orrect_partial_ord_impl_on_ord_type.stderr | 23 ++-- 5 files changed, 174 insertions(+), 50 deletions(-) create mode 100644 tests/ui/incorrect_partial_ord_impl_on_ord_type.fixed diff --git a/clippy_lints/src/incorrect_impls.rs b/clippy_lints/src/incorrect_impls.rs index f7894f9c17b0..25e1cb36b74a 100644 --- a/clippy_lints/src/incorrect_impls.rs +++ b/clippy_lints/src/incorrect_impls.rs @@ -4,13 +4,12 @@ use clippy_utils::{ ty::implements_trait, }; use rustc_errors::Applicability; -use rustc_hir::{def::Res, Expr, ExprKind, ImplItem, ImplItemKind, ItemKind, LangItem, Node, PatKind, UnOp}; -use rustc_hir::{ExprKind, ImplItem, ImplItemKind, Node, UnOp}; +use rustc_hir::{def::Res, Expr, ExprKind, ImplItem, ImplItemKind, ItemKind, LangItem, Node, UnOp}; +use rustc_hir_analysis::hir_ty_to_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::EarlyBinder; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::{sym, symbol}; -use std::borrow::Cow; +use rustc_span::{sym, symbol::kw}; declare_clippy_lint! { /// ### What it does @@ -61,31 +60,39 @@ declare_clippy_lint! { /// wrapping the result of `cmp` in `Some` for `partial_cmp`. Not doing this may silently /// introduce an error upon refactoring. /// + /// ### Limitations + /// Will not lint if `Self` and `Rhs` do not have the same type. + /// /// ### Example - /// ```rust,ignore + /// ```rust + /// # use std::cmp::Ordering; /// #[derive(Eq, PartialEq)] /// struct A(u32); /// /// impl Ord for A { /// fn cmp(&self, other: &Self) -> Ordering { - /// todo!(); + /// // ... + /// # todo!(); /// } /// } /// /// impl PartialOrd for A { /// fn partial_cmp(&self, other: &Self) -> Option { - /// todo!(); + /// // ... + /// # todo!(); /// } /// } /// ``` /// Use instead: - /// ```rust,ignore + /// ```rust + /// # use std::cmp::Ordering; /// #[derive(Eq, PartialEq)] /// struct A(u32); /// /// impl Ord for A { /// fn cmp(&self, other: &Self) -> Ordering { - /// todo!(); + /// // ... + /// # todo!(); /// } /// } /// @@ -105,17 +112,18 @@ declare_lint_pass!(IncorrectImpls => [INCORRECT_CLONE_IMPL_ON_COPY_TYPE, INCORRE impl LateLintPass<'_> for IncorrectImpls { #[expect(clippy::too_many_lines)] fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &ImplItem<'_>) { - let node = get_parent_node(cx.tcx, impl_item.hir_id()); - let Some(Node::Item(item)) = node else { + let Some(Node::Item(item)) = get_parent_node(cx.tcx, impl_item.hir_id()) else { return; }; let Some(trait_impl) = cx.tcx.impl_trait_ref(item.owner_id).map(EarlyBinder::skip_binder) else { return; }; - let trait_impl_def_id = trait_impl.def_id; if cx.tcx.is_automatically_derived(item.owner_id.to_def_id()) { return; } + let ItemKind::Impl(imp) = item.kind else { + return; + }; let ImplItemKind::Fn(_, impl_item_id) = cx.tcx.hir().impl_item(impl_item.impl_item_id()).kind else { return; }; @@ -124,7 +132,7 @@ impl LateLintPass<'_> for IncorrectImpls { return; }; - if cx.tcx.is_diagnostic_item(sym::Clone, trait_impl_def_id) + if cx.tcx.is_diagnostic_item(sym::Clone, trait_impl.def_id) && let Some(copy_def_id) = cx.tcx.get_diagnostic_item(sym::Copy) && implements_trait( cx, @@ -136,9 +144,9 @@ impl LateLintPass<'_> for IncorrectImpls { if impl_item.ident.name == sym::clone { if block.stmts.is_empty() && let Some(expr) = block.expr - && let ExprKind::Unary(UnOp::Deref, inner) = expr.kind - && let ExprKind::Path(qpath) = inner.kind - && last_path_segment(&qpath).ident.name == symbol::kw::SelfLower + && let ExprKind::Unary(UnOp::Deref, deref) = expr.kind + && let ExprKind::Path(qpath) = deref.kind + && last_path_segment(&qpath).ident.name == kw::SelfLower {} else { span_lint_and_sugg( cx, @@ -160,7 +168,7 @@ impl LateLintPass<'_> for IncorrectImpls { INCORRECT_CLONE_IMPL_ON_COPY_TYPE, impl_item.span, "incorrect implementation of `clone_from` on a `Copy` type", - "remove this", + "remove it", String::new(), Applicability::MaybeIncorrect, ); @@ -169,7 +177,7 @@ impl LateLintPass<'_> for IncorrectImpls { } } - if cx.tcx.is_diagnostic_item(sym::PartialOrd, trait_impl_def_id) + if cx.tcx.is_diagnostic_item(sym::PartialOrd, trait_impl.def_id) && impl_item.ident.name == sym::partial_cmp && let Some(ord_def_id) = cx .tcx @@ -198,12 +206,9 @@ impl LateLintPass<'_> for IncorrectImpls { && cmp_path.ident.name == sym::cmp && let Res::Local(..) = path_res(cx, other_expr) {} else { - // If lhs and rhs are not the same type, bail. This makes creating a valid + // If `Self` and `Rhs` are not the same type, bail. This makes creating a valid // suggestion tons more complex. - if let Some(lhs) = trait_impl.substs.get(0) - && let Some(rhs) = trait_impl.substs.get(1) - && lhs != rhs - { + if let [lhs, rhs, ..] = trait_impl.substs.as_slice() && lhs != rhs { return; } @@ -213,22 +218,23 @@ impl LateLintPass<'_> for IncorrectImpls { item.span, "incorrect implementation of `partial_cmp` on an `Ord` type", |diag| { - let (help, app) = if let Some(other) = body.params.get(1) - && let PatKind::Binding(_, _, other_ident, ..) = other.pat.kind - { - ( - Cow::Owned(format!("{{ Some(self.cmp({})) }}", other_ident.name)), - Applicability::Unspecified, - ) - } else { - (Cow::Borrowed("{ Some(self.cmp(...)) }"), Applicability::HasPlaceholders) + let [_, other] = body.params else { + return; }; - diag.span_suggestion( - block.span, + let suggs = if let Some(other_ident) = other.pat.simple_ident() { + vec![(block.span, format!("{{ Some(self.cmp({})) }}", other_ident.name))] + } else { + vec![ + (block.span, "{ Some(self.cmp(other)) }".to_owned()), + (other.pat.span, "other".to_owned()), + ] + }; + + diag.multipart_suggestion( "change this to", - help, - app, + suggs, + Applicability::Unspecified, ); } ); diff --git a/tests/ui/incorrect_clone_impl_on_copy_type.stderr b/tests/ui/incorrect_clone_impl_on_copy_type.stderr index 0021841aa860..7bcba8ba45a2 100644 --- a/tests/ui/incorrect_clone_impl_on_copy_type.stderr +++ b/tests/ui/incorrect_clone_impl_on_copy_type.stderr @@ -16,7 +16,7 @@ LL | / fn clone_from(&mut self, source: &Self) { LL | | source.clone(); LL | | *self = source.clone(); LL | | } - | |_____^ help: remove this + | |_____^ help: remove it error: incorrect implementation of `clone` on a `Copy` type --> $DIR/incorrect_clone_impl_on_copy_type.rs:81:29 @@ -34,7 +34,7 @@ LL | / fn clone_from(&mut self, source: &Self) { LL | | source.clone(); LL | | *self = source.clone(); LL | | } - | |_____^ help: remove this + | |_____^ help: remove it error: aborting due to 4 previous errors diff --git a/tests/ui/incorrect_partial_ord_impl_on_ord_type.fixed b/tests/ui/incorrect_partial_ord_impl_on_ord_type.fixed new file mode 100644 index 000000000000..dd4fdd98822c --- /dev/null +++ b/tests/ui/incorrect_partial_ord_impl_on_ord_type.fixed @@ -0,0 +1,114 @@ +//@run-rustfix +#![allow(unused)] +#![no_main] + +use std::cmp::Ordering; + +// lint + +#[derive(Eq, PartialEq)] +struct A(u32); + +impl Ord for A { + fn cmp(&self, other: &Self) -> Ordering { + todo!(); + } +} + +impl PartialOrd for A { + fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } +} + +// do not lint + +#[derive(Eq, PartialEq)] +struct B(u32); + +impl Ord for B { + fn cmp(&self, other: &Self) -> Ordering { + todo!(); + } +} + +impl PartialOrd for B { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +// lint, and give `_` a name + +#[derive(Eq, PartialEq)] +struct C(u32); + +impl Ord for C { + fn cmp(&self, other: &Self) -> Ordering { + todo!(); + } +} + +impl PartialOrd for C { + fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } +} + +// do not lint derived + +#[derive(Eq, Ord, PartialEq, PartialOrd)] +struct D(u32); + +// do not lint if ord is not manually implemented + +#[derive(Eq, PartialEq)] +struct E(u32); + +impl PartialOrd for E { + fn partial_cmp(&self, other: &Self) -> Option { + todo!(); + } +} + +// do not lint since ord has more restrictive bounds + +#[derive(Eq, PartialEq)] +struct Uwu(A); + +impl Ord for Uwu { + fn cmp(&self, other: &Self) -> Ordering { + todo!(); + } +} + +impl PartialOrd for Uwu { + fn partial_cmp(&self, other: &Self) -> Option { + todo!(); + } +} + +// do not lint since `Rhs` is not `Self` + +#[derive(Eq, PartialEq)] +struct F(u32); + +impl Ord for F { + fn cmp(&self, other: &Self) -> Ordering { + todo!(); + } +} + +impl PartialOrd for F { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl PartialEq for F { + fn eq(&self, other: &u32) -> bool { + todo!(); + } +} + +impl PartialOrd for F { + fn partial_cmp(&self, other: &u32) -> Option { + todo!(); + } +} diff --git a/tests/ui/incorrect_partial_ord_impl_on_ord_type.rs b/tests/ui/incorrect_partial_ord_impl_on_ord_type.rs index 25fe909a8d39..522e82299c0a 100644 --- a/tests/ui/incorrect_partial_ord_impl_on_ord_type.rs +++ b/tests/ui/incorrect_partial_ord_impl_on_ord_type.rs @@ -1,3 +1,4 @@ +//@run-rustfix #![allow(unused)] #![no_main] @@ -37,7 +38,7 @@ impl PartialOrd for B { } } -// lint, but we can't give a suggestion since &Self is not named +// lint, and give `_` a name #[derive(Eq, PartialEq)] struct C(u32); @@ -50,7 +51,7 @@ impl Ord for C { impl PartialOrd for C { fn partial_cmp(&self, _: &Self) -> Option { - todo!(); // don't run rustfix, or else this will cause it to fail to compile + todo!(); } } diff --git a/tests/ui/incorrect_partial_ord_impl_on_ord_type.stderr b/tests/ui/incorrect_partial_ord_impl_on_ord_type.stderr index 86b3d37241a7..0e477798c406 100644 --- a/tests/ui/incorrect_partial_ord_impl_on_ord_type.stderr +++ b/tests/ui/incorrect_partial_ord_impl_on_ord_type.stderr @@ -1,5 +1,5 @@ error: incorrect implementation of `partial_cmp` on an `Ord` type - --> $DIR/incorrect_partial_ord_impl_on_ord_type.rs:17:1 + --> $DIR/incorrect_partial_ord_impl_on_ord_type.rs:18:1 | LL | / impl PartialOrd for A { LL | | fn partial_cmp(&self, other: &Self) -> Option { @@ -13,16 +13,19 @@ LL | | } = note: `#[deny(clippy::incorrect_partial_ord_impl_on_ord_type)]` on by default error: incorrect implementation of `partial_cmp` on an `Ord` type - --> $DIR/incorrect_partial_ord_impl_on_ord_type.rs:51:1 + --> $DIR/incorrect_partial_ord_impl_on_ord_type.rs:52:1 | -LL | / impl PartialOrd for C { -LL | | fn partial_cmp(&self, _: &Self) -> Option { - | | _________________________________________________________- -LL | || todo!(); // don't run rustfix, or else this will cause it to fail to compile -LL | || } - | ||_____- help: change this to: `{ Some(self.cmp(...)) }` -LL | | } - | |__^ +LL | / impl PartialOrd for C { +LL | | fn partial_cmp(&self, _: &Self) -> Option { +LL | | todo!(); +LL | | } +LL | | } + | |_^ + | +help: change this to + | +LL | fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } + | ~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to 2 previous errors From 41438c2b90f0324494c6ca22d205bf0acec4c03c Mon Sep 17 00:00:00 2001 From: Catherine <114838443+Centri3@users.noreply.github.com> Date: Tue, 4 Jul 2023 12:49:15 -0500 Subject: [PATCH 212/324] Refactor, remove `Constant::to_bits` --- README.md | 2 +- book/src/README.md | 2 +- clippy_lints/src/manual_float_methods.rs | 59 +++++++++++++++--------- clippy_utils/src/consts.rs | 11 ----- tests/ui/manual_float_methods.rs | 21 ++++++++- tests/ui/manual_float_methods.stderr | 12 ++--- 6 files changed, 66 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index d712d3e67507..5d490645d897 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are over 600 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are over 650 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html). You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the lint level by category. diff --git a/book/src/README.md b/book/src/README.md index 3b6270962680..486ea3df7042 100644 --- a/book/src/README.md +++ b/book/src/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are over 600 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are over 650 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html). You can choose how diff --git a/clippy_lints/src/manual_float_methods.rs b/clippy_lints/src/manual_float_methods.rs index 0f488627b4e9..09b39634333f 100644 --- a/clippy_lints/src/manual_float_methods.rs +++ b/clippy_lints/src/manual_float_methods.rs @@ -1,5 +1,8 @@ use clippy_utils::{ - consts::constant, diagnostics::span_lint_and_then, is_from_proc_macro, path_to_local, source::snippet_opt, + consts::{constant, Constant}, + diagnostics::span_lint_and_then, + is_from_proc_macro, path_to_local, + source::snippet_opt, }; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; @@ -9,10 +12,11 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { /// ### What it does - /// Checks for `x == ::INFINITY || x == ::NEG_INFINITY`. + /// Checks for manual `is_infinite` reimplementations + /// (i.e., `x == ::INFINITY || x == ::NEG_INFINITY`). /// /// ### Why is this bad? - /// This should use the dedicated method instead, `is_infinite`. + /// The method `is_infinite` is shorter and more readable. /// /// ### Example /// ```rust @@ -31,20 +35,23 @@ declare_clippy_lint! { } declare_clippy_lint! { /// ### What it does - /// Checks for `x != ::INFINITY && x != ::NEG_INFINITY`. + /// Checks for manual `is_finite` reimplementations + /// (i.e., `x != ::INFINITY && x != ::NEG_INFINITY`). /// /// ### Why is this bad? - /// This should use the dedicated method instead, `is_finite`. + /// The method `is_finite` is shorter and more readable. /// /// ### Example /// ```rust /// # let x = 1.0f32; /// if x != f32::INFINITY && x != f32::NEG_INFINITY {} + /// if x.abs() < f32::INFINITY {} /// ``` /// Use instead: /// ```rust /// # let x = 1.0f32; /// if x.is_finite() {} + /// if x.is_finite() {} /// ``` #[clippy::version = "1.72.0"] pub MANUAL_IS_FINITE, @@ -84,20 +91,22 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods { && let ExprKind::Binary(rhs_kind, rhs_lhs, rhs_rhs) = rhs.kind // Checking all possible scenarios using a function would be a hopeless task, as we have // 16 possible alignments of constants/operands. For now, let's use `partition`. - && let (operands, consts) = [lhs_lhs, lhs_rhs, rhs_lhs, rhs_rhs] + && let (operands, constants) = [lhs_lhs, lhs_rhs, rhs_lhs, rhs_rhs] .into_iter() .partition::>, _>(|i| path_to_local(i).is_some()) && let [first, second] = &*operands - && let Some([const_1, const_2]) = consts + && let Some([const_1, const_2]) = constants .into_iter() - .map(|i| constant(cx, cx.typeck_results(), i).and_then(|c| c.to_bits())) + .map(|i| constant(cx, cx.typeck_results(), i)) .collect::>>() .as_deref() && path_to_local(first).is_some_and(|f| path_to_local(second).is_some_and(|s| f == s)) - && (is_infinity(*const_1) && is_neg_infinity(*const_2) - || is_neg_infinity(*const_1) && is_infinity(*const_2)) - && let Some(local_snippet) = snippet_opt(cx, first.span) + // The actual infinity check, we also allow `NEG_INFINITY` before` INFINITY` just in + // case somebody does that for some reason + && (is_infinity(const_1) && is_neg_infinity(const_2) + || is_neg_infinity(const_1) && is_infinity(const_2)) && !is_from_proc_macro(cx, expr) + && let Some(local_snippet) = snippet_opt(cx, first.span) { let variant = match (kind.node, lhs_kind.node, rhs_kind.node) { (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Eq) => Variant::ManualIsInfinite, @@ -128,31 +137,39 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods { "use the dedicated method instead", format!("{local_snippet}.is_finite()"), Applicability::MaybeIncorrect, - ); - diag.span_suggestion_verbose( + ) + .span_suggestion_verbose( expr.span, "this will alter how it handles NaN; if that is a problem, use instead", format!("{local_snippet}.is_finite() || {local_snippet}.is_nan()"), Applicability::MaybeIncorrect, - ); - diag.span_suggestion_verbose( + ) + .span_suggestion_verbose( expr.span, "or, for conciseness", format!("!{local_snippet}.is_infinite()"), Applicability::MaybeIncorrect, ); - } + }, } - } + }, ); } } } -fn is_infinity(bits: u128) -> bool { - bits == 0x7f80_0000 || bits == 0x7ff0_0000_0000_0000 +fn is_infinity(constant: &Constant<'_>) -> bool { + match constant { + Constant::F32(float) => *float == f32::INFINITY, + Constant::F64(float) => *float == f64::INFINITY, + _ => false, + } } -fn is_neg_infinity(bits: u128) -> bool { - bits == 0xff80_0000 || bits == 0xfff0_0000_0000_0000 +fn is_neg_infinity(constant: &Constant<'_>) -> bool { + match constant { + Constant::F32(float) => *float == f32::NEG_INFINITY, + Constant::F64(float) => *float == f64::NEG_INFINITY, + _ => false, + } } diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index b9f8eefeb8e7..87d85d742ce4 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -190,17 +190,6 @@ impl<'tcx> Constant<'tcx> { } } - /// Returns the bit representation if `self` is a bool, integer, or float. - pub fn to_bits(&self) -> Option { - match self { - Constant::Int(int) => Some(*int), - Constant::F32(float) => Some(u128::from(float.to_bits())), - Constant::F64(float) => Some(u128::from(float.to_bits())), - Constant::Bool(bool) => Some(u128::from(*bool)), - _ => None, - } - } - /// Returns the integer value or `None` if `self` or `val_type` is not integer type. pub fn int_value(&self, cx: &LateContext<'_>, val_type: Ty<'_>) -> Option { if let Constant::Int(const_int) = *self { diff --git a/tests/ui/manual_float_methods.rs b/tests/ui/manual_float_methods.rs index b772202c003f..af9076cfb71f 100644 --- a/tests/ui/manual_float_methods.rs +++ b/tests/ui/manual_float_methods.rs @@ -1,6 +1,7 @@ //@aux-build:proc_macros.rs:proc-macro #![allow(clippy::needless_if, unused)] #![warn(clippy::manual_is_infinite, clippy::manual_is_finite)] +#![feature(inline_const)] #[macro_use] extern crate proc_macros; @@ -8,6 +9,14 @@ extern crate proc_macros; const INFINITE: f32 = f32::INFINITY; const NEG_INFINITE: f32 = f32::NEG_INFINITY; +fn fn_test() -> f64 { + f64::NEG_INFINITY +} + +fn fn_test_not_inf() -> f64 { + 112.0 +} + fn main() { let x = 1.0f32; if x == f32::INFINITY || x == f32::NEG_INFINITY {} @@ -20,8 +29,18 @@ fn main() { // Don't lint if x.is_infinite() {} if x.is_finite() {} - // If they're doing it this way, they probably know what they're doing if x.abs() < f64::INFINITY {} + if f64::INFINITY > x.abs() {} + if f64::abs(x) < f64::INFINITY {} + if f64::INFINITY > f64::abs(x) {} + // Is not evaluated by `clippy_utils::constant` + if x != f64::INFINITY && x != fn_test() {} + // Not -inf + if x != f64::INFINITY && x != fn_test_not_inf() {} + const X: f64 = 1.0f64; + // Will be linted if `const_float_classify` is enabled + if const { X == f64::INFINITY || X == f64::NEG_INFINITY } {} + if const { X != f64::INFINITY && X != f64::NEG_INFINITY } {} external! { let x = 1.0; if x == f32::INFINITY || x == f32::NEG_INFINITY {} diff --git a/tests/ui/manual_float_methods.stderr b/tests/ui/manual_float_methods.stderr index 7f4a4d2e95b3..a56118b316ae 100644 --- a/tests/ui/manual_float_methods.stderr +++ b/tests/ui/manual_float_methods.stderr @@ -1,5 +1,5 @@ error: manually checking if a float is infinite - --> $DIR/manual_float_methods.rs:13:8 + --> $DIR/manual_float_methods.rs:22:8 | LL | if x == f32::INFINITY || x == f32::NEG_INFINITY {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()` @@ -7,7 +7,7 @@ LL | if x == f32::INFINITY || x == f32::NEG_INFINITY {} = note: `-D clippy::manual-is-infinite` implied by `-D warnings` error: manually checking if a float is finite - --> $DIR/manual_float_methods.rs:14:8 + --> $DIR/manual_float_methods.rs:23:8 | LL | if x != f32::INFINITY && x != f32::NEG_INFINITY {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -27,13 +27,13 @@ LL | if !x.is_infinite() {} | ~~~~~~~~~~~~~~~~ error: manually checking if a float is infinite - --> $DIR/manual_float_methods.rs:15:8 + --> $DIR/manual_float_methods.rs:24:8 | LL | if x == INFINITE || x == NEG_INFINITE {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()` error: manually checking if a float is finite - --> $DIR/manual_float_methods.rs:16:8 + --> $DIR/manual_float_methods.rs:25:8 | LL | if x != INFINITE && x != NEG_INFINITE {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -52,13 +52,13 @@ LL | if !x.is_infinite() {} | ~~~~~~~~~~~~~~~~ error: manually checking if a float is infinite - --> $DIR/manual_float_methods.rs:18:8 + --> $DIR/manual_float_methods.rs:27:8 | LL | if x == f64::INFINITY || x == f64::NEG_INFINITY {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()` error: manually checking if a float is finite - --> $DIR/manual_float_methods.rs:19:8 + --> $DIR/manual_float_methods.rs:28:8 | LL | if x != f64::INFINITY && x != f64::NEG_INFINITY {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 2be695bf290299563c5589b3954bd9d044cfa6b9 Mon Sep 17 00:00:00 2001 From: Caio Date: Sat, 8 Jul 2023 17:43:34 -0300 Subject: [PATCH 213/324] [significant_drop_tightening] Fix #11128 --- .../src/significant_drop_tightening.rs | 11 +++++---- clippy_utils/src/paths.rs | 1 + tests/ui/significant_drop_tightening.fixed | 23 +++++++++++++++++++ tests/ui/significant_drop_tightening.rs | 23 +++++++++++++++++++ tests/ui/significant_drop_tightening.stderr | 6 ++--- 5 files changed, 56 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/significant_drop_tightening.rs b/clippy_lints/src/significant_drop_tightening.rs index fffa8a380c2f..3febf7479674 100644 --- a/clippy_lints/src/significant_drop_tightening.rs +++ b/clippy_lints/src/significant_drop_tightening.rs @@ -1,12 +1,13 @@ use clippy_utils::{ diagnostics::span_lint_and_then, - expr_or_init, get_attr, path_to_local, + expr_or_init, get_attr, match_def_path, path_to_local, paths, source::{indent_of, snippet}, }; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_errors::Applicability; use rustc_hir::{ self as hir, + def::{DefKind, Res}, intravisit::{walk_expr, Visitor}, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -333,7 +334,7 @@ impl<'ap, 'lc, 'others, 'stmt, 'tcx> Visitor<'tcx> for StmtsChecker<'ap, 'lc, 'o } }, hir::StmtKind::Semi(expr) => { - if has_drop(expr, &apa.first_bind_ident) { + if has_drop(expr, &apa.first_bind_ident, self.cx) { apa.has_expensive_expr_after_last_attr = false; apa.last_stmt_span = DUMMY_SP; return; @@ -430,11 +431,11 @@ fn dummy_stmt_expr<'any>(expr: &'any hir::Expr<'any>) -> hir::Stmt<'any> { } } -fn has_drop(expr: &hir::Expr<'_>, first_bind_ident: &Ident) -> bool { +fn has_drop(expr: &hir::Expr<'_>, first_bind_ident: &Ident, lcx: &LateContext<'_>) -> bool { if let hir::ExprKind::Call(fun, args) = expr.kind && let hir::ExprKind::Path(hir::QPath::Resolved(_, fun_path)) = &fun.kind - && let [fun_ident, ..] = fun_path.segments - && fun_ident.ident.name == rustc_span::sym::drop + && let Res::Def(DefKind::Fn, did) = fun_path.res + && match_def_path(lcx, did, &paths::DROP) && let [first_arg, ..] = args && let hir::ExprKind::Path(hir::QPath::Resolved(_, arg_path)) = &first_arg.kind && let [first_arg_ps, .. ] = arg_path.segments diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 0e6f01287b56..e8510987225a 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -57,6 +57,7 @@ pub const LATE_CONTEXT: [&str; 2] = ["rustc_lint", "LateContext"]; pub const LATE_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "LateLintPass"]; #[cfg(feature = "internal")] pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"]; +pub const DROP: [&str; 3] = ["core", "mem", "drop"]; pub const MEM_SWAP: [&str; 3] = ["core", "mem", "swap"]; #[cfg(feature = "internal")] pub const MSRV: [&str; 3] = ["clippy_utils", "msrvs", "Msrv"]; diff --git a/tests/ui/significant_drop_tightening.fixed b/tests/ui/significant_drop_tightening.fixed index 7b848ead7846..eb8524167c4a 100644 --- a/tests/ui/significant_drop_tightening.fixed +++ b/tests/ui/significant_drop_tightening.fixed @@ -28,6 +28,29 @@ pub fn issue_10413() { } } +pub fn issue_11128() { + use std::mem::drop as unlock; + + struct Foo { + droppable: Option>, + mutex: Mutex>, + } + + impl Drop for Foo { + fn drop(&mut self) { + if let Some(droppable) = self.droppable.take() { + let lock = self.mutex.lock().unwrap(); + let idx_opt = lock.iter().copied().find(|el| Some(el) == droppable.first()); + if let Some(idx) = idx_opt { + let local_droppable = vec![lock.first().copied().unwrap_or_default()]; + unlock(lock); + drop(local_droppable); + } + } + } + } +} + pub fn path_return_can_be_ignored() -> i32 { let mutex = Mutex::new(1); let lock = mutex.lock().unwrap(); diff --git a/tests/ui/significant_drop_tightening.rs b/tests/ui/significant_drop_tightening.rs index 36f77cf1bdb6..f7fa65ea9227 100644 --- a/tests/ui/significant_drop_tightening.rs +++ b/tests/ui/significant_drop_tightening.rs @@ -27,6 +27,29 @@ pub fn issue_10413() { } } +pub fn issue_11128() { + use std::mem::drop as unlock; + + struct Foo { + droppable: Option>, + mutex: Mutex>, + } + + impl Drop for Foo { + fn drop(&mut self) { + if let Some(droppable) = self.droppable.take() { + let lock = self.mutex.lock().unwrap(); + let idx_opt = lock.iter().copied().find(|el| Some(el) == droppable.first()); + if let Some(idx) = idx_opt { + let local_droppable = vec![lock.first().copied().unwrap_or_default()]; + unlock(lock); + drop(local_droppable); + } + } + } + } +} + pub fn path_return_can_be_ignored() -> i32 { let mutex = Mutex::new(1); let lock = mutex.lock().unwrap(); diff --git a/tests/ui/significant_drop_tightening.stderr b/tests/ui/significant_drop_tightening.stderr index 3bdac0b0a6b7..ca4fede17c93 100644 --- a/tests/ui/significant_drop_tightening.stderr +++ b/tests/ui/significant_drop_tightening.stderr @@ -23,7 +23,7 @@ LL + drop(lock); | error: temporary with significant `Drop` can be early dropped - --> $DIR/significant_drop_tightening.rs:56:13 + --> $DIR/significant_drop_tightening.rs:79:13 | LL | / { LL | | let mutex = Mutex::new(1i32); @@ -43,7 +43,7 @@ LL + drop(lock); | error: temporary with significant `Drop` can be early dropped - --> $DIR/significant_drop_tightening.rs:77:13 + --> $DIR/significant_drop_tightening.rs:100:13 | LL | / { LL | | let mutex = Mutex::new(1i32); @@ -67,7 +67,7 @@ LL + | error: temporary with significant `Drop` can be early dropped - --> $DIR/significant_drop_tightening.rs:83:17 + --> $DIR/significant_drop_tightening.rs:106:17 | LL | / { LL | | let mutex = Mutex::new(vec![1i32]); From 6384221910ce09cca044511d52c489f6193bca7d Mon Sep 17 00:00:00 2001 From: Caio Date: Sat, 8 Jul 2023 18:08:48 -0300 Subject: [PATCH 214/324] Dogfood --- clippy_lints/src/significant_drop_tightening.rs | 5 +++-- clippy_utils/src/paths.rs | 1 - 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/significant_drop_tightening.rs b/clippy_lints/src/significant_drop_tightening.rs index 3febf7479674..cc2dbae4bc4b 100644 --- a/clippy_lints/src/significant_drop_tightening.rs +++ b/clippy_lints/src/significant_drop_tightening.rs @@ -1,6 +1,6 @@ use clippy_utils::{ diagnostics::span_lint_and_then, - expr_or_init, get_attr, match_def_path, path_to_local, paths, + expr_or_init, get_attr, path_to_local, source::{indent_of, snippet}, }; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; @@ -13,6 +13,7 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::{subst::GenericArgKind, Ty, TypeAndMut}; use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::sym; use rustc_span::{symbol::Ident, Span, DUMMY_SP}; use std::borrow::Cow; @@ -435,7 +436,7 @@ fn has_drop(expr: &hir::Expr<'_>, first_bind_ident: &Ident, lcx: &LateContext<'_ if let hir::ExprKind::Call(fun, args) = expr.kind && let hir::ExprKind::Path(hir::QPath::Resolved(_, fun_path)) = &fun.kind && let Res::Def(DefKind::Fn, did) = fun_path.res - && match_def_path(lcx, did, &paths::DROP) + && lcx.tcx.is_diagnostic_item(sym::mem_drop, did) && let [first_arg, ..] = args && let hir::ExprKind::Path(hir::QPath::Resolved(_, arg_path)) = &first_arg.kind && let [first_arg_ps, .. ] = arg_path.segments diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index e8510987225a..0e6f01287b56 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -57,7 +57,6 @@ pub const LATE_CONTEXT: [&str; 2] = ["rustc_lint", "LateContext"]; pub const LATE_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "LateLintPass"]; #[cfg(feature = "internal")] pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"]; -pub const DROP: [&str; 3] = ["core", "mem", "drop"]; pub const MEM_SWAP: [&str; 3] = ["core", "mem", "swap"]; #[cfg(feature = "internal")] pub const MSRV: [&str; 3] = ["clippy_utils", "msrvs", "Msrv"]; From b4738a6b572c0aa3752a6a9bf6c4036de7feee19 Mon Sep 17 00:00:00 2001 From: Samuel Moelius Date: Sat, 8 Jul 2023 19:11:15 -0400 Subject: [PATCH 215/324] Add test for #10535 --- tests/ui/needless_borrow.fixed | 12 ++++++++++++ tests/ui/needless_borrow.rs | 12 ++++++++++++ 2 files changed, 24 insertions(+) diff --git a/tests/ui/needless_borrow.fixed b/tests/ui/needless_borrow.fixed index 80cdb4e472d4..1dfbee150d78 100644 --- a/tests/ui/needless_borrow.fixed +++ b/tests/ui/needless_borrow.fixed @@ -492,3 +492,15 @@ mod issue_9782_method_variant { S.foo::<&[u8; 100]>(&a); } } + +mod issue_10535 { + static SOME_STATIC: String = String::new(); + + static UNIT: () = compute(&SOME_STATIC); + + pub const fn compute(_: T) + where + T: Copy, + { + } +} diff --git a/tests/ui/needless_borrow.rs b/tests/ui/needless_borrow.rs index 99f735127eb8..3c0d73f5f025 100644 --- a/tests/ui/needless_borrow.rs +++ b/tests/ui/needless_borrow.rs @@ -492,3 +492,15 @@ mod issue_9782_method_variant { S.foo::<&[u8; 100]>(&a); } } + +mod issue_10535 { + static SOME_STATIC: String = String::new(); + + static UNIT: () = compute(&SOME_STATIC); + + pub const fn compute(_: T) + where + T: Copy, + { + } +} From 3bf2138289151bb400b53a9817d6e6ab2cf12f13 Mon Sep 17 00:00:00 2001 From: Samuel Moelius Date: Sat, 8 Jul 2023 19:12:10 -0400 Subject: [PATCH 216/324] Fix #10535 --- clippy_lints/src/dereference.rs | 4 ++-- clippy_utils/src/mir/mod.rs | 23 ++++++++++++++--------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 73556c1053ec..12f2f37e3c25 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -1296,8 +1296,8 @@ fn referent_used_exactly_once<'tcx>( possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>, reference: &Expr<'tcx>, ) -> bool { - let mir = enclosing_mir(cx.tcx, reference.hir_id); - if let Some(local) = expr_local(cx.tcx, reference) + if let Some(mir) = enclosing_mir(cx.tcx, reference.hir_id) + && let Some(local) = expr_local(cx.tcx, reference) && let [location] = *local_assignments(mir, local).as_slice() && let Some(statement) = mir.basic_blocks[location.block].statements.get(location.statement_index) && let StatementKind::Assign(box (_, Rvalue::Ref(_, _, place))) = statement.kind diff --git a/clippy_utils/src/mir/mod.rs b/clippy_utils/src/mir/mod.rs index 26c0015e87e0..131f3c0aa394 100644 --- a/clippy_utils/src/mir/mod.rs +++ b/clippy_utils/src/mir/mod.rs @@ -101,21 +101,26 @@ pub fn used_exactly_once(mir: &rustc_middle::mir::Body<'_>, local: rustc_middle: /// Returns the `mir::Body` containing the node associated with `hir_id`. #[allow(clippy::module_name_repetitions)] -pub fn enclosing_mir(tcx: TyCtxt<'_>, hir_id: HirId) -> &Body<'_> { +pub fn enclosing_mir(tcx: TyCtxt<'_>, hir_id: HirId) -> Option<&Body<'_>> { let body_owner_local_def_id = tcx.hir().enclosing_body_owner(hir_id); - tcx.optimized_mir(body_owner_local_def_id.to_def_id()) + if tcx.hir().body_owner_kind(body_owner_local_def_id).is_fn_or_closure() { + Some(tcx.optimized_mir(body_owner_local_def_id.to_def_id())) + } else { + None + } } /// Tries to determine the `Local` corresponding to `expr`, if any. /// This function is expensive and should be used sparingly. pub fn expr_local(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> Option { - let mir = enclosing_mir(tcx, expr.hir_id); - mir.local_decls.iter_enumerated().find_map(|(local, local_decl)| { - if local_decl.source_info.span == expr.span { - Some(local) - } else { - None - } + enclosing_mir(tcx, expr.hir_id).and_then(|mir| { + mir.local_decls.iter_enumerated().find_map(|(local, local_decl)| { + if local_decl.source_info.span == expr.span { + Some(local) + } else { + None + } + }) }) } From 8befd920d6f921760580267ce33179437b4fd990 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Sun, 9 Jul 2023 09:26:05 +0300 Subject: [PATCH 217/324] Remove old section about downloading the server from the manual --- docs/user/manual.adoc | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc index b23c7c35d5d7..31035c4b7295 100644 --- a/docs/user/manual.adoc +++ b/docs/user/manual.adoc @@ -64,22 +64,8 @@ You can install the latest release of the plugin from https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer[the marketplace]. Note that the plugin may cause conflicts with the -https://marketplace.visualstudio.com/items?itemName=rust-lang.rust[official Rust plugin]. -It is recommended to disable the Rust plugin when using the rust-analyzer extension. - -By default, the plugin will prompt you to download the matching version of the server as well: - -image::https://user-images.githubusercontent.com/9021944/75067008-17502500-54ba-11ea-835a-f92aac50e866.png[] - -[NOTE] -==== -To disable this notification put the following to `settings.json` - -[source,json] ----- -{ "rust-analyzer.updates.askBeforeDownload": false } ----- -==== +https://marketplace.visualstudio.com/items?itemName=rust-lang.rust[previous official Rust plugin]. +The latter is no longer maintained and should be uninstalled. The server binary is stored in the extension install directory, which starts with `rust-lang.rust-analyzer-` and is located under: From 35f2e82e0b381f2f324970fc1464ad29a1151a96 Mon Sep 17 00:00:00 2001 From: DropDemBits Date: Sun, 9 Jul 2023 02:32:44 -0400 Subject: [PATCH 218/324] Don't show `add_missing_match_arms` when not needed `does_not_fill_wildcard_with_wildcard` and `does_not_fill_wildcard_with_partial_wildcard_and_wildcard` both made no modifications to the code, which is a problem for mutable ast porting as it generates a best-effort minimal set of text edits, and assists require at least one text edit. --- .../src/handlers/add_missing_match_arms.rs | 79 +++++++++++-------- 1 file changed, 45 insertions(+), 34 deletions(-) diff --git a/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/crates/ide-assists/src/handlers/add_missing_match_arms.rs index 7384390f28b5..2c7d8fc63a25 100644 --- a/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -75,14 +75,18 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) .collect(); let module = ctx.sema.scope(expr.syntax())?.module(); - let (mut missing_pats, is_non_exhaustive): ( + let (mut missing_pats, is_non_exhaustive, has_hidden_variants): ( Peekable>>, bool, + bool, ) = if let Some(enum_def) = resolve_enum_def(&ctx.sema, &expr) { let is_non_exhaustive = enum_def.is_non_exhaustive(ctx.db(), module.krate()); let variants = enum_def.variants(ctx.db()); + let has_hidden_variants = + variants.iter().any(|variant| variant.should_be_hidden(ctx.db(), module.krate())); + let missing_pats = variants .into_iter() .filter_map(|variant| { @@ -101,7 +105,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) } else { Box::new(missing_pats) }; - (missing_pats.peekable(), is_non_exhaustive) + (missing_pats.peekable(), is_non_exhaustive, has_hidden_variants) } else if let Some(enum_defs) = resolve_tuple_of_enum_def(&ctx.sema, &expr) { let is_non_exhaustive = enum_defs.iter().any(|enum_def| enum_def.is_non_exhaustive(ctx.db(), module.krate())); @@ -124,6 +128,12 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) if n_arms > 256 { return None; } + + let has_hidden_variants = variants_of_enums + .iter() + .flatten() + .any(|variant| variant.should_be_hidden(ctx.db(), module.krate())); + let missing_pats = variants_of_enums .into_iter() .multi_cartesian_product() @@ -139,7 +149,11 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) (ast::Pat::from(make::tuple_pat(patterns)), is_hidden) }) .filter(|(variant_pat, _)| is_variant_missing(&top_lvl_pats, variant_pat)); - ((Box::new(missing_pats) as Box>).peekable(), is_non_exhaustive) + ( + (Box::new(missing_pats) as Box>).peekable(), + is_non_exhaustive, + has_hidden_variants, + ) } else if let Some((enum_def, len)) = resolve_array_of_enum_def(&ctx.sema, &expr) { let is_non_exhaustive = enum_def.is_non_exhaustive(ctx.db(), module.krate()); let variants = enum_def.variants(ctx.db()); @@ -148,6 +162,9 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) return None; } + let has_hidden_variants = + variants.iter().any(|variant| variant.should_be_hidden(ctx.db(), module.krate())); + let variants_of_enums = vec![variants; len]; let missing_pats = variants_of_enums @@ -164,14 +181,20 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) (ast::Pat::from(make::slice_pat(patterns)), is_hidden) }) .filter(|(variant_pat, _)| is_variant_missing(&top_lvl_pats, variant_pat)); - ((Box::new(missing_pats) as Box>).peekable(), is_non_exhaustive) + ( + (Box::new(missing_pats) as Box>).peekable(), + is_non_exhaustive, + has_hidden_variants, + ) } else { return None; }; let mut needs_catch_all_arm = is_non_exhaustive && !has_catch_all_arm; - if !needs_catch_all_arm && missing_pats.peek().is_none() { + if !needs_catch_all_arm + && ((has_hidden_variants && has_catch_all_arm) || missing_pats.peek().is_none()) + { return None; } @@ -181,11 +204,17 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) target_range, |builder| { let new_match_arm_list = match_arm_list.clone_for_update(); - let missing_arms = missing_pats - .map(|(pat, hidden)| { - (make::match_arm(iter::once(pat), None, make::ext::expr_todo()), hidden) + + // having any hidden variants means that we need a catch-all arm + needs_catch_all_arm |= has_hidden_variants; + + let missing_arms = missing_pats.filter_map(|(pat, hidden)| { + // filter out hidden patterns because they're handled by the catch-all arm + (!hidden).then(|| { + make::match_arm(iter::once(pat), None, make::ext::expr_todo()) + .clone_for_update() }) - .map(|(it, hidden)| (it.clone_for_update(), hidden)); + }); let catch_all_arm = new_match_arm_list .arms() @@ -204,15 +233,13 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) cov_mark::hit!(add_missing_match_arms_empty_expr); } } + let mut first_new_arm = None; - for (arm, hidden) in missing_arms { - if hidden { - needs_catch_all_arm = !has_catch_all_arm; - } else { - first_new_arm.get_or_insert_with(|| arm.clone()); - new_match_arm_list.add_arm(arm); - } + for arm in missing_arms { + first_new_arm.get_or_insert_with(|| arm.clone()); + new_match_arm_list.add_arm(arm); } + if needs_catch_all_arm && !has_catch_all_arm { cov_mark::hit!(added_wildcard_pattern); let arm = make::match_arm( @@ -1621,10 +1648,9 @@ pub enum E { #[doc(hidden)] A, } ); } - // FIXME: I don't think the assist should be applicable in this case #[test] fn does_not_fill_wildcard_with_wildcard() { - check_assist( + check_assist_not_applicable( add_missing_match_arms, r#" //- /main.rs crate:main deps:e @@ -1635,13 +1661,6 @@ fn foo(t: ::e::E) { } //- /e.rs crate:e pub enum E { #[doc(hidden)] A, } -"#, - r#" -fn foo(t: ::e::E) { - match t { - _ => todo!(), - } -} "#, ); } @@ -1777,7 +1796,7 @@ fn foo(t: ::e::E, b: bool) { #[test] fn does_not_fill_wildcard_with_partial_wildcard_and_wildcard() { - check_assist( + check_assist_not_applicable( add_missing_match_arms, r#" //- /main.rs crate:main deps:e @@ -1789,14 +1808,6 @@ fn foo(t: ::e::E, b: bool) { } //- /e.rs crate:e pub enum E { #[doc(hidden)] A, }"#, - r#" -fn foo(t: ::e::E, b: bool) { - match t { - _ if b => todo!(), - _ => todo!(), - } -} -"#, ); } From aa52cbf784b17819663f9a2b0b68e63460957a79 Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Sun, 9 Jul 2023 23:17:51 +0330 Subject: [PATCH 219/324] Support read_via_copy intrinsic --- .../hir-ty/src/consteval/tests/intrinsics.rs | 18 ++++++++++++++++++ crates/hir-ty/src/mir/eval/shim.rs | 7 +++++++ 2 files changed, 25 insertions(+) diff --git a/crates/hir-ty/src/consteval/tests/intrinsics.rs b/crates/hir-ty/src/consteval/tests/intrinsics.rs index b74133e24f10..89f3a6d49058 100644 --- a/crates/hir-ty/src/consteval/tests/intrinsics.rs +++ b/crates/hir-ty/src/consteval/tests/intrinsics.rs @@ -163,6 +163,24 @@ fn transmute() { ); } +#[test] +fn read_via_copy() { + check_number( + r#" + extern "rust-intrinsic" { + pub fn read_via_copy(e: *const T) -> T; + pub fn volatile_load(e: *const T) -> T; + } + + const GOAL: i32 = { + let x = 2; + read_via_copy(&x) + volatile_load(&x) + }; + "#, + 4, + ); +} + #[test] fn const_eval_select() { check_number( diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs index 6cdf9f03c91f..8f22bb365688 100644 --- a/crates/hir-ty/src/mir/eval/shim.rs +++ b/crates/hir-ty/src/mir/eval/shim.rs @@ -888,6 +888,13 @@ impl Evaluator<'_> { } not_supported!("FnOnce was not available for executing const_eval_select"); } + "read_via_copy" | "volatile_load" => { + let [arg] = args else { + return Err(MirEvalError::TypeError("read_via_copy args are not provided")); + }; + let addr = Address::from_bytes(arg.interval.get(self)?)?; + destination.write_from_interval(self, Interval { addr, size: destination.size }) + } _ => not_supported!("unknown intrinsic {name}"), } } From d0df00d2742e6a3e6b499e403926bde09ca19f0f Mon Sep 17 00:00:00 2001 From: Adenine Date: Sun, 9 Jul 2023 16:11:15 -0400 Subject: [PATCH 220/324] Rework view memory layout tests to use expect_test and to_strings. --- crates/ide/src/view_memory_layout.rs | 230 ++++++++++++++++----------- 1 file changed, 133 insertions(+), 97 deletions(-) diff --git a/crates/ide/src/view_memory_layout.rs b/crates/ide/src/view_memory_layout.rs index ae8dd504e3e0..2f6332abd259 100644 --- a/crates/ide/src/view_memory_layout.rs +++ b/crates/ide/src/view_memory_layout.rs @@ -1,3 +1,5 @@ +use std::fmt; + use hir::{Field, HirDisplay, Layout, Semantics, Type}; use ide_db::{ defs::Definition, @@ -23,6 +25,36 @@ pub struct RecursiveMemoryLayout { pub nodes: Vec, } +// NOTE: this is currently strictly for testing and so isn't super useful as a visualization tool, however it could be adapted to become one? +impl fmt::Display for RecursiveMemoryLayout { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fn process( + fmt: &mut fmt::Formatter<'_>, + nodes: &Vec, + idx: usize, + depth: usize, + ) -> fmt::Result { + let mut out = "\t".repeat(depth); + let node = &nodes[idx]; + out += &format!( + "{}: {} (size: {}, align: {}, field offset: {})\n", + node.item_name, node.typename, node.size, node.alignment, node.offset + ); + write!(fmt, "{}", out)?; + if node.children_start != -1 { + for j in nodes[idx].children_start + ..(nodes[idx].children_start + nodes[idx].children_len as i64) + { + process(fmt, nodes, j as usize, depth + 1)?; + } + } + Ok(()) + } + + process(fmt, &self.nodes, 0, 0) + } +} + enum FieldOrTupleIdx { Field(Field), TupleIdx(usize), @@ -191,6 +223,7 @@ mod tests { use super::*; use crate::fixture; + use expect_test::expect; fn make_memory_layout(ra_fixture: &str) -> Option { let (analysis, position, _) = fixture::annotations(ra_fixture); @@ -198,15 +231,6 @@ mod tests { view_memory_layout(&analysis.db, position) } - fn check_item_info(node: &MemoryLayoutNode, item_name: &str, check_typename: bool) { - assert_eq!(node.item_name, item_name); - assert_eq!(node.size, core::mem::size_of::() as u64); - assert_eq!(node.alignment, core::mem::align_of::() as u64); - if check_typename { - assert_eq!(node.typename, std::any::type_name::()); - } - } - #[test] fn view_memory_layout_none() { assert!(make_memory_layout(r#"$0"#).is_none()); @@ -215,75 +239,88 @@ mod tests { #[test] fn view_memory_layout_primitive() { - let ml = make_memory_layout( - r#" + expect![[r#" + foo: i32 (size: 4, align: 4, field offset: 0) + "#]] + .assert_eq( + &make_memory_layout( + r#" fn main() { let foo$0 = 109; // default i32 } "#, - ) - .unwrap(); - - assert_eq!(ml.nodes.len(), 1); - assert_eq!(ml.nodes[0].parent_idx, -1); - assert_eq!(ml.nodes[0].children_start, -1); - check_item_info::(&ml.nodes[0], "foo", true); - assert_eq!(ml.nodes[0].offset, 0); + ) + .unwrap() + .to_string(), + ); } #[test] fn view_memory_layout_constant() { - let ml = make_memory_layout( - r#" + expect![[r#" + BLAH: bool (size: 1, align: 1, field offset: 0) + "#]] + .assert_eq( + &make_memory_layout( + r#" const BLAH$0: bool = 0; "#, - ) - .unwrap(); - - assert_eq!(ml.nodes.len(), 1); - assert_eq!(ml.nodes[0].parent_idx, -1); - assert_eq!(ml.nodes[0].children_start, -1); - check_item_info::(&ml.nodes[0], "BLAH", true); - assert_eq!(ml.nodes[0].offset, 0); + ) + .unwrap() + .to_string(), + ); } #[test] fn view_memory_layout_static() { - let ml = make_memory_layout( - r#" + expect![[r#" + BLAH: bool (size: 1, align: 1, field offset: 0) + "#]] + .assert_eq( + &make_memory_layout( + r#" static BLAH$0: bool = 0; "#, - ) - .unwrap(); - - assert_eq!(ml.nodes.len(), 1); - assert_eq!(ml.nodes[0].parent_idx, -1); - assert_eq!(ml.nodes[0].children_start, -1); - check_item_info::(&ml.nodes[0], "BLAH", true); - assert_eq!(ml.nodes[0].offset, 0); + ) + .unwrap() + .to_string(), + ); } #[test] fn view_memory_layout_tuple() { - let ml = make_memory_layout( - r#" + expect![[r#" + x: (f64, u8, i64) (size: 24, align: 8, field offset: 0) + .0: f64 (size: 8, align: 8, field offset: 0) + .1: u8 (size: 1, align: 1, field offset: 8) + .2: i64 (size: 8, align: 8, field offset: 16) + "#]] + .assert_eq( + &make_memory_layout( + r#" fn main() { let x$0 = (101.0, 111u8, 119i64); } - "#, - ) - .unwrap(); - - assert_eq!(ml.nodes.len(), 4); - assert_eq!(ml.nodes[0].children_start, 1); - assert_eq!(ml.nodes[0].children_len, 3); - check_item_info::<(f64, u8, i64)>(&ml.nodes[0], "x", true); +"#, + ) + .unwrap() + .to_string(), + ); } #[test] - fn view_memory_layout_struct() { - let ml = make_memory_layout( - r#" + fn view_memory_layout_c_struct() { + expect![[r#" + [ROOT]: Blah (size: 16, align: 4, field offset: 0) + a: u32 (size: 4, align: 4, field offset: 0) + b: (i32, u8) (size: 8, align: 4, field offset: 4) + .0: i32 (size: 4, align: 4, field offset: 0) + .1: u8 (size: 1, align: 1, field offset: 4) + c: i8 (size: 1, align: 1, field offset: 12) + "#]] + .assert_eq( + &make_memory_layout( + r#" #[repr(C)] struct Blah$0 { a: u32, @@ -291,47 +328,54 @@ struct Blah$0 { c: i8, } "#, - ) - .unwrap(); + ) + .unwrap() + .to_string(), + ); + } - #[repr(C)] // repr C makes this testable, rustc doesn't enforce a layout otherwise ;-; - struct Blah { - a: u32, - b: (i32, u8), - c: i8, - } - - assert_eq!(ml.nodes.len(), 6); - check_item_info::(&ml.nodes[0], "[ROOT]", false); - assert_eq!(ml.nodes[0].offset, 0); - - check_item_info::(&ml.nodes[1], "a", true); - assert_eq!(ml.nodes[1].offset, 0); - - check_item_info::<(i32, u8)>(&ml.nodes[2], "b", true); - assert_eq!(ml.nodes[2].offset, 4); - - check_item_info::(&ml.nodes[3], "c", true); - assert_eq!(ml.nodes[3].offset, 12); + #[test] + fn view_memory_layout_struct() { + expect![[r#" + [ROOT]: Blah (size: 16, align: 4, field offset: 0) + b: (i32, u8) (size: 8, align: 4, field offset: 0) + .0: i32 (size: 4, align: 4, field offset: 0) + .1: u8 (size: 1, align: 1, field offset: 4) + a: u32 (size: 4, align: 4, field offset: 8) + c: i8 (size: 1, align: 1, field offset: 12) + "#]] + .assert_eq( + &make_memory_layout( + r#" +struct Blah$0 { + a: u32, + b: (i32, u8), + c: i8, +} +"#, + ) + .unwrap() + .to_string(), + ); } #[test] fn view_memory_layout_member() { - let ml = make_memory_layout( - r#" + expect![[r#" + a: bool (size: 1, align: 1, field offset: 0) + "#]] + .assert_eq( + &make_memory_layout( + r#" +#[repr(C)] struct Oof { - a$0: bool + a$0: bool, } "#, - ) - .unwrap(); - - assert_eq!(ml.nodes.len(), 1); - assert_eq!(ml.nodes[0].parent_idx, -1); - assert_eq!(ml.nodes[0].children_start, -1); - check_item_info::(&ml.nodes[0], "a", true); - // NOTE: this should not give the memory layout relative to the parent structure, but the type referred to by the member variable alone. - assert_eq!(ml.nodes[0].offset, 0); + ) + .unwrap() + .to_string(), + ); } #[test] @@ -345,9 +389,10 @@ struct X { } type Foo$0 = X; - "#, +"#, ) .unwrap(); + let ml_b = make_memory_layout( r#" struct X$0 { @@ -355,19 +400,10 @@ struct X$0 { b: i8, c: (f32, f32), } - "#, +"#, ) .unwrap(); - ml_a.nodes.iter().zip(ml_b.nodes.iter()).for_each(|(a, b)| { - assert_eq!(a.item_name, b.item_name); - assert_eq!(a.typename, b.typename); - assert_eq!(a.size, b.size); - assert_eq!(a.alignment, b.alignment); - assert_eq!(a.offset, b.offset); - assert_eq!(a.parent_idx, b.parent_idx); - assert_eq!(a.children_start, b.children_start); - assert_eq!(a.children_len, b.children_len); - }) + assert_eq!(ml_a.to_string(), ml_b.to_string()); } } From 42d35f8af91e2788b342d13a64b9966d7f0e41e1 Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Mon, 10 Jul 2023 01:01:59 +0330 Subject: [PATCH 221/324] Fix missing terminator in pattern matching of consts --- crates/hir-ty/src/mir/lower/pattern_matching.rs | 7 ++++++- .../src/handlers/mutability_errors.rs | 16 ++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/crates/hir-ty/src/mir/lower/pattern_matching.rs b/crates/hir-ty/src/mir/lower/pattern_matching.rs index ff43c64a9e60..3354cbd76a0a 100644 --- a/crates/hir-ty/src/mir/lower/pattern_matching.rs +++ b/crates/hir-ty/src/mir/lower/pattern_matching.rs @@ -307,6 +307,11 @@ impl MirLowerCtx<'_> { mode, )?, None => { + // The path is not a variant, so it is a const + if mode != MatchingMode::Check { + // A const don't bind anything. Only needs check. + return Ok((current, current_else)); + } let unresolved_name = || MirLowerError::unresolved_path(self.db, p); let resolver = self.owner.resolver(self.db.upcast()); let pr = resolver @@ -362,8 +367,8 @@ impl MirLowerCtx<'_> { }, Pat::Lit(l) => match &self.body.exprs[*l] { Expr::Literal(l) => { - let c = self.lower_literal_to_operand(self.infer[pattern].clone(), l)?; if mode == MatchingMode::Check { + let c = self.lower_literal_to_operand(self.infer[pattern].clone(), l)?; self.pattern_match_const(current_else, current, c, cond_place, pattern)? } else { (current, current_else) diff --git a/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/crates/ide-diagnostics/src/handlers/mutability_errors.rs index 0a004c0647dc..935f12a39696 100644 --- a/crates/ide-diagnostics/src/handlers/mutability_errors.rs +++ b/crates/ide-diagnostics/src/handlers/mutability_errors.rs @@ -795,6 +795,22 @@ fn main() { //^^^^^ 💡 warn: variable does not need to be mutable f(x); } +"#, + ); + check_diagnostics( + r#" +struct Foo(i32); + +const X: Foo = Foo(5); +const Y: Foo = Foo(12); + +const fn f(mut a: Foo) -> bool { + //^^^^^ 💡 warn: variable does not need to be mutable + match a { + X | Y => true, + _ => false, + } +} "#, ); } From 6ab2788978282eefdc67429b10f11c2b5b58b6d5 Mon Sep 17 00:00:00 2001 From: DropDemBits Date: Sun, 9 Jul 2023 18:31:38 -0400 Subject: [PATCH 222/324] Migrate `add_missing_match_arms` to mutable ast Requires a hack in order to work inside of macros --- .../src/handlers/add_missing_match_arms.rs | 54 +++++++++++-------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/crates/ide-assists/src/handlers/add_missing_match_arms.rs index 2c7d8fc63a25..01d121cd89f5 100644 --- a/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -8,10 +8,7 @@ use itertools::Itertools; use syntax::ast::edit_in_place::Removable; use syntax::ast::{self, make, AstNode, HasName, MatchArmList, MatchExpr, Pat}; -use crate::{ - utils::{self, render_snippet, Cursor}, - AssistContext, AssistId, AssistKind, Assists, -}; +use crate::{utils, AssistContext, AssistId, AssistKind, Assists}; // Assist: add_missing_match_arms // @@ -202,7 +199,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) AssistId("add_missing_match_arms", AssistKind::QuickFix), "Fill match arms", target_range, - |builder| { + |edit| { let new_match_arm_list = match_arm_list.clone_for_update(); // having any hidden variants means that we need a catch-all arm @@ -252,24 +249,39 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) new_match_arm_list.add_arm(arm); } - let old_range = ctx.sema.original_range(match_arm_list.syntax()).range; - match (first_new_arm, ctx.config.snippet_cap) { - (Some(first_new_arm), Some(cap)) => { - let extend_lifetime; - let cursor = - match first_new_arm.syntax().descendants().find_map(ast::WildcardPat::cast) - { - Some(it) => { - extend_lifetime = it.syntax().clone(); - Cursor::Replace(&extend_lifetime) - } - None => Cursor::Before(first_new_arm.syntax()), - }; - let snippet = render_snippet(cap, new_match_arm_list.syntax(), cursor); - builder.replace_snippet(cap, old_range, snippet); + if let (Some(first_new_arm), Some(cap)) = (first_new_arm, ctx.config.snippet_cap) { + match first_new_arm.syntax().descendants().find_map(ast::WildcardPat::cast) { + Some(it) => edit.add_placeholder_snippet(cap, it), + None => edit.add_tabstop_before(cap, first_new_arm), } - _ => builder.replace(old_range, new_match_arm_list.to_string()), } + + // FIXME: Hack for mutable syntax trees not having great support for macros + // Just replace the element that the original range came from + let old_place = { + // Find the original element + let old_file_range = ctx.sema.original_range(match_arm_list.syntax()); + let file = ctx.sema.parse(old_file_range.file_id); + let old_place = file.syntax().covering_element(old_file_range.range); + + // Make `old_place` mut + match old_place { + syntax::SyntaxElement::Node(it) => { + syntax::SyntaxElement::from(edit.make_syntax_mut(it)) + } + syntax::SyntaxElement::Token(it) => { + // Don't have a way to make tokens mut, so instead make the parent mut + // and find the token again + let parent = edit.make_syntax_mut(it.parent().unwrap()); + let mut_token = + parent.covering_element(it.text_range()).into_token().unwrap(); + + syntax::SyntaxElement::from(mut_token) + } + } + }; + + syntax::ted::replace(old_place, new_match_arm_list.syntax()); }, ) } From 27444eda56214e80f55705be9595f7d98e80db56 Mon Sep 17 00:00:00 2001 From: DropDemBits Date: Sun, 9 Jul 2023 18:49:29 -0400 Subject: [PATCH 223/324] Migrate `promote_local_to_const` to mutable ast --- .../src/handlers/promote_local_to_const.rs | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/crates/ide-assists/src/handlers/promote_local_to_const.rs b/crates/ide-assists/src/handlers/promote_local_to_const.rs index 23153b4c566c..7a31a21be9ca 100644 --- a/crates/ide-assists/src/handlers/promote_local_to_const.rs +++ b/crates/ide-assists/src/handlers/promote_local_to_const.rs @@ -8,13 +8,10 @@ use ide_db::{ use stdx::to_upper_snake_case; use syntax::{ ast::{self, make, HasName}, - AstNode, WalkEvent, + ted, AstNode, WalkEvent, }; -use crate::{ - assist_context::{AssistContext, Assists}, - utils::{render_snippet, Cursor}, -}; +use crate::assist_context::{AssistContext, Assists}; // Assist: promote_local_to_const // @@ -75,24 +72,28 @@ pub(crate) fn promote_local_to_const(acc: &mut Assists, ctx: &AssistContext<'_>) AssistId("promote_local_to_const", AssistKind::Refactor), "Promote local to constant", target, - |builder| { + |edit| { let name = to_upper_snake_case(&name.to_string()); let usages = Definition::Local(local).usages(&ctx.sema).all(); if let Some(usages) = usages.references.get(&ctx.file_id()) { for usage in usages { - builder.replace(usage.range, &name); + let Some(usage) = usage.name.as_name_ref().cloned() else { + continue + }; + let usage = edit.make_mut(usage); + ted::replace(usage.syntax(), make::name_ref(&name).clone_for_update().syntax()); } } - let item = make::item_const(None, make::name(&name), make::ty(&ty), initializer); - match ctx.config.snippet_cap.zip(item.name()) { - Some((cap, name)) => builder.replace_snippet( - cap, - target, - render_snippet(cap, item.syntax(), Cursor::Before(name.syntax())), - ), - None => builder.replace(target, item.to_string()), + let item = make::item_const(None, make::name(&name), make::ty(&ty), initializer) + .clone_for_update(); + let let_stmt = edit.make_mut(let_stmt); + + if let Some((cap, name)) = ctx.config.snippet_cap.zip(item.name()) { + edit.add_tabstop_before(cap, name); } + + ted::replace(let_stmt.syntax(), item.syntax()); }, ) } From 8c40fa33df0e7f8964764311fcd6498f8d15b914 Mon Sep 17 00:00:00 2001 From: DropDemBits Date: Sun, 9 Jul 2023 20:50:20 -0400 Subject: [PATCH 224/324] Add `HasVisibilityEdit::set_visibility` --- crates/syntax/src/ast/edit_in_place.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs index 1f5ed206b4a9..606804aea25f 100644 --- a/crates/syntax/src/ast/edit_in_place.rs +++ b/crates/syntax/src/ast/edit_in_place.rs @@ -748,6 +748,27 @@ fn normalize_ws_between_braces(node: &SyntaxNode) -> Option<()> { Some(()) } +pub trait HasVisibilityEdit: ast::HasVisibility { + fn set_visibility(&self, visbility: ast::Visibility) { + match self.visibility() { + Some(current_visibility) => { + ted::replace(current_visibility.syntax(), visbility.syntax()) + } + None => { + let vis_before = self + .syntax() + .children_with_tokens() + .find(|it| !matches!(it.kind(), WHITESPACE | COMMENT | ATTR)) + .unwrap_or_else(|| self.syntax().first_child_or_token().unwrap()); + + ted::insert(ted::Position::before(vis_before), visbility.syntax()); + } + } + } +} + +impl HasVisibilityEdit for T {} + pub trait Indent: AstNode + Clone + Sized { fn indent_level(&self) -> IndentLevel { IndentLevel::from_node(self.syntax()) From d1575d1f544691ec3c5b24834b99df0a7df0534a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 9 Jul 2023 21:59:23 +0200 Subject: [PATCH 225/324] changelog: Fix typo in `needless_pass_by_ref_mut` lint description --- clippy_lints/src/needless_pass_by_ref_mut.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/needless_pass_by_ref_mut.rs b/clippy_lints/src/needless_pass_by_ref_mut.rs index 96cb09c071ac..46c9b6c4141f 100644 --- a/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -22,7 +22,7 @@ declare_clippy_lint! { /// ### What it does /// Check if a `&mut` function argument is actually used mutably. /// - /// Be careful if the function is publically reexported as it would break compatibility with + /// Be careful if the function is publicly reexported as it would break compatibility with /// users of this function. /// /// ### Why is this bad? From 23ac72316d7cf0c7979bf94544b2cc8f3ea3f89f Mon Sep 17 00:00:00 2001 From: y21 <30553356+y21@users.noreply.github.com> Date: Fri, 23 Jun 2023 23:23:36 +0200 Subject: [PATCH 226/324] adjust applicability and suggest making binding mutable --- clippy_lints/src/methods/filter_next.rs | 51 ++++++++++++++++++++----- tests/ui/methods_unfixable.rs | 10 +++++ tests/ui/methods_unfixable.stderr | 15 ++++++++ 3 files changed, 66 insertions(+), 10 deletions(-) create mode 100644 tests/ui/methods_unfixable.rs create mode 100644 tests/ui/methods_unfixable.stderr diff --git a/clippy_lints/src/methods/filter_next.rs b/clippy_lints/src/methods/filter_next.rs index ad71b4946190..ce7f9997b5a6 100644 --- a/clippy_lints/src/methods/filter_next.rs +++ b/clippy_lints/src/methods/filter_next.rs @@ -1,6 +1,7 @@ -use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::source::snippet; use clippy_utils::ty::implements_trait; +use rustc_ast::{BindingAnnotation, Mutability}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; @@ -8,6 +9,21 @@ use rustc_span::sym; use super::FILTER_NEXT; +fn path_to_local(expr: &hir::Expr<'_>) -> Option { + match expr.kind { + hir::ExprKind::Field(f, _) => path_to_local(f), + hir::ExprKind::Index(recv, _) => path_to_local(recv), + hir::ExprKind::Path(hir::QPath::Resolved( + _, + hir::Path { + res: rustc_hir::def::Res::Local(local), + .. + }, + )) => Some(*local), + _ => None, + } +} + /// lint use of `filter().next()` for `Iterators` pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, @@ -26,15 +42,30 @@ pub(super) fn check<'tcx>( if filter_snippet.lines().count() <= 1 { let iter_snippet = snippet(cx, recv.span, ".."); // add note if not multi-line - span_lint_and_sugg( - cx, - FILTER_NEXT, - expr.span, - msg, - "try", - format!("{iter_snippet}.find({filter_snippet})"), - Applicability::MachineApplicable, - ); + span_lint_and_then(cx, FILTER_NEXT, expr.span, msg, |diag| { + let (applicability, pat) = if let Some(id) = path_to_local(recv) + && let Some(hir::Node::Pat(pat)) = cx.tcx.hir().find(id) + && let hir::PatKind::Binding(BindingAnnotation(_, Mutability::Not), _, ident, _) = pat.kind + { + (Applicability::Unspecified, Some((pat.span, ident))) + } else { + (Applicability::MachineApplicable, None) + }; + + diag.span_suggestion( + expr.span, + "try", + format!("{iter_snippet}.find({filter_snippet})"), + applicability, + ); + + if let Some((pat_span, ident)) = pat { + diag.span_help( + pat_span, + format!("you will also need to make `{ident}` mutable, because `find` takes `&mut self`"), + ); + } + }); } else { span_lint(cx, FILTER_NEXT, expr.span, msg); } diff --git a/tests/ui/methods_unfixable.rs b/tests/ui/methods_unfixable.rs new file mode 100644 index 000000000000..3d88ce4b6bbd --- /dev/null +++ b/tests/ui/methods_unfixable.rs @@ -0,0 +1,10 @@ +#![warn(clippy::filter_next)] + +fn main() { + issue10029(); +} + +pub fn issue10029() { + let iter = (0..10); + let _ = iter.filter(|_| true).next(); +} diff --git a/tests/ui/methods_unfixable.stderr b/tests/ui/methods_unfixable.stderr new file mode 100644 index 000000000000..6e101fe16b09 --- /dev/null +++ b/tests/ui/methods_unfixable.stderr @@ -0,0 +1,15 @@ +error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead + --> $DIR/methods_unfixable.rs:9:13 + | +LL | let _ = iter.filter(|_| true).next(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `iter.find(|_| true)` + | +help: you will also need to make `iter` mutable, because `find` takes `&mut self` + --> $DIR/methods_unfixable.rs:8:9 + | +LL | let iter = (0..10); + | ^^^^ + = note: `-D clippy::filter-next` implied by `-D warnings` + +error: aborting due to previous error + From 0f09a7742d96fdac2863322b1c02af3e56c553ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Mon, 10 Jul 2023 13:40:37 +0300 Subject: [PATCH 227/324] Fix publishing of load-cargo crate --- crates/load-cargo/Cargo.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/load-cargo/Cargo.toml b/crates/load-cargo/Cargo.toml index 4a6946d7f617..f041ca88ac08 100644 --- a/crates/load-cargo/Cargo.toml +++ b/crates/load-cargo/Cargo.toml @@ -1,6 +1,8 @@ [package] name = "load-cargo" version = "0.0.0" +description = "TBD" + rust-version.workspace = true edition.workspace = true license.workspace = true From 4ff93398fd275d1ee9f31ee7d92ae59bf9559f60 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 10 Jul 2023 15:19:00 +0200 Subject: [PATCH 228/324] Skip buildin subtrees for builtin derives --- crates/hir-expand/src/builtin_derive_macro.rs | 86 ++++++----- crates/hir-expand/src/db.rs | 94 ++++++++---- crates/mbe/src/lib.rs | 3 +- crates/mbe/src/syntax_bridge.rs | 136 ++++++++++++++++++ 4 files changed, 243 insertions(+), 76 deletions(-) diff --git a/crates/hir-expand/src/builtin_derive_macro.rs b/crates/hir-expand/src/builtin_derive_macro.rs index 78218a83452c..c8c3cebb88e5 100644 --- a/crates/hir-expand/src/builtin_derive_macro.rs +++ b/crates/hir-expand/src/builtin_derive_macro.rs @@ -12,9 +12,7 @@ use crate::{ name::{AsName, Name}, tt::{self, TokenId}, }; -use syntax::ast::{ - self, AstNode, FieldList, HasAttrs, HasGenericParams, HasModuleItem, HasName, HasTypeBounds, -}; +use syntax::ast::{self, AstNode, FieldList, HasAttrs, HasGenericParams, HasName, HasTypeBounds}; use crate::{db::ExpandDatabase, name, quote, ExpandError, ExpandResult, MacroCallId}; @@ -30,12 +28,13 @@ macro_rules! register_builtin { &self, db: &dyn ExpandDatabase, id: MacroCallId, - tt: &tt::Subtree, + tt: &ast::Adt, + token_map: &TokenMap, ) -> ExpandResult { let expander = match *self { $( BuiltinDeriveExpander::$trait => $expand, )* }; - expander(db, id, tt) + expander(db, id, tt, token_map) } fn find_by_name(name: &name::Name) -> Option { @@ -118,13 +117,13 @@ impl VariantShape { } } - fn from(value: Option, token_map: &TokenMap) -> Result { + fn from(tm: &TokenMap, value: Option) -> Result { let r = match value { None => VariantShape::Unit, Some(FieldList::RecordFieldList(it)) => VariantShape::Struct( it.fields() .map(|it| it.name()) - .map(|it| name_to_token(token_map, it)) + .map(|it| name_to_token(tm, it)) .collect::>()?, ), Some(FieldList::TupleFieldList(it)) => VariantShape::Tuple(it.fields().count()), @@ -190,25 +189,12 @@ struct BasicAdtInfo { associated_types: Vec, } -fn parse_adt(tt: &tt::Subtree) -> Result { - let (parsed, token_map) = mbe::token_tree_to_syntax_node(tt, mbe::TopEntryPoint::MacroItems); - let macro_items = ast::MacroItems::cast(parsed.syntax_node()).ok_or_else(|| { - debug!("derive node didn't parse"); - ExpandError::other("invalid item definition") - })?; - let item = macro_items.items().next().ok_or_else(|| { - debug!("no module item parsed"); - ExpandError::other("no item found") - })?; - let adt = ast::Adt::cast(item.syntax().clone()).ok_or_else(|| { - debug!("expected adt, found: {:?}", item); - ExpandError::other("expected struct, enum or union") - })?; +fn parse_adt(tm: &TokenMap, adt: &ast::Adt) -> Result { let (name, generic_param_list, shape) = match &adt { ast::Adt::Struct(it) => ( it.name(), it.generic_param_list(), - AdtShape::Struct(VariantShape::from(it.field_list(), &token_map)?), + AdtShape::Struct(VariantShape::from(tm, it.field_list())?), ), ast::Adt::Enum(it) => { let default_variant = it @@ -227,8 +213,8 @@ fn parse_adt(tt: &tt::Subtree) -> Result { .flat_map(|it| it.variants()) .map(|it| { Ok(( - name_to_token(&token_map, it.name())?, - VariantShape::from(it.field_list(), &token_map)?, + name_to_token(tm, it.name())?, + VariantShape::from(tm, it.field_list())?, )) }) .collect::>()?, @@ -298,7 +284,7 @@ fn parse_adt(tt: &tt::Subtree) -> Result { }) .map(|it| mbe::syntax_node_to_token_tree(it.syntax()).0) .collect(); - let name_token = name_to_token(&token_map, name)?; + let name_token = name_to_token(&tm, name)?; Ok(BasicAdtInfo { name: name_token, shape, param_types, associated_types }) } @@ -345,11 +331,12 @@ fn name_to_token(token_map: &TokenMap, name: Option) -> Result tt::Subtree, ) -> ExpandResult { - let info = match parse_adt(tt) { + let info = match parse_adt(tm, tt) { Ok(info) => info, Err(e) => return ExpandResult::new(tt::Subtree::empty(), e), }; @@ -405,19 +392,21 @@ fn find_builtin_crate(db: &dyn ExpandDatabase, id: MacroCallId) -> tt::TokenTree fn copy_expand( db: &dyn ExpandDatabase, id: MacroCallId, - tt: &tt::Subtree, + tt: &ast::Adt, + tm: &TokenMap, ) -> ExpandResult { let krate = find_builtin_crate(db, id); - expand_simple_derive(tt, quote! { #krate::marker::Copy }, |_| quote! {}) + expand_simple_derive(tt, tm, quote! { #krate::marker::Copy }, |_| quote! {}) } fn clone_expand( db: &dyn ExpandDatabase, id: MacroCallId, - tt: &tt::Subtree, + tt: &ast::Adt, + tm: &TokenMap, ) -> ExpandResult { let krate = find_builtin_crate(db, id); - expand_simple_derive(tt, quote! { #krate::clone::Clone }, |adt| { + expand_simple_derive(tt, tm, quote! { #krate::clone::Clone }, |adt| { if matches!(adt.shape, AdtShape::Union) { let star = tt::Punct { char: '*', @@ -479,10 +468,11 @@ fn and_and() -> ::tt::Subtree { fn default_expand( db: &dyn ExpandDatabase, id: MacroCallId, - tt: &tt::Subtree, + tt: &ast::Adt, + tm: &TokenMap, ) -> ExpandResult { let krate = &find_builtin_crate(db, id); - expand_simple_derive(tt, quote! { #krate::default::Default }, |adt| { + expand_simple_derive(tt, tm, quote! { #krate::default::Default }, |adt| { let body = match &adt.shape { AdtShape::Struct(fields) => { let name = &adt.name; @@ -518,10 +508,11 @@ fn default_expand( fn debug_expand( db: &dyn ExpandDatabase, id: MacroCallId, - tt: &tt::Subtree, + tt: &ast::Adt, + tm: &TokenMap, ) -> ExpandResult { let krate = &find_builtin_crate(db, id); - expand_simple_derive(tt, quote! { #krate::fmt::Debug }, |adt| { + expand_simple_derive(tt, tm, quote! { #krate::fmt::Debug }, |adt| { let for_variant = |name: String, v: &VariantShape| match v { VariantShape::Struct(fields) => { let for_fields = fields.iter().map(|it| { @@ -598,10 +589,11 @@ fn debug_expand( fn hash_expand( db: &dyn ExpandDatabase, id: MacroCallId, - tt: &tt::Subtree, + tt: &ast::Adt, + tm: &TokenMap, ) -> ExpandResult { let krate = &find_builtin_crate(db, id); - expand_simple_derive(tt, quote! { #krate::hash::Hash }, |adt| { + expand_simple_derive(tt, tm, quote! { #krate::hash::Hash }, |adt| { if matches!(adt.shape, AdtShape::Union) { // FIXME: Return expand error here return quote! {}; @@ -646,19 +638,21 @@ fn hash_expand( fn eq_expand( db: &dyn ExpandDatabase, id: MacroCallId, - tt: &tt::Subtree, + tt: &ast::Adt, + tm: &TokenMap, ) -> ExpandResult { let krate = find_builtin_crate(db, id); - expand_simple_derive(tt, quote! { #krate::cmp::Eq }, |_| quote! {}) + expand_simple_derive(tt, tm, quote! { #krate::cmp::Eq }, |_| quote! {}) } fn partial_eq_expand( db: &dyn ExpandDatabase, id: MacroCallId, - tt: &tt::Subtree, + tt: &ast::Adt, + tm: &TokenMap, ) -> ExpandResult { let krate = find_builtin_crate(db, id); - expand_simple_derive(tt, quote! { #krate::cmp::PartialEq }, |adt| { + expand_simple_derive(tt, tm, quote! { #krate::cmp::PartialEq }, |adt| { if matches!(adt.shape, AdtShape::Union) { // FIXME: Return expand error here return quote! {}; @@ -722,10 +716,11 @@ fn self_and_other_patterns( fn ord_expand( db: &dyn ExpandDatabase, id: MacroCallId, - tt: &tt::Subtree, + tt: &ast::Adt, + tm: &TokenMap, ) -> ExpandResult { let krate = &find_builtin_crate(db, id); - expand_simple_derive(tt, quote! { #krate::cmp::Ord }, |adt| { + expand_simple_derive(tt, tm, quote! { #krate::cmp::Ord }, |adt| { fn compare( krate: &tt::TokenTree, left: tt::Subtree, @@ -786,10 +781,11 @@ fn ord_expand( fn partial_ord_expand( db: &dyn ExpandDatabase, id: MacroCallId, - tt: &tt::Subtree, + tt: &ast::Adt, + tm: &TokenMap, ) -> ExpandResult { let krate = &find_builtin_crate(db, id); - expand_simple_derive(tt, quote! { #krate::cmp::PartialOrd }, |adt| { + expand_simple_derive(tt, tm, quote! { #krate::cmp::PartialOrd }, |adt| { fn compare( krate: &tt::TokenTree, left: tt::Subtree, diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs index 3f08a0986931..f528dfed31ed 100644 --- a/crates/hir-expand/src/db.rs +++ b/crates/hir-expand/src/db.rs @@ -55,7 +55,9 @@ impl TokenExpander { TokenExpander::Builtin(it) => it.expand(db, id, tt).map_err(Into::into), TokenExpander::BuiltinEager(it) => it.expand(db, id, tt).map_err(Into::into), TokenExpander::BuiltinAttr(it) => it.expand(db, id, tt), - TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt), + TokenExpander::BuiltinDerive(_) => { + unreachable!("builtin derives should be expanded manually") + } TokenExpander::ProcMacro(_) => { unreachable!("ExpandDatabase::expand_proc_macro should be used for proc macros") } @@ -232,6 +234,11 @@ pub fn expand_speculative( MacroDefKind::BuiltInAttr(BuiltinAttrExpander::Derive, _) => { pseudo_derive_attr_expansion(&tt, attr_arg.as_ref()?) } + MacroDefKind::BuiltInDerive(expander, ..) => { + // this cast is a bit sus, can we avoid losing the typedness here? + let adt = ast::Adt::cast(speculative_args.clone()).unwrap(); + expander.expand(db, actual_macro_call, &adt, &spec_args_tmap) + } _ => macro_def.expand(db, actual_macro_call, &tt), }; @@ -333,6 +340,9 @@ fn macro_arg( Some(Arc::new((tt, tmap, fixups.undo_info))) } +/// Certain macro calls expect some nodes in the input to be preprocessed away, namely: +/// - derives expect all `#[derive(..)]` invocations up to the currently invoked one to be stripped +/// - attributes expect the invoking attribute to be stripped fn censor_for_macro_input(loc: &MacroCallLoc, node: &SyntaxNode) -> FxHashSet { // FIXME: handle `cfg_attr` (|| { @@ -451,37 +461,59 @@ fn macro_expand(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult return db.expand_proc_macro(id), + MacroDefKind::BuiltInDerive(expander, ..) => { + let arg = db.macro_arg_text(id).unwrap(); - let expander = match db.macro_def(loc.def) { - Ok(it) => it, - // FIXME: We should make sure to enforce a variant that invalid macro - // definitions do not get expanders that could reach this call path! - Err(err) => { - return ExpandResult { - value: Arc::new(tt::Subtree { - delimiter: tt::Delimiter::UNSPECIFIED, - token_trees: vec![], - }), - err: Some(ExpandError::other(format!("invalid macro definition: {err}"))), - } + let node = SyntaxNode::new_root(arg); + let censor = censor_for_macro_input(&loc, &node); + let mut fixups = fixup::fixup_syntax(&node); + fixups.replace.extend(censor.into_iter().map(|node| (node.into(), Vec::new()))); + let (tmap, _) = mbe::syntax_node_to_token_map_with_modifications( + &node, + fixups.token_map, + fixups.next_id, + fixups.replace, + fixups.append, + ); + + // this cast is a bit sus, can we avoid losing the typedness here? + let adt = ast::Adt::cast(node).unwrap(); + (expander.expand(db, id, &adt, &tmap), Some((tmap, fixups.undo_info))) + } + _ => { + let expander = match db.macro_def(loc.def) { + Ok(it) => it, + // FIXME: We should make sure to enforce a variant that invalid macro + // definitions do not get expanders that could reach this call path! + Err(err) => { + return ExpandResult { + value: Arc::new(tt::Subtree { + delimiter: tt::Delimiter::UNSPECIFIED, + token_trees: vec![], + }), + err: Some(ExpandError::other(format!("invalid macro definition: {err}"))), + } + } + }; + let Some(macro_arg) = db.macro_arg(id) else { + return ExpandResult { + value: Arc::new(tt::Subtree { + delimiter: tt::Delimiter::UNSPECIFIED, + token_trees: Vec::new(), + }), + // FIXME: We should make sure to enforce an invariant that invalid macro + // calls do not reach this call path! + err: Some(ExpandError::other("invalid token tree")), + }; + }; + let (arg, arg_tm, undo_info) = &*macro_arg; + let mut res = expander.expand(db, id, arg); + fixup::reverse_fixups(&mut res.value, arg_tm, undo_info); + (res, None) } }; - let Some(macro_arg) = db.macro_arg(id) else { - return ExpandResult { - value: Arc::new(tt::Subtree { - delimiter: tt::Delimiter::UNSPECIFIED, - token_trees: Vec::new(), - }), - // FIXME: We should make sure to enforce an invariant that invalid macro - // calls do not reach this call path! - err: Some(ExpandError::other("invalid token tree")), - }; - }; - let (arg_tt, arg_tm, undo_info) = &*macro_arg; - let ExpandResult { value: mut tt, mut err } = expander.expand(db, id, arg_tt); if let Some(EagerCallInfo { error, .. }) = loc.eager.as_deref() { // FIXME: We should report both errors! @@ -493,7 +525,9 @@ fn macro_expand(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult TokenMap { + syntax_node_to_token_map_with_modifications( + node, + Default::default(), + 0, + Default::default(), + Default::default(), + ) + .0 +} + +/// Convert the syntax node to a `TokenTree` (what macro will consume) +/// with the censored range excluded. +pub fn syntax_node_to_token_map_with_modifications( + node: &SyntaxNode, + existing_token_map: TokenMap, + next_id: u32, + replace: FxHashMap>, + append: FxHashMap>, +) -> (TokenMap, u32) { + let global_offset = node.text_range().start(); + let mut c = Converter::new(node, global_offset, existing_token_map, next_id, replace, append); + collect_tokens(&mut c); + c.id_alloc.map.shrink_to_fit(); + always!(c.replace.is_empty(), "replace: {:?}", c.replace); + always!(c.append.is_empty(), "append: {:?}", c.append); + (c.id_alloc.map, c.id_alloc.next_id) +} + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct SyntheticTokenId(pub u32); @@ -327,6 +358,111 @@ fn convert_tokens(conv: &mut C) -> tt::Subtree { } } +fn collect_tokens(conv: &mut C) { + struct StackEntry { + idx: usize, + open_range: TextRange, + delimiter: tt::DelimiterKind, + } + + let entry = StackEntry { + delimiter: tt::DelimiterKind::Invisible, + // never used (delimiter is `None`) + idx: !0, + open_range: TextRange::empty(TextSize::of('.')), + }; + let mut stack = NonEmptyVec::new(entry); + + loop { + let StackEntry { delimiter, .. } = stack.last_mut(); + let (token, range) = match conv.bump() { + Some(it) => it, + None => break, + }; + let synth_id = token.synthetic_id(conv); + + let kind = token.kind(conv); + if kind == COMMENT { + // Since `convert_doc_comment` can fail, we need to peek the next id, so that we can + // figure out which token id to use for the doc comment, if it is converted successfully. + let next_id = conv.id_alloc().peek_next_id(); + if let Some(_tokens) = conv.convert_doc_comment(&token, next_id) { + let id = conv.id_alloc().alloc(range, synth_id); + debug_assert_eq!(id, next_id); + } + continue; + } + if kind.is_punct() && kind != UNDERSCORE { + if synth_id.is_none() { + assert_eq!(range.len(), TextSize::of('.')); + } + + let expected = match delimiter { + tt::DelimiterKind::Parenthesis => Some(T![')']), + tt::DelimiterKind::Brace => Some(T!['}']), + tt::DelimiterKind::Bracket => Some(T![']']), + tt::DelimiterKind::Invisible => None, + }; + + if let Some(expected) = expected { + if kind == expected { + if let Some(entry) = stack.pop() { + conv.id_alloc().close_delim(entry.idx, Some(range)); + } + continue; + } + } + + let delim = match kind { + T!['('] => Some(tt::DelimiterKind::Parenthesis), + T!['{'] => Some(tt::DelimiterKind::Brace), + T!['['] => Some(tt::DelimiterKind::Bracket), + _ => None, + }; + + if let Some(kind) = delim { + let (_id, idx) = conv.id_alloc().open_delim(range, synth_id); + + stack.push(StackEntry { idx, open_range: range, delimiter: kind }); + continue; + } + + conv.id_alloc().alloc(range, synth_id); + } else { + macro_rules! make_leaf { + ($i:ident) => {{ + conv.id_alloc().alloc(range, synth_id); + }}; + } + match kind { + T![true] | T![false] => make_leaf!(Ident), + IDENT => make_leaf!(Ident), + UNDERSCORE => make_leaf!(Ident), + k if k.is_keyword() => make_leaf!(Ident), + k if k.is_literal() => make_leaf!(Literal), + LIFETIME_IDENT => { + let char_unit = TextSize::of('\''); + let r = TextRange::at(range.start(), char_unit); + conv.id_alloc().alloc(r, synth_id); + + let r = TextRange::at(range.start() + char_unit, range.len() - char_unit); + conv.id_alloc().alloc(r, synth_id); + continue; + } + _ => continue, + }; + }; + + // If we get here, we've consumed all input tokens. + // We might have more than one subtree in the stack, if the delimiters are improperly balanced. + // Merge them so we're left with one. + while let Some(entry) = stack.pop() { + conv.id_alloc().close_delim(entry.idx, None); + conv.id_alloc().alloc(entry.open_range, None); + } + } +} + fn is_single_token_op(kind: SyntaxKind) -> bool { matches!( kind, From fd31006646b3c9014b1770cf02ab2e9bca59c1e8 Mon Sep 17 00:00:00 2001 From: Tetsuharu Ohzeki Date: Mon, 10 Jul 2023 23:12:42 +0900 Subject: [PATCH 229/324] editor/code: Assert types in catch in `sendRequestWithRetry()` properly --- editors/code/src/util.ts | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/editors/code/src/util.ts b/editors/code/src/util.ts index b6b779e26601..688e3873ab4c 100644 --- a/editors/code/src/util.ts +++ b/editors/code/src/util.ts @@ -69,20 +69,24 @@ export async function sendRequestWithRetry( return await (token ? client.sendRequest(reqType, param, token) : client.sendRequest(reqType, param)); - } catch (error) { + } catch (error: unknown) { if (delay === null) { log.warn("LSP request timed out", { method: reqType.method, param, error }); throw error; } - if (error.code === lc.LSPErrorCodes.RequestCancelled) { - throw error; + + if (error instanceof lc.ResponseError) { + switch (error.code) { + case lc.LSPErrorCodes.RequestCancelled: + throw error; + case lc.LSPErrorCodes.ContentModified: + await sleep(delay); + continue; + } } - if (error.code !== lc.LSPErrorCodes.ContentModified) { - log.warn("LSP request failed", { method: reqType.method, param, error }); - throw error; - } - await sleep(delay); + log.warn("LSP request failed", { method: reqType.method, param, error }); + throw error; } } throw "unreachable"; From a66b7e3eba90690ed2860125c7d47932fddaff22 Mon Sep 17 00:00:00 2001 From: Tetsuharu Ohzeki Date: Mon, 10 Jul 2023 23:13:16 +0900 Subject: [PATCH 230/324] editor/code: Remove unused `sendRequestWithRetry` --- editors/code/src/util.ts | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/editors/code/src/util.ts b/editors/code/src/util.ts index 688e3873ab4c..b6240234aa6f 100644 --- a/editors/code/src/util.ts +++ b/editors/code/src/util.ts @@ -1,4 +1,3 @@ -import * as lc from "vscode-languageclient/node"; import * as vscode from "vscode"; import { strict as nativeAssert } from "assert"; import { exec, ExecOptions, spawnSync } from "child_process"; @@ -57,41 +56,6 @@ export const log = new (class { } })(); -export async function sendRequestWithRetry( - client: lc.LanguageClient, - reqType: lc.RequestType, - param: TParam, - token?: vscode.CancellationToken -): Promise { - // The sequence is `10 * (2 ** (2 * n))` where n is 1, 2, 3... - for (const delay of [40, 160, 640, 2560, 10240, null]) { - try { - return await (token - ? client.sendRequest(reqType, param, token) - : client.sendRequest(reqType, param)); - } catch (error: unknown) { - if (delay === null) { - log.warn("LSP request timed out", { method: reqType.method, param, error }); - throw error; - } - - if (error instanceof lc.ResponseError) { - switch (error.code) { - case lc.LSPErrorCodes.RequestCancelled: - throw error; - case lc.LSPErrorCodes.ContentModified: - await sleep(delay); - continue; - } - } - - log.warn("LSP request failed", { method: reqType.method, param, error }); - throw error; - } - } - throw "unreachable"; -} - export function sleep(ms: number) { return new Promise((resolve) => setTimeout(resolve, ms)); } From 444bc5b3ba366d2eab252e2c4f5c956a5e21df58 Mon Sep 17 00:00:00 2001 From: Tetsuharu Ohzeki Date: Mon, 10 Jul 2023 23:03:08 +0900 Subject: [PATCH 231/324] editor/code: Enable TypeScript's `--useUnknownInCatchVariables` option see: https://www.typescriptlang.org/tsconfig#useUnknownInCatchVariables --- editors/code/src/commands.ts | 4 ++-- editors/code/tests/unit/index.ts | 3 +++ editors/code/tsconfig.json | 1 - 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts index 17202e5345aa..94ec5e99c6a7 100644 --- a/editors/code/src/commands.ts +++ b/editors/code/src/commands.ts @@ -373,7 +373,7 @@ export function ssr(ctx: CtxInit): Cmd { selections, }); } catch (e) { - return e.toString(); + return String(e); } return null; }, @@ -1156,7 +1156,7 @@ export function viewMemoryLayout(ctx: CtxInit): Cmd { Document -