aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_cli
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_cli')
-rw-r--r--crates/ra_cli/Cargo.toml2
-rw-r--r--crates/ra_cli/src/analysis_bench.rs54
-rw-r--r--crates/ra_cli/src/analysis_stats.rs83
-rw-r--r--crates/ra_cli/src/main.rs56
4 files changed, 149 insertions, 46 deletions
diff --git a/crates/ra_cli/Cargo.toml b/crates/ra_cli/Cargo.toml
index bcd408421..53d4876f6 100644
--- a/crates/ra_cli/Cargo.toml
+++ b/crates/ra_cli/Cargo.toml
@@ -6,8 +6,10 @@ authors = ["rust-analyzer developers"]
6publish = false 6publish = false
7 7
8[dependencies] 8[dependencies]
9itertools = "0.8.0"
9pico-args = "0.3.0" 10pico-args = "0.3.0"
10env_logger = { version = "0.7.1", default-features = false } 11env_logger = { version = "0.7.1", default-features = false }
12rand = { version = "0.7.0", features = ["small_rng"] }
11 13
12ra_syntax = { path = "../ra_syntax" } 14ra_syntax = { path = "../ra_syntax" }
13ra_ide = { path = "../ra_ide" } 15ra_ide = { path = "../ra_ide" }
diff --git a/crates/ra_cli/src/analysis_bench.rs b/crates/ra_cli/src/analysis_bench.rs
index 5485a38ff..4835a68ce 100644
--- a/crates/ra_cli/src/analysis_bench.rs
+++ b/crates/ra_cli/src/analysis_bench.rs
@@ -2,6 +2,7 @@
2 2
3use std::{ 3use std::{
4 path::{Path, PathBuf}, 4 path::{Path, PathBuf},
5 str::FromStr,
5 sync::Arc, 6 sync::Arc,
6 time::Instant, 7 time::Instant,
7}; 8};
@@ -14,12 +15,35 @@ use ra_ide::{Analysis, AnalysisChange, AnalysisHost, FilePosition, LineCol};
14 15
15use crate::Result; 16use crate::Result;
16 17
18pub(crate) struct Position {
19 path: PathBuf,
20 line: u32,
21 column: u32,
22}
23
24impl FromStr for Position {
25 type Err = Box<dyn std::error::Error + Send + Sync>;
26 fn from_str(s: &str) -> Result<Self> {
27 let (path_line, column) = rsplit_at_char(s, ':')?;
28 let (path, line) = rsplit_at_char(path_line, ':')?;
29 Ok(Position { path: path.into(), line: line.parse()?, column: column.parse()? })
30 }
31}
32
33fn rsplit_at_char(s: &str, c: char) -> Result<(&str, &str)> {
34 let idx = s.rfind(':').ok_or_else(|| format!("no `{}` in {}", c, s))?;
35 Ok((&s[..idx], &s[idx + 1..]))
36}
37
17pub(crate) enum Op { 38pub(crate) enum Op {
18 Highlight { path: PathBuf }, 39 Highlight { path: PathBuf },
19 Complete { path: PathBuf, line: u32, column: u32 }, 40 Complete(Position),
41 GotoDef(Position),
20} 42}
21 43
22pub(crate) fn run(verbose: bool, path: &Path, op: Op) -> Result<()> { 44pub(crate) fn run(verbose: bool, path: &Path, op: Op) -> Result<()> {
45 ra_prof::init();
46
23 let start = Instant::now(); 47 let start = Instant::now();
24 eprint!("loading: "); 48 eprint!("loading: ");
25 let (mut host, roots) = ra_batch::load_cargo(path)?; 49 let (mut host, roots) = ra_batch::load_cargo(path)?;
@@ -29,7 +53,7 @@ pub(crate) fn run(verbose: bool, path: &Path, op: Op) -> Result<()> {
29 let file_id = { 53 let file_id = {
30 let path = match &op { 54 let path = match &op {
31 Op::Highlight { path } => path, 55 Op::Highlight { path } => path,
32 Op::Complete { path, .. } => path, 56 Op::Complete(pos) | Op::GotoDef(pos) => &pos.path,
33 }; 57 };
34 let path = std::env::current_dir()?.join(path).canonicalize()?; 58 let path = std::env::current_dir()?.join(path).canonicalize()?;
35 roots 59 roots
@@ -49,7 +73,7 @@ pub(crate) fn run(verbose: bool, path: &Path, op: Op) -> Result<()> {
49 .ok_or_else(|| format!("Can't find {:?}", path))? 73 .ok_or_else(|| format!("Can't find {:?}", path))?
50 }; 74 };
51 75
52 match op { 76 match &op {
53 Op::Highlight { .. } => { 77 Op::Highlight { .. } => {
54 let res = do_work(&mut host, file_id, |analysis| { 78 let res = do_work(&mut host, file_id, |analysis| {
55 analysis.diagnostics(file_id).unwrap(); 79 analysis.diagnostics(file_id).unwrap();
@@ -59,16 +83,30 @@ pub(crate) fn run(verbose: bool, path: &Path, op: Op) -> Result<()> {
59 println!("\n{}", res); 83 println!("\n{}", res);
60 } 84 }
61 } 85 }
62 Op::Complete { line, column, .. } => { 86 Op::Complete(pos) | Op::GotoDef(pos) => {
87 let is_completion = match op {
88 Op::Complete(..) => true,
89 _ => false,
90 };
91
63 let offset = host 92 let offset = host
64 .analysis() 93 .analysis()
65 .file_line_index(file_id)? 94 .file_line_index(file_id)?
66 .offset(LineCol { line, col_utf16: column }); 95 .offset(LineCol { line: pos.line - 1, col_utf16: pos.column });
67 let file_postion = FilePosition { file_id, offset }; 96 let file_postion = FilePosition { file_id, offset };
68 97
69 let res = do_work(&mut host, file_id, |analysis| analysis.completions(file_postion)); 98 if is_completion {
70 if verbose { 99 let res =
71 println!("\n{:#?}", res); 100 do_work(&mut host, file_id, |analysis| analysis.completions(file_postion));
101 if verbose {
102 println!("\n{:#?}", res);
103 }
104 } else {
105 let res =
106 do_work(&mut host, file_id, |analysis| analysis.goto_definition(file_postion));
107 if verbose {
108 println!("\n{:#?}", res);
109 }
72 } 110 }
73 } 111 }
74 } 112 }
diff --git a/crates/ra_cli/src/analysis_stats.rs b/crates/ra_cli/src/analysis_stats.rs
index 833235bff..6d2dd34c6 100644
--- a/crates/ra_cli/src/analysis_stats.rs
+++ b/crates/ra_cli/src/analysis_stats.rs
@@ -2,6 +2,9 @@
2 2
3use std::{collections::HashSet, fmt::Write, path::Path, time::Instant}; 3use std::{collections::HashSet, fmt::Write, path::Path, time::Instant};
4 4
5use itertools::Itertools;
6use rand::{seq::SliceRandom, thread_rng};
7
5use hir::{ 8use hir::{
6 db::{DefDatabase, HirDatabase}, 9 db::{DefDatabase, HirDatabase},
7 AssocItem, Crate, HasSource, HirDisplay, ModuleDef, 10 AssocItem, Crate, HasSource, HirDisplay, ModuleDef,
@@ -19,6 +22,7 @@ pub fn run(
19 path: &Path, 22 path: &Path,
20 only: Option<&str>, 23 only: Option<&str>,
21 with_deps: bool, 24 with_deps: bool,
25 randomize: bool,
22) -> Result<()> { 26) -> Result<()> {
23 let db_load_time = Instant::now(); 27 let db_load_time = Instant::now();
24 let (mut host, roots) = ra_batch::load_cargo(path)?; 28 let (mut host, roots) = ra_batch::load_cargo(path)?;
@@ -41,7 +45,11 @@ pub fn run(
41 }) 45 })
42 .collect::<HashSet<_>>(); 46 .collect::<HashSet<_>>();
43 47
44 for krate in Crate::all(db) { 48 let mut krates = Crate::all(db);
49 if randomize {
50 krates.shuffle(&mut thread_rng());
51 }
52 for krate in krates {
45 let module = krate.root_module(db).expect("crate without root module"); 53 let module = krate.root_module(db).expect("crate without root module");
46 let file_id = module.definition_source(db).file_id; 54 let file_id = module.definition_source(db).file_id;
47 if members.contains(&db.file_source_root(file_id.original_file(db))) { 55 if members.contains(&db.file_source_root(file_id.original_file(db))) {
@@ -50,6 +58,10 @@ pub fn run(
50 } 58 }
51 } 59 }
52 60
61 if randomize {
62 visit_queue.shuffle(&mut thread_rng());
63 }
64
53 println!("Crates in this dir: {}", num_crates); 65 println!("Crates in this dir: {}", num_crates);
54 let mut num_decls = 0; 66 let mut num_decls = 0;
55 let mut funcs = Vec::new(); 67 let mut funcs = Vec::new();
@@ -79,10 +91,14 @@ pub fn run(
79 println!("Total functions: {}", funcs.len()); 91 println!("Total functions: {}", funcs.len());
80 println!("Item Collection: {:?}, {}", analysis_time.elapsed(), ra_prof::memory_usage()); 92 println!("Item Collection: {:?}, {}", analysis_time.elapsed(), ra_prof::memory_usage());
81 93
94 if randomize {
95 funcs.shuffle(&mut thread_rng());
96 }
97
82 let inference_time = Instant::now(); 98 let inference_time = Instant::now();
83 let mut bar = match verbosity { 99 let mut bar = match verbosity {
84 Verbosity::Verbose | Verbosity::Normal => ProgressReport::new(funcs.len() as u64), 100 Verbosity::Quiet | Verbosity::Spammy => ProgressReport::hidden(),
85 Verbosity::Quiet => ProgressReport::hidden(), 101 _ => ProgressReport::new(funcs.len() as u64),
86 }; 102 };
87 103
88 bar.tick(); 104 bar.tick();
@@ -92,7 +108,20 @@ pub fn run(
92 let mut num_type_mismatches = 0; 108 let mut num_type_mismatches = 0;
93 for f in funcs { 109 for f in funcs {
94 let name = f.name(db); 110 let name = f.name(db);
95 let mut msg = format!("processing: {}", name); 111 let full_name = f
112 .module(db)
113 .path_to_root(db)
114 .into_iter()
115 .rev()
116 .filter_map(|it| it.name(db))
117 .chain(Some(f.name(db)))
118 .join("::");
119 if let Some(only_name) = only {
120 if name.to_string() != only_name && full_name != only_name {
121 continue;
122 }
123 }
124 let mut msg = format!("processing: {}", full_name);
96 if verbosity.is_verbose() { 125 if verbosity.is_verbose() {
97 let src = f.source(db); 126 let src = f.source(db);
98 let original_file = src.file_id.original_file(db); 127 let original_file = src.file_id.original_file(db);
@@ -100,15 +129,15 @@ pub fn run(
100 let syntax_range = src.value.syntax().text_range(); 129 let syntax_range = src.value.syntax().text_range();
101 write!(msg, " ({:?} {})", path, syntax_range).unwrap(); 130 write!(msg, " ({:?} {})", path, syntax_range).unwrap();
102 } 131 }
103 bar.set_message(&msg); 132 if verbosity.is_spammy() {
104 if let Some(only_name) = only { 133 bar.println(format!("{}", msg));
105 if name.to_string() != only_name {
106 continue;
107 }
108 } 134 }
135 bar.set_message(&msg);
109 let f_id = FunctionId::from(f); 136 let f_id = FunctionId::from(f);
110 let body = db.body(f_id.into()); 137 let body = db.body(f_id.into());
111 let inference_result = db.infer(f_id.into()); 138 let inference_result = db.infer(f_id.into());
139 let (previous_exprs, previous_unknown, previous_partially_unknown) =
140 (num_exprs, num_exprs_unknown, num_exprs_partially_unknown);
112 for (expr_id, _) in body.exprs.iter() { 141 for (expr_id, _) in body.exprs.iter() {
113 let ty = &inference_result[expr_id]; 142 let ty = &inference_result[expr_id];
114 num_exprs += 1; 143 num_exprs += 1;
@@ -125,6 +154,33 @@ pub fn run(
125 num_exprs_partially_unknown += 1; 154 num_exprs_partially_unknown += 1;
126 } 155 }
127 } 156 }
157 if only.is_some() && verbosity.is_spammy() {
158 // in super-verbose mode for just one function, we print every single expression
159 let (_, sm) = db.body_with_source_map(f_id.into());
160 let src = sm.expr_syntax(expr_id);
161 if let Some(src) = src {
162 let original_file = src.file_id.original_file(db);
163 let line_index = host.analysis().file_line_index(original_file).unwrap();
164 let text_range = src.value.either(
165 |it| it.syntax_node_ptr().range(),
166 |it| it.syntax_node_ptr().range(),
167 );
168 let (start, end) = (
169 line_index.line_col(text_range.start()),
170 line_index.line_col(text_range.end()),
171 );
172 bar.println(format!(
173 "{}:{}-{}:{}: {}",
174 start.line + 1,
175 start.col_utf16,
176 end.line + 1,
177 end.col_utf16,
178 ty.display(db)
179 ));
180 } else {
181 bar.println(format!("unknown location: {}", ty.display(db)));
182 }
183 }
128 if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr_id) { 184 if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr_id) {
129 num_type_mismatches += 1; 185 num_type_mismatches += 1;
130 if verbosity.is_verbose() { 186 if verbosity.is_verbose() {
@@ -164,6 +220,15 @@ pub fn run(
164 } 220 }
165 } 221 }
166 } 222 }
223 if verbosity.is_spammy() {
224 bar.println(format!(
225 "In {}: {} exprs, {} unknown, {} partial",
226 full_name,
227 num_exprs - previous_exprs,
228 num_exprs_unknown - previous_unknown,
229 num_exprs_partially_unknown - previous_partially_unknown
230 ));
231 }
167 bar.inc(1); 232 bar.inc(1);
168 } 233 }
169 bar.finish_and_clear(); 234 bar.finish_and_clear();
diff --git a/crates/ra_cli/src/main.rs b/crates/ra_cli/src/main.rs
index 806612c2c..750cbab86 100644
--- a/crates/ra_cli/src/main.rs
+++ b/crates/ra_cli/src/main.rs
@@ -16,6 +16,7 @@ type Result<T> = std::result::Result<T, Box<dyn Error + Send + Sync>>;
16 16
17#[derive(Clone, Copy)] 17#[derive(Clone, Copy)]
18pub enum Verbosity { 18pub enum Verbosity {
19 Spammy,
19 Verbose, 20 Verbose,
20 Normal, 21 Normal,
21 Quiet, 22 Quiet,
@@ -24,7 +25,13 @@ pub enum Verbosity {
24impl Verbosity { 25impl Verbosity {
25 fn is_verbose(self) -> bool { 26 fn is_verbose(self) -> bool {
26 match self { 27 match self {
27 Verbosity::Verbose => true, 28 Verbosity::Verbose | Verbosity::Spammy => true,
29 _ => false,
30 }
31 }
32 fn is_spammy(self) -> bool {
33 match self {
34 Verbosity::Spammy => true,
28 _ => false, 35 _ => false,
29 } 36 }
30 } 37 }
@@ -86,14 +93,18 @@ fn main() -> Result<()> {
86 return Ok(()); 93 return Ok(());
87 } 94 }
88 let verbosity = match ( 95 let verbosity = match (
96 matches.contains(["-vv", "--spammy"]),
89 matches.contains(["-v", "--verbose"]), 97 matches.contains(["-v", "--verbose"]),
90 matches.contains(["-q", "--quiet"]), 98 matches.contains(["-q", "--quiet"]),
91 ) { 99 ) {
92 (false, false) => Verbosity::Normal, 100 (true, _, true) => Err("Invalid flags: -q conflicts with -vv")?,
93 (false, true) => Verbosity::Quiet, 101 (true, _, false) => Verbosity::Spammy,
94 (true, false) => Verbosity::Verbose, 102 (false, false, false) => Verbosity::Normal,
95 (true, true) => Err("Invalid flags: -q conflicts with -v")?, 103 (false, false, true) => Verbosity::Quiet,
104 (false, true, false) => Verbosity::Verbose,
105 (false, true, true) => Err("Invalid flags: -q conflicts with -v")?,
96 }; 106 };
107 let randomize = matches.contains("--randomize");
97 let memory_usage = matches.contains("--memory-usage"); 108 let memory_usage = matches.contains("--memory-usage");
98 let only: Option<String> = matches.opt_value_from_str(["-o", "--only"])?; 109 let only: Option<String> = matches.opt_value_from_str(["-o", "--only"])?;
99 let with_deps: bool = matches.contains("--with-deps"); 110 let with_deps: bool = matches.contains("--with-deps");
@@ -111,6 +122,7 @@ fn main() -> Result<()> {
111 path.as_ref(), 122 path.as_ref(),
112 only.as_ref().map(String::as_ref), 123 only.as_ref().map(String::as_ref),
113 with_deps, 124 with_deps,
125 randomize,
114 )?; 126 )?;
115 } 127 }
116 "analysis-bench" => { 128 "analysis-bench" => {
@@ -120,25 +132,16 @@ fn main() -> Result<()> {
120 } 132 }
121 let verbose = matches.contains(["-v", "--verbose"]); 133 let verbose = matches.contains(["-v", "--verbose"]);
122 let path: String = matches.opt_value_from_str("--path")?.unwrap_or_default(); 134 let path: String = matches.opt_value_from_str("--path")?.unwrap_or_default();
123 let highlight_path = matches.opt_value_from_str("--highlight")?; 135 let highlight_path: Option<String> = matches.opt_value_from_str("--highlight")?;
124 let complete_path = matches.opt_value_from_str("--complete")?; 136 let complete_path: Option<String> = matches.opt_value_from_str("--complete")?;
125 if highlight_path.is_some() && complete_path.is_some() { 137 let goto_def_path: Option<String> = matches.opt_value_from_str("--goto-def")?;
126 panic!("either --highlight or --complete must be set, not both") 138 let op = match (highlight_path, complete_path, goto_def_path) {
127 } 139 (Some(path), None, None) => analysis_bench::Op::Highlight { path: path.into() },
128 let op = if let Some(path) = highlight_path { 140 (None, Some(position), None) => analysis_bench::Op::Complete(position.parse()?),
129 let path: String = path; 141 (None, None, Some(position)) => analysis_bench::Op::GotoDef(position.parse()?),
130 analysis_bench::Op::Highlight { path: path.into() } 142 _ => panic!(
131 } else if let Some(path_line_col) = complete_path { 143 "exactly one of `--highlight`, `--complete` or `--goto-def` must be set"
132 let path_line_col: String = path_line_col; 144 ),
133 let (path_line, column) = rsplit_at_char(path_line_col.as_str(), ':')?;
134 let (path, line) = rsplit_at_char(path_line, ':')?;
135 analysis_bench::Op::Complete {
136 path: path.into(),
137 line: line.parse()?,
138 column: column.parse()?,
139 }
140 } else {
141 panic!("either --highlight or --complete must be set")
142 }; 145 };
143 matches.finish().or_else(handle_extra_flags)?; 146 matches.finish().or_else(handle_extra_flags)?;
144 analysis_bench::run(verbose, path.as_ref(), op)?; 147 analysis_bench::run(verbose, path.as_ref(), op)?;
@@ -171,8 +174,3 @@ fn read_stdin() -> Result<String> {
171 std::io::stdin().read_to_string(&mut buff)?; 174 std::io::stdin().read_to_string(&mut buff)?;
172 Ok(buff) 175 Ok(buff)
173} 176}
174
175fn rsplit_at_char(s: &str, c: char) -> Result<(&str, &str)> {
176 let idx = s.rfind(':').ok_or_else(|| format!("no `{}` in {}", c, s))?;
177 Ok((&s[..idx], &s[idx + 1..]))
178}