]> git.proxmox.com Git - rustc.git/blob - src/tools/clippy/tests/dogfood.rs
New upstream version 1.57.0+dfsg1
[rustc.git] / src / tools / clippy / tests / dogfood.rs
1 //! This test is a part of quality control and makes clippy eat what it produces. Awesome lints and
2 //! long error messages
3 //!
4 //! See [Eating your own dog food](https://en.wikipedia.org/wiki/Eating_your_own_dog_food) for context
5
6 // Dogfood cannot run on Windows
7 #![cfg(not(windows))]
8 #![feature(once_cell)]
9 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
10 #![warn(rust_2018_idioms, unused_lifetimes)]
11
12 use std::lazy::SyncLazy;
13 use std::path::PathBuf;
14 use std::process::Command;
15
16 mod cargo;
17
18 static CLIPPY_PATH: SyncLazy<PathBuf> = SyncLazy::new(|| {
19 let mut path = std::env::current_exe().unwrap();
20 assert!(path.pop()); // deps
21 path.set_file_name("cargo-clippy");
22 path
23 });
24
25 #[test]
26 fn dogfood_clippy() {
27 // run clippy on itself and fail the test if lint warnings are reported
28 if cargo::is_rustc_test_suite() {
29 return;
30 }
31 let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
32
33 let mut command = Command::new(&*CLIPPY_PATH);
34 command
35 .current_dir(root_dir)
36 .env("CARGO_INCREMENTAL", "0")
37 .arg("clippy")
38 .arg("--all-targets")
39 .arg("--all-features")
40 .arg("--")
41 .args(&["-D", "clippy::all"])
42 .args(&["-D", "clippy::pedantic"])
43 .arg("-Cdebuginfo=0"); // disable debuginfo to generate less data in the target dir
44
45 // internal lints only exist if we build with the internal-lints feature
46 if cfg!(feature = "internal-lints") {
47 command.args(&["-D", "clippy::internal"]);
48 }
49
50 let output = command.output().unwrap();
51
52 println!("status: {}", output.status);
53 println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
54 println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
55
56 assert!(output.status.success());
57 }
58
59 fn test_no_deps_ignores_path_deps_in_workspaces() {
60 if cargo::is_rustc_test_suite() {
61 return;
62 }
63 let root = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
64 let target_dir = root.join("target").join("dogfood");
65 let cwd = root.join("clippy_workspace_tests");
66
67 // Make sure we start with a clean state
68 Command::new("cargo")
69 .current_dir(&cwd)
70 .env("CARGO_TARGET_DIR", &target_dir)
71 .arg("clean")
72 .args(&["-p", "subcrate"])
73 .args(&["-p", "path_dep"])
74 .output()
75 .unwrap();
76
77 // `path_dep` is a path dependency of `subcrate` that would trigger a denied lint.
78 // Make sure that with the `--no-deps` argument Clippy does not run on `path_dep`.
79 let output = Command::new(&*CLIPPY_PATH)
80 .current_dir(&cwd)
81 .env("CARGO_INCREMENTAL", "0")
82 .arg("clippy")
83 .args(&["-p", "subcrate"])
84 .arg("--no-deps")
85 .arg("--")
86 .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir
87 .args(&["--cfg", r#"feature="primary_package_test""#])
88 .output()
89 .unwrap();
90 println!("status: {}", output.status);
91 println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
92 println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
93
94 assert!(output.status.success());
95
96 let lint_path_dep = || {
97 // Test that without the `--no-deps` argument, `path_dep` is linted.
98 let output = Command::new(&*CLIPPY_PATH)
99 .current_dir(&cwd)
100 .env("CARGO_INCREMENTAL", "0")
101 .arg("clippy")
102 .args(&["-p", "subcrate"])
103 .arg("--")
104 .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir
105 .args(&["--cfg", r#"feature="primary_package_test""#])
106 .output()
107 .unwrap();
108 println!("status: {}", output.status);
109 println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
110 println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
111
112 assert!(!output.status.success());
113 assert!(
114 String::from_utf8(output.stderr)
115 .unwrap()
116 .contains("error: empty `loop {}` wastes CPU cycles")
117 );
118 };
119
120 // Make sure Cargo is aware of the removal of `--no-deps`.
121 lint_path_dep();
122
123 let successful_build = || {
124 let output = Command::new(&*CLIPPY_PATH)
125 .current_dir(&cwd)
126 .env("CARGO_INCREMENTAL", "0")
127 .arg("clippy")
128 .args(&["-p", "subcrate"])
129 .arg("--")
130 .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir
131 .output()
132 .unwrap();
133 println!("status: {}", output.status);
134 println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
135 println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
136
137 assert!(output.status.success());
138
139 output
140 };
141
142 // Trigger a sucessful build, so Cargo would like to cache the build result.
143 successful_build();
144
145 // Make sure there's no spurious rebuild when nothing changes.
146 let stderr = String::from_utf8(successful_build().stderr).unwrap();
147 assert!(!stderr.contains("Compiling"));
148 assert!(!stderr.contains("Checking"));
149 assert!(stderr.contains("Finished"));
150
151 // Make sure Cargo is aware of the new `--cfg` flag.
152 lint_path_dep();
153 }
154
155 #[test]
156 fn dogfood_subprojects() {
157 // run clippy on remaining subprojects and fail the test if lint warnings are reported
158 if cargo::is_rustc_test_suite() {
159 return;
160 }
161
162 // NOTE: `path_dep` crate is omitted on purpose here
163 for project in &[
164 "clippy_workspace_tests",
165 "clippy_workspace_tests/src",
166 "clippy_workspace_tests/subcrate",
167 "clippy_workspace_tests/subcrate/src",
168 "clippy_dev",
169 "clippy_lints",
170 "clippy_utils",
171 "rustc_tools_util",
172 ] {
173 run_clippy_for_project(project);
174 }
175
176 // NOTE: Since tests run in parallel we can't run cargo commands on the same workspace at the
177 // same time, so we test this immediately after the dogfood for workspaces.
178 test_no_deps_ignores_path_deps_in_workspaces();
179 }
180
181 #[test]
182 #[ignore]
183 #[cfg(feature = "metadata-collector-lint")]
184 fn run_metadata_collection_lint() {
185 use std::fs::File;
186 use std::time::SystemTime;
187
188 // Setup for validation
189 let metadata_output_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("util/gh-pages/lints.json");
190 let start_time = SystemTime::now();
191
192 // Run collection as is
193 std::env::set_var("ENABLE_METADATA_COLLECTION", "1");
194 run_clippy_for_project("clippy_lints");
195
196 // Check if cargo caching got in the way
197 if let Ok(file) = File::open(metadata_output_path) {
198 if let Ok(metadata) = file.metadata() {
199 if let Ok(last_modification) = metadata.modified() {
200 if last_modification > start_time {
201 // The output file has been modified. Most likely by a hungry
202 // metadata collection monster. So We'll return.
203 return;
204 }
205 }
206 }
207 }
208
209 // Force cargo to invalidate the caches
210 filetime::set_file_mtime(
211 PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("clippy_lints/src/lib.rs"),
212 filetime::FileTime::now(),
213 )
214 .unwrap();
215
216 // Running the collection again
217 run_clippy_for_project("clippy_lints");
218 }
219
220 fn run_clippy_for_project(project: &str) {
221 let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
222
223 let mut command = Command::new(&*CLIPPY_PATH);
224
225 command
226 .current_dir(root_dir.join(project))
227 .env("CARGO_INCREMENTAL", "0")
228 .arg("clippy")
229 .arg("--all-targets")
230 .arg("--all-features")
231 .arg("--")
232 .args(&["-D", "clippy::all"])
233 .args(&["-D", "clippy::pedantic"])
234 .arg("-Cdebuginfo=0"); // disable debuginfo to generate less data in the target dir
235
236 // internal lints only exist if we build with the internal-lints feature
237 if cfg!(feature = "internal-lints") {
238 command.args(&["-D", "clippy::internal"]);
239 }
240
241 let output = command.output().unwrap();
242
243 println!("status: {}", output.status);
244 println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
245 println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
246
247 assert!(output.status.success());
248 }