aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/rust-analyzer/src/cli/analysis_stats.rs87
1 files changed, 53 insertions, 34 deletions
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs
index 3f3134562..14dbbb20d 100644
--- a/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -11,9 +11,9 @@ use hir::{
11 db::{AstDatabase, DefDatabase, HirDatabase}, 11 db::{AstDatabase, DefDatabase, HirDatabase},
12 AssocItem, Crate, Function, HasSource, HirDisplay, ModuleDef, 12 AssocItem, Crate, Function, HasSource, HirDisplay, ModuleDef,
13}; 13};
14use hir_def::FunctionId; 14use hir_def::{body::BodySourceMap, expr::ExprId, FunctionId};
15use hir_ty::{TyExt, TypeWalk}; 15use hir_ty::{TyExt, TypeWalk};
16use ide::{AnalysisHost, RootDatabase}; 16use ide::{Analysis, AnalysisHost, LineCol, RootDatabase};
17use ide_db::base_db::{ 17use ide_db::base_db::{
18 salsa::{self, ParallelDatabase}, 18 salsa::{self, ParallelDatabase},
19 SourceDatabaseExt, 19 SourceDatabaseExt,
@@ -25,7 +25,7 @@ use rayon::prelude::*;
25use rustc_hash::FxHashSet; 25use rustc_hash::FxHashSet;
26use stdx::format_to; 26use stdx::format_to;
27use syntax::AstNode; 27use syntax::AstNode;
28use vfs::Vfs; 28use vfs::{Vfs, VfsPath};
29 29
30use crate::cli::{ 30use crate::cli::{
31 load_cargo::{load_workspace_at, LoadCargoConfig}, 31 load_cargo::{load_workspace_at, LoadCargoConfig},
@@ -191,6 +191,7 @@ impl AnalysisStatsCmd {
191 let mut num_exprs_unknown = 0; 191 let mut num_exprs_unknown = 0;
192 let mut num_exprs_partially_unknown = 0; 192 let mut num_exprs_partially_unknown = 0;
193 let mut num_type_mismatches = 0; 193 let mut num_type_mismatches = 0;
194 let analysis = host.analysis();
194 for f in funcs.iter().copied() { 195 for f in funcs.iter().copied() {
195 let name = f.name(db); 196 let name = f.name(db);
196 let full_name = f 197 let full_name = f
@@ -220,7 +221,7 @@ impl AnalysisStatsCmd {
220 } 221 }
221 bar.set_message(&msg); 222 bar.set_message(&msg);
222 let f_id = FunctionId::from(f); 223 let f_id = FunctionId::from(f);
223 let body = db.body(f_id.into()); 224 let (body, sm) = db.body_with_source_map(f_id.into());
224 let inference_result = db.infer(f_id.into()); 225 let inference_result = db.infer(f_id.into());
225 let (previous_exprs, previous_unknown, previous_partially_unknown) = 226 let (previous_exprs, previous_unknown, previous_partially_unknown) =
226 (num_exprs, num_exprs_unknown, num_exprs_partially_unknown); 227 (num_exprs, num_exprs_unknown, num_exprs_partially_unknown);
@@ -229,6 +230,22 @@ impl AnalysisStatsCmd {
229 num_exprs += 1; 230 num_exprs += 1;
230 if ty.is_unknown() { 231 if ty.is_unknown() {
231 num_exprs_unknown += 1; 232 num_exprs_unknown += 1;
233 if verbosity.is_spammy() {
234 if let Some((path, start, end)) =
235 expr_syntax_range(db, &analysis, vfs, &sm, expr_id)
236 {
237 bar.println(format!(
238 "{} {}:{}-{}:{}: Unknown type",
239 path,
240 start.line + 1,
241 start.col,
242 end.line + 1,
243 end.col,
244 ));
245 } else {
246 bar.println(format!("{}: Unknown type", name,));
247 }
248 }
232 } else { 249 } else {
233 let mut is_partially_unknown = false; 250 let mut is_partially_unknown = false;
234 ty.walk(&mut |ty| { 251 ty.walk(&mut |ty| {
@@ -242,20 +259,9 @@ impl AnalysisStatsCmd {
242 } 259 }
243 if self.only.is_some() && verbosity.is_spammy() { 260 if self.only.is_some() && verbosity.is_spammy() {
244 // in super-verbose mode for just one function, we print every single expression 261 // in super-verbose mode for just one function, we print every single expression
245 let (_, sm) = db.body_with_source_map(f_id.into()); 262 if let Some((_, start, end)) =
246 let src = sm.expr_syntax(expr_id); 263 expr_syntax_range(db, &analysis, vfs, &sm, expr_id)
247 if let Ok(src) = src { 264 {
248 let node = {
249 let root = db.parse_or_expand(src.file_id).unwrap();
250 src.value.to_node(&root)
251 };
252 let original_file = src.file_id.original_file(db);
253 let line_index = host.analysis().file_line_index(original_file).unwrap();
254 let text_range = node.syntax().text_range();
255 let (start, end) = (
256 line_index.line_col(text_range.start()),
257 line_index.line_col(text_range.end()),
258 );
259 bar.println(format!( 265 bar.println(format!(
260 "{}:{}-{}:{}: {}", 266 "{}:{}-{}:{}: {}",
261 start.line + 1, 267 start.line + 1,
@@ -271,22 +277,9 @@ impl AnalysisStatsCmd {
271 if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr_id) { 277 if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr_id) {
272 num_type_mismatches += 1; 278 num_type_mismatches += 1;
273 if verbosity.is_verbose() { 279 if verbosity.is_verbose() {
274 let (_, sm) = db.body_with_source_map(f_id.into()); 280 if let Some((path, start, end)) =
275 let src = sm.expr_syntax(expr_id); 281 expr_syntax_range(db, &analysis, vfs, &sm, expr_id)
276 if let Ok(src) = src { 282 {
277 // FIXME: it might be nice to have a function (on Analysis?) that goes from Source<T> -> (LineCol, LineCol) directly
278 // But also, we should just turn the type mismatches into diagnostics and provide these
279 let root = db.parse_or_expand(src.file_id).unwrap();
280 let node = src.map(|e| e.to_node(&root).syntax().clone());
281 let original_range = node.as_ref().original_file_range(db);
282 let path = vfs.file_path(original_range.file_id);
283 let line_index =
284 host.analysis().file_line_index(original_range.file_id).unwrap();
285 let text_range = original_range.range;
286 let (start, end) = (
287 line_index.line_col(text_range.start()),
288 line_index.line_col(text_range.end()),
289 );
290 bar.println(format!( 283 bar.println(format!(
291 "{} {}:{}-{}:{}: Expected {}, got {}", 284 "{} {}:{}-{}:{}: Expected {}, got {}",
292 path, 285 path,
@@ -319,6 +312,7 @@ impl AnalysisStatsCmd {
319 } 312 }
320 bar.inc(1); 313 bar.inc(1);
321 } 314 }
315
322 bar.finish_and_clear(); 316 bar.finish_and_clear();
323 eprintln!( 317 eprintln!(
324 " exprs: {}, ??ty: {} ({}%), ?ty: {} ({}%), !ty: {}", 318 " exprs: {}, ??ty: {} ({}%), ?ty: {} ({}%), !ty: {}",
@@ -340,6 +334,31 @@ impl AnalysisStatsCmd {
340 } 334 }
341} 335}
342 336
337fn expr_syntax_range(
338 db: &RootDatabase,
339 analysis: &Analysis,
340 vfs: &Vfs,
341 sm: &BodySourceMap,
342 expr_id: ExprId,
343) -> Option<(VfsPath, LineCol, LineCol)> {
344 let src = sm.expr_syntax(expr_id);
345 if let Ok(src) = src {
346 // FIXME: it might be nice to have a function (on Analysis?) that goes from Source<T> -> (LineCol, LineCol) directly
347 // But also, we should just turn the type mismatches into diagnostics and provide these
348 let root = db.parse_or_expand(src.file_id).unwrap();
349 let node = src.map(|e| e.to_node(&root).syntax().clone());
350 let original_range = node.as_ref().original_file_range(db);
351 let path = vfs.file_path(original_range.file_id);
352 let line_index = analysis.file_line_index(original_range.file_id).unwrap();
353 let text_range = original_range.range;
354 let (start, end) =
355 (line_index.line_col(text_range.start()), line_index.line_col(text_range.end()));
356 Some((path, start, end))
357 } else {
358 None
359 }
360}
361
343fn shuffle<T>(rng: &mut Rand32, slice: &mut [T]) { 362fn shuffle<T>(rng: &mut Rand32, slice: &mut [T]) {
344 for i in 0..slice.len() { 363 for i in 0..slice.len() {
345 randomize_first(rng, &mut slice[i..]); 364 randomize_first(rng, &mut slice[i..]);