From 6964a88e8c90f06220498d3e9194b7e2073c1e32 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 9 Feb 2019 18:27:11 +0100 Subject: Add an ra_cli command that analyses all crates in the current workspace ... and prints various stats about how many expressions have a type etc. --- crates/ra_cli/src/analysis_stats.rs | 100 ++++++++++++++++++++++++++++++++++++ crates/ra_cli/src/main.rs | 11 ++++ 2 files changed, 111 insertions(+) create mode 100644 crates/ra_cli/src/analysis_stats.rs (limited to 'crates/ra_cli/src') diff --git a/crates/ra_cli/src/analysis_stats.rs b/crates/ra_cli/src/analysis_stats.rs new file mode 100644 index 000000000..a46ac974d --- /dev/null +++ b/crates/ra_cli/src/analysis_stats.rs @@ -0,0 +1,100 @@ +use std::collections::HashSet; + +use ra_db::SourceDatabase; +use ra_batch::BatchDatabase; +use ra_hir::{Crate, ModuleDef, Ty, ImplItem}; +use ra_syntax::AstNode; + +use crate::Result; + +pub fn run(verbose: bool) -> Result<()> { + let (db, roots) = BatchDatabase::load_cargo(".")?; + println!("Database loaded, {} roots", roots.len()); + let mut num_crates = 0; + let mut visited_modules = HashSet::new(); + let mut visit_queue = Vec::new(); + for root in roots { + for krate in Crate::source_root_crates(&db, root) { + num_crates += 1; + let module = krate.root_module(&db).expect("crate in source root without root module"); + visit_queue.push(module); + } + } + println!("Crates in this dir: {}", num_crates); + let mut num_decls = 0; + let mut funcs = Vec::new(); + while let Some(module) = visit_queue.pop() { + if visited_modules.insert(module) { + visit_queue.extend(module.children(&db)); + + for decl in module.declarations(&db) { + num_decls += 1; + match decl { + ModuleDef::Function(f) => funcs.push(f), + _ => {} + } + } + + for impl_block in module.impl_blocks(&db) { + for item in impl_block.items() { + num_decls += 1; + match item { + ImplItem::Method(f) => funcs.push(*f), + _ => {} + } + } + } + } + } + println!("Total modules found: {}", visited_modules.len()); + println!("Total declarations: {}", num_decls); + println!("Total functions: {}", funcs.len()); + let bar = indicatif::ProgressBar::new(funcs.len() as u64); + bar.tick(); + let mut num_exprs = 0; + let mut num_exprs_unknown = 0; + let mut num_exprs_partially_unknown = 0; + for f in funcs { + if verbose { + let (file_id, source) = f.source(&db); + let original_file = file_id.original_file(&db); + let path = db.file_relative_path(original_file); + let syntax_range = source.syntax().range(); + let name = f.name(&db); + println!("{} ({:?} {})", name, path, syntax_range); + } + let body = f.body(&db); + let inference_result = f.infer(&db); + for (expr_id, _) in body.exprs() { + let ty = &inference_result[expr_id]; + num_exprs += 1; + if let Ty::Unknown = ty { + num_exprs_unknown += 1; + } else { + let mut is_partially_unknown = false; + ty.walk(&mut |ty| { + if let Ty::Unknown = ty { + is_partially_unknown = true; + } + }); + if is_partially_unknown { + num_exprs_partially_unknown += 1; + } + } + } + bar.inc(1); + } + bar.finish_and_clear(); + println!("Total expressions: {}", num_exprs); + println!( + "Expressions of unknown type: {} ({}%)", + num_exprs_unknown, + (num_exprs_unknown * 100 / num_exprs) + ); + println!( + "Expressions of partially unknown type: {} ({}%)", + num_exprs_partially_unknown, + (num_exprs_partially_unknown * 100 / num_exprs) + ); + Ok(()) +} diff --git a/crates/ra_cli/src/main.rs b/crates/ra_cli/src/main.rs index a4debeb48..72e6ae4d5 100644 --- a/crates/ra_cli/src/main.rs +++ b/crates/ra_cli/src/main.rs @@ -1,3 +1,5 @@ +mod analysis_stats; + use std::{fs, io::Read, path::Path, time::Instant}; use clap::{App, Arg, SubCommand}; @@ -5,10 +7,12 @@ use join_to_string::join; use ra_ide_api_light::{extend_selection, file_structure, syntax_tree}; use ra_syntax::{SourceFile, TextRange, TreeArc, AstNode}; use tools::collect_tests; +use flexi_logger::Logger; type Result = ::std::result::Result; fn main() -> Result<()> { + Logger::with_env().start()?; let matches = App::new("ra-cli") .setting(clap::AppSettings::SubcommandRequiredElseHelp) .subcommand( @@ -23,6 +27,9 @@ fn main() -> Result<()> { .arg(Arg::with_name("start")) .arg(Arg::with_name("end")), ) + .subcommand( + SubCommand::with_name("analysis-stats").arg(Arg::with_name("verbose").short("v")), + ) .get_matches(); match matches.subcommand() { ("parse", Some(matches)) => { @@ -56,6 +63,10 @@ fn main() -> Result<()> { let sels = selections(&file, start, end); println!("{}", sels) } + ("analysis-stats", Some(matches)) => { + let verbose = matches.is_present("verbose"); + analysis_stats::run(verbose)?; + } _ => unreachable!(), } Ok(()) -- cgit v1.2.3