1use super::tool::{SourceType, prepare_tool_cargo};
17use crate::builder::{Builder, ShouldRun};
18use crate::core::build_steps::check::{CompilerForCheck, prepare_compiler_for_check};
19use crate::core::build_steps::compile::{
20 ArtifactKeepMode, run_cargo, rustc_cargo, std_cargo, std_crates_for_make_run,
21};
22use crate::core::builder;
23use crate::core::builder::{Alias, Kind, RunConfig, Step, StepMetadata, crate_description};
24use crate::utils::build_stamp::{self, BuildStamp};
25use crate::{Compiler, Mode, Subcommand, TargetSelection, exit};
26
27const IGNORED_RULES_FOR_STD_AND_RUSTC: &[&str] = &[
29 "many_single_char_names", "collapsible_if",
31 "type_complexity",
32 "missing_safety_doc", "too_many_arguments",
34 "needless_lifetimes", "wrong_self_convention",
36 "approx_constant", ];
38
39fn lint_args(builder: &Builder<'_>, config: &LintConfig, ignored_rules: &[&str]) -> Vec<String> {
40 fn strings<'a>(arr: &'a [&str]) -> impl Iterator<Item = String> + 'a {
41 arr.iter().copied().map(String::from)
42 }
43
44 let Subcommand::Clippy { fix, allow_dirty, allow_staged, .. } = &builder.config.cmd else {
45 unreachable!("clippy::lint_args can only be called from `clippy` subcommands.");
46 };
47
48 let mut args = vec![];
49 if *fix {
50 #[rustfmt::skip]
51 args.extend(strings(&[
52 "--fix", "-Zunstable-options",
53 "--lib", "--bins", "--examples",
57 ]));
58
59 if *allow_dirty {
60 args.push("--allow-dirty".to_owned());
61 }
62
63 if *allow_staged {
64 args.push("--allow-staged".to_owned());
65 }
66 }
67
68 args.extend(strings(&["--"]));
69
70 if config.deny.is_empty() && config.forbid.is_empty() {
71 args.extend(strings(&["--cap-lints", "warn"]));
72 }
73
74 let all_args = std::env::args().collect::<Vec<_>>();
75 args.extend(get_clippy_rules_in_order(&all_args, config));
76
77 args.extend(ignored_rules.iter().map(|lint| format!("-Aclippy::{lint}")));
78 args.extend(builder.config.free_args.clone());
79 args
80}
81
82pub fn get_clippy_rules_in_order(all_args: &[String], config: &LintConfig) -> Vec<String> {
86 let mut result = vec![];
87
88 for (prefix, item) in
89 [("-A", &config.allow), ("-D", &config.deny), ("-W", &config.warn), ("-F", &config.forbid)]
90 {
91 item.iter().for_each(|v| {
92 let rule = format!("{prefix}{v}");
93 let position = all_args.iter().position(|t| t == &rule || t == v).unwrap_or(usize::MAX);
96 result.push((position, rule));
97 });
98 }
99
100 result.sort_by_key(|&(position, _)| position);
101 result.into_iter().map(|v| v.1).collect()
102}
103
104#[derive(Debug, Clone, PartialEq, Eq, Hash)]
105pub struct LintConfig {
106 pub allow: Vec<String>,
107 pub warn: Vec<String>,
108 pub deny: Vec<String>,
109 pub forbid: Vec<String>,
110}
111
112impl LintConfig {
113 fn new(builder: &Builder<'_>) -> Self {
114 match builder.config.cmd.clone() {
115 Subcommand::Clippy { allow, deny, warn, forbid, .. } => {
116 Self { allow, warn, deny, forbid }
117 }
118 _ => unreachable!("LintConfig can only be called from `clippy` subcommands."),
119 }
120 }
121
122 fn merge(&self, other: &Self) -> Self {
123 let merged = |self_attr: &[String], other_attr: &[String]| -> Vec<String> {
124 self_attr.iter().cloned().chain(other_attr.iter().cloned()).collect()
125 };
126 Self {
128 allow: merged(&self.allow, &other.allow),
129 warn: merged(&self.warn, &other.warn),
130 deny: merged(&self.deny, &other.deny),
131 forbid: merged(&self.forbid, &other.forbid),
132 }
133 }
134}
135
136#[derive(Debug, Clone, PartialEq, Eq, Hash)]
137pub struct Std {
138 build_compiler: Compiler,
139 target: TargetSelection,
140 config: LintConfig,
141 crates: Vec<String>,
143}
144
145impl Std {
146 fn new(
147 builder: &Builder<'_>,
148 target: TargetSelection,
149 config: LintConfig,
150 crates: Vec<String>,
151 ) -> Self {
152 Self {
153 build_compiler: builder.compiler(builder.top_stage, builder.host_target),
154 target,
155 config,
156 crates,
157 }
158 }
159
160 fn from_build_compiler(
161 build_compiler: Compiler,
162 target: TargetSelection,
163 config: LintConfig,
164 crates: Vec<String>,
165 ) -> Self {
166 Self { build_compiler, target, config, crates }
167 }
168}
169
170impl Step for Std {
171 type Output = ();
172
173 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
174 run.crate_or_deps("sysroot").path("library")
175 }
176
177 fn is_default_step(_builder: &Builder<'_>) -> bool {
178 true
179 }
180
181 fn make_run(run: RunConfig<'_>) {
182 let crates = std_crates_for_make_run(&run);
183 let config = LintConfig::new(run.builder);
184 run.builder.ensure(Std::new(run.builder, run.target, config, crates));
185 }
186
187 fn run(self, builder: &Builder<'_>) {
188 let target = self.target;
189 let build_compiler = self.build_compiler;
190
191 let mut cargo = builder::Cargo::new(
192 builder,
193 build_compiler,
194 Mode::Std,
195 SourceType::InTree,
196 target,
197 Kind::Clippy,
198 );
199
200 std_cargo(builder, target, &mut cargo, &self.crates);
201
202 let _guard = builder.msg(
203 Kind::Clippy,
204 format_args!("library{}", crate_description(&self.crates)),
205 Mode::Std,
206 build_compiler,
207 target,
208 );
209
210 run_cargo(
211 builder,
212 cargo,
213 lint_args(builder, &self.config, IGNORED_RULES_FOR_STD_AND_RUSTC),
214 &build_stamp::libstd_stamp(builder, build_compiler, target),
215 vec![],
216 ArtifactKeepMode::OnlyRmeta,
217 );
218 }
219
220 fn metadata(&self) -> Option<StepMetadata> {
221 Some(StepMetadata::clippy("std", self.target).built_by(self.build_compiler))
222 }
223}
224
225#[derive(Debug, Clone, PartialEq, Eq, Hash)]
230pub struct Rustc {
231 build_compiler: CompilerForCheck,
232 target: TargetSelection,
233 config: LintConfig,
234 crates: Vec<String>,
236}
237
238impl Rustc {
239 fn new(
240 builder: &Builder<'_>,
241 target: TargetSelection,
242 config: LintConfig,
243 crates: Vec<String>,
244 ) -> Self {
245 Self {
246 build_compiler: prepare_compiler_for_check(builder, target, Mode::Rustc),
247 target,
248 config,
249 crates,
250 }
251 }
252}
253
254impl Step for Rustc {
255 type Output = ();
256 const IS_HOST: bool = true;
257
258 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
259 run.crate_or_deps("rustc-main").path("compiler")
260 }
261
262 fn is_default_step(_builder: &Builder<'_>) -> bool {
263 true
264 }
265
266 fn make_run(run: RunConfig<'_>) {
267 let builder = run.builder;
268 let crates = run.make_run_crates(Alias::Compiler);
269 let config = LintConfig::new(run.builder);
270 run.builder.ensure(Rustc::new(builder, run.target, config, crates));
271 }
272
273 fn run(self, builder: &Builder<'_>) {
274 let build_compiler = self.build_compiler.build_compiler();
275 let target = self.target;
276
277 let mut cargo = builder::Cargo::new(
278 builder,
279 build_compiler,
280 Mode::Rustc,
281 SourceType::InTree,
282 target,
283 Kind::Clippy,
284 );
285
286 rustc_cargo(builder, &mut cargo, target, &build_compiler, &self.crates);
287 self.build_compiler.configure_cargo(&mut cargo);
288
289 for krate in &*self.crates {
293 cargo.arg("-p").arg(krate);
294 }
295
296 let _guard = builder.msg(
297 Kind::Clippy,
298 format_args!("compiler{}", crate_description(&self.crates)),
299 Mode::Rustc,
300 build_compiler,
301 target,
302 );
303
304 run_cargo(
305 builder,
306 cargo,
307 lint_args(builder, &self.config, IGNORED_RULES_FOR_STD_AND_RUSTC),
308 &build_stamp::librustc_stamp(builder, build_compiler, target),
309 vec![],
310 ArtifactKeepMode::OnlyRmeta,
311 );
312 }
313
314 fn metadata(&self) -> Option<StepMetadata> {
315 Some(
316 StepMetadata::clippy("rustc", self.target)
317 .built_by(self.build_compiler.build_compiler()),
318 )
319 }
320}
321
322#[derive(Debug, Clone, Hash, PartialEq, Eq)]
323pub struct CodegenGcc {
324 build_compiler: CompilerForCheck,
325 target: TargetSelection,
326 config: LintConfig,
327}
328
329impl CodegenGcc {
330 fn new(builder: &Builder<'_>, target: TargetSelection, config: LintConfig) -> Self {
331 Self {
332 build_compiler: prepare_compiler_for_check(builder, target, Mode::Codegen),
333 target,
334 config,
335 }
336 }
337}
338
339impl Step for CodegenGcc {
340 type Output = ();
341
342 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
343 run.alias("rustc_codegen_gcc")
344 }
345
346 fn make_run(run: RunConfig<'_>) {
347 let builder = run.builder;
348 let config = LintConfig::new(builder);
349 builder.ensure(CodegenGcc::new(builder, run.target, config));
350 }
351
352 fn run(self, builder: &Builder<'_>) -> Self::Output {
353 let build_compiler = self.build_compiler.build_compiler();
354 let target = self.target;
355
356 let mut cargo = prepare_tool_cargo(
357 builder,
358 build_compiler,
359 Mode::Codegen,
360 target,
361 Kind::Clippy,
362 "compiler/rustc_codegen_gcc",
363 SourceType::InTree,
364 &[],
365 );
366 self.build_compiler.configure_cargo(&mut cargo);
367
368 let _guard = builder.msg(
369 Kind::Clippy,
370 "rustc_codegen_gcc",
371 Mode::ToolRustcPrivate,
372 build_compiler,
373 target,
374 );
375
376 let stamp = BuildStamp::new(&builder.cargo_out(build_compiler, Mode::Codegen, target))
377 .with_prefix("rustc_codegen_gcc-check");
378
379 let args = lint_args(builder, &self.config, &[]);
380 run_cargo(builder, cargo, args.clone(), &stamp, vec![], ArtifactKeepMode::OnlyRmeta);
381
382 let mut cargo = prepare_tool_cargo(
384 builder,
385 build_compiler,
386 Mode::Codegen,
387 target,
388 Kind::Clippy,
389 "compiler/rustc_codegen_gcc",
390 SourceType::InTree,
391 &[],
392 );
393 self.build_compiler.configure_cargo(&mut cargo);
394 println!("Now running clippy on `rustc_codegen_gcc` with `--no-default-features`");
395 cargo.arg("--no-default-features");
396 run_cargo(builder, cargo, args, &stamp, vec![], ArtifactKeepMode::OnlyRmeta);
397 }
398
399 fn metadata(&self) -> Option<StepMetadata> {
400 Some(
401 StepMetadata::clippy("rustc_codegen_gcc", self.target)
402 .built_by(self.build_compiler.build_compiler()),
403 )
404 }
405}
406
407macro_rules! lint_any {
408 ($(
409 $name:ident,
410 $path:expr,
411 $readable_name:expr,
412 $mode:expr
413 $(, lint_by_default = $lint_by_default:expr )?
414 ;
415 )+) => {
416 $(
417
418 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
419 pub struct $name {
420 build_compiler: CompilerForCheck,
421 target: TargetSelection,
422 config: LintConfig,
423 }
424
425 impl Step for $name {
426 type Output = ();
427
428 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
429 run.path($path)
430 }
431
432 fn is_default_step(_builder: &Builder<'_>) -> bool {
433 false $( || const { $lint_by_default } )?
434 }
435
436 fn make_run(run: RunConfig<'_>) {
437 let config = LintConfig::new(run.builder);
438 run.builder.ensure($name {
439 build_compiler: prepare_compiler_for_check(run.builder, run.target, $mode),
440 target: run.target,
441 config,
442 });
443 }
444
445 fn run(self, builder: &Builder<'_>) -> Self::Output {
446 let build_compiler = self.build_compiler.build_compiler();
447 let target = self.target;
448 let mut cargo = prepare_tool_cargo(
449 builder,
450 build_compiler,
451 $mode,
452 target,
453 Kind::Clippy,
454 $path,
455 SourceType::InTree,
456 &[],
457 );
458 self.build_compiler.configure_cargo(&mut cargo);
459
460 let _guard = builder.msg(
461 Kind::Clippy,
462 $readable_name,
463 $mode,
464 build_compiler,
465 target,
466 );
467
468 let stringified_name = stringify!($name).to_lowercase();
469 let stamp = BuildStamp::new(&builder.cargo_out(build_compiler, $mode, target))
470 .with_prefix(&format!("{}-check", stringified_name));
471
472 run_cargo(
473 builder,
474 cargo,
475 lint_args(builder, &self.config, &[]),
476 &stamp,
477 vec![],
478 ArtifactKeepMode::OnlyRmeta
479 );
480 }
481
482 fn metadata(&self) -> Option<StepMetadata> {
483 Some(StepMetadata::clippy($readable_name, self.target).built_by(self.build_compiler.build_compiler()))
484 }
485 }
486 )+
487 }
488}
489
490lint_any!(
493 Bootstrap, "src/bootstrap", "bootstrap", Mode::ToolTarget;
494 BuildHelper, "src/build_helper", "build_helper", Mode::ToolTarget;
495 BuildManifest, "src/tools/build-manifest", "build-manifest", Mode::ToolTarget;
496 CargoMiri, "src/tools/miri/cargo-miri", "cargo-miri", Mode::ToolRustcPrivate;
497 Clippy, "src/tools/clippy", "clippy", Mode::ToolRustcPrivate;
498 CollectLicenseMetadata, "src/tools/collect-license-metadata", "collect-license-metadata", Mode::ToolTarget;
499 Compiletest, "src/tools/compiletest", "compiletest", Mode::ToolTarget;
500 CoverageDump, "src/tools/coverage-dump", "coverage-dump", Mode::ToolTarget;
501 Jsondocck, "src/tools/jsondocck", "jsondocck", Mode::ToolTarget;
502 Jsondoclint, "src/tools/jsondoclint", "jsondoclint", Mode::ToolTarget;
503 LintDocs, "src/tools/lint-docs", "lint-docs", Mode::ToolTarget;
504 LlvmBitcodeLinker, "src/tools/llvm-bitcode-linker", "llvm-bitcode-linker", Mode::ToolTarget;
505 Miri, "src/tools/miri", "miri", Mode::ToolRustcPrivate;
506 MiroptTestTools, "src/tools/miropt-test-tools", "miropt-test-tools", Mode::ToolTarget;
507 OptDist, "src/tools/opt-dist", "opt-dist", Mode::ToolTarget;
508 RemoteTestClient, "src/tools/remote-test-client", "remote-test-client", Mode::ToolTarget;
509 RemoteTestServer, "src/tools/remote-test-server", "remote-test-server", Mode::ToolTarget;
510 RustAnalyzer, "src/tools/rust-analyzer", "rust-analyzer", Mode::ToolRustcPrivate;
511 Rustdoc, "src/librustdoc", "clippy", Mode::ToolRustcPrivate;
512 Rustfmt, "src/tools/rustfmt", "rustfmt", Mode::ToolRustcPrivate;
513 RustInstaller, "src/tools/rust-installer", "rust-installer", Mode::ToolTarget;
514 Tidy, "src/tools/tidy", "tidy", Mode::ToolTarget;
515 TestFloatParse, "src/tools/test-float-parse", "test-float-parse", Mode::ToolStd;
516);
517
518#[derive(Debug, Clone, PartialEq, Eq, Hash)]
520pub struct CI {
521 target: TargetSelection,
522 config: LintConfig,
523}
524
525impl Step for CI {
526 type Output = ();
527
528 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
529 run.alias("ci")
530 }
531
532 fn is_default_step(_builder: &Builder<'_>) -> bool {
533 false
534 }
535
536 fn make_run(run: RunConfig<'_>) {
537 let config = LintConfig::new(run.builder);
538 run.builder.ensure(CI { target: run.target, config });
539 }
540
541 fn run(self, builder: &Builder<'_>) -> Self::Output {
542 if builder.top_stage != 2 {
543 eprintln!("ERROR: `x clippy ci` should always be executed with --stage 2");
544 exit!(1);
545 }
546
547 builder.ensure(Bootstrap {
555 build_compiler: prepare_compiler_for_check(builder, self.target, Mode::ToolTarget),
557 target: self.target,
558 config: self.config.merge(&LintConfig {
559 allow: vec![],
560 warn: vec![],
561 deny: vec!["warnings".into()],
562 forbid: vec![],
563 }),
564 });
565
566 let library_clippy_cfg = LintConfig {
567 allow: vec!["clippy::all".into()],
568 warn: vec![],
569 deny: vec![
570 "clippy::correctness".into(),
571 "clippy::char_lit_as_u8".into(),
572 "clippy::four_forward_slashes".into(),
573 "clippy::needless_bool".into(),
574 "clippy::needless_bool_assign".into(),
575 "clippy::non_minimal_cfg".into(),
576 "clippy::print_literal".into(),
577 "clippy::same_item_push".into(),
578 "clippy::single_char_add_str".into(),
579 "clippy::to_string_in_format_args".into(),
580 "clippy::unconditional_recursion".into(),
581 ],
582 forbid: vec![],
583 };
584 builder.ensure(Std::from_build_compiler(
585 builder.compiler(1, self.target),
587 self.target,
588 self.config.merge(&library_clippy_cfg),
589 vec![],
590 ));
591
592 let compiler_clippy_cfg = LintConfig {
593 allow: vec!["clippy::all".into()],
594 warn: vec![],
595 deny: vec![
596 "clippy::correctness".into(),
597 "clippy::char_lit_as_u8".into(),
598 "clippy::clone_on_ref_ptr".into(),
599 "clippy::format_in_format_args".into(),
600 "clippy::four_forward_slashes".into(),
601 "clippy::needless_bool".into(),
602 "clippy::needless_bool_assign".into(),
603 "clippy::non_minimal_cfg".into(),
604 "clippy::print_literal".into(),
605 "clippy::same_item_push".into(),
606 "clippy::single_char_add_str".into(),
607 "clippy::to_string_in_format_args".into(),
608 "clippy::unconditional_recursion".into(),
609 "clippy::mem_replace_with_default".into(),
610 ],
611 forbid: vec![],
612 };
613 builder.ensure(Rustc::new(
615 builder,
616 self.target,
617 self.config.merge(&compiler_clippy_cfg),
618 vec![],
619 ));
620
621 let rustc_codegen_gcc = LintConfig {
622 allow: vec![],
623 warn: vec![],
624 deny: vec!["warnings".into()],
625 forbid: vec![],
626 };
627 builder.ensure(CodegenGcc::new(
629 builder,
630 self.target,
631 self.config.merge(&rustc_codegen_gcc),
632 ));
633 }
634}