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