diff options
| -rw-r--r-- | src/bootstrap/src/core/build_steps/check.rs | 111 | ||||
| -rw-r--r-- | src/bootstrap/src/core/build_steps/clippy.rs | 307 | ||||
| -rw-r--r-- | src/bootstrap/src/core/build_steps/mod.rs | 1 | ||||
| -rw-r--r-- | src/bootstrap/src/core/builder.rs | 14 | ||||
| -rw-r--r-- | src/bootstrap/src/core/config/tests.rs | 2 |
5 files changed, 335 insertions, 100 deletions
diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 37d91b14ca1..654ef1ec6a7 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -11,6 +11,14 @@ use crate::core::config::TargetSelection; use crate::{Compiler, Mode, Subcommand}; use std::path::{Path, PathBuf}; +pub fn cargo_subcommand(kind: Kind) -> &'static str { + match kind { + Kind::Check | Kind::Clippy => "check", + Kind::Fix => "fix", + _ => unreachable!(), + } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Std { pub target: TargetSelection, @@ -22,97 +30,6 @@ pub struct Std { crates: Vec<String>, } -/// Returns args for the subcommand itself (not for cargo) -fn args(builder: &Builder<'_>) -> Vec<String> { - fn strings<'a>(arr: &'a [&str]) -> impl Iterator<Item = String> + 'a { - arr.iter().copied().map(String::from) - } - - if let Subcommand::Clippy { fix, allow_dirty, allow_staged, allow, deny, warn, forbid } = - &builder.config.cmd - { - // disable the most spammy clippy lints - let ignored_lints = [ - "many_single_char_names", // there are a lot in stdarch - "collapsible_if", - "type_complexity", - "missing_safety_doc", // almost 3K warnings - "too_many_arguments", - "needless_lifetimes", // people want to keep the lifetimes - "wrong_self_convention", - ]; - let mut args = vec![]; - if *fix { - #[rustfmt::skip] - args.extend(strings(&[ - "--fix", "-Zunstable-options", - // FIXME: currently, `--fix` gives an error while checking tests for libtest, - // possibly because libtest is not yet built in the sysroot. - // As a workaround, avoid checking tests and benches when passed --fix. - "--lib", "--bins", "--examples", - ])); - - if *allow_dirty { - args.push("--allow-dirty".to_owned()); - } - - if *allow_staged { - args.push("--allow-staged".to_owned()); - } - } - - args.extend(strings(&["--"])); - - if deny.is_empty() && forbid.is_empty() { - args.extend(strings(&["--cap-lints", "warn"])); - } - - let all_args = std::env::args().collect::<Vec<_>>(); - args.extend(get_clippy_rules_in_order(&all_args, allow, deny, warn, forbid)); - - args.extend(ignored_lints.iter().map(|lint| format!("-Aclippy::{}", lint))); - args.extend(builder.config.free_args.clone()); - args - } else { - builder.config.free_args.clone() - } -} - -/// We need to keep the order of the given clippy lint rules before passing them. -/// Since clap doesn't offer any useful interface for this purpose out of the box, -/// we have to handle it manually. -pub(crate) fn get_clippy_rules_in_order( - all_args: &[String], - allow_rules: &[String], - deny_rules: &[String], - warn_rules: &[String], - forbid_rules: &[String], -) -> Vec<String> { - let mut result = vec![]; - - for (prefix, item) in - [("-A", allow_rules), ("-D", deny_rules), ("-W", warn_rules), ("-F", forbid_rules)] - { - item.iter().for_each(|v| { - let rule = format!("{prefix}{v}"); - let position = all_args.iter().position(|t| t == &rule).unwrap(); - result.push((position, rule)); - }); - } - - result.sort_by_key(|&(position, _)| position); - result.into_iter().map(|v| v.1).collect() -} - -fn cargo_subcommand(kind: Kind) -> &'static str { - match kind { - Kind::Check => "check", - Kind::Clippy => "clippy", - Kind::Fix => "fix", - _ => unreachable!(), - } -} - impl Std { pub fn new(target: TargetSelection) -> Self { Self { target, crates: vec![] } @@ -164,7 +81,7 @@ impl Step for Std { run_cargo( builder, cargo, - args(builder), + builder.config.free_args.clone(), &libstd_stamp(builder, compiler, target), vec![], true, @@ -221,7 +138,7 @@ impl Step for Std { run_cargo( builder, cargo, - args(builder), + builder.config.free_args.clone(), &libstd_test_stamp(builder, compiler, target), vec![], true, @@ -318,7 +235,7 @@ impl Step for Rustc { run_cargo( builder, cargo, - args(builder), + builder.config.free_args.clone(), &librustc_stamp(builder, compiler, target), vec![], true, @@ -384,7 +301,7 @@ impl Step for CodegenBackend { run_cargo( builder, cargo, - args(builder), + builder.config.free_args.clone(), &codegen_backend_stamp(builder, compiler, target, backend), vec![], true, @@ -450,7 +367,7 @@ impl Step for RustAnalyzer { run_cargo( builder, cargo, - args(builder), + builder.config.free_args.clone(), &stamp(builder, compiler, target), vec![], true, @@ -513,7 +430,7 @@ macro_rules! tool_check_step { run_cargo( builder, cargo, - args(builder), + builder.config.free_args.clone(), &stamp(builder, compiler, target), vec![], true, diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs new file mode 100644 index 00000000000..e2c2d3c9ef8 --- /dev/null +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -0,0 +1,307 @@ +use std::path::Path; + +use crate::builder::Builder; +use crate::builder::ShouldRun; +use crate::core::builder; +use crate::core::builder::crate_description; +use crate::core::builder::Alias; +use crate::core::builder::RunConfig; +use crate::core::builder::Step; +use crate::Mode; +use crate::Subcommand; +use crate::TargetSelection; + +use super::check; +use super::compile; +use super::compile::librustc_stamp; +use super::compile::libstd_stamp; +use super::compile::run_cargo; +use super::compile::rustc_cargo; +use super::compile::std_cargo; +use super::tool::prepare_tool_cargo; +use super::tool::SourceType; + +// Disable the most spammy clippy lints +const IGNORED_RULES_FOR_STD_AND_RUSTC: &[&str] = &[ + "many_single_char_names", // there are a lot in stdarch + "collapsible_if", + "type_complexity", + "missing_safety_doc", // almost 3K warnings + "too_many_arguments", + "needless_lifetimes", // people want to keep the lifetimes + "wrong_self_convention", +]; + +fn lint_args(builder: &Builder<'_>, ignored_rules: &[&str]) -> Vec<String> { + fn strings<'a>(arr: &'a [&str]) -> impl Iterator<Item = String> + 'a { + arr.iter().copied().map(String::from) + } + + let Subcommand::Clippy { fix, allow_dirty, allow_staged, allow, deny, warn, forbid } = + &builder.config.cmd + else { + unreachable!("clippy::lint_args can only be called from `clippy` subcommands."); + }; + + let mut args = vec![]; + if *fix { + #[rustfmt::skip] + args.extend(strings(&[ + "--fix", "-Zunstable-options", + // FIXME: currently, `--fix` gives an error while checking tests for libtest, + // possibly because libtest is not yet built in the sysroot. + // As a workaround, avoid checking tests and benches when passed --fix. + "--lib", "--bins", "--examples", + ])); + + if *allow_dirty { + args.push("--allow-dirty".to_owned()); + } + + if *allow_staged { + args.push("--allow-staged".to_owned()); + } + } + + args.extend(strings(&["--"])); + + if deny.is_empty() && forbid.is_empty() { + args.extend(strings(&["--cap-lints", "warn"])); + } + + let all_args = std::env::args().collect::<Vec<_>>(); + args.extend(get_clippy_rules_in_order(&all_args, allow, deny, warn, forbid)); + + args.extend(ignored_rules.iter().map(|lint| format!("-Aclippy::{}", lint))); + args.extend(builder.config.free_args.clone()); + args +} + +/// We need to keep the order of the given clippy lint rules before passing them. +/// Since clap doesn't offer any useful interface for this purpose out of the box, +/// we have to handle it manually. +pub(crate) fn get_clippy_rules_in_order( + all_args: &[String], + allow_rules: &[String], + deny_rules: &[String], + warn_rules: &[String], + forbid_rules: &[String], +) -> Vec<String> { + let mut result = vec![]; + + for (prefix, item) in + [("-A", allow_rules), ("-D", deny_rules), ("-W", warn_rules), ("-F", forbid_rules)] + { + item.iter().for_each(|v| { + let rule = format!("{prefix}{v}"); + let position = all_args.iter().position(|t| t == &rule).unwrap(); + result.push((position, rule)); + }); + } + + result.sort_by_key(|&(position, _)| position); + result.into_iter().map(|v| v.1).collect() +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Std { + pub target: TargetSelection, + /// Whether to lint only a subset of crates. + crates: Vec<String>, +} + +impl Step for Std { + type Output = (); + const DEFAULT: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.crate_or_deps("sysroot").path("library") + } + + fn make_run(run: RunConfig<'_>) { + let crates = run.make_run_crates(Alias::Library); + run.builder.ensure(Std { target: run.target, crates }); + } + + fn run(self, builder: &Builder<'_>) { + builder.update_submodule(&Path::new("library").join("stdarch")); + + let target = self.target; + let compiler = builder.compiler(builder.top_stage, builder.config.build); + + let mut cargo = + builder::Cargo::new(builder, compiler, Mode::Std, SourceType::InTree, target, "clippy"); + + std_cargo(builder, target, compiler.stage, &mut cargo); + + if matches!(builder.config.cmd, Subcommand::Fix { .. }) { + // By default, cargo tries to fix all targets. Tell it not to fix tests until we've added `test` to the sysroot. + cargo.arg("--lib"); + } + + for krate in &*self.crates { + cargo.arg("-p").arg(krate); + } + + let _guard = builder.msg_check( + format_args!("library artifacts{}", crate_description(&self.crates)), + target, + ); + + run_cargo( + builder, + cargo, + lint_args(builder, IGNORED_RULES_FOR_STD_AND_RUSTC), + &libstd_stamp(builder, compiler, target), + vec![], + true, + false, + ); + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Rustc { + pub target: TargetSelection, + /// Whether to lint only a subset of crates. + crates: Vec<String>, +} + +impl Step for Rustc { + type Output = (); + const ONLY_HOSTS: bool = true; + const DEFAULT: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.crate_or_deps("rustc-main").path("compiler") + } + + fn make_run(run: RunConfig<'_>) { + let crates = run.make_run_crates(Alias::Compiler); + run.builder.ensure(Rustc { target: run.target, crates }); + } + + /// Lints the compiler. + /// + /// This will lint the compiler for a particular stage of the build using + /// the `compiler` targeting the `target` architecture. + fn run(self, builder: &Builder<'_>) { + let compiler = builder.compiler(builder.top_stage, builder.config.build); + let target = self.target; + + if compiler.stage != 0 { + // If we're not in stage 0, then we won't have a std from the beta + // compiler around. That means we need to make sure there's one in + // the sysroot for the compiler to find. Otherwise, we're going to + // fail when building crates that need to generate code (e.g., build + // scripts and their dependencies). + builder.ensure(compile::Std::new(compiler, compiler.host)); + builder.ensure(compile::Std::new(compiler, target)); + } else { + builder.ensure(check::Std::new(target)); + } + + let mut cargo = builder::Cargo::new( + builder, + compiler, + Mode::Rustc, + SourceType::InTree, + target, + "clippy", + ); + + rustc_cargo(builder, &mut cargo, target, compiler.stage); + + // Explicitly pass -p for all compiler crates -- this will force cargo + // to also check the tests/benches/examples for these crates, rather + // than just the leaf crate. + for krate in &*self.crates { + cargo.arg("-p").arg(krate); + } + + let _guard = builder.msg_check( + format_args!("compiler artifacts{}", crate_description(&self.crates)), + target, + ); + + run_cargo( + builder, + cargo, + lint_args(builder, IGNORED_RULES_FOR_STD_AND_RUSTC), + &librustc_stamp(builder, compiler, target), + vec![], + true, + false, + ); + } +} + +macro_rules! lint_any { + ($( + $name:ident, $path:expr, $tool_name:expr + $(,is_external_tool = $external:expr)* + $(,is_unstable_tool = $unstable:expr)* + $(,allow_features = $allow_features:expr)? + ; + )+) => { + $( + + #[derive(Debug, Clone, Hash, PartialEq, Eq)] + pub struct $name { + pub target: TargetSelection, + } + + impl Step for $name { + type Output = (); + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path($path) + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure($name { + target: run.target, + }); + } + + fn run(self, builder: &Builder<'_>) -> Self::Output { + let compiler = builder.compiler(builder.top_stage, builder.config.build); + let target = self.target; + + builder.ensure(check::Rustc::new(target, builder)); + + let cargo = prepare_tool_cargo( + builder, + compiler, + Mode::ToolRustc, + target, + "clippy", + $path, + SourceType::InTree, + &[], + ); + + run_cargo( + builder, + cargo, + lint_args(builder, &[]), + &libstd_stamp(builder, compiler, target), + vec![], + true, + false, + ); + } + } + )+ + } +} + +lint_any!( + Bootstrap, "src/bootstrap", "bootstrap"; + BuildHelper, "src/tools/build_helper", "build_helper"; + CoverageDump, "src/tools/coverage-dump", "coverage-dump"; + Tidy, "src/tools/tidy", "tidy"; + Compiletest, "src/tools/compiletest", "compiletest"; + RemoteTestServer, "src/tools/remote-test-server", "remote-test-server"; + RemoteTestClient, "src/tools/remote-test-client", "remote-test-client"; +); diff --git a/src/bootstrap/src/core/build_steps/mod.rs b/src/bootstrap/src/core/build_steps/mod.rs index 50d83789be8..9b7378165de 100644 --- a/src/bootstrap/src/core/build_steps/mod.rs +++ b/src/bootstrap/src/core/build_steps/mod.rs @@ -1,5 +1,6 @@ pub(crate) mod check; pub(crate) mod clean; +pub(crate) mod clippy; pub(crate) mod compile; pub(crate) mod dist; pub(crate) mod doc; diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index f31bc46d25f..6ee37acc905 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -13,7 +13,7 @@ use std::process::Command; use std::sync::OnceLock; use std::time::{Duration, Instant}; -use crate::core::build_steps::llvm; +use crate::core::build_steps::{clippy, llvm}; use crate::core::build_steps::tool::{self, SourceType}; use crate::core::build_steps::{check, clean, compile, dist, doc, install, run, setup, test}; use crate::core::config::flags::{Color, Subcommand}; @@ -726,7 +726,17 @@ impl<'a> Builder<'a> { tool::CoverageDump, tool::LlvmBitcodeLinker ), - Kind::Check | Kind::Clippy | Kind::Fix => describe!( + Kind::Clippy => describe!( + clippy::Std, + clippy::Rustc, + clippy::Bootstrap, + clippy::BuildHelper, + clippy::CoverageDump, + clippy::Tidy, + clippy::RemoteTestServer, + clippy::RemoteTestClient, + ), + Kind::Check | Kind::Fix => describe!( check::Std, check::Rustc, check::Rustdoc, diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs index 8cd538953c5..59e16b65427 100644 --- a/src/bootstrap/src/core/config/tests.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -1,5 +1,5 @@ use super::{flags::Flags, ChangeIdWrapper, Config}; -use crate::core::build_steps::check::get_clippy_rules_in_order; +use crate::core::build_steps::clippy::get_clippy_rules_in_order; use crate::core::config::{LldMode, TomlConfig}; use clap::CommandFactory; |
