Skip to content

Commit 6c5bf27

Browse files
committed
clippy dev crater: use and parse clippy messages as json message, to get the lint name of a warning
1 parent 62337f2 commit 6c5bf27

File tree

3 files changed

+3306
-3265
lines changed

3 files changed

+3306
-3265
lines changed

clippy_dev/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ itertools = "0.9"
1212
opener = "0.4"
1313
regex = "1"
1414
serde = {version = "1.0", features = ["derive"]}
15+
serde_json = "1.0"
1516
shell-escape = "0.1"
1617
tar = "0.4.30"
1718
toml = "0.5"

clippy_dev/src/crater.rs

Lines changed: 56 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@ use crate::clippy_project_root;
1010

1111
use std::collections::HashMap;
1212
use std::process::Command;
13-
use std::{fs::write, path::PathBuf};
13+
use std::{fmt, fs::write, path::PathBuf};
1414

1515
use serde::{Deserialize, Serialize};
16+
use serde_json::Value;
1617

1718
// use this to store the crates when interacting with the crates.toml file
1819
#[derive(Debug, Serialize, Deserialize)]
@@ -43,6 +44,27 @@ struct Crate {
4344
path: PathBuf,
4445
}
4546

47+
#[derive(Debug)]
48+
struct ClippyWarning {
49+
crate_name: String,
50+
crate_version: String,
51+
file: String,
52+
line: String,
53+
column: String,
54+
linttype: String,
55+
message: String,
56+
}
57+
58+
impl std::fmt::Display for ClippyWarning {
59+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60+
writeln!(
61+
f,
62+
r#"{}/{}/{}:{}:{} {} "{}""#,
63+
&self.crate_name, &self.crate_version, &self.file, &self.line, &self.column, &self.linttype, &self.message
64+
)
65+
}
66+
}
67+
4668
impl CrateSource {
4769
fn download_and_extract(&self) -> Crate {
4870
let extract_dir = PathBuf::from("target/crater/crates");
@@ -96,7 +118,7 @@ impl Crate {
96118
// src/cargo/ops/cargo_compile.rs:127:35: warning: usage of `FromIterator::from_iter`
97119
.args(&[
98120
"--",
99-
"--message-format=short",
121+
"--message-format=json",
100122
"--",
101123
"--cap-lints=warn",
102124
"-Wclippy::pedantic",
@@ -105,27 +127,17 @@ impl Crate {
105127
.current_dir(&self.path)
106128
.output()
107129
.unwrap();
108-
let stderr = String::from_utf8_lossy(&all_output.stderr);
109-
let output_lines = stderr.lines();
110-
let mut output: Vec<String> = output_lines
130+
let stdout = String::from_utf8_lossy(&all_output.stdout);
131+
let output_lines = stdout.lines();
132+
//dbg!(&output_lines);
133+
let warnings: Vec<ClippyWarning> = output_lines
111134
.into_iter()
112-
.filter(|line| line.contains(": warning: "))
113-
// prefix with the crate name and version
114-
// cargo-0.49.0/src/cargo/ops/cargo_compile.rs:127:35: warning: usage of `FromIterator::from_iter`
115-
.map(|line| format!("{}-{}/{}", self.name, self.version, line))
116-
// remove the "warning: "
117-
.map(|line| {
118-
let remove_pat = "warning: ";
119-
let pos = line
120-
.find(&remove_pat)
121-
.expect("clippy output did not contain \"warning: \"");
122-
let mut new = line[0..pos].to_string();
123-
new.push_str(&line[pos + remove_pat.len()..]);
124-
new.push('\n');
125-
new
126-
})
135+
// get all clippy warnings
136+
.filter(|line| line.contains("clippy::"))
137+
.map(|json_msg| parse_json_message(json_msg, &self))
127138
.collect();
128139

140+
let mut output: Vec<String> = warnings.iter().map(|warning| warning.to_string()).collect();
129141
// sort messages alphabetically to avoid noise in the logs
130142
output.sort();
131143
output
@@ -167,6 +179,30 @@ fn read_crates() -> Vec<CrateSource> {
167179
crate_sources
168180
}
169181

182+
// extract interesting data from a json lint message
183+
fn parse_json_message(json_message: &str, krate: &Crate) -> ClippyWarning {
184+
let jmsg: Value = serde_json::from_str(&json_message).unwrap_or_else(|e| panic!("Failed to parse json:\n{:?}", e));
185+
186+
ClippyWarning {
187+
crate_name: krate.name.to_string(),
188+
crate_version: krate.version.to_string(),
189+
file: jmsg["message"]["spans"][0]["file_name"]
190+
.to_string()
191+
.trim_matches('"')
192+
.into(),
193+
line: jmsg["message"]["spans"][0]["line_start"]
194+
.to_string()
195+
.trim_matches('"')
196+
.into(),
197+
column: jmsg["message"]["spans"][0]["text"][0]["highlight_start"]
198+
.to_string()
199+
.trim_matches('"')
200+
.into(),
201+
linttype: jmsg["message"]["code"]["code"].to_string().trim_matches('"').into(),
202+
message: jmsg["message"]["message"].to_string().trim_matches('"').into(),
203+
}
204+
}
205+
170206
// the main fn
171207
pub fn run() {
172208
let cargo_clippy_path: PathBuf = PathBuf::from("target/debug/cargo-clippy");

0 commit comments

Comments
 (0)