From 81966faf792178b6960a59833cedc3f4232ac336 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Mon, 24 Mar 2025 15:13:24 -0400 Subject: [PATCH 1/4] chore: enable `rustc::internal` lints in ci --- .github/workflows/ci.yml | 3 +++ bevy_lint/src/lib.rs | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1e776220..dbfc9d5d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -88,6 +88,9 @@ jobs: sweep-cache: true - name: Run Clippy + env: + # Although we don't use any unstable options, this enables `rustc::internal` lints. + RUSTFLAGS: -Zunstable-options run: cargo clippy --workspace --all-targets ${{ matrix.features }} -- --deny warnings rustfmt: diff --git a/bevy_lint/src/lib.rs b/bevy_lint/src/lib.rs index e726399e..13a76fbb 100644 --- a/bevy_lint/src/lib.rs +++ b/bevy_lint/src/lib.rs @@ -9,7 +9,9 @@ #![feature(rustc_private)] // Allows chaining `if let` multiple times using `&&`. #![feature(let_chains)] -// Warn on internal `rustc` lints that check for poor usage of internal compiler APIs. +// Warn on internal `rustc` lints that check for poor usage of internal compiler APIs. Note that +// you also need to pass `-Z unstable-options` to `rustc` for this to be enabled: +// `RUSTFLAGS="-Zunstable-options" cargo check` #![warn(rustc::internal)] // This is a list of every single `rustc` crate used within this library. If you need another, add From 0ade2a037d889fd33f797d4c142b8fb92cd91492 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Mon, 24 Mar 2025 15:17:18 -0400 Subject: [PATCH 2/4] chore: silence `rustc::usage_of_ty_tykind` It has too many false-positives to be useful, unfortunately. --- bevy_lint/src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bevy_lint/src/lib.rs b/bevy_lint/src/lib.rs index 13a76fbb..e76b2bc5 100644 --- a/bevy_lint/src/lib.rs +++ b/bevy_lint/src/lib.rs @@ -13,6 +13,10 @@ // you also need to pass `-Z unstable-options` to `rustc` for this to be enabled: // `RUSTFLAGS="-Zunstable-options" cargo check` #![warn(rustc::internal)] +#![allow( + rustc::usage_of_ty_tykind, + reason = "Many false positives without a valid replacement." +)] // This is a list of every single `rustc` crate used within this library. If you need another, add // it here! From 3a029f358d72e68e0c5ebbfe67584aa81e8e5650 Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Mon, 24 Mar 2025 15:32:54 -0400 Subject: [PATCH 3/4] fix: `rustc` lint warnings --- bevy_lint/src/lib.rs | 1 + .../src/lints/duplicate_bevy_dependencies.rs | 23 +++++++++++-------- bevy_lint/src/lints/zst_query.rs | 4 ++-- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/bevy_lint/src/lib.rs b/bevy_lint/src/lib.rs index e76b2bc5..878b14e6 100644 --- a/bevy_lint/src/lib.rs +++ b/bevy_lint/src/lib.rs @@ -21,6 +21,7 @@ // This is a list of every single `rustc` crate used within this library. If you need another, add // it here! extern crate rustc_abi; +extern crate rustc_data_structures; extern crate rustc_driver; extern crate rustc_errors; extern crate rustc_hir; diff --git a/bevy_lint/src/lints/duplicate_bevy_dependencies.rs b/bevy_lint/src/lints/duplicate_bevy_dependencies.rs index 7a6a157c..d3e1465c 100644 --- a/bevy_lint/src/lints/duplicate_bevy_dependencies.rs +++ b/bevy_lint/src/lints/duplicate_bevy_dependencies.rs @@ -60,13 +60,7 @@ //! leafwing-input-manager = "0.16" //! ``` -use std::{ - collections::{BTreeMap, HashMap}, - ops::Range, - path::Path, - str::FromStr, - sync::Arc, -}; +use std::{collections::BTreeMap, ops::Range, path::Path, str::FromStr, sync::Arc}; use crate::declare_bevy_lint; use cargo_metadata::{ @@ -77,6 +71,7 @@ use clippy_utils::{ diagnostics::{span_lint, span_lint_and_then}, find_crates, }; +use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::LOCAL_CRATE; use rustc_lint::LateContext; use rustc_span::{BytePos, Pos, SourceFile, Span, Symbol, SyntaxContext}; @@ -121,7 +116,7 @@ pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata, bevy_symbol: Symb let local_name = cx.tcx.crate_name(LOCAL_CRATE); // get the package name and the corresponding version of `bevy` that they depend on - let mut bevy_dependents = HashMap::new(); + let mut bevy_dependents = FxHashMap::default(); for package in &metadata.packages { for dependency in &package.dependencies { if dependency.name.as_str() == "bevy" @@ -155,7 +150,7 @@ fn lint_with_target_version( cargo_toml: &CargoToml, file: &Arc, bevy_cargo: &Spanned, - bevy_dependents: &HashMap<&str, VersionReq>, + bevy_dependents: &FxHashMap<&str, VersionReq>, ) { // Semver only supports checking if a given `VersionReq` matches a `Version` and not if two // `VersionReq` can successfully resolve to one `Version`. Therefore we try to parse the @@ -167,6 +162,10 @@ fn lint_with_target_version( let bevy_cargo_toml_span = toml_span(bevy_cargo.span(), file); + #[allow( + rustc::potential_query_instability, + reason = "Iterating a hash map may lead to query instability, but the fix is not trivial." + )] let mismatching_dependencies = bevy_dependents .iter() .filter(|dependency| !dependency.1.matches(&target_version)); @@ -191,7 +190,7 @@ fn lint_with_target_version( fn minimal_lint( cx: &LateContext<'_>, - bevy_dependents: &HashMap<&str, VersionReq>, + bevy_dependents: &FxHashMap<&str, VersionReq>, resolved: &Resolve, ) { // Examples of the underlying string representation of resolved crates @@ -207,6 +206,10 @@ fn minimal_lint( } // Extract versions from external crates if let Some((id, _)) = node.id.repr.split_once('@') { + #[allow( + rustc::potential_query_instability, + reason = "This is deterministic because we do not depend on the order of keys with `any()`." + )] if bevy_dependents .keys() .any(|crate_name| id.ends_with(crate_name)) diff --git a/bevy_lint/src/lints/zst_query.rs b/bevy_lint/src/lints/zst_query.rs index cd4fd021..91a34e15 100644 --- a/bevy_lint/src/lints/zst_query.rs +++ b/bevy_lint/src/lints/zst_query.rs @@ -108,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for ZstQuery { hir_ty.span, ZST_QUERY.lint.desc, None, - query_kind.help(&peeled), + query_kind.help(peeled), ); } } @@ -127,7 +127,7 @@ impl QueryKind { } } - fn help(&self, ty: &Ty<'_>) -> String { + fn help(&self, ty: Ty<'_>) -> String { // It should be noted that `With` is not always the best filter to suggest. // While it's most often going to be what users want, there's also `Added` // and `Changed` which might be more appropriate in some cases From e70a4a6f3cbfef76edc01196d2563be87d94fdff Mon Sep 17 00:00:00 2001 From: BD103 <59022059+BD103@users.noreply.github.com> Date: Sat, 29 Mar 2025 12:45:25 -0400 Subject: [PATCH 4/4] fix: switch to `BTreeMap` for query stability --- .../src/lints/duplicate_bevy_dependencies.rs | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/bevy_lint/src/lints/duplicate_bevy_dependencies.rs b/bevy_lint/src/lints/duplicate_bevy_dependencies.rs index d3e1465c..acf6a44d 100644 --- a/bevy_lint/src/lints/duplicate_bevy_dependencies.rs +++ b/bevy_lint/src/lints/duplicate_bevy_dependencies.rs @@ -71,7 +71,6 @@ use clippy_utils::{ diagnostics::{span_lint, span_lint_and_then}, find_crates, }; -use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::LOCAL_CRATE; use rustc_lint::LateContext; use rustc_span::{BytePos, Pos, SourceFile, Span, Symbol, SyntaxContext}; @@ -116,7 +115,7 @@ pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata, bevy_symbol: Symb let local_name = cx.tcx.crate_name(LOCAL_CRATE); // get the package name and the corresponding version of `bevy` that they depend on - let mut bevy_dependents = FxHashMap::default(); + let mut bevy_dependents = BTreeMap::default(); for package in &metadata.packages { for dependency in &package.dependencies { if dependency.name.as_str() == "bevy" @@ -150,7 +149,7 @@ fn lint_with_target_version( cargo_toml: &CargoToml, file: &Arc, bevy_cargo: &Spanned, - bevy_dependents: &FxHashMap<&str, VersionReq>, + bevy_dependents: &BTreeMap<&str, VersionReq>, ) { // Semver only supports checking if a given `VersionReq` matches a `Version` and not if two // `VersionReq` can successfully resolve to one `Version`. Therefore we try to parse the @@ -162,10 +161,6 @@ fn lint_with_target_version( let bevy_cargo_toml_span = toml_span(bevy_cargo.span(), file); - #[allow( - rustc::potential_query_instability, - reason = "Iterating a hash map may lead to query instability, but the fix is not trivial." - )] let mismatching_dependencies = bevy_dependents .iter() .filter(|dependency| !dependency.1.matches(&target_version)); @@ -190,7 +185,7 @@ fn lint_with_target_version( fn minimal_lint( cx: &LateContext<'_>, - bevy_dependents: &FxHashMap<&str, VersionReq>, + bevy_dependents: &BTreeMap<&str, VersionReq>, resolved: &Resolve, ) { // Examples of the underlying string representation of resolved crates @@ -206,10 +201,6 @@ fn minimal_lint( } // Extract versions from external crates if let Some((id, _)) = node.id.repr.split_once('@') { - #[allow( - rustc::potential_query_instability, - reason = "This is deterministic because we do not depend on the order of keys with `any()`." - )] if bevy_dependents .keys() .any(|crate_name| id.ends_with(crate_name))