aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_assists/src/auto_import.rs96
-rw-r--r--crates/ra_assists/src/lib.rs2
-rw-r--r--crates/ra_assists/src/remove_dbg.rs8
-rw-r--r--crates/ra_db/src/cancellation.rs2
-rw-r--r--crates/ra_db/src/input.rs44
-rw-r--r--crates/ra_db/src/lib.rs2
-rw-r--r--crates/ra_hir/src/code_model_api.rs15
-rw-r--r--crates/ra_hir/src/expr/scope.rs2
-rw-r--r--crates/ra_hir/src/ids.rs16
-rw-r--r--crates/ra_hir/src/macros.rs2
-rw-r--r--crates/ra_hir/src/marks.rs1
-rw-r--r--crates/ra_hir/src/mock.rs18
-rw-r--r--crates/ra_hir/src/nameres.rs129
-rw-r--r--crates/ra_hir/src/nameres/lower.rs18
-rw-r--r--crates/ra_hir/src/nameres/tests.rs112
-rw-r--r--crates/ra_hir/src/path.rs2
-rw-r--r--crates/ra_hir/src/resolve.rs24
-rw-r--r--crates/ra_hir/src/ty.rs4
-rw-r--r--crates/ra_hir/src/ty/snapshots/tests__infer_nested_generics_crash.snap12
-rw-r--r--crates/ra_hir/src/ty/tests.rs19
-rw-r--r--crates/ra_ide_api/src/completion.rs5
-rw-r--r--crates/ra_ide_api/src/completion/complete_dot.rs20
-rw-r--r--crates/ra_ide_api/src/completion/complete_fn_param.rs2
-rw-r--r--crates/ra_ide_api/src/completion/complete_scope.rs21
-rw-r--r--crates/ra_ide_api/src/completion/snapshots/completion_item__completes_prelude.snap54
-rw-r--r--crates/ra_ide_api/src/completion/snapshots/completion_item__method_attr_filtering.snap26
-rw-r--r--crates/ra_ide_api/src/goto_definition.rs8
-rw-r--r--crates/ra_ide_api/src/hover.rs4
-rw-r--r--crates/ra_ide_api/src/impls.rs4
-rw-r--r--crates/ra_ide_api/src/lib.rs13
-rw-r--r--crates/ra_ide_api/src/mock_analysis.rs8
-rw-r--r--crates/ra_ide_api/src/navigation_target.rs11
-rw-r--r--crates/ra_ide_api/src/references.rs6
-rw-r--r--crates/ra_ide_api/src/symbol_index.rs64
-rw-r--r--crates/ra_ide_api/tests/test/main.rs54
-rw-r--r--crates/ra_ide_api_light/Cargo.toml2
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs2
-rw-r--r--crates/ra_mbe/src/lib.rs6
-rw-r--r--crates/ra_mbe/src/mbe_expander.rs2
-rw-r--r--crates/ra_project_model/src/cargo_workspace.rs8
-rw-r--r--crates/ra_project_model/src/lib.rs8
-rw-r--r--crates/ra_syntax/src/ast.rs2
-rw-r--r--crates/ra_syntax/src/ast/generated.rs3
-rw-r--r--crates/ra_syntax/src/ast/generated.rs.tera2
-rw-r--r--crates/ra_syntax/src/grammar.ron3
-rw-r--r--crates/ra_syntax/src/lib.rs8
-rw-r--r--crates/ra_syntax/src/parser_impl.rs2
-rw-r--r--crates/ra_syntax/src/parser_impl/event.rs2
-rw-r--r--crates/ra_syntax/src/reparsing.rs4
-rw-r--r--crates/ra_syntax/src/syntax_node.rs (renamed from crates/ra_syntax/src/yellow.rs)0
-rw-r--r--crates/ra_syntax/src/syntax_node/builder.rs (renamed from crates/ra_syntax/src/yellow/builder.rs)2
-rw-r--r--crates/ra_syntax/src/syntax_node/syntax_error.rs (renamed from crates/ra_syntax/src/yellow/syntax_error.rs)0
-rw-r--r--crates/ra_syntax/src/syntax_node/syntax_text.rs (renamed from crates/ra_syntax/src/yellow/syntax_text.rs)0
-rw-r--r--crates/ra_syntax/src/validation.rs2
-rw-r--r--crates/ra_syntax/src/validation/block.rs2
-rw-r--r--crates/ra_syntax/src/validation/byte.rs2
-rw-r--r--crates/ra_syntax/src/validation/byte_string.rs2
-rw-r--r--crates/ra_syntax/src/validation/char.rs2
-rw-r--r--crates/ra_syntax/src/validation/string.rs2
-rw-r--r--crates/ra_syntax/tests/data/parser/fuzz-failures/0000.rs4
-rw-r--r--crates/ra_tt/src/lib.rs10
-rw-r--r--crates/ra_vfs/src/io.rs4
-rw-r--r--crates/ra_vfs/src/lib.rs14
-rw-r--r--crates/test_utils/src/lib.rs4
-rw-r--r--crates/test_utils/src/marks.rs8
-rw-r--r--crates/thread_worker/src/lib.rs2
66 files changed, 758 insertions, 184 deletions
diff --git a/crates/ra_assists/src/auto_import.rs b/crates/ra_assists/src/auto_import.rs
index b251c9369..52c2a0b2b 100644
--- a/crates/ra_assists/src/auto_import.rs
+++ b/crates/ra_assists/src/auto_import.rs
@@ -1,6 +1,6 @@
1use hir::db::HirDatabase; 1use hir::db::HirDatabase;
2use ra_syntax::{ 2use ra_syntax::{
3 ast, AstNode, SyntaxNode, Direction, TextRange, 3 ast::{ self, NameOwner }, AstNode, SyntaxNode, Direction, TextRange,
4 SyntaxKind::{ PATH, PATH_SEGMENT, COLONCOLON, COMMA } 4 SyntaxKind::{ PATH, PATH_SEGMENT, COLONCOLON, COMMA }
5}; 5};
6use crate::assist_ctx::{AssistCtx, Assist, AssistBuilder}; 6use crate::assist_ctx::{AssistCtx, Assist, AssistBuilder};
@@ -345,9 +345,9 @@ fn best_action_for_target<'b, 'a: 'b>(
345 match best_action { 345 match best_action {
346 Some(action) => return action, 346 Some(action) => return action,
347 None => { 347 None => {
348 // We have no action we no use item was found in container so we find 348 // We have no action and no UseItem was found in container so we find
349 // another item and we use it as anchor. 349 // another item and we use it as anchor.
350 // If there are not items, we choose the target path itself as anchor. 350 // If there are no items, we choose the target path itself as anchor.
351 let anchor = container 351 let anchor = container
352 .children() 352 .children()
353 .find_map(ast::ModuleItem::cast) 353 .find_map(ast::ModuleItem::cast)
@@ -480,6 +480,24 @@ fn make_assist_add_nested_import(
480 } 480 }
481} 481}
482 482
483fn apply_auto_import<'a>(
484 container: &SyntaxNode,
485 path: &ast::Path,
486 target: &[&'a ast::PathSegment],
487 edit: &mut AssistBuilder,
488) {
489 let action = best_action_for_target(container, path, target);
490 make_assist(&action, target, edit);
491 if let (Some(first), Some(last)) = (target.first(), target.last()) {
492 // Here we are assuming the assist will provide a correct use statement
493 // so we can delete the path qualifier
494 edit.delete(TextRange::from_to(
495 first.syntax().range().start(),
496 last.syntax().range().start(),
497 ));
498 }
499}
500
483pub(crate) fn auto_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 501pub(crate) fn auto_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
484 let node = ctx.covering_node(); 502 let node = ctx.covering_node();
485 let current_file = node.ancestors().find_map(ast::SourceFile::cast)?; 503 let current_file = node.ancestors().find_map(ast::SourceFile::cast)?;
@@ -495,18 +513,20 @@ pub(crate) fn auto_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist
495 return None; 513 return None;
496 } 514 }
497 515
498 ctx.add_action(format!("import {} in the current file", fmt_segments(&segments)), |edit| { 516 if let Some(module) = path.syntax().ancestors().find_map(ast::Module::cast) {
499 let action = best_action_for_target(current_file.syntax(), path, &segments); 517 if let (Some(item_list), Some(name)) = (module.item_list(), module.name()) {
500 make_assist(&action, segments.as_slice(), edit); 518 ctx.add_action(
501 if let Some(last_segment) = path.segment() { 519 format!("import {} in mod {}", fmt_segments(&segments), name.text()),
502 // Here we are assuming the assist will provide a correct use statement 520 |edit| {
503 // so we can delete the path qualifier 521 apply_auto_import(item_list.syntax(), path, &segments, edit);
504 edit.delete(TextRange::from_to( 522 },
505 path.syntax().range().start(), 523 );
506 last_segment.syntax().range().start(),
507 ));
508 } 524 }
509 }); 525 } else {
526 ctx.add_action(format!("import {} in the current file", fmt_segments(&segments)), |edit| {
527 apply_auto_import(current_file.syntax(), path, &segments, edit);
528 });
529 }
510 530
511 ctx.build() 531 ctx.build()
512} 532}
@@ -532,6 +552,21 @@ Debug<|>
532 } 552 }
533 553
534 #[test] 554 #[test]
555 fn test_auto_import_file_add_use_no_anchor_2seg() {
556 check_assist(
557 auto_import,
558 "
559std::fmt<|>::Debug
560 ",
561 "
562use std::fmt;
563
564fmt<|>::Debug
565 ",
566 );
567 }
568
569 #[test]
535 fn test_auto_import_file_add_use() { 570 fn test_auto_import_file_add_use() {
536 check_assist( 571 check_assist(
537 auto_import, 572 auto_import,
@@ -728,4 +763,37 @@ impl foo<|> for Foo {
728", 763",
729 ); 764 );
730 } 765 }
766
767 #[test]
768 fn test_auto_import_not_applicable_in_use() {
769 check_assist_not_applicable(
770 auto_import,
771 "
772use std::fmt<|>;
773",
774 );
775 }
776
777 #[test]
778 fn test_auto_import_file_add_use_no_anchor_in_mod_mod() {
779 check_assist(
780 auto_import,
781 "
782mod foo {
783 mod bar {
784 std::fmt::Debug<|>
785 }
786}
787 ",
788 "
789mod foo {
790 mod bar {
791 use std::fmt::Debug;
792
793 Debug<|>
794 }
795}
796 ",
797 );
798 }
731} 799}
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index c607a5142..7bd9b5ae6 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -1,4 +1,4 @@
1//! `ra_assits` crate provides a bunch of code assists, aslo known as code 1//! `ra_assits` crate provides a bunch of code assists, also known as code
2//! actions (in LSP) or intentions (in IntelliJ). 2//! actions (in LSP) or intentions (in IntelliJ).
3//! 3//!
4//! An assist is a micro-refactoring, which is automatically activated in 4//! An assist is a micro-refactoring, which is automatically activated in
diff --git a/crates/ra_assists/src/remove_dbg.rs b/crates/ra_assists/src/remove_dbg.rs
index db260c6ca..2bed270a1 100644
--- a/crates/ra_assists/src/remove_dbg.rs
+++ b/crates/ra_assists/src/remove_dbg.rs
@@ -17,9 +17,9 @@ pub(crate) fn remove_dbg(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist>
17 17
18 let macro_range = macro_call.syntax().range(); 18 let macro_range = macro_call.syntax().range();
19 19
20 // If the cursor is inside the macrocall, we'll try to maintain 20 // If the cursor is inside the macro call, we'll try to maintain the cursor
21 // the cursor position by subtracting the length of dbg!( from the start 21 // position by subtracting the length of dbg!( from the start of the file
22 // of the filerange, otherwise we'll default to using the start of the macrocall 22 // range, otherwise we'll default to using the start of the macro call
23 let cursor_pos = { 23 let cursor_pos = {
24 let file_range = ctx.frange.range; 24 let file_range = ctx.frange.range;
25 25
@@ -61,7 +61,7 @@ fn is_valid_macrocall(macro_call: &ast::MacroCall, macro_name: &str) -> Option<b
61 let path = macro_call.path()?; 61 let path = macro_call.path()?;
62 let name_ref = path.segment()?.name_ref()?; 62 let name_ref = path.segment()?.name_ref()?;
63 63
64 // Make sure it is actually a dbg-macrocall, dbg followed by ! 64 // Make sure it is actually a dbg-macro call, dbg followed by !
65 let excl = path.syntax().next_sibling()?; 65 let excl = path.syntax().next_sibling()?;
66 66
67 if name_ref.text() != macro_name || excl.kind() != EXCL { 67 if name_ref.text() != macro_name || excl.kind() != EXCL {
diff --git a/crates/ra_db/src/cancellation.rs b/crates/ra_db/src/cancellation.rs
index 439080075..7420a1976 100644
--- a/crates/ra_db/src/cancellation.rs
+++ b/crates/ra_db/src/cancellation.rs
@@ -15,7 +15,7 @@
15//! any background processing (this bit is handled by salsa, see the 15//! any background processing (this bit is handled by salsa, see the
16//! `BaseDatabase::check_canceled` method). 16//! `BaseDatabase::check_canceled` method).
17 17
18/// An "error" signifing that the operation was canceled. 18/// An "error" signifying that the operation was canceled.
19#[derive(Clone, PartialEq, Eq, Hash)] 19#[derive(Clone, PartialEq, Eq, Hash)]
20pub struct Canceled { 20pub struct Canceled {
21 _private: (), 21 _private: (),
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs
index 8decc65c5..e45a510b3 100644
--- a/crates/ra_db/src/input.rs
+++ b/crates/ra_db/src/input.rs
@@ -56,15 +56,31 @@ pub struct CyclicDependencies;
56#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 56#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
57pub struct CrateId(pub u32); 57pub struct CrateId(pub u32);
58 58
59#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
60pub enum Edition {
61 Edition2018,
62 Edition2015,
63}
64
65impl Edition {
66 pub fn from_string(s: &str) -> Edition {
67 match s {
68 "2015" => Edition::Edition2015,
69 "2018" | _ => Edition::Edition2018,
70 }
71 }
72}
73
59#[derive(Debug, Clone, PartialEq, Eq)] 74#[derive(Debug, Clone, PartialEq, Eq)]
60struct CrateData { 75struct CrateData {
61 file_id: FileId, 76 file_id: FileId,
77 edition: Edition,
62 dependencies: Vec<Dependency>, 78 dependencies: Vec<Dependency>,
63} 79}
64 80
65impl CrateData { 81impl CrateData {
66 fn new(file_id: FileId) -> CrateData { 82 fn new(file_id: FileId, edition: Edition) -> CrateData {
67 CrateData { file_id, dependencies: Vec::new() } 83 CrateData { file_id, edition, dependencies: Vec::new() }
68 } 84 }
69 85
70 fn add_dep(&mut self, name: SmolStr, crate_id: CrateId) { 86 fn add_dep(&mut self, name: SmolStr, crate_id: CrateId) {
@@ -85,9 +101,9 @@ impl Dependency {
85} 101}
86 102
87impl CrateGraph { 103impl CrateGraph {
88 pub fn add_crate_root(&mut self, file_id: FileId) -> CrateId { 104 pub fn add_crate_root(&mut self, file_id: FileId, edition: Edition) -> CrateId {
89 let crate_id = CrateId(self.arena.len() as u32); 105 let crate_id = CrateId(self.arena.len() as u32);
90 let prev = self.arena.insert(crate_id, CrateData::new(file_id)); 106 let prev = self.arena.insert(crate_id, CrateData::new(file_id, edition));
91 assert!(prev.is_none()); 107 assert!(prev.is_none());
92 crate_id 108 crate_id
93 } 109 }
@@ -112,6 +128,10 @@ impl CrateGraph {
112 self.arena[&crate_id].file_id 128 self.arena[&crate_id].file_id
113 } 129 }
114 130
131 pub fn edition(&self, crate_id: CrateId) -> Edition {
132 self.arena[&crate_id].edition
133 }
134
115 // TODO: this only finds one crate with the given root; we could have multiple 135 // TODO: this only finds one crate with the given root; we could have multiple
116 pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> { 136 pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> {
117 let (&crate_id, _) = self.arena.iter().find(|(_crate_id, data)| data.file_id == file_id)?; 137 let (&crate_id, _) = self.arena.iter().find(|(_crate_id, data)| data.file_id == file_id)?;
@@ -159,14 +179,14 @@ impl CrateGraph {
159 179
160#[cfg(test)] 180#[cfg(test)]
161mod tests { 181mod tests {
162 use super::{CrateGraph, FileId, SmolStr}; 182 use super::{CrateGraph, FileId, SmolStr, Edition::Edition2018};
163 183
164 #[test] 184 #[test]
165 fn it_should_painc_because_of_cycle_dependencies() { 185 fn it_should_panic_because_of_cycle_dependencies() {
166 let mut graph = CrateGraph::default(); 186 let mut graph = CrateGraph::default();
167 let crate1 = graph.add_crate_root(FileId(1u32)); 187 let crate1 = graph.add_crate_root(FileId(1u32), Edition2018);
168 let crate2 = graph.add_crate_root(FileId(2u32)); 188 let crate2 = graph.add_crate_root(FileId(2u32), Edition2018);
169 let crate3 = graph.add_crate_root(FileId(3u32)); 189 let crate3 = graph.add_crate_root(FileId(3u32), Edition2018);
170 assert!(graph.add_dep(crate1, SmolStr::new("crate2"), crate2).is_ok()); 190 assert!(graph.add_dep(crate1, SmolStr::new("crate2"), crate2).is_ok());
171 assert!(graph.add_dep(crate2, SmolStr::new("crate3"), crate3).is_ok()); 191 assert!(graph.add_dep(crate2, SmolStr::new("crate3"), crate3).is_ok());
172 assert!(graph.add_dep(crate3, SmolStr::new("crate1"), crate1).is_err()); 192 assert!(graph.add_dep(crate3, SmolStr::new("crate1"), crate1).is_err());
@@ -175,9 +195,9 @@ mod tests {
175 #[test] 195 #[test]
176 fn it_works() { 196 fn it_works() {
177 let mut graph = CrateGraph::default(); 197 let mut graph = CrateGraph::default();
178 let crate1 = graph.add_crate_root(FileId(1u32)); 198 let crate1 = graph.add_crate_root(FileId(1u32), Edition2018);
179 let crate2 = graph.add_crate_root(FileId(2u32)); 199 let crate2 = graph.add_crate_root(FileId(2u32), Edition2018);
180 let crate3 = graph.add_crate_root(FileId(3u32)); 200 let crate3 = graph.add_crate_root(FileId(3u32), Edition2018);
181 assert!(graph.add_dep(crate1, SmolStr::new("crate2"), crate2).is_ok()); 201 assert!(graph.add_dep(crate1, SmolStr::new("crate2"), crate2).is_ok());
182 assert!(graph.add_dep(crate2, SmolStr::new("crate3"), crate3).is_ok()); 202 assert!(graph.add_dep(crate2, SmolStr::new("crate3"), crate3).is_ok());
183 } 203 }
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs
index 31442713d..e006c6d27 100644
--- a/crates/ra_db/src/lib.rs
+++ b/crates/ra_db/src/lib.rs
@@ -14,7 +14,7 @@ pub use ::salsa as salsa;
14pub use crate::{ 14pub use crate::{
15 cancellation::Canceled, 15 cancellation::Canceled,
16 input::{ 16 input::{
17 FileId, CrateId, SourceRoot, SourceRootId, CrateGraph, Dependency, 17 FileId, CrateId, SourceRoot, SourceRootId, CrateGraph, Dependency, Edition,
18 }, 18 },
19 loc2id::LocationIntener, 19 loc2id::LocationIntener,
20}; 20};
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs
index 94a08aa63..fb7ad0867 100644
--- a/crates/ra_hir/src/code_model_api.rs
+++ b/crates/ra_hir/src/code_model_api.rs
@@ -1,7 +1,7 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use relative_path::RelativePathBuf; 3use relative_path::RelativePathBuf;
4use ra_db::{CrateId, FileId, SourceRootId}; 4use ra_db::{CrateId, FileId, SourceRootId, Edition};
5use ra_syntax::{ast::self, TreeArc, SyntaxNode}; 5use ra_syntax::{ast::self, TreeArc, SyntaxNode};
6 6
7use crate::{ 7use crate::{
@@ -38,13 +38,20 @@ impl Crate {
38 pub fn crate_id(&self) -> CrateId { 38 pub fn crate_id(&self) -> CrateId {
39 self.crate_id 39 self.crate_id
40 } 40 }
41
41 pub fn dependencies(&self, db: &impl PersistentHirDatabase) -> Vec<CrateDependency> { 42 pub fn dependencies(&self, db: &impl PersistentHirDatabase) -> Vec<CrateDependency> {
42 self.dependencies_impl(db) 43 self.dependencies_impl(db)
43 } 44 }
45
44 pub fn root_module(&self, db: &impl PersistentHirDatabase) -> Option<Module> { 46 pub fn root_module(&self, db: &impl PersistentHirDatabase) -> Option<Module> {
45 self.root_module_impl(db) 47 self.root_module_impl(db)
46 } 48 }
47 49
50 pub fn edition(&self, db: &impl PersistentHirDatabase) -> Edition {
51 let crate_graph = db.crate_graph();
52 crate_graph.edition(self.crate_id)
53 }
54
48 // TODO: should this be in source_binder? 55 // TODO: should this be in source_binder?
49 pub fn source_root_crates( 56 pub fn source_root_crates(
50 db: &impl PersistentHirDatabase, 57 db: &impl PersistentHirDatabase,
@@ -134,7 +141,7 @@ impl Module {
134 141
135 /// Topmost parent of this module. Every module has a `crate_root`, but some 142 /// Topmost parent of this module. Every module has a `crate_root`, but some
136 /// might be missing `krate`. This can happen if a module's file is not included 143 /// might be missing `krate`. This can happen if a module's file is not included
137 /// in the module tree of any target in Cargo.toml. 144 /// in the module tree of any target in `Cargo.toml`.
138 pub fn crate_root(&self, db: &impl PersistentHirDatabase) -> Module { 145 pub fn crate_root(&self, db: &impl PersistentHirDatabase) -> Module {
139 self.crate_root_impl(db) 146 self.crate_root_impl(db)
140 } 147 }
@@ -351,7 +358,7 @@ impl Enum {
351 db.type_for_def((*self).into()) 358 db.type_for_def((*self).into())
352 } 359 }
353 360
354 // TODO move to a more general type 361 // TODO: move to a more general type
355 /// Builds a resolver for type references inside this struct. 362 /// Builds a resolver for type references inside this struct.
356 pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { 363 pub fn resolver(&self, db: &impl HirDatabase) -> Resolver {
357 // take the outer scope... 364 // take the outer scope...
@@ -495,7 +502,7 @@ impl Function {
495 db.generic_params((*self).into()) 502 db.generic_params((*self).into())
496 } 503 }
497 504
498 // TODO move to a more general type for 'body-having' items 505 // TODO: move to a more general type for 'body-having' items
499 /// Builds a resolver for code inside this item. 506 /// Builds a resolver for code inside this item.
500 pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { 507 pub fn resolver(&self, db: &impl HirDatabase) -> Resolver {
501 // take the outer scope... 508 // take the outer scope...
diff --git a/crates/ra_hir/src/expr/scope.rs b/crates/ra_hir/src/expr/scope.rs
index 44d5c2429..bb8d50db8 100644
--- a/crates/ra_hir/src/expr/scope.rs
+++ b/crates/ra_hir/src/expr/scope.rs
@@ -84,7 +84,7 @@ impl ExprScopes {
84 fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) { 84 fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) {
85 match &body[pat] { 85 match &body[pat] {
86 Pat::Bind { name, .. } => { 86 Pat::Bind { name, .. } => {
87 // bind can have a subpattern, but it's actually not allowed 87 // bind can have a sub pattern, but it's actually not allowed
88 // to bind to things in there 88 // to bind to things in there
89 let entry = ScopeEntry { name: name.clone(), pat }; 89 let entry = ScopeEntry { name: name.clone(), pat };
90 self.scopes[scope].entries.push(entry) 90 self.scopes[scope].entries.push(entry)
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs
index d3fa7d266..8d81d5ebf 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -46,24 +46,24 @@ impl HirInterner {
46/// This module defines a bunch of ids we are using. The most important ones are 46/// This module defines a bunch of ids we are using. The most important ones are
47/// probably `HirFileId` and `DefId`. 47/// probably `HirFileId` and `DefId`.
48 48
49/// Input to the analyzer is a set of files, where each file is indentified by 49/// Input to the analyzer is a set of files, where each file is identified by
50/// `FileId` and contains source code. However, another source of source code in 50/// `FileId` and contains source code. However, another source of source code in
51/// Rust are macros: each macro can be thought of as producing a "temporary 51/// Rust are macros: each macro can be thought of as producing a "temporary
52/// file". To assign an id to such a file, we use the id of the macro call that 52/// file". To assign an id to such a file, we use the id of the macro call that
53/// produced the file. So, a `HirFileId` is either a `FileId` (source code 53/// produced the file. So, a `HirFileId` is either a `FileId` (source code
54/// written by user), or a `MacroCallId` (source code produced by macro). 54/// written by user), or a `MacroCallId` (source code produced by macro).
55/// 55///
56/// What is a `MacroCallId`? Simplifying, it's a `HirFileId` of a file containin 56/// What is a `MacroCallId`? Simplifying, it's a `HirFileId` of a file
57/// the call plus the offset of the macro call in the file. Note that this is a 57/// containing the call plus the offset of the macro call in the file. Note that
58/// recursive definition! However, the size_of of `HirFileId` is finite 58/// this is a recursive definition! However, the size_of of `HirFileId` is
59/// (because everything bottoms out at the real `FileId`) and small 59/// finite (because everything bottoms out at the real `FileId`) and small
60/// (`MacroCallId` uses the location interner). 60/// (`MacroCallId` uses the location interner).
61#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 61#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
62pub struct HirFileId(HirFileIdRepr); 62pub struct HirFileId(HirFileIdRepr);
63 63
64impl HirFileId { 64impl HirFileId {
65 /// For macro-expansion files, returns the file original source file the 65 /// For macro-expansion files, returns the file original source file the
66 /// expansionoriginated from. 66 /// expansion originated from.
67 pub fn original_file(self, db: &impl PersistentHirDatabase) -> FileId { 67 pub fn original_file(self, db: &impl PersistentHirDatabase) -> FileId {
68 match self.0 { 68 match self.0 {
69 HirFileIdRepr::File(file_id) => file_id, 69 HirFileIdRepr::File(file_id) => file_id,
@@ -324,9 +324,9 @@ impl SourceFileItems {
324 324
325 fn init(&mut self, source_file: &SourceFile) { 325 fn init(&mut self, source_file: &SourceFile) {
326 // By walking the tree in bread-first order we make sure that parents 326 // By walking the tree in bread-first order we make sure that parents
327 // get lower ids then children. That is, addding a new child does not 327 // get lower ids then children. That is, adding a new child does not
328 // change parent's id. This means that, say, adding a new function to a 328 // change parent's id. This means that, say, adding a new function to a
329 // trait does not chage ids of top-level items, which helps caching. 329 // trait does not change ids of top-level items, which helps caching.
330 bfs(source_file.syntax(), |it| { 330 bfs(source_file.syntax(), |it| {
331 if let Some(module_item) = ast::ModuleItem::cast(it) { 331 if let Some(module_item) = ast::ModuleItem::cast(it) {
332 self.alloc(module_item.syntax()); 332 self.alloc(module_item.syntax());
diff --git a/crates/ra_hir/src/macros.rs b/crates/ra_hir/src/macros.rs
index dd477e9f9..45128c7df 100644
--- a/crates/ra_hir/src/macros.rs
+++ b/crates/ra_hir/src/macros.rs
@@ -67,7 +67,7 @@ impl MacroDef {
67 } 67 }
68} 68}
69 69
70#[derive(Debug, Clone, PartialEq, Eq, Hash)] 70#[derive(Debug, Clone, PartialEq, Eq)]
71pub struct MacroInput { 71pub struct MacroInput {
72 // Should be token trees 72 // Should be token trees
73 pub text: String, 73 pub text: String,
diff --git a/crates/ra_hir/src/marks.rs b/crates/ra_hir/src/marks.rs
index 50d4e824c..16852a6a1 100644
--- a/crates/ra_hir/src/marks.rs
+++ b/crates/ra_hir/src/marks.rs
@@ -6,4 +6,5 @@ test_utils::marks!(
6 type_var_resolves_to_int_var 6 type_var_resolves_to_int_var
7 glob_enum 7 glob_enum
8 glob_across_crates 8 glob_across_crates
9 std_prelude
9); 10);
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs
index 5ca870867..f1cad77c5 100644
--- a/crates/ra_hir/src/mock.rs
+++ b/crates/ra_hir/src/mock.rs
@@ -3,6 +3,7 @@ use std::{sync::Arc, panic};
3use parking_lot::Mutex; 3use parking_lot::Mutex;
4use ra_db::{ 4use ra_db::{
5 FilePosition, FileId, CrateGraph, SourceRoot, SourceRootId, SourceDatabase, salsa, 5 FilePosition, FileId, CrateGraph, SourceRoot, SourceRootId, SourceDatabase, salsa,
6 Edition,
6}; 7};
7use relative_path::RelativePathBuf; 8use relative_path::RelativePathBuf;
8use test_utils::{parse_fixture, CURSOR_MARKER, extract_offset}; 9use test_utils::{parse_fixture, CURSOR_MARKER, extract_offset};
@@ -58,12 +59,12 @@ impl MockDatabase {
58 pub fn set_crate_graph_from_fixture(&mut self, graph: CrateGraphFixture) { 59 pub fn set_crate_graph_from_fixture(&mut self, graph: CrateGraphFixture) {
59 let mut ids = FxHashMap::default(); 60 let mut ids = FxHashMap::default();
60 let mut crate_graph = CrateGraph::default(); 61 let mut crate_graph = CrateGraph::default();
61 for (crate_name, (crate_root, _)) in graph.0.iter() { 62 for (crate_name, (crate_root, edition, _)) in graph.0.iter() {
62 let crate_root = self.file_id_of(&crate_root); 63 let crate_root = self.file_id_of(&crate_root);
63 let crate_id = crate_graph.add_crate_root(crate_root); 64 let crate_id = crate_graph.add_crate_root(crate_root, *edition);
64 ids.insert(crate_name, crate_id); 65 ids.insert(crate_name, crate_id);
65 } 66 }
66 for (crate_name, (_, deps)) in graph.0.iter() { 67 for (crate_name, (_, _, deps)) in graph.0.iter() {
67 let from = ids[crate_name]; 68 let from = ids[crate_name];
68 for dep in deps { 69 for dep in deps {
69 let to = ids[dep]; 70 let to = ids[dep];
@@ -144,7 +145,7 @@ impl MockDatabase {
144 145
145 if is_crate_root { 146 if is_crate_root {
146 let mut crate_graph = CrateGraph::default(); 147 let mut crate_graph = CrateGraph::default();
147 crate_graph.add_crate_root(file_id); 148 crate_graph.add_crate_root(file_id, Edition::Edition2018);
148 self.set_crate_graph(Arc::new(crate_graph)); 149 self.set_crate_graph(Arc::new(crate_graph));
149 } 150 }
150 file_id 151 file_id
@@ -232,16 +233,19 @@ impl MockDatabase {
232} 233}
233 234
234#[derive(Default)] 235#[derive(Default)]
235pub struct CrateGraphFixture(pub FxHashMap<String, (String, Vec<String>)>); 236pub struct CrateGraphFixture(pub FxHashMap<String, (String, Edition, Vec<String>)>);
236 237
237#[macro_export] 238#[macro_export]
238macro_rules! crate_graph { 239macro_rules! crate_graph {
239 ($($crate_name:literal: ($crate_path:literal, [$($dep:literal),*]),)*) => {{ 240 ($($crate_name:literal: ($crate_path:literal, $($edition:literal,)? [$($dep:literal),*]),)*) => {{
240 let mut res = $crate::mock::CrateGraphFixture::default(); 241 let mut res = $crate::mock::CrateGraphFixture::default();
241 $( 242 $(
243 #[allow(unused_mut, unused_assignments)]
244 let mut edition = ra_db::Edition::Edition2018;
245 $(edition = ra_db::Edition::from_string($edition);)?
242 res.0.insert( 246 res.0.insert(
243 $crate_name.to_string(), 247 $crate_name.to_string(),
244 ($crate_path.to_string(), vec![$($dep.to_string()),*]) 248 ($crate_path.to_string(), edition, vec![$($dep.to_string()),*])
245 ); 249 );
246 )* 250 )*
247 res 251 res
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index 261ebdf97..e35b4b129 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -18,9 +18,11 @@ pub(crate) mod lower;
18 18
19use std::{time, sync::Arc}; 19use std::{time, sync::Arc};
20 20
21use rustc_hash::{FxHashMap, FxHashSet};
22
21use ra_arena::map::ArenaMap; 23use ra_arena::map::ArenaMap;
24use ra_db::Edition;
22use test_utils::tested_by; 25use test_utils::tested_by;
23use rustc_hash::{FxHashMap, FxHashSet};
24 26
25use crate::{ 27use crate::{
26 Module, ModuleDef, 28 Module, ModuleDef,
@@ -32,8 +34,13 @@ use crate::{
32 34
33/// `ItemMap` is the result of module name resolution. It contains, for each 35/// `ItemMap` is the result of module name resolution. It contains, for each
34/// module, the set of visible items. 36/// module, the set of visible items.
35#[derive(Default, Debug, PartialEq, Eq)] 37#[derive(Debug, PartialEq, Eq)]
36pub struct ItemMap { 38pub struct ItemMap {
39 edition: Edition,
40 /// The prelude module for this crate. This either comes from an import
41 /// marked with the `prelude_import` attribute, or (in the normal case) from
42 /// a dependency (`std` or `core`).
43 pub(crate) prelude: Option<Module>,
37 pub(crate) extern_prelude: FxHashMap<Name, ModuleDef>, 44 pub(crate) extern_prelude: FxHashMap<Name, ModuleDef>,
38 per_module: ArenaMap<ModuleId, ModuleScope>, 45 per_module: ArenaMap<ModuleId, ModuleScope>,
39} 46}
@@ -176,7 +183,12 @@ where
176 module_tree, 183 module_tree,
177 processed_imports: FxHashSet::default(), 184 processed_imports: FxHashSet::default(),
178 glob_imports: FxHashMap::default(), 185 glob_imports: FxHashMap::default(),
179 result: ItemMap::default(), 186 result: ItemMap {
187 edition: krate.edition(db),
188 prelude: None,
189 extern_prelude: FxHashMap::default(),
190 per_module: ArenaMap::default(),
191 },
180 } 192 }
181 } 193 }
182 194
@@ -211,6 +223,13 @@ where
211 if let Some(module) = dep.krate.root_module(self.db) { 223 if let Some(module) = dep.krate.root_module(self.db) {
212 self.result.extern_prelude.insert(dep.name.clone(), module.into()); 224 self.result.extern_prelude.insert(dep.name.clone(), module.into());
213 } 225 }
226 // look for the prelude
227 if self.result.prelude.is_none() {
228 let item_map = self.db.item_map(dep.krate);
229 if item_map.prelude.is_some() {
230 self.result.prelude = item_map.prelude;
231 }
232 }
214 } 233 }
215 } 234 }
216 235
@@ -266,10 +285,20 @@ where
266 import_id: ImportId, 285 import_id: ImportId,
267 import: &ImportData, 286 import: &ImportData,
268 ) -> ReachedFixedPoint { 287 ) -> ReachedFixedPoint {
269 log::debug!("resolving import: {:?}", import); 288 log::debug!("resolving import: {:?} ({:?})", import, self.result.edition);
270 let original_module = Module { krate: self.krate, module_id }; 289 let original_module = Module { krate: self.krate, module_id };
271 let (def, reached_fixedpoint) = 290
272 self.result.resolve_path_fp(self.db, original_module, &import.path); 291 let (def, reached_fixedpoint) = if import.is_extern_crate {
292 let res = self.result.resolve_name_in_extern_prelude(
293 &import
294 .path
295 .as_ident()
296 .expect("extern crate should have been desugared to one-element path"),
297 );
298 (res, if res.is_none() { ReachedFixedPoint::No } else { ReachedFixedPoint::Yes })
299 } else {
300 self.result.resolve_path_fp(self.db, ResolveMode::Import, original_module, &import.path)
301 };
273 302
274 if reached_fixedpoint != ReachedFixedPoint::Yes { 303 if reached_fixedpoint != ReachedFixedPoint::Yes {
275 return reached_fixedpoint; 304 return reached_fixedpoint;
@@ -279,7 +308,10 @@ where
279 log::debug!("glob import: {:?}", import); 308 log::debug!("glob import: {:?}", import);
280 match def.take_types() { 309 match def.take_types() {
281 Some(ModuleDef::Module(m)) => { 310 Some(ModuleDef::Module(m)) => {
282 if m.krate != self.krate { 311 if import.is_prelude {
312 tested_by!(std_prelude);
313 self.result.prelude = Some(m);
314 } else if m.krate != self.krate {
283 tested_by!(glob_across_crates); 315 tested_by!(glob_across_crates);
284 // glob import from other crate => we can just import everything once 316 // glob import from other crate => we can just import everything once
285 let item_map = self.db.item_map(m.krate); 317 let item_map = self.db.item_map(m.krate);
@@ -404,6 +436,12 @@ where
404} 436}
405 437
406#[derive(Debug, Clone, Copy, PartialEq, Eq)] 438#[derive(Debug, Clone, Copy, PartialEq, Eq)]
439enum ResolveMode {
440 Import,
441 Other,
442}
443
444#[derive(Debug, Clone, Copy, PartialEq, Eq)]
407enum ReachedFixedPoint { 445enum ReachedFixedPoint {
408 Yes, 446 Yes,
409 No, 447 No,
@@ -431,15 +469,61 @@ impl ItemMap {
431 original_module: Module, 469 original_module: Module,
432 path: &Path, 470 path: &Path,
433 ) -> PerNs<ModuleDef> { 471 ) -> PerNs<ModuleDef> {
434 self.resolve_path_fp(db, original_module, path).0 472 self.resolve_path_fp(db, ResolveMode::Other, original_module, path).0
473 }
474
475 fn resolve_in_prelude(
476 &self,
477 db: &impl PersistentHirDatabase,
478 original_module: Module,
479 name: &Name,
480 ) -> PerNs<ModuleDef> {
481 if let Some(prelude) = self.prelude {
482 let resolution = if prelude.krate == original_module.krate {
483 self[prelude.module_id].items.get(name).cloned()
484 } else {
485 db.item_map(prelude.krate)[prelude.module_id].items.get(name).cloned()
486 };
487 resolution.map(|r| r.def).unwrap_or_else(PerNs::none)
488 } else {
489 PerNs::none()
490 }
435 } 491 }
436 492
437 pub(crate) fn resolve_name_in_module(&self, module: Module, name: &Name) -> PerNs<ModuleDef> { 493 pub(crate) fn resolve_name_in_module(
494 &self,
495 db: &impl PersistentHirDatabase,
496 module: Module,
497 name: &Name,
498 ) -> PerNs<ModuleDef> {
499 // Resolve in:
500 // - current module / scope
501 // - extern prelude
502 // - std prelude
438 let from_scope = self[module.module_id].items.get(name).map_or(PerNs::none(), |it| it.def); 503 let from_scope = self[module.module_id].items.get(name).map_or(PerNs::none(), |it| it.def);
439 let from_extern_prelude = 504 let from_extern_prelude =
440 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); 505 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
506 let from_prelude = self.resolve_in_prelude(db, module, name);
507
508 from_scope.or(from_extern_prelude).or(from_prelude)
509 }
510
511 fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> {
512 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it))
513 }
441 514
442 from_scope.or(from_extern_prelude) 515 fn resolve_name_in_crate_root_or_extern_prelude(
516 &self,
517 db: &impl PersistentHirDatabase,
518 module: Module,
519 name: &Name,
520 ) -> PerNs<ModuleDef> {
521 let crate_root = module.crate_root(db);
522 let from_crate_root =
523 self[crate_root.module_id].items.get(name).map_or(PerNs::none(), |it| it.def);
524 let from_extern_prelude = self.resolve_name_in_extern_prelude(name);
525
526 from_crate_root.or(from_extern_prelude)
443 } 527 }
444 528
445 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change 529 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change
@@ -447,6 +531,7 @@ impl ItemMap {
447 fn resolve_path_fp( 531 fn resolve_path_fp(
448 &self, 532 &self,
449 db: &impl PersistentHirDatabase, 533 db: &impl PersistentHirDatabase,
534 mode: ResolveMode,
450 original_module: Module, 535 original_module: Module,
451 path: &Path, 536 path: &Path,
452 ) -> (PerNs<ModuleDef>, ReachedFixedPoint) { 537 ) -> (PerNs<ModuleDef>, ReachedFixedPoint) {
@@ -454,12 +539,32 @@ impl ItemMap {
454 let mut curr_per_ns: PerNs<ModuleDef> = match path.kind { 539 let mut curr_per_ns: PerNs<ModuleDef> = match path.kind {
455 PathKind::Crate => PerNs::types(original_module.crate_root(db).into()), 540 PathKind::Crate => PerNs::types(original_module.crate_root(db).into()),
456 PathKind::Self_ => PerNs::types(original_module.into()), 541 PathKind::Self_ => PerNs::types(original_module.into()),
542 // plain import or absolute path in 2015: crate-relative with
543 // fallback to extern prelude (with the simplification in
544 // rust-lang/rust#57745)
545 // TODO there must be a nicer way to write this condition
546 PathKind::Plain | PathKind::Abs
547 if self.edition == Edition::Edition2015
548 && (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
549 {
550 let segment = match segments.next() {
551 Some((_, segment)) => segment,
552 None => return (PerNs::none(), ReachedFixedPoint::Yes),
553 };
554 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
555 self.resolve_name_in_crate_root_or_extern_prelude(
556 db,
557 original_module,
558 &segment.name,
559 )
560 }
457 PathKind::Plain => { 561 PathKind::Plain => {
458 let segment = match segments.next() { 562 let segment = match segments.next() {
459 Some((_, segment)) => segment, 563 Some((_, segment)) => segment,
460 None => return (PerNs::none(), ReachedFixedPoint::Yes), 564 None => return (PerNs::none(), ReachedFixedPoint::Yes),
461 }; 565 };
462 self.resolve_name_in_module(original_module, &segment.name) 566 log::debug!("resolving {:?} in module", segment);
567 self.resolve_name_in_module(db, original_module, &segment.name)
463 } 568 }
464 PathKind::Super => { 569 PathKind::Super => {
465 if let Some(p) = original_module.parent(db) { 570 if let Some(p) = original_module.parent(db) {
@@ -490,7 +595,7 @@ impl ItemMap {
490 None => { 595 None => {
491 // we still have path segments left, but the path so far 596 // we still have path segments left, but the path so far
492 // didn't resolve in the types namespace => no resolution 597 // didn't resolve in the types namespace => no resolution
493 // (don't break here because curr_per_ns might contain 598 // (don't break here because `curr_per_ns` might contain
494 // something in the value namespace, and it would be wrong 599 // something in the value namespace, and it would be wrong
495 // to return that) 600 // to return that)
496 return (PerNs::none(), ReachedFixedPoint::No); 601 return (PerNs::none(), ReachedFixedPoint::No);
diff --git a/crates/ra_hir/src/nameres/lower.rs b/crates/ra_hir/src/nameres/lower.rs
index 7e9a3de2b..81d80654c 100644
--- a/crates/ra_hir/src/nameres/lower.rs
+++ b/crates/ra_hir/src/nameres/lower.rs
@@ -2,13 +2,13 @@ use std::sync::Arc;
2 2
3use ra_syntax::{ 3use ra_syntax::{
4 AstNode, SourceFile, TreeArc, AstPtr, 4 AstNode, SourceFile, TreeArc, AstPtr,
5 ast::{self, ModuleItemOwner, NameOwner}, 5 ast::{self, ModuleItemOwner, NameOwner, AttrsOwner},
6}; 6};
7use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; 7use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap};
8use rustc_hash::FxHashMap; 8use rustc_hash::FxHashMap;
9 9
10use crate::{ 10use crate::{
11 SourceItemId, Path, PathKind, ModuleSource, Name, 11 SourceItemId, Path, ModuleSource, Name,
12 HirFileId, MacroCallLoc, AsName, PerNs, Function, 12 HirFileId, MacroCallLoc, AsName, PerNs, Function,
13 ModuleDef, Module, Struct, Enum, Const, Static, Trait, Type, 13 ModuleDef, Module, Struct, Enum, Const, Static, Trait, Type,
14 ids::LocationCtx, PersistentHirDatabase, 14 ids::LocationCtx, PersistentHirDatabase,
@@ -23,6 +23,7 @@ pub(super) struct ImportData {
23 pub(super) path: Path, 23 pub(super) path: Path,
24 pub(super) alias: Option<Name>, 24 pub(super) alias: Option<Name>,
25 pub(super) is_glob: bool, 25 pub(super) is_glob: bool,
26 pub(super) is_prelude: bool,
26 pub(super) is_extern_crate: bool, 27 pub(super) is_extern_crate: bool,
27} 28}
28 29
@@ -179,18 +180,14 @@ impl LoweredModule {
179 self.add_use_item(source_map, it); 180 self.add_use_item(source_map, it);
180 } 181 }
181 ast::ModuleItemKind::ExternCrateItem(it) => { 182 ast::ModuleItemKind::ExternCrateItem(it) => {
182 // Lower `extern crate x` to `use ::x`. This is kind of cheating
183 // and only works if we always interpret absolute paths in the
184 // 2018 style; otherwise `::x` could also refer to a module in
185 // the crate root.
186 if let Some(name_ref) = it.name_ref() { 183 if let Some(name_ref) = it.name_ref() {
187 let mut path = Path::from_name_ref(name_ref); 184 let path = Path::from_name_ref(name_ref);
188 path.kind = PathKind::Abs;
189 let alias = it.alias().and_then(|a| a.name()).map(AsName::as_name); 185 let alias = it.alias().and_then(|a| a.name()).map(AsName::as_name);
190 self.imports.alloc(ImportData { 186 self.imports.alloc(ImportData {
191 path, 187 path,
192 alias, 188 alias,
193 is_glob: false, 189 is_glob: false,
190 is_prelude: false,
194 is_extern_crate: true, 191 is_extern_crate: true,
195 }); 192 });
196 } 193 }
@@ -208,17 +205,20 @@ impl LoweredModule {
208 } 205 }
209 } 206 }
210 ast::ModuleItemKind::Module(_) => { 207 ast::ModuleItemKind::Module(_) => {
211 // modules are handled separately direclty by nameres 208 // modules are handled separately directly by name res
212 } 209 }
213 }; 210 };
214 } 211 }
215 212
216 fn add_use_item(&mut self, source_map: &mut ImportSourceMap, item: &ast::UseItem) { 213 fn add_use_item(&mut self, source_map: &mut ImportSourceMap, item: &ast::UseItem) {
214 let is_prelude =
215 item.attrs().any(|attr| attr.as_atom().map(|s| s == "prelude_import").unwrap_or(false));
217 Path::expand_use_item(item, |path, segment, alias| { 216 Path::expand_use_item(item, |path, segment, alias| {
218 let import = self.imports.alloc(ImportData { 217 let import = self.imports.alloc(ImportData {
219 path, 218 path,
220 alias, 219 alias,
221 is_glob: segment.is_none(), 220 is_glob: segment.is_none(),
221 is_prelude,
222 is_extern_crate: false, 222 is_extern_crate: false,
223 }); 223 });
224 if let Some(segment) = segment { 224 if let Some(segment) = segment {
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs
index 6dbe759d1..6402c89c0 100644
--- a/crates/ra_hir/src/nameres/tests.rs
+++ b/crates/ra_hir/src/nameres/tests.rs
@@ -266,6 +266,45 @@ fn glob_across_crates() {
266} 266}
267 267
268#[test] 268#[test]
269fn edition_2015_imports() {
270 let mut db = MockDatabase::with_files(
271 "
272 //- /main.rs
273 mod foo;
274 mod bar;
275
276 //- /bar.rs
277 struct Bar;
278
279 //- /foo.rs
280 use bar::Bar;
281 use other_crate::FromLib;
282
283 //- /lib.rs
284 struct FromLib;
285 ",
286 );
287 db.set_crate_graph_from_fixture(crate_graph! {
288 "main": ("/main.rs", "2015", ["other_crate"]),
289 "other_crate": ("/lib.rs", "2018", []),
290 });
291 let foo_id = db.file_id_of("/foo.rs");
292
293 let module = crate::source_binder::module_from_file_id(&db, foo_id).unwrap();
294 let krate = module.krate(&db).unwrap();
295 let item_map = db.item_map(krate);
296
297 check_module_item_map(
298 &item_map,
299 module.module_id,
300 "
301 Bar: t v
302 FromLib: t v
303 ",
304 );
305}
306
307#[test]
269fn module_resolution_works_for_non_standard_filenames() { 308fn module_resolution_works_for_non_standard_filenames() {
270 let mut db = MockDatabase::with_files( 309 let mut db = MockDatabase::with_files(
271 " 310 "
@@ -297,6 +336,43 @@ fn module_resolution_works_for_non_standard_filenames() {
297} 336}
298 337
299#[test] 338#[test]
339fn std_prelude() {
340 covers!(std_prelude);
341 let mut db = MockDatabase::with_files(
342 "
343 //- /main.rs
344 use Foo::*;
345
346 //- /lib.rs
347 mod prelude;
348 #[prelude_import]
349 use prelude::*;
350
351 //- /prelude.rs
352 pub enum Foo { Bar, Baz };
353 ",
354 );
355 db.set_crate_graph_from_fixture(crate_graph! {
356 "main": ("/main.rs", ["test_crate"]),
357 "test_crate": ("/lib.rs", []),
358 });
359 let main_id = db.file_id_of("/main.rs");
360
361 let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap();
362 let krate = module.krate(&db).unwrap();
363 let item_map = db.item_map(krate);
364
365 check_module_item_map(
366 &item_map,
367 module.module_id,
368 "
369 Bar: t v
370 Baz: t v
371 ",
372 );
373}
374
375#[test]
300fn name_res_works_for_broken_modules() { 376fn name_res_works_for_broken_modules() {
301 covers!(name_res_works_for_broken_modules); 377 covers!(name_res_works_for_broken_modules);
302 let (item_map, module_id) = item_map( 378 let (item_map, module_id) = item_map(
@@ -467,6 +543,42 @@ fn extern_crate_rename() {
467} 543}
468 544
469#[test] 545#[test]
546fn extern_crate_rename_2015_edition() {
547 let mut db = MockDatabase::with_files(
548 "
549 //- /main.rs
550 extern crate alloc as alloc_crate;
551
552 mod alloc;
553 mod sync;
554
555 //- /sync.rs
556 use alloc_crate::Arc;
557
558 //- /lib.rs
559 struct Arc;
560 ",
561 );
562 db.set_crate_graph_from_fixture(crate_graph! {
563 "main": ("/main.rs", "2015", ["alloc"]),
564 "alloc": ("/lib.rs", []),
565 });
566 let sync_id = db.file_id_of("/sync.rs");
567
568 let module = crate::source_binder::module_from_file_id(&db, sync_id).unwrap();
569 let krate = module.krate(&db).unwrap();
570 let item_map = db.item_map(krate);
571
572 check_module_item_map(
573 &item_map,
574 module.module_id,
575 "
576 Arc: t v
577 ",
578 );
579}
580
581#[test]
470fn import_across_source_roots() { 582fn import_across_source_roots() {
471 let mut db = MockDatabase::with_files( 583 let mut db = MockDatabase::with_files(
472 " 584 "
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs
index 6a24c8aa7..8ed54607a 100644
--- a/crates/ra_hir/src/path.rs
+++ b/crates/ra_hir/src/path.rs
@@ -97,7 +97,7 @@ impl Path {
97 return Some(q); 97 return Some(q);
98 } 98 }
99 // TODO: this bottom up traversal is not too precise. 99 // TODO: this bottom up traversal is not too precise.
100 // Should we handle do a top-down analysiss, recording results? 100 // Should we handle do a top-down analysis, recording results?
101 let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?; 101 let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?;
102 let use_tree = use_tree_list.parent_use_tree(); 102 let use_tree = use_tree_list.parent_use_tree();
103 use_tree.path() 103 use_tree.path()
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs
index 40c860cf4..91a531801 100644
--- a/crates/ra_hir/src/resolve.rs
+++ b/crates/ra_hir/src/resolve.rs
@@ -56,10 +56,10 @@ pub enum Resolution {
56} 56}
57 57
58impl Resolver { 58impl Resolver {
59 pub fn resolve_name(&self, name: &Name) -> PerNs<Resolution> { 59 pub fn resolve_name(&self, db: &impl HirDatabase, name: &Name) -> PerNs<Resolution> {
60 let mut resolution = PerNs::none(); 60 let mut resolution = PerNs::none();
61 for scope in self.scopes.iter().rev() { 61 for scope in self.scopes.iter().rev() {
62 resolution = resolution.or(scope.resolve_name(name)); 62 resolution = resolution.or(scope.resolve_name(db, name));
63 if resolution.is_both() { 63 if resolution.is_both() {
64 return resolution; 64 return resolution;
65 } 65 }
@@ -69,9 +69,9 @@ impl Resolver {
69 69
70 pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PerNs<Resolution> { 70 pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PerNs<Resolution> {
71 if let Some(name) = path.as_ident() { 71 if let Some(name) = path.as_ident() {
72 self.resolve_name(name) 72 self.resolve_name(db, name)
73 } else if path.is_self() { 73 } else if path.is_self() {
74 self.resolve_name(&Name::self_param()) 74 self.resolve_name(db, &Name::self_param())
75 } else { 75 } else {
76 let (item_map, module) = match self.module() { 76 let (item_map, module) = match self.module() {
77 Some(m) => m, 77 Some(m) => m,
@@ -82,10 +82,10 @@ impl Resolver {
82 } 82 }
83 } 83 }
84 84
85 pub fn all_names(&self) -> FxHashMap<Name, PerNs<Resolution>> { 85 pub fn all_names(&self, db: &impl HirDatabase) -> FxHashMap<Name, PerNs<Resolution>> {
86 let mut names = FxHashMap::default(); 86 let mut names = FxHashMap::default();
87 for scope in self.scopes.iter().rev() { 87 for scope in self.scopes.iter().rev() {
88 scope.collect_names(&mut |name, res| { 88 scope.collect_names(db, &mut |name, res| {
89 let current: &mut PerNs<Resolution> = names.entry(name).or_default(); 89 let current: &mut PerNs<Resolution> = names.entry(name).or_default();
90 if current.types.is_none() { 90 if current.types.is_none() {
91 current.types = res.types; 91 current.types = res.types;
@@ -143,13 +143,13 @@ impl Resolver {
143} 143}
144 144
145impl Scope { 145impl Scope {
146 fn resolve_name(&self, name: &Name) -> PerNs<Resolution> { 146 fn resolve_name(&self, db: &impl HirDatabase, name: &Name) -> PerNs<Resolution> {
147 match self { 147 match self {
148 Scope::ModuleScope(m) => { 148 Scope::ModuleScope(m) => {
149 if let Some(KnownName::SelfParam) = name.as_known_name() { 149 if let Some(KnownName::SelfParam) = name.as_known_name() {
150 PerNs::types(Resolution::Def(m.module.into())) 150 PerNs::types(Resolution::Def(m.module.into()))
151 } else { 151 } else {
152 m.item_map.resolve_name_in_module(m.module, name).map(Resolution::Def) 152 m.item_map.resolve_name_in_module(db, m.module, name).map(Resolution::Def)
153 } 153 }
154 } 154 }
155 Scope::GenericParams(gp) => match gp.find_by_name(name) { 155 Scope::GenericParams(gp) => match gp.find_by_name(name) {
@@ -174,7 +174,7 @@ impl Scope {
174 } 174 }
175 } 175 }
176 176
177 fn collect_names(&self, f: &mut dyn FnMut(Name, PerNs<Resolution>)) { 177 fn collect_names(&self, db: &impl HirDatabase, f: &mut dyn FnMut(Name, PerNs<Resolution>)) {
178 match self { 178 match self {
179 Scope::ModuleScope(m) => { 179 Scope::ModuleScope(m) => {
180 // TODO: should we provide `self` here? 180 // TODO: should we provide `self` here?
@@ -190,6 +190,12 @@ impl Scope {
190 m.item_map.extern_prelude.iter().for_each(|(name, def)| { 190 m.item_map.extern_prelude.iter().for_each(|(name, def)| {
191 f(name.clone(), PerNs::types(Resolution::Def(*def))); 191 f(name.clone(), PerNs::types(Resolution::Def(*def)));
192 }); 192 });
193 if let Some(prelude) = m.item_map.prelude {
194 let prelude_item_map = db.item_map(prelude.krate);
195 prelude_item_map[prelude.module_id].entries().for_each(|(name, res)| {
196 f(name.clone(), res.def.map(Resolution::Def));
197 });
198 }
193 } 199 }
194 Scope::GenericParams(gp) => { 200 Scope::GenericParams(gp) => {
195 for param in &gp.params { 201 for param in &gp.params {
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index 2dc1de41a..f28a7e731 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -450,7 +450,6 @@ impl Ty {
450 } 450 }
451 451
452 pub fn walk(&self, f: &mut impl FnMut(&Ty)) { 452 pub fn walk(&self, f: &mut impl FnMut(&Ty)) {
453 f(self);
454 match self { 453 match self {
455 Ty::Slice(t) | Ty::Array(t) => t.walk(f), 454 Ty::Slice(t) | Ty::Array(t) => t.walk(f),
456 Ty::RawPtr(t, _) => t.walk(f), 455 Ty::RawPtr(t, _) => t.walk(f),
@@ -490,10 +489,10 @@ impl Ty {
490 | Ty::Infer(_) 489 | Ty::Infer(_)
491 | Ty::Unknown => {} 490 | Ty::Unknown => {}
492 } 491 }
492 f(self);
493 } 493 }
494 494
495 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { 495 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
496 f(self);
497 match self { 496 match self {
498 Ty::Slice(t) | Ty::Array(t) => Arc::make_mut(t).walk_mut(f), 497 Ty::Slice(t) | Ty::Array(t) => Arc::make_mut(t).walk_mut(f),
499 Ty::RawPtr(t, _) => Arc::make_mut(t).walk_mut(f), 498 Ty::RawPtr(t, _) => Arc::make_mut(t).walk_mut(f),
@@ -544,6 +543,7 @@ impl Ty {
544 | Ty::Infer(_) 543 | Ty::Infer(_)
545 | Ty::Unknown => {} 544 | Ty::Unknown => {}
546 } 545 }
546 f(self);
547 } 547 }
548 548
549 fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Ty { 549 fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Ty {
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_nested_generics_crash.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_nested_generics_crash.snap
new file mode 100644
index 000000000..209454a91
--- /dev/null
+++ b/crates/ra_hir/src/ty/snapshots/tests__infer_nested_generics_crash.snap
@@ -0,0 +1,12 @@
1---
2created: "2019-02-11T21:59:04.302375838Z"
3creator: [email protected]
4source: crates/ra_hir/src/ty/tests.rs
5expression: "&result"
6---
7[92; 106) 'query_response': Canonical<QueryResponse<R>>
8[137; 167) '{ ...lue; }': ()
9[143; 164) '&query....value': &QueryResponse<R>
10[144; 158) 'query_response': Canonical<QueryResponse<R>>
11[144; 164) 'query_....value': QueryResponse<R>
12
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index e64fd2749..203f1fe4d 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -719,6 +719,25 @@ fn extra_compiler_flags() {
719 ); 719 );
720} 720}
721 721
722#[test]
723fn infer_nested_generics_crash() {
724 // another crash found typechecking rustc
725 check_inference(
726 "infer_nested_generics_crash",
727 r#"
728struct Canonical<V> {
729 value: V,
730}
731struct QueryResponse<V> {
732 value: V,
733}
734fn test<R>(query_response: Canonical<QueryResponse<R>>) {
735 &query_response.value;
736}
737"#,
738 );
739}
740
722fn infer(content: &str) -> String { 741fn infer(content: &str) -> String {
723 let (db, _, file_id) = MockDatabase::with_single_file(content); 742 let (db, _, file_id) = MockDatabase::with_single_file(content);
724 let source_file = db.parse(file_id); 743 let source_file = db.parse(file_id);
diff --git a/crates/ra_ide_api/src/completion.rs b/crates/ra_ide_api/src/completion.rs
index 83c243944..4a38d62bb 100644
--- a/crates/ra_ide_api/src/completion.rs
+++ b/crates/ra_ide_api/src/completion.rs
@@ -30,7 +30,7 @@ pub use crate::completion::completion_item::{CompletionItem, CompletionItemKind,
30/// incomplete and can look really weird. 30/// incomplete and can look really weird.
31/// 31///
32/// Once the context is collected, we run a series of completion routines which 32/// Once the context is collected, we run a series of completion routines which
33/// look at the context and produce completion items. One subtelty about this 33/// look at the context and produce completion items. One subtlety about this
34/// phase is that completion engine should not filter by the substring which is 34/// phase is that completion engine should not filter by the substring which is
35/// already present, it should give all possible variants for the identifier at 35/// already present, it should give all possible variants for the identifier at
36/// the caret. In other words, for 36/// the caret. In other words, for
@@ -71,6 +71,7 @@ pub fn function_label(node: &ast::FnDef) -> Option<String> {
71 .children() 71 .children()
72 .filter(|child| !child.range().is_subrange(&body_range)) // Filter out body 72 .filter(|child| !child.range().is_subrange(&body_range)) // Filter out body
73 .filter(|child| ast::Comment::cast(child).is_none()) // Filter out comments 73 .filter(|child| ast::Comment::cast(child).is_none()) // Filter out comments
74 .filter(|child| ast::Attr::cast(child).is_none()) // Filter out attributes
74 .map(|node| node.text().to_string()) 75 .map(|node| node.text().to_string())
75 .collect(); 76 .collect();
76 label 77 label
@@ -86,6 +87,7 @@ pub fn const_label(node: &ast::ConstDef) -> String {
86 .syntax() 87 .syntax()
87 .children() 88 .children()
88 .filter(|child| ast::Comment::cast(child).is_none()) 89 .filter(|child| ast::Comment::cast(child).is_none())
90 .filter(|child| ast::Attr::cast(child).is_none())
89 .map(|node| node.text().to_string()) 91 .map(|node| node.text().to_string())
90 .collect(); 92 .collect();
91 93
@@ -97,6 +99,7 @@ pub fn type_label(node: &ast::TypeDef) -> String {
97 .syntax() 99 .syntax()
98 .children() 100 .children()
99 .filter(|child| ast::Comment::cast(child).is_none()) 101 .filter(|child| ast::Comment::cast(child).is_none())
102 .filter(|child| ast::Attr::cast(child).is_none())
100 .map(|node| node.text().to_string()) 103 .map(|node| node.text().to_string())
101 .collect(); 104 .collect();
102 105
diff --git a/crates/ra_ide_api/src/completion/complete_dot.rs b/crates/ra_ide_api/src/completion/complete_dot.rs
index a673dbdcf..be839345f 100644
--- a/crates/ra_ide_api/src/completion/complete_dot.rs
+++ b/crates/ra_ide_api/src/completion/complete_dot.rs
@@ -180,6 +180,26 @@ mod tests {
180 } 180 }
181 181
182 #[test] 182 #[test]
183 fn test_method_attr_filtering() {
184 check_ref_completion(
185 "method_attr_filtering",
186 r"
187 struct A {}
188 impl A {
189 #[inline]
190 fn the_method(&self) {
191 let x = 1;
192 let y = 2;
193 }
194 }
195 fn foo(a: A) {
196 a.<|>
197 }
198 ",
199 );
200 }
201
202 #[test]
183 fn test_tuple_field_completion() { 203 fn test_tuple_field_completion() {
184 check_ref_completion( 204 check_ref_completion(
185 "tuple_field_completion", 205 "tuple_field_completion",
diff --git a/crates/ra_ide_api/src/completion/complete_fn_param.rs b/crates/ra_ide_api/src/completion/complete_fn_param.rs
index 43532226f..4d6416284 100644
--- a/crates/ra_ide_api/src/completion/complete_fn_param.rs
+++ b/crates/ra_ide_api/src/completion/complete_fn_param.rs
@@ -7,7 +7,7 @@ use rustc_hash::FxHashMap;
7 7
8use crate::completion::{CompletionContext, Completions, CompletionKind, CompletionItem}; 8use crate::completion::{CompletionContext, Completions, CompletionKind, CompletionItem};
9 9
10/// Complete repeated parametes, both name and type. For example, if all 10/// Complete repeated parameters, both name and type. For example, if all
11/// functions in a file have a `spam: &mut Spam` parameter, a completion with 11/// functions in a file have a `spam: &mut Spam` parameter, a completion with
12/// `spam: &mut Spam` insert text/label and `spam` lookup string will be 12/// `spam: &mut Spam` insert text/label and `spam` lookup string will be
13/// suggested. 13/// suggested.
diff --git a/crates/ra_ide_api/src/completion/complete_scope.rs b/crates/ra_ide_api/src/completion/complete_scope.rs
index 445788407..eeaf26d93 100644
--- a/crates/ra_ide_api/src/completion/complete_scope.rs
+++ b/crates/ra_ide_api/src/completion/complete_scope.rs
@@ -4,7 +4,7 @@ pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) {
4 if !ctx.is_trivial_path { 4 if !ctx.is_trivial_path {
5 return; 5 return;
6 } 6 }
7 let names = ctx.resolver.all_names(); 7 let names = ctx.resolver.all_names(ctx.db);
8 8
9 names.into_iter().for_each(|(name, res)| { 9 names.into_iter().for_each(|(name, res)| {
10 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string()) 10 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string())
@@ -165,4 +165,23 @@ mod tests {
165 fn completes_self_in_methods() { 165 fn completes_self_in_methods() {
166 check_reference_completion("self_in_methods", r"impl S { fn foo(&self) { <|> } }") 166 check_reference_completion("self_in_methods", r"impl S { fn foo(&self) { <|> } }")
167 } 167 }
168
169 #[test]
170 fn completes_prelude() {
171 check_reference_completion(
172 "completes_prelude",
173 "
174 //- /main.rs
175 fn foo() { let x: <|> }
176
177 //- /std/lib.rs
178 #[prelude_import]
179 use prelude::*;
180
181 mod prelude {
182 struct Option;
183 }
184 ",
185 );
186 }
168} 187}
diff --git a/crates/ra_ide_api/src/completion/snapshots/completion_item__completes_prelude.snap b/crates/ra_ide_api/src/completion/snapshots/completion_item__completes_prelude.snap
new file mode 100644
index 000000000..2b5a1a8ea
--- /dev/null
+++ b/crates/ra_ide_api/src/completion/snapshots/completion_item__completes_prelude.snap
@@ -0,0 +1,54 @@
1---
2created: "2019-02-13T19:52:43.734834624Z"
3creator: [email protected]
4source: crates/ra_ide_api/src/completion/completion_item.rs
5expression: kind_completions
6---
7[
8 CompletionItem {
9 completion_kind: Reference,
10 label: "Option",
11 kind: Some(
12 Struct
13 ),
14 detail: None,
15 documentation: None,
16 lookup: None,
17 insert_text: None,
18 insert_text_format: PlainText,
19 source_range: [18; 18),
20 text_edit: None
21 },
22 CompletionItem {
23 completion_kind: Reference,
24 label: "foo",
25 kind: Some(
26 Function
27 ),
28 detail: Some(
29 "fn foo()"
30 ),
31 documentation: None,
32 lookup: None,
33 insert_text: Some(
34 "foo()$0"
35 ),
36 insert_text_format: Snippet,
37 source_range: [18; 18),
38 text_edit: None
39 },
40 CompletionItem {
41 completion_kind: Reference,
42 label: "std",
43 kind: Some(
44 Module
45 ),
46 detail: None,
47 documentation: None,
48 lookup: None,
49 insert_text: None,
50 insert_text_format: PlainText,
51 source_range: [18; 18),
52 text_edit: None
53 }
54]
diff --git a/crates/ra_ide_api/src/completion/snapshots/completion_item__method_attr_filtering.snap b/crates/ra_ide_api/src/completion/snapshots/completion_item__method_attr_filtering.snap
new file mode 100644
index 000000000..46f9fa971
--- /dev/null
+++ b/crates/ra_ide_api/src/completion/snapshots/completion_item__method_attr_filtering.snap
@@ -0,0 +1,26 @@
1---
2created: "2019-02-12T18:32:09.428929418Z"
3creator: [email protected]
4source: crates/ra_ide_api/src/completion/completion_item.rs
5expression: kind_completions
6---
7[
8 CompletionItem {
9 completion_kind: Reference,
10 label: "the_method",
11 kind: Some(
12 Method
13 ),
14 detail: Some(
15 "fn the_method(&self)"
16 ),
17 documentation: None,
18 lookup: None,
19 insert_text: Some(
20 "the_method()$0"
21 ),
22 insert_text_format: Snippet,
23 source_range: [249; 249),
24 text_edit: None
25 }
26]
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs
index 413720960..96ed8c8e9 100644
--- a/crates/ra_ide_api/src/goto_definition.rs
+++ b/crates/ra_ide_api/src/goto_definition.rs
@@ -93,10 +93,10 @@ pub(crate) fn reference_definition(
93 return Exact(nav); 93 return Exact(nav);
94 } 94 }
95 Some(Resolution::GenericParam(..)) => { 95 Some(Resolution::GenericParam(..)) => {
96 // TODO go to the generic param def 96 // TODO: go to the generic param def
97 } 97 }
98 Some(Resolution::SelfType(_impl_block)) => { 98 Some(Resolution::SelfType(_impl_block)) => {
99 // TODO go to the implemented type 99 // TODO: go to the implemented type
100 } 100 }
101 None => {} 101 None => {}
102 } 102 }
@@ -133,8 +133,8 @@ mod tests {
133 133
134 use crate::mock_analysis::analysis_and_position; 134 use crate::mock_analysis::analysis_and_position;
135 135
136 fn check_goto(fixuture: &str, expected: &str) { 136 fn check_goto(fixture: &str, expected: &str) {
137 let (analysis, pos) = analysis_and_position(fixuture); 137 let (analysis, pos) = analysis_and_position(fixture);
138 138
139 let mut navs = analysis.goto_definition(pos).unwrap().unwrap().info; 139 let mut navs = analysis.goto_definition(pos).unwrap().unwrap().info;
140 assert_eq!(navs.len(), 1); 140 assert_eq!(navs.len(), 1);
diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs
index 60b81567c..0888ab6de 100644
--- a/crates/ra_ide_api/src/hover.rs
+++ b/crates/ra_ide_api/src/hover.rs
@@ -71,8 +71,8 @@ pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> {
71 } 71 }
72} 72}
73 73
74// FIXME: this should not really use navigation target. Rather, approximatelly 74// FIXME: this should not really use navigation target. Rather, approximately
75// resovled symbol should return a `DefId`. 75// resolved symbol should return a `DefId`.
76fn doc_text_for(db: &RootDatabase, nav: NavigationTarget) -> Option<String> { 76fn doc_text_for(db: &RootDatabase, nav: NavigationTarget) -> Option<String> {
77 match (nav.description(db), nav.docs(db)) { 77 match (nav.description(db), nav.docs(db)) {
78 (Some(desc), Some(docs)) => Some("```rust\n".to_string() + &*desc + "\n```\n\n" + &*docs), 78 (Some(desc), Some(docs)) => Some("```rust\n".to_string() + &*desc + "\n```\n\n" + &*docs),
diff --git a/crates/ra_ide_api/src/impls.rs b/crates/ra_ide_api/src/impls.rs
index 444c4aeb2..681bd808d 100644
--- a/crates/ra_ide_api/src/impls.rs
+++ b/crates/ra_ide_api/src/impls.rs
@@ -78,8 +78,8 @@ fn impls_for_trait(
78mod tests { 78mod tests {
79 use crate::mock_analysis::analysis_and_position; 79 use crate::mock_analysis::analysis_and_position;
80 80
81 fn check_goto(fixuture: &str, expected: &[&str]) { 81 fn check_goto(fixture: &str, expected: &[&str]) {
82 let (analysis, pos) = analysis_and_position(fixuture); 82 let (analysis, pos) = analysis_and_position(fixture);
83 83
84 let navs = analysis.goto_implementation(pos).unwrap().unwrap().info; 84 let navs = analysis.goto_implementation(pos).unwrap().unwrap().info;
85 assert_eq!(navs.len(), expected.len()); 85 assert_eq!(navs.len(), expected.len());
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs
index 2d090d9b4..d77a56ce8 100644
--- a/crates/ra_ide_api/src/lib.rs
+++ b/crates/ra_ide_api/src/lib.rs
@@ -7,7 +7,7 @@
7//! However, IDE specific bits of the analysis (most notably completion) happen 7//! However, IDE specific bits of the analysis (most notably completion) happen
8//! in this crate. 8//! in this crate.
9//! 9//!
10//! The sibling `ra_ide_api_light` handles thouse bits of IDE functionality 10//! The sibling `ra_ide_api_light` handles those bits of IDE functionality
11//! which are restricted to a single file and need only syntax. 11//! which are restricted to a single file and need only syntax.
12 12
13// For proving that RootDatabase is RefUnwindSafe. 13// For proving that RootDatabase is RefUnwindSafe.
@@ -62,12 +62,13 @@ pub use ra_ide_api_light::{
62 LineIndex, LineCol, translate_offset_with_edit, 62 LineIndex, LineCol, translate_offset_with_edit,
63}; 63};
64pub use ra_db::{ 64pub use ra_db::{
65 Canceled, CrateGraph, CrateId, FileId, FilePosition, FileRange, SourceRootId 65 Canceled, CrateGraph, CrateId, FileId, FilePosition, FileRange, SourceRootId,
66 Edition
66}; 67};
67pub use hir::Documentation; 68pub use hir::Documentation;
68 69
69// We use jemalloc mainly to get heap usage statistics, actual performance 70// We use jemalloc mainly to get heap usage statistics, actual performance
70// differnece is not measures. 71// difference is not measures.
71#[cfg(feature = "jemalloc")] 72#[cfg(feature = "jemalloc")]
72#[global_allocator] 73#[global_allocator]
73static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; 74static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
@@ -221,12 +222,12 @@ impl Analysis {
221 self.db.line_index(file_id) 222 self.db.line_index(file_id)
222 } 223 }
223 224
224 /// Selects the next syntactic nodes encopasing the range. 225 /// Selects the next syntactic nodes encompassing the range.
225 pub fn extend_selection(&self, frange: FileRange) -> Cancelable<TextRange> { 226 pub fn extend_selection(&self, frange: FileRange) -> Cancelable<TextRange> {
226 self.with_db(|db| extend_selection::extend_selection(db, frange)) 227 self.with_db(|db| extend_selection::extend_selection(db, frange))
227 } 228 }
228 229
229 /// Returns position of the mathcing brace (all types of braces are 230 /// Returns position of the matching brace (all types of braces are
230 /// supported). 231 /// supported).
231 pub fn matching_brace(&self, position: FilePosition) -> Option<TextUnit> { 232 pub fn matching_brace(&self, position: FilePosition) -> Option<TextUnit> {
232 let file = self.db.parse(position.file_id); 233 let file = self.db.parse(position.file_id);
@@ -316,7 +317,7 @@ impl Analysis {
316 self.with_db(|db| references::find_all_refs(db, position)) 317 self.with_db(|db| references::find_all_refs(db, position))
317 } 318 }
318 319
319 /// Returns a short text descrbing element at position. 320 /// Returns a short text describing element at position.
320 pub fn hover(&self, position: FilePosition) -> Cancelable<Option<RangeInfo<String>>> { 321 pub fn hover(&self, position: FilePosition) -> Cancelable<Option<RangeInfo<String>>> {
321 self.with_db(|db| hover::hover(db, position)) 322 self.with_db(|db| hover::hover(db, position))
322 } 323 }
diff --git a/crates/ra_ide_api/src/mock_analysis.rs b/crates/ra_ide_api/src/mock_analysis.rs
index 8d8603062..550d69641 100644
--- a/crates/ra_ide_api/src/mock_analysis.rs
+++ b/crates/ra_ide_api/src/mock_analysis.rs
@@ -3,7 +3,7 @@ use std::sync::Arc;
3use relative_path::RelativePathBuf; 3use relative_path::RelativePathBuf;
4use test_utils::{extract_offset, extract_range, parse_fixture, CURSOR_MARKER}; 4use test_utils::{extract_offset, extract_range, parse_fixture, CURSOR_MARKER};
5 5
6use crate::{Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, FilePosition, FileRange, SourceRootId}; 6use crate::{Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, FilePosition, FileRange, SourceRootId, Edition::Edition2018};
7 7
8/// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis 8/// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis
9/// from a set of in-memory files. 9/// from a set of in-memory files.
@@ -18,7 +18,7 @@ impl MockAnalysis {
18 } 18 }
19 /// Creates `MockAnalysis` using a fixture data in the following format: 19 /// Creates `MockAnalysis` using a fixture data in the following format:
20 /// 20 ///
21 /// ```notrust 21 /// ```rust,ignore
22 /// //- /main.rs 22 /// //- /main.rs
23 /// mod foo; 23 /// mod foo;
24 /// fn main() {} 24 /// fn main() {}
@@ -89,9 +89,9 @@ impl MockAnalysis {
89 let path = RelativePathBuf::from_path(&path[1..]).unwrap(); 89 let path = RelativePathBuf::from_path(&path[1..]).unwrap();
90 let file_id = FileId(i as u32 + 1); 90 let file_id = FileId(i as u32 + 1);
91 if path == "/lib.rs" || path == "/main.rs" { 91 if path == "/lib.rs" || path == "/main.rs" {
92 root_crate = Some(crate_graph.add_crate_root(file_id)); 92 root_crate = Some(crate_graph.add_crate_root(file_id, Edition2018));
93 } else if path.ends_with("/lib.rs") { 93 } else if path.ends_with("/lib.rs") {
94 let other_crate = crate_graph.add_crate_root(file_id); 94 let other_crate = crate_graph.add_crate_root(file_id, Edition2018);
95 let crate_name = path.parent().unwrap().file_name().unwrap(); 95 let crate_name = path.parent().unwrap().file_name().unwrap();
96 if let Some(root_crate) = root_crate { 96 if let Some(root_crate) = root_crate {
97 crate_graph.add_dep(root_crate, crate_name.into(), other_crate).unwrap(); 97 crate_graph.add_dep(root_crate, crate_name.into(), other_crate).unwrap();
diff --git a/crates/ra_ide_api/src/navigation_target.rs b/crates/ra_ide_api/src/navigation_target.rs
index a2e4b6506..c559dca11 100644
--- a/crates/ra_ide_api/src/navigation_target.rs
+++ b/crates/ra_ide_api/src/navigation_target.rs
@@ -19,6 +19,7 @@ pub struct NavigationTarget {
19 kind: SyntaxKind, 19 kind: SyntaxKind,
20 full_range: TextRange, 20 full_range: TextRange,
21 focus_range: Option<TextRange>, 21 focus_range: Option<TextRange>,
22 container_name: Option<SmolStr>,
22} 23}
23 24
24impl NavigationTarget { 25impl NavigationTarget {
@@ -26,6 +27,10 @@ impl NavigationTarget {
26 &self.name 27 &self.name
27 } 28 }
28 29
30 pub fn container_name(&self) -> Option<&SmolStr> {
31 self.container_name.as_ref()
32 }
33
29 pub fn kind(&self) -> SyntaxKind { 34 pub fn kind(&self) -> SyntaxKind {
30 self.kind 35 self.kind
31 } 36 }
@@ -53,6 +58,7 @@ impl NavigationTarget {
53 kind: symbol.ptr.kind(), 58 kind: symbol.ptr.kind(),
54 full_range: symbol.ptr.range(), 59 full_range: symbol.ptr.range(),
55 focus_range: None, 60 focus_range: None,
61 container_name: symbol.container_name.clone(),
56 } 62 }
57 } 63 }
58 64
@@ -67,6 +73,7 @@ impl NavigationTarget {
67 full_range: ptr.range(), 73 full_range: ptr.range(),
68 focus_range: None, 74 focus_range: None,
69 kind: NAME, 75 kind: NAME,
76 container_name: None,
70 } 77 }
71 } 78 }
72 79
@@ -170,6 +177,9 @@ impl NavigationTarget {
170 if let Some(focus_range) = self.focus_range() { 177 if let Some(focus_range) = self.focus_range() {
171 buf.push_str(&format!(" {:?}", focus_range)) 178 buf.push_str(&format!(" {:?}", focus_range))
172 } 179 }
180 if let Some(container_name) = self.container_name() {
181 buf.push_str(&format!(" {:?}", container_name))
182 }
173 buf 183 buf
174 } 184 }
175 185
@@ -192,6 +202,7 @@ impl NavigationTarget {
192 full_range: node.range(), 202 full_range: node.range(),
193 focus_range, 203 focus_range,
194 // ptr: Some(LocalSyntaxPtr::new(node)), 204 // ptr: Some(LocalSyntaxPtr::new(node)),
205 container_name: None,
195 } 206 }
196 } 207 }
197} 208}
diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs
index 2cb1cc9be..ca145f3e4 100644
--- a/crates/ra_ide_api/src/references.rs
+++ b/crates/ra_ide_api/src/references.rs
@@ -295,17 +295,17 @@ mod tests {
295 fn test_rename(text: &str, new_name: &str, expected: &str) { 295 fn test_rename(text: &str, new_name: &str, expected: &str) {
296 let (analysis, position) = single_file_with_position(text); 296 let (analysis, position) = single_file_with_position(text);
297 let source_change = analysis.rename(position, new_name).unwrap(); 297 let source_change = analysis.rename(position, new_name).unwrap();
298 let mut text_edit_bulder = ra_text_edit::TextEditBuilder::default(); 298 let mut text_edit_builder = ra_text_edit::TextEditBuilder::default();
299 let mut file_id: Option<FileId> = None; 299 let mut file_id: Option<FileId> = None;
300 if let Some(change) = source_change { 300 if let Some(change) = source_change {
301 for edit in change.source_file_edits { 301 for edit in change.source_file_edits {
302 file_id = Some(edit.file_id); 302 file_id = Some(edit.file_id);
303 for atom in edit.edit.as_atoms() { 303 for atom in edit.edit.as_atoms() {
304 text_edit_bulder.replace(atom.delete, atom.insert.clone()); 304 text_edit_builder.replace(atom.delete, atom.insert.clone());
305 } 305 }
306 } 306 }
307 } 307 }
308 let result = text_edit_bulder.finish().apply(&*analysis.file_text(file_id.unwrap())); 308 let result = text_edit_builder.finish().apply(&*analysis.file_text(file_id.unwrap()));
309 assert_eq_text!(expected, &*result); 309 assert_eq_text!(expected, &*result);
310 } 310 }
311} 311}
diff --git a/crates/ra_ide_api/src/symbol_index.rs b/crates/ra_ide_api/src/symbol_index.rs
index de0f46134..afb10fa92 100644
--- a/crates/ra_ide_api/src/symbol_index.rs
+++ b/crates/ra_ide_api/src/symbol_index.rs
@@ -5,20 +5,20 @@
5//! symbols. The backbone of the index is the **awesome** `fst` crate by 5//! symbols. The backbone of the index is the **awesome** `fst` crate by
6//! @BurntSushi. 6//! @BurntSushi.
7//! 7//!
8//! In a nutshell, you give a set of strings to the `fst`, and it builds a 8//! In a nutshell, you give a set of strings to `fst`, and it builds a
9//! finite state machine describing this set of strings. The strings which 9//! finite state machine describing this set of strings. The strings which
10//! could fuzzy-match a pattern can also be described by a finite state machine. 10//! could fuzzy-match a pattern can also be described by a finite state machine.
11//! What is freakingly cool is that you can now traverse both state machines in 11//! What is freaking cool is that you can now traverse both state machines in
12//! lock-step to enumerate the strings which are both in the input set and 12//! lock-step to enumerate the strings which are both in the input set and
13//! fuzz-match the query. Or, more formally, given two languages described by 13//! fuzz-match the query. Or, more formally, given two languages described by
14//! fsts, one can build an product fst which describes the intersection of the 14//! FSTs, one can build a product FST which describes the intersection of the
15//! languages. 15//! languages.
16//! 16//!
17//! `fst` does not support cheap updating of the index, but it supports unioning 17//! `fst` does not support cheap updating of the index, but it supports unioning
18//! of state machines. So, to account for changing source code, we build an fst 18//! of state machines. So, to account for changing source code, we build an FST
19//! for each library (which is assumed to never change) and an fst for each rust 19//! for each library (which is assumed to never change) and an FST for each Rust
20//! file in the current workspace, and run a query against the union of all 20//! file in the current workspace, and run a query against the union of all
21//! those fsts. 21//! those FSTs.
22use std::{ 22use std::{
23 cmp::Ordering, 23 cmp::Ordering,
24 hash::{Hash, Hasher}, 24 hash::{Hash, Hasher},
@@ -32,6 +32,7 @@ use ra_syntax::{
32 algo::{visit::{visitor, Visitor}, find_covering_node}, 32 algo::{visit::{visitor, Visitor}, find_covering_node},
33 SyntaxKind::{self, *}, 33 SyntaxKind::{self, *},
34 ast::{self, NameOwner}, 34 ast::{self, NameOwner},
35 WalkEvent,
35}; 36};
36use ra_db::{ 37use ra_db::{
37 SourceRootId, SourceDatabase, 38 SourceRootId, SourceDatabase,
@@ -62,17 +63,14 @@ pub(crate) trait SymbolsDatabase: hir::db::HirDatabase {
62fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex> { 63fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex> {
63 db.check_canceled(); 64 db.check_canceled();
64 let source_file = db.parse(file_id); 65 let source_file = db.parse(file_id);
65 let mut symbols = source_file 66
66 .syntax() 67 let mut symbols = source_file_to_file_symbols(&source_file, file_id);
67 .descendants()
68 .filter_map(to_symbol)
69 .map(move |(name, ptr)| FileSymbol { name, ptr, file_id })
70 .collect::<Vec<_>>();
71 68
72 for (name, text_range) in hir::source_binder::macro_symbols(db, file_id) { 69 for (name, text_range) in hir::source_binder::macro_symbols(db, file_id) {
73 let node = find_covering_node(source_file.syntax(), text_range); 70 let node = find_covering_node(source_file.syntax(), text_range);
74 let ptr = SyntaxNodePtr::new(node); 71 let ptr = SyntaxNodePtr::new(node);
75 symbols.push(FileSymbol { file_id, name, ptr }) 72 // TODO: Should we get container name for macro symbols?
73 symbols.push(FileSymbol { file_id, name, ptr, container_name: None })
76 } 74 }
77 75
78 Arc::new(SymbolIndex::new(symbols)) 76 Arc::new(SymbolIndex::new(symbols))
@@ -158,13 +156,7 @@ impl SymbolIndex {
158 files: impl ParallelIterator<Item = (FileId, TreeArc<SourceFile>)>, 156 files: impl ParallelIterator<Item = (FileId, TreeArc<SourceFile>)>,
159 ) -> SymbolIndex { 157 ) -> SymbolIndex {
160 let symbols = files 158 let symbols = files
161 .flat_map(|(file_id, file)| { 159 .flat_map(|(file_id, file)| source_file_to_file_symbols(&file, file_id))
162 file.syntax()
163 .descendants()
164 .filter_map(to_symbol)
165 .map(move |(name, ptr)| FileSymbol { name, ptr, file_id })
166 .collect::<Vec<_>>()
167 })
168 .collect::<Vec<_>>(); 160 .collect::<Vec<_>>();
169 SymbolIndex::new(symbols) 161 SymbolIndex::new(symbols)
170 } 162 }
@@ -215,12 +207,40 @@ pub(crate) struct FileSymbol {
215 pub(crate) file_id: FileId, 207 pub(crate) file_id: FileId,
216 pub(crate) name: SmolStr, 208 pub(crate) name: SmolStr,
217 pub(crate) ptr: SyntaxNodePtr, 209 pub(crate) ptr: SyntaxNodePtr,
210 pub(crate) container_name: Option<SmolStr>,
211}
212
213fn source_file_to_file_symbols(source_file: &SourceFile, file_id: FileId) -> Vec<FileSymbol> {
214 let mut symbols = Vec::new();
215 let mut stack = Vec::new();
216
217 for event in source_file.syntax().preorder() {
218 match event {
219 WalkEvent::Enter(node) => {
220 if let Some(mut symbol) = to_file_symbol(node, file_id) {
221 symbol.container_name = stack.last().cloned();
222
223 stack.push(symbol.name.clone());
224 symbols.push(symbol);
225 }
226 }
227
228 WalkEvent::Leave(node) => {
229 if to_symbol(node).is_some() {
230 stack.pop();
231 }
232 }
233 }
234 }
235
236 symbols
218} 237}
219 238
220fn to_symbol(node: &SyntaxNode) -> Option<(SmolStr, SyntaxNodePtr)> { 239fn to_symbol(node: &SyntaxNode) -> Option<(SmolStr, SyntaxNodePtr)> {
221 fn decl<N: NameOwner>(node: &N) -> Option<(SmolStr, SyntaxNodePtr)> { 240 fn decl<N: NameOwner>(node: &N) -> Option<(SmolStr, SyntaxNodePtr)> {
222 let name = node.name()?.text().clone(); 241 let name = node.name()?.text().clone();
223 let ptr = SyntaxNodePtr::new(node.syntax()); 242 let ptr = SyntaxNodePtr::new(node.syntax());
243
224 Some((name, ptr)) 244 Some((name, ptr))
225 } 245 }
226 visitor() 246 visitor()
@@ -234,3 +254,7 @@ fn to_symbol(node: &SyntaxNode) -> Option<(SmolStr, SyntaxNodePtr)> {
234 .visit(decl::<ast::StaticDef>) 254 .visit(decl::<ast::StaticDef>)
235 .accept(node)? 255 .accept(node)?
236} 256}
257
258fn to_file_symbol(node: &SyntaxNode, file_id: FileId) -> Option<FileSymbol> {
259 to_symbol(node).map(move |(name, ptr)| FileSymbol { name, ptr, file_id, container_name: None })
260}
diff --git a/crates/ra_ide_api/tests/test/main.rs b/crates/ra_ide_api/tests/test/main.rs
index 7d1695cfd..0526f7584 100644
--- a/crates/ra_ide_api/tests/test/main.rs
+++ b/crates/ra_ide_api/tests/test/main.rs
@@ -1,9 +1,9 @@
1use insta::assert_debug_snapshot_matches; 1use insta::assert_debug_snapshot_matches;
2use ra_ide_api::{ 2use ra_ide_api::{
3 mock_analysis::{single_file, single_file_with_position, MockAnalysis}, 3 mock_analysis::{single_file, single_file_with_position, MockAnalysis},
4 AnalysisChange, CrateGraph, FileId, Query, 4 AnalysisChange, CrateGraph, Edition::Edition2018, FileId, Query, NavigationTarget
5}; 5};
6use ra_syntax::TextRange; 6use ra_syntax::{TextRange, SmolStr};
7 7
8#[test] 8#[test]
9fn test_unresolved_module_diagnostic() { 9fn test_unresolved_module_diagnostic() {
@@ -36,7 +36,7 @@ fn test_resolve_crate_root() {
36 assert!(host.analysis().crate_for(mod_file).unwrap().is_empty()); 36 assert!(host.analysis().crate_for(mod_file).unwrap().is_empty());
37 37
38 let mut crate_graph = CrateGraph::default(); 38 let mut crate_graph = CrateGraph::default();
39 let crate_id = crate_graph.add_crate_root(root_file); 39 let crate_id = crate_graph.add_crate_root(root_file, Edition2018);
40 let mut change = AnalysisChange::new(); 40 let mut change = AnalysisChange::new();
41 change.set_crate_graph(crate_graph); 41 change.set_crate_graph(crate_graph);
42 host.apply_change(change); 42 host.apply_change(change);
@@ -49,6 +49,11 @@ fn get_all_refs(text: &str) -> Vec<(FileId, TextRange)> {
49 analysis.find_all_refs(position).unwrap() 49 analysis.find_all_refs(position).unwrap()
50} 50}
51 51
52fn get_symbols_matching(text: &str, query: &str) -> Vec<NavigationTarget> {
53 let (analysis, _) = single_file(text);
54 analysis.symbol_search(Query::new(query.into())).unwrap()
55}
56
52#[test] 57#[test]
53fn test_find_all_refs_for_local() { 58fn test_find_all_refs_for_local() {
54 let code = r#" 59 let code = r#"
@@ -91,6 +96,49 @@ fn test_find_all_refs_for_fn_param() {
91} 96}
92 97
93#[test] 98#[test]
99fn test_world_symbols_with_no_container() {
100 let code = r#"
101 enum FooInner { }
102 "#;
103
104 let mut symbols = get_symbols_matching(code, "FooInner");
105
106 let s = symbols.pop().unwrap();
107
108 assert_eq!(s.name(), "FooInner");
109 assert!(s.container_name().is_none());
110}
111
112#[test]
113fn test_world_symbols_include_container_name() {
114 let code = r#"
115fn foo() {
116 enum FooInner { }
117}
118 "#;
119
120 let mut symbols = get_symbols_matching(code, "FooInner");
121
122 let s = symbols.pop().unwrap();
123
124 assert_eq!(s.name(), "FooInner");
125 assert_eq!(s.container_name(), Some(&SmolStr::new("foo")));
126
127 let code = r#"
128mod foo {
129 struct FooInner;
130}
131 "#;
132
133 let mut symbols = get_symbols_matching(code, "FooInner");
134
135 let s = symbols.pop().unwrap();
136
137 assert_eq!(s.name(), "FooInner");
138 assert_eq!(s.container_name(), Some(&SmolStr::new("foo")));
139}
140
141#[test]
94#[ignore] 142#[ignore]
95fn world_symbols_include_stuff_from_macros() { 143fn world_symbols_include_stuff_from_macros() {
96 let (analysis, _) = single_file( 144 let (analysis, _) = single_file(
diff --git a/crates/ra_ide_api_light/Cargo.toml b/crates/ra_ide_api_light/Cargo.toml
index 0735e6ae1..29c1f4639 100644
--- a/crates/ra_ide_api_light/Cargo.toml
+++ b/crates/ra_ide_api_light/Cargo.toml
@@ -7,7 +7,7 @@ publish = false
7 7
8[dependencies] 8[dependencies]
9itertools = "0.8.0" 9itertools = "0.8.0"
10superslice = "0.1.0" 10superslice = "1.0.0"
11join_to_string = "0.1.1" 11join_to_string = "0.1.1"
12rustc-hash = "1.0" 12rustc-hash = "1.0"
13 13
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index 0cdb39c32..09d896c40 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -190,7 +190,7 @@ pub fn handle_workspace_symbol(
190 name: nav.name().to_string(), 190 name: nav.name().to_string(),
191 kind: nav.kind().conv(), 191 kind: nav.kind().conv(),
192 location: nav.try_conv_with(world)?, 192 location: nav.try_conv_with(world)?,
193 container_name: None, 193 container_name: nav.container_name().map(|v| v.to_string()),
194 deprecated: None, 194 deprecated: None,
195 }; 195 };
196 res.push(info); 196 res.push(info);
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs
index ec2fd1eb5..cdca3cafb 100644
--- a/crates/ra_mbe/src/lib.rs
+++ b/crates/ra_mbe/src/lib.rs
@@ -109,7 +109,7 @@ mod tests {
109 109
110 use super::*; 110 use super::*;
111 111
112 // Good first issue (although a slightly chellegning one): 112 // Good first issue (although a slightly challenging one):
113 // 113 //
114 // * Pick a random test from here 114 // * Pick a random test from here
115 // https://github.com/intellij-rust/intellij-rust/blob/c4e9feee4ad46e7953b1948c112533360b6087bb/src/test/kotlin/org/rust/lang/core/macros/RsMacroExpansionTest.kt 115 // https://github.com/intellij-rust/intellij-rust/blob/c4e9feee4ad46e7953b1948c112533360b6087bb/src/test/kotlin/org/rust/lang/core/macros/RsMacroExpansionTest.kt
@@ -171,8 +171,8 @@ impl_froms!(TokenTree: Leaf, Subtree);
171 171
172 let (invocation_tt, _) = ast_to_token_tree(macro_invocation.token_tree().unwrap()).unwrap(); 172 let (invocation_tt, _) = ast_to_token_tree(macro_invocation.token_tree().unwrap()).unwrap();
173 173
174 let expaned = rules.expand(&invocation_tt).unwrap(); 174 let expanded = rules.expand(&invocation_tt).unwrap();
175 assert_eq!(expaned.to_string(), expansion); 175 assert_eq!(expanded.to_string(), expansion);
176 } 176 }
177 177
178 #[test] 178 #[test]
diff --git a/crates/ra_mbe/src/mbe_expander.rs b/crates/ra_mbe/src/mbe_expander.rs
index f6177f078..1acba86ea 100644
--- a/crates/ra_mbe/src/mbe_expander.rs
+++ b/crates/ra_mbe/src/mbe_expander.rs
@@ -58,7 +58,7 @@ fn expand_rule(rule: &crate::Rule, input: &tt::Subtree) -> Option<tt::Subtree> {
58/// 58///
59/// The other side of the puzzle is `expand_subtree`, where we use the bindings 59/// The other side of the puzzle is `expand_subtree`, where we use the bindings
60/// to substitute meta variables in the output template. When expanding, we 60/// to substitute meta variables in the output template. When expanding, we
61/// maintain a `nesteing` stack of indicies whihc tells us which occurence from 61/// maintain a `nesting` stack of indices which tells us which occurrence from
62/// the `Bindings` we should take. We push to the stack when we enter a 62/// the `Bindings` we should take. We push to the stack when we enter a
63/// repetition. 63/// repetition.
64/// 64///
diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs
index 8adf463a6..81cb506b7 100644
--- a/crates/ra_project_model/src/cargo_workspace.rs
+++ b/crates/ra_project_model/src/cargo_workspace.rs
@@ -4,6 +4,7 @@ use cargo_metadata::{MetadataCommand, CargoOpt};
4use ra_arena::{Arena, RawId, impl_arena_id}; 4use ra_arena::{Arena, RawId, impl_arena_id};
5use rustc_hash::FxHashMap; 5use rustc_hash::FxHashMap;
6use failure::format_err; 6use failure::format_err;
7use ra_db::Edition;
7 8
8use crate::Result; 9use crate::Result;
9 10
@@ -12,7 +13,7 @@ use crate::Result;
12/// 13///
13/// Note that internally, rust analyzer uses a different structure: 14/// Note that internally, rust analyzer uses a different structure:
14/// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates, 15/// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates,
15/// while this knows about `Pacakges` & `Targets`: purely cargo-related 16/// while this knows about `Packages` & `Targets`: purely cargo-related
16/// concepts. 17/// concepts.
17#[derive(Debug, Clone)] 18#[derive(Debug, Clone)]
18pub struct CargoWorkspace { 19pub struct CargoWorkspace {
@@ -35,6 +36,7 @@ struct PackageData {
35 targets: Vec<Target>, 36 targets: Vec<Target>,
36 is_member: bool, 37 is_member: bool,
37 dependencies: Vec<PackageDependency>, 38 dependencies: Vec<PackageDependency>,
39 edition: Edition,
38} 40}
39 41
40#[derive(Debug, Clone)] 42#[derive(Debug, Clone)]
@@ -84,6 +86,9 @@ impl Package {
84 pub fn root(self, ws: &CargoWorkspace) -> &Path { 86 pub fn root(self, ws: &CargoWorkspace) -> &Path {
85 ws.packages[self].manifest.parent().unwrap() 87 ws.packages[self].manifest.parent().unwrap()
86 } 88 }
89 pub fn edition(self, ws: &CargoWorkspace) -> Edition {
90 ws.packages[self].edition
91 }
87 pub fn targets<'a>(self, ws: &'a CargoWorkspace) -> impl Iterator<Item = Target> + 'a { 92 pub fn targets<'a>(self, ws: &'a CargoWorkspace) -> impl Iterator<Item = Target> + 'a {
88 ws.packages[self].targets.iter().cloned() 93 ws.packages[self].targets.iter().cloned()
89 } 94 }
@@ -135,6 +140,7 @@ impl CargoWorkspace {
135 manifest: meta_pkg.manifest_path.clone(), 140 manifest: meta_pkg.manifest_path.clone(),
136 targets: Vec::new(), 141 targets: Vec::new(),
137 is_member, 142 is_member,
143 edition: Edition::from_string(&meta_pkg.edition),
138 dependencies: Vec::new(), 144 dependencies: Vec::new(),
139 }); 145 });
140 let pkg_data = &mut packages[pkg]; 146 let pkg_data = &mut packages[pkg];
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs
index 3b1e07149..1b18ac836 100644
--- a/crates/ra_project_model/src/lib.rs
+++ b/crates/ra_project_model/src/lib.rs
@@ -6,7 +6,7 @@ use std::path::{Path, PathBuf};
6use failure::bail; 6use failure::bail;
7use rustc_hash::FxHashMap; 7use rustc_hash::FxHashMap;
8 8
9use ra_db::{CrateGraph, FileId}; 9use ra_db::{CrateGraph, FileId, Edition};
10 10
11pub use crate::{ 11pub use crate::{
12 cargo_workspace::{CargoWorkspace, Package, Target, TargetKind}, 12 cargo_workspace::{CargoWorkspace, Package, Target, TargetKind},
@@ -36,7 +36,8 @@ impl ProjectWorkspace {
36 let mut sysroot_crates = FxHashMap::default(); 36 let mut sysroot_crates = FxHashMap::default();
37 for krate in self.sysroot.crates() { 37 for krate in self.sysroot.crates() {
38 if let Some(file_id) = load(krate.root(&self.sysroot)) { 38 if let Some(file_id) = load(krate.root(&self.sysroot)) {
39 sysroot_crates.insert(krate, crate_graph.add_crate_root(file_id)); 39 sysroot_crates
40 .insert(krate, crate_graph.add_crate_root(file_id, Edition::Edition2015));
40 } 41 }
41 } 42 }
42 for from in self.sysroot.crates() { 43 for from in self.sysroot.crates() {
@@ -62,7 +63,8 @@ impl ProjectWorkspace {
62 for tgt in pkg.targets(&self.cargo) { 63 for tgt in pkg.targets(&self.cargo) {
63 let root = tgt.root(&self.cargo); 64 let root = tgt.root(&self.cargo);
64 if let Some(file_id) = load(root) { 65 if let Some(file_id) = load(root) {
65 let crate_id = crate_graph.add_crate_root(file_id); 66 let edition = pkg.edition(&self.cargo);
67 let crate_id = crate_graph.add_crate_root(file_id, edition);
66 if tgt.kind(&self.cargo) == TargetKind::Lib { 68 if tgt.kind(&self.cargo) == TargetKind::Lib {
67 lib_tgt = Some(crate_id); 69 lib_tgt = Some(crate_id);
68 pkg_to_lib_crate.insert(pkg, crate_id); 70 pkg_to_lib_crate.insert(pkg, crate_id);
diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs
index cf5cfecc2..22105d6c9 100644
--- a/crates/ra_syntax/src/ast.rs
+++ b/crates/ra_syntax/src/ast.rs
@@ -6,7 +6,7 @@ use itertools::Itertools;
6 6
7pub use self::generated::*; 7pub use self::generated::*;
8use crate::{ 8use crate::{
9 yellow::{SyntaxNode, SyntaxNodeChildren, TreeArc, RaTypes}, 9 syntax_node::{SyntaxNode, SyntaxNodeChildren, TreeArc, RaTypes},
10 SmolStr, 10 SmolStr,
11 SyntaxKind::*, 11 SyntaxKind::*,
12}; 12};
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index d2b080743..7c5e8ce5e 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -13,7 +13,7 @@ use rowan::TransparentNewType;
13 13
14use crate::{ 14use crate::{
15 SyntaxNode, SyntaxKind::*, 15 SyntaxNode, SyntaxKind::*,
16 yellow::{RaTypes, TreeArc}, 16 syntax_node::{RaTypes, TreeArc},
17 ast::{self, AstNode}, 17 ast::{self, AstNode},
18}; 18};
19 19
@@ -4210,6 +4210,7 @@ impl ToOwned for UseItem {
4210} 4210}
4211 4211
4212 4212
4213impl ast::AttrsOwner for UseItem {}
4213impl UseItem { 4214impl UseItem {
4214 pub fn use_tree(&self) -> Option<&UseTree> { 4215 pub fn use_tree(&self) -> Option<&UseTree> {
4215 super::child_opt(self) 4216 super::child_opt(self)
diff --git a/crates/ra_syntax/src/ast/generated.rs.tera b/crates/ra_syntax/src/ast/generated.rs.tera
index ea0fc35fd..ca7a28581 100644
--- a/crates/ra_syntax/src/ast/generated.rs.tera
+++ b/crates/ra_syntax/src/ast/generated.rs.tera
@@ -15,7 +15,7 @@ use rowan::TransparentNewType;
15 15
16use crate::{ 16use crate::{
17 SyntaxNode, SyntaxKind::*, 17 SyntaxNode, SyntaxKind::*,
18 yellow::{RaTypes, TreeArc}, 18 syntax_node::{RaTypes, TreeArc},
19 ast::{self, AstNode}, 19 ast::{self, AstNode},
20}; 20};
21{% for node, methods in ast %} 21{% for node, methods in ast %}
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron
index 2e4b2d776..304bc5909 100644
--- a/crates/ra_syntax/src/grammar.ron
+++ b/crates/ra_syntax/src/grammar.ron
@@ -596,7 +596,8 @@ Grammar(
596 options: [ "Pat", "TypeRef" ], 596 options: [ "Pat", "TypeRef" ],
597 ), 597 ),
598 "UseItem": ( 598 "UseItem": (
599 options: [ "UseTree" ] 599 traits: ["AttrsOwner"],
600 options: [ "UseTree" ],
600 ), 601 ),
601 "UseTree": ( 602 "UseTree": (
602 options: [ "Path", "UseTreeList", "Alias" ] 603 options: [ "Path", "UseTreeList", "Alias" ]
diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs
index 088b2f5d7..cbba1d4ae 100644
--- a/crates/ra_syntax/src/lib.rs
+++ b/crates/ra_syntax/src/lib.rs
@@ -30,7 +30,7 @@ mod syntax_kinds;
30/// Utilities for simple uses of the parser. 30/// Utilities for simple uses of the parser.
31pub mod utils; 31pub mod utils;
32mod validation; 32mod validation;
33mod yellow; 33mod syntax_node;
34mod ptr; 34mod ptr;
35 35
36pub use rowan::{SmolStr, TextRange, TextUnit}; 36pub use rowan::{SmolStr, TextRange, TextUnit};
@@ -38,12 +38,12 @@ pub use crate::{
38 ast::AstNode, 38 ast::AstNode,
39 lexer::{tokenize, Token}, 39 lexer::{tokenize, Token},
40 syntax_kinds::SyntaxKind, 40 syntax_kinds::SyntaxKind,
41 yellow::{Direction, SyntaxError, SyntaxNode, WalkEvent, Location, TreeArc}, 41 syntax_node::{Direction, SyntaxError, SyntaxNode, WalkEvent, Location, TreeArc},
42 ptr::{SyntaxNodePtr, AstPtr}, 42 ptr::{SyntaxNodePtr, AstPtr},
43}; 43};
44 44
45use ra_text_edit::AtomTextEdit; 45use ra_text_edit::AtomTextEdit;
46use crate::yellow::GreenNode; 46use crate::syntax_node::GreenNode;
47 47
48/// `SourceFile` represents a parse tree for a single Rust file. 48/// `SourceFile` represents a parse tree for a single Rust file.
49pub use crate::ast::SourceFile; 49pub use crate::ast::SourceFile;
@@ -61,7 +61,7 @@ impl SourceFile {
61 pub fn parse(text: &str) -> TreeArc<SourceFile> { 61 pub fn parse(text: &str) -> TreeArc<SourceFile> {
62 let tokens = tokenize(&text); 62 let tokens = tokenize(&text);
63 let (green, errors) = 63 let (green, errors) =
64 parser_impl::parse_with(yellow::GreenBuilder::new(), text, &tokens, grammar::root); 64 parser_impl::parse_with(syntax_node::GreenBuilder::new(), text, &tokens, grammar::root);
65 SourceFile::new(green, errors) 65 SourceFile::new(green, errors)
66 } 66 }
67 67
diff --git a/crates/ra_syntax/src/parser_impl.rs b/crates/ra_syntax/src/parser_impl.rs
index f255dc23b..d99615d72 100644
--- a/crates/ra_syntax/src/parser_impl.rs
+++ b/crates/ra_syntax/src/parser_impl.rs
@@ -11,7 +11,7 @@ use crate::{
11 input::{InputPosition, ParserInput}, 11 input::{InputPosition, ParserInput},
12 }, 12 },
13 SmolStr, 13 SmolStr,
14 yellow::syntax_error::{ 14 syntax_node::syntax_error::{
15 ParseError, 15 ParseError,
16 SyntaxError, 16 SyntaxError,
17 }, 17 },
diff --git a/crates/ra_syntax/src/parser_impl/event.rs b/crates/ra_syntax/src/parser_impl/event.rs
index 677876ab5..b45830c61 100644
--- a/crates/ra_syntax/src/parser_impl/event.rs
+++ b/crates/ra_syntax/src/parser_impl/event.rs
@@ -13,7 +13,7 @@ use crate::{
13 SmolStr, 13 SmolStr,
14 SyntaxKind::{self, *}, 14 SyntaxKind::{self, *},
15 TextRange, TextUnit, 15 TextRange, TextUnit,
16 yellow::syntax_error::{ 16 syntax_node::syntax_error::{
17 ParseError, 17 ParseError,
18 SyntaxError, 18 SyntaxError,
19 SyntaxErrorKind, 19 SyntaxErrorKind,
diff --git a/crates/ra_syntax/src/reparsing.rs b/crates/ra_syntax/src/reparsing.rs
index c5c609ad5..dd751465c 100644
--- a/crates/ra_syntax/src/reparsing.rs
+++ b/crates/ra_syntax/src/reparsing.rs
@@ -3,7 +3,7 @@ use crate::grammar;
3use crate::lexer::{tokenize, Token}; 3use crate::lexer::{tokenize, Token};
4use crate::parser_api::Parser; 4use crate::parser_api::Parser;
5use crate::parser_impl; 5use crate::parser_impl;
6use crate::yellow::{self, GreenNode, SyntaxError, SyntaxNode}; 6use crate::syntax_node::{self, GreenNode, SyntaxError, SyntaxNode};
7use crate::{SyntaxKind::*, TextRange, TextUnit}; 7use crate::{SyntaxKind::*, TextRange, TextUnit};
8use ra_text_edit::AtomTextEdit; 8use ra_text_edit::AtomTextEdit;
9 9
@@ -56,7 +56,7 @@ fn reparse_block<'node>(
56 return None; 56 return None;
57 } 57 }
58 let (green, new_errors) = 58 let (green, new_errors) =
59 parser_impl::parse_with(yellow::GreenBuilder::new(), &text, &tokens, reparser); 59 parser_impl::parse_with(syntax_node::GreenBuilder::new(), &text, &tokens, reparser);
60 Some((node, green, new_errors)) 60 Some((node, green, new_errors))
61} 61}
62 62
diff --git a/crates/ra_syntax/src/yellow.rs b/crates/ra_syntax/src/syntax_node.rs
index ed48739f8..ed48739f8 100644
--- a/crates/ra_syntax/src/yellow.rs
+++ b/crates/ra_syntax/src/syntax_node.rs
diff --git a/crates/ra_syntax/src/yellow/builder.rs b/crates/ra_syntax/src/syntax_node/builder.rs
index e8b9112d4..8abd0f051 100644
--- a/crates/ra_syntax/src/yellow/builder.rs
+++ b/crates/ra_syntax/src/syntax_node/builder.rs
@@ -1,6 +1,6 @@
1use crate::{ 1use crate::{
2 parser_impl::Sink, 2 parser_impl::Sink,
3 yellow::{GreenNode, RaTypes, SyntaxError}, 3 syntax_node::{GreenNode, RaTypes, SyntaxError},
4 SmolStr, SyntaxKind, 4 SmolStr, SyntaxKind,
5}; 5};
6use rowan::GreenNodeBuilder; 6use rowan::GreenNodeBuilder;
diff --git a/crates/ra_syntax/src/yellow/syntax_error.rs b/crates/ra_syntax/src/syntax_node/syntax_error.rs
index 412cf82cc..412cf82cc 100644
--- a/crates/ra_syntax/src/yellow/syntax_error.rs
+++ b/crates/ra_syntax/src/syntax_node/syntax_error.rs
diff --git a/crates/ra_syntax/src/yellow/syntax_text.rs b/crates/ra_syntax/src/syntax_node/syntax_text.rs
index 84e5b231a..84e5b231a 100644
--- a/crates/ra_syntax/src/yellow/syntax_text.rs
+++ b/crates/ra_syntax/src/syntax_node/syntax_text.rs
diff --git a/crates/ra_syntax/src/validation.rs b/crates/ra_syntax/src/validation.rs
index ac6cc3dd6..10672d6bf 100644
--- a/crates/ra_syntax/src/validation.rs
+++ b/crates/ra_syntax/src/validation.rs
@@ -5,7 +5,7 @@ mod string;
5mod block; 5mod block;
6 6
7use crate::{ 7use crate::{
8 SourceFile, yellow::SyntaxError, AstNode, 8 SourceFile, syntax_node::SyntaxError, AstNode,
9 ast, 9 ast,
10 algo::visit::{visitor_ctx, VisitorCtx}, 10 algo::visit::{visitor_ctx, VisitorCtx},
11}; 11};
diff --git a/crates/ra_syntax/src/validation/block.rs b/crates/ra_syntax/src/validation/block.rs
index 4e77c15b6..de949d967 100644
--- a/crates/ra_syntax/src/validation/block.rs
+++ b/crates/ra_syntax/src/validation/block.rs
@@ -1,6 +1,6 @@
1use crate::{SyntaxKind::*, 1use crate::{SyntaxKind::*,
2 ast::{self, AttrsOwner, AstNode}, 2 ast::{self, AttrsOwner, AstNode},
3 yellow::{ 3 syntax_node::{
4 SyntaxError, 4 SyntaxError,
5 SyntaxErrorKind::*, 5 SyntaxErrorKind::*,
6 }, 6 },
diff --git a/crates/ra_syntax/src/validation/byte.rs b/crates/ra_syntax/src/validation/byte.rs
index d51fabcf9..acdc12552 100644
--- a/crates/ra_syntax/src/validation/byte.rs
+++ b/crates/ra_syntax/src/validation/byte.rs
@@ -5,7 +5,7 @@ use crate::{
5 string_lexing::{self, StringComponentKind}, 5 string_lexing::{self, StringComponentKind},
6 TextRange, 6 TextRange,
7 validation::char, 7 validation::char,
8 yellow::{ 8 syntax_node::{
9 SyntaxError, 9 SyntaxError,
10 SyntaxErrorKind::*, 10 SyntaxErrorKind::*,
11 }, 11 },
diff --git a/crates/ra_syntax/src/validation/byte_string.rs b/crates/ra_syntax/src/validation/byte_string.rs
index 7abe8f330..69a98b640 100644
--- a/crates/ra_syntax/src/validation/byte_string.rs
+++ b/crates/ra_syntax/src/validation/byte_string.rs
@@ -1,7 +1,7 @@
1use crate::{ 1use crate::{
2 ast::{self, AstNode, AstToken}, 2 ast::{self, AstNode, AstToken},
3 string_lexing::{self, StringComponentKind}, 3 string_lexing::{self, StringComponentKind},
4 yellow::{ 4 syntax_node::{
5 SyntaxError, 5 SyntaxError,
6 SyntaxErrorKind::*, 6 SyntaxErrorKind::*,
7 }, 7 },
diff --git a/crates/ra_syntax/src/validation/char.rs b/crates/ra_syntax/src/validation/char.rs
index 012594db3..26c15e36d 100644
--- a/crates/ra_syntax/src/validation/char.rs
+++ b/crates/ra_syntax/src/validation/char.rs
@@ -8,7 +8,7 @@ use crate::{
8 ast::{self, AstNode, AstToken}, 8 ast::{self, AstNode, AstToken},
9 string_lexing::{self, StringComponentKind}, 9 string_lexing::{self, StringComponentKind},
10 TextRange, 10 TextRange,
11 yellow::{ 11 syntax_node::{
12 SyntaxError, 12 SyntaxError,
13 SyntaxErrorKind::*, 13 SyntaxErrorKind::*,
14 }, 14 },
diff --git a/crates/ra_syntax/src/validation/string.rs b/crates/ra_syntax/src/validation/string.rs
index 4fd7fffdf..2f7f9c7c4 100644
--- a/crates/ra_syntax/src/validation/string.rs
+++ b/crates/ra_syntax/src/validation/string.rs
@@ -1,7 +1,7 @@
1use crate::{ 1use crate::{
2 ast::{self, AstNode, AstToken}, 2 ast::{self, AstNode, AstToken},
3 string_lexing, 3 string_lexing,
4 yellow::{ 4 syntax_node::{
5 SyntaxError, 5 SyntaxError,
6 SyntaxErrorKind::*, 6 SyntaxErrorKind::*,
7 }, 7 },
diff --git a/crates/ra_syntax/tests/data/parser/fuzz-failures/0000.rs b/crates/ra_syntax/tests/data/parser/fuzz-failures/0000.rs
index 59cd11495..e0437d163 100644
--- a/crates/ra_syntax/tests/data/parser/fuzz-failures/0000.rs
+++ b/crates/ra_syntax/tests/data/parser/fuzz-failures/0000.rs
@@ -5,7 +5,7 @@
5 } 5 }
6 pub fn parse(text: &str) -> File { 6 pub fn parse(text: &str) -> File {
7 let tokens = tokenize(&text); 7 let tokens = tokenize(&text);
8 let (green, errors) = parser_impl::parse_with::<yellow::GreenBuilder>( 8 let (green, errors) = parser_impl::parse_with::<syntax_node::GreenBuilder>(
9 text, &tokens, grammar::root, 9 text, &tokens, grammar::root,
10 ); 10 );
11 File::new(green, errors) 11 File::new(green, errors)
@@ -24,7 +24,7 @@
24 if !is_balanced(&tokens) { 24 if !is_balanced(&tokens) {
25 return None; 25 return None;
26 } 26 }
27 let (green, new_errors) = parser_impl::parse_with::<yellow::GreenBuilder>( 27 let (green, new_errors) = parser_impl::parse_with::<syntax_node::GreenBuilder>(
28 &te2t, &tokens, reparser, 28 &te2t, &tokens, reparser,
29 ); 29 );
30 let green_root = node.replace_with(green); 30 let green_root = node.replace_with(green);
diff --git a/crates/ra_tt/src/lib.rs b/crates/ra_tt/src/lib.rs
index c1f37b889..0b0b9b4d2 100644
--- a/crates/ra_tt/src/lib.rs
+++ b/crates/ra_tt/src/lib.rs
@@ -33,14 +33,14 @@ impl TokenId {
33 } 33 }
34} 34}
35 35
36#[derive(Debug, Clone)] 36#[derive(Debug, Clone, PartialEq, Eq)]
37pub enum TokenTree { 37pub enum TokenTree {
38 Leaf(Leaf), 38 Leaf(Leaf),
39 Subtree(Subtree), 39 Subtree(Subtree),
40} 40}
41impl_froms!(TokenTree: Leaf, Subtree); 41impl_froms!(TokenTree: Leaf, Subtree);
42 42
43#[derive(Debug, Clone)] 43#[derive(Debug, Clone, PartialEq, Eq)]
44pub enum Leaf { 44pub enum Leaf {
45 Literal(Literal), 45 Literal(Literal),
46 Punct(Punct), 46 Punct(Punct),
@@ -48,7 +48,7 @@ pub enum Leaf {
48} 48}
49impl_froms!(Leaf: Literal, Punct, Ident); 49impl_froms!(Leaf: Literal, Punct, Ident);
50 50
51#[derive(Debug, Clone)] 51#[derive(Debug, Clone, PartialEq, Eq)]
52pub struct Subtree { 52pub struct Subtree {
53 pub delimiter: Delimiter, 53 pub delimiter: Delimiter,
54 pub token_trees: Vec<TokenTree>, 54 pub token_trees: Vec<TokenTree>,
@@ -62,7 +62,7 @@ pub enum Delimiter {
62 None, 62 None,
63} 63}
64 64
65#[derive(Debug, Clone)] 65#[derive(Debug, Clone, PartialEq, Eq)]
66pub struct Literal { 66pub struct Literal {
67 pub text: SmolStr, 67 pub text: SmolStr,
68} 68}
@@ -79,7 +79,7 @@ pub enum Spacing {
79 Joint, 79 Joint,
80} 80}
81 81
82#[derive(Debug, Clone)] 82#[derive(Debug, Clone, PartialEq, Eq)]
83pub struct Ident { 83pub struct Ident {
84 pub text: SmolStr, 84 pub text: SmolStr,
85 pub id: TokenId, 85 pub id: TokenId,
diff --git a/crates/ra_vfs/src/io.rs b/crates/ra_vfs/src/io.rs
index dc0b84d5a..3952b200b 100644
--- a/crates/ra_vfs/src/io.rs
+++ b/crates/ra_vfs/src/io.rs
@@ -169,7 +169,7 @@ fn convert_notify_event(event: DebouncedEvent, sender: &Sender<(PathBuf, ChangeK
169 // ignore 169 // ignore
170 } 170 }
171 DebouncedEvent::Rescan => { 171 DebouncedEvent::Rescan => {
172 // TODO rescan all roots 172 // TODO: rescan all roots
173 } 173 }
174 DebouncedEvent::Create(path) => { 174 DebouncedEvent::Create(path) => {
175 sender.send((path, ChangeKind::Create)).unwrap(); 175 sender.send((path, ChangeKind::Create)).unwrap();
@@ -185,7 +185,7 @@ fn convert_notify_event(event: DebouncedEvent, sender: &Sender<(PathBuf, ChangeK
185 sender.send((dst, ChangeKind::Create)).unwrap(); 185 sender.send((dst, ChangeKind::Create)).unwrap();
186 } 186 }
187 DebouncedEvent::Error(err, path) => { 187 DebouncedEvent::Error(err, path) => {
188 // TODO should we reload the file contents? 188 // TODO: should we reload the file contents?
189 log::warn!("watcher error \"{}\", {:?}", err, path); 189 log::warn!("watcher error \"{}\", {:?}", err, path);
190 } 190 }
191 } 191 }
diff --git a/crates/ra_vfs/src/lib.rs b/crates/ra_vfs/src/lib.rs
index d589a254b..f07657db6 100644
--- a/crates/ra_vfs/src/lib.rs
+++ b/crates/ra_vfs/src/lib.rs
@@ -7,8 +7,10 @@
7//! 7//!
8//! It is also responsible for watching the disk for changes, and for merging 8//! It is also responsible for watching the disk for changes, and for merging
9//! editor state (modified, unsaved files) with disk state. 9//! editor state (modified, unsaved files) with disk state.
10//! TODO: Some LSP clients support watching the disk, so this crate should 10//!
11//! to support custom watcher events (related to https://github.com/rust-analyzer/rust-analyzer/issues/131) 11//! TODO: Some LSP clients support watching the disk, so this crate should to
12//! support custom watcher events (related to
13//! <https://github.com/rust-analyzer/rust-analyzer/issues/131>)
12//! 14//!
13//! VFS is based on a concept of roots: a set of directories on the file system 15//! VFS is based on a concept of roots: a set of directories on the file system
14//! which are watched for changes. Typically, there will be a root for each 16//! which are watched for changes. Typically, there will be a root for each
@@ -225,12 +227,12 @@ impl Vfs {
225 let mut cur_files = Vec::new(); 227 let mut cur_files = Vec::new();
226 // While we were scanning the root in the background, a file might have 228 // While we were scanning the root in the background, a file might have
227 // been open in the editor, so we need to account for that. 229 // been open in the editor, so we need to account for that.
228 let exising = self.root2files[root] 230 let existing = self.root2files[root]
229 .iter() 231 .iter()
230 .map(|&file| (self.files[file].path.clone(), file)) 232 .map(|&file| (self.files[file].path.clone(), file))
231 .collect::<FxHashMap<_, _>>(); 233 .collect::<FxHashMap<_, _>>();
232 for (path, text) in files { 234 for (path, text) in files {
233 if let Some(&file) = exising.get(&path) { 235 if let Some(&file) = existing.get(&path) {
234 let text = Arc::clone(&self.files[file].text); 236 let text = Arc::clone(&self.files[file].text);
235 cur_files.push((file, path, text)); 237 cur_files.push((file, path, text));
236 continue; 238 continue;
@@ -335,7 +337,7 @@ impl Vfs {
335 mem::replace(&mut self.pending_changes, Vec::new()) 337 mem::replace(&mut self.pending_changes, Vec::new())
336 } 338 }
337 339
338 /// Sutdown the VFS and terminate the background watching thread. 340 /// Shutdown the VFS and terminate the background watching thread.
339 pub fn shutdown(self) -> thread::Result<()> { 341 pub fn shutdown(self) -> thread::Result<()> {
340 self.worker.shutdown() 342 self.worker.shutdown()
341 } 343 }
@@ -360,7 +362,7 @@ impl Vfs {
360 } 362 }
361 363
362 fn remove_file(&mut self, file: VfsFile) { 364 fn remove_file(&mut self, file: VfsFile) {
363 //FIXME: use arena with removal 365 // FIXME: use arena with removal
364 self.files[file].text = Default::default(); 366 self.files[file].text = Default::default();
365 self.files[file].path = Default::default(); 367 self.files[file].path = Default::default();
366 let root = self.files[file].root; 368 let root = self.files[file].root;
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs
index 09fc2e659..4d83af00c 100644
--- a/crates/test_utils/src/lib.rs
+++ b/crates/test_utils/src/lib.rs
@@ -113,9 +113,9 @@ pub struct FixtureEntry {
113 pub text: String, 113 pub text: String,
114} 114}
115 115
116/// Parses text wich looks like this: 116/// Parses text which looks like this:
117/// 117///
118/// ```notrust 118/// ```rust,ignore
119/// //- some meta 119/// //- some meta
120/// line 1 120/// line 1
121/// line 2 121/// line 2
diff --git a/crates/test_utils/src/marks.rs b/crates/test_utils/src/marks.rs
index d2a84643c..107432926 100644
--- a/crates/test_utils/src/marks.rs
+++ b/crates/test_utils/src/marks.rs
@@ -1,10 +1,10 @@
1//! This module implements manually tracked test coverage, which useful for 1//! This module implements manually tracked test coverage, which useful for
2//! quickly finding a test responsible for testing a particular bit of code. 2//! quickly finding a test responsible for testing a particular bit of code.
3//! 3//!
4//! See https://matklad.github.io/2018/06/18/a-trick-for-test-maintenance.html 4//! See <https://matklad.github.io/2018/06/18/a-trick-for-test-maintenance.html>
5//! for details, but the TL;DR is that you write your test as 5//! for details, but the TL;DR is that you write your test as
6//! 6//!
7//! ```no-run 7//! ```rust,no_run
8//! #[test] 8//! #[test]
9//! fn test_foo() { 9//! fn test_foo() {
10//! covers!(test_foo); 10//! covers!(test_foo);
@@ -13,7 +13,9 @@
13//! 13//!
14//! and in the code under test you write 14//! and in the code under test you write
15//! 15//!
16//! ```no-run 16//! ```rust,no_run
17//! # use test_utils::tested_by;
18//! # fn some_condition() -> bool { true }
17//! fn foo() { 19//! fn foo() {
18//! if some_condition() { 20//! if some_condition() {
19//! tested_by!(test_foo); 21//! tested_by!(test_foo);
diff --git a/crates/thread_worker/src/lib.rs b/crates/thread_worker/src/lib.rs
index ca0aad136..a522a0843 100644
--- a/crates/thread_worker/src/lib.rs
+++ b/crates/thread_worker/src/lib.rs
@@ -65,7 +65,7 @@ impl WorkerHandle {
65 } 65 }
66} 66}
67 67
68/// Sets up worker channels in a deadlock-avoind way. 68/// Sets up worker channels in a deadlock-avoiding way.
69/// If one sets both input and output buffers to a fixed size, 69/// If one sets both input and output buffers to a fixed size,
70/// a worker might get stuck. 70/// a worker might get stuck.
71fn worker_chan<I, O>(buf: usize) -> (Worker<I, O>, Receiver<I>, Sender<O>) { 71fn worker_chan<I, O>(buf: usize) -> (Worker<I, O>, Receiver<I>, Sender<O>) {