aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/rust-analyzer/src/bin/args.rs7
-rw-r--r--crates/rust-analyzer/src/bin/main.rs4
-rw-r--r--crates/rust-analyzer/src/cli/diagnostics.rs90
3 files changed, 51 insertions, 50 deletions
diff --git a/crates/rust-analyzer/src/bin/args.rs b/crates/rust-analyzer/src/bin/args.rs
index 25367df45..f5981588a 100644
--- a/crates/rust-analyzer/src/bin/args.rs
+++ b/crates/rust-analyzer/src/bin/args.rs
@@ -38,6 +38,9 @@ pub(crate) enum Command {
38 Diagnostics { 38 Diagnostics {
39 path: PathBuf, 39 path: PathBuf,
40 load_output_dirs: bool, 40 load_output_dirs: bool,
41 /// Include files which are not modules. In rust-analyzer
42 /// this would include the parser test files.
43 all: bool,
41 }, 44 },
42 RunServer, 45 RunServer,
43 Version, 46 Version,
@@ -225,6 +228,7 @@ USAGE:
225FLAGS: 228FLAGS:
226 -h, --help Prints help information 229 -h, --help Prints help information
227 --load-output-dirs Load OUT_DIR values by running `cargo check` before analysis 230 --load-output-dirs Load OUT_DIR values by running `cargo check` before analysis
231 --all Include all files rather than only modules
228 232
229ARGS: 233ARGS:
230 <PATH>" 234 <PATH>"
@@ -233,6 +237,7 @@ ARGS:
233 } 237 }
234 238
235 let load_output_dirs = matches.contains("--load-output-dirs"); 239 let load_output_dirs = matches.contains("--load-output-dirs");
240 let all = matches.contains("--all");
236 let path = { 241 let path = {
237 let mut trailing = matches.free()?; 242 let mut trailing = matches.free()?;
238 if trailing.len() != 1 { 243 if trailing.len() != 1 {
@@ -241,7 +246,7 @@ ARGS:
241 trailing.pop().unwrap().into() 246 trailing.pop().unwrap().into()
242 }; 247 };
243 248
244 Command::Diagnostics { path, load_output_dirs } 249 Command::Diagnostics { path, load_output_dirs, all }
245 } 250 }
246 _ => { 251 _ => {
247 eprintln!( 252 eprintln!(
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs
index 4edd617ee..7cfc44f01 100644
--- a/crates/rust-analyzer/src/bin/main.rs
+++ b/crates/rust-analyzer/src/bin/main.rs
@@ -39,8 +39,8 @@ 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 } => { 42 args::Command::Diagnostics { path, load_output_dirs, all } => {
43 cli::diagnostics(path.as_ref(), load_output_dirs)? 43 cli::diagnostics(path.as_ref(), load_output_dirs, all)?
44 } 44 }
45 45
46 args::Command::RunServer => run_server()?, 46 args::Command::RunServer => run_server()?,
diff --git a/crates/rust-analyzer/src/cli/diagnostics.rs b/crates/rust-analyzer/src/cli/diagnostics.rs
index f5aab89a2..2d92c1f78 100644
--- a/crates/rust-analyzer/src/cli/diagnostics.rs
+++ b/crates/rust-analyzer/src/cli/diagnostics.rs
@@ -1,36 +1,61 @@
1//! Analyze all files in project for diagnostics. Exits with a non-zero status 1//! Analyze all modules in a project for diagnostics. Exits with a non-zero status
2//! code if any errors are found. 2//! code if any errors are found.
3 3
4use anyhow::anyhow; 4use anyhow::anyhow;
5use ra_db::{SourceDatabaseExt, SourceRootId}; 5use ra_db::{SourceDatabase, SourceDatabaseExt};
6use ra_ide::{Analysis, Severity}; 6use ra_ide::Severity;
7use std::{collections::HashSet, path::Path}; 7use std::{collections::HashSet, path::Path};
8 8
9use crate::cli::{load_cargo::load_cargo, Result}; 9use crate::cli::{load_cargo::load_cargo, Result};
10use hir::{db::HirDatabase, Crate, Module}; 10use hir::Semantics;
11 11
12pub fn diagnostics(path: &Path, load_output_dirs: bool) -> Result<()> { 12pub fn diagnostics(path: &Path, load_output_dirs: bool, all: bool) -> Result<()> {
13 let (host, roots) = load_cargo(path, load_output_dirs)?; 13 let (host, roots) = load_cargo(path, load_output_dirs)?;
14 let db = host.raw_database(); 14 let db = host.raw_database();
15 let analysis = host.analysis(); 15 let analysis = host.analysis();
16 let semantics = Semantics::new(db);
16 let members = roots 17 let members = roots
17 .into_iter() 18 .into_iter()
18 .filter_map( 19 .filter_map(|(source_root_id, project_root)| {
19 |(source_root_id, project_root)| { 20 // filter out dependencies
20 if project_root.is_member() { 21 if project_root.is_member() {
21 Some(source_root_id) 22 Some(source_root_id)
22 } else { 23 } else {
23 None 24 None
24 } 25 }
25 }, 26 })
26 )
27 .collect::<HashSet<_>>(); 27 .collect::<HashSet<_>>();
28 28
29 let mut found_error = false; 29 let mut found_error = false;
30 let mut visited_modules = HashSet::new(); 30 let mut visited_files = HashSet::new();
31 for krate in Crate::all(db) { 31 let crate_graph = db.crate_graph();
32 let module = krate.root_module(db).expect("crate without root module"); 32 for crate_id in crate_graph.iter() {
33 check_module(module, db, &mut visited_modules, &members, &analysis, &mut found_error); 33 let krate = &crate_graph[crate_id];
34 if let Some(crate_name) = &krate.display_name {
35 println!("processing crate: {}", crate_name);
36 } else {
37 println!("processing crate: unknown");
38 }
39 for file_id in db.source_root(db.file_source_root(krate.root_file_id)).walk() {
40 // Filter out files which are not actually modules (unless `--all` flag is
41 // passed). In the rust-analyzer repository this filters out the parser test files.
42 if semantics.to_module_def(file_id).is_some() || all {
43 if !visited_files.contains(&file_id) {
44 if members.contains(&db.file_source_root(file_id)) {
45 println!("processing module: {}", db.file_relative_path(file_id));
46 for diagnostic in analysis.diagnostics(file_id).unwrap() {
47 if matches!(diagnostic.severity, Severity::Error) {
48 found_error = true;
49 }
50
51 println!("{:?}", diagnostic);
52 }
53 }
54
55 visited_files.insert(file_id);
56 }
57 }
58 }
34 } 59 }
35 60
36 println!(); 61 println!();
@@ -43,32 +68,3 @@ pub fn diagnostics(path: &Path, load_output_dirs: bool) -> Result<()> {
43 Ok(()) 68 Ok(())
44 } 69 }
45} 70}
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}