aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarco Groppo <[email protected]>2019-03-26 19:26:16 +0000
committerMarco Groppo <[email protected]>2019-03-26 19:26:16 +0000
commit6030d6f500e42bde012a391666b68363d8479d21 (patch)
tree42c799a75b1803afe1838818de86cebe9674c38a
parent12b5d4f795f69f7fa07051cdec7a1347d3aa7924 (diff)
parent1011e37f3a260b0565f88c84d3c49fac1ec7b879 (diff)
Merge branch 'master' of github.com:rust-analyzer/rust-analyzer into flip-binexpr
-rw-r--r--Cargo.lock8
-rw-r--r--README.md6
-rw-r--r--crates/ra_hir/src/code_model_api.rs17
-rw-r--r--crates/ra_hir/src/code_model_impl/module.rs20
-rw-r--r--crates/ra_hir/src/db.rs31
-rw-r--r--crates/ra_hir/src/ids.rs197
-rw-r--r--crates/ra_hir/src/lib.rs7
-rw-r--r--crates/ra_hir/src/nameres.rs54
-rw-r--r--crates/ra_hir/src/nameres/collector.rs140
-rw-r--r--crates/ra_hir/src/nameres/raw.rs143
-rw-r--r--crates/ra_hir/src/nameres/tests/incremental.rs46
-rw-r--r--crates/ra_hir/src/resolve.rs17
-rw-r--r--crates/ra_hir/src/source_binder.rs10
-rw-r--r--crates/ra_hir/src/source_id.rs150
-rw-r--r--crates/ra_hir/src/traits.rs52
-rw-r--r--crates/ra_hir/src/ty.rs23
-rw-r--r--crates/ra_hir/src/ty/infer.rs3
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs95
-rw-r--r--crates/ra_hir/src/ty/tests.rs12
-rw-r--r--crates/ra_ide_api/src/change.rs4
-rw-r--r--crates/ra_ide_api/src/parent_module.rs30
-rw-r--r--crates/ra_ide_api/src/references.rs48
-rw-r--r--crates/ra_ide_api/src/symbol_index.rs58
-rw-r--r--crates/ra_ide_api/src/syntax_tree.rs257
-rw-r--r--crates/ra_ide_api/tests/test/main.rs376
-rw-r--r--crates/ra_syntax/src/ast/generated.rs6
-rw-r--r--crates/ra_syntax/src/grammar.ron5
-rw-r--r--docs/user/features.md19
28 files changed, 1017 insertions, 817 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 3bc5f261c..00f2338c9 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -913,7 +913,7 @@ dependencies = [
913 "ra_hir 0.1.0", 913 "ra_hir 0.1.0",
914 "ra_project_model 0.1.0", 914 "ra_project_model 0.1.0",
915 "ra_syntax 0.1.0", 915 "ra_syntax 0.1.0",
916 "ra_vfs 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 916 "ra_vfs 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
917 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 917 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
918 "test_utils 0.1.0", 918 "test_utils 0.1.0",
919] 919]
@@ -1021,7 +1021,7 @@ dependencies = [
1021 "ra_project_model 0.1.0", 1021 "ra_project_model 0.1.0",
1022 "ra_syntax 0.1.0", 1022 "ra_syntax 0.1.0",
1023 "ra_text_edit 0.1.0", 1023 "ra_text_edit 0.1.0",
1024 "ra_vfs 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 1024 "ra_vfs 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
1025 "relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 1025 "relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
1026 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1026 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
1027 "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", 1027 "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1103,7 +1103,7 @@ dependencies = [
1103 1103
1104[[package]] 1104[[package]]
1105name = "ra_vfs" 1105name = "ra_vfs"
1106version = "0.2.0" 1106version = "0.2.1"
1107source = "registry+https://github.com/rust-lang/crates.io-index" 1107source = "registry+https://github.com/rust-lang/crates.io-index"
1108dependencies = [ 1108dependencies = [
1109 "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 1109 "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1943,7 +1943,7 @@ dependencies = [
1943"checksum proptest 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24f5844db2f839e97e3021980975f6ebf8691d9b9b2ca67ed3feb38dc3edb52c" 1943"checksum proptest 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24f5844db2f839e97e3021980975f6ebf8691d9b9b2ca67ed3feb38dc3edb52c"
1944"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" 1944"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
1945"checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1" 1945"checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1"
1946"checksum ra_vfs 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1839e4e003d865b58b8b6c231aae6c463dfcd01bfbbddffbdb7662a7b5a627" 1946"checksum ra_vfs 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d75d08da053ec832676686c72dfe509fdd1e807191a50ac79087466ffefccb1c"
1947"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" 1947"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
1948"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" 1948"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
1949"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" 1949"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
diff --git a/README.md b/README.md
index 3a0c9dee1..8df991246 100644
--- a/README.md
+++ b/README.md
@@ -51,6 +51,12 @@ We are on the rust-lang Zulip!
51 51
52https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frls-2.2E0 52https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frls-2.2E0
53 53
54## Quick Links
55
56* Work List: https://paper.dropbox.com/doc/RLS-2.0-work-list--AZ3BgHKKCtqszbsi3gi6sjchAQ-42vbnxzuKq2lKwW0mkn8Y
57* API docs: https://rust-analyzer.github.io/rust-analyzer/ra_ide_api/index.html
58* CI: https://travis-ci.org/rust-analyzer/rust-analyzer
59
54## License 60## License
55 61
56Rust analyzer is primarily distributed under the terms of both the MIT 62Rust analyzer is primarily distributed under the terms of both the MIT
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs
index 5437133b8..624c25c4d 100644
--- a/crates/ra_hir/src/code_model_api.rs
+++ b/crates/ra_hir/src/code_model_api.rs
@@ -13,10 +13,11 @@ use crate::{
13 adt::{EnumVariantId, StructFieldId, VariantDef}, 13 adt::{EnumVariantId, StructFieldId, VariantDef},
14 generics::GenericParams, 14 generics::GenericParams,
15 docs::{Documentation, Docs, docs_from_ast}, 15 docs::{Documentation, Docs, docs_from_ast},
16 ids::{FunctionId, StructId, EnumId, AstItemDef, ConstId, StaticId, TraitId, TypeId}, 16 ids::{FunctionId, StructId, EnumId, AstItemDef, ConstId, StaticId, TraitId, TypeAliasId},
17 impl_block::ImplBlock, 17 impl_block::ImplBlock,
18 resolve::Resolver, 18 resolve::Resolver,
19 diagnostics::DiagnosticSink, 19 diagnostics::DiagnosticSink,
20 traits::{TraitItem, TraitData},
20}; 21};
21 22
22/// hir::Crate describes a single crate. It's the main interface with which 23/// hir::Crate describes a single crate. It's the main interface with which
@@ -649,6 +650,18 @@ impl Trait {
649 pub fn generic_params(&self, db: &impl DefDatabase) -> Arc<GenericParams> { 650 pub fn generic_params(&self, db: &impl DefDatabase) -> Arc<GenericParams> {
650 db.generic_params((*self).into()) 651 db.generic_params((*self).into())
651 } 652 }
653
654 pub fn name(self, db: &impl DefDatabase) -> Option<Name> {
655 self.trait_data(db).name().clone()
656 }
657
658 pub fn items(self, db: &impl DefDatabase) -> Vec<TraitItem> {
659 self.trait_data(db).items().to_vec()
660 }
661
662 pub(crate) fn trait_data(self, db: &impl DefDatabase) -> Arc<TraitData> {
663 db.trait_data(self)
664 }
652} 665}
653 666
654impl Docs for Trait { 667impl Docs for Trait {
@@ -659,7 +672,7 @@ impl Docs for Trait {
659 672
660#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 673#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
661pub struct TypeAlias { 674pub struct TypeAlias {
662 pub(crate) id: TypeId, 675 pub(crate) id: TypeAliasId,
663} 676}
664 677
665impl TypeAlias { 678impl TypeAlias {
diff --git a/crates/ra_hir/src/code_model_impl/module.rs b/crates/ra_hir/src/code_model_impl/module.rs
index 14237060c..0edb8ade5 100644
--- a/crates/ra_hir/src/code_model_impl/module.rs
+++ b/crates/ra_hir/src/code_model_impl/module.rs
@@ -1,18 +1,18 @@
1use ra_db::FileId; 1use ra_db::FileId;
2use ra_syntax::{ast, TreeArc, AstNode}; 2use ra_syntax::{ast, TreeArc};
3 3
4use crate::{ 4use crate::{
5 Module, ModuleSource, Name, 5 Module, ModuleSource, Name, AstId,
6 nameres::{CrateModuleId, ImportId}, 6 nameres::{CrateModuleId, ImportId},
7 HirDatabase, DefDatabase, 7 HirDatabase, DefDatabase,
8 HirFileId, SourceItemId, 8 HirFileId,
9}; 9};
10 10
11impl ModuleSource { 11impl ModuleSource {
12 pub(crate) fn new( 12 pub(crate) fn new(
13 db: &impl DefDatabase, 13 db: &impl DefDatabase,
14 file_id: Option<FileId>, 14 file_id: Option<FileId>,
15 decl_id: Option<SourceItemId>, 15 decl_id: Option<AstId<ast::Module>>,
16 ) -> ModuleSource { 16 ) -> ModuleSource {
17 match (file_id, decl_id) { 17 match (file_id, decl_id) {
18 (Some(file_id), _) => { 18 (Some(file_id), _) => {
@@ -20,8 +20,7 @@ impl ModuleSource {
20 ModuleSource::SourceFile(source_file) 20 ModuleSource::SourceFile(source_file)
21 } 21 }
22 (None, Some(item_id)) => { 22 (None, Some(item_id)) => {
23 let module = db.file_item(item_id); 23 let module = item_id.to_node(db);
24 let module = ast::Module::cast(&*module).unwrap();
25 assert!(module.item_list().is_some(), "expected inline module"); 24 assert!(module.item_list().is_some(), "expected inline module");
26 ModuleSource::Module(module.to_owned()) 25 ModuleSource::Module(module.to_owned())
27 } 26 }
@@ -55,7 +54,7 @@ impl Module {
55 let decl_id = def_map[self.module_id].declaration; 54 let decl_id = def_map[self.module_id].declaration;
56 let file_id = def_map[self.module_id].definition; 55 let file_id = def_map[self.module_id].definition;
57 let module_source = ModuleSource::new(db, file_id, decl_id); 56 let module_source = ModuleSource::new(db, file_id, decl_id);
58 let file_id = file_id.map(HirFileId::from).unwrap_or_else(|| decl_id.unwrap().file_id); 57 let file_id = file_id.map(HirFileId::from).unwrap_or_else(|| decl_id.unwrap().file_id());
59 (file_id, module_source) 58 (file_id, module_source)
60 } 59 }
61 60
@@ -65,9 +64,8 @@ impl Module {
65 ) -> Option<(HirFileId, TreeArc<ast::Module>)> { 64 ) -> Option<(HirFileId, TreeArc<ast::Module>)> {
66 let def_map = db.crate_def_map(self.krate); 65 let def_map = db.crate_def_map(self.krate);
67 let decl = def_map[self.module_id].declaration?; 66 let decl = def_map[self.module_id].declaration?;
68 let syntax_node = db.file_item(decl); 67 let ast = decl.to_node(db);
69 let ast = ast::Module::cast(&syntax_node).unwrap().to_owned(); 68 Some((decl.file_id(), ast))
70 Some((decl.file_id, ast))
71 } 69 }
72 70
73 pub(crate) fn import_source_impl( 71 pub(crate) fn import_source_impl(
@@ -76,7 +74,7 @@ impl Module {
76 import: ImportId, 74 import: ImportId,
77 ) -> TreeArc<ast::PathSegment> { 75 ) -> TreeArc<ast::PathSegment> {
78 let (file_id, source) = self.definition_source(db); 76 let (file_id, source) = self.definition_source(db);
79 let (_, source_map) = db.raw_items_with_source_map(file_id.original_file(db)); 77 let (_, source_map) = db.raw_items_with_source_map(file_id);
80 source_map.get(&source, import) 78 source_map.get(&source, import)
81 } 79 }
82 80
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index d3908f8ac..147005848 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -1,10 +1,10 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use ra_syntax::{SyntaxNode, TreeArc, SourceFile}; 3use ra_syntax::{SyntaxNode, TreeArc, SourceFile};
4use ra_db::{SourceDatabase, salsa, FileId}; 4use ra_db::{SourceDatabase, salsa};
5 5
6use crate::{ 6use crate::{
7 HirFileId, SourceFileItems, SourceItemId, Crate, Module, HirInterner, 7 HirFileId, MacroDefId, AstIdMap, ErasedFileAstId, Crate, Module, HirInterner,
8 Function, FnSignature, ExprScopes, TypeAlias, 8 Function, FnSignature, ExprScopes, TypeAlias,
9 Struct, Enum, StructField, 9 Struct, Enum, StructField,
10 Const, ConstSignature, Static, 10 Const, ConstSignature, Static,
@@ -14,11 +14,15 @@ use crate::{
14 impl_block::{ModuleImplBlocks, ImplSourceMap}, 14 impl_block::{ModuleImplBlocks, ImplSourceMap},
15 generics::{GenericParams, GenericDef}, 15 generics::{GenericParams, GenericDef},
16 type_ref::TypeRef, 16 type_ref::TypeRef,
17 traits::TraitData, Trait, ty::TraitRef
17}; 18};
18 19
19#[salsa::query_group(DefDatabaseStorage)] 20#[salsa::query_group(DefDatabaseStorage)]
20pub trait DefDatabase: SourceDatabase + AsRef<HirInterner> { 21pub trait DefDatabase: SourceDatabase + AsRef<HirInterner> {
21 #[salsa::invoke(HirFileId::hir_parse)] 22 #[salsa::invoke(crate::ids::macro_def_query)]
23 fn macro_def(&self, macro_id: MacroDefId) -> Option<Arc<mbe::MacroRules>>;
24
25 #[salsa::invoke(HirFileId::hir_parse_query)]
22 fn hir_parse(&self, file_id: HirFileId) -> TreeArc<SourceFile>; 26 fn hir_parse(&self, file_id: HirFileId) -> TreeArc<SourceFile>;
23 27
24 #[salsa::invoke(crate::adt::StructData::struct_data_query)] 28 #[salsa::invoke(crate::adt::StructData::struct_data_query)]
@@ -27,17 +31,23 @@ pub trait DefDatabase: SourceDatabase + AsRef<HirInterner> {
27 #[salsa::invoke(crate::adt::EnumData::enum_data_query)] 31 #[salsa::invoke(crate::adt::EnumData::enum_data_query)]
28 fn enum_data(&self, e: Enum) -> Arc<EnumData>; 32 fn enum_data(&self, e: Enum) -> Arc<EnumData>;
29 33
30 #[salsa::invoke(crate::ids::SourceFileItems::file_items_query)] 34 #[salsa::invoke(crate::traits::TraitData::trait_data_query)]
31 fn file_items(&self, file_id: HirFileId) -> Arc<SourceFileItems>; 35 fn trait_data(&self, t: Trait) -> Arc<TraitData>;
36
37 #[salsa::invoke(crate::source_id::AstIdMap::ast_id_map_query)]
38 fn ast_id_map(&self, file_id: HirFileId) -> Arc<AstIdMap>;
32 39
33 #[salsa::invoke(crate::ids::SourceFileItems::file_item_query)] 40 #[salsa::invoke(crate::source_id::AstIdMap::file_item_query)]
34 fn file_item(&self, source_item_id: SourceItemId) -> TreeArc<SyntaxNode>; 41 fn ast_id_to_node(&self, file_id: HirFileId, ast_id: ErasedFileAstId) -> TreeArc<SyntaxNode>;
35 42
36 #[salsa::invoke(RawItems::raw_items_query)] 43 #[salsa::invoke(RawItems::raw_items_query)]
37 fn raw_items(&self, file_id: FileId) -> Arc<RawItems>; 44 fn raw_items(&self, file_id: HirFileId) -> Arc<RawItems>;
38 45
39 #[salsa::invoke(RawItems::raw_items_with_source_map_query)] 46 #[salsa::invoke(RawItems::raw_items_with_source_map_query)]
40 fn raw_items_with_source_map(&self, file_id: FileId) -> (Arc<RawItems>, Arc<ImportSourceMap>); 47 fn raw_items_with_source_map(
48 &self,
49 file_id: HirFileId,
50 ) -> (Arc<RawItems>, Arc<ImportSourceMap>);
41 51
42 #[salsa::invoke(CrateDefMap::crate_def_map_query)] 52 #[salsa::invoke(CrateDefMap::crate_def_map_query)]
43 fn crate_def_map(&self, krate: Crate) -> Arc<CrateDefMap>; 53 fn crate_def_map(&self, krate: Crate) -> Arc<CrateDefMap>;
@@ -98,6 +108,9 @@ pub trait HirDatabase: DefDatabase {
98 108
99 #[salsa::invoke(crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query)] 109 #[salsa::invoke(crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query)]
100 fn impls_in_crate(&self, krate: Crate) -> Arc<CrateImplBlocks>; 110 fn impls_in_crate(&self, krate: Crate) -> Arc<CrateImplBlocks>;
111
112 #[salsa::invoke(crate::ty::method_resolution::implements)]
113 fn implements(&self, trait_ref: TraitRef) -> bool;
101} 114}
102 115
103#[test] 116#[test]
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs
index 18401f865..eb9939df7 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -1,16 +1,15 @@
1use std::{ 1use std::{
2 marker::PhantomData,
3 hash::{Hash, Hasher}, 2 hash::{Hash, Hasher},
4 sync::Arc, 3 sync::Arc,
5}; 4};
6 5
7use ra_db::{LocationInterner, FileId}; 6use ra_db::{LocationInterner, FileId};
8use ra_syntax::{TreeArc, SyntaxNode, SourceFile, AstNode, SyntaxNodePtr, ast}; 7use ra_syntax::{TreeArc, SourceFile, AstNode, ast};
9use ra_arena::{Arena, RawId, ArenaId, impl_arena_id}; 8use ra_arena::{RawId, ArenaId, impl_arena_id};
9use mbe::MacroRules;
10 10
11use crate::{ 11use crate::{
12 Module, 12 Module, DefDatabase, AstId, FileAstId,
13 DefDatabase,
14}; 13};
15 14
16#[derive(Debug, Default)] 15#[derive(Debug, Default)]
@@ -22,7 +21,7 @@ pub struct HirInterner {
22 consts: LocationInterner<ItemLoc<ast::ConstDef>, ConstId>, 21 consts: LocationInterner<ItemLoc<ast::ConstDef>, ConstId>,
23 statics: LocationInterner<ItemLoc<ast::StaticDef>, StaticId>, 22 statics: LocationInterner<ItemLoc<ast::StaticDef>, StaticId>,
24 traits: LocationInterner<ItemLoc<ast::TraitDef>, TraitId>, 23 traits: LocationInterner<ItemLoc<ast::TraitDef>, TraitId>,
25 types: LocationInterner<ItemLoc<ast::TypeAliasDef>, TypeId>, 24 types: LocationInterner<ItemLoc<ast::TypeAliasDef>, TypeAliasId>,
26} 25}
27 26
28impl HirInterner { 27impl HirInterner {
@@ -68,7 +67,7 @@ impl HirFileId {
68 HirFileIdRepr::File(file_id) => file_id, 67 HirFileIdRepr::File(file_id) => file_id,
69 HirFileIdRepr::Macro(macro_call_id) => { 68 HirFileIdRepr::Macro(macro_call_id) => {
70 let loc = macro_call_id.loc(db); 69 let loc = macro_call_id.loc(db);
71 loc.source_item_id.file_id.original_file(db) 70 loc.ast_id.file_id().original_file(db)
72 } 71 }
73 } 72 }
74 } 73 }
@@ -83,7 +82,10 @@ impl HirFileId {
83 } 82 }
84 } 83 }
85 84
86 pub(crate) fn hir_parse(db: &impl DefDatabase, file_id: HirFileId) -> TreeArc<SourceFile> { 85 pub(crate) fn hir_parse_query(
86 db: &impl DefDatabase,
87 file_id: HirFileId,
88 ) -> TreeArc<SourceFile> {
87 match file_id.0 { 89 match file_id.0 {
88 HirFileIdRepr::File(file_id) => db.parse(file_id), 90 HirFileIdRepr::File(file_id) => db.parse(file_id),
89 HirFileIdRepr::Macro(macro_call_id) => { 91 HirFileIdRepr::Macro(macro_call_id) => {
@@ -96,14 +98,10 @@ impl HirFileId {
96 98
97fn parse_macro(db: &impl DefDatabase, macro_call_id: MacroCallId) -> Option<TreeArc<SourceFile>> { 99fn parse_macro(db: &impl DefDatabase, macro_call_id: MacroCallId) -> Option<TreeArc<SourceFile>> {
98 let loc = macro_call_id.loc(db); 100 let loc = macro_call_id.loc(db);
99 let syntax = db.file_item(loc.source_item_id); 101 let macro_call = loc.ast_id.to_node(db);
100 let macro_call = ast::MacroCall::cast(&syntax).unwrap();
101 let (macro_arg, _) = macro_call.token_tree().and_then(mbe::ast_to_token_tree)?; 102 let (macro_arg, _) = macro_call.token_tree().and_then(mbe::ast_to_token_tree)?;
102 103
103 let def_map = db.crate_def_map(loc.module.krate); 104 let macro_rules = db.macro_def(loc.def)?;
104 let (krate, macro_id) = def_map.resolve_macro(macro_call_id)?;
105 let def_map = db.crate_def_map(krate);
106 let macro_rules = &def_map[macro_id];
107 let tt = macro_rules.expand(&macro_arg).ok()?; 105 let tt = macro_rules.expand(&macro_arg).ok()?;
108 Some(mbe::token_tree_to_ast_item_list(&tt)) 106 Some(mbe::token_tree_to_ast_item_list(&tt))
109} 107}
@@ -126,6 +124,17 @@ impl From<MacroCallId> for HirFileId {
126 } 124 }
127} 125}
128 126
127#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
128pub struct MacroDefId(pub(crate) AstId<ast::MacroCall>);
129
130pub(crate) fn macro_def_query(db: &impl DefDatabase, id: MacroDefId) -> Option<Arc<MacroRules>> {
131 let macro_call = id.0.to_node(db);
132 let arg = macro_call.token_tree()?;
133 let (tt, _) = mbe::ast_to_token_tree(arg)?;
134 let rules = MacroRules::parse(&tt).ok()?;
135 Some(Arc::new(rules))
136}
137
129/// `MacroCallId` identifies a particular macro invocation, like 138/// `MacroCallId` identifies a particular macro invocation, like
130/// `println!("Hello, {}", world)`. 139/// `println!("Hello, {}", world)`.
131#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 140#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -134,8 +143,8 @@ impl_arena_id!(MacroCallId);
134 143
135#[derive(Debug, Clone, PartialEq, Eq, Hash)] 144#[derive(Debug, Clone, PartialEq, Eq, Hash)]
136pub struct MacroCallLoc { 145pub struct MacroCallLoc {
137 pub(crate) module: Module, 146 pub(crate) def: MacroDefId,
138 pub(crate) source_item_id: SourceItemId, 147 pub(crate) ast_id: AstId<ast::MacroCall>,
139} 148}
140 149
141impl MacroCallId { 150impl MacroCallId {
@@ -145,7 +154,6 @@ impl MacroCallId {
145} 154}
146 155
147impl MacroCallLoc { 156impl MacroCallLoc {
148 #[allow(unused)]
149 pub(crate) fn id(&self, db: &impl AsRef<HirInterner>) -> MacroCallId { 157 pub(crate) fn id(&self, db: &impl AsRef<HirInterner>) -> MacroCallId {
150 db.as_ref().macros.loc2id(&self) 158 db.as_ref().macros.loc2id(&self)
151 } 159 }
@@ -154,26 +162,25 @@ impl MacroCallLoc {
154#[derive(Debug)] 162#[derive(Debug)]
155pub struct ItemLoc<N: AstNode> { 163pub struct ItemLoc<N: AstNode> {
156 pub(crate) module: Module, 164 pub(crate) module: Module,
157 raw: SourceItemId, 165 ast_id: AstId<N>,
158 _ty: PhantomData<N>,
159} 166}
160 167
161impl<N: AstNode> PartialEq for ItemLoc<N> { 168impl<N: AstNode> PartialEq for ItemLoc<N> {
162 fn eq(&self, other: &Self) -> bool { 169 fn eq(&self, other: &Self) -> bool {
163 self.module == other.module && self.raw == other.raw 170 self.module == other.module && self.ast_id == other.ast_id
164 } 171 }
165} 172}
166impl<N: AstNode> Eq for ItemLoc<N> {} 173impl<N: AstNode> Eq for ItemLoc<N> {}
167impl<N: AstNode> Hash for ItemLoc<N> { 174impl<N: AstNode> Hash for ItemLoc<N> {
168 fn hash<H: Hasher>(&self, hasher: &mut H) { 175 fn hash<H: Hasher>(&self, hasher: &mut H) {
169 self.module.hash(hasher); 176 self.module.hash(hasher);
170 self.raw.hash(hasher); 177 self.ast_id.hash(hasher);
171 } 178 }
172} 179}
173 180
174impl<N: AstNode> Clone for ItemLoc<N> { 181impl<N: AstNode> Clone for ItemLoc<N> {
175 fn clone(&self) -> ItemLoc<N> { 182 fn clone(&self) -> ItemLoc<N> {
176 ItemLoc { module: self.module, raw: self.raw, _ty: PhantomData } 183 ItemLoc { module: self.module, ast_id: self.ast_id }
177 } 184 }
178} 185}
179 186
@@ -200,26 +207,19 @@ impl<'a, DB: DefDatabase> LocationCtx<&'a DB> {
200pub(crate) trait AstItemDef<N: AstNode>: ArenaId + Clone { 207pub(crate) trait AstItemDef<N: AstNode>: ArenaId + Clone {
201 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<N>, Self>; 208 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<N>, Self>;
202 fn from_ast(ctx: LocationCtx<&impl DefDatabase>, ast: &N) -> Self { 209 fn from_ast(ctx: LocationCtx<&impl DefDatabase>, ast: &N) -> Self {
203 let items = ctx.db.file_items(ctx.file_id); 210 let items = ctx.db.ast_id_map(ctx.file_id);
204 let item_id = items.id_of(ctx.file_id, ast.syntax()); 211 let item_id = items.ast_id(ast);
205 Self::from_source_item_id_unchecked(ctx, item_id) 212 Self::from_ast_id(ctx, item_id)
206 } 213 }
207 fn from_source_item_id_unchecked( 214 fn from_ast_id(ctx: LocationCtx<&impl DefDatabase>, ast_id: FileAstId<N>) -> Self {
208 ctx: LocationCtx<&impl DefDatabase>, 215 let loc = ItemLoc { module: ctx.module, ast_id: ast_id.with_file_id(ctx.file_id) };
209 item_id: SourceFileItemId,
210 ) -> Self {
211 let raw = SourceItemId { file_id: ctx.file_id, item_id };
212 let loc = ItemLoc { module: ctx.module, raw, _ty: PhantomData };
213
214 Self::interner(ctx.db.as_ref()).loc2id(&loc) 216 Self::interner(ctx.db.as_ref()).loc2id(&loc)
215 } 217 }
216 fn source(self, db: &impl DefDatabase) -> (HirFileId, TreeArc<N>) { 218 fn source(self, db: &impl DefDatabase) -> (HirFileId, TreeArc<N>) {
217 let int = Self::interner(db.as_ref()); 219 let int = Self::interner(db.as_ref());
218 let loc = int.id2loc(self); 220 let loc = int.id2loc(self);
219 let syntax = db.file_item(loc.raw); 221 let ast = loc.ast_id.to_node(db);
220 let ast = 222 (loc.ast_id.file_id(), ast)
221 N::cast(&syntax).unwrap_or_else(|| panic!("invalid ItemLoc: {:?}", loc.raw)).to_owned();
222 (loc.raw.file_id, ast)
223 } 223 }
224 fn module(self, db: &impl DefDatabase) -> Module { 224 fn module(self, db: &impl DefDatabase) -> Module {
225 let int = Self::interner(db.as_ref()); 225 let int = Self::interner(db.as_ref());
@@ -229,7 +229,7 @@ pub(crate) trait AstItemDef<N: AstNode>: ArenaId + Clone {
229} 229}
230 230
231#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 231#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
232pub struct FunctionId(RawId); 232pub(crate) struct FunctionId(RawId);
233impl_arena_id!(FunctionId); 233impl_arena_id!(FunctionId);
234impl AstItemDef<ast::FnDef> for FunctionId { 234impl AstItemDef<ast::FnDef> for FunctionId {
235 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::FnDef>, Self> { 235 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::FnDef>, Self> {
@@ -238,7 +238,7 @@ impl AstItemDef<ast::FnDef> for FunctionId {
238} 238}
239 239
240#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 240#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
241pub struct StructId(RawId); 241pub(crate) struct StructId(RawId);
242impl_arena_id!(StructId); 242impl_arena_id!(StructId);
243impl AstItemDef<ast::StructDef> for StructId { 243impl AstItemDef<ast::StructDef> for StructId {
244 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::StructDef>, Self> { 244 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::StructDef>, Self> {
@@ -247,7 +247,7 @@ impl AstItemDef<ast::StructDef> for StructId {
247} 247}
248 248
249#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 249#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
250pub struct EnumId(RawId); 250pub(crate) struct EnumId(RawId);
251impl_arena_id!(EnumId); 251impl_arena_id!(EnumId);
252impl AstItemDef<ast::EnumDef> for EnumId { 252impl AstItemDef<ast::EnumDef> for EnumId {
253 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::EnumDef>, Self> { 253 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::EnumDef>, Self> {
@@ -256,7 +256,7 @@ impl AstItemDef<ast::EnumDef> for EnumId {
256} 256}
257 257
258#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 258#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
259pub struct ConstId(RawId); 259pub(crate) struct ConstId(RawId);
260impl_arena_id!(ConstId); 260impl_arena_id!(ConstId);
261impl AstItemDef<ast::ConstDef> for ConstId { 261impl AstItemDef<ast::ConstDef> for ConstId {
262 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::ConstDef>, Self> { 262 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::ConstDef>, Self> {
@@ -265,7 +265,7 @@ impl AstItemDef<ast::ConstDef> for ConstId {
265} 265}
266 266
267#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 267#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
268pub struct StaticId(RawId); 268pub(crate) struct StaticId(RawId);
269impl_arena_id!(StaticId); 269impl_arena_id!(StaticId);
270impl AstItemDef<ast::StaticDef> for StaticId { 270impl AstItemDef<ast::StaticDef> for StaticId {
271 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::StaticDef>, Self> { 271 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::StaticDef>, Self> {
@@ -274,7 +274,7 @@ impl AstItemDef<ast::StaticDef> for StaticId {
274} 274}
275 275
276#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 276#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
277pub struct TraitId(RawId); 277pub(crate) struct TraitId(RawId);
278impl_arena_id!(TraitId); 278impl_arena_id!(TraitId);
279impl AstItemDef<ast::TraitDef> for TraitId { 279impl AstItemDef<ast::TraitDef> for TraitId {
280 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::TraitDef>, Self> { 280 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::TraitDef>, Self> {
@@ -283,117 +283,10 @@ impl AstItemDef<ast::TraitDef> for TraitId {
283} 283}
284 284
285#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 285#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
286pub struct TypeId(RawId); 286pub(crate) struct TypeAliasId(RawId);
287impl_arena_id!(TypeId); 287impl_arena_id!(TypeAliasId);
288impl AstItemDef<ast::TypeAliasDef> for TypeId { 288impl AstItemDef<ast::TypeAliasDef> for TypeAliasId {
289 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::TypeAliasDef>, Self> { 289 fn interner(interner: &HirInterner) -> &LocationInterner<ItemLoc<ast::TypeAliasDef>, Self> {
290 &interner.types 290 &interner.types
291 } 291 }
292} 292}
293
294/// Identifier of item within a specific file. This is stable over reparses, so
295/// it's OK to use it as a salsa key/value.
296#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
297pub struct SourceFileItemId(RawId);
298impl_arena_id!(SourceFileItemId);
299
300impl SourceFileItemId {
301 pub(crate) fn with_file_id(self, file_id: HirFileId) -> SourceItemId {
302 SourceItemId { file_id, item_id: self }
303 }
304}
305
306#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
307pub struct SourceItemId {
308 pub(crate) file_id: HirFileId,
309 pub(crate) item_id: SourceFileItemId,
310}
311
312/// Maps items' `SyntaxNode`s to `SourceFileItemId`s and back.
313#[derive(Debug, PartialEq, Eq)]
314pub struct SourceFileItems {
315 file_id: HirFileId,
316 arena: Arena<SourceFileItemId, SyntaxNodePtr>,
317}
318
319impl SourceFileItems {
320 pub(crate) fn file_items_query(
321 db: &impl DefDatabase,
322 file_id: HirFileId,
323 ) -> Arc<SourceFileItems> {
324 let source_file = db.hir_parse(file_id);
325 Arc::new(SourceFileItems::from_source_file(&source_file, file_id))
326 }
327
328 pub(crate) fn file_item_query(
329 db: &impl DefDatabase,
330 source_item_id: SourceItemId,
331 ) -> TreeArc<SyntaxNode> {
332 let source_file = db.hir_parse(source_item_id.file_id);
333 db.file_items(source_item_id.file_id)[source_item_id.item_id]
334 .to_node(&source_file)
335 .to_owned()
336 }
337
338 pub(crate) fn from_source_file(
339 source_file: &SourceFile,
340 file_id: HirFileId,
341 ) -> SourceFileItems {
342 let mut res = SourceFileItems { file_id, arena: Arena::default() };
343 // By walking the tree in bread-first order we make sure that parents
344 // get lower ids then children. That is, adding a new child does not
345 // change parent's id. This means that, say, adding a new function to a
346 // trait does not change ids of top-level items, which helps caching.
347 bfs(source_file.syntax(), |it| {
348 if let Some(module_item) = ast::ModuleItem::cast(it) {
349 res.alloc(module_item.syntax());
350 } else if let Some(macro_call) = ast::MacroCall::cast(it) {
351 res.alloc(macro_call.syntax());
352 }
353 });
354 res
355 }
356
357 fn alloc(&mut self, item: &SyntaxNode) -> SourceFileItemId {
358 self.arena.alloc(SyntaxNodePtr::new(item))
359 }
360 pub(crate) fn id_of(&self, file_id: HirFileId, item: &SyntaxNode) -> SourceFileItemId {
361 assert_eq!(
362 self.file_id, file_id,
363 "SourceFileItems: wrong file, expected {:?}, got {:?}",
364 self.file_id, file_id
365 );
366 self.id_of_unchecked(item)
367 }
368 pub(crate) fn id_of_unchecked(&self, item: &SyntaxNode) -> SourceFileItemId {
369 let ptr = SyntaxNodePtr::new(item);
370 if let Some((id, _)) = self.arena.iter().find(|(_id, i)| **i == ptr) {
371 return id;
372 }
373 panic!(
374 "Can't find {:?} in SourceFileItems:\n{:?}",
375 item,
376 self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(),
377 );
378 }
379}
380
381impl std::ops::Index<SourceFileItemId> for SourceFileItems {
382 type Output = SyntaxNodePtr;
383 fn index(&self, idx: SourceFileItemId) -> &SyntaxNodePtr {
384 &self.arena[idx]
385 }
386}
387
388/// Walks the subtree in bfs order, calling `f` for each node.
389fn bfs(node: &SyntaxNode, mut f: impl FnMut(&SyntaxNode)) {
390 let mut curr_layer = vec![node];
391 let mut next_layer = vec![];
392 while !curr_layer.is_empty() {
393 curr_layer.drain(..).for_each(|node| {
394 next_layer.extend(node.children());
395 f(node);
396 });
397 std::mem::swap(&mut curr_layer, &mut next_layer);
398 }
399}
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index ce54d7608..7c603bbd3 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -23,10 +23,12 @@ pub mod mock;
23mod path; 23mod path;
24pub mod source_binder; 24pub mod source_binder;
25 25
26mod source_id;
26mod ids; 27mod ids;
27mod name; 28mod name;
28mod nameres; 29mod nameres;
29mod adt; 30mod adt;
31mod traits;
30mod type_alias; 32mod type_alias;
31mod type_ref; 33mod type_ref;
32mod ty; 34mod ty;
@@ -46,13 +48,14 @@ mod marks;
46use crate::{ 48use crate::{
47 db::{HirDatabase, DefDatabase}, 49 db::{HirDatabase, DefDatabase},
48 name::{AsName, KnownName}, 50 name::{AsName, KnownName},
49 ids::{SourceItemId, SourceFileItems}, 51 source_id::{FileAstId, AstId},
50}; 52};
51 53
52pub use self::{ 54pub use self::{
53 path::{Path, PathKind}, 55 path::{Path, PathKind},
54 name::Name, 56 name::Name,
55 ids::{HirFileId, MacroCallId, MacroCallLoc, HirInterner}, 57 source_id::{AstIdMap, ErasedFileAstId},
58 ids::{HirFileId, MacroDefId, MacroCallId, MacroCallLoc, HirInterner},
56 nameres::{PerNs, Namespace}, 59 nameres::{PerNs, Namespace},
57 ty::{Ty, ApplicationTy, TypeCtor, Substs, display::HirDisplay}, 60 ty::{Ty, ApplicationTy, TypeCtor, Substs, display::HirDisplay},
58 impl_block::{ImplBlock, ImplItem}, 61 impl_block::{ImplBlock, ImplItem},
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index 56ed872d5..67b9d6986 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -59,13 +59,15 @@ use rustc_hash::FxHashMap;
59use ra_arena::{Arena, RawId, impl_arena_id}; 59use ra_arena::{Arena, RawId, impl_arena_id};
60use ra_db::{FileId, Edition}; 60use ra_db::{FileId, Edition};
61use test_utils::tested_by; 61use test_utils::tested_by;
62use ra_syntax::ast;
62 63
63use crate::{ 64use crate::{
64 ModuleDef, Name, Crate, Module, 65 ModuleDef, Name, Crate, Module,
65 DefDatabase, Path, PathKind, HirFileId, 66 DefDatabase, Path, PathKind, HirFileId, Trait,
66 ids::{SourceItemId, SourceFileItemId, MacroCallId}, 67 ids::MacroDefId,
67 diagnostics::DiagnosticSink, 68 diagnostics::DiagnosticSink,
68 nameres::diagnostics::DefDiagnostic, 69 nameres::diagnostics::DefDiagnostic,
70 AstId,
69}; 71};
70 72
71pub(crate) use self::raw::{RawItems, ImportId, ImportSourceMap}; 73pub(crate) use self::raw::{RawItems, ImportId, ImportSourceMap};
@@ -84,9 +86,7 @@ pub struct CrateDefMap {
84 extern_prelude: FxHashMap<Name, ModuleDef>, 86 extern_prelude: FxHashMap<Name, ModuleDef>,
85 root: CrateModuleId, 87 root: CrateModuleId,
86 modules: Arena<CrateModuleId, ModuleData>, 88 modules: Arena<CrateModuleId, ModuleData>,
87 macros: Arena<CrateMacroId, mbe::MacroRules>, 89 public_macros: FxHashMap<Name, MacroDefId>,
88 public_macros: FxHashMap<Name, CrateMacroId>,
89 macro_resolutions: FxHashMap<MacroCallId, (Crate, CrateMacroId)>,
90 diagnostics: Vec<DefDiagnostic>, 90 diagnostics: Vec<DefDiagnostic>,
91} 91}
92 92
@@ -97,18 +97,6 @@ impl std::ops::Index<CrateModuleId> for CrateDefMap {
97 } 97 }
98} 98}
99 99
100impl std::ops::Index<CrateMacroId> for CrateDefMap {
101 type Output = mbe::MacroRules;
102 fn index(&self, id: CrateMacroId) -> &mbe::MacroRules {
103 &self.macros[id]
104 }
105}
106
107/// An ID of a macro, **local** to a specific crate
108#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
109pub(crate) struct CrateMacroId(RawId);
110impl_arena_id!(CrateMacroId);
111
112/// An ID of a module, **local** to a specific crate 100/// An ID of a module, **local** to a specific crate
113#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 101#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
114pub(crate) struct CrateModuleId(RawId); 102pub(crate) struct CrateModuleId(RawId);
@@ -120,7 +108,7 @@ pub(crate) struct ModuleData {
120 pub(crate) children: FxHashMap<Name, CrateModuleId>, 108 pub(crate) children: FxHashMap<Name, CrateModuleId>,
121 pub(crate) scope: ModuleScope, 109 pub(crate) scope: ModuleScope,
122 /// None for root 110 /// None for root
123 pub(crate) declaration: Option<SourceItemId>, 111 pub(crate) declaration: Option<AstId<ast::Module>>,
124 /// None for inline modules. 112 /// None for inline modules.
125 /// 113 ///
126 /// Note that non-inline modules, by definition, live inside non-macro file. 114 /// Note that non-inline modules, by definition, live inside non-macro file.
@@ -139,6 +127,12 @@ impl ModuleScope {
139 pub fn get(&self, name: &Name) -> Option<&Resolution> { 127 pub fn get(&self, name: &Name) -> Option<&Resolution> {
140 self.items.get(name) 128 self.items.get(name)
141 } 129 }
130 pub fn traits<'a>(&'a self) -> impl Iterator<Item = Trait> + 'a {
131 self.items.values().filter_map(|r| match r.def.take_types() {
132 Some(ModuleDef::Trait(t)) => Some(t),
133 _ => None,
134 })
135 }
142} 136}
143 137
144#[derive(Debug, Clone, PartialEq, Eq, Default)] 138#[derive(Debug, Clone, PartialEq, Eq, Default)]
@@ -196,9 +190,7 @@ impl CrateDefMap {
196 prelude: None, 190 prelude: None,
197 root, 191 root,
198 modules, 192 modules,
199 macros: Arena::default(),
200 public_macros: FxHashMap::default(), 193 public_macros: FxHashMap::default(),
201 macro_resolutions: FxHashMap::default(),
202 diagnostics: Vec::new(), 194 diagnostics: Vec::new(),
203 } 195 }
204 }; 196 };
@@ -232,19 +224,11 @@ impl CrateDefMap {
232 self.diagnostics.iter().for_each(|it| it.add_to(db, module, sink)) 224 self.diagnostics.iter().for_each(|it| it.add_to(db, module, sink))
233 } 225 }
234 226
235 pub(crate) fn resolve_macro(
236 &self,
237 macro_call_id: MacroCallId,
238 ) -> Option<(Crate, CrateMacroId)> {
239 self.macro_resolutions.get(&macro_call_id).map(|&it| it)
240 }
241
242 pub(crate) fn find_module_by_source( 227 pub(crate) fn find_module_by_source(
243 &self, 228 &self,
244 file_id: HirFileId, 229 file_id: HirFileId,
245 decl_id: Option<SourceFileItemId>, 230 decl_id: Option<AstId<ast::Module>>,
246 ) -> Option<CrateModuleId> { 231 ) -> Option<CrateModuleId> {
247 let decl_id = decl_id.map(|it| it.with_file_id(file_id));
248 let (module_id, _module_data) = self.modules.iter().find(|(_module_id, module_data)| { 232 let (module_id, _module_data) = self.modules.iter().find(|(_module_id, module_data)| {
249 if decl_id.is_some() { 233 if decl_id.is_some() {
250 module_data.declaration == decl_id 234 module_data.declaration == decl_id
@@ -447,10 +431,10 @@ impl CrateDefMap {
447 431
448mod diagnostics { 432mod diagnostics {
449 use relative_path::RelativePathBuf; 433 use relative_path::RelativePathBuf;
450 use ra_syntax::{AstPtr, AstNode, ast}; 434 use ra_syntax::{AstPtr, ast};
451 435
452 use crate::{ 436 use crate::{
453 SourceItemId, DefDatabase, 437 AstId, DefDatabase,
454 nameres::CrateModuleId, 438 nameres::CrateModuleId,
455 diagnostics::{DiagnosticSink, UnresolvedModule}, 439 diagnostics::{DiagnosticSink, UnresolvedModule},
456}; 440};
@@ -459,7 +443,7 @@ mod diagnostics {
459 pub(super) enum DefDiagnostic { 443 pub(super) enum DefDiagnostic {
460 UnresolvedModule { 444 UnresolvedModule {
461 module: CrateModuleId, 445 module: CrateModuleId,
462 declaration: SourceItemId, 446 declaration: AstId<ast::Module>,
463 candidate: RelativePathBuf, 447 candidate: RelativePathBuf,
464 }, 448 },
465 } 449 }
@@ -476,10 +460,9 @@ mod diagnostics {
476 if *module != target_module { 460 if *module != target_module {
477 return; 461 return;
478 } 462 }
479 let syntax = db.file_item(*declaration); 463 let decl = declaration.to_node(db);
480 let decl = ast::Module::cast(&syntax).unwrap();
481 sink.push(UnresolvedModule { 464 sink.push(UnresolvedModule {
482 file: declaration.file_id, 465 file: declaration.file_id(),
483 decl: AstPtr::new(&decl), 466 decl: AstPtr::new(&decl),
484 candidate: candidate.clone(), 467 candidate: candidate.clone(),
485 }) 468 })
@@ -487,5 +470,4 @@ mod diagnostics {
487 } 470 }
488 } 471 }
489 } 472 }
490
491} 473}
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs
index 8830b4624..39cadc94a 100644
--- a/crates/ra_hir/src/nameres/collector.rs
+++ b/crates/ra_hir/src/nameres/collector.rs
@@ -3,18 +3,20 @@ use rustc_hash::FxHashMap;
3use relative_path::RelativePathBuf; 3use relative_path::RelativePathBuf;
4use test_utils::tested_by; 4use test_utils::tested_by;
5use ra_db::FileId; 5use ra_db::FileId;
6use ra_syntax::ast;
6 7
7use crate::{ 8use crate::{
8 Function, Module, Struct, Enum, Const, Static, Trait, TypeAlias, 9 Function, Module, Struct, Enum, Const, Static, Trait, TypeAlias,
9 DefDatabase, HirFileId, Name, Path, Crate, 10 DefDatabase, HirFileId, Name, Path,
10 KnownName, 11 KnownName,
11 nameres::{ 12 nameres::{
12 Resolution, PerNs, ModuleDef, ReachedFixedPoint, ResolveMode, 13 Resolution, PerNs, ModuleDef, ReachedFixedPoint, ResolveMode,
13 CrateDefMap, CrateModuleId, ModuleData, CrateMacroId, 14 CrateDefMap, CrateModuleId, ModuleData,
14 diagnostics::DefDiagnostic, 15 diagnostics::DefDiagnostic,
15 raw, 16 raw,
16 }, 17 },
17 ids::{AstItemDef, LocationCtx, MacroCallLoc, SourceItemId, MacroCallId}, 18 ids::{AstItemDef, LocationCtx, MacroCallLoc, MacroCallId, MacroDefId},
19 AstId,
18}; 20};
19 21
20pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { 22pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap {
@@ -51,8 +53,8 @@ struct DefCollector<DB> {
51 def_map: CrateDefMap, 53 def_map: CrateDefMap,
52 glob_imports: FxHashMap<CrateModuleId, Vec<(CrateModuleId, raw::ImportId)>>, 54 glob_imports: FxHashMap<CrateModuleId, Vec<(CrateModuleId, raw::ImportId)>>,
53 unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>, 55 unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>,
54 unexpanded_macros: Vec<(CrateModuleId, MacroCallId, Path, tt::Subtree)>, 56 unexpanded_macros: Vec<(CrateModuleId, AstId<ast::MacroCall>, Path)>,
55 global_macro_scope: FxHashMap<Name, CrateMacroId>, 57 global_macro_scope: FxHashMap<Name, MacroDefId>,
56} 58}
57 59
58impl<'a, DB> DefCollector<&'a DB> 60impl<'a, DB> DefCollector<&'a DB>
@@ -62,7 +64,7 @@ where
62 fn collect(&mut self) { 64 fn collect(&mut self) {
63 let crate_graph = self.db.crate_graph(); 65 let crate_graph = self.db.crate_graph();
64 let file_id = crate_graph.crate_root(self.def_map.krate.crate_id()); 66 let file_id = crate_graph.crate_root(self.def_map.krate.crate_id());
65 let raw_items = self.db.raw_items(file_id); 67 let raw_items = self.db.raw_items(file_id.into());
66 let module_id = self.def_map.root; 68 let module_id = self.def_map.root;
67 self.def_map.modules[module_id].definition = Some(file_id); 69 self.def_map.modules[module_id].definition = Some(file_id);
68 ModCollector { 70 ModCollector {
@@ -93,14 +95,11 @@ where
93 } 95 }
94 } 96 }
95 97
96 fn define_macro(&mut self, name: Name, tt: &tt::Subtree, export: bool) { 98 fn define_macro(&mut self, name: Name, macro_id: MacroDefId, export: bool) {
97 if let Ok(rules) = mbe::MacroRules::parse(tt) { 99 if export {
98 let macro_id = self.def_map.macros.alloc(rules); 100 self.def_map.public_macros.insert(name.clone(), macro_id);
99 if export {
100 self.def_map.public_macros.insert(name.clone(), macro_id);
101 }
102 self.global_macro_scope.insert(name, macro_id);
103 } 101 }
102 self.global_macro_scope.insert(name, macro_id);
104 } 103 }
105 104
106 fn resolve_imports(&mut self) -> ReachedFixedPoint { 105 fn resolve_imports(&mut self) -> ReachedFixedPoint {
@@ -296,7 +295,7 @@ where
296 let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new()); 295 let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new());
297 let mut resolved = Vec::new(); 296 let mut resolved = Vec::new();
298 let mut res = ReachedFixedPoint::Yes; 297 let mut res = ReachedFixedPoint::Yes;
299 macros.retain(|(module_id, call_id, path, tt)| { 298 macros.retain(|(module_id, ast_id, path)| {
300 if path.segments.len() != 2 { 299 if path.segments.len() != 2 {
301 return true; 300 return true;
302 } 301 }
@@ -312,47 +311,23 @@ where
312 res = ReachedFixedPoint::No; 311 res = ReachedFixedPoint::No;
313 let def_map = self.db.crate_def_map(krate); 312 let def_map = self.db.crate_def_map(krate);
314 if let Some(macro_id) = def_map.public_macros.get(&path.segments[1].name).cloned() { 313 if let Some(macro_id) = def_map.public_macros.get(&path.segments[1].name).cloned() {
315 resolved.push((*module_id, *call_id, (krate, macro_id), tt.clone())); 314 let call_id = MacroCallLoc { def: macro_id, ast_id: *ast_id }.id(self.db);
315 resolved.push((*module_id, call_id));
316 } 316 }
317 false 317 false
318 }); 318 });
319 319
320 for (module_id, macro_call_id, macro_def_id, arg) in resolved { 320 for (module_id, macro_call_id) in resolved {
321 self.collect_macro_expansion(module_id, macro_call_id, macro_def_id, arg); 321 self.collect_macro_expansion(module_id, macro_call_id);
322 } 322 }
323 res 323 res
324 } 324 }
325 325
326 fn collect_macro_expansion( 326 fn collect_macro_expansion(&mut self, module_id: CrateModuleId, macro_call_id: MacroCallId) {
327 &mut self, 327 let file_id: HirFileId = macro_call_id.into();
328 module_id: CrateModuleId, 328 let raw_items = self.db.raw_items(file_id);
329 macro_call_id: MacroCallId, 329 ModCollector { def_collector: &mut *self, file_id, module_id, raw_items: &raw_items }
330 macro_def_id: (Crate, CrateMacroId), 330 .collect(raw_items.items())
331 macro_arg: tt::Subtree,
332 ) {
333 let (macro_krate, macro_id) = macro_def_id;
334 let dm;
335 let rules = if macro_krate == self.def_map.krate {
336 &self.def_map[macro_id]
337 } else {
338 dm = self.db.crate_def_map(macro_krate);
339 &dm[macro_id]
340 };
341 if let Ok(expansion) = rules.expand(&macro_arg) {
342 self.def_map.macro_resolutions.insert(macro_call_id, macro_def_id);
343 // XXX: this **does not** go through a database, because we can't
344 // identify macro_call without adding the whole state of name resolution
345 // as a parameter to the query.
346 //
347 // So, we run the queries "manually" and we must ensure that
348 // `db.hir_parse(macro_call_id)` returns the same source_file.
349 let file_id: HirFileId = macro_call_id.into();
350 let source_file = mbe::token_tree_to_ast_item_list(&expansion);
351
352 let raw_items = raw::RawItems::from_source_file(&source_file, file_id);
353 ModCollector { def_collector: &mut *self, file_id, module_id, raw_items: &raw_items }
354 .collect(raw_items.items())
355 }
356 } 331 }
357 332
358 fn finish(self) -> CrateDefMap { 333 fn finish(self) -> CrateDefMap {
@@ -390,12 +365,9 @@ where
390 fn collect_module(&mut self, module: &raw::ModuleData) { 365 fn collect_module(&mut self, module: &raw::ModuleData) {
391 match module { 366 match module {
392 // inline module, just recurse 367 // inline module, just recurse
393 raw::ModuleData::Definition { name, items, source_item_id } => { 368 raw::ModuleData::Definition { name, items, ast_id } => {
394 let module_id = self.push_child_module( 369 let module_id =
395 name.clone(), 370 self.push_child_module(name.clone(), ast_id.with_file_id(self.file_id), None);
396 source_item_id.with_file_id(self.file_id),
397 None,
398 );
399 ModCollector { 371 ModCollector {
400 def_collector: &mut *self.def_collector, 372 def_collector: &mut *self.def_collector,
401 module_id, 373 module_id,
@@ -405,14 +377,13 @@ where
405 .collect(&*items); 377 .collect(&*items);
406 } 378 }
407 // out of line module, resovle, parse and recurse 379 // out of line module, resovle, parse and recurse
408 raw::ModuleData::Declaration { name, source_item_id } => { 380 raw::ModuleData::Declaration { name, ast_id } => {
409 let source_item_id = source_item_id.with_file_id(self.file_id); 381 let ast_id = ast_id.with_file_id(self.file_id);
410 let is_root = self.def_collector.def_map.modules[self.module_id].parent.is_none(); 382 let is_root = self.def_collector.def_map.modules[self.module_id].parent.is_none();
411 match resolve_submodule(self.def_collector.db, self.file_id, name, is_root) { 383 match resolve_submodule(self.def_collector.db, self.file_id, name, is_root) {
412 Ok(file_id) => { 384 Ok(file_id) => {
413 let module_id = 385 let module_id = self.push_child_module(name.clone(), ast_id, Some(file_id));
414 self.push_child_module(name.clone(), source_item_id, Some(file_id)); 386 let raw_items = self.def_collector.db.raw_items(file_id.into());
415 let raw_items = self.def_collector.db.raw_items(file_id);
416 ModCollector { 387 ModCollector {
417 def_collector: &mut *self.def_collector, 388 def_collector: &mut *self.def_collector,
418 module_id, 389 module_id,
@@ -424,7 +395,7 @@ where
424 Err(candidate) => self.def_collector.def_map.diagnostics.push( 395 Err(candidate) => self.def_collector.def_map.diagnostics.push(
425 DefDiagnostic::UnresolvedModule { 396 DefDiagnostic::UnresolvedModule {
426 module: self.module_id, 397 module: self.module_id,
427 declaration: source_item_id, 398 declaration: ast_id,
428 candidate, 399 candidate,
429 }, 400 },
430 ), 401 ),
@@ -436,7 +407,7 @@ where
436 fn push_child_module( 407 fn push_child_module(
437 &mut self, 408 &mut self,
438 name: Name, 409 name: Name,
439 declaration: SourceItemId, 410 declaration: AstId<ast::Module>,
440 definition: Option<FileId>, 411 definition: Option<FileId>,
441 ) -> CrateModuleId { 412 ) -> CrateModuleId {
442 let modules = &mut self.def_collector.def_map.modules; 413 let modules = &mut self.def_collector.def_map.modules;
@@ -458,23 +429,24 @@ where
458 fn define_def(&mut self, def: &raw::DefData) { 429 fn define_def(&mut self, def: &raw::DefData) {
459 let module = Module { krate: self.def_collector.def_map.krate, module_id: self.module_id }; 430 let module = Module { krate: self.def_collector.def_map.krate, module_id: self.module_id };
460 let ctx = LocationCtx::new(self.def_collector.db, module, self.file_id.into()); 431 let ctx = LocationCtx::new(self.def_collector.db, module, self.file_id.into());
461 macro_rules! id { 432
462 () => { 433 macro_rules! def {
463 AstItemDef::from_source_item_id_unchecked(ctx, def.source_item_id) 434 ($kind:ident, $ast_id:ident) => {
435 $kind { id: AstItemDef::from_ast_id(ctx, $ast_id) }.into()
464 }; 436 };
465 } 437 }
466 let name = def.name.clone(); 438 let name = def.name.clone();
467 let def: PerNs<ModuleDef> = match def.kind { 439 let def: PerNs<ModuleDef> = match def.kind {
468 raw::DefKind::Function => PerNs::values(Function { id: id!() }.into()), 440 raw::DefKind::Function(ast_id) => PerNs::values(def!(Function, ast_id)),
469 raw::DefKind::Struct => { 441 raw::DefKind::Struct(ast_id) => {
470 let s = Struct { id: id!() }.into(); 442 let s = def!(Struct, ast_id);
471 PerNs::both(s, s) 443 PerNs::both(s, s)
472 } 444 }
473 raw::DefKind::Enum => PerNs::types(Enum { id: id!() }.into()), 445 raw::DefKind::Enum(ast_id) => PerNs::types(def!(Enum, ast_id)),
474 raw::DefKind::Const => PerNs::values(Const { id: id!() }.into()), 446 raw::DefKind::Const(ast_id) => PerNs::values(def!(Const, ast_id)),
475 raw::DefKind::Static => PerNs::values(Static { id: id!() }.into()), 447 raw::DefKind::Static(ast_id) => PerNs::values(def!(Static, ast_id)),
476 raw::DefKind::Trait => PerNs::types(Trait { id: id!() }.into()), 448 raw::DefKind::Trait(ast_id) => PerNs::types(def!(Trait, ast_id)),
477 raw::DefKind::TypeAlias => PerNs::types(TypeAlias { id: id!() }.into()), 449 raw::DefKind::TypeAlias(ast_id) => PerNs::types(def!(TypeAlias, ast_id)),
478 }; 450 };
479 let resolution = Resolution { def, import: None }; 451 let resolution = Resolution { def, import: None };
480 self.def_collector.update(self.module_id, None, &[(name, resolution)]) 452 self.def_collector.update(self.module_id, None, &[(name, resolution)])
@@ -484,39 +456,27 @@ where
484 // Case 1: macro rules, define a macro in crate-global mutable scope 456 // Case 1: macro rules, define a macro in crate-global mutable scope
485 if is_macro_rules(&mac.path) { 457 if is_macro_rules(&mac.path) {
486 if let Some(name) = &mac.name { 458 if let Some(name) = &mac.name {
487 self.def_collector.define_macro(name.clone(), &mac.arg, mac.export) 459 let macro_id = MacroDefId(mac.ast_id.with_file_id(self.file_id));
460 self.def_collector.define_macro(name.clone(), macro_id, mac.export)
488 } 461 }
489 return; 462 return;
490 } 463 }
491 464
492 let source_item_id = SourceItemId { file_id: self.file_id, item_id: mac.source_item_id }; 465 let ast_id = mac.ast_id.with_file_id(self.file_id);
493 let macro_call_id = MacroCallLoc {
494 module: Module { krate: self.def_collector.def_map.krate, module_id: self.module_id },
495 source_item_id,
496 }
497 .id(self.def_collector.db);
498 466
499 // Case 2: try to expand macro_rules from this crate, triggering 467 // Case 2: try to expand macro_rules from this crate, triggering
500 // recursive item collection. 468 // recursive item collection.
501 if let Some(&macro_id) = 469 if let Some(&macro_id) =
502 mac.path.as_ident().and_then(|name| self.def_collector.global_macro_scope.get(name)) 470 mac.path.as_ident().and_then(|name| self.def_collector.global_macro_scope.get(name))
503 { 471 {
504 self.def_collector.collect_macro_expansion( 472 let macro_call_id = MacroCallLoc { def: macro_id, ast_id }.id(self.def_collector.db);
505 self.module_id, 473
506 macro_call_id, 474 self.def_collector.collect_macro_expansion(self.module_id, macro_call_id);
507 (self.def_collector.def_map.krate, macro_id),
508 mac.arg.clone(),
509 );
510 return; 475 return;
511 } 476 }
512 477
513 // Case 3: path to a macro from another crate, expand during name resolution 478 // Case 3: path to a macro from another crate, expand during name resolution
514 self.def_collector.unexpanded_macros.push(( 479 self.def_collector.unexpanded_macros.push((self.module_id, ast_id, mac.path.clone()))
515 self.module_id,
516 macro_call_id,
517 mac.path.clone(),
518 mac.arg.clone(),
519 ))
520 } 480 }
521} 481}
522 482
diff --git a/crates/ra_hir/src/nameres/raw.rs b/crates/ra_hir/src/nameres/raw.rs
index f8ba398ec..0936229ac 100644
--- a/crates/ra_hir/src/nameres/raw.rs
+++ b/crates/ra_hir/src/nameres/raw.rs
@@ -4,7 +4,6 @@ use std::{
4}; 4};
5 5
6use test_utils::tested_by; 6use test_utils::tested_by;
7use ra_db::FileId;
8use ra_arena::{Arena, impl_arena_id, RawId, map::ArenaMap}; 7use ra_arena::{Arena, impl_arena_id, RawId, map::ArenaMap};
9use ra_syntax::{ 8use ra_syntax::{
10 AstNode, SourceFile, AstPtr, TreeArc, 9 AstNode, SourceFile, AstPtr, TreeArc,
@@ -13,9 +12,13 @@ use ra_syntax::{
13 12
14use crate::{ 13use crate::{
15 DefDatabase, Name, AsName, Path, HirFileId, ModuleSource, 14 DefDatabase, Name, AsName, Path, HirFileId, ModuleSource,
16 ids::{SourceFileItemId, SourceFileItems}, 15 AstIdMap, FileAstId,
17}; 16};
18 17
18/// `RawItems` is a set of top-level items in a file (except for impls).
19///
20/// It is the input to name resolution algorithm. `RawItems` are not invalidated
21/// on most edits.
19#[derive(Debug, Default, PartialEq, Eq)] 22#[derive(Debug, Default, PartialEq, Eq)]
20pub struct RawItems { 23pub struct RawItems {
21 modules: Arena<Module, ModuleData>, 24 modules: Arena<Module, ModuleData>,
@@ -32,11 +35,11 @@ pub struct ImportSourceMap {
32} 35}
33 36
34impl ImportSourceMap { 37impl ImportSourceMap {
35 pub(crate) fn insert(&mut self, import: ImportId, segment: &ast::PathSegment) { 38 fn insert(&mut self, import: ImportId, segment: &ast::PathSegment) {
36 self.map.insert(import, AstPtr::new(segment)) 39 self.map.insert(import, AstPtr::new(segment))
37 } 40 }
38 41
39 pub fn get(&self, source: &ModuleSource, import: ImportId) -> TreeArc<ast::PathSegment> { 42 pub(crate) fn get(&self, source: &ModuleSource, import: ImportId) -> TreeArc<ast::PathSegment> {
40 let file = match source { 43 let file = match source {
41 ModuleSource::SourceFile(file) => &*file, 44 ModuleSource::SourceFile(file) => &*file,
42 ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(), 45 ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(),
@@ -47,40 +50,27 @@ impl ImportSourceMap {
47} 50}
48 51
49impl RawItems { 52impl RawItems {
50 pub(crate) fn raw_items_query(db: &impl DefDatabase, file_id: FileId) -> Arc<RawItems> { 53 pub(crate) fn raw_items_query(db: &impl DefDatabase, file_id: HirFileId) -> Arc<RawItems> {
51 db.raw_items_with_source_map(file_id).0 54 db.raw_items_with_source_map(file_id).0
52 } 55 }
53 56
54 pub(crate) fn raw_items_with_source_map_query( 57 pub(crate) fn raw_items_with_source_map_query(
55 db: &impl DefDatabase, 58 db: &impl DefDatabase,
56 file_id: FileId, 59 file_id: HirFileId,
57 ) -> (Arc<RawItems>, Arc<ImportSourceMap>) { 60 ) -> (Arc<RawItems>, Arc<ImportSourceMap>) {
58 let mut collector = RawItemsCollector { 61 let mut collector = RawItemsCollector {
59 raw_items: RawItems::default(), 62 raw_items: RawItems::default(),
60 source_file_items: db.file_items(file_id.into()), 63 source_ast_id_map: db.ast_id_map(file_id.into()),
61 source_map: ImportSourceMap::default(), 64 source_map: ImportSourceMap::default(),
62 }; 65 };
63 let source_file = db.parse(file_id); 66 let source_file = db.hir_parse(file_id);
64 collector.process_module(None, &*source_file); 67 collector.process_module(None, &*source_file);
65 (Arc::new(collector.raw_items), Arc::new(collector.source_map)) 68 (Arc::new(collector.raw_items), Arc::new(collector.source_map))
66 } 69 }
67 70
68 pub(crate) fn items(&self) -> &[RawItem] { 71 pub(super) fn items(&self) -> &[RawItem] {
69 &self.items 72 &self.items
70 } 73 }
71
72 // We can't use queries during name resolution for fear of cycles, so this
73 // is a query-less variant of the above function.
74 pub(crate) fn from_source_file(source_file: &SourceFile, file_id: HirFileId) -> RawItems {
75 let source_file_items = SourceFileItems::from_source_file(source_file, file_id);
76 let mut collector = RawItemsCollector {
77 raw_items: RawItems::default(),
78 source_file_items: Arc::new(source_file_items),
79 source_map: ImportSourceMap::default(),
80 };
81 collector.process_module(None, &*source_file);
82 collector.raw_items
83 }
84} 74}
85 75
86impl Index<Module> for RawItems { 76impl Index<Module> for RawItems {
@@ -112,7 +102,7 @@ impl Index<Macro> for RawItems {
112} 102}
113 103
114#[derive(Debug, PartialEq, Eq, Clone, Copy)] 104#[derive(Debug, PartialEq, Eq, Clone, Copy)]
115pub(crate) enum RawItem { 105pub(super) enum RawItem {
116 Module(Module), 106 Module(Module),
117 Import(ImportId), 107 Import(ImportId),
118 Def(Def), 108 Def(Def),
@@ -120,13 +110,13 @@ pub(crate) enum RawItem {
120} 110}
121 111
122#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 112#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
123pub(crate) struct Module(RawId); 113pub(super) struct Module(RawId);
124impl_arena_id!(Module); 114impl_arena_id!(Module);
125 115
126#[derive(Debug, PartialEq, Eq)] 116#[derive(Debug, PartialEq, Eq)]
127pub(crate) enum ModuleData { 117pub(super) enum ModuleData {
128 Declaration { name: Name, source_item_id: SourceFileItemId }, 118 Declaration { name: Name, ast_id: FileAstId<ast::Module> },
129 Definition { name: Name, source_item_id: SourceFileItemId, items: Vec<RawItem> }, 119 Definition { name: Name, ast_id: FileAstId<ast::Module>, items: Vec<RawItem> },
130} 120}
131 121
132#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 122#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -135,51 +125,49 @@ impl_arena_id!(ImportId);
135 125
136#[derive(Debug, Clone, PartialEq, Eq)] 126#[derive(Debug, Clone, PartialEq, Eq)]
137pub struct ImportData { 127pub struct ImportData {
138 pub(crate) path: Path, 128 pub(super) path: Path,
139 pub(crate) alias: Option<Name>, 129 pub(super) alias: Option<Name>,
140 pub(crate) is_glob: bool, 130 pub(super) is_glob: bool,
141 pub(crate) is_prelude: bool, 131 pub(super) is_prelude: bool,
142 pub(crate) is_extern_crate: bool, 132 pub(super) is_extern_crate: bool,
143} 133}
144 134
145#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 135#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
146pub(crate) struct Def(RawId); 136pub(super) struct Def(RawId);
147impl_arena_id!(Def); 137impl_arena_id!(Def);
148 138
149#[derive(Debug, PartialEq, Eq)] 139#[derive(Debug, PartialEq, Eq)]
150pub(crate) struct DefData { 140pub(super) struct DefData {
151 pub(crate) source_item_id: SourceFileItemId, 141 pub(super) name: Name,
152 pub(crate) name: Name, 142 pub(super) kind: DefKind,
153 pub(crate) kind: DefKind,
154} 143}
155 144
156#[derive(Debug, PartialEq, Eq, Clone, Copy)] 145#[derive(Debug, PartialEq, Eq, Clone, Copy)]
157pub(crate) enum DefKind { 146pub(super) enum DefKind {
158 Function, 147 Function(FileAstId<ast::FnDef>),
159 Struct, 148 Struct(FileAstId<ast::StructDef>),
160 Enum, 149 Enum(FileAstId<ast::EnumDef>),
161 Const, 150 Const(FileAstId<ast::ConstDef>),
162 Static, 151 Static(FileAstId<ast::StaticDef>),
163 Trait, 152 Trait(FileAstId<ast::TraitDef>),
164 TypeAlias, 153 TypeAlias(FileAstId<ast::TypeAliasDef>),
165} 154}
166 155
167#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 156#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
168pub(crate) struct Macro(RawId); 157pub(super) struct Macro(RawId);
169impl_arena_id!(Macro); 158impl_arena_id!(Macro);
170 159
171#[derive(Debug, PartialEq, Eq)] 160#[derive(Debug, PartialEq, Eq)]
172pub(crate) struct MacroData { 161pub(super) struct MacroData {
173 pub(crate) source_item_id: SourceFileItemId, 162 pub(super) ast_id: FileAstId<ast::MacroCall>,
174 pub(crate) path: Path, 163 pub(super) path: Path,
175 pub(crate) name: Option<Name>, 164 pub(super) name: Option<Name>,
176 pub(crate) arg: tt::Subtree, 165 pub(super) export: bool,
177 pub(crate) export: bool,
178} 166}
179 167
180struct RawItemsCollector { 168struct RawItemsCollector {
181 raw_items: RawItems, 169 raw_items: RawItems,
182 source_file_items: Arc<SourceFileItems>, 170 source_ast_id_map: Arc<AstIdMap>,
183 source_map: ImportSourceMap, 171 source_map: ImportSourceMap,
184} 172}
185 173
@@ -211,18 +199,31 @@ impl RawItemsCollector {
211 // impls don't participate in name resolution 199 // impls don't participate in name resolution
212 return; 200 return;
213 } 201 }
214 ast::ModuleItemKind::StructDef(it) => (DefKind::Struct, it.name()), 202 ast::ModuleItemKind::StructDef(it) => {
215 ast::ModuleItemKind::EnumDef(it) => (DefKind::Enum, it.name()), 203 (DefKind::Struct(self.source_ast_id_map.ast_id(it)), it.name())
216 ast::ModuleItemKind::FnDef(it) => (DefKind::Function, it.name()), 204 }
217 ast::ModuleItemKind::TraitDef(it) => (DefKind::Trait, it.name()), 205 ast::ModuleItemKind::EnumDef(it) => {
218 ast::ModuleItemKind::TypeAliasDef(it) => (DefKind::TypeAlias, it.name()), 206 (DefKind::Enum(self.source_ast_id_map.ast_id(it)), it.name())
219 ast::ModuleItemKind::ConstDef(it) => (DefKind::Const, it.name()), 207 }
220 ast::ModuleItemKind::StaticDef(it) => (DefKind::Static, it.name()), 208 ast::ModuleItemKind::FnDef(it) => {
209 (DefKind::Function(self.source_ast_id_map.ast_id(it)), it.name())
210 }
211 ast::ModuleItemKind::TraitDef(it) => {
212 (DefKind::Trait(self.source_ast_id_map.ast_id(it)), it.name())
213 }
214 ast::ModuleItemKind::TypeAliasDef(it) => {
215 (DefKind::TypeAlias(self.source_ast_id_map.ast_id(it)), it.name())
216 }
217 ast::ModuleItemKind::ConstDef(it) => {
218 (DefKind::Const(self.source_ast_id_map.ast_id(it)), it.name())
219 }
220 ast::ModuleItemKind::StaticDef(it) => {
221 (DefKind::Static(self.source_ast_id_map.ast_id(it)), it.name())
222 }
221 }; 223 };
222 if let Some(name) = name { 224 if let Some(name) = name {
223 let name = name.as_name(); 225 let name = name.as_name();
224 let source_item_id = self.source_file_items.id_of_unchecked(item.syntax()); 226 let def = self.raw_items.defs.alloc(DefData { name, kind });
225 let def = self.raw_items.defs.alloc(DefData { name, kind, source_item_id });
226 self.push_item(current_module, RawItem::Def(def)) 227 self.push_item(current_module, RawItem::Def(def))
227 } 228 }
228 } 229 }
@@ -232,10 +233,9 @@ impl RawItemsCollector {
232 Some(it) => it.as_name(), 233 Some(it) => it.as_name(),
233 None => return, 234 None => return,
234 }; 235 };
235 let source_item_id = self.source_file_items.id_of_unchecked(module.syntax()); 236 let ast_id = self.source_ast_id_map.ast_id(module);
236 if module.has_semi() { 237 if module.has_semi() {
237 let item = 238 let item = self.raw_items.modules.alloc(ModuleData::Declaration { name, ast_id });
238 self.raw_items.modules.alloc(ModuleData::Declaration { name, source_item_id });
239 self.push_item(current_module, RawItem::Module(item)); 239 self.push_item(current_module, RawItem::Module(item));
240 return; 240 return;
241 } 241 }
@@ -243,7 +243,7 @@ impl RawItemsCollector {
243 if let Some(item_list) = module.item_list() { 243 if let Some(item_list) = module.item_list() {
244 let item = self.raw_items.modules.alloc(ModuleData::Definition { 244 let item = self.raw_items.modules.alloc(ModuleData::Definition {
245 name, 245 name,
246 source_item_id, 246 ast_id,
247 items: Vec::new(), 247 items: Vec::new(),
248 }); 248 });
249 self.process_module(Some(item), item_list); 249 self.process_module(Some(item), item_list);
@@ -291,18 +291,15 @@ impl RawItemsCollector {
291 } 291 }
292 292
293 fn add_macro(&mut self, current_module: Option<Module>, m: &ast::MacroCall) { 293 fn add_macro(&mut self, current_module: Option<Module>, m: &ast::MacroCall) {
294 let (path, arg) = match ( 294 let path = match m.path().and_then(Path::from_ast) {
295 m.path().and_then(Path::from_ast), 295 Some(it) => it,
296 m.token_tree().and_then(mbe::ast_to_token_tree),
297 ) {
298 (Some(path), Some((token_tree, _token_map))) => (path, token_tree),
299 _ => return, 296 _ => return,
300 }; 297 };
301 298
302 let name = m.name().map(|it| it.as_name()); 299 let name = m.name().map(|it| it.as_name());
303 let source_item_id = self.source_file_items.id_of_unchecked(m.syntax()); 300 let ast_id = self.source_ast_id_map.ast_id(m);
304 let export = m.has_atom_attr("macro_export"); 301 let export = m.has_atom_attr("macro_export");
305 let m = self.raw_items.macros.alloc(MacroData { source_item_id, path, arg, name, export }); 302 let m = self.raw_items.macros.alloc(MacroData { ast_id, path, name, export });
306 self.push_item(current_module, RawItem::Macro(m)); 303 self.push_item(current_module, RawItem::Macro(m));
307 } 304 }
308 305
diff --git a/crates/ra_hir/src/nameres/tests/incremental.rs b/crates/ra_hir/src/nameres/tests/incremental.rs
index 698781923..001f76ac3 100644
--- a/crates/ra_hir/src/nameres/tests/incremental.rs
+++ b/crates/ra_hir/src/nameres/tests/incremental.rs
@@ -90,34 +90,44 @@ fn adding_inner_items_should_not_invalidate_def_map() {
90 ); 90 );
91} 91}
92 92
93// It would be awesome to make this work, but it's unclear how
94#[test] 93#[test]
95#[ignore] 94fn typing_inside_a_macro_should_not_invalidate_def_map() {
96fn typing_inside_a_function_inside_a_macro_should_not_invalidate_def_map() { 95 let (mut db, pos) = MockDatabase::with_position(
97 check_def_map_is_not_recomputed(
98 " 96 "
99 //- /lib.rs 97 //- /lib.rs
98 macro_rules! m {
99 ($ident:ident) => {
100 fn f() {
101 $ident + $ident;
102 };
103 }
104 }
100 mod foo; 105 mod foo;
101 106
102 use crate::foo::bar::Baz;
103
104 //- /foo/mod.rs 107 //- /foo/mod.rs
105 pub mod bar; 108 pub mod bar;
106 109
107 //- /foo/bar.rs 110 //- /foo/bar.rs
108 <|> 111 <|>
109 salsa::query_group! { 112 m!(X);
110 trait Baz {
111 fn foo() -> i32 { 1 + 1 }
112 }
113 }
114 ",
115 "
116 salsa::query_group! {
117 trait Baz {
118 fn foo() -> i32 { 92 }
119 }
120 }
121 ", 113 ",
122 ); 114 );
115 {
116 let events = db.log_executed(|| {
117 let module = crate::source_binder::module_from_file_id(&db, pos.file_id).unwrap();
118 let decls = module.declarations(&db);
119 assert_eq!(decls.len(), 1);
120 });
121 assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events)
122 }
123 db.set_file_text(pos.file_id, Arc::new("m!(Y);".to_string()));
124
125 {
126 let events = db.log_executed(|| {
127 let module = crate::source_binder::module_from_file_id(&db, pos.file_id).unwrap();
128 let decls = module.declarations(&db);
129 assert_eq!(decls.len(), 1);
130 });
131 assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events)
132 }
123} 133}
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs
index f28154517..2609585b1 100644
--- a/crates/ra_hir/src/resolve.rs
+++ b/crates/ra_hir/src/resolve.rs
@@ -11,7 +11,7 @@ use crate::{
11 generics::GenericParams, 11 generics::GenericParams,
12 expr::{scope::{ExprScopes, ScopeId}, PatId, Body}, 12 expr::{scope::{ExprScopes, ScopeId}, PatId, Body},
13 impl_block::ImplBlock, 13 impl_block::ImplBlock,
14 path::Path, 14 path::Path, Trait
15}; 15};
16 16
17#[derive(Debug, Clone, Default)] 17#[derive(Debug, Clone, Default)]
@@ -175,6 +175,21 @@ impl Resolver {
175 names 175 names
176 } 176 }
177 177
178 pub(crate) fn traits_in_scope<'a>(&'a self) -> impl Iterator<Item = Trait> + 'a {
179 // FIXME prelude
180 self.scopes
181 .iter()
182 .rev()
183 .flat_map(|scope| {
184 match scope {
185 Scope::ModuleScope(m) => Some(m.crate_def_map[m.module_id].scope.traits()),
186 _ => None,
187 }
188 .into_iter()
189 })
190 .flatten()
191 }
192
178 fn module(&self) -> Option<(&CrateDefMap, CrateModuleId)> { 193 fn module(&self) -> Option<(&CrateDefMap, CrateModuleId)> {
179 self.scopes.iter().rev().find_map(|scope| match scope { 194 self.scopes.iter().rev().find_map(|scope| match scope {
180 Scope::ModuleScope(m) => Some((&*m.crate_def_map, m.module_id)), 195 Scope::ModuleScope(m) => Some((&*m.crate_def_map, m.module_id)),
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index 3645b73b4..9dae4c3d1 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -15,8 +15,8 @@ use ra_syntax::{
15use crate::{ 15use crate::{
16 HirDatabase, Function, Struct, Enum, 16 HirDatabase, Function, Struct, Enum,
17 AsName, Module, HirFileId, Crate, Trait, Resolver, 17 AsName, Module, HirFileId, Crate, Trait, Resolver,
18 ids::{LocationCtx, SourceFileItemId}, 18 ids::LocationCtx,
19 expr 19 expr, AstId
20}; 20};
21 21
22/// Locates the module by `FileId`. Picks topmost module in the file. 22/// Locates the module by `FileId`. Picks topmost module in the file.
@@ -54,8 +54,8 @@ fn module_from_inline(
54) -> Option<Module> { 54) -> Option<Module> {
55 assert!(!module.has_semi()); 55 assert!(!module.has_semi());
56 let file_id = file_id.into(); 56 let file_id = file_id.into();
57 let file_items = db.file_items(file_id); 57 let ast_id_map = db.ast_id_map(file_id);
58 let item_id = file_items.id_of(file_id, module.syntax()); 58 let item_id = ast_id_map.ast_id(module).with_file_id(file_id);
59 module_from_source(db, file_id, Some(item_id)) 59 module_from_source(db, file_id, Some(item_id))
60} 60}
61 61
@@ -75,7 +75,7 @@ pub fn module_from_child_node(
75fn module_from_source( 75fn module_from_source(
76 db: &impl HirDatabase, 76 db: &impl HirDatabase,
77 file_id: HirFileId, 77 file_id: HirFileId,
78 decl_id: Option<SourceFileItemId>, 78 decl_id: Option<AstId<ast::Module>>,
79) -> Option<Module> { 79) -> Option<Module> {
80 let source_root_id = db.file_source_root(file_id.as_original_file()); 80 let source_root_id = db.file_source_root(file_id.as_original_file());
81 db.source_root_crates(source_root_id).iter().map(|&crate_id| Crate { crate_id }).find_map( 81 db.source_root_crates(source_root_id).iter().map(|&crate_id| Crate { crate_id }).find_map(
diff --git a/crates/ra_hir/src/source_id.rs b/crates/ra_hir/src/source_id.rs
new file mode 100644
index 000000000..0a8fb6d32
--- /dev/null
+++ b/crates/ra_hir/src/source_id.rs
@@ -0,0 +1,150 @@
1use std::{marker::PhantomData, sync::Arc, hash::{Hash, Hasher}};
2
3use ra_arena::{Arena, RawId, impl_arena_id};
4use ra_syntax::{SyntaxNodePtr, TreeArc, SyntaxNode, SourceFile, AstNode, ast};
5
6use crate::{HirFileId, DefDatabase};
7
8/// `AstId` points to an AST node in any file.
9///
10/// It is stable across reparses, and can be used as salsa key/value.
11#[derive(Debug)]
12pub(crate) struct AstId<N: AstNode> {
13 file_id: HirFileId,
14 file_ast_id: FileAstId<N>,
15}
16
17impl<N: AstNode> Clone for AstId<N> {
18 fn clone(&self) -> AstId<N> {
19 *self
20 }
21}
22impl<N: AstNode> Copy for AstId<N> {}
23
24impl<N: AstNode> PartialEq for AstId<N> {
25 fn eq(&self, other: &Self) -> bool {
26 (self.file_id, self.file_ast_id) == (other.file_id, other.file_ast_id)
27 }
28}
29impl<N: AstNode> Eq for AstId<N> {}
30impl<N: AstNode> Hash for AstId<N> {
31 fn hash<H: Hasher>(&self, hasher: &mut H) {
32 (self.file_id, self.file_ast_id).hash(hasher);
33 }
34}
35
36impl<N: AstNode> AstId<N> {
37 pub(crate) fn file_id(&self) -> HirFileId {
38 self.file_id
39 }
40
41 pub(crate) fn to_node(&self, db: &impl DefDatabase) -> TreeArc<N> {
42 let syntax_node = db.ast_id_to_node(self.file_id, self.file_ast_id.raw);
43 N::cast(&syntax_node).unwrap().to_owned()
44 }
45}
46
47/// `AstId` points to an AST node in a specific file.
48#[derive(Debug)]
49pub(crate) struct FileAstId<N: AstNode> {
50 raw: ErasedFileAstId,
51 _ty: PhantomData<N>,
52}
53
54impl<N: AstNode> Clone for FileAstId<N> {
55 fn clone(&self) -> FileAstId<N> {
56 *self
57 }
58}
59impl<N: AstNode> Copy for FileAstId<N> {}
60
61impl<N: AstNode> PartialEq for FileAstId<N> {
62 fn eq(&self, other: &Self) -> bool {
63 self.raw == other.raw
64 }
65}
66impl<N: AstNode> Eq for FileAstId<N> {}
67impl<N: AstNode> Hash for FileAstId<N> {
68 fn hash<H: Hasher>(&self, hasher: &mut H) {
69 self.raw.hash(hasher);
70 }
71}
72
73impl<N: AstNode> FileAstId<N> {
74 pub(crate) fn with_file_id(self, file_id: HirFileId) -> AstId<N> {
75 AstId { file_id, file_ast_id: self }
76 }
77}
78
79#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
80pub struct ErasedFileAstId(RawId);
81impl_arena_id!(ErasedFileAstId);
82
83/// Maps items' `SyntaxNode`s to `ErasedFileAstId`s and back.
84#[derive(Debug, PartialEq, Eq)]
85pub struct AstIdMap {
86 arena: Arena<ErasedFileAstId, SyntaxNodePtr>,
87}
88
89impl AstIdMap {
90 pub(crate) fn ast_id_map_query(db: &impl DefDatabase, file_id: HirFileId) -> Arc<AstIdMap> {
91 let source_file = db.hir_parse(file_id);
92 Arc::new(AstIdMap::from_source_file(&source_file))
93 }
94
95 pub(crate) fn file_item_query(
96 db: &impl DefDatabase,
97 file_id: HirFileId,
98 ast_id: ErasedFileAstId,
99 ) -> TreeArc<SyntaxNode> {
100 let source_file = db.hir_parse(file_id);
101 db.ast_id_map(file_id).arena[ast_id].to_node(&source_file).to_owned()
102 }
103
104 pub(crate) fn ast_id<N: AstNode>(&self, item: &N) -> FileAstId<N> {
105 let ptr = SyntaxNodePtr::new(item.syntax());
106 let raw = match self.arena.iter().find(|(_id, i)| **i == ptr) {
107 Some((it, _)) => it,
108 None => panic!(
109 "Can't find {:?} in AstIdMap:\n{:?}",
110 item.syntax(),
111 self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(),
112 ),
113 };
114
115 FileAstId { raw, _ty: PhantomData }
116 }
117
118 fn from_source_file(source_file: &SourceFile) -> AstIdMap {
119 let mut res = AstIdMap { arena: Arena::default() };
120 // By walking the tree in bread-first order we make sure that parents
121 // get lower ids then children. That is, adding a new child does not
122 // change parent's id. This means that, say, adding a new function to a
123 // trait does not change ids of top-level items, which helps caching.
124 bfs(source_file.syntax(), |it| {
125 if let Some(module_item) = ast::ModuleItem::cast(it) {
126 res.alloc(module_item.syntax());
127 } else if let Some(macro_call) = ast::MacroCall::cast(it) {
128 res.alloc(macro_call.syntax());
129 }
130 });
131 res
132 }
133
134 fn alloc(&mut self, item: &SyntaxNode) -> ErasedFileAstId {
135 self.arena.alloc(SyntaxNodePtr::new(item))
136 }
137}
138
139/// Walks the subtree in bfs order, calling `f` for each node.
140fn bfs(node: &SyntaxNode, mut f: impl FnMut(&SyntaxNode)) {
141 let mut curr_layer = vec![node];
142 let mut next_layer = vec![];
143 while !curr_layer.is_empty() {
144 curr_layer.drain(..).for_each(|node| {
145 next_layer.extend(node.children());
146 f(node);
147 });
148 std::mem::swap(&mut curr_layer, &mut next_layer);
149 }
150}
diff --git a/crates/ra_hir/src/traits.rs b/crates/ra_hir/src/traits.rs
new file mode 100644
index 000000000..725bdd5cb
--- /dev/null
+++ b/crates/ra_hir/src/traits.rs
@@ -0,0 +1,52 @@
1//! HIR for trait definitions.
2
3use std::sync::Arc;
4
5use ra_syntax::ast::{self, NameOwner};
6
7use crate::{Function, Const, TypeAlias, Name, DefDatabase, Trait, ids::LocationCtx, name::AsName};
8
9#[derive(Debug, Clone, PartialEq, Eq)]
10pub struct TraitData {
11 name: Option<Name>,
12 items: Vec<TraitItem>,
13}
14
15impl TraitData {
16 pub(crate) fn trait_data_query(db: &impl DefDatabase, tr: Trait) -> Arc<TraitData> {
17 let (file_id, node) = tr.source(db);
18 let name = node.name().map(|n| n.as_name());
19 let module = tr.module(db);
20 let ctx = LocationCtx::new(db, module, file_id);
21 let items = if let Some(item_list) = node.item_list() {
22 item_list
23 .impl_items()
24 .map(|item_node| match item_node.kind() {
25 ast::ImplItemKind::FnDef(it) => Function { id: ctx.to_def(it) }.into(),
26 ast::ImplItemKind::ConstDef(it) => Const { id: ctx.to_def(it) }.into(),
27 ast::ImplItemKind::TypeAliasDef(it) => TypeAlias { id: ctx.to_def(it) }.into(),
28 })
29 .collect()
30 } else {
31 Vec::new()
32 };
33 Arc::new(TraitData { name, items })
34 }
35
36 pub(crate) fn name(&self) -> &Option<Name> {
37 &self.name
38 }
39
40 pub(crate) fn items(&self) -> &[TraitItem] {
41 &self.items
42 }
43}
44
45#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
46pub enum TraitItem {
47 Function(Function),
48 Const(Const),
49 TypeAlias(TypeAlias),
50 // Existential
51}
52impl_froms!(TraitItem: Function, Const, TypeAlias);
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index 7d25ade47..d42c61e9d 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -14,7 +14,7 @@ pub(crate) mod display;
14use std::sync::Arc; 14use std::sync::Arc;
15use std::{fmt, mem}; 15use std::{fmt, mem};
16 16
17use crate::{Name, AdtDef, type_ref::Mutability, db::HirDatabase}; 17use crate::{Name, AdtDef, type_ref::Mutability, db::HirDatabase, Trait};
18 18
19pub(crate) use lower::{TypableDef, CallableDef, type_for_def, type_for_field, callable_item_sig}; 19pub(crate) use lower::{TypableDef, CallableDef, type_for_def, type_for_field, callable_item_sig};
20pub(crate) use infer::{infer, InferenceResult, InferTy}; 20pub(crate) use infer::{infer, InferenceResult, InferTy};
@@ -91,7 +91,7 @@ pub enum TypeCtor {
91/// A nominal type with (maybe 0) type parameters. This might be a primitive 91/// A nominal type with (maybe 0) type parameters. This might be a primitive
92/// type like `bool`, a struct, tuple, function pointer, reference or 92/// type like `bool`, a struct, tuple, function pointer, reference or
93/// several other things. 93/// several other things.
94#[derive(Clone, PartialEq, Eq, Debug)] 94#[derive(Clone, PartialEq, Eq, Debug, Hash)]
95pub struct ApplicationTy { 95pub struct ApplicationTy {
96 pub ctor: TypeCtor, 96 pub ctor: TypeCtor,
97 pub parameters: Substs, 97 pub parameters: Substs,
@@ -103,7 +103,7 @@ pub struct ApplicationTy {
103/// the same thing (but in a different way). 103/// the same thing (but in a different way).
104/// 104///
105/// This should be cheap to clone. 105/// This should be cheap to clone.
106#[derive(Clone, PartialEq, Eq, Debug)] 106#[derive(Clone, PartialEq, Eq, Debug, Hash)]
107pub enum Ty { 107pub enum Ty {
108 /// A nominal type with (maybe 0) type parameters. This might be a primitive 108 /// A nominal type with (maybe 0) type parameters. This might be a primitive
109 /// type like `bool`, a struct, tuple, function pointer, reference or 109 /// type like `bool`, a struct, tuple, function pointer, reference or
@@ -132,7 +132,7 @@ pub enum Ty {
132} 132}
133 133
134/// A list of substitutions for generic parameters. 134/// A list of substitutions for generic parameters.
135#[derive(Clone, PartialEq, Eq, Debug)] 135#[derive(Clone, PartialEq, Eq, Debug, Hash)]
136pub struct Substs(Arc<[Ty]>); 136pub struct Substs(Arc<[Ty]>);
137 137
138impl Substs { 138impl Substs {
@@ -169,6 +169,21 @@ impl Substs {
169 } 169 }
170} 170}
171 171
172/// A trait with type parameters. This includes the `Self`, so this represents a concrete type implementing the trait.
173/// Name to be bikeshedded: TraitBound? TraitImplements?
174#[derive(Clone, PartialEq, Eq, Debug, Hash)]
175pub struct TraitRef {
176 /// FIXME name?
177 trait_: Trait,
178 substs: Substs,
179}
180
181impl TraitRef {
182 pub fn self_ty(&self) -> &Ty {
183 &self.substs.0[0]
184 }
185}
186
172/// A function signature as seen by type inference: Several parameter types and 187/// A function signature as seen by type inference: Several parameter types and
173/// one return type. 188/// one return type.
174#[derive(Clone, PartialEq, Eq, Debug)] 189#[derive(Clone, PartialEq, Eq, Debug)]
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index 5fd602a9e..573115321 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -821,7 +821,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
821 } 821 }
822 Expr::MethodCall { receiver, args, method_name, generic_args } => { 822 Expr::MethodCall { receiver, args, method_name, generic_args } => {
823 let receiver_ty = self.infer_expr(*receiver, &Expectation::none()); 823 let receiver_ty = self.infer_expr(*receiver, &Expectation::none());
824 let resolved = receiver_ty.clone().lookup_method(self.db, method_name); 824 let resolved =
825 receiver_ty.clone().lookup_method(self.db, method_name, &self.resolver);
825 let (derefed_receiver_ty, method_ty, def_generics) = match resolved { 826 let (derefed_receiver_ty, method_ty, def_generics) = match resolved {
826 Some((ty, func)) => { 827 Some((ty, func)) => {
827 self.write_method_resolution(tgt_expr, func); 828 self.write_method_resolution(tgt_expr, func);
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index b1684acf9..3ac8dc46b 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -8,12 +8,12 @@ use rustc_hash::FxHashMap;
8 8
9use crate::{ 9use crate::{
10 HirDatabase, Module, Crate, Name, Function, Trait, 10 HirDatabase, Module, Crate, Name, Function, Trait,
11 ids::TraitId,
12 impl_block::{ImplId, ImplBlock, ImplItem}, 11 impl_block::{ImplId, ImplBlock, ImplItem},
13 ty::{Ty, TypeCtor}, 12 ty::{Ty, TypeCtor},
14 nameres::CrateModuleId, 13 nameres::CrateModuleId, resolve::Resolver, traits::TraitItem
15 14
16}; 15};
16use super::{ TraitRef, Substs};
17 17
18/// This is used as a key for indexing impls. 18/// This is used as a key for indexing impls.
19#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 19#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
@@ -38,7 +38,7 @@ pub struct CrateImplBlocks {
38 /// To make sense of the CrateModuleIds, we need the source root. 38 /// To make sense of the CrateModuleIds, we need the source root.
39 krate: Crate, 39 krate: Crate,
40 impls: FxHashMap<TyFingerprint, Vec<(CrateModuleId, ImplId)>>, 40 impls: FxHashMap<TyFingerprint, Vec<(CrateModuleId, ImplId)>>,
41 impls_by_trait: FxHashMap<TraitId, Vec<(CrateModuleId, ImplId)>>, 41 impls_by_trait: FxHashMap<Trait, Vec<(CrateModuleId, ImplId)>>,
42} 42}
43 43
44impl CrateImplBlocks { 44impl CrateImplBlocks {
@@ -56,8 +56,7 @@ impl CrateImplBlocks {
56 &'a self, 56 &'a self,
57 tr: &Trait, 57 tr: &Trait,
58 ) -> impl Iterator<Item = ImplBlock> + 'a { 58 ) -> impl Iterator<Item = ImplBlock> + 'a {
59 let id = tr.id; 59 self.impls_by_trait.get(&tr).into_iter().flat_map(|i| i.iter()).map(
60 self.impls_by_trait.get(&id).into_iter().flat_map(|i| i.iter()).map(
61 move |(module_id, impl_id)| { 60 move |(module_id, impl_id)| {
62 let module = Module { krate: self.krate, module_id: *module_id }; 61 let module = Module { krate: self.krate, module_id: *module_id };
63 ImplBlock::from_id(module, *impl_id) 62 ImplBlock::from_id(module, *impl_id)
@@ -73,18 +72,18 @@ impl CrateImplBlocks {
73 72
74 let target_ty = impl_block.target_ty(db); 73 let target_ty = impl_block.target_ty(db);
75 74
76 if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) {
77 self.impls
78 .entry(target_ty_fp)
79 .or_insert_with(Vec::new)
80 .push((module.module_id, impl_id));
81 }
82
83 if let Some(tr) = impl_block.target_trait(db) { 75 if let Some(tr) = impl_block.target_trait(db) {
84 self.impls_by_trait 76 self.impls_by_trait
85 .entry(tr.id) 77 .entry(tr)
86 .or_insert_with(Vec::new) 78 .or_insert_with(Vec::new)
87 .push((module.module_id, impl_id)); 79 .push((module.module_id, impl_id));
80 } else {
81 if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) {
82 self.impls
83 .entry(target_ty_fp)
84 .or_insert_with(Vec::new)
85 .push((module.module_id, impl_id));
86 }
88 } 87 }
89 } 88 }
90 89
@@ -109,6 +108,20 @@ impl CrateImplBlocks {
109 } 108 }
110} 109}
111 110
111/// Rudimentary check whether an impl exists for a given type and trait; this
112/// will actually be done by chalk.
113pub(crate) fn implements(db: &impl HirDatabase, trait_ref: TraitRef) -> bool {
114 // FIXME use all trait impls in the whole crate graph
115 let krate = trait_ref.trait_.module(db).krate(db);
116 let krate = match krate {
117 Some(krate) => krate,
118 None => return false,
119 };
120 let crate_impl_blocks = db.impls_in_crate(krate);
121 let mut impl_blocks = crate_impl_blocks.lookup_impl_blocks_for_trait(&trait_ref.trait_);
122 impl_blocks.any(|impl_block| &impl_block.target_ty(db) == trait_ref.self_ty())
123}
124
112fn def_crate(db: &impl HirDatabase, ty: &Ty) -> Option<Crate> { 125fn def_crate(db: &impl HirDatabase, ty: &Ty) -> Option<Crate> {
113 match ty { 126 match ty {
114 Ty::Apply(a_ty) => match a_ty.ctor { 127 Ty::Apply(a_ty) => match a_ty.ctor {
@@ -120,20 +133,64 @@ fn def_crate(db: &impl HirDatabase, ty: &Ty) -> Option<Crate> {
120} 133}
121 134
122impl Ty { 135impl Ty {
123 // FIXME: cache this as a query?
124 // - if so, what signature? (TyFingerprint, Name)?
125 // - or maybe cache all names and def_ids of methods per fingerprint?
126 /// Look up the method with the given name, returning the actual autoderefed 136 /// Look up the method with the given name, returning the actual autoderefed
127 /// receiver type (but without autoref applied yet). 137 /// receiver type (but without autoref applied yet).
128 pub fn lookup_method(self, db: &impl HirDatabase, name: &Name) -> Option<(Ty, Function)> { 138 pub fn lookup_method(
129 self.iterate_methods(db, |ty, f| { 139 self,
140 db: &impl HirDatabase,
141 name: &Name,
142 resolver: &Resolver,
143 ) -> Option<(Ty, Function)> {
144 // FIXME: trait methods should be used before autoderefs
145 let inherent_method = self.clone().iterate_methods(db, |ty, f| {
130 let sig = f.signature(db); 146 let sig = f.signature(db);
131 if sig.name() == name && sig.has_self_param() { 147 if sig.name() == name && sig.has_self_param() {
132 Some((ty.clone(), f)) 148 Some((ty.clone(), f))
133 } else { 149 } else {
134 None 150 None
135 } 151 }
136 }) 152 });
153 inherent_method.or_else(|| self.lookup_trait_method(db, name, resolver))
154 }
155
156 fn lookup_trait_method(
157 self,
158 db: &impl HirDatabase,
159 name: &Name,
160 resolver: &Resolver,
161 ) -> Option<(Ty, Function)> {
162 let mut candidates = Vec::new();
163 for t in resolver.traits_in_scope() {
164 let data = t.trait_data(db);
165 for item in data.items() {
166 match item {
167 &TraitItem::Function(m) => {
168 let sig = m.signature(db);
169 if sig.name() == name && sig.has_self_param() {
170 candidates.push((t, m));
171 }
172 }
173 _ => {}
174 }
175 }
176 }
177 // FIXME:
178 // - we might not actually be able to determine fully that the type
179 // implements the trait here; it's enough if we (well, Chalk) determine
180 // that it's possible.
181 // - when the trait method is picked, we need to register an
182 // 'obligation' somewhere so that we later check that it's really
183 // implemented
184 // - both points go for additional requirements from where clauses as
185 // well (in fact, the 'implements' condition could just be considered a
186 // 'where Self: Trait' clause)
187 candidates.retain(|(t, _m)| {
188 let trait_ref = TraitRef { trait_: *t, substs: Substs::single(self.clone()) };
189 db.implements(trait_ref)
190 });
191 // FIXME if there's multiple candidates here, that's an ambiguity error
192 let (_chosen_trait, chosen_method) = candidates.first()?;
193 Some((self.clone(), *chosen_method))
137 } 194 }
138 195
139 // This would be nicer if it just returned an iterator, but that runs into 196 // This would be nicer if it just returned an iterator, but that runs into
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 3aedba243..655f3c522 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -1272,8 +1272,8 @@ fn test() {
1272[241; 252) 'Struct::FOO': u32 1272[241; 252) 'Struct::FOO': u32
1273[262; 263) 'y': u32 1273[262; 263) 'y': u32
1274[266; 275) 'Enum::BAR': u32 1274[266; 275) 'Enum::BAR': u32
1275[285; 286) 'z': u32 1275[285; 286) 'z': {unknown}
1276[289; 302) 'TraitTest::ID': u32"### 1276[289; 302) 'TraitTest::ID': {unknown}"###
1277 ); 1277 );
1278} 1278}
1279 1279
@@ -1918,9 +1918,9 @@ fn test() {
1918[110; 114) 'self': &{unknown} 1918[110; 114) 'self': &{unknown}
1919[170; 228) '{ ...i128 }': () 1919[170; 228) '{ ...i128 }': ()
1920[176; 178) 'S1': S1 1920[176; 178) 'S1': S1
1921[176; 187) 'S1.method()': {unknown} 1921[176; 187) 'S1.method()': u32
1922[203; 205) 'S2': S2 1922[203; 205) 'S2': S2
1923[203; 214) 'S2.method()': {unknown}"### 1923[203; 214) 'S2.method()': i128"###
1924 ); 1924 );
1925} 1925}
1926 1926
@@ -1964,10 +1964,10 @@ mod bar_test {
1964[169; 173) 'self': &{unknown} 1964[169; 173) 'self': &{unknown}
1965[300; 337) '{ ... }': () 1965[300; 337) '{ ... }': ()
1966[310; 311) 'S': S 1966[310; 311) 'S': S
1967[310; 320) 'S.method()': {unknown} 1967[310; 320) 'S.method()': u32
1968[416; 454) '{ ... }': () 1968[416; 454) '{ ... }': ()
1969[426; 427) 'S': S 1969[426; 427) 'S': S
1970[426; 436) 'S.method()': {unknown}"### 1970[426; 436) 'S.method()': i128"###
1971 ); 1971 );
1972} 1972}
1973 1973
diff --git a/crates/ra_ide_api/src/change.rs b/crates/ra_ide_api/src/change.rs
index 26fde91bc..a4a086931 100644
--- a/crates/ra_ide_api/src/change.rs
+++ b/crates/ra_ide_api/src/change.rs
@@ -220,8 +220,8 @@ impl RootDatabase {
220 self.query(ra_db::ParseQuery).sweep(sweep); 220 self.query(ra_db::ParseQuery).sweep(sweep);
221 221
222 self.query(hir::db::HirParseQuery).sweep(sweep); 222 self.query(hir::db::HirParseQuery).sweep(sweep);
223 self.query(hir::db::FileItemsQuery).sweep(sweep); 223 self.query(hir::db::AstIdMapQuery).sweep(sweep);
224 self.query(hir::db::FileItemQuery).sweep(sweep); 224 self.query(hir::db::AstIdToNodeQuery).sweep(sweep);
225 225
226 self.query(hir::db::RawItemsWithSourceMapQuery).sweep(sweep); 226 self.query(hir::db::RawItemsWithSourceMapQuery).sweep(sweep);
227 self.query(hir::db::BodyWithSourceMapQuery).sweep(sweep); 227 self.query(hir::db::BodyWithSourceMapQuery).sweep(sweep);
diff --git a/crates/ra_ide_api/src/parent_module.rs b/crates/ra_ide_api/src/parent_module.rs
index 603c3db6a..27788c984 100644
--- a/crates/ra_ide_api/src/parent_module.rs
+++ b/crates/ra_ide_api/src/parent_module.rs
@@ -28,7 +28,11 @@ pub(crate) fn crate_for(db: &RootDatabase, file_id: FileId) -> Vec<CrateId> {
28 28
29#[cfg(test)] 29#[cfg(test)]
30mod tests { 30mod tests {
31 use crate::mock_analysis::analysis_and_position; 31 use crate::{
32 AnalysisChange, CrateGraph,
33 mock_analysis::{analysis_and_position, MockAnalysis},
34 Edition::Edition2018,
35};
32 36
33 #[test] 37 #[test]
34 fn test_resolve_parent_module() { 38 fn test_resolve_parent_module() {
@@ -59,4 +63,28 @@ mod tests {
59 let nav = analysis.parent_module(pos).unwrap().pop().unwrap(); 63 let nav = analysis.parent_module(pos).unwrap().pop().unwrap();
60 nav.assert_match("baz MODULE FileId(1) [32; 44)"); 64 nav.assert_match("baz MODULE FileId(1) [32; 44)");
61 } 65 }
66
67 #[test]
68 fn test_resolve_crate_root() {
69 let mock = MockAnalysis::with_files(
70 "
71 //- /bar.rs
72 mod foo;
73 //- /foo.rs
74 // empty <|>
75 ",
76 );
77 let root_file = mock.id_of("/bar.rs");
78 let mod_file = mock.id_of("/foo.rs");
79 let mut host = mock.analysis_host();
80 assert!(host.analysis().crate_for(mod_file).unwrap().is_empty());
81
82 let mut crate_graph = CrateGraph::default();
83 let crate_id = crate_graph.add_crate_root(root_file, Edition2018);
84 let mut change = AnalysisChange::new();
85 change.set_crate_graph(crate_graph);
86 host.apply_change(change);
87
88 assert_eq!(host.analysis().crate_for(mod_file).unwrap(), vec![crate_id]);
89 }
62} 90}
diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs
index 22741445a..20bbf11a3 100644
--- a/crates/ra_ide_api/src/references.rs
+++ b/crates/ra_ide_api/src/references.rs
@@ -216,10 +216,56 @@ mod tests {
216 use crate::{ 216 use crate::{
217 mock_analysis::single_file_with_position, 217 mock_analysis::single_file_with_position,
218 mock_analysis::analysis_and_position, 218 mock_analysis::analysis_and_position,
219 FileId 219 FileId, ReferenceSearchResult
220}; 220};
221 221
222 #[test] 222 #[test]
223 fn test_find_all_refs_for_local() {
224 let code = r#"
225 fn main() {
226 let mut i = 1;
227 let j = 1;
228 i = i<|> + j;
229
230 {
231 i = 0;
232 }
233
234 i = 5;
235 }"#;
236
237 let refs = get_all_refs(code);
238 assert_eq!(refs.len(), 5);
239 }
240
241 #[test]
242 fn test_find_all_refs_for_param_inside() {
243 let code = r#"
244 fn foo(i : u32) -> u32 {
245 i<|>
246 }"#;
247
248 let refs = get_all_refs(code);
249 assert_eq!(refs.len(), 2);
250 }
251
252 #[test]
253 fn test_find_all_refs_for_fn_param() {
254 let code = r#"
255 fn foo(i<|> : u32) -> u32 {
256 i
257 }"#;
258
259 let refs = get_all_refs(code);
260 assert_eq!(refs.len(), 2);
261 }
262
263 fn get_all_refs(text: &str) -> ReferenceSearchResult {
264 let (analysis, position) = single_file_with_position(text);
265 analysis.find_all_refs(position).unwrap().unwrap()
266 }
267
268 #[test]
223 fn test_rename_for_local() { 269 fn test_rename_for_local() {
224 test_rename( 270 test_rename(
225 r#" 271 r#"
diff --git a/crates/ra_ide_api/src/symbol_index.rs b/crates/ra_ide_api/src/symbol_index.rs
index 0978d164a..0eadc4e71 100644
--- a/crates/ra_ide_api/src/symbol_index.rs
+++ b/crates/ra_ide_api/src/symbol_index.rs
@@ -270,3 +270,61 @@ fn to_file_symbol(node: &SyntaxNode, file_id: FileId) -> Option<FileSymbol> {
270 container_name: None, 270 container_name: None,
271 }) 271 })
272} 272}
273
274#[cfg(test)]
275mod tests {
276 use ra_syntax::SmolStr;
277 use crate::{
278 navigation_target::NavigationTarget,
279 mock_analysis::single_file,
280 Query,
281};
282
283 #[test]
284 fn test_world_symbols_with_no_container() {
285 let code = r#"
286 enum FooInner { }
287 "#;
288
289 let mut symbols = get_symbols_matching(code, "FooInner");
290
291 let s = symbols.pop().unwrap();
292
293 assert_eq!(s.name(), "FooInner");
294 assert!(s.container_name().is_none());
295 }
296
297 #[test]
298 fn test_world_symbols_include_container_name() {
299 let code = r#"
300fn foo() {
301 enum FooInner { }
302}
303 "#;
304
305 let mut symbols = get_symbols_matching(code, "FooInner");
306
307 let s = symbols.pop().unwrap();
308
309 assert_eq!(s.name(), "FooInner");
310 assert_eq!(s.container_name(), Some(&SmolStr::new("foo")));
311
312 let code = r#"
313mod foo {
314 struct FooInner;
315}
316 "#;
317
318 let mut symbols = get_symbols_matching(code, "FooInner");
319
320 let s = symbols.pop().unwrap();
321
322 assert_eq!(s.name(), "FooInner");
323 assert_eq!(s.container_name(), Some(&SmolStr::new("foo")));
324 }
325
326 fn get_symbols_matching(text: &str, query: &str) -> Vec<NavigationTarget> {
327 let (analysis, _) = single_file(text);
328 analysis.symbol_search(Query::new(query.into())).unwrap()
329 }
330}
diff --git a/crates/ra_ide_api/src/syntax_tree.rs b/crates/ra_ide_api/src/syntax_tree.rs
index bbe9222b4..276f8a8c8 100644
--- a/crates/ra_ide_api/src/syntax_tree.rs
+++ b/crates/ra_ide_api/src/syntax_tree.rs
@@ -85,3 +85,260 @@ fn syntax_tree_for_token<T: AstToken>(node: &T, text_range: TextRange) -> Option
85 85
86 None 86 None
87} 87}
88
89#[cfg(test)]
90mod tests {
91 use crate::mock_analysis::{single_file, single_file_with_range};
92
93 #[test]
94 fn test_syntax_tree_without_range() {
95 // Basic syntax
96 let (analysis, file_id) = single_file(r#"fn foo() {}"#);
97 let syn = analysis.syntax_tree(file_id, None);
98
99 assert_eq!(
100 syn.trim(),
101 r#"
102SOURCE_FILE@[0; 11)
103 FN_DEF@[0; 11)
104 FN_KW@[0; 2)
105 WHITESPACE@[2; 3)
106 NAME@[3; 6)
107 IDENT@[3; 6) "foo"
108 PARAM_LIST@[6; 8)
109 L_PAREN@[6; 7)
110 R_PAREN@[7; 8)
111 WHITESPACE@[8; 9)
112 BLOCK@[9; 11)
113 L_CURLY@[9; 10)
114 R_CURLY@[10; 11)
115 "#
116 .trim()
117 );
118
119 let (analysis, file_id) = single_file(
120 r#"
121fn test() {
122 assert!("
123 fn foo() {
124 }
125 ", "");
126}"#
127 .trim(),
128 );
129 let syn = analysis.syntax_tree(file_id, None);
130
131 assert_eq!(
132 syn.trim(),
133 r#"
134SOURCE_FILE@[0; 60)
135 FN_DEF@[0; 60)
136 FN_KW@[0; 2)
137 WHITESPACE@[2; 3)
138 NAME@[3; 7)
139 IDENT@[3; 7) "test"
140 PARAM_LIST@[7; 9)
141 L_PAREN@[7; 8)
142 R_PAREN@[8; 9)
143 WHITESPACE@[9; 10)
144 BLOCK@[10; 60)
145 L_CURLY@[10; 11)
146 WHITESPACE@[11; 16)
147 EXPR_STMT@[16; 58)
148 MACRO_CALL@[16; 57)
149 PATH@[16; 22)
150 PATH_SEGMENT@[16; 22)
151 NAME_REF@[16; 22)
152 IDENT@[16; 22) "assert"
153 EXCL@[22; 23)
154 TOKEN_TREE@[23; 57)
155 L_PAREN@[23; 24)
156 STRING@[24; 52)
157 COMMA@[52; 53)
158 WHITESPACE@[53; 54)
159 STRING@[54; 56)
160 R_PAREN@[56; 57)
161 SEMI@[57; 58)
162 WHITESPACE@[58; 59)
163 R_CURLY@[59; 60)
164 "#
165 .trim()
166 );
167 }
168
169 #[test]
170 fn test_syntax_tree_with_range() {
171 let (analysis, range) = single_file_with_range(r#"<|>fn foo() {}<|>"#.trim());
172 let syn = analysis.syntax_tree(range.file_id, Some(range.range));
173
174 assert_eq!(
175 syn.trim(),
176 r#"
177FN_DEF@[0; 11)
178 FN_KW@[0; 2)
179 WHITESPACE@[2; 3)
180 NAME@[3; 6)
181 IDENT@[3; 6) "foo"
182 PARAM_LIST@[6; 8)
183 L_PAREN@[6; 7)
184 R_PAREN@[7; 8)
185 WHITESPACE@[8; 9)
186 BLOCK@[9; 11)
187 L_CURLY@[9; 10)
188 R_CURLY@[10; 11)
189 "#
190 .trim()
191 );
192
193 let (analysis, range) = single_file_with_range(
194 r#"fn test() {
195 <|>assert!("
196 fn foo() {
197 }
198 ", "");<|>
199}"#
200 .trim(),
201 );
202 let syn = analysis.syntax_tree(range.file_id, Some(range.range));
203
204 assert_eq!(
205 syn.trim(),
206 r#"
207EXPR_STMT@[16; 58)
208 MACRO_CALL@[16; 57)
209 PATH@[16; 22)
210 PATH_SEGMENT@[16; 22)
211 NAME_REF@[16; 22)
212 IDENT@[16; 22) "assert"
213 EXCL@[22; 23)
214 TOKEN_TREE@[23; 57)
215 L_PAREN@[23; 24)
216 STRING@[24; 52)
217 COMMA@[52; 53)
218 WHITESPACE@[53; 54)
219 STRING@[54; 56)
220 R_PAREN@[56; 57)
221 SEMI@[57; 58)
222 "#
223 .trim()
224 );
225 }
226
227 #[test]
228 fn test_syntax_tree_inside_string() {
229 let (analysis, range) = single_file_with_range(
230 r#"fn test() {
231 assert!("
232<|>fn foo() {
233}<|>
234fn bar() {
235}
236 ", "");
237}"#
238 .trim(),
239 );
240 let syn = analysis.syntax_tree(range.file_id, Some(range.range));
241 assert_eq!(
242 syn.trim(),
243 r#"
244SOURCE_FILE@[0; 12)
245 FN_DEF@[0; 12)
246 FN_KW@[0; 2)
247 WHITESPACE@[2; 3)
248 NAME@[3; 6)
249 IDENT@[3; 6) "foo"
250 PARAM_LIST@[6; 8)
251 L_PAREN@[6; 7)
252 R_PAREN@[7; 8)
253 WHITESPACE@[8; 9)
254 BLOCK@[9; 12)
255 L_CURLY@[9; 10)
256 WHITESPACE@[10; 11)
257 R_CURLY@[11; 12)
258"#
259 .trim()
260 );
261
262 // With a raw string
263 let (analysis, range) = single_file_with_range(
264 r###"fn test() {
265 assert!(r#"
266<|>fn foo() {
267}<|>
268fn bar() {
269}
270 "#, "");
271}"###
272 .trim(),
273 );
274 let syn = analysis.syntax_tree(range.file_id, Some(range.range));
275 assert_eq!(
276 syn.trim(),
277 r#"
278SOURCE_FILE@[0; 12)
279 FN_DEF@[0; 12)
280 FN_KW@[0; 2)
281 WHITESPACE@[2; 3)
282 NAME@[3; 6)
283 IDENT@[3; 6) "foo"
284 PARAM_LIST@[6; 8)
285 L_PAREN@[6; 7)
286 R_PAREN@[7; 8)
287 WHITESPACE@[8; 9)
288 BLOCK@[9; 12)
289 L_CURLY@[9; 10)
290 WHITESPACE@[10; 11)
291 R_CURLY@[11; 12)
292"#
293 .trim()
294 );
295
296 // With a raw string
297 let (analysis, range) = single_file_with_range(
298 r###"fn test() {
299 assert!(r<|>#"
300fn foo() {
301}
302fn bar() {
303}"<|>#, "");
304}"###
305 .trim(),
306 );
307 let syn = analysis.syntax_tree(range.file_id, Some(range.range));
308 assert_eq!(
309 syn.trim(),
310 r#"
311SOURCE_FILE@[0; 25)
312 FN_DEF@[0; 12)
313 FN_KW@[0; 2)
314 WHITESPACE@[2; 3)
315 NAME@[3; 6)
316 IDENT@[3; 6) "foo"
317 PARAM_LIST@[6; 8)
318 L_PAREN@[6; 7)
319 R_PAREN@[7; 8)
320 WHITESPACE@[8; 9)
321 BLOCK@[9; 12)
322 L_CURLY@[9; 10)
323 WHITESPACE@[10; 11)
324 R_CURLY@[11; 12)
325 WHITESPACE@[12; 13)
326 FN_DEF@[13; 25)
327 FN_KW@[13; 15)
328 WHITESPACE@[15; 16)
329 NAME@[16; 19)
330 IDENT@[16; 19) "bar"
331 PARAM_LIST@[19; 21)
332 L_PAREN@[19; 20)
333 R_PAREN@[20; 21)
334 WHITESPACE@[21; 22)
335 BLOCK@[22; 25)
336 L_CURLY@[22; 23)
337 WHITESPACE@[23; 24)
338 R_CURLY@[24; 25)
339
340"#
341 .trim()
342 );
343 }
344}
diff --git a/crates/ra_ide_api/tests/test/main.rs b/crates/ra_ide_api/tests/test/main.rs
deleted file mode 100644
index d4ff21c09..000000000
--- a/crates/ra_ide_api/tests/test/main.rs
+++ /dev/null
@@ -1,376 +0,0 @@
1use ra_ide_api::{
2 mock_analysis::{single_file, single_file_with_position, single_file_with_range, MockAnalysis},
3 AnalysisChange, CrateGraph, Edition::Edition2018, Query, NavigationTarget,
4 ReferenceSearchResult,
5};
6use ra_syntax::SmolStr;
7
8#[test]
9fn test_resolve_crate_root() {
10 let mock = MockAnalysis::with_files(
11 "
12 //- /bar.rs
13 mod foo;
14 //- /foo.rs
15 // empty <|>
16 ",
17 );
18 let root_file = mock.id_of("/bar.rs");
19 let mod_file = mock.id_of("/foo.rs");
20 let mut host = mock.analysis_host();
21 assert!(host.analysis().crate_for(mod_file).unwrap().is_empty());
22
23 let mut crate_graph = CrateGraph::default();
24 let crate_id = crate_graph.add_crate_root(root_file, Edition2018);
25 let mut change = AnalysisChange::new();
26 change.set_crate_graph(crate_graph);
27 host.apply_change(change);
28
29 assert_eq!(host.analysis().crate_for(mod_file).unwrap(), vec![crate_id]);
30}
31
32fn get_all_refs(text: &str) -> ReferenceSearchResult {
33 let (analysis, position) = single_file_with_position(text);
34 analysis.find_all_refs(position).unwrap().unwrap()
35}
36
37fn get_symbols_matching(text: &str, query: &str) -> Vec<NavigationTarget> {
38 let (analysis, _) = single_file(text);
39 analysis.symbol_search(Query::new(query.into())).unwrap()
40}
41
42#[test]
43fn test_find_all_refs_for_local() {
44 let code = r#"
45 fn main() {
46 let mut i = 1;
47 let j = 1;
48 i = i<|> + j;
49
50 {
51 i = 0;
52 }
53
54 i = 5;
55 }"#;
56
57 let refs = get_all_refs(code);
58 assert_eq!(refs.len(), 5);
59}
60
61#[test]
62fn test_find_all_refs_for_param_inside() {
63 let code = r#"
64 fn foo(i : u32) -> u32 {
65 i<|>
66 }"#;
67
68 let refs = get_all_refs(code);
69 assert_eq!(refs.len(), 2);
70}
71
72#[test]
73fn test_find_all_refs_for_fn_param() {
74 let code = r#"
75 fn foo(i<|> : u32) -> u32 {
76 i
77 }"#;
78
79 let refs = get_all_refs(code);
80 assert_eq!(refs.len(), 2);
81}
82
83#[test]
84fn test_world_symbols_with_no_container() {
85 let code = r#"
86 enum FooInner { }
87 "#;
88
89 let mut symbols = get_symbols_matching(code, "FooInner");
90
91 let s = symbols.pop().unwrap();
92
93 assert_eq!(s.name(), "FooInner");
94 assert!(s.container_name().is_none());
95}
96
97#[test]
98fn test_world_symbols_include_container_name() {
99 let code = r#"
100fn foo() {
101 enum FooInner { }
102}
103 "#;
104
105 let mut symbols = get_symbols_matching(code, "FooInner");
106
107 let s = symbols.pop().unwrap();
108
109 assert_eq!(s.name(), "FooInner");
110 assert_eq!(s.container_name(), Some(&SmolStr::new("foo")));
111
112 let code = r#"
113mod foo {
114 struct FooInner;
115}
116 "#;
117
118 let mut symbols = get_symbols_matching(code, "FooInner");
119
120 let s = symbols.pop().unwrap();
121
122 assert_eq!(s.name(), "FooInner");
123 assert_eq!(s.container_name(), Some(&SmolStr::new("foo")));
124}
125
126#[test]
127fn test_syntax_tree_without_range() {
128 // Basic syntax
129 let (analysis, file_id) = single_file(r#"fn foo() {}"#);
130 let syn = analysis.syntax_tree(file_id, None);
131
132 assert_eq!(
133 syn.trim(),
134 r#"
135SOURCE_FILE@[0; 11)
136 FN_DEF@[0; 11)
137 FN_KW@[0; 2)
138 WHITESPACE@[2; 3)
139 NAME@[3; 6)
140 IDENT@[3; 6) "foo"
141 PARAM_LIST@[6; 8)
142 L_PAREN@[6; 7)
143 R_PAREN@[7; 8)
144 WHITESPACE@[8; 9)
145 BLOCK@[9; 11)
146 L_CURLY@[9; 10)
147 R_CURLY@[10; 11)
148 "#
149 .trim()
150 );
151
152 let (analysis, file_id) = single_file(
153 r#"
154fn test() {
155 assert!("
156 fn foo() {
157 }
158 ", "");
159}"#
160 .trim(),
161 );
162 let syn = analysis.syntax_tree(file_id, None);
163
164 assert_eq!(
165 syn.trim(),
166 r#"
167SOURCE_FILE@[0; 60)
168 FN_DEF@[0; 60)
169 FN_KW@[0; 2)
170 WHITESPACE@[2; 3)
171 NAME@[3; 7)
172 IDENT@[3; 7) "test"
173 PARAM_LIST@[7; 9)
174 L_PAREN@[7; 8)
175 R_PAREN@[8; 9)
176 WHITESPACE@[9; 10)
177 BLOCK@[10; 60)
178 L_CURLY@[10; 11)
179 WHITESPACE@[11; 16)
180 EXPR_STMT@[16; 58)
181 MACRO_CALL@[16; 57)
182 PATH@[16; 22)
183 PATH_SEGMENT@[16; 22)
184 NAME_REF@[16; 22)
185 IDENT@[16; 22) "assert"
186 EXCL@[22; 23)
187 TOKEN_TREE@[23; 57)
188 L_PAREN@[23; 24)
189 STRING@[24; 52)
190 COMMA@[52; 53)
191 WHITESPACE@[53; 54)
192 STRING@[54; 56)
193 R_PAREN@[56; 57)
194 SEMI@[57; 58)
195 WHITESPACE@[58; 59)
196 R_CURLY@[59; 60)
197 "#
198 .trim()
199 );
200}
201
202#[test]
203fn test_syntax_tree_with_range() {
204 let (analysis, range) = single_file_with_range(r#"<|>fn foo() {}<|>"#.trim());
205 let syn = analysis.syntax_tree(range.file_id, Some(range.range));
206
207 assert_eq!(
208 syn.trim(),
209 r#"
210FN_DEF@[0; 11)
211 FN_KW@[0; 2)
212 WHITESPACE@[2; 3)
213 NAME@[3; 6)
214 IDENT@[3; 6) "foo"
215 PARAM_LIST@[6; 8)
216 L_PAREN@[6; 7)
217 R_PAREN@[7; 8)
218 WHITESPACE@[8; 9)
219 BLOCK@[9; 11)
220 L_CURLY@[9; 10)
221 R_CURLY@[10; 11)
222 "#
223 .trim()
224 );
225
226 let (analysis, range) = single_file_with_range(
227 r#"fn test() {
228 <|>assert!("
229 fn foo() {
230 }
231 ", "");<|>
232}"#
233 .trim(),
234 );
235 let syn = analysis.syntax_tree(range.file_id, Some(range.range));
236
237 assert_eq!(
238 syn.trim(),
239 r#"
240EXPR_STMT@[16; 58)
241 MACRO_CALL@[16; 57)
242 PATH@[16; 22)
243 PATH_SEGMENT@[16; 22)
244 NAME_REF@[16; 22)
245 IDENT@[16; 22) "assert"
246 EXCL@[22; 23)
247 TOKEN_TREE@[23; 57)
248 L_PAREN@[23; 24)
249 STRING@[24; 52)
250 COMMA@[52; 53)
251 WHITESPACE@[53; 54)
252 STRING@[54; 56)
253 R_PAREN@[56; 57)
254 SEMI@[57; 58)
255 "#
256 .trim()
257 );
258}
259
260#[test]
261fn test_syntax_tree_inside_string() {
262 let (analysis, range) = single_file_with_range(
263 r#"fn test() {
264 assert!("
265<|>fn foo() {
266}<|>
267fn bar() {
268}
269 ", "");
270}"#
271 .trim(),
272 );
273 let syn = analysis.syntax_tree(range.file_id, Some(range.range));
274 assert_eq!(
275 syn.trim(),
276 r#"
277SOURCE_FILE@[0; 12)
278 FN_DEF@[0; 12)
279 FN_KW@[0; 2)
280 WHITESPACE@[2; 3)
281 NAME@[3; 6)
282 IDENT@[3; 6) "foo"
283 PARAM_LIST@[6; 8)
284 L_PAREN@[6; 7)
285 R_PAREN@[7; 8)
286 WHITESPACE@[8; 9)
287 BLOCK@[9; 12)
288 L_CURLY@[9; 10)
289 WHITESPACE@[10; 11)
290 R_CURLY@[11; 12)
291"#
292 .trim()
293 );
294
295 // With a raw string
296 let (analysis, range) = single_file_with_range(
297 r###"fn test() {
298 assert!(r#"
299<|>fn foo() {
300}<|>
301fn bar() {
302}
303 "#, "");
304}"###
305 .trim(),
306 );
307 let syn = analysis.syntax_tree(range.file_id, Some(range.range));
308 assert_eq!(
309 syn.trim(),
310 r#"
311SOURCE_FILE@[0; 12)
312 FN_DEF@[0; 12)
313 FN_KW@[0; 2)
314 WHITESPACE@[2; 3)
315 NAME@[3; 6)
316 IDENT@[3; 6) "foo"
317 PARAM_LIST@[6; 8)
318 L_PAREN@[6; 7)
319 R_PAREN@[7; 8)
320 WHITESPACE@[8; 9)
321 BLOCK@[9; 12)
322 L_CURLY@[9; 10)
323 WHITESPACE@[10; 11)
324 R_CURLY@[11; 12)
325"#
326 .trim()
327 );
328
329 // With a raw string
330 let (analysis, range) = single_file_with_range(
331 r###"fn test() {
332 assert!(r<|>#"
333fn foo() {
334}
335fn bar() {
336}"<|>#, "");
337}"###
338 .trim(),
339 );
340 let syn = analysis.syntax_tree(range.file_id, Some(range.range));
341 assert_eq!(
342 syn.trim(),
343 r#"
344SOURCE_FILE@[0; 25)
345 FN_DEF@[0; 12)
346 FN_KW@[0; 2)
347 WHITESPACE@[2; 3)
348 NAME@[3; 6)
349 IDENT@[3; 6) "foo"
350 PARAM_LIST@[6; 8)
351 L_PAREN@[6; 7)
352 R_PAREN@[7; 8)
353 WHITESPACE@[8; 9)
354 BLOCK@[9; 12)
355 L_CURLY@[9; 10)
356 WHITESPACE@[10; 11)
357 R_CURLY@[11; 12)
358 WHITESPACE@[12; 13)
359 FN_DEF@[13; 25)
360 FN_KW@[13; 15)
361 WHITESPACE@[15; 16)
362 NAME@[16; 19)
363 IDENT@[16; 19) "bar"
364 PARAM_LIST@[19; 21)
365 L_PAREN@[19; 20)
366 R_PAREN@[20; 21)
367 WHITESPACE@[21; 22)
368 BLOCK@[22; 25)
369 L_CURLY@[22; 23)
370 WHITESPACE@[23; 24)
371 R_CURLY@[24; 25)
372
373"#
374 .trim()
375 );
376}
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index 54b72f8c5..47a37e4d1 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -4061,7 +4061,11 @@ impl ast::NameOwner for TraitDef {}
4061impl ast::AttrsOwner for TraitDef {} 4061impl ast::AttrsOwner for TraitDef {}
4062impl ast::DocCommentsOwner for TraitDef {} 4062impl ast::DocCommentsOwner for TraitDef {}
4063impl ast::TypeParamsOwner for TraitDef {} 4063impl ast::TypeParamsOwner for TraitDef {}
4064impl TraitDef {} 4064impl TraitDef {
4065 pub fn item_list(&self) -> Option<&ItemList> {
4066 super::child_opt(self)
4067 }
4068}
4065 4069
4066// TrueKw 4070// TrueKw
4067#[derive(Debug, PartialEq, Eq, Hash)] 4071#[derive(Debug, PartialEq, Eq, Hash)]
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron
index 4f8e19bd0..ad6d74162 100644
--- a/crates/ra_syntax/src/grammar.ron
+++ b/crates/ra_syntax/src/grammar.ron
@@ -292,7 +292,10 @@ Grammar(
292 ], options: [["variant_list", "EnumVariantList"]] ), 292 ], options: [["variant_list", "EnumVariantList"]] ),
293 "EnumVariantList": ( collections: [["variants", "EnumVariant"]] ), 293 "EnumVariantList": ( collections: [["variants", "EnumVariant"]] ),
294 "EnumVariant": ( traits: ["NameOwner", "DocCommentsOwner", "AttrsOwner"], options: ["Expr"] ), 294 "EnumVariant": ( traits: ["NameOwner", "DocCommentsOwner", "AttrsOwner"], options: ["Expr"] ),
295 "TraitDef": ( traits: ["VisibilityOwner", "NameOwner", "AttrsOwner", "DocCommentsOwner", "TypeParamsOwner"] ), 295 "TraitDef": (
296 traits: ["VisibilityOwner", "NameOwner", "AttrsOwner", "DocCommentsOwner", "TypeParamsOwner"],
297 options: ["ItemList"]
298 ),
296 "Module": ( 299 "Module": (
297 traits: ["VisibilityOwner", "NameOwner", "AttrsOwner", "DocCommentsOwner" ], 300 traits: ["VisibilityOwner", "NameOwner", "AttrsOwner", "DocCommentsOwner" ],
298 options: [ "ItemList" ] 301 options: [ "ItemList" ]
diff --git a/docs/user/features.md b/docs/user/features.md
index b9d2aa84f..7173d88e9 100644
--- a/docs/user/features.md
+++ b/docs/user/features.md
@@ -210,7 +210,7 @@ fn main() {
210} 210}
211``` 211```
212 212
213-- Fill struct fields 213- Fill struct fields
214 214
215```rust 215```rust
216// before: 216// before:
@@ -270,7 +270,22 @@ fn foo() {
270} 270}
271``` 271```
272 272
273-- Remove `dbg!` 273- Inline local variable:
274
275```rust
276// before:
277fn foo() {
278 let a<|> = 1 + 1;
279 let b = a * 10;
280}
281
282// after:
283fn foo() {
284 let b = (1 + 1) * 10;
285}
286```
287
288- Remove `dbg!`
274 289
275```rust 290```rust
276// before: 291// before: