Skip to content

Commit 1d5df5e

Browse files
Merge #11548
11548: Add CSV output to analysis-stats r=flodiebold a=flodiebold For easy diffing, to find changes in unknown types / type mismatches. Co-authored-by: Florian Diebold <[email protected]>
2 parents f6901c9 + f807ccd commit 1d5df5e

File tree

3 files changed

+74
-6
lines changed

3 files changed

+74
-6
lines changed

crates/rust-analyzer/src/cli/analysis_stats.rs

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ use hir::{
1010
db::{AstDatabase, DefDatabase, HirDatabase},
1111
AssocItem, Crate, Function, HasSource, HirDisplay, ModuleDef,
1212
};
13-
use hir_def::{body::BodySourceMap, expr::ExprId, FunctionId};
13+
use hir_def::{
14+
body::{BodySourceMap, SyntheticSyntax},
15+
expr::ExprId,
16+
FunctionId,
17+
};
1418
use hir_ty::{TyExt, TypeWalk};
1519
use ide::{Analysis, AnalysisHost, LineCol, RootDatabase};
1620
use ide_db::base_db::{
@@ -28,7 +32,7 @@ use syntax::{AstNode, SyntaxNode};
2832
use vfs::{AbsPathBuf, Vfs, VfsPath};
2933

3034
use crate::cli::{
31-
flags,
35+
flags::{self, OutputFormat},
3236
load_cargo::{load_workspace, LoadCargoConfig},
3337
print_memory_usage,
3438
progress_report::ProgressReport,
@@ -191,7 +195,7 @@ impl flags::AnalysisStats {
191195
) {
192196
let mut bar = match verbosity {
193197
Verbosity::Quiet | Verbosity::Spammy => ProgressReport::hidden(),
194-
_ if self.parallel => ProgressReport::hidden(),
198+
_ if self.parallel || self.output.is_some() => ProgressReport::hidden(),
195199
_ => ProgressReport::new(funcs.len() as u64),
196200
};
197201

@@ -252,7 +256,7 @@ impl flags::AnalysisStats {
252256
for (expr_id, _) in body.exprs.iter() {
253257
let ty = &inference_result[expr_id];
254258
num_exprs += 1;
255-
if ty.is_unknown() {
259+
let unknown_or_partial = if ty.is_unknown() {
256260
num_exprs_unknown += 1;
257261
if verbosity.is_spammy() {
258262
if let Some((path, start, end)) =
@@ -270,6 +274,7 @@ impl flags::AnalysisStats {
270274
bar.println(format!("{}: Unknown type", name,));
271275
}
272276
}
277+
true
273278
} else {
274279
let mut is_partially_unknown = false;
275280
ty.walk(&mut |ty| {
@@ -280,7 +285,8 @@ impl flags::AnalysisStats {
280285
if is_partially_unknown {
281286
num_exprs_partially_unknown += 1;
282287
}
283-
}
288+
is_partially_unknown
289+
};
284290
if self.only.is_some() && verbosity.is_spammy() {
285291
// in super-verbose mode for just one function, we print every single expression
286292
if let Some((_, start, end)) =
@@ -298,6 +304,13 @@ impl flags::AnalysisStats {
298304
bar.println(format!("unknown location: {}", ty.display(db)));
299305
}
300306
}
307+
if unknown_or_partial && self.output == Some(OutputFormat::Csv) {
308+
println!(
309+
r#"{},type,"{}""#,
310+
location_csv(db, &analysis, vfs, &sm, expr_id),
311+
ty.display(db)
312+
);
313+
}
301314
if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr_id) {
302315
num_type_mismatches += 1;
303316
if verbosity.is_verbose() {
@@ -323,6 +336,14 @@ impl flags::AnalysisStats {
323336
));
324337
}
325338
}
339+
if self.output == Some(OutputFormat::Csv) {
340+
println!(
341+
r#"{},mismatch,"{}","{}""#,
342+
location_csv(db, &analysis, vfs, &sm, expr_id),
343+
mismatch.expected.display(db),
344+
mismatch.actual.display(db)
345+
);
346+
}
326347
}
327348
}
328349
if verbosity.is_spammy() {
@@ -358,6 +379,28 @@ impl flags::AnalysisStats {
358379
}
359380
}
360381

382+
fn location_csv(
383+
db: &RootDatabase,
384+
analysis: &Analysis,
385+
vfs: &Vfs,
386+
sm: &BodySourceMap,
387+
expr_id: ExprId,
388+
) -> String {
389+
let src = match sm.expr_syntax(expr_id) {
390+
Ok(s) => s,
391+
Err(SyntheticSyntax) => return "synthetic,,".to_string(),
392+
};
393+
let root = db.parse_or_expand(src.file_id).unwrap();
394+
let node = src.map(|e| e.to_node(&root).syntax().clone());
395+
let original_range = node.as_ref().original_file_range(db);
396+
let path = vfs.file_path(original_range.file_id);
397+
let line_index = analysis.file_line_index(original_range.file_id).unwrap();
398+
let text_range = original_range.range;
399+
let (start, end) =
400+
(line_index.line_col(text_range.start()), line_index.line_col(text_range.end()));
401+
format!("{},{}:{},{}:{}", path, start.line + 1, start.col, end.line + 1, end.col)
402+
}
403+
361404
fn expr_syntax_range(
362405
db: &RootDatabase,
363406
analysis: &Analysis,

crates/rust-analyzer/src/cli/flags.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Grammar for the command-line arguments.
22
#![allow(unreachable_pub)]
3-
use std::path::PathBuf;
3+
use std::{path::PathBuf, str::FromStr};
44

55
use ide_ssr::{SsrPattern, SsrRule};
66

@@ -54,6 +54,8 @@ xflags::xflags! {
5454
/// Directory with Cargo.toml.
5555
required path: PathBuf
5656
{
57+
optional --output format: OutputFormat
58+
5759
/// Randomize order in which crates, modules, and items are processed.
5860
optional --randomize
5961
/// Run type inference in parallel.
@@ -160,6 +162,7 @@ pub struct Highlight {
160162
pub struct AnalysisStats {
161163
pub path: PathBuf,
162164

165+
pub output: Option<OutputFormat>,
163166
pub randomize: bool,
164167
pub parallel: bool,
165168
pub memory_usage: bool,
@@ -215,6 +218,11 @@ impl RustAnalyzer {
215218
}
216219
// generated end
217220

221+
#[derive(Debug, PartialEq, Eq)]
222+
pub enum OutputFormat {
223+
Csv,
224+
}
225+
218226
impl RustAnalyzer {
219227
pub fn verbosity(&self) -> Verbosity {
220228
if self.quiet {
@@ -227,3 +235,14 @@ impl RustAnalyzer {
227235
}
228236
}
229237
}
238+
239+
impl FromStr for OutputFormat {
240+
type Err = String;
241+
242+
fn from_str(s: &str) -> Result<Self, Self::Err> {
243+
match s {
244+
"csv" => Ok(Self::Csv),
245+
_ => Err(format!("unknown output format `{}`", s)),
246+
}
247+
}
248+
}

xtask/src/flags.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,15 @@ pub struct Bb {
113113
impl Xtask {
114114
pub const HELP: &'static str = Self::HELP_;
115115

116+
#[allow(dead_code)]
116117
pub fn from_env() -> xflags::Result<Self> {
117118
Self::from_env_()
118119
}
120+
121+
#[allow(dead_code)]
122+
pub fn from_vec(args: Vec<std::ffi::OsString>) -> xflags::Result<Self> {
123+
Self::from_vec_(args)
124+
}
119125
}
120126
// generated end
121127

0 commit comments

Comments
 (0)