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::Kind;
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;
const IGNORED_RULES_FOR_STD_AND_RUSTC: &[&str] = &[
"many_single_char_names", "collapsible_if",
"type_complexity",
"missing_safety_doc", "too_many_arguments",
"needless_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",
"--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
}
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,
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);
for krate in &*self.crates {
cargo.arg("-p").arg(krate);
}
let _guard =
builder.msg_clippy(format_args!("library{}", 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,
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 });
}
fn run(self, builder: &Builder<'_>) {
let compiler = builder.compiler(builder.top_stage, builder.config.build);
let target = self.target;
if compiler.stage != 0 {
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);
for krate in &*self.crates {
cargo.arg("-p").arg(krate);
}
let _guard =
builder.msg_clippy(format_args!("compiler{}", 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, $readable_name:expr
$(,lint_by_default = $lint_by_default:expr)*
;
)+) => {
$(
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct $name {
pub target: TargetSelection,
}
impl Step for $name {
type Output = ();
const DEFAULT: bool = if false $(|| $lint_by_default)* { true } else { false };
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,
&[],
);
let _guard = builder.msg_tool(
Kind::Clippy,
Mode::ToolRustc,
$readable_name,
compiler.stage,
&compiler.host,
&target,
);
let stamp = builder
.cargo_out(compiler, Mode::ToolRustc, target)
.join(format!(".{}-check.stamp", stringify!($name).to_lowercase()));
run_cargo(
builder,
cargo,
lint_args(builder, &[]),
&stamp,
vec![],
true,
false,
);
}
}
)+
}
}
lint_any!(
Bootstrap, "src/bootstrap", "bootstrap";
BuildHelper, "src/tools/build_helper", "build_helper";
BuildManifest, "src/tools/build-manifest", "build-manifest";
CargoMiri, "src/tools/miri/cargo-miri", "cargo-miri";
Clippy, "src/tools/clippy", "clippy";
CollectLicenseMetadata, "src/tools/collect-license-metadata", "collect-license-metadata";
Compiletest, "src/tools/compiletest", "compiletest";
CoverageDump, "src/tools/coverage-dump", "coverage-dump";
Jsondocck, "src/tools/jsondocck", "jsondocck";
Jsondoclint, "src/tools/jsondoclint", "jsondoclint";
LintDocs, "src/tools/lint-docs", "lint-docs";
LlvmBitcodeLinker, "src/tools/llvm-bitcode-linker", "llvm-bitcode-linker";
Miri, "src/tools/miri", "miri";
MiroptTestTools, "src/tools/miropt-test-tools", "miropt-test-tools";
OptDist, "src/tools/opt-dist", "opt-dist";
RemoteTestClient, "src/tools/remote-test-client", "remote-test-client";
RemoteTestServer, "src/tools/remote-test-server", "remote-test-server";
Rls, "src/tools/rls", "rls";
RustAnalyzer, "src/tools/rust-analyzer", "rust-analyzer";
Rustdoc, "src/tools/rustdoc", "clippy";
Rustfmt, "src/tools/rustfmt", "rustfmt";
RustInstaller, "src/tools/rust-installer", "rust-installer";
Tidy, "src/tools/tidy", "tidy";
);