diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/rust-analyzer/src/cli/analysis_stats.rs | 87 |
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 | }; |
14 | use hir_def::FunctionId; | 14 | use hir_def::{body::BodySourceMap, expr::ExprId, FunctionId}; |
15 | use hir_ty::{TyExt, TypeWalk}; | 15 | use hir_ty::{TyExt, TypeWalk}; |
16 | use ide::{AnalysisHost, RootDatabase}; | 16 | use ide::{Analysis, AnalysisHost, LineCol, RootDatabase}; |
17 | use ide_db::base_db::{ | 17 | use ide_db::base_db::{ |
18 | salsa::{self, ParallelDatabase}, | 18 | salsa::{self, ParallelDatabase}, |
19 | SourceDatabaseExt, | 19 | SourceDatabaseExt, |
@@ -25,7 +25,7 @@ use rayon::prelude::*; | |||
25 | use rustc_hash::FxHashSet; | 25 | use rustc_hash::FxHashSet; |
26 | use stdx::format_to; | 26 | use stdx::format_to; |
27 | use syntax::AstNode; | 27 | use syntax::AstNode; |
28 | use vfs::Vfs; | 28 | use vfs::{Vfs, VfsPath}; |
29 | 29 | ||
30 | use crate::cli::{ | 30 | use 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 | ||
337 | fn 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 | |||
343 | fn shuffle<T>(rng: &mut Rand32, slice: &mut [T]) { | 362 | fn 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..]); |