aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/assists/src/handlers/inline_local_variable.rs31
-rw-r--r--crates/rust-analyzer/src/bin/args.rs492
-rw-r--r--crates/rust-analyzer/src/bin/logger.rs73
-rw-r--r--crates/rust-analyzer/src/bin/main.rs29
-rw-r--r--crates/rust-analyzer/src/cli/diagnostics.rs7
-rw-r--r--docs/user/manual.adoc2
6 files changed, 289 insertions, 345 deletions
diff --git a/crates/assists/src/handlers/inline_local_variable.rs b/crates/assists/src/handlers/inline_local_variable.rs
index 164bbce86..587eb5feb 100644
--- a/crates/assists/src/handlers/inline_local_variable.rs
+++ b/crates/assists/src/handlers/inline_local_variable.rs
@@ -1,4 +1,4 @@
1use ide_db::defs::Definition; 1use ide_db::{defs::Definition, search::ReferenceKind};
2use syntax::{ 2use syntax::{
3 ast::{self, AstNode, AstToken}, 3 ast::{self, AstNode, AstToken},
4 TextRange, 4 TextRange,
@@ -119,7 +119,13 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> O
119 for (desc, should_wrap) in refs.iter().zip(wrap_in_parens) { 119 for (desc, should_wrap) in refs.iter().zip(wrap_in_parens) {
120 let replacement = 120 let replacement =
121 if should_wrap { init_in_paren.clone() } else { init_str.clone() }; 121 if should_wrap { init_in_paren.clone() } else { init_str.clone() };
122 builder.replace(desc.file_range.range, replacement) 122 match desc.kind {
123 ReferenceKind::FieldShorthandForLocal => {
124 mark::hit!(inline_field_shorthand);
125 builder.insert(desc.file_range.range.end(), format!(": {}", replacement))
126 }
127 _ => builder.replace(desc.file_range.range, replacement),
128 }
123 } 129 }
124 }, 130 },
125 ) 131 )
@@ -667,6 +673,27 @@ fn foo() {
667 } 673 }
668 674
669 #[test] 675 #[test]
676 fn inline_field_shorthand() {
677 mark::check!(inline_field_shorthand);
678 check_assist(
679 inline_local_variable,
680 r"
681struct S { foo: i32}
682fn main() {
683 let <|>foo = 92;
684 S { foo }
685}
686",
687 r"
688struct S { foo: i32}
689fn main() {
690 S { foo: 92 }
691}
692",
693 );
694 }
695
696 #[test]
670 fn test_not_applicable_if_variable_unused() { 697 fn test_not_applicable_if_variable_unused() {
671 mark::check!(test_not_applicable_if_variable_unused); 698 mark::check!(test_not_applicable_if_variable_unused);
672 check_assist_not_applicable( 699 check_assist_not_applicable(
diff --git a/crates/rust-analyzer/src/bin/args.rs b/crates/rust-analyzer/src/bin/args.rs
index 0bc92431a..8ddf1e031 100644
--- a/crates/rust-analyzer/src/bin/args.rs
+++ b/crates/rust-analyzer/src/bin/args.rs
@@ -3,9 +3,9 @@
3//! If run started args, we run the LSP server loop. With a subcommand, we do a 3//! If run started args, we run the LSP server loop. With a subcommand, we do a
4//! one-time batch processing. 4//! one-time batch processing.
5 5
6use std::{env, fmt::Write, path::PathBuf}; 6use std::{env, path::PathBuf};
7 7
8use anyhow::{bail, Result}; 8use anyhow::{bail, format_err, Result};
9use pico_args::Arguments; 9use pico_args::Arguments;
10use rust_analyzer::cli::{AnalysisStatsCmd, BenchCmd, BenchWhat, Position, Verbosity}; 10use rust_analyzer::cli::{AnalysisStatsCmd, BenchCmd, BenchWhat, Position, Verbosity};
11use ssr::{SsrPattern, SsrRule}; 11use ssr::{SsrPattern, SsrRule};
@@ -13,47 +13,107 @@ use vfs::AbsPathBuf;
13 13
14pub(crate) struct Args { 14pub(crate) struct Args {
15 pub(crate) verbosity: Verbosity, 15 pub(crate) verbosity: Verbosity,
16 pub(crate) log_file: Option<PathBuf>,
16 pub(crate) command: Command, 17 pub(crate) command: Command,
17} 18}
18 19
19pub(crate) enum Command { 20pub(crate) enum Command {
20 Parse { 21 Parse { no_dump: bool },
21 no_dump: bool,
22 },
23 Symbols, 22 Symbols,
24 Highlight { 23 Highlight { rainbow: bool },
25 rainbow: bool,
26 },
27 AnalysisStats(AnalysisStatsCmd), 24 AnalysisStats(AnalysisStatsCmd),
28 Bench(BenchCmd), 25 Bench(BenchCmd),
29 Diagnostics { 26 Diagnostics { path: PathBuf, load_output_dirs: bool, with_proc_macro: bool },
30 path: PathBuf, 27 Ssr { rules: Vec<SsrRule> },
31 load_output_dirs: bool, 28 StructuredSearch { debug_snippet: Option<String>, patterns: Vec<SsrPattern> },
32 with_proc_macro: bool,
33 /// Include files which are not modules. In rust-analyzer
34 /// this would include the parser test files.
35 all: bool,
36 },
37 Ssr {
38 rules: Vec<SsrRule>,
39 },
40 StructuredSearch {
41 debug_snippet: Option<String>,
42 patterns: Vec<SsrPattern>,
43 },
44 ProcMacro, 29 ProcMacro,
45 RunServer, 30 RunServer,
46 Version, 31 Version,
47 Help, 32 Help,
48} 33}
49 34
35const HELP: &str = "\
36rust-analyzer
37
38USAGE:
39 rust-analyzer [FLAGS] [COMMAND] [COMMAND_OPTIONS]
40
41FLAGS:
42 --version Print version
43 -h, --help Print this help
44
45 -v, --verbose
46 -vv, --spammy
47 -q, --quiet Set verbosity
48
49 --log-file <PATH> Log to the specified filed instead of stderr
50
51ENVIRONMENTAL VARIABLES:
52 RA_LOG Set log filter in env_logger format
53 RA_PROFILE Enable hierarchical profiler
54
55COMMANDS:
56
57not specified Launch LSP server
58
59parse < main.rs Parse tree
60 --no-dump Suppress printing
61
62symbols < main.rs Parse input an print the list of symbols
63
64highlight < main.rs Highlight input as html
65 --rainbow Enable rainbow highlighting of identifiers
66
67analysis-stats <PATH> Batch typecheck project and print summary statistics
68 <PATH> Directory with Cargo.toml
69 --randomize Randomize order in which crates, modules, and items are processed
70 --parallel Run type inference in parallel
71 --memory-usage Collect memory usage statistics
72 -o, --only <PATH> Only analyze items matching this path
73 --with-deps Also analyze all dependencies
74 --load-output-dirs
75 Load OUT_DIR values by running `cargo check` before analysis
76 --with-proc-macro Use proc-macro-srv for proc-macro expanding
77
78analysis-bench <PATH> Benchmark specific analysis operation
79 <PATH> Directory with Cargo.toml
80 --highlight <PATH>
81 Compute syntax highlighting for this file
82 --complete <PATH:LINE:COLUMN>
83 Compute completions at this location
84 --goto-def <PATH:LINE:COLUMN>
85 Compute goto definition at this location
86 --memory-usage Collect memory usage statistics
87 --load-output-dirs
88 Load OUT_DIR values by running `cargo check` before analysis
89 --with-proc-macro Use proc-macro-srv for proc-macro expanding
90
91diagnostics <PATH>
92 <PATH> Directory with Cargo.toml
93 --load-output-dirs
94 Load OUT_DIR values by running `cargo check` before analysis
95 --with-proc-macro Use proc-macro-srv for proc-macro expanding
96
97ssr [RULE...]
98 <RULE> A structured search replace rule (`$a.foo($b) ==> bar($a, $b)`)
99
100search [PATTERN..]
101 <PATTERN> A structured search replace pattern (`$a.foo($b)`)
102 --debug <snippet> Prints debug information for any nodes with source exactly
103 equal to <snippet>
104";
105
50impl Args { 106impl Args {
51 pub(crate) fn parse() -> Result<Args> { 107 pub(crate) fn parse() -> Result<Args> {
52 let mut matches = Arguments::from_env(); 108 let mut matches = Arguments::from_env();
53 109
54 if matches.contains("--version") { 110 if matches.contains("--version") {
55 matches.finish().or_else(handle_extra_flags)?; 111 matches.finish()?;
56 return Ok(Args { verbosity: Verbosity::Normal, command: Command::Version }); 112 return Ok(Args {
113 verbosity: Verbosity::Normal,
114 log_file: None,
115 command: Command::Version,
116 });
57 } 117 }
58 118
59 let verbosity = match ( 119 let verbosity = match (
@@ -68,320 +128,96 @@ impl Args {
68 (false, true, false) => Verbosity::Verbose, 128 (false, true, false) => Verbosity::Verbose,
69 (false, true, true) => bail!("Invalid flags: -q conflicts with -v"), 129 (false, true, true) => bail!("Invalid flags: -q conflicts with -v"),
70 }; 130 };
131 let log_file = matches.opt_value_from_str("--log-file")?;
132
133 if matches.contains(["-h", "--help"]) {
134 eprintln!("{}", HELP);
135 return Ok(Args { verbosity, log_file: None, command: Command::Help });
136 }
71 137
72 let help = Ok(Args { verbosity, command: Command::Help });
73 let subcommand = match matches.subcommand()? { 138 let subcommand = match matches.subcommand()? {
74 Some(it) => it, 139 Some(it) => it,
75 None => { 140 None => {
76 if matches.contains(["-h", "--help"]) { 141 matches.finish()?;
77 print_subcommands(); 142 return Ok(Args { verbosity, log_file, command: Command::RunServer });
78 return help;
79 }
80 matches.finish().or_else(handle_extra_flags)?;
81 return Ok(Args { verbosity, command: Command::RunServer });
82 } 143 }
83 }; 144 };
84 let command = match subcommand.as_str() { 145 let command = match subcommand.as_str() {
85 "parse" => { 146 "parse" => Command::Parse { no_dump: matches.contains("--no-dump") },
86 if matches.contains(["-h", "--help"]) { 147 "symbols" => Command::Symbols,
87 eprintln!( 148 "highlight" => Command::Highlight { rainbow: matches.contains("--rainbow") },
88 "\ 149 "analysis-stats" => Command::AnalysisStats(AnalysisStatsCmd {
89rust-analyzer parse 150 randomize: matches.contains("--randomize"),
90 151 parallel: matches.contains("--parallel"),
91USAGE: 152 memory_usage: matches.contains("--memory-usage"),
92 rust-analyzer parse [FLAGS] 153 only: matches.opt_value_from_str(["-o", "--only"])?,
93 154 with_deps: matches.contains("--with-deps"),
94FLAGS: 155 load_output_dirs: matches.contains("--load-output-dirs"),
95 -h, --help Prints help information 156 with_proc_macro: matches.contains("--with-proc-macro"),
96 --no-dump" 157 path: matches
97 ); 158 .free_from_str()?
98 return help; 159 .ok_or_else(|| format_err!("expected positional argument"))?,
99 } 160 }),
100 161 "analysis-bench" => Command::Bench(BenchCmd {
101 let no_dump = matches.contains("--no-dump"); 162 what: {
102 matches.finish().or_else(handle_extra_flags)?; 163 let highlight_path: Option<String> =
103 Command::Parse { no_dump } 164 matches.opt_value_from_str("--highlight")?;
104 } 165 let complete_path: Option<Position> =
105 "symbols" => { 166 matches.opt_value_from_str("--complete")?;
106 if matches.contains(["-h", "--help"]) { 167 let goto_def_path: Option<Position> =
107 eprintln!( 168 matches.opt_value_from_str("--goto-def")?;
108 "\ 169 match (highlight_path, complete_path, goto_def_path) {
109rust-analyzer symbols 170 (Some(path), None, None) => {
110 171 let path = env::current_dir().unwrap().join(path);
111USAGE: 172 BenchWhat::Highlight { path: AbsPathBuf::assert(path) }
112 rust-analyzer highlight [FLAGS] 173 }
113 174 (None, Some(position), None) => BenchWhat::Complete(position),
114FLAGS: 175 (None, None, Some(position)) => BenchWhat::GotoDef(position),
115 -h, --help Prints help inforamtion" 176 _ => panic!(
116 ); 177 "exactly one of `--highlight`, `--complete` or `--goto-def` must be set"
117 return help; 178 ),
118 } 179 }
119 180 },
120 matches.finish().or_else(handle_extra_flags)?; 181 memory_usage: matches.contains("--memory-usage"),
121 182 load_output_dirs: matches.contains("--load-output-dirs"),
122 Command::Symbols 183 with_proc_macro: matches.contains("--with-proc-macro"),
123 } 184 path: matches
124 "highlight" => { 185 .free_from_str()?
125 if matches.contains(["-h", "--help"]) { 186 .ok_or_else(|| format_err!("expected positional argument"))?,
126 eprintln!( 187 }),
127 "\ 188 "diagnostics" => Command::Diagnostics {
128rust-analyzer highlight 189 load_output_dirs: matches.contains("--load-output-dirs"),
129 190 with_proc_macro: matches.contains("--with-proc-macro"),
130USAGE: 191 path: matches
131 rust-analyzer highlight [FLAGS] 192 .free_from_str()?
132 193 .ok_or_else(|| format_err!("expected positional argument"))?,
133FLAGS: 194 },
134 -h, --help Prints help information 195 "proc-macro" => Command::ProcMacro,
135 -r, --rainbow" 196 "ssr" => Command::Ssr {
136 ); 197 rules: {
137 return help; 198 let mut acc = Vec::new();
138 } 199 while let Some(rule) = matches.free_from_str()? {
139 200 acc.push(rule);
140 let rainbow = matches.contains(["-r", "--rainbow"]);
141 matches.finish().or_else(handle_extra_flags)?;
142 Command::Highlight { rainbow }
143 }
144 "analysis-stats" => {
145 if matches.contains(["-h", "--help"]) {
146 eprintln!(
147 "\
148rust-analyzer analysis-stats
149
150USAGE:
151 rust-analyzer analysis-stats [FLAGS] [OPTIONS] [PATH]
152
153FLAGS:
154 -o, --only Only analyze items matching this path
155 -h, --help Prints help information
156 --memory-usage Collect memory usage statistics
157 --randomize Randomize order in which crates, modules, and items are processed
158 --parallel Run type inference in parallel
159 --load-output-dirs Load OUT_DIR values by running `cargo check` before analysis
160 --with-proc-macro Use ra-proc-macro-srv for proc-macro expanding
161 --with-deps Also analyze all dependencies
162 -v, --verbose
163 -q, --quiet
164
165OPTIONS:
166 -o <ONLY>
167
168ARGS:
169 <PATH>"
170 );
171 return help;
172 }
173
174 let randomize = matches.contains("--randomize");
175 let parallel = matches.contains("--parallel");
176 let memory_usage = matches.contains("--memory-usage");
177 let only: Option<String> = matches.opt_value_from_str(["-o", "--only"])?;
178 let with_deps: bool = matches.contains("--with-deps");
179 let load_output_dirs = matches.contains("--load-output-dirs");
180 let with_proc_macro = matches.contains("--with-proc-macro");
181 let path = {
182 let mut trailing = matches.free()?;
183 if trailing.len() != 1 {
184 bail!("Invalid flags");
185 }
186 trailing.pop().unwrap().into()
187 };
188
189 Command::AnalysisStats(AnalysisStatsCmd {
190 randomize,
191 parallel,
192 memory_usage,
193 only,
194 with_deps,
195 path,
196 load_output_dirs,
197 with_proc_macro,
198 })
199 }
200 "analysis-bench" => {
201 if matches.contains(["-h", "--help"]) {
202 eprintln!(
203 "\
204rust-analyzer analysis-bench
205
206USAGE:
207 rust-analyzer analysis-bench [FLAGS] [OPTIONS]
208
209FLAGS:
210 -h, --help Prints help information
211 --memory-usage Collect memory usage statistics
212 --load-output-dirs Load OUT_DIR values by running `cargo check` before analysis
213 --with-proc-macro Use ra-proc-macro-srv for proc-macro expanding
214 -v, --verbose
215
216OPTIONS:
217 --project <PATH> Path to directory with Cargo.toml
218 --complete <PATH:LINE:COLUMN> Compute completions at this location
219 --goto-def <PATH:LINE:COLUMN> Compute goto definition at this location
220 --highlight <PATH> Hightlight this file
221
222ARGS:
223 <PATH> Project to analyse"
224 );
225 return help;
226 }
227
228 let path: PathBuf = matches.opt_value_from_str("--project")?.unwrap_or_default();
229 let highlight_path: Option<String> = matches.opt_value_from_str("--highlight")?;
230 let complete_path: Option<Position> = matches.opt_value_from_str("--complete")?;
231 let goto_def_path: Option<Position> = matches.opt_value_from_str("--goto-def")?;
232 let what = match (highlight_path, complete_path, goto_def_path) {
233 (Some(path), None, None) => {
234 let path = env::current_dir().unwrap().join(path);
235 BenchWhat::Highlight { path: AbsPathBuf::assert(path) }
236 } 201 }
237 (None, Some(position), None) => BenchWhat::Complete(position), 202 acc
238 (None, None, Some(position)) => BenchWhat::GotoDef(position), 203 },
239 _ => panic!( 204 },
240 "exactly one of `--highlight`, `--complete` or `--goto-def` must be set" 205 "search" => Command::StructuredSearch {
241 ), 206 debug_snippet: matches.opt_value_from_str("--debug")?,
242 }; 207 patterns: {
243 let memory_usage = matches.contains("--memory-usage"); 208 let mut acc = Vec::new();
244 let load_output_dirs = matches.contains("--load-output-dirs"); 209 while let Some(rule) = matches.free_from_str()? {
245 let with_proc_macro = matches.contains("--with-proc-macro"); 210 acc.push(rule);
246 Command::Bench(BenchCmd {
247 memory_usage,
248 path,
249 what,
250 load_output_dirs,
251 with_proc_macro,
252 })
253 }
254 "diagnostics" => {
255 if matches.contains(["-h", "--help"]) {
256 eprintln!(
257 "\
258rust-analyzer diagnostics
259
260USAGE:
261 rust-analyzer diagnostics [FLAGS] [PATH]
262
263FLAGS:
264 -h, --help Prints help information
265 --load-output-dirs Load OUT_DIR values by running `cargo check` before analysis
266 --all Include all files rather than only modules
267
268ARGS:
269 <PATH>"
270 );
271 return help;
272 }
273
274 let load_output_dirs = matches.contains("--load-output-dirs");
275 let with_proc_macro = matches.contains("--with-proc-macro");
276 let all = matches.contains("--all");
277 let path = {
278 let mut trailing = matches.free()?;
279 if trailing.len() != 1 {
280 bail!("Invalid flags");
281 } 211 }
282 trailing.pop().unwrap().into() 212 acc
283 }; 213 },
284 214 },
285 Command::Diagnostics { path, load_output_dirs, with_proc_macro, all }
286 }
287 "proc-macro" => Command::ProcMacro,
288 "ssr" => {
289 if matches.contains(["-h", "--help"]) {
290 eprintln!(
291 "\
292rust-analyzer ssr
293
294USAGE:
295 rust-analyzer ssr [FLAGS] [RULE...]
296
297EXAMPLE:
298 rust-analyzer ssr '$a.foo($b) ==> bar($a, $b)'
299
300FLAGS:
301 --debug <snippet> Prints debug information for any nodes with source exactly equal to <snippet>
302 -h, --help Prints help information
303
304ARGS:
305 <RULE> A structured search replace rule"
306 );
307 return help;
308 }
309 let mut rules = Vec::new();
310 while let Some(rule) = matches.free_from_str()? {
311 rules.push(rule);
312 }
313 Command::Ssr { rules }
314 }
315 "search" => {
316 if matches.contains(["-h", "--help"]) {
317 eprintln!(
318 "\
319rust-analyzer search
320
321USAGE:
322 rust-analyzer search [FLAGS] [PATTERN...]
323
324EXAMPLE:
325 rust-analyzer search '$a.foo($b)'
326
327FLAGS:
328 --debug <snippet> Prints debug information for any nodes with source exactly equal to <snippet>
329 -h, --help Prints help information
330
331ARGS:
332 <PATTERN> A structured search pattern"
333 );
334 return help;
335 }
336 let debug_snippet = matches.opt_value_from_str("--debug")?;
337 let mut patterns = Vec::new();
338 while let Some(rule) = matches.free_from_str()? {
339 patterns.push(rule);
340 }
341 Command::StructuredSearch { patterns, debug_snippet }
342 }
343 _ => { 215 _ => {
344 print_subcommands(); 216 eprintln!("{}", HELP);
345 return help; 217 return Ok(Args { verbosity, log_file: None, command: Command::Help });
346 } 218 }
347 }; 219 };
348 Ok(Args { verbosity, command }) 220 matches.finish()?;
349 } 221 Ok(Args { verbosity, log_file, command })
350}
351
352fn print_subcommands() {
353 eprintln!(
354 "\
355rust-analyzer
356
357USAGE:
358 rust-analyzer <SUBCOMMAND>
359
360FLAGS:
361 -h, --help Prints help information
362
363SUBCOMMANDS:
364 analysis-bench
365 analysis-stats
366 highlight
367 diagnostics
368 proc-macro
369 parse
370 search
371 ssr
372 symbols"
373 )
374}
375
376fn handle_extra_flags(e: pico_args::Error) -> Result<()> {
377 if let pico_args::Error::UnusedArgsLeft(flags) = e {
378 let mut invalid_flags = String::new();
379 for flag in flags {
380 write!(&mut invalid_flags, "{}, ", flag)?;
381 }
382 let (invalid_flags, _) = invalid_flags.split_at(invalid_flags.len() - 2);
383 bail!("Invalid flags: {}", invalid_flags);
384 } else {
385 bail!(e);
386 } 222 }
387} 223}
diff --git a/crates/rust-analyzer/src/bin/logger.rs b/crates/rust-analyzer/src/bin/logger.rs
new file mode 100644
index 000000000..3bcb1ae37
--- /dev/null
+++ b/crates/rust-analyzer/src/bin/logger.rs
@@ -0,0 +1,73 @@
1//! Simple logger that logs either to stderr or to a file, using `env_logger`
2//! filter syntax. Amusingly, there's no crates.io crate that can do this and
3//! only this.
4
5use std::{
6 fs::File,
7 io::{BufWriter, Write},
8};
9
10use env_logger::filter::{Builder, Filter};
11use log::{Log, Metadata, Record};
12use parking_lot::Mutex;
13
14pub(crate) struct Logger {
15 filter: Filter,
16 file: Option<Mutex<BufWriter<File>>>,
17}
18
19impl Logger {
20 pub(crate) fn new(log_file: Option<File>, filter: Option<&str>) -> Logger {
21 let filter = {
22 let mut builder = Builder::new();
23 if let Some(filter) = filter {
24 builder.parse(filter);
25 }
26 builder.build()
27 };
28
29 let file = log_file.map(|it| Mutex::new(BufWriter::new(it)));
30
31 Logger { filter, file }
32 }
33
34 pub(crate) fn install(self) {
35 let max_level = self.filter.filter();
36 let _ = log::set_boxed_logger(Box::new(self)).map(|()| log::set_max_level(max_level));
37 }
38}
39
40impl Log for Logger {
41 fn enabled(&self, metadata: &Metadata) -> bool {
42 self.filter.enabled(metadata)
43 }
44
45 fn log(&self, record: &Record) {
46 if !self.filter.matches(record) {
47 return;
48 }
49 match &self.file {
50 Some(w) => {
51 let _ = writeln!(
52 w.lock(),
53 "[{} {}] {}",
54 record.level(),
55 record.module_path().unwrap_or_default(),
56 record.args(),
57 );
58 }
59 None => eprintln!(
60 "[{} {}] {}",
61 record.level(),
62 record.module_path().unwrap_or_default(),
63 record.args(),
64 ),
65 }
66 }
67
68 fn flush(&self) {
69 if let Some(w) = &self.file {
70 let _ = w.lock().flush();
71 }
72 }
73}
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs
index 0e03a0ca8..ba4402ade 100644
--- a/crates/rust-analyzer/src/bin/main.rs
+++ b/crates/rust-analyzer/src/bin/main.rs
@@ -2,8 +2,9 @@
2//! 2//!
3//! Based on cli flags, either spawns an LSP server, or runs a batch analysis 3//! Based on cli flags, either spawns an LSP server, or runs a batch analysis
4mod args; 4mod args;
5mod logger;
5 6
6use std::{convert::TryFrom, process}; 7use std::{convert::TryFrom, env, fs, path::PathBuf, process};
7 8
8use lsp_server::Connection; 9use lsp_server::Connection;
9use project_model::ProjectManifest; 10use project_model::ProjectManifest;
@@ -26,8 +27,8 @@ fn main() {
26} 27}
27 28
28fn try_main() -> Result<()> { 29fn try_main() -> Result<()> {
29 setup_logging()?;
30 let args = args::Args::parse()?; 30 let args = args::Args::parse()?;
31 setup_logging(args.log_file)?;
31 match args.command { 32 match args.command {
32 args::Command::RunServer => run_server()?, 33 args::Command::RunServer => run_server()?,
33 args::Command::ProcMacro => proc_macro_srv::cli::run()?, 34 args::Command::ProcMacro => proc_macro_srv::cli::run()?,
@@ -37,8 +38,8 @@ fn try_main() -> Result<()> {
37 args::Command::Highlight { rainbow } => cli::highlight(rainbow)?, 38 args::Command::Highlight { rainbow } => cli::highlight(rainbow)?,
38 args::Command::AnalysisStats(cmd) => cmd.run(args.verbosity)?, 39 args::Command::AnalysisStats(cmd) => cmd.run(args.verbosity)?,
39 args::Command::Bench(cmd) => cmd.run(args.verbosity)?, 40 args::Command::Bench(cmd) => cmd.run(args.verbosity)?,
40 args::Command::Diagnostics { path, load_output_dirs, with_proc_macro, all } => { 41 args::Command::Diagnostics { path, load_output_dirs, with_proc_macro } => {
41 cli::diagnostics(path.as_ref(), load_output_dirs, with_proc_macro, all)? 42 cli::diagnostics(path.as_ref(), load_output_dirs, with_proc_macro)?
42 } 43 }
43 args::Command::Ssr { rules } => { 44 args::Command::Ssr { rules } => {
44 cli::apply_ssr_rules(rules)?; 45 cli::apply_ssr_rules(rules)?;
@@ -52,9 +53,21 @@ fn try_main() -> Result<()> {
52 Ok(()) 53 Ok(())
53} 54}
54 55
55fn setup_logging() -> Result<()> { 56fn setup_logging(log_file: Option<PathBuf>) -> Result<()> {
56 std::env::set_var("RUST_BACKTRACE", "short"); 57 env::set_var("RUST_BACKTRACE", "short");
57 env_logger::try_init_from_env("RA_LOG")?; 58
59 let log_file = match log_file {
60 Some(path) => {
61 if let Some(parent) = path.parent() {
62 let _ = fs::create_dir_all(parent);
63 }
64 Some(fs::File::create(path)?)
65 }
66 None => None,
67 };
68 let filter = env::var("RA_LOG").ok();
69 logger::Logger::new(log_file, filter.as_deref()).install();
70
58 profile::init(); 71 profile::init();
59 Ok(()) 72 Ok(())
60} 73}
@@ -95,7 +108,7 @@ fn run_server() -> Result<()> {
95 { 108 {
96 Some(it) => it, 109 Some(it) => it,
97 None => { 110 None => {
98 let cwd = std::env::current_dir()?; 111 let cwd = env::current_dir()?;
99 AbsPathBuf::assert(cwd) 112 AbsPathBuf::assert(cwd)
100 } 113 }
101 }; 114 };
diff --git a/crates/rust-analyzer/src/cli/diagnostics.rs b/crates/rust-analyzer/src/cli/diagnostics.rs
index c424aa6e2..f3b6c900e 100644
--- a/crates/rust-analyzer/src/cli/diagnostics.rs
+++ b/crates/rust-analyzer/src/cli/diagnostics.rs
@@ -12,12 +12,7 @@ use ide::{DiagnosticsConfig, Severity};
12 12
13use crate::cli::{load_cargo::load_cargo, Result}; 13use crate::cli::{load_cargo::load_cargo, Result};
14 14
15pub fn diagnostics( 15pub fn diagnostics(path: &Path, load_output_dirs: bool, with_proc_macro: bool) -> Result<()> {
16 path: &Path,
17 load_output_dirs: bool,
18 with_proc_macro: bool,
19 _all: bool,
20) -> Result<()> {
21 let (host, _vfs) = load_cargo(path, load_output_dirs, with_proc_macro)?; 16 let (host, _vfs) = load_cargo(path, load_output_dirs, with_proc_macro)?;
22 let db = host.raw_database(); 17 let db = host.raw_database();
23 let analysis = host.analysis(); 18 let analysis = host.analysis();
diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc
index 367bba546..b15c9ee7f 100644
--- a/docs/user/manual.adoc
+++ b/docs/user/manual.adoc
@@ -351,7 +351,7 @@ Relative paths are interpreted relative to `rust-project.json` file location or
351 351
352See https://github.com/rust-analyzer/rust-project.json-example for a small example. 352See https://github.com/rust-analyzer/rust-project.json-example for a small example.
353 353
354You can set `RA_LOG` environmental variable to `"'rust_analyzer=info"` to inspect how rust-analyzer handles config and project loading. 354You can set `RA_LOG` environmental variable to `rust_analyzer=info` to inspect how rust-analyzer handles config and project loading.
355 355
356== Features 356== Features
357 357