diff options
-rw-r--r-- | crates/rust-analyzer/src/bin/args.rs | 34 | ||||
-rw-r--r-- | crates/rust-analyzer/src/bin/main.rs | 4 | ||||
-rw-r--r-- | crates/rust-analyzer/src/cli.rs | 8 | ||||
-rw-r--r-- | crates/rust-analyzer/src/cli/diagnostics.rs | 74 |
4 files changed, 117 insertions, 3 deletions
diff --git a/crates/rust-analyzer/src/bin/args.rs b/crates/rust-analyzer/src/bin/args.rs index 3cf394bb4..25367df45 100644 --- a/crates/rust-analyzer/src/bin/args.rs +++ b/crates/rust-analyzer/src/bin/args.rs | |||
@@ -35,6 +35,10 @@ pub(crate) enum Command { | |||
35 | what: BenchWhat, | 35 | what: BenchWhat, |
36 | load_output_dirs: bool, | 36 | load_output_dirs: bool, |
37 | }, | 37 | }, |
38 | Diagnostics { | ||
39 | path: PathBuf, | ||
40 | load_output_dirs: bool, | ||
41 | }, | ||
38 | RunServer, | 42 | RunServer, |
39 | Version, | 43 | Version, |
40 | } | 44 | } |
@@ -209,6 +213,36 @@ ARGS: | |||
209 | let load_output_dirs = matches.contains("--load-output-dirs"); | 213 | let load_output_dirs = matches.contains("--load-output-dirs"); |
210 | Command::Bench { path, what, load_output_dirs } | 214 | Command::Bench { path, what, load_output_dirs } |
211 | } | 215 | } |
216 | "diagnostics" => { | ||
217 | if matches.contains(["-h", "--help"]) { | ||
218 | eprintln!( | ||
219 | "\ | ||
220 | ra-cli-diagnostics | ||
221 | |||
222 | USAGE: | ||
223 | rust-analyzer diagnostics [FLAGS] [PATH] | ||
224 | |||
225 | FLAGS: | ||
226 | -h, --help Prints help information | ||
227 | --load-output-dirs Load OUT_DIR values by running `cargo check` before analysis | ||
228 | |||
229 | ARGS: | ||
230 | <PATH>" | ||
231 | ); | ||
232 | return Ok(Err(HelpPrinted)); | ||
233 | } | ||
234 | |||
235 | let load_output_dirs = matches.contains("--load-output-dirs"); | ||
236 | let path = { | ||
237 | let mut trailing = matches.free()?; | ||
238 | if trailing.len() != 1 { | ||
239 | bail!("Invalid flags"); | ||
240 | } | ||
241 | trailing.pop().unwrap().into() | ||
242 | }; | ||
243 | |||
244 | Command::Diagnostics { path, load_output_dirs } | ||
245 | } | ||
212 | _ => { | 246 | _ => { |
213 | eprintln!( | 247 | eprintln!( |
214 | "\ | 248 | "\ |
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs index 608f4f67b..4edd617ee 100644 --- a/crates/rust-analyzer/src/bin/main.rs +++ b/crates/rust-analyzer/src/bin/main.rs | |||
@@ -39,6 +39,10 @@ fn main() -> Result<()> { | |||
39 | cli::analysis_bench(args.verbosity, path.as_ref(), what, load_output_dirs)? | 39 | cli::analysis_bench(args.verbosity, path.as_ref(), what, load_output_dirs)? |
40 | } | 40 | } |
41 | 41 | ||
42 | args::Command::Diagnostics { path, load_output_dirs } => { | ||
43 | cli::diagnostics(path.as_ref(), load_output_dirs)? | ||
44 | } | ||
45 | |||
42 | args::Command::RunServer => run_server()?, | 46 | args::Command::RunServer => run_server()?, |
43 | args::Command::Version => println!("rust-analyzer {}", env!("REV")), | 47 | args::Command::Version => println!("rust-analyzer {}", env!("REV")), |
44 | } | 48 | } |
diff --git a/crates/rust-analyzer/src/cli.rs b/crates/rust-analyzer/src/cli.rs index c9738d101..a865a7c7e 100644 --- a/crates/rust-analyzer/src/cli.rs +++ b/crates/rust-analyzer/src/cli.rs | |||
@@ -3,6 +3,7 @@ | |||
3 | mod load_cargo; | 3 | mod load_cargo; |
4 | mod analysis_stats; | 4 | mod analysis_stats; |
5 | mod analysis_bench; | 5 | mod analysis_bench; |
6 | mod diagnostics; | ||
6 | mod progress_report; | 7 | mod progress_report; |
7 | 8 | ||
8 | use std::io::Read; | 9 | use std::io::Read; |
@@ -12,6 +13,10 @@ use ra_ide::{file_structure, Analysis}; | |||
12 | use ra_prof::profile; | 13 | use ra_prof::profile; |
13 | use ra_syntax::{AstNode, SourceFile}; | 14 | use ra_syntax::{AstNode, SourceFile}; |
14 | 15 | ||
16 | pub use analysis_bench::{analysis_bench, BenchWhat, Position}; | ||
17 | pub use analysis_stats::analysis_stats; | ||
18 | pub use diagnostics::diagnostics; | ||
19 | |||
15 | #[derive(Clone, Copy)] | 20 | #[derive(Clone, Copy)] |
16 | pub enum Verbosity { | 21 | pub enum Verbosity { |
17 | Spammy, | 22 | Spammy, |
@@ -60,9 +65,6 @@ pub fn highlight(rainbow: bool) -> Result<()> { | |||
60 | Ok(()) | 65 | Ok(()) |
61 | } | 66 | } |
62 | 67 | ||
63 | pub use analysis_bench::{analysis_bench, BenchWhat, Position}; | ||
64 | pub use analysis_stats::analysis_stats; | ||
65 | |||
66 | fn file() -> Result<SourceFile> { | 68 | fn file() -> Result<SourceFile> { |
67 | let text = read_stdin()?; | 69 | let text = read_stdin()?; |
68 | Ok(SourceFile::parse(&text).tree()) | 70 | Ok(SourceFile::parse(&text).tree()) |
diff --git a/crates/rust-analyzer/src/cli/diagnostics.rs b/crates/rust-analyzer/src/cli/diagnostics.rs new file mode 100644 index 000000000..f5aab89a2 --- /dev/null +++ b/crates/rust-analyzer/src/cli/diagnostics.rs | |||
@@ -0,0 +1,74 @@ | |||
1 | //! Analyze all files in project for diagnostics. Exits with a non-zero status | ||
2 | //! code if any errors are found. | ||
3 | |||
4 | use anyhow::anyhow; | ||
5 | use ra_db::{SourceDatabaseExt, SourceRootId}; | ||
6 | use ra_ide::{Analysis, Severity}; | ||
7 | use std::{collections::HashSet, path::Path}; | ||
8 | |||
9 | use crate::cli::{load_cargo::load_cargo, Result}; | ||
10 | use hir::{db::HirDatabase, Crate, Module}; | ||
11 | |||
12 | pub fn diagnostics(path: &Path, load_output_dirs: bool) -> Result<()> { | ||
13 | let (host, roots) = load_cargo(path, load_output_dirs)?; | ||
14 | let db = host.raw_database(); | ||
15 | let analysis = host.analysis(); | ||
16 | let members = roots | ||
17 | .into_iter() | ||
18 | .filter_map( | ||
19 | |(source_root_id, project_root)| { | ||
20 | if project_root.is_member() { | ||
21 | Some(source_root_id) | ||
22 | } else { | ||
23 | None | ||
24 | } | ||
25 | }, | ||
26 | ) | ||
27 | .collect::<HashSet<_>>(); | ||
28 | |||
29 | let mut found_error = false; | ||
30 | let mut visited_modules = HashSet::new(); | ||
31 | for krate in Crate::all(db) { | ||
32 | let module = krate.root_module(db).expect("crate without root module"); | ||
33 | check_module(module, db, &mut visited_modules, &members, &analysis, &mut found_error); | ||
34 | } | ||
35 | |||
36 | println!(); | ||
37 | println!("diagnostic scan complete"); | ||
38 | |||
39 | if found_error { | ||
40 | println!(); | ||
41 | Err(anyhow!("diagnostic error detected")) | ||
42 | } else { | ||
43 | Ok(()) | ||
44 | } | ||
45 | } | ||
46 | |||
47 | fn check_module( | ||
48 | module: Module, | ||
49 | db: &(impl HirDatabase + SourceDatabaseExt), | ||
50 | visited_modules: &mut HashSet<Module>, | ||
51 | members: &HashSet<SourceRootId>, | ||
52 | analysis: &Analysis, | ||
53 | found_error: &mut bool, | ||
54 | ) { | ||
55 | let file_id = module.definition_source(db).file_id.original_file(db); | ||
56 | if !visited_modules.contains(&module) { | ||
57 | if members.contains(&db.file_source_root(file_id)) { | ||
58 | println!("processing: {}", db.file_relative_path(file_id)); | ||
59 | for diagnostic in analysis.diagnostics(file_id).unwrap() { | ||
60 | if matches!(diagnostic.severity, Severity::Error) { | ||
61 | *found_error = true; | ||
62 | } | ||
63 | |||
64 | println!("{:?}", diagnostic); | ||
65 | } | ||
66 | } | ||
67 | |||
68 | visited_modules.insert(module); | ||
69 | |||
70 | for child_module in module.children(db) { | ||
71 | check_module(child_module, db, visited_modules, members, analysis, found_error); | ||
72 | } | ||
73 | } | ||
74 | } | ||