aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_db/src/fixture.rs6
-rw-r--r--crates/ra_db/src/input.rs8
-rw-r--r--crates/ra_ide/src/change.rs3
-rw-r--r--crates/ra_ide/src/feature_flags.rs1
-rw-r--r--crates/ra_ide/src/lib.rs2
-rw-r--r--crates/ra_ide/src/references.rs112
-rw-r--r--crates/ra_lsp_server/src/main_loop.rs39
-rw-r--r--crates/ra_project_model/src/lib.rs14
-rw-r--r--crates/ra_project_model/src/sysroot.rs5
-rw-r--r--docs/user/README.md2
10 files changed, 148 insertions, 44 deletions
diff --git a/crates/ra_db/src/fixture.rs b/crates/ra_db/src/fixture.rs
index e8f335e33..30b598e9a 100644
--- a/crates/ra_db/src/fixture.rs
+++ b/crates/ra_db/src/fixture.rs
@@ -49,7 +49,7 @@ fn with_single_file(db: &mut dyn SourceDatabaseExt, text: &str) -> FileId {
49 let file_id = FileId(0); 49 let file_id = FileId(0);
50 let rel_path: RelativePathBuf = "/main.rs".into(); 50 let rel_path: RelativePathBuf = "/main.rs".into();
51 51
52 let mut source_root = SourceRoot::default(); 52 let mut source_root = SourceRoot::new_local();
53 source_root.insert_file(rel_path.clone(), file_id); 53 source_root.insert_file(rel_path.clone(), file_id);
54 54
55 let mut crate_graph = CrateGraph::default(); 55 let mut crate_graph = CrateGraph::default();
@@ -77,7 +77,7 @@ fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosit
77 let mut crate_deps = Vec::new(); 77 let mut crate_deps = Vec::new();
78 let mut default_crate_root: Option<FileId> = None; 78 let mut default_crate_root: Option<FileId> = None;
79 79
80 let mut source_root = SourceRoot::default(); 80 let mut source_root = SourceRoot::new_local();
81 let mut source_root_id = WORKSPACE; 81 let mut source_root_id = WORKSPACE;
82 let mut source_root_prefix: RelativePathBuf = "/".into(); 82 let mut source_root_prefix: RelativePathBuf = "/".into();
83 let mut file_id = FileId(0); 83 let mut file_id = FileId(0);
@@ -87,7 +87,7 @@ fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosit
87 for entry in fixture.iter() { 87 for entry in fixture.iter() {
88 let meta = match parse_meta(&entry.meta) { 88 let meta = match parse_meta(&entry.meta) {
89 ParsedMeta::Root { path } => { 89 ParsedMeta::Root { path } => {
90 let source_root = std::mem::replace(&mut source_root, SourceRoot::default()); 90 let source_root = std::mem::replace(&mut source_root, SourceRoot::new_local());
91 db.set_source_root(source_root_id, Arc::new(source_root)); 91 db.set_source_root(source_root_id, Arc::new(source_root));
92 source_root_id.0 += 1; 92 source_root_id.0 += 1;
93 source_root_prefix = path; 93 source_root_prefix = path;
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs
index 2a7ed20d1..07269237a 100644
--- a/crates/ra_db/src/input.rs
+++ b/crates/ra_db/src/input.rs
@@ -33,7 +33,7 @@ pub struct FileId(pub u32);
33#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] 33#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
34pub struct SourceRootId(pub u32); 34pub struct SourceRootId(pub u32);
35 35
36#[derive(Default, Clone, Debug, PartialEq, Eq)] 36#[derive(Clone, Debug, PartialEq, Eq)]
37pub struct SourceRoot { 37pub struct SourceRoot {
38 /// Sysroot or crates.io library. 38 /// Sysroot or crates.io library.
39 /// 39 ///
@@ -44,11 +44,11 @@ pub struct SourceRoot {
44} 44}
45 45
46impl SourceRoot { 46impl SourceRoot {
47 pub fn new() -> SourceRoot { 47 pub fn new_local() -> SourceRoot {
48 Default::default() 48 SourceRoot { is_library: false, files: Default::default() }
49 } 49 }
50 pub fn new_library() -> SourceRoot { 50 pub fn new_library() -> SourceRoot {
51 SourceRoot { is_library: true, ..SourceRoot::new() } 51 SourceRoot { is_library: true, files: Default::default() }
52 } 52 }
53 pub fn insert_file(&mut self, path: RelativePathBuf, file_id: FileId) { 53 pub fn insert_file(&mut self, path: RelativePathBuf, file_id: FileId) {
54 self.files.insert(path, file_id); 54 self.files.insert(path, file_id);
diff --git a/crates/ra_ide/src/change.rs b/crates/ra_ide/src/change.rs
index 8b197d642..b0aa2c8e0 100644
--- a/crates/ra_ide/src/change.rs
+++ b/crates/ra_ide/src/change.rs
@@ -176,7 +176,8 @@ impl RootDatabase {
176 if !change.new_roots.is_empty() { 176 if !change.new_roots.is_empty() {
177 let mut local_roots = Vec::clone(&self.local_roots()); 177 let mut local_roots = Vec::clone(&self.local_roots());
178 for (root_id, is_local) in change.new_roots { 178 for (root_id, is_local) in change.new_roots {
179 let root = if is_local { SourceRoot::new() } else { SourceRoot::new_library() }; 179 let root =
180 if is_local { SourceRoot::new_local() } else { SourceRoot::new_library() };
180 let durability = durability(&root); 181 let durability = durability(&root);
181 self.set_source_root_with_durability(root_id, Arc::new(root), durability); 182 self.set_source_root_with_durability(root_id, Arc::new(root), durability);
182 if is_local { 183 if is_local {
diff --git a/crates/ra_ide/src/feature_flags.rs b/crates/ra_ide/src/feature_flags.rs
index de4ae513d..85617640d 100644
--- a/crates/ra_ide/src/feature_flags.rs
+++ b/crates/ra_ide/src/feature_flags.rs
@@ -56,6 +56,7 @@ impl Default for FeatureFlags {
56 ("completion.insertion.add-call-parenthesis", true), 56 ("completion.insertion.add-call-parenthesis", true),
57 ("completion.enable-postfix", true), 57 ("completion.enable-postfix", true),
58 ("notifications.workspace-loaded", true), 58 ("notifications.workspace-loaded", true),
59 ("notifications.cargo-toml-not-found", true),
59 ]) 60 ])
60 } 61 }
61} 62}
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs
index 06497617b..7b187eba3 100644
--- a/crates/ra_ide/src/lib.rs
+++ b/crates/ra_ide/src/lib.rs
@@ -75,7 +75,7 @@ pub use crate::{
75 inlay_hints::{InlayHint, InlayKind}, 75 inlay_hints::{InlayHint, InlayKind},
76 line_index::{LineCol, LineIndex}, 76 line_index::{LineCol, LineIndex},
77 line_index_utils::translate_offset_with_edit, 77 line_index_utils::translate_offset_with_edit,
78 references::{ReferenceSearchResult, SearchScope}, 78 references::{Reference, ReferenceKind, ReferenceSearchResult, SearchScope},
79 runnables::{Runnable, RunnableKind}, 79 runnables::{Runnable, RunnableKind},
80 source_change::{FileSystemEdit, SourceChange, SourceFileEdit}, 80 source_change::{FileSystemEdit, SourceChange, SourceFileEdit},
81 syntax_highlighting::HighlightedRange, 81 syntax_highlighting::HighlightedRange,
diff --git a/crates/ra_ide/src/references.rs b/crates/ra_ide/src/references.rs
index a0226b1bc..5a3ec4eb9 100644
--- a/crates/ra_ide/src/references.rs
+++ b/crates/ra_ide/src/references.rs
@@ -214,7 +214,7 @@ fn process_definition(
214mod tests { 214mod tests {
215 use crate::{ 215 use crate::{
216 mock_analysis::{analysis_and_position, single_file_with_position, MockAnalysis}, 216 mock_analysis::{analysis_and_position, single_file_with_position, MockAnalysis},
217 ReferenceSearchResult, SearchScope, 217 Reference, ReferenceKind, ReferenceSearchResult, SearchScope,
218 }; 218 };
219 219
220 #[test] 220 #[test]
@@ -232,7 +232,12 @@ mod tests {
232 }"#; 232 }"#;
233 233
234 let refs = get_all_refs(code); 234 let refs = get_all_refs(code);
235 assert_eq!(refs.len(), 2); 235 check_result(
236 refs,
237 "Foo STRUCT_DEF FileId(1) [5; 39) [12; 15)",
238 ReferenceKind::Other,
239 &["FileId(1) [142; 145) StructLiteral"],
240 );
236 } 241 }
237 242
238 #[test] 243 #[test]
@@ -251,7 +256,17 @@ mod tests {
251 }"#; 256 }"#;
252 257
253 let refs = get_all_refs(code); 258 let refs = get_all_refs(code);
254 assert_eq!(refs.len(), 5); 259 check_result(
260 refs,
261 "i BIND_PAT FileId(1) [33; 34)",
262 ReferenceKind::Other,
263 &[
264 "FileId(1) [67; 68) Other",
265 "FileId(1) [71; 72) Other",
266 "FileId(1) [101; 102) Other",
267 "FileId(1) [127; 128) Other",
268 ],
269 );
255 } 270 }
256 271
257 #[test] 272 #[test]
@@ -262,7 +277,12 @@ mod tests {
262 }"#; 277 }"#;
263 278
264 let refs = get_all_refs(code); 279 let refs = get_all_refs(code);
265 assert_eq!(refs.len(), 2); 280 check_result(
281 refs,
282 "i BIND_PAT FileId(1) [12; 13)",
283 ReferenceKind::Other,
284 &["FileId(1) [38; 39) Other"],
285 );
266 } 286 }
267 287
268 #[test] 288 #[test]
@@ -273,7 +293,12 @@ mod tests {
273 }"#; 293 }"#;
274 294
275 let refs = get_all_refs(code); 295 let refs = get_all_refs(code);
276 assert_eq!(refs.len(), 2); 296 check_result(
297 refs,
298 "i BIND_PAT FileId(1) [12; 13)",
299 ReferenceKind::Other,
300 &["FileId(1) [38; 39) Other"],
301 );
277 } 302 }
278 303
279 #[test] 304 #[test]
@@ -290,7 +315,12 @@ mod tests {
290 "#; 315 "#;
291 316
292 let refs = get_all_refs(code); 317 let refs = get_all_refs(code);
293 assert_eq!(refs.len(), 2); 318 check_result(
319 refs,
320 "spam RECORD_FIELD_DEF FileId(1) [66; 79) [70; 74)",
321 ReferenceKind::Other,
322 &["FileId(1) [152; 156) Other"],
323 );
294 } 324 }
295 325
296 #[test] 326 #[test]
@@ -304,7 +334,7 @@ mod tests {
304 "#; 334 "#;
305 335
306 let refs = get_all_refs(code); 336 let refs = get_all_refs(code);
307 assert_eq!(refs.len(), 1); 337 check_result(refs, "f FN_DEF FileId(1) [88; 104) [91; 92)", ReferenceKind::Other, &[]);
308 } 338 }
309 339
310 #[test] 340 #[test]
@@ -319,7 +349,7 @@ mod tests {
319 "#; 349 "#;
320 350
321 let refs = get_all_refs(code); 351 let refs = get_all_refs(code);
322 assert_eq!(refs.len(), 1); 352 check_result(refs, "B ENUM_VARIANT FileId(1) [83; 84) [83; 84)", ReferenceKind::Other, &[]);
323 } 353 }
324 354
325 #[test] 355 #[test]
@@ -358,7 +388,12 @@ mod tests {
358 388
359 let (analysis, pos) = analysis_and_position(code); 389 let (analysis, pos) = analysis_and_position(code);
360 let refs = analysis.find_all_refs(pos, None).unwrap().unwrap(); 390 let refs = analysis.find_all_refs(pos, None).unwrap().unwrap();
361 assert_eq!(refs.len(), 3); 391 check_result(
392 refs,
393 "Foo STRUCT_DEF FileId(2) [16; 50) [27; 30)",
394 ReferenceKind::Other,
395 &["FileId(1) [52; 55) StructLiteral", "FileId(3) [77; 80) StructLiteral"],
396 );
362 } 397 }
363 398
364 // `mod foo;` is not in the results because `foo` is an `ast::Name`. 399 // `mod foo;` is not in the results because `foo` is an `ast::Name`.
@@ -384,7 +419,12 @@ mod tests {
384 419
385 let (analysis, pos) = analysis_and_position(code); 420 let (analysis, pos) = analysis_and_position(code);
386 let refs = analysis.find_all_refs(pos, None).unwrap().unwrap(); 421 let refs = analysis.find_all_refs(pos, None).unwrap().unwrap();
387 assert_eq!(refs.len(), 2); 422 check_result(
423 refs,
424 "foo SOURCE_FILE FileId(2) [0; 35)",
425 ReferenceKind::Other,
426 &["FileId(1) [13; 16) Other"],
427 );
388 } 428 }
389 429
390 #[test] 430 #[test]
@@ -409,7 +449,12 @@ mod tests {
409 449
410 let (analysis, pos) = analysis_and_position(code); 450 let (analysis, pos) = analysis_and_position(code);
411 let refs = analysis.find_all_refs(pos, None).unwrap().unwrap(); 451 let refs = analysis.find_all_refs(pos, None).unwrap().unwrap();
412 assert_eq!(refs.len(), 3); 452 check_result(
453 refs,
454 "Foo STRUCT_DEF FileId(3) [0; 41) [18; 21)",
455 ReferenceKind::Other,
456 &["FileId(2) [20; 23) Other", "FileId(2) [46; 49) StructLiteral"],
457 );
413 } 458 }
414 459
415 #[test] 460 #[test]
@@ -433,11 +478,21 @@ mod tests {
433 let analysis = mock.analysis(); 478 let analysis = mock.analysis();
434 479
435 let refs = analysis.find_all_refs(pos, None).unwrap().unwrap(); 480 let refs = analysis.find_all_refs(pos, None).unwrap().unwrap();
436 assert_eq!(refs.len(), 3); 481 check_result(
482 refs,
483 "quux FN_DEF FileId(1) [18; 34) [25; 29)",
484 ReferenceKind::Other,
485 &["FileId(2) [16; 20) Other", "FileId(3) [16; 20) Other"],
486 );
437 487
438 let refs = 488 let refs =
439 analysis.find_all_refs(pos, Some(SearchScope::single_file(bar))).unwrap().unwrap(); 489 analysis.find_all_refs(pos, Some(SearchScope::single_file(bar))).unwrap().unwrap();
440 assert_eq!(refs.len(), 2); 490 check_result(
491 refs,
492 "quux FN_DEF FileId(1) [18; 34) [25; 29)",
493 ReferenceKind::Other,
494 &["FileId(3) [16; 20) Other"],
495 );
441 } 496 }
442 497
443 #[test] 498 #[test]
@@ -452,11 +507,40 @@ mod tests {
452 }"#; 507 }"#;
453 508
454 let refs = get_all_refs(code); 509 let refs = get_all_refs(code);
455 assert_eq!(refs.len(), 3); 510 check_result(
511 refs,
512 "m1 MACRO_CALL FileId(1) [9; 63) [46; 48)",
513 ReferenceKind::Other,
514 &["FileId(1) [96; 98) Other", "FileId(1) [114; 116) Other"],
515 );
456 } 516 }
457 517
458 fn get_all_refs(text: &str) -> ReferenceSearchResult { 518 fn get_all_refs(text: &str) -> ReferenceSearchResult {
459 let (analysis, position) = single_file_with_position(text); 519 let (analysis, position) = single_file_with_position(text);
460 analysis.find_all_refs(position, None).unwrap().unwrap() 520 analysis.find_all_refs(position, None).unwrap().unwrap()
461 } 521 }
522
523 fn check_result(
524 res: ReferenceSearchResult,
525 expected_decl: &str,
526 decl_kind: ReferenceKind,
527 expected_refs: &[&str],
528 ) {
529 res.declaration().assert_match(expected_decl);
530 assert_eq!(res.declaration_kind, decl_kind);
531
532 assert_eq!(res.references.len(), expected_refs.len());
533 res.references().iter().enumerate().for_each(|(i, r)| r.assert_match(expected_refs[i]));
534 }
535
536 impl Reference {
537 fn debug_render(&self) -> String {
538 format!("{:?} {:?} {:?}", self.file_range.file_id, self.file_range.range, self.kind)
539 }
540
541 fn assert_match(&self, expected: &str) {
542 let actual = self.debug_render();
543 test_utils::assert_eq_text!(expected.trim(), actual.trim(),);
544 }
545 }
462} 546}
diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs
index 047c86a3b..7a49cad86 100644
--- a/crates/ra_lsp_server/src/main_loop.rs
+++ b/crates/ra_lsp_server/src/main_loop.rs
@@ -62,6 +62,22 @@ pub fn main_loop(
62 62
63 let mut loop_state = LoopState::default(); 63 let mut loop_state = LoopState::default();
64 let mut world_state = { 64 let mut world_state = {
65 let feature_flags = {
66 let mut ff = FeatureFlags::default();
67 for (flag, value) in config.feature_flags {
68 if ff.set(flag.as_str(), value).is_err() {
69 log::error!("unknown feature flag: {:?}", flag);
70 show_message(
71 req::MessageType::Error,
72 format!("unknown feature flag: {:?}", flag),
73 &connection.sender,
74 );
75 }
76 }
77 ff
78 };
79 log::info!("feature_flags: {:#?}", feature_flags);
80
65 // FIXME: support dynamic workspace loading. 81 // FIXME: support dynamic workspace loading.
66 let workspaces = { 82 let workspaces = {
67 let mut loaded_workspaces = Vec::new(); 83 let mut loaded_workspaces = Vec::new();
@@ -75,7 +91,12 @@ pub fn main_loop(
75 Ok(workspace) => loaded_workspaces.push(workspace), 91 Ok(workspace) => loaded_workspaces.push(workspace),
76 Err(e) => { 92 Err(e) => {
77 log::error!("loading workspace failed: {}", e); 93 log::error!("loading workspace failed: {}", e);
78 94 if let Some(ra_project_model::CargoTomlNotFoundError(_)) = e.downcast_ref()
95 {
96 if !feature_flags.get("notifications.cargo-toml-not-found") {
97 continue;
98 }
99 }
79 show_message( 100 show_message(
80 req::MessageType::Error, 101 req::MessageType::Error,
81 format!("rust-analyzer failed to load workspace: {}", e), 102 format!("rust-analyzer failed to load workspace: {}", e),
@@ -136,22 +157,6 @@ pub fn main_loop(
136 } 157 }
137 }; 158 };
138 159
139 let feature_flags = {
140 let mut ff = FeatureFlags::default();
141 for (flag, value) in config.feature_flags {
142 if ff.set(flag.as_str(), value).is_err() {
143 log::error!("unknown feature flag: {:?}", flag);
144 show_message(
145 req::MessageType::Error,
146 format!("unknown feature flag: {:?}", flag),
147 &connection.sender,
148 );
149 }
150 }
151 ff
152 };
153 log::info!("feature_flags: {:#?}", feature_flags);
154
155 WorldState::new( 160 WorldState::new(
156 ws_roots, 161 ws_roots,
157 workspaces, 162 workspaces,
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs
index d71b7031a..b7f6a9b57 100644
--- a/crates/ra_project_model/src/lib.rs
+++ b/crates/ra_project_model/src/lib.rs
@@ -23,9 +23,19 @@ pub use crate::{
23 sysroot::Sysroot, 23 sysroot::Sysroot,
24}; 24};
25 25
26// FIXME use proper error enum
27pub type Result<T> = ::std::result::Result<T, Box<dyn Error + Send + Sync>>; 26pub type Result<T> = ::std::result::Result<T, Box<dyn Error + Send + Sync>>;
28 27
28#[derive(Clone, PartialEq, Eq, Hash, Debug)]
29pub struct CargoTomlNotFoundError(pub PathBuf);
30
31impl std::fmt::Display for CargoTomlNotFoundError {
32 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33 write!(fmt, "can't find Cargo.toml at {}", self.0.display())
34 }
35}
36
37impl Error for CargoTomlNotFoundError {}
38
29#[derive(Debug, Clone)] 39#[derive(Debug, Clone)]
30pub enum ProjectWorkspace { 40pub enum ProjectWorkspace {
31 /// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`. 41 /// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`.
@@ -362,7 +372,7 @@ fn find_cargo_toml(path: &Path) -> Result<PathBuf> {
362 } 372 }
363 curr = path.parent(); 373 curr = path.parent();
364 } 374 }
365 Err(format!("can't find Cargo.toml at {}", path.display()))? 375 Err(CargoTomlNotFoundError(path.to_path_buf()))?
366} 376}
367 377
368pub fn get_rustc_cfg_options() -> CfgOptions { 378pub fn get_rustc_cfg_options() -> CfgOptions {
diff --git a/crates/ra_project_model/src/sysroot.rs b/crates/ra_project_model/src/sysroot.rs
index 10ca391b6..34d066b1e 100644
--- a/crates/ra_project_model/src/sysroot.rs
+++ b/crates/ra_project_model/src/sysroot.rs
@@ -53,9 +53,10 @@ impl Sysroot {
53 if !src.exists() { 53 if !src.exists() {
54 Err(format!( 54 Err(format!(
55 "can't load standard library from sysroot\n\ 55 "can't load standard library from sysroot\n\
56 {:?}\n\ 56 {}\n\
57 (discovered via `rustc --print sysroot`)\n\
57 try running `rustup component add rust-src` or set `RUST_SRC_PATH`", 58 try running `rustup component add rust-src` or set `RUST_SRC_PATH`",
58 src, 59 src.display(),
59 ))?; 60 ))?;
60 } 61 }
61 62
diff --git a/docs/user/README.md b/docs/user/README.md
index 282445722..fa202f06c 100644
--- a/docs/user/README.md
+++ b/docs/user/README.md
@@ -122,6 +122,8 @@ host.
122 "completion.enable-postfix": true, 122 "completion.enable-postfix": true,
123 // Show notification when workspace is fully loaded 123 // Show notification when workspace is fully loaded
124 "notifications.workspace-loaded": true, 124 "notifications.workspace-loaded": true,
125 // Show error when no Cargo.toml was found
126 "notifications.cargo-toml-not-found": true,
125 } 127 }
126 ``` 128 ```
127 129