diff options
author | Florian Diebold <[email protected]> | 2019-02-09 17:27:11 +0000 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-02-10 09:56:58 +0000 |
commit | 6964a88e8c90f06220498d3e9194b7e2073c1e32 (patch) | |
tree | a3f8e225118c810d5c2784d64b559e3e05e6b6db /crates/ra_cli | |
parent | 43e52ac9e2b26ec287b1778823bad10851cfd44e (diff) |
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.
Diffstat (limited to 'crates/ra_cli')
-rw-r--r-- | crates/ra_cli/Cargo.toml | 6 | ||||
-rw-r--r-- | crates/ra_cli/src/analysis_stats.rs | 100 | ||||
-rw-r--r-- | crates/ra_cli/src/main.rs | 11 |
3 files changed, 117 insertions, 0 deletions
diff --git a/crates/ra_cli/Cargo.toml b/crates/ra_cli/Cargo.toml index eb1722d5e..641ac5cbd 100644 --- a/crates/ra_cli/Cargo.toml +++ b/crates/ra_cli/Cargo.toml | |||
@@ -9,6 +9,12 @@ publish = false | |||
9 | clap = "2.32.0" | 9 | clap = "2.32.0" |
10 | failure = "0.1.4" | 10 | failure = "0.1.4" |
11 | join_to_string = "0.1.1" | 11 | join_to_string = "0.1.1" |
12 | flexi_logger = "0.10.0" | ||
13 | indicatif = "0.11.0" | ||
14 | |||
12 | ra_syntax = { path = "../ra_syntax" } | 15 | ra_syntax = { path = "../ra_syntax" } |
13 | ra_ide_api_light = { path = "../ra_ide_api_light" } | 16 | ra_ide_api_light = { path = "../ra_ide_api_light" } |
14 | tools = { path = "../tools" } | 17 | tools = { path = "../tools" } |
18 | ra_batch = { path = "../ra_batch" } | ||
19 | ra_hir = { path = "../ra_hir" } | ||
20 | ra_db = { path = "../ra_db" } | ||
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 @@ | |||
1 | use std::collections::HashSet; | ||
2 | |||
3 | use ra_db::SourceDatabase; | ||
4 | use ra_batch::BatchDatabase; | ||
5 | use ra_hir::{Crate, ModuleDef, Ty, ImplItem}; | ||
6 | use ra_syntax::AstNode; | ||
7 | |||
8 | use crate::Result; | ||
9 | |||
10 | pub fn run(verbose: bool) -> Result<()> { | ||
11 | let (db, roots) = BatchDatabase::load_cargo(".")?; | ||
12 | println!("Database loaded, {} roots", roots.len()); | ||
13 | let mut num_crates = 0; | ||
14 | let mut visited_modules = HashSet::new(); | ||
15 | let mut visit_queue = Vec::new(); | ||
16 | for root in roots { | ||
17 | for krate in Crate::source_root_crates(&db, root) { | ||
18 | num_crates += 1; | ||
19 | let module = krate.root_module(&db).expect("crate in source root without root module"); | ||
20 | visit_queue.push(module); | ||
21 | } | ||
22 | } | ||
23 | println!("Crates in this dir: {}", num_crates); | ||
24 | let mut num_decls = 0; | ||
25 | let mut funcs = Vec::new(); | ||
26 | while let Some(module) = visit_queue.pop() { | ||
27 | if visited_modules.insert(module) { | ||
28 | visit_queue.extend(module.children(&db)); | ||
29 | |||
30 | for decl in module.declarations(&db) { | ||
31 | num_decls += 1; | ||
32 | match decl { | ||
33 | ModuleDef::Function(f) => funcs.push(f), | ||
34 | _ => {} | ||
35 | } | ||
36 | } | ||
37 | |||
38 | for impl_block in module.impl_blocks(&db) { | ||
39 | for item in impl_block.items() { | ||
40 | num_decls += 1; | ||
41 | match item { | ||
42 | ImplItem::Method(f) => funcs.push(*f), | ||
43 | _ => {} | ||
44 | } | ||
45 | } | ||
46 | } | ||
47 | } | ||
48 | } | ||
49 | println!("Total modules found: {}", visited_modules.len()); | ||
50 | println!("Total declarations: {}", num_decls); | ||
51 | println!("Total functions: {}", funcs.len()); | ||
52 | let bar = indicatif::ProgressBar::new(funcs.len() as u64); | ||
53 | bar.tick(); | ||
54 | let mut num_exprs = 0; | ||
55 | let mut num_exprs_unknown = 0; | ||
56 | let mut num_exprs_partially_unknown = 0; | ||
57 | for f in funcs { | ||
58 | if verbose { | ||
59 | let (file_id, source) = f.source(&db); | ||
60 | let original_file = file_id.original_file(&db); | ||
61 | let path = db.file_relative_path(original_file); | ||
62 | let syntax_range = source.syntax().range(); | ||
63 | let name = f.name(&db); | ||
64 | println!("{} ({:?} {})", name, path, syntax_range); | ||
65 | } | ||
66 | let body = f.body(&db); | ||
67 | let inference_result = f.infer(&db); | ||
68 | for (expr_id, _) in body.exprs() { | ||
69 | let ty = &inference_result[expr_id]; | ||
70 | num_exprs += 1; | ||
71 | if let Ty::Unknown = ty { | ||
72 | num_exprs_unknown += 1; | ||
73 | } else { | ||
74 | let mut is_partially_unknown = false; | ||
75 | ty.walk(&mut |ty| { | ||
76 | if let Ty::Unknown = ty { | ||
77 | is_partially_unknown = true; | ||
78 | } | ||
79 | }); | ||
80 | if is_partially_unknown { | ||
81 | num_exprs_partially_unknown += 1; | ||
82 | } | ||
83 | } | ||
84 | } | ||
85 | bar.inc(1); | ||
86 | } | ||
87 | bar.finish_and_clear(); | ||
88 | println!("Total expressions: {}", num_exprs); | ||
89 | println!( | ||
90 | "Expressions of unknown type: {} ({}%)", | ||
91 | num_exprs_unknown, | ||
92 | (num_exprs_unknown * 100 / num_exprs) | ||
93 | ); | ||
94 | println!( | ||
95 | "Expressions of partially unknown type: {} ({}%)", | ||
96 | num_exprs_partially_unknown, | ||
97 | (num_exprs_partially_unknown * 100 / num_exprs) | ||
98 | ); | ||
99 | Ok(()) | ||
100 | } | ||
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 @@ | |||
1 | mod analysis_stats; | ||
2 | |||
1 | use std::{fs, io::Read, path::Path, time::Instant}; | 3 | use std::{fs, io::Read, path::Path, time::Instant}; |
2 | 4 | ||
3 | use clap::{App, Arg, SubCommand}; | 5 | use clap::{App, Arg, SubCommand}; |
@@ -5,10 +7,12 @@ use join_to_string::join; | |||
5 | use ra_ide_api_light::{extend_selection, file_structure, syntax_tree}; | 7 | use ra_ide_api_light::{extend_selection, file_structure, syntax_tree}; |
6 | use ra_syntax::{SourceFile, TextRange, TreeArc, AstNode}; | 8 | use ra_syntax::{SourceFile, TextRange, TreeArc, AstNode}; |
7 | use tools::collect_tests; | 9 | use tools::collect_tests; |
10 | use flexi_logger::Logger; | ||
8 | 11 | ||
9 | type Result<T> = ::std::result::Result<T, failure::Error>; | 12 | type Result<T> = ::std::result::Result<T, failure::Error>; |
10 | 13 | ||
11 | fn main() -> Result<()> { | 14 | fn main() -> Result<()> { |
15 | Logger::with_env().start()?; | ||
12 | let matches = App::new("ra-cli") | 16 | let matches = App::new("ra-cli") |
13 | .setting(clap::AppSettings::SubcommandRequiredElseHelp) | 17 | .setting(clap::AppSettings::SubcommandRequiredElseHelp) |
14 | .subcommand( | 18 | .subcommand( |
@@ -23,6 +27,9 @@ fn main() -> Result<()> { | |||
23 | .arg(Arg::with_name("start")) | 27 | .arg(Arg::with_name("start")) |
24 | .arg(Arg::with_name("end")), | 28 | .arg(Arg::with_name("end")), |
25 | ) | 29 | ) |
30 | .subcommand( | ||
31 | SubCommand::with_name("analysis-stats").arg(Arg::with_name("verbose").short("v")), | ||
32 | ) | ||
26 | .get_matches(); | 33 | .get_matches(); |
27 | match matches.subcommand() { | 34 | match matches.subcommand() { |
28 | ("parse", Some(matches)) => { | 35 | ("parse", Some(matches)) => { |
@@ -56,6 +63,10 @@ fn main() -> Result<()> { | |||
56 | let sels = selections(&file, start, end); | 63 | let sels = selections(&file, start, end); |
57 | println!("{}", sels) | 64 | println!("{}", sels) |
58 | } | 65 | } |
66 | ("analysis-stats", Some(matches)) => { | ||
67 | let verbose = matches.is_present("verbose"); | ||
68 | analysis_stats::run(verbose)?; | ||
69 | } | ||
59 | _ => unreachable!(), | 70 | _ => unreachable!(), |
60 | } | 71 | } |
61 | Ok(()) | 72 | Ok(()) |