Skip to content

Commit 8dbcffe

Browse files
committed
Auto merge of #6708 - matthiaskrgr:lintcheck, r=flip1995
some more lintcheck changes * Explain why tokei is commented out in the lintcheck sources. * If we specify a custom sources.toml, don't override the preexisting lintcheck logs, but rather start a new log with the filename depending on the sources.toml name. * Start adding a readme.md to clippy_dev and add some information on how to use the lintcheck subcommand. * Add support for path/local sources (I needed this for the next item which is: ) * Collect ICEs that happen while clippy checks crates changelog: more lintcheck changes
2 parents beb49ba + a6d493d commit 8dbcffe

File tree

5 files changed

+101
-10
lines changed

5 files changed

+101
-10
lines changed

Diff for: clippy_dev/Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ edition = "2018"
99
bytecount = "0.6"
1010
clap = "2.33"
1111
flate2 = { version = "1.0.19", optional = true }
12+
fs_extra = { version = "1.2.0", optional = true }
1213
itertools = "0.9"
1314
opener = "0.4"
1415
regex = "1"
@@ -21,5 +22,5 @@ ureq = { version = "2.0.0-rc3", optional = true }
2122
walkdir = "2"
2223

2324
[features]
24-
lintcheck = ["flate2", "serde_json", "tar", "toml", "ureq", "serde"]
25+
lintcheck = ["flate2", "serde_json", "tar", "toml", "ureq", "serde", "fs_extra"]
2526
deny-warnings = []

Diff for: clippy_dev/README.md

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Clippy Dev Tool
2+
3+
The Clippy Dev Tool is a tool to ease Clippy development, similar to `rustc`s `x.py`.
4+
5+
Functionalities (incomplete):
6+
7+
## `lintcheck`
8+
Runs clippy on a fixed set of crates read from `clippy_dev/lintcheck_crates.toml`
9+
and saves logs of the lint warnings into the repo.
10+
We can then check the diff and spot new or disappearing warnings.
11+
12+
From the repo root, run:
13+
````
14+
cargo run --target-dir clippy_dev/target --package clippy_dev \
15+
--bin clippy_dev --manifest-path clippy_dev/Cargo.toml --features lintcheck -- lintcheck
16+
````
17+
or
18+
````
19+
cargo dev-lintcheck
20+
````
21+
22+
By default the logs will be saved into `lintcheck-logs/lintcheck_crates_logs.txt`.
23+
24+
You can set a custom sources.toml by adding `--crates-toml custom.toml`
25+
where `custom.toml` must be a relative path from the repo root.
26+
27+
The results will then be saved to `lintcheck-logs/custom_logs.toml`.
28+

Diff for: clippy_dev/lintcheck_crates.toml

+2
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ cargo = {name = "cargo", versions = ['0.49.0']}
44
iron = {name = "iron", versions = ['0.6.1']}
55
ripgrep = {name = "ripgrep", versions = ['12.1.1']}
66
xsv = {name = "xsv", versions = ['0.13.0']}
7+
# commented out because of 173K clippy::match_same_arms msgs in language_type.rs
78
#tokei = { name = "tokei", versions = ['12.0.4']}
89
rayon = {name = "rayon", versions = ['1.5.0']}
910
serde = {name = "serde", versions = ['1.0.118']}
1011
# top 10 crates.io dls
1112
bitflags = {name = "bitflags", versions = ['1.2.1']}
13+
# crash = {name = "clippy_crash", path = "/tmp/clippy_crash"}
1214
libc = {name = "libc", versions = ['0.2.81']}
1315
log = {name = "log", versions = ['0.4.11']}
1416
proc-macro2 = {name = "proc-macro2", versions = ['1.0.24']}

Diff for: clippy_dev/src/lintcheck.rs

+69-9
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,15 @@ struct TomlCrate {
3131
versions: Option<Vec<String>>,
3232
git_url: Option<String>,
3333
git_hash: Option<String>,
34+
path: Option<String>,
3435
}
3536

36-
// represents an archive we download from crates.io
37+
// represents an archive we download from crates.io, or a git repo, or a local repo
3738
#[derive(Debug, Serialize, Deserialize, Eq, Hash, PartialEq)]
3839
enum CrateSource {
3940
CratesIo { name: String, version: String },
4041
Git { name: String, url: String, commit: String },
42+
Path { name: String, path: PathBuf },
4143
}
4244

4345
// represents the extracted sourcecode of a crate
@@ -60,6 +62,7 @@ struct ClippyWarning {
6062
column: String,
6163
linttype: String,
6264
message: String,
65+
ice: bool,
6366
}
6467

6568
impl std::fmt::Display for ClippyWarning {
@@ -111,7 +114,7 @@ impl CrateSource {
111114
},
112115
CrateSource::Git { name, url, commit } => {
113116
let repo_path = {
114-
let mut repo_path = PathBuf::from("target/lintcheck/downloads");
117+
let mut repo_path = PathBuf::from("target/lintcheck/crates");
115118
// add a -git suffix in case we have the same crate from crates.io and a git repo
116119
repo_path.push(format!("{}-git", name));
117120
repo_path
@@ -139,6 +142,37 @@ impl CrateSource {
139142
path: repo_path,
140143
}
141144
},
145+
CrateSource::Path { name, path } => {
146+
use fs_extra::dir;
147+
148+
// simply copy the entire directory into our target dir
149+
let copy_dest = PathBuf::from("target/lintcheck/crates/");
150+
151+
// the source path of the crate we copied, ${copy_dest}/crate_name
152+
let crate_root = copy_dest.join(name); // .../crates/local_crate
153+
154+
if !crate_root.exists() {
155+
println!("Copying {} to {}", path.display(), copy_dest.display());
156+
157+
dir::copy(path, &copy_dest, &dir::CopyOptions::new()).expect(&format!(
158+
"Failed to copy from {}, to {}",
159+
path.display(),
160+
crate_root.display()
161+
));
162+
} else {
163+
println!(
164+
"Not copying {} to {}, destination already exists",
165+
path.display(),
166+
crate_root.display()
167+
);
168+
}
169+
170+
Crate {
171+
version: String::from("local"),
172+
name: name.clone(),
173+
path: crate_root,
174+
}
175+
},
142176
}
143177
}
144178
}
@@ -176,8 +210,8 @@ impl Crate {
176210
let output_lines = stdout.lines();
177211
let warnings: Vec<ClippyWarning> = output_lines
178212
.into_iter()
179-
// get all clippy warnings
180-
.filter(|line| line.contains("clippy::"))
213+
// get all clippy warnings and ICEs
214+
.filter(|line| line.contains("clippy::") || line.contains("internal compiler error: "))
181215
.map(|json_msg| parse_json_message(json_msg, &self))
182216
.collect();
183217
warnings
@@ -192,8 +226,10 @@ fn build_clippy() {
192226
}
193227

194228
// get a list of CrateSources we want to check from a "lintcheck_crates.toml" file.
195-
fn read_crates(toml_path: Option<&str>) -> Vec<CrateSource> {
229+
fn read_crates(toml_path: Option<&str>) -> (String, Vec<CrateSource>) {
196230
let toml_path = PathBuf::from(toml_path.unwrap_or("clippy_dev/lintcheck_crates.toml"));
231+
// save it so that we can use the name of the sources.toml as name for the logfile later.
232+
let toml_filename = toml_path.file_stem().unwrap().to_str().unwrap().to_string();
197233
let toml_content: String =
198234
std::fs::read_to_string(&toml_path).unwrap_or_else(|_| panic!("Failed to read {}", toml_path.display()));
199235
let crate_list: CrateList =
@@ -209,6 +245,13 @@ fn read_crates(toml_path: Option<&str>) -> Vec<CrateSource> {
209245
// multiple Cratesources)
210246
let mut crate_sources = Vec::new();
211247
tomlcrates.into_iter().for_each(|tk| {
248+
if let Some(ref path) = tk.path {
249+
crate_sources.push(CrateSource::Path {
250+
name: tk.name.clone(),
251+
path: PathBuf::from(path),
252+
});
253+
}
254+
212255
// if we have multiple versions, save each one
213256
if let Some(ref versions) = tk.versions {
214257
versions.iter().for_each(|ver| {
@@ -232,12 +275,15 @@ fn read_crates(toml_path: Option<&str>) -> Vec<CrateSource> {
232275
{
233276
eprintln!("tomlkrate: {:?}", tk);
234277
if tk.git_hash.is_some() != tk.git_url.is_some() {
235-
panic!("Encountered TomlCrate with only one of git_hash and git_url!")
278+
panic!("Error: Encountered TomlCrate with only one of git_hash and git_url!");
279+
}
280+
if tk.path.is_some() && (tk.git_hash.is_some() || tk.versions.is_some()) {
281+
panic!("Error: TomlCrate can only have one of 'git_.*', 'version' or 'path' fields");
236282
}
237283
unreachable!("Failed to translate TomlCrate into CrateSource!");
238284
}
239285
});
240-
crate_sources
286+
(toml_filename, crate_sources)
241287
}
242288

243289
// extract interesting data from a json lint message
@@ -261,6 +307,7 @@ fn parse_json_message(json_message: &str, krate: &Crate) -> ClippyWarning {
261307
.into(),
262308
linttype: jmsg["message"]["code"]["code"].to_string().trim_matches('"').into(),
263309
message: jmsg["message"]["message"].to_string().trim_matches('"').into(),
310+
ice: json_message.contains("internal compiler error: "),
264311
}
265312
}
266313

@@ -288,14 +335,15 @@ pub fn run(clap_config: &ArgMatches) {
288335
// download and extract the crates, then run clippy on them and collect clippys warnings
289336
// flatten into one big list of warnings
290337

291-
let crates = read_crates(clap_config.value_of("crates-toml"));
338+
let (filename, crates) = read_crates(clap_config.value_of("crates-toml"));
292339

293340
let clippy_warnings: Vec<ClippyWarning> = if let Some(only_one_crate) = clap_config.value_of("only") {
294341
// if we don't have the specified crate in the .toml, throw an error
295342
if !crates.iter().any(|krate| {
296343
let name = match krate {
297344
CrateSource::CratesIo { name, .. } => name,
298345
CrateSource::Git { name, .. } => name,
346+
CrateSource::Path { name, .. } => name,
299347
};
300348
name == only_one_crate
301349
}) {
@@ -326,6 +374,13 @@ pub fn run(clap_config: &ArgMatches) {
326374

327375
// generate some stats:
328376

377+
// grab crashes/ICEs, save the crate name and the ice message
378+
let ices: Vec<(&String, &String)> = clippy_warnings
379+
.iter()
380+
.filter(|warning| warning.ice)
381+
.map(|w| (&w.crate_name, &w.message))
382+
.collect();
383+
329384
// count lint type occurrences
330385
let mut counter: HashMap<&String, usize> = HashMap::new();
331386
clippy_warnings
@@ -351,5 +406,10 @@ pub fn run(clap_config: &ArgMatches) {
351406
// save the text into lintcheck-logs/logs.txt
352407
let mut text = clippy_ver; // clippy version number on top
353408
text.push_str(&format!("\n{}", all_msgs.join("")));
354-
write("lintcheck-logs/logs.txt", text).unwrap();
409+
text.push_str("ICEs:\n");
410+
ices.iter()
411+
.for_each(|(cratename, msg)| text.push_str(&format!("{}: '{}'", cratename, msg)));
412+
413+
let file = format!("lintcheck-logs/{}_logs.txt", filename);
414+
write(file, text).unwrap();
355415
}
File renamed without changes.

0 commit comments

Comments
 (0)