aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Mcguigan <[email protected]>2020-04-13 13:44:35 +0100
committerJosh Mcguigan <[email protected]>2020-04-14 02:40:41 +0100
commitf62c73a97286a49c228cd13c32ed37340afd2c1d (patch)
tree1d0e15b4b93b49ab64f68ff42b8efc6886be1068
parentc388130f5ffbcbe7d3131213a24d12d02f769b87 (diff)
add diagnostics subcommand to rust-analyzer CLI
-rw-r--r--crates/rust-analyzer/src/bin/args.rs34
-rw-r--r--crates/rust-analyzer/src/bin/main.rs4
-rw-r--r--crates/rust-analyzer/src/cli.rs8
-rw-r--r--crates/rust-analyzer/src/cli/diagnostics.rs74
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 "\
220ra-cli-diagnostics
221
222USAGE:
223 rust-analyzer diagnostics [FLAGS] [PATH]
224
225FLAGS:
226 -h, --help Prints help information
227 --load-output-dirs Load OUT_DIR values by running `cargo check` before analysis
228
229ARGS:
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 @@
3mod load_cargo; 3mod load_cargo;
4mod analysis_stats; 4mod analysis_stats;
5mod analysis_bench; 5mod analysis_bench;
6mod diagnostics;
6mod progress_report; 7mod progress_report;
7 8
8use std::io::Read; 9use std::io::Read;
@@ -12,6 +13,10 @@ use ra_ide::{file_structure, Analysis};
12use ra_prof::profile; 13use ra_prof::profile;
13use ra_syntax::{AstNode, SourceFile}; 14use ra_syntax::{AstNode, SourceFile};
14 15
16pub use analysis_bench::{analysis_bench, BenchWhat, Position};
17pub use analysis_stats::analysis_stats;
18pub use diagnostics::diagnostics;
19
15#[derive(Clone, Copy)] 20#[derive(Clone, Copy)]
16pub enum Verbosity { 21pub enum Verbosity {
17 Spammy, 22 Spammy,
@@ -60,9 +65,6 @@ pub fn highlight(rainbow: bool) -> Result<()> {
60 Ok(()) 65 Ok(())
61} 66}
62 67
63pub use analysis_bench::{analysis_bench, BenchWhat, Position};
64pub use analysis_stats::analysis_stats;
65
66fn file() -> Result<SourceFile> { 68fn 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
4use anyhow::anyhow;
5use ra_db::{SourceDatabaseExt, SourceRootId};
6use ra_ide::{Analysis, Severity};
7use std::{collections::HashSet, path::Path};
8
9use crate::cli::{load_cargo::load_cargo, Result};
10use hir::{db::HirDatabase, Crate, Module};
11
12pub 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
47fn 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}