aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_assists/src/assists/apply_demorgan.rs40
-rw-r--r--crates/ra_assists/src/assists/invert_if.rs102
-rw-r--r--crates/ra_assists/src/doc_tests/generated.rs17
-rw-r--r--crates/ra_assists/src/lib.rs2
-rw-r--r--crates/ra_assists/src/test_db.rs1
-rw-r--r--crates/ra_hir/src/code_model.rs150
-rw-r--r--crates/ra_hir/src/code_model/attrs.rs91
-rw-r--r--crates/ra_hir/src/code_model/docs.rs97
-rw-r--r--crates/ra_hir/src/code_model/src.rs112
-rw-r--r--crates/ra_hir/src/db.rs38
-rw-r--r--crates/ra_hir/src/debug.rs2
-rw-r--r--crates/ra_hir/src/from_id.rs46
-rw-r--r--crates/ra_hir/src/lang_item.rs160
-rw-r--r--crates/ra_hir/src/lib.rs13
-rw-r--r--crates/ra_hir/src/test_db.rs3
-rw-r--r--crates/ra_hir/src/ty/autoderef.rs7
-rw-r--r--crates/ra_hir/src/ty/infer/coerce.rs7
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs47
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs5
-rw-r--r--crates/ra_hir_def/src/adt.rs152
-rw-r--r--crates/ra_hir_def/src/attr.rs76
-rw-r--r--crates/ra_hir_def/src/body.rs16
-rw-r--r--crates/ra_hir_def/src/body/lower.rs6
-rw-r--r--crates/ra_hir_def/src/body/scope.rs6
-rw-r--r--crates/ra_hir_def/src/data.rs14
-rw-r--r--crates/ra_hir_def/src/db.rs46
-rw-r--r--crates/ra_hir_def/src/docs.rs68
-rw-r--r--crates/ra_hir_def/src/generics.rs8
-rw-r--r--crates/ra_hir_def/src/lang_item.rs120
-rw-r--r--crates/ra_hir_def/src/lib.rs160
-rw-r--r--crates/ra_hir_def/src/nameres.rs83
-rw-r--r--crates/ra_hir_def/src/nameres/collector.rs59
-rw-r--r--crates/ra_hir_def/src/nameres/mod_resolution.rs4
-rw-r--r--crates/ra_hir_def/src/nameres/path_resolution.rs17
-rw-r--r--crates/ra_hir_def/src/nameres/raw.rs40
-rw-r--r--crates/ra_hir_def/src/nameres/tests.rs4
-rw-r--r--crates/ra_hir_def/src/nameres/tests/mod_resolution.rs2
-rw-r--r--crates/ra_hir_def/src/per_ns.rs (renamed from crates/ra_hir_def/src/nameres/per_ns.rs)0
-rw-r--r--crates/ra_hir_def/src/resolver.rs75
-rw-r--r--crates/ra_hir_def/src/test_db.rs2
-rw-r--r--crates/ra_hir_def/src/trace.rs49
-rw-r--r--crates/ra_hir_expand/src/builtin_macro.rs163
-rw-r--r--crates/ra_hir_expand/src/db.rs6
-rw-r--r--crates/ra_hir_expand/src/lib.rs7
-rw-r--r--crates/ra_hir_expand/src/test_db.rs50
-rw-r--r--crates/ra_ide_api/src/completion/complete_path.rs4
-rw-r--r--crates/ra_ide_api/src/db.rs1
-rw-r--r--crates/ra_syntax/src/ast/edit.rs12
-rw-r--r--crates/ra_syntax/src/ast/expr_extensions.rs2
-rw-r--r--crates/ra_syntax/src/ast/make.rs15
-rw-r--r--docs/user/README.md5
-rw-r--r--docs/user/assists.md19
52 files changed, 1329 insertions, 902 deletions
diff --git a/crates/ra_assists/src/assists/apply_demorgan.rs b/crates/ra_assists/src/assists/apply_demorgan.rs
index 068da1774..7c57c0560 100644
--- a/crates/ra_assists/src/assists/apply_demorgan.rs
+++ b/crates/ra_assists/src/assists/apply_demorgan.rs
@@ -1,6 +1,6 @@
1use super::invert_if::invert_boolean_expression;
1use hir::db::HirDatabase; 2use hir::db::HirDatabase;
2use ra_syntax::ast::{self, AstNode}; 3use ra_syntax::ast::{self, AstNode};
3use ra_syntax::SyntaxNode;
4 4
5use crate::{Assist, AssistCtx, AssistId}; 5use crate::{Assist, AssistCtx, AssistId};
6 6
@@ -32,18 +32,18 @@ pub(crate) fn apply_demorgan(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist>
32 if !cursor_in_range { 32 if !cursor_in_range {
33 return None; 33 return None;
34 } 34 }
35 let lhs = expr.lhs()?.syntax().clone(); 35 let lhs = expr.lhs()?;
36 let lhs_range = lhs.text_range(); 36 let lhs_range = lhs.syntax().text_range();
37 let rhs = expr.rhs()?.syntax().clone(); 37 let rhs = expr.rhs()?;
38 let rhs_range = rhs.text_range(); 38 let rhs_range = rhs.syntax().text_range();
39 let not_lhs = undo_negation(lhs)?; 39 let not_lhs = invert_boolean_expression(&lhs)?;
40 let not_rhs = undo_negation(rhs)?; 40 let not_rhs = invert_boolean_expression(&rhs)?;
41 41
42 ctx.add_assist(AssistId("apply_demorgan"), "apply demorgan's law", |edit| { 42 ctx.add_assist(AssistId("apply_demorgan"), "apply demorgan's law", |edit| {
43 edit.target(op_range); 43 edit.target(op_range);
44 edit.replace(op_range, opposite_op); 44 edit.replace(op_range, opposite_op);
45 edit.replace(lhs_range, format!("!({}", not_lhs)); 45 edit.replace(lhs_range, format!("!({}", not_lhs.syntax().text()));
46 edit.replace(rhs_range, format!("{})", not_rhs)); 46 edit.replace(rhs_range, format!("{})", not_rhs.syntax().text()));
47 }) 47 })
48} 48}
49 49
@@ -56,28 +56,6 @@ fn opposite_logic_op(kind: ast::BinOp) -> Option<&'static str> {
56 } 56 }
57} 57}
58 58
59// This function tries to undo unary negation, or inequality
60fn undo_negation(node: SyntaxNode) -> Option<String> {
61 match ast::Expr::cast(node)? {
62 ast::Expr::BinExpr(bin) => match bin.op_kind()? {
63 ast::BinOp::NegatedEqualityTest => {
64 let lhs = bin.lhs()?.syntax().text();
65 let rhs = bin.rhs()?.syntax().text();
66 Some(format!("{} == {}", lhs, rhs))
67 }
68 _ => None,
69 },
70 ast::Expr::PrefixExpr(pe) => match pe.op_kind()? {
71 ast::PrefixOp::Not => {
72 let child = pe.expr()?.syntax().text();
73 Some(String::from(child))
74 }
75 _ => None,
76 },
77 _ => None,
78 }
79}
80
81#[cfg(test)] 59#[cfg(test)]
82mod tests { 60mod tests {
83 use super::*; 61 use super::*;
diff --git a/crates/ra_assists/src/assists/invert_if.rs b/crates/ra_assists/src/assists/invert_if.rs
new file mode 100644
index 000000000..bababa3e2
--- /dev/null
+++ b/crates/ra_assists/src/assists/invert_if.rs
@@ -0,0 +1,102 @@
1use hir::db::HirDatabase;
2use ra_syntax::ast::{self, AstNode};
3use ra_syntax::T;
4
5use crate::{Assist, AssistCtx, AssistId};
6
7// Assist: invert_if
8//
9// Apply invert_if
10// This transforms if expressions of the form `if !x {A} else {B}` into `if x {B} else {A}`
11// This also works with `!=`. This assist can only be applied with the cursor
12// on `if`.
13//
14// ```
15// fn main() {
16// if<|> !y { A } else { B }
17// }
18// ```
19// ->
20// ```
21// fn main() {
22// if y { B } else { A }
23// }
24// ```
25
26pub(crate) fn invert_if(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
27 let if_keyword = ctx.find_token_at_offset(T![if])?;
28 let expr = ast::IfExpr::cast(if_keyword.parent())?;
29 let if_range = if_keyword.text_range();
30 let cursor_in_range = ctx.frange.range.is_subrange(&if_range);
31 if !cursor_in_range {
32 return None;
33 }
34
35 let cond = expr.condition()?.expr()?;
36 let then_node = expr.then_branch()?.syntax().clone();
37
38 if let ast::ElseBranch::Block(else_block) = expr.else_branch()? {
39 let flip_cond = invert_boolean_expression(&cond)?;
40 let cond_range = cond.syntax().text_range();
41 let else_node = else_block.syntax();
42 let else_range = else_node.text_range();
43 let then_range = then_node.text_range();
44 return ctx.add_assist(AssistId("invert_if"), "invert if branches", |edit| {
45 edit.target(if_range);
46 edit.replace(cond_range, flip_cond.syntax().text());
47 edit.replace(else_range, then_node.text());
48 edit.replace(then_range, else_node.text());
49 });
50 }
51
52 None
53}
54
55pub(crate) fn invert_boolean_expression(expr: &ast::Expr) -> Option<ast::Expr> {
56 match expr {
57 ast::Expr::BinExpr(bin) => match bin.op_kind()? {
58 ast::BinOp::NegatedEqualityTest => bin.replace_op(T![==]).map(|it| it.into()),
59 _ => None,
60 },
61 ast::Expr::PrefixExpr(pe) => match pe.op_kind()? {
62 ast::PrefixOp::Not => pe.expr(),
63 _ => None,
64 },
65 _ => None,
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72
73 use crate::helpers::{check_assist, check_assist_not_applicable};
74
75 #[test]
76 fn invert_if_remove_inequality() {
77 check_assist(
78 invert_if,
79 "fn f() { i<|>f x != 3 { 1 } else { 3 + 2 } }",
80 "fn f() { i<|>f x == 3 { 3 + 2 } else { 1 } }",
81 )
82 }
83
84 #[test]
85 fn invert_if_remove_not() {
86 check_assist(
87 invert_if,
88 "fn f() { <|>if !cond { 3 * 2 } else { 1 } }",
89 "fn f() { <|>if cond { 1 } else { 3 * 2 } }",
90 )
91 }
92
93 #[test]
94 fn invert_if_doesnt_apply_with_cursor_not_on_if() {
95 check_assist_not_applicable(invert_if, "fn f() { if !<|>cond { 3 * 2 } else { 1 } }")
96 }
97
98 #[test]
99 fn invert_if_doesnt_apply_without_negated() {
100 check_assist_not_applicable(invert_if, "fn f() { i<|>f cond { 3 * 2 } else { 1 } }")
101 }
102}
diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs
index 176761efb..3c716c2d1 100644
--- a/crates/ra_assists/src/doc_tests/generated.rs
+++ b/crates/ra_assists/src/doc_tests/generated.rs
@@ -342,6 +342,23 @@ fn main() {
342} 342}
343 343
344#[test] 344#[test]
345fn doctest_invert_if() {
346 check(
347 "invert_if",
348 r#####"
349fn main() {
350 if<|> !y { A } else { B }
351}
352"#####,
353 r#####"
354fn main() {
355 if y { B } else { A }
356}
357"#####,
358 )
359}
360
361#[test]
345fn doctest_make_raw_string() { 362fn doctest_make_raw_string() {
346 check( 363 check(
347 "make_raw_string", 364 "make_raw_string",
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index f2f0dacbf..a372bd8b9 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -97,6 +97,7 @@ mod assists {
97 mod add_impl; 97 mod add_impl;
98 mod add_new; 98 mod add_new;
99 mod apply_demorgan; 99 mod apply_demorgan;
100 mod invert_if;
100 mod flip_comma; 101 mod flip_comma;
101 mod flip_binexpr; 102 mod flip_binexpr;
102 mod flip_trait_bound; 103 mod flip_trait_bound;
@@ -122,6 +123,7 @@ mod assists {
122 add_impl::add_impl, 123 add_impl::add_impl,
123 add_new::add_new, 124 add_new::add_new,
124 apply_demorgan::apply_demorgan, 125 apply_demorgan::apply_demorgan,
126 invert_if::invert_if,
125 change_visibility::change_visibility, 127 change_visibility::change_visibility,
126 fill_match_arms::fill_match_arms, 128 fill_match_arms::fill_match_arms,
127 merge_match_arms::merge_match_arms, 129 merge_match_arms::merge_match_arms,
diff --git a/crates/ra_assists/src/test_db.rs b/crates/ra_assists/src/test_db.rs
index 5be7383ed..5f96c974b 100644
--- a/crates/ra_assists/src/test_db.rs
+++ b/crates/ra_assists/src/test_db.rs
@@ -10,7 +10,6 @@ use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath
10 hir::db::InternDatabaseStorage, 10 hir::db::InternDatabaseStorage,
11 hir::db::AstDatabaseStorage, 11 hir::db::AstDatabaseStorage,
12 hir::db::DefDatabaseStorage, 12 hir::db::DefDatabaseStorage,
13 hir::db::DefDatabase2Storage,
14 hir::db::HirDatabaseStorage 13 hir::db::HirDatabaseStorage
15)] 14)]
16#[derive(Debug, Default)] 15#[derive(Debug, Default)]
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 9f8c6c4a5..fd7776fb7 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -1,8 +1,6 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3pub(crate) mod src; 3pub(crate) mod src;
4pub(crate) mod docs;
5pub(crate) mod attrs;
6 4
7use std::sync::Arc; 5use std::sync::Arc;
8 6
@@ -10,18 +8,20 @@ use hir_def::{
10 adt::VariantData, 8 adt::VariantData,
11 body::scope::ExprScopes, 9 body::scope::ExprScopes,
12 builtin_type::BuiltinType, 10 builtin_type::BuiltinType,
13 nameres::per_ns::PerNs, 11 docs::Documentation,
12 per_ns::PerNs,
14 resolver::{HasResolver, TypeNs}, 13 resolver::{HasResolver, TypeNs},
15 type_ref::TypeRef, 14 type_ref::TypeRef,
16 ContainerId, CrateModuleId, HasModule, ImplId, LocalEnumVariantId, LocalStructFieldId, Lookup, 15 ContainerId, HasModule, ImplId, LocalEnumVariantId, LocalImportId, LocalModuleId,
17 ModuleId, UnionId, 16 LocalStructFieldId, Lookup, ModuleId, UnionId,
18}; 17};
19use hir_expand::{ 18use hir_expand::{
20 diagnostics::DiagnosticSink, 19 diagnostics::DiagnosticSink,
21 name::{self, AsName}, 20 name::{self, AsName},
21 AstId,
22}; 22};
23use ra_db::{CrateId, Edition}; 23use ra_db::{CrateId, Edition, FileId, FilePosition};
24use ra_syntax::ast; 24use ra_syntax::{ast, AstNode, SyntaxNode};
25 25
26use crate::{ 26use crate::{
27 db::{DefDatabase, HirDatabase}, 27 db::{DefDatabase, HirDatabase},
@@ -31,7 +31,7 @@ use crate::{
31 TypeAliasId, 31 TypeAliasId,
32 }, 32 },
33 ty::{InferenceResult, Namespace, TraitRef}, 33 ty::{InferenceResult, Namespace, TraitRef},
34 Either, HasSource, ImportId, Name, Source, Ty, 34 Either, HasSource, Name, Source, Ty,
35}; 35};
36 36
37/// hir::Crate describes a single crate. It's the main interface with which 37/// hir::Crate describes a single crate. It's the main interface with which
@@ -79,6 +79,64 @@ impl Crate {
79 } 79 }
80} 80}
81 81
82pub enum ModuleSource {
83 SourceFile(ast::SourceFile),
84 Module(ast::Module),
85}
86
87impl ModuleSource {
88 pub fn new(
89 db: &impl DefDatabase,
90 file_id: Option<FileId>,
91 decl_id: Option<AstId<ast::Module>>,
92 ) -> ModuleSource {
93 match (file_id, decl_id) {
94 (Some(file_id), _) => {
95 let source_file = db.parse(file_id).tree();
96 ModuleSource::SourceFile(source_file)
97 }
98 (None, Some(item_id)) => {
99 let module = item_id.to_node(db);
100 assert!(module.item_list().is_some(), "expected inline module");
101 ModuleSource::Module(module)
102 }
103 (None, None) => panic!(),
104 }
105 }
106
107 // FIXME: this methods do not belong here
108 pub fn from_position(db: &impl DefDatabase, position: FilePosition) -> ModuleSource {
109 let parse = db.parse(position.file_id);
110 match &ra_syntax::algo::find_node_at_offset::<ast::Module>(
111 parse.tree().syntax(),
112 position.offset,
113 ) {
114 Some(m) if !m.has_semi() => ModuleSource::Module(m.clone()),
115 _ => {
116 let source_file = parse.tree();
117 ModuleSource::SourceFile(source_file)
118 }
119 }
120 }
121
122 pub fn from_child_node(db: &impl DefDatabase, child: Source<&SyntaxNode>) -> ModuleSource {
123 if let Some(m) =
124 child.value.ancestors().filter_map(ast::Module::cast).find(|it| !it.has_semi())
125 {
126 ModuleSource::Module(m)
127 } else {
128 let file_id = child.file_id.original_file(db);
129 let source_file = db.parse(file_id).tree();
130 ModuleSource::SourceFile(source_file)
131 }
132 }
133
134 pub fn from_file_id(db: &impl DefDatabase, file_id: FileId) -> ModuleSource {
135 let source_file = db.parse(file_id).tree();
136 ModuleSource::SourceFile(source_file)
137 }
138}
139
82#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 140#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
83pub struct Module { 141pub struct Module {
84 pub(crate) id: ModuleId, 142 pub(crate) id: ModuleId,
@@ -110,10 +168,10 @@ impl_froms!(
110 BuiltinType 168 BuiltinType
111); 169);
112 170
113pub use hir_def::ModuleSource; 171pub use hir_def::attr::Attrs;
114 172
115impl Module { 173impl Module {
116 pub(crate) fn new(krate: Crate, crate_module_id: CrateModuleId) -> Module { 174 pub(crate) fn new(krate: Crate, crate_module_id: LocalModuleId) -> Module {
117 Module { id: ModuleId { krate: krate.crate_id, module_id: crate_module_id } } 175 Module { id: ModuleId { krate: krate.crate_id, module_id: crate_module_id } }
118 } 176 }
119 177
@@ -130,17 +188,6 @@ impl Module {
130 }) 188 })
131 } 189 }
132 190
133 /// Returns the syntax of the last path segment corresponding to this import
134 pub fn import_source(
135 self,
136 db: &impl HirDatabase,
137 import: ImportId,
138 ) -> Either<ast::UseTree, ast::ExternCrateItem> {
139 let src = self.definition_source(db);
140 let (_, source_map) = db.raw_items_with_source_map(src.file_id);
141 source_map.get(&src.value, import)
142 }
143
144 /// Returns the crate this module is part of. 191 /// Returns the crate this module is part of.
145 pub fn krate(self) -> Crate { 192 pub fn krate(self) -> Crate {
146 Crate { crate_id: self.id.krate } 193 Crate { crate_id: self.id.krate }
@@ -190,11 +237,13 @@ impl Module {
190 } 237 }
191 238
192 /// Returns a `ModuleScope`: a set of items, visible in this module. 239 /// Returns a `ModuleScope`: a set of items, visible in this module.
193 pub fn scope(self, db: &impl HirDatabase) -> Vec<(Name, ScopeDef, Option<ImportId>)> { 240 pub fn scope(self, db: &impl HirDatabase) -> Vec<(Name, ScopeDef, Option<Import>)> {
194 db.crate_def_map(self.id.krate)[self.id.module_id] 241 db.crate_def_map(self.id.krate)[self.id.module_id]
195 .scope 242 .scope
196 .entries() 243 .entries()
197 .map(|(name, res)| (name.clone(), res.def.into(), res.import)) 244 .map(|(name, res)| {
245 (name.clone(), res.def.into(), res.import.map(|id| Import { parent: self, id }))
246 })
198 .collect() 247 .collect()
199 } 248 }
200 249
@@ -232,11 +281,16 @@ impl Module {
232 def_map[self.id.module_id].impls.iter().copied().map(ImplBlock::from).collect() 281 def_map[self.id.module_id].impls.iter().copied().map(ImplBlock::from).collect()
233 } 282 }
234 283
235 fn with_module_id(self, module_id: CrateModuleId) -> Module { 284 fn with_module_id(self, module_id: LocalModuleId) -> Module {
236 Module::new(self.krate(), module_id) 285 Module::new(self.krate(), module_id)
237 } 286 }
238} 287}
239 288
289pub struct Import {
290 pub(crate) parent: Module,
291 pub(crate) id: LocalImportId,
292}
293
240#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 294#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
241pub struct StructField { 295pub struct StructField {
242 pub(crate) parent: VariantDef, 296 pub(crate) parent: VariantDef,
@@ -991,3 +1045,51 @@ impl From<PerNs> for ScopeDef {
991 .unwrap_or(ScopeDef::Unknown) 1045 .unwrap_or(ScopeDef::Unknown)
992 } 1046 }
993} 1047}
1048
1049#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1050pub enum AttrDef {
1051 Module(Module),
1052 StructField(StructField),
1053 Adt(Adt),
1054 Function(Function),
1055 EnumVariant(EnumVariant),
1056 Static(Static),
1057 Const(Const),
1058 Trait(Trait),
1059 TypeAlias(TypeAlias),
1060 MacroDef(MacroDef),
1061}
1062
1063impl_froms!(
1064 AttrDef: Module,
1065 StructField,
1066 Adt(Struct, Enum, Union),
1067 EnumVariant,
1068 Static,
1069 Const,
1070 Function,
1071 Trait,
1072 TypeAlias,
1073 MacroDef
1074);
1075
1076pub trait HasAttrs {
1077 fn attrs(self, db: &impl DefDatabase) -> Attrs;
1078}
1079
1080impl<T: Into<AttrDef>> HasAttrs for T {
1081 fn attrs(self, db: &impl DefDatabase) -> Attrs {
1082 let def: AttrDef = self.into();
1083 db.attrs(def.into())
1084 }
1085}
1086
1087pub trait Docs {
1088 fn docs(&self, db: &impl HirDatabase) -> Option<Documentation>;
1089}
1090impl<T: Into<AttrDef> + Copy> Docs for T {
1091 fn docs(&self, db: &impl HirDatabase) -> Option<Documentation> {
1092 let def: AttrDef = (*self).into();
1093 db.documentation(def.into())
1094 }
1095}
diff --git a/crates/ra_hir/src/code_model/attrs.rs b/crates/ra_hir/src/code_model/attrs.rs
deleted file mode 100644
index 96da8c88c..000000000
--- a/crates/ra_hir/src/code_model/attrs.rs
+++ /dev/null
@@ -1,91 +0,0 @@
1//! FIXME: write short doc here
2
3use crate::{
4 db::{AstDatabase, DefDatabase, HirDatabase},
5 Adt, Const, Enum, EnumVariant, FieldSource, Function, HasSource, MacroDef, Module, Static,
6 Struct, StructField, Trait, TypeAlias, Union,
7};
8use hir_def::attr::{Attr, Attrs};
9use hir_expand::hygiene::Hygiene;
10use ra_syntax::ast;
11
12#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
13pub enum AttrDef {
14 Module(Module),
15 StructField(StructField),
16 Adt(Adt),
17 Function(Function),
18 EnumVariant(EnumVariant),
19 Static(Static),
20 Const(Const),
21 Trait(Trait),
22 TypeAlias(TypeAlias),
23 MacroDef(MacroDef),
24}
25
26impl_froms!(
27 AttrDef: Module,
28 StructField,
29 Adt(Struct, Enum, Union),
30 EnumVariant,
31 Static,
32 Const,
33 Function,
34 Trait,
35 TypeAlias,
36 MacroDef
37);
38
39pub trait HasAttrs {
40 fn attrs(&self, db: &impl HirDatabase) -> Attrs;
41}
42
43pub(crate) fn attributes_query(db: &(impl DefDatabase + AstDatabase), def: AttrDef) -> Attrs {
44 match def {
45 AttrDef::Module(it) => {
46 let src = match it.declaration_source(db) {
47 Some(it) => it,
48 None => return Attrs::default(),
49 };
50 let hygiene = Hygiene::new(db, src.file_id);
51 Attr::from_attrs_owner(&src.value, &hygiene)
52 }
53 AttrDef::StructField(it) => match it.source(db).value {
54 FieldSource::Named(named) => {
55 let src = it.source(db);
56 let hygiene = Hygiene::new(db, src.file_id);
57 Attr::from_attrs_owner(&named, &hygiene)
58 }
59 FieldSource::Pos(..) => Attrs::default(),
60 },
61 AttrDef::Adt(it) => match it {
62 Adt::Struct(it) => attrs_from_ast(it, db),
63 Adt::Enum(it) => attrs_from_ast(it, db),
64 Adt::Union(it) => attrs_from_ast(it, db),
65 },
66 AttrDef::EnumVariant(it) => attrs_from_ast(it, db),
67 AttrDef::Static(it) => attrs_from_ast(it, db),
68 AttrDef::Const(it) => attrs_from_ast(it, db),
69 AttrDef::Function(it) => attrs_from_ast(it, db),
70 AttrDef::Trait(it) => attrs_from_ast(it, db),
71 AttrDef::TypeAlias(it) => attrs_from_ast(it, db),
72 AttrDef::MacroDef(it) => attrs_from_ast(it, db),
73 }
74}
75
76fn attrs_from_ast<T, D>(node: T, db: &D) -> Attrs
77where
78 T: HasSource,
79 T::Ast: ast::AttrsOwner,
80 D: DefDatabase + AstDatabase,
81{
82 let src = node.source(db);
83 let hygiene = Hygiene::new(db, src.file_id);
84 Attr::from_attrs_owner(&src.value, &hygiene)
85}
86
87impl<T: Into<AttrDef> + Copy> HasAttrs for T {
88 fn attrs(&self, db: &impl HirDatabase) -> Attrs {
89 db.attrs((*self).into())
90 }
91}
diff --git a/crates/ra_hir/src/code_model/docs.rs b/crates/ra_hir/src/code_model/docs.rs
deleted file mode 100644
index e40efef34..000000000
--- a/crates/ra_hir/src/code_model/docs.rs
+++ /dev/null
@@ -1,97 +0,0 @@
1//! FIXME: write short doc here
2
3use std::sync::Arc;
4
5use ra_syntax::ast;
6
7use crate::{
8 db::{AstDatabase, DefDatabase, HirDatabase},
9 Adt, Const, Enum, EnumVariant, FieldSource, Function, HasSource, MacroDef, Module, Static,
10 Struct, StructField, Trait, TypeAlias, Union,
11};
12
13#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
14pub enum DocDef {
15 Module(Module),
16 StructField(StructField),
17 Adt(Adt),
18 EnumVariant(EnumVariant),
19 Static(Static),
20 Const(Const),
21 Function(Function),
22 Trait(Trait),
23 TypeAlias(TypeAlias),
24 MacroDef(MacroDef),
25}
26
27impl_froms!(
28 DocDef: Module,
29 StructField,
30 Adt(Struct, Enum, Union),
31 EnumVariant,
32 Static,
33 Const,
34 Function,
35 Trait,
36 TypeAlias,
37 MacroDef
38);
39
40/// Holds documentation
41#[derive(Debug, Clone, PartialEq, Eq)]
42pub struct Documentation(Arc<str>);
43
44impl Documentation {
45 fn new(s: &str) -> Documentation {
46 Documentation(s.into())
47 }
48
49 pub fn as_str(&self) -> &str {
50 &*self.0
51 }
52}
53
54impl Into<String> for Documentation {
55 fn into(self) -> String {
56 self.as_str().to_owned()
57 }
58}
59
60pub trait Docs {
61 fn docs(&self, db: &impl HirDatabase) -> Option<Documentation>;
62}
63
64pub(crate) fn docs_from_ast(node: &impl ast::DocCommentsOwner) -> Option<Documentation> {
65 node.doc_comment_text().map(|it| Documentation::new(&it))
66}
67
68pub(crate) fn documentation_query(
69 db: &(impl DefDatabase + AstDatabase),
70 def: DocDef,
71) -> Option<Documentation> {
72 match def {
73 DocDef::Module(it) => docs_from_ast(&it.declaration_source(db)?.value),
74 DocDef::StructField(it) => match it.source(db).value {
75 FieldSource::Named(named) => docs_from_ast(&named),
76 FieldSource::Pos(..) => None,
77 },
78 DocDef::Adt(it) => match it {
79 Adt::Struct(it) => docs_from_ast(&it.source(db).value),
80 Adt::Enum(it) => docs_from_ast(&it.source(db).value),
81 Adt::Union(it) => docs_from_ast(&it.source(db).value),
82 },
83 DocDef::EnumVariant(it) => docs_from_ast(&it.source(db).value),
84 DocDef::Static(it) => docs_from_ast(&it.source(db).value),
85 DocDef::Const(it) => docs_from_ast(&it.source(db).value),
86 DocDef::Function(it) => docs_from_ast(&it.source(db).value),
87 DocDef::Trait(it) => docs_from_ast(&it.source(db).value),
88 DocDef::TypeAlias(it) => docs_from_ast(&it.source(db).value),
89 DocDef::MacroDef(it) => docs_from_ast(&it.source(db).value),
90 }
91}
92
93impl<T: Into<DocDef> + Copy> Docs for T {
94 fn docs(&self, db: &impl HirDatabase) -> Option<Documentation> {
95 db.documentation((*self).into())
96 }
97}
diff --git a/crates/ra_hir/src/code_model/src.rs b/crates/ra_hir/src/code_model/src.rs
index fc466c1f0..b7bafe23d 100644
--- a/crates/ra_hir/src/code_model/src.rs
+++ b/crates/ra_hir/src/code_model/src.rs
@@ -1,151 +1,127 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir_def::{HasSource as _, Lookup}; 3use hir_def::{HasChildSource, HasSource as _, Lookup, VariantId};
4use hir_expand::either::Either;
4use ra_syntax::ast::{self, AstNode}; 5use ra_syntax::ast::{self, AstNode};
5 6
6use crate::{ 7use crate::{
7 db::{AstDatabase, DefDatabase, HirDatabase}, 8 db::{DefDatabase, HirDatabase},
8 ids::AstItemDef, 9 ids::AstItemDef,
9 Const, Either, Enum, EnumVariant, FieldSource, Function, HasBody, HirFileId, MacroDef, Module, 10 Const, Enum, EnumVariant, FieldSource, Function, HasBody, Import, MacroDef, Module,
10 ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union, VariantDef, 11 ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union,
11}; 12};
12 13
13pub use hir_expand::Source; 14pub use hir_expand::Source;
14 15
15pub trait HasSource { 16pub trait HasSource {
16 type Ast; 17 type Ast;
17 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<Self::Ast>; 18 fn source(self, db: &impl DefDatabase) -> Source<Self::Ast>;
18} 19}
19 20
20/// NB: Module is !HasSource, because it has two source nodes at the same time: 21/// NB: Module is !HasSource, because it has two source nodes at the same time:
21/// definition and declaration. 22/// definition and declaration.
22impl Module { 23impl Module {
23 /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items. 24 /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items.
24 pub fn definition_source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ModuleSource> { 25 pub fn definition_source(self, db: &impl DefDatabase) -> Source<ModuleSource> {
25 let def_map = db.crate_def_map(self.id.krate); 26 let def_map = db.crate_def_map(self.id.krate);
26 let decl_id = def_map[self.id.module_id].declaration; 27 let src = def_map[self.id.module_id].definition_source(db);
27 let file_id = def_map[self.id.module_id].definition; 28 src.map(|it| match it {
28 let value = ModuleSource::new(db, file_id, decl_id); 29 Either::A(it) => ModuleSource::SourceFile(it),
29 let file_id = file_id.map(HirFileId::from).unwrap_or_else(|| decl_id.unwrap().file_id()); 30 Either::B(it) => ModuleSource::Module(it),
30 Source { file_id, value } 31 })
31 } 32 }
32 33
33 /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`. 34 /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`.
34 /// `None` for the crate root. 35 /// `None` for the crate root.
35 pub fn declaration_source( 36 pub fn declaration_source(self, db: &impl DefDatabase) -> Option<Source<ast::Module>> {
36 self,
37 db: &(impl DefDatabase + AstDatabase),
38 ) -> Option<Source<ast::Module>> {
39 let def_map = db.crate_def_map(self.id.krate); 37 let def_map = db.crate_def_map(self.id.krate);
40 let decl = def_map[self.id.module_id].declaration?; 38 def_map[self.id.module_id].declaration_source(db)
41 let value = decl.to_node(db);
42 Some(Source { file_id: decl.file_id(), value })
43 } 39 }
44} 40}
45 41
46impl HasSource for StructField { 42impl HasSource for StructField {
47 type Ast = FieldSource; 43 type Ast = FieldSource;
48 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<FieldSource> { 44 fn source(self, db: &impl DefDatabase) -> Source<FieldSource> {
49 let var_data = self.parent.variant_data(db); 45 let var = VariantId::from(self.parent);
50 let fields = var_data.fields().unwrap(); 46 let src = var.child_source(db);
51 let ss; 47 src.map(|it| match it[self.id].clone() {
52 let es; 48 Either::A(it) => FieldSource::Pos(it),
53 let (file_id, struct_kind) = match self.parent { 49 Either::B(it) => FieldSource::Named(it),
54 VariantDef::Struct(s) => { 50 })
55 ss = s.source(db);
56 (ss.file_id, ss.value.kind())
57 }
58 VariantDef::EnumVariant(e) => {
59 es = e.source(db);
60 (es.file_id, es.value.kind())
61 }
62 };
63
64 let field_sources = match struct_kind {
65 ast::StructKind::Tuple(fl) => fl.fields().map(|it| FieldSource::Pos(it)).collect(),
66 ast::StructKind::Record(fl) => fl.fields().map(|it| FieldSource::Named(it)).collect(),
67 ast::StructKind::Unit => Vec::new(),
68 };
69 let value = field_sources
70 .into_iter()
71 .zip(fields.iter())
72 .find(|(_syntax, (id, _))| *id == self.id)
73 .unwrap()
74 .0;
75 Source { file_id, value }
76 } 51 }
77} 52}
78impl HasSource for Struct { 53impl HasSource for Struct {
79 type Ast = ast::StructDef; 54 type Ast = ast::StructDef;
80 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::StructDef> { 55 fn source(self, db: &impl DefDatabase) -> Source<ast::StructDef> {
81 self.id.0.source(db) 56 self.id.0.source(db)
82 } 57 }
83} 58}
84impl HasSource for Union { 59impl HasSource for Union {
85 type Ast = ast::StructDef; 60 type Ast = ast::StructDef;
86 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::StructDef> { 61 fn source(self, db: &impl DefDatabase) -> Source<ast::StructDef> {
87 self.id.0.source(db) 62 self.id.0.source(db)
88 } 63 }
89} 64}
90impl HasSource for Enum { 65impl HasSource for Enum {
91 type Ast = ast::EnumDef; 66 type Ast = ast::EnumDef;
92 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::EnumDef> { 67 fn source(self, db: &impl DefDatabase) -> Source<ast::EnumDef> {
93 self.id.source(db) 68 self.id.source(db)
94 } 69 }
95} 70}
96impl HasSource for EnumVariant { 71impl HasSource for EnumVariant {
97 type Ast = ast::EnumVariant; 72 type Ast = ast::EnumVariant;
98 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::EnumVariant> { 73 fn source(self, db: &impl DefDatabase) -> Source<ast::EnumVariant> {
99 let enum_data = db.enum_data(self.parent.id); 74 self.parent.id.child_source(db).map(|map| map[self.id].clone())
100 let src = self.parent.id.source(db);
101 let value = src
102 .value
103 .variant_list()
104 .into_iter()
105 .flat_map(|it| it.variants())
106 .zip(enum_data.variants.iter())
107 .find(|(_syntax, (id, _))| *id == self.id)
108 .unwrap()
109 .0;
110 Source { file_id: src.file_id, value }
111 } 75 }
112} 76}
113impl HasSource for Function { 77impl HasSource for Function {
114 type Ast = ast::FnDef; 78 type Ast = ast::FnDef;
115 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::FnDef> { 79 fn source(self, db: &impl DefDatabase) -> Source<ast::FnDef> {
116 self.id.lookup(db).source(db) 80 self.id.lookup(db).source(db)
117 } 81 }
118} 82}
119impl HasSource for Const { 83impl HasSource for Const {
120 type Ast = ast::ConstDef; 84 type Ast = ast::ConstDef;
121 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::ConstDef> { 85 fn source(self, db: &impl DefDatabase) -> Source<ast::ConstDef> {
122 self.id.lookup(db).source(db) 86 self.id.lookup(db).source(db)
123 } 87 }
124} 88}
125impl HasSource for Static { 89impl HasSource for Static {
126 type Ast = ast::StaticDef; 90 type Ast = ast::StaticDef;
127 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::StaticDef> { 91 fn source(self, db: &impl DefDatabase) -> Source<ast::StaticDef> {
128 self.id.source(db) 92 self.id.source(db)
129 } 93 }
130} 94}
131impl HasSource for Trait { 95impl HasSource for Trait {
132 type Ast = ast::TraitDef; 96 type Ast = ast::TraitDef;
133 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::TraitDef> { 97 fn source(self, db: &impl DefDatabase) -> Source<ast::TraitDef> {
134 self.id.source(db) 98 self.id.source(db)
135 } 99 }
136} 100}
137impl HasSource for TypeAlias { 101impl HasSource for TypeAlias {
138 type Ast = ast::TypeAliasDef; 102 type Ast = ast::TypeAliasDef;
139 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::TypeAliasDef> { 103 fn source(self, db: &impl DefDatabase) -> Source<ast::TypeAliasDef> {
140 self.id.lookup(db).source(db) 104 self.id.lookup(db).source(db)
141 } 105 }
142} 106}
143impl HasSource for MacroDef { 107impl HasSource for MacroDef {
144 type Ast = ast::MacroCall; 108 type Ast = ast::MacroCall;
145 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::MacroCall> { 109 fn source(self, db: &impl DefDatabase) -> Source<ast::MacroCall> {
146 Source { file_id: self.id.ast_id.file_id(), value: self.id.ast_id.to_node(db) } 110 Source { file_id: self.id.ast_id.file_id(), value: self.id.ast_id.to_node(db) }
147 } 111 }
148} 112}
113impl HasSource for Import {
114 type Ast = Either<ast::UseTree, ast::ExternCrateItem>;
115
116 /// Returns the syntax of the last path segment corresponding to this import
117 fn source(self, db: &impl DefDatabase) -> Source<Self::Ast> {
118 let src = self.parent.definition_source(db);
119 let (_, source_map) = db.raw_items_with_source_map(src.file_id);
120 let root = db.parse_or_expand(src.file_id).unwrap();
121 let ptr = source_map.get(self.id);
122 src.with_value(ptr.map(|it| it.to_node(&root), |it| it.to_node(&root)))
123 }
124}
149 125
150pub trait HasBodySource: HasBody + HasSource 126pub trait HasBodySource: HasBody + HasSource
151where 127where
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index 85d46b485..3ae5df8d5 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -2,58 +2,34 @@
2 2
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use hir_def::attr::Attrs;
6use ra_db::salsa; 5use ra_db::salsa;
7use ra_syntax::SmolStr;
8 6
9use crate::{ 7use crate::{
10 debug::HirDebugDatabase,
11 ids, 8 ids,
12 lang_item::{LangItemTarget, LangItems},
13 ty::{ 9 ty::{
14 method_resolution::CrateImplBlocks, 10 method_resolution::CrateImplBlocks,
15 traits::{AssocTyValue, Impl}, 11 traits::{AssocTyValue, Impl},
16 CallableDef, FnSig, GenericPredicate, InferenceResult, Namespace, Substs, Ty, TypableDef, 12 CallableDef, FnSig, GenericPredicate, InferenceResult, Namespace, Substs, Ty, TypableDef,
17 TypeCtor, 13 TypeCtor,
18 }, 14 },
19 Crate, DefWithBody, GenericDef, ImplBlock, Module, StructField, Trait, 15 Crate, DefWithBody, GenericDef, ImplBlock, StructField, Trait,
20}; 16};
21 17
22pub use hir_def::db::{ 18pub use hir_def::db::{
23 BodyQuery, BodyWithSourceMapQuery, ConstDataQuery, CrateDefMapQuery, DefDatabase2, 19 BodyQuery, BodyWithSourceMapQuery, ConstDataQuery, CrateDefMapQuery, CrateLangItemsQuery,
24 DefDatabase2Storage, EnumDataQuery, ExprScopesQuery, FunctionDataQuery, GenericParamsQuery, 20 DefDatabase, DefDatabaseStorage, DocumentationQuery, EnumDataQuery, ExprScopesQuery,
25 ImplDataQuery, InternDatabase, InternDatabaseStorage, RawItemsQuery, 21 FunctionDataQuery, GenericParamsQuery, ImplDataQuery, InternDatabase, InternDatabaseStorage,
26 RawItemsWithSourceMapQuery, StaticDataQuery, StructDataQuery, TraitDataQuery, 22 LangItemQuery, ModuleLangItemsQuery, RawItemsQuery, RawItemsWithSourceMapQuery,
27 TypeAliasDataQuery, 23 StaticDataQuery, StructDataQuery, TraitDataQuery, TypeAliasDataQuery,
28}; 24};
29pub use hir_expand::db::{ 25pub use hir_expand::db::{
30 AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery, 26 AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery,
31 ParseMacroQuery, 27 ParseMacroQuery,
32}; 28};
33 29
34// This database uses `AstDatabase` internally,
35#[salsa::query_group(DefDatabaseStorage)]
36#[salsa::requires(AstDatabase)]
37pub trait DefDatabase: HirDebugDatabase + DefDatabase2 {
38 #[salsa::invoke(LangItems::module_lang_items_query)]
39 fn module_lang_items(&self, module: Module) -> Option<Arc<LangItems>>;
40
41 #[salsa::invoke(LangItems::crate_lang_items_query)]
42 fn crate_lang_items(&self, krate: Crate) -> Arc<LangItems>;
43
44 #[salsa::invoke(LangItems::lang_item_query)]
45 fn lang_item(&self, start_crate: Crate, item: SmolStr) -> Option<LangItemTarget>;
46
47 #[salsa::invoke(crate::code_model::docs::documentation_query)]
48 fn documentation(&self, def: crate::DocDef) -> Option<crate::Documentation>;
49
50 #[salsa::invoke(crate::code_model::attrs::attributes_query)]
51 fn attrs(&self, def: crate::AttrDef) -> Attrs;
52}
53
54#[salsa::query_group(HirDatabaseStorage)] 30#[salsa::query_group(HirDatabaseStorage)]
55#[salsa::requires(salsa::Database)] 31#[salsa::requires(salsa::Database)]
56pub trait HirDatabase: DefDatabase + AstDatabase { 32pub trait HirDatabase: DefDatabase {
57 #[salsa::invoke(crate::ty::infer_query)] 33 #[salsa::invoke(crate::ty::infer_query)]
58 fn infer(&self, def: DefWithBody) -> Arc<InferenceResult>; 34 fn infer(&self, def: DefWithBody) -> Arc<InferenceResult>;
59 35
diff --git a/crates/ra_hir/src/debug.rs b/crates/ra_hir/src/debug.rs
index 4f3e922c3..8ec371f6e 100644
--- a/crates/ra_hir/src/debug.rs
+++ b/crates/ra_hir/src/debug.rs
@@ -1,3 +1,5 @@
1//! XXX: This does not work at the moment.
2//!
1//! printf debugging infrastructure for rust-analyzer. 3//! printf debugging infrastructure for rust-analyzer.
2//! 4//!
3//! When you print a hir type, like a module, using `eprintln!("{:?}", module)`, 5//! When you print a hir type, like a module, using `eprintln!("{:?}", module)`,
diff --git a/crates/ra_hir/src/from_id.rs b/crates/ra_hir/src/from_id.rs
index e8ed04056..529ac8251 100644
--- a/crates/ra_hir/src/from_id.rs
+++ b/crates/ra_hir/src/from_id.rs
@@ -4,14 +4,14 @@
4//! are splitting the hir. 4//! are splitting the hir.
5 5
6use hir_def::{ 6use hir_def::{
7 AdtId, AssocItemId, ConstId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, GenericDefId, 7 AdtId, AssocItemId, AttrDefId, ConstId, DefWithBodyId, EnumId, EnumVariantId, FunctionId,
8 ModuleDefId, StaticId, StructId, TypeAliasId, UnionId, 8 GenericDefId, ModuleDefId, StaticId, StructFieldId, StructId, TypeAliasId, UnionId, VariantId,
9}; 9};
10 10
11use crate::{ 11use crate::{
12 ty::{CallableDef, TypableDef}, 12 ty::{CallableDef, TypableDef},
13 Adt, AssocItem, Const, Crate, DefWithBody, EnumVariant, Function, GenericDef, ModuleDef, 13 Adt, AssocItem, AttrDef, Const, Crate, DefWithBody, EnumVariant, Function, GenericDef,
14 Static, TypeAlias, 14 ModuleDef, Static, StructField, TypeAlias, VariantDef,
15}; 15};
16 16
17impl From<ra_db::CrateId> for Crate { 17impl From<ra_db::CrateId> for Crate {
@@ -70,6 +70,12 @@ impl From<EnumVariantId> for EnumVariant {
70 } 70 }
71} 71}
72 72
73impl From<EnumVariant> for EnumVariantId {
74 fn from(def: EnumVariant) -> Self {
75 EnumVariantId { parent: def.parent.id, local_id: def.id }
76 }
77}
78
73impl From<ModuleDefId> for ModuleDef { 79impl From<ModuleDefId> for ModuleDef {
74 fn from(id: ModuleDefId) -> Self { 80 fn from(id: ModuleDefId) -> Self {
75 match id { 81 match id {
@@ -219,3 +225,35 @@ impl From<CallableDef> for GenericDefId {
219 } 225 }
220 } 226 }
221} 227}
228
229impl From<VariantDef> for VariantId {
230 fn from(def: VariantDef) -> Self {
231 match def {
232 VariantDef::Struct(it) => VariantId::StructId(it.id),
233 VariantDef::EnumVariant(it) => VariantId::EnumVariantId(it.into()),
234 }
235 }
236}
237
238impl From<StructField> for StructFieldId {
239 fn from(def: StructField) -> Self {
240 StructFieldId { parent: def.parent.into(), local_id: def.id }
241 }
242}
243
244impl From<AttrDef> for AttrDefId {
245 fn from(def: AttrDef) -> Self {
246 match def {
247 AttrDef::Module(it) => AttrDefId::ModuleId(it.id),
248 AttrDef::StructField(it) => AttrDefId::StructFieldId(it.into()),
249 AttrDef::Adt(it) => AttrDefId::AdtId(it.into()),
250 AttrDef::Function(it) => AttrDefId::FunctionId(it.id),
251 AttrDef::EnumVariant(it) => AttrDefId::EnumVariantId(it.into()),
252 AttrDef::Static(it) => AttrDefId::StaticId(it.id),
253 AttrDef::Const(it) => AttrDefId::ConstId(it.id),
254 AttrDef::Trait(it) => AttrDefId::TraitId(it.id),
255 AttrDef::TypeAlias(it) => AttrDefId::TypeAliasId(it.id),
256 AttrDef::MacroDef(it) => AttrDefId::MacroDefId(it.id),
257 }
258 }
259}
diff --git a/crates/ra_hir/src/lang_item.rs b/crates/ra_hir/src/lang_item.rs
deleted file mode 100644
index 89fd85f59..000000000
--- a/crates/ra_hir/src/lang_item.rs
+++ /dev/null
@@ -1,160 +0,0 @@
1//! FIXME: write short doc here
2
3use rustc_hash::FxHashMap;
4use std::sync::Arc;
5
6use ra_syntax::{ast::AttrsOwner, SmolStr};
7
8use crate::{
9 db::{AstDatabase, DefDatabase, HirDatabase},
10 Adt, Crate, Enum, Function, HasSource, ImplBlock, Module, ModuleDef, Static, Struct, Trait,
11};
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
14pub enum LangItemTarget {
15 Enum(Enum),
16 Function(Function),
17 ImplBlock(ImplBlock),
18 Static(Static),
19 Struct(Struct),
20 Trait(Trait),
21}
22
23impl LangItemTarget {
24 pub(crate) fn krate(&self, db: &impl HirDatabase) -> Option<Crate> {
25 Some(match self {
26 LangItemTarget::Enum(e) => e.module(db).krate(),
27 LangItemTarget::Function(f) => f.module(db).krate(),
28 LangItemTarget::ImplBlock(i) => i.krate(db),
29 LangItemTarget::Static(s) => s.module(db).krate(),
30 LangItemTarget::Struct(s) => s.module(db).krate(),
31 LangItemTarget::Trait(t) => t.module(db).krate(),
32 })
33 }
34}
35
36#[derive(Default, Debug, Clone, PartialEq, Eq)]
37pub struct LangItems {
38 items: FxHashMap<SmolStr, LangItemTarget>,
39}
40
41impl LangItems {
42 pub fn target<'a>(&'a self, item: &str) -> Option<&'a LangItemTarget> {
43 self.items.get(item)
44 }
45
46 /// Salsa query. This will look for lang items in a specific crate.
47 pub(crate) fn crate_lang_items_query(
48 db: &(impl DefDatabase + AstDatabase),
49 krate: Crate,
50 ) -> Arc<LangItems> {
51 let mut lang_items = LangItems::default();
52
53 if let Some(module) = krate.root_module(db) {
54 lang_items.collect_lang_items_recursive(db, module);
55 }
56
57 Arc::new(lang_items)
58 }
59
60 pub(crate) fn module_lang_items_query(
61 db: &(impl DefDatabase + AstDatabase),
62 module: Module,
63 ) -> Option<Arc<LangItems>> {
64 let mut lang_items = LangItems::default();
65 lang_items.collect_lang_items(db, module);
66 if lang_items.items.is_empty() {
67 None
68 } else {
69 Some(Arc::new(lang_items))
70 }
71 }
72
73 /// Salsa query. Look for a lang item, starting from the specified crate and recursively
74 /// traversing its dependencies.
75 pub(crate) fn lang_item_query(
76 db: &impl DefDatabase,
77 start_crate: Crate,
78 item: SmolStr,
79 ) -> Option<LangItemTarget> {
80 let lang_items = db.crate_lang_items(start_crate);
81 let start_crate_target = lang_items.items.get(&item);
82 if let Some(target) = start_crate_target {
83 Some(*target)
84 } else {
85 for dep in start_crate.dependencies(db) {
86 let dep_crate = dep.krate;
87 let dep_target = db.lang_item(dep_crate, item.clone());
88 if dep_target.is_some() {
89 return dep_target;
90 }
91 }
92 None
93 }
94 }
95
96 fn collect_lang_items(&mut self, db: &(impl DefDatabase + AstDatabase), module: Module) {
97 // Look for impl targets
98 for impl_block in module.impl_blocks(db) {
99 let src = impl_block.source(db);
100 if let Some(lang_item_name) = lang_item_name(&src.value) {
101 self.items
102 .entry(lang_item_name)
103 .or_insert_with(|| LangItemTarget::ImplBlock(impl_block));
104 }
105 }
106
107 for def in module.declarations(db) {
108 match def {
109 ModuleDef::Trait(trait_) => {
110 self.collect_lang_item(db, trait_, LangItemTarget::Trait)
111 }
112 ModuleDef::Adt(Adt::Enum(e)) => self.collect_lang_item(db, e, LangItemTarget::Enum),
113 ModuleDef::Adt(Adt::Struct(s)) => {
114 self.collect_lang_item(db, s, LangItemTarget::Struct)
115 }
116 ModuleDef::Function(f) => self.collect_lang_item(db, f, LangItemTarget::Function),
117 ModuleDef::Static(s) => self.collect_lang_item(db, s, LangItemTarget::Static),
118 _ => {}
119 }
120 }
121 }
122
123 fn collect_lang_items_recursive(
124 &mut self,
125 db: &(impl DefDatabase + AstDatabase),
126 module: Module,
127 ) {
128 if let Some(module_lang_items) = db.module_lang_items(module) {
129 self.items.extend(module_lang_items.items.iter().map(|(k, v)| (k.clone(), *v)))
130 }
131
132 // Look for lang items in the children
133 for child in module.children(db) {
134 self.collect_lang_items_recursive(db, child);
135 }
136 }
137
138 fn collect_lang_item<T, N>(
139 &mut self,
140 db: &(impl DefDatabase + AstDatabase),
141 item: T,
142 constructor: fn(T) -> LangItemTarget,
143 ) where
144 T: Copy + HasSource<Ast = N>,
145 N: AttrsOwner,
146 {
147 let node = item.source(db).value;
148 if let Some(lang_item_name) = lang_item_name(&node) {
149 self.items.entry(lang_item_name).or_insert_with(|| constructor(item));
150 }
151 }
152}
153
154fn lang_item_name<T: AttrsOwner>(node: &T) -> Option<SmolStr> {
155 node.attrs()
156 .filter_map(|a| a.as_simple_key_value())
157 .filter(|(key, _)| key == "lang")
158 .map(|(_, val)| val)
159 .nth(0)
160}
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index e164c9b32..e51d4d063 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -35,7 +35,6 @@ mod ids;
35mod ty; 35mod ty;
36mod impl_block; 36mod impl_block;
37mod expr; 37mod expr;
38mod lang_item;
39pub mod diagnostics; 38pub mod diagnostics;
40mod util; 39mod util;
41 40
@@ -51,13 +50,11 @@ mod marks;
51 50
52pub use crate::{ 51pub use crate::{
53 code_model::{ 52 code_model::{
54 attrs::{AttrDef, HasAttrs},
55 docs::{DocDef, Docs, Documentation},
56 src::{HasBodySource, HasSource}, 53 src::{HasBodySource, HasSource},
57 Adt, AssocItem, Const, Container, Crate, CrateDependency, DefWithBody, Enum, EnumVariant, 54 Adt, AssocItem, AttrDef, Const, Container, Crate, CrateDependency, DefWithBody, Docs, Enum,
58 FieldSource, Function, GenericDef, GenericParam, HasBody, ImplBlock, Local, MacroDef, 55 EnumVariant, FieldSource, Function, GenericDef, GenericParam, HasAttrs, HasBody, ImplBlock,
59 Module, ModuleDef, ModuleSource, ScopeDef, Static, Struct, StructField, Trait, TypeAlias, 56 Import, Local, MacroDef, Module, ModuleDef, ModuleSource, ScopeDef, Static, Struct,
60 Union, VariantDef, 57 StructField, Trait, TypeAlias, Union, VariantDef,
61 }, 58 },
62 expr::ExprScopes, 59 expr::ExprScopes,
63 from_source::FromSource, 60 from_source::FromSource,
@@ -72,7 +69,7 @@ pub use crate::{
72 69
73pub use hir_def::{ 70pub use hir_def::{
74 builtin_type::BuiltinType, 71 builtin_type::BuiltinType,
75 nameres::{per_ns::PerNs, raw::ImportId}, 72 docs::Documentation,
76 path::{Path, PathKind}, 73 path::{Path, PathKind},
77 type_ref::Mutability, 74 type_ref::Mutability,
78}; 75};
diff --git a/crates/ra_hir/src/test_db.rs b/crates/ra_hir/src/test_db.rs
index 1caa2e875..03c7ac155 100644
--- a/crates/ra_hir/src/test_db.rs
+++ b/crates/ra_hir/src/test_db.rs
@@ -2,7 +2,7 @@
2 2
3use std::{panic, sync::Arc}; 3use std::{panic, sync::Arc};
4 4
5use hir_def::{db::DefDatabase2, ModuleId}; 5use hir_def::{db::DefDatabase, ModuleId};
6use hir_expand::diagnostics::DiagnosticSink; 6use hir_expand::diagnostics::DiagnosticSink;
7use parking_lot::Mutex; 7use parking_lot::Mutex;
8use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath, SourceDatabase}; 8use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath, SourceDatabase};
@@ -15,7 +15,6 @@ use crate::{db, debug::HirDebugHelper};
15 db::InternDatabaseStorage, 15 db::InternDatabaseStorage,
16 db::AstDatabaseStorage, 16 db::AstDatabaseStorage,
17 db::DefDatabaseStorage, 17 db::DefDatabaseStorage,
18 db::DefDatabase2Storage,
19 db::HirDatabaseStorage 18 db::HirDatabaseStorage
20)] 19)]
21#[derive(Debug, Default)] 20#[derive(Debug, Default)]
diff --git a/crates/ra_hir/src/ty/autoderef.rs b/crates/ra_hir/src/ty/autoderef.rs
index b60e4bb31..41c99d227 100644
--- a/crates/ra_hir/src/ty/autoderef.rs
+++ b/crates/ra_hir/src/ty/autoderef.rs
@@ -5,12 +5,13 @@
5 5
6use std::iter::successors; 6use std::iter::successors;
7 7
8use hir_def::resolver::Resolver; 8use hir_def::{lang_item::LangItemTarget, resolver::Resolver};
9use hir_expand::name; 9use hir_expand::name;
10use log::{info, warn}; 10use log::{info, warn};
11 11
12use crate::{db::HirDatabase, Trait};
13
12use super::{traits::Solution, Canonical, Substs, Ty, TypeWalk}; 14use super::{traits::Solution, Canonical, Substs, Ty, TypeWalk};
13use crate::db::HirDatabase;
14 15
15const AUTODEREF_RECURSION_LIMIT: usize = 10; 16const AUTODEREF_RECURSION_LIMIT: usize = 10;
16 17
@@ -41,7 +42,7 @@ fn deref_by_trait(
41) -> Option<Canonical<Ty>> { 42) -> Option<Canonical<Ty>> {
42 let krate = resolver.krate()?; 43 let krate = resolver.krate()?;
43 let deref_trait = match db.lang_item(krate.into(), "deref".into())? { 44 let deref_trait = match db.lang_item(krate.into(), "deref".into())? {
44 crate::lang_item::LangItemTarget::Trait(t) => t, 45 LangItemTarget::TraitId(t) => Trait::from(t),
45 _ => return None, 46 _ => return None,
46 }; 47 };
47 let target = deref_trait.associated_type_by_name(db, &name::TARGET_TYPE)?; 48 let target = deref_trait.associated_type_by_name(db, &name::TARGET_TYPE)?;
diff --git a/crates/ra_hir/src/ty/infer/coerce.rs b/crates/ra_hir/src/ty/infer/coerce.rs
index 0772b9df5..4ea038d99 100644
--- a/crates/ra_hir/src/ty/infer/coerce.rs
+++ b/crates/ra_hir/src/ty/infer/coerce.rs
@@ -4,13 +4,12 @@
4//! 4//!
5//! See: https://doc.rust-lang.org/nomicon/coercions.html 5//! See: https://doc.rust-lang.org/nomicon/coercions.html
6 6
7use hir_def::resolver::Resolver; 7use hir_def::{lang_item::LangItemTarget, resolver::Resolver};
8use rustc_hash::FxHashMap; 8use rustc_hash::FxHashMap;
9use test_utils::tested_by; 9use test_utils::tested_by;
10 10
11use crate::{ 11use crate::{
12 db::HirDatabase, 12 db::HirDatabase,
13 lang_item::LangItemTarget,
14 ty::{autoderef, Substs, Ty, TypeCtor, TypeWalk}, 13 ty::{autoderef, Substs, Ty, TypeCtor, TypeWalk},
15 Adt, Mutability, 14 Adt, Mutability,
16}; 15};
@@ -50,7 +49,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
50 ) -> FxHashMap<(TypeCtor, TypeCtor), usize> { 49 ) -> FxHashMap<(TypeCtor, TypeCtor), usize> {
51 let krate = resolver.krate().unwrap(); 50 let krate = resolver.krate().unwrap();
52 let impls = match db.lang_item(krate.into(), "coerce_unsized".into()) { 51 let impls = match db.lang_item(krate.into(), "coerce_unsized".into()) {
53 Some(LangItemTarget::Trait(trait_)) => db.impls_for_trait(krate.into(), trait_), 52 Some(LangItemTarget::TraitId(trait_)) => {
53 db.impls_for_trait(krate.into(), trait_.into())
54 }
54 _ => return FxHashMap::default(), 55 _ => return FxHashMap::default(),
55 }; 56 };
56 57
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index f61c27218..caa5f5f74 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -5,7 +5,7 @@
5use std::sync::Arc; 5use std::sync::Arc;
6 6
7use arrayvec::ArrayVec; 7use arrayvec::ArrayVec;
8use hir_def::resolver::Resolver; 8use hir_def::{lang_item::LangItemTarget, resolver::Resolver, AstItemDef};
9use rustc_hash::FxHashMap; 9use rustc_hash::FxHashMap;
10 10
11use crate::{ 11use crate::{
@@ -91,34 +91,43 @@ fn def_crates(db: &impl HirDatabase, cur_crate: Crate, ty: &Ty) -> Option<ArrayV
91 // Types like slice can have inherent impls in several crates, (core and alloc). 91 // Types like slice can have inherent impls in several crates, (core and alloc).
92 // The corresponding impls are marked with lang items, so we can use them to find the required crates. 92 // The corresponding impls are marked with lang items, so we can use them to find the required crates.
93 macro_rules! lang_item_crate { 93 macro_rules! lang_item_crate {
94 ($db:expr, $cur_crate:expr, $($name:expr),+ $(,)?) => {{ 94 ($($name:expr),+ $(,)?) => {{
95 let mut v = ArrayVec::<[Crate; 2]>::new(); 95 let mut v = ArrayVec::<[LangItemTarget; 2]>::new();
96 $( 96 $(
97 v.extend($db.lang_item($cur_crate, $name.into()).and_then(|item| item.krate($db))); 97 v.extend(db.lang_item(cur_crate.crate_id, $name.into()));
98 )+ 98 )+
99 Some(v) 99 v
100 }}; 100 }};
101 } 101 }
102 102
103 match ty { 103 let lang_item_targets = match ty {
104 Ty::Apply(a_ty) => match a_ty.ctor { 104 Ty::Apply(a_ty) => match a_ty.ctor {
105 TypeCtor::Adt(def_id) => Some(std::iter::once(def_id.krate(db)?).collect()), 105 TypeCtor::Adt(def_id) => return Some(std::iter::once(def_id.krate(db)?).collect()),
106 TypeCtor::Bool => lang_item_crate!(db, cur_crate, "bool"), 106 TypeCtor::Bool => lang_item_crate!("bool"),
107 TypeCtor::Char => lang_item_crate!(db, cur_crate, "char"), 107 TypeCtor::Char => lang_item_crate!("char"),
108 TypeCtor::Float(Uncertain::Known(f)) => match f.bitness { 108 TypeCtor::Float(Uncertain::Known(f)) => match f.bitness {
109 // There are two lang items: one in libcore (fXX) and one in libstd (fXX_runtime) 109 // There are two lang items: one in libcore (fXX) and one in libstd (fXX_runtime)
110 FloatBitness::X32 => lang_item_crate!(db, cur_crate, "f32", "f32_runtime"), 110 FloatBitness::X32 => lang_item_crate!("f32", "f32_runtime"),
111 FloatBitness::X64 => lang_item_crate!(db, cur_crate, "f64", "f64_runtime"), 111 FloatBitness::X64 => lang_item_crate!("f64", "f64_runtime"),
112 }, 112 },
113 TypeCtor::Int(Uncertain::Known(i)) => lang_item_crate!(db, cur_crate, i.ty_to_string()), 113 TypeCtor::Int(Uncertain::Known(i)) => lang_item_crate!(i.ty_to_string()),
114 TypeCtor::Str => lang_item_crate!(db, cur_crate, "str_alloc", "str"), 114 TypeCtor::Str => lang_item_crate!("str_alloc", "str"),
115 TypeCtor::Slice => lang_item_crate!(db, cur_crate, "slice_alloc", "slice"), 115 TypeCtor::Slice => lang_item_crate!("slice_alloc", "slice"),
116 TypeCtor::RawPtr(Mutability::Shared) => lang_item_crate!(db, cur_crate, "const_ptr"), 116 TypeCtor::RawPtr(Mutability::Shared) => lang_item_crate!("const_ptr"),
117 TypeCtor::RawPtr(Mutability::Mut) => lang_item_crate!(db, cur_crate, "mut_ptr"), 117 TypeCtor::RawPtr(Mutability::Mut) => lang_item_crate!("mut_ptr"),
118 _ => None, 118 _ => return None,
119 }, 119 },
120 _ => None, 120 _ => return None,
121 } 121 };
122 let res = lang_item_targets
123 .into_iter()
124 .filter_map(|it| match it {
125 LangItemTarget::ImplBlockId(it) => Some(it),
126 _ => None,
127 })
128 .map(|it| it.module(db).krate.into())
129 .collect();
130 Some(res)
122} 131}
123 132
124/// Look up the method with the given name, returning the actual autoderefed 133/// Look up the method with the given name, returning the actual autoderefed
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs
index 88785f305..53818a5e5 100644
--- a/crates/ra_hir/src/ty/traits/chalk.rs
+++ b/crates/ra_hir/src/ty/traits/chalk.rs
@@ -9,6 +9,7 @@ use chalk_ir::{
9}; 9};
10use chalk_rust_ir::{AssociatedTyDatum, AssociatedTyValue, ImplDatum, StructDatum, TraitDatum}; 10use chalk_rust_ir::{AssociatedTyDatum, AssociatedTyValue, ImplDatum, StructDatum, TraitDatum};
11 11
12use hir_def::lang_item::LangItemTarget;
12use hir_expand::name; 13use hir_expand::name;
13 14
14use ra_db::salsa::{InternId, InternKey}; 15use ra_db::salsa::{InternId, InternKey};
@@ -832,9 +833,9 @@ fn closure_fn_trait_output_assoc_ty_value(
832} 833}
833 834
834fn get_fn_trait(db: &impl HirDatabase, krate: Crate, fn_trait: super::FnTrait) -> Option<Trait> { 835fn get_fn_trait(db: &impl HirDatabase, krate: Crate, fn_trait: super::FnTrait) -> Option<Trait> {
835 let target = db.lang_item(krate, fn_trait.lang_item_name().into())?; 836 let target = db.lang_item(krate.crate_id, fn_trait.lang_item_name().into())?;
836 match target { 837 match target {
837 crate::lang_item::LangItemTarget::Trait(t) => Some(t), 838 LangItemTarget::TraitId(t) => Some(t.into()),
838 _ => None, 839 _ => None,
839 } 840 }
840} 841}
diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs
index 2bd18255c..20e9a1eb5 100644
--- a/crates/ra_hir_def/src/adt.rs
+++ b/crates/ra_hir_def/src/adt.rs
@@ -2,13 +2,17 @@
2 2
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use hir_expand::name::{AsName, Name}; 5use hir_expand::{
6use ra_arena::Arena; 6 either::Either,
7 name::{AsName, Name},
8 Source,
9};
10use ra_arena::{map::ArenaMap, Arena};
7use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; 11use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner};
8 12
9use crate::{ 13use crate::{
10 db::DefDatabase2, type_ref::TypeRef, AstItemDef, EnumId, LocalEnumVariantId, 14 db::DefDatabase, trace::Trace, type_ref::TypeRef, AstItemDef, EnumId, HasChildSource,
11 LocalStructFieldId, StructOrUnionId, 15 LocalEnumVariantId, LocalStructFieldId, StructOrUnionId, VariantId,
12}; 16};
13 17
14/// Note that we use `StructData` for unions as well! 18/// Note that we use `StructData` for unions as well!
@@ -45,10 +49,7 @@ pub struct StructFieldData {
45} 49}
46 50
47impl StructData { 51impl StructData {
48 pub(crate) fn struct_data_query( 52 pub(crate) fn struct_data_query(db: &impl DefDatabase, id: StructOrUnionId) -> Arc<StructData> {
49 db: &impl DefDatabase2,
50 id: StructOrUnionId,
51 ) -> Arc<StructData> {
52 let src = id.source(db); 53 let src = id.source(db);
53 let name = src.value.name().map(|n| n.as_name()); 54 let name = src.value.name().map(|n| n.as_name());
54 let variant_data = VariantData::new(src.value.kind()); 55 let variant_data = VariantData::new(src.value.kind());
@@ -58,20 +59,12 @@ impl StructData {
58} 59}
59 60
60impl EnumData { 61impl EnumData {
61 pub(crate) fn enum_data_query(db: &impl DefDatabase2, e: EnumId) -> Arc<EnumData> { 62 pub(crate) fn enum_data_query(db: &impl DefDatabase, e: EnumId) -> Arc<EnumData> {
62 let src = e.source(db); 63 let src = e.source(db);
63 let name = src.value.name().map(|n| n.as_name()); 64 let name = src.value.name().map(|n| n.as_name());
64 let variants = src 65 let mut trace = Trace::new_for_arena();
65 .value 66 lower_enum(&mut trace, &src.value);
66 .variant_list() 67 Arc::new(EnumData { name, variants: trace.into_arena() })
67 .into_iter()
68 .flat_map(|it| it.variants())
69 .map(|var| EnumVariantData {
70 name: var.name().map(|it| it.as_name()),
71 variant_data: Arc::new(VariantData::new(var.kind())),
72 })
73 .collect();
74 Arc::new(EnumData { name, variants })
75 } 68 }
76 69
77 pub(crate) fn variant(&self, name: &Name) -> Option<LocalEnumVariantId> { 70 pub(crate) fn variant(&self, name: &Name) -> Option<LocalEnumVariantId> {
@@ -80,38 +73,109 @@ impl EnumData {
80 } 73 }
81} 74}
82 75
76impl HasChildSource for EnumId {
77 type ChildId = LocalEnumVariantId;
78 type Value = ast::EnumVariant;
79 fn child_source(&self, db: &impl DefDatabase) -> Source<ArenaMap<Self::ChildId, Self::Value>> {
80 let src = self.source(db);
81 let mut trace = Trace::new_for_map();
82 lower_enum(&mut trace, &src.value);
83 src.with_value(trace.into_map())
84 }
85}
86
87fn lower_enum(
88 trace: &mut Trace<LocalEnumVariantId, EnumVariantData, ast::EnumVariant>,
89 ast: &ast::EnumDef,
90) {
91 for var in ast.variant_list().into_iter().flat_map(|it| it.variants()) {
92 trace.alloc(
93 || var.clone(),
94 || EnumVariantData {
95 name: var.name().map(|it| it.as_name()),
96 variant_data: Arc::new(VariantData::new(var.kind())),
97 },
98 )
99 }
100}
101
83impl VariantData { 102impl VariantData {
84 fn new(flavor: ast::StructKind) -> Self { 103 fn new(flavor: ast::StructKind) -> Self {
85 match flavor { 104 let mut trace = Trace::new_for_arena();
86 ast::StructKind::Tuple(fl) => { 105 match lower_struct(&mut trace, &flavor) {
87 let fields = fl 106 StructKind::Tuple => VariantData::Tuple(trace.into_arena()),
88 .fields() 107 StructKind::Record => VariantData::Record(trace.into_arena()),
89 .enumerate() 108 StructKind::Unit => VariantData::Unit,
90 .map(|(i, fd)| StructFieldData {
91 name: Name::new_tuple_field(i),
92 type_ref: TypeRef::from_ast_opt(fd.type_ref()),
93 })
94 .collect();
95 VariantData::Tuple(fields)
96 }
97 ast::StructKind::Record(fl) => {
98 let fields = fl
99 .fields()
100 .map(|fd| StructFieldData {
101 name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing),
102 type_ref: TypeRef::from_ast_opt(fd.ascribed_type()),
103 })
104 .collect();
105 VariantData::Record(fields)
106 }
107 ast::StructKind::Unit => VariantData::Unit,
108 } 109 }
109 } 110 }
110 111
111 pub fn fields(&self) -> Option<&Arena<LocalStructFieldId, StructFieldData>> { 112 pub fn fields(&self) -> Option<&Arena<LocalStructFieldId, StructFieldData>> {
112 match self { 113 match &self {
113 VariantData::Record(fields) | VariantData::Tuple(fields) => Some(fields), 114 VariantData::Record(fields) | VariantData::Tuple(fields) => Some(fields),
114 _ => None, 115 _ => None,
115 } 116 }
116 } 117 }
117} 118}
119
120impl HasChildSource for VariantId {
121 type ChildId = LocalStructFieldId;
122 type Value = Either<ast::TupleFieldDef, ast::RecordFieldDef>;
123
124 fn child_source(&self, db: &impl DefDatabase) -> Source<ArenaMap<Self::ChildId, Self::Value>> {
125 let src = match self {
126 VariantId::EnumVariantId(it) => {
127 // I don't really like the fact that we call into parent source
128 // here, this might add to more queries then necessary.
129 let src = it.parent.child_source(db);
130 src.map(|map| map[it.local_id].kind())
131 }
132 VariantId::StructId(it) => it.0.source(db).map(|it| it.kind()),
133 };
134 let mut trace = Trace::new_for_map();
135 lower_struct(&mut trace, &src.value);
136 src.with_value(trace.into_map())
137 }
138}
139
140enum StructKind {
141 Tuple,
142 Record,
143 Unit,
144}
145
146fn lower_struct(
147 trace: &mut Trace<
148 LocalStructFieldId,
149 StructFieldData,
150 Either<ast::TupleFieldDef, ast::RecordFieldDef>,
151 >,
152 ast: &ast::StructKind,
153) -> StructKind {
154 match ast {
155 ast::StructKind::Tuple(fl) => {
156 for (i, fd) in fl.fields().enumerate() {
157 trace.alloc(
158 || Either::A(fd.clone()),
159 || StructFieldData {
160 name: Name::new_tuple_field(i),
161 type_ref: TypeRef::from_ast_opt(fd.type_ref()),
162 },
163 )
164 }
165 StructKind::Tuple
166 }
167 ast::StructKind::Record(fl) => {
168 for fd in fl.fields() {
169 trace.alloc(
170 || Either::B(fd.clone()),
171 || StructFieldData {
172 name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing),
173 type_ref: TypeRef::from_ast_opt(fd.ascribed_type()),
174 },
175 )
176 }
177 StructKind::Record
178 }
179 ast::StructKind::Unit => StructKind::Unit,
180 }
181}
diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs
index 7a9d0fdf4..48ce8cd93 100644
--- a/crates/ra_hir_def/src/attr.rs
+++ b/crates/ra_hir_def/src/attr.rs
@@ -2,7 +2,7 @@
2 2
3use std::{ops, sync::Arc}; 3use std::{ops, sync::Arc};
4 4
5use hir_expand::hygiene::Hygiene; 5use hir_expand::{either::Either, hygiene::Hygiene, AstId};
6use mbe::ast_to_token_tree; 6use mbe::ast_to_token_tree;
7use ra_cfg::CfgOptions; 7use ra_cfg::CfgOptions;
8use ra_syntax::{ 8use ra_syntax::{
@@ -11,7 +11,9 @@ use ra_syntax::{
11}; 11};
12use tt::Subtree; 12use tt::Subtree;
13 13
14use crate::path::Path; 14use crate::{
15 db::DefDatabase, path::Path, AdtId, AstItemDef, AttrDefId, HasChildSource, HasSource, Lookup,
16};
15 17
16#[derive(Default, Debug, Clone, PartialEq, Eq)] 18#[derive(Default, Debug, Clone, PartialEq, Eq)]
17pub struct Attrs { 19pub struct Attrs {
@@ -30,9 +32,59 @@ impl ops::Deref for Attrs {
30} 32}
31 33
32impl Attrs { 34impl Attrs {
35 pub(crate) fn attrs_query(db: &impl DefDatabase, def: AttrDefId) -> Attrs {
36 match def {
37 AttrDefId::ModuleId(module) => {
38 let def_map = db.crate_def_map(module.krate);
39 let src = match def_map[module.module_id].declaration_source(db) {
40 Some(it) => it,
41 None => return Attrs::default(),
42 };
43 let hygiene = Hygiene::new(db, src.file_id);
44 Attr::from_attrs_owner(&src.value, &hygiene)
45 }
46 AttrDefId::StructFieldId(it) => {
47 let src = it.parent.child_source(db);
48 match &src.value[it.local_id] {
49 Either::A(_tuple) => Attrs::default(),
50 Either::B(record) => {
51 let hygiene = Hygiene::new(db, src.file_id);
52 Attr::from_attrs_owner(record, &hygiene)
53 }
54 }
55 }
56 AttrDefId::EnumVariantId(it) => {
57 let src = it.parent.child_source(db);
58 let hygiene = Hygiene::new(db, src.file_id);
59 Attr::from_attrs_owner(&src.value[it.local_id], &hygiene)
60 }
61 AttrDefId::AdtId(it) => match it {
62 AdtId::StructId(it) => attrs_from_ast(it.0.lookup_intern(db).ast_id, db),
63 AdtId::EnumId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db),
64 AdtId::UnionId(it) => attrs_from_ast(it.0.lookup_intern(db).ast_id, db),
65 },
66 AttrDefId::StaticId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db),
67 AttrDefId::TraitId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db),
68 AttrDefId::MacroDefId(it) => attrs_from_ast(it.ast_id, db),
69 AttrDefId::ImplId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db),
70 AttrDefId::ConstId(it) => attrs_from_loc(it.lookup(db), db),
71 AttrDefId::FunctionId(it) => attrs_from_loc(it.lookup(db), db),
72 AttrDefId::TypeAliasId(it) => attrs_from_loc(it.lookup(db), db),
73 }
74 }
75
33 pub fn has_atom(&self, atom: &str) -> bool { 76 pub fn has_atom(&self, atom: &str) -> bool {
34 self.iter().any(|it| it.is_simple_atom(atom)) 77 self.iter().any(|it| it.is_simple_atom(atom))
35 } 78 }
79
80 pub fn find_string_value(&self, key: &str) -> Option<SmolStr> {
81 self.iter().filter(|attr| attr.is_simple_atom(key)).find_map(|attr| {
82 match attr.input.as_ref()? {
83 AttrInput::Literal(it) => Some(it.clone()),
84 _ => None,
85 }
86 })
87 }
36} 88}
37 89
38#[derive(Debug, Clone, PartialEq, Eq)] 90#[derive(Debug, Clone, PartialEq, Eq)]
@@ -106,3 +158,23 @@ impl Attr {
106 cfg_options.is_cfg_enabled(self.as_cfg()?) 158 cfg_options.is_cfg_enabled(self.as_cfg()?)
107 } 159 }
108} 160}
161
162fn attrs_from_ast<D, N>(src: AstId<N>, db: &D) -> Attrs
163where
164 N: ast::AttrsOwner,
165 D: DefDatabase,
166{
167 let hygiene = Hygiene::new(db, src.file_id());
168 Attr::from_attrs_owner(&src.to_node(db), &hygiene)
169}
170
171fn attrs_from_loc<T, D>(node: T, db: &D) -> Attrs
172where
173 T: HasSource,
174 T::Value: ast::AttrsOwner,
175 D: DefDatabase,
176{
177 let src = node.source(db);
178 let hygiene = Hygiene::new(db, src.file_id);
179 Attr::from_attrs_owner(&src.value, &hygiene)
180}
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs
index dfb79a30a..225638b42 100644
--- a/crates/ra_hir_def/src/body.rs
+++ b/crates/ra_hir_def/src/body.rs
@@ -13,7 +13,7 @@ use ra_syntax::{ast, AstNode, AstPtr};
13use rustc_hash::FxHashMap; 13use rustc_hash::FxHashMap;
14 14
15use crate::{ 15use crate::{
16 db::DefDatabase2, 16 db::DefDatabase,
17 expr::{Expr, ExprId, Pat, PatId}, 17 expr::{Expr, ExprId, Pat, PatId},
18 nameres::CrateDefMap, 18 nameres::CrateDefMap,
19 path::Path, 19 path::Path,
@@ -28,7 +28,7 @@ pub struct Expander {
28} 28}
29 29
30impl Expander { 30impl Expander {
31 pub fn new(db: &impl DefDatabase2, current_file_id: HirFileId, module: ModuleId) -> Expander { 31 pub fn new(db: &impl DefDatabase, current_file_id: HirFileId, module: ModuleId) -> Expander {
32 let crate_def_map = db.crate_def_map(module.krate); 32 let crate_def_map = db.crate_def_map(module.krate);
33 let hygiene = Hygiene::new(db, current_file_id); 33 let hygiene = Hygiene::new(db, current_file_id);
34 Expander { crate_def_map, current_file_id, hygiene, module } 34 Expander { crate_def_map, current_file_id, hygiene, module }
@@ -36,7 +36,7 @@ impl Expander {
36 36
37 fn enter_expand( 37 fn enter_expand(
38 &mut self, 38 &mut self,
39 db: &impl DefDatabase2, 39 db: &impl DefDatabase,
40 macro_call: ast::MacroCall, 40 macro_call: ast::MacroCall,
41 ) -> Option<(Mark, ast::Expr)> { 41 ) -> Option<(Mark, ast::Expr)> {
42 let ast_id = AstId::new( 42 let ast_id = AstId::new(
@@ -67,7 +67,7 @@ impl Expander {
67 None 67 None
68 } 68 }
69 69
70 fn exit(&mut self, db: &impl DefDatabase2, mark: Mark) { 70 fn exit(&mut self, db: &impl DefDatabase, mark: Mark) {
71 self.hygiene = Hygiene::new(db, mark.file_id); 71 self.hygiene = Hygiene::new(db, mark.file_id);
72 self.current_file_id = mark.file_id; 72 self.current_file_id = mark.file_id;
73 std::mem::forget(mark); 73 std::mem::forget(mark);
@@ -81,7 +81,7 @@ impl Expander {
81 Path::from_src(path, &self.hygiene) 81 Path::from_src(path, &self.hygiene)
82 } 82 }
83 83
84 fn resolve_path_as_macro(&self, db: &impl DefDatabase2, path: &Path) -> Option<MacroDefId> { 84 fn resolve_path_as_macro(&self, db: &impl DefDatabase, path: &Path) -> Option<MacroDefId> {
85 self.crate_def_map.resolve_path(db, self.module.module_id, path).0.get_macros() 85 self.crate_def_map.resolve_path(db, self.module.module_id, path).0.get_macros()
86 } 86 }
87} 87}
@@ -142,7 +142,7 @@ pub struct BodySourceMap {
142 142
143impl Body { 143impl Body {
144 pub(crate) fn body_with_source_map_query( 144 pub(crate) fn body_with_source_map_query(
145 db: &impl DefDatabase2, 145 db: &impl DefDatabase,
146 def: DefWithBodyId, 146 def: DefWithBodyId,
147 ) -> (Arc<Body>, Arc<BodySourceMap>) { 147 ) -> (Arc<Body>, Arc<BodySourceMap>) {
148 let mut params = None; 148 let mut params = None;
@@ -169,12 +169,12 @@ impl Body {
169 (Arc::new(body), Arc::new(source_map)) 169 (Arc::new(body), Arc::new(source_map))
170 } 170 }
171 171
172 pub(crate) fn body_query(db: &impl DefDatabase2, def: DefWithBodyId) -> Arc<Body> { 172 pub(crate) fn body_query(db: &impl DefDatabase, def: DefWithBodyId) -> Arc<Body> {
173 db.body_with_source_map(def).0 173 db.body_with_source_map(def).0
174 } 174 }
175 175
176 fn new( 176 fn new(
177 db: &impl DefDatabase2, 177 db: &impl DefDatabase,
178 expander: Expander, 178 expander: Expander,
179 params: Option<ast::ParamList>, 179 params: Option<ast::ParamList>,
180 body: Option<ast::Expr>, 180 body: Option<ast::Expr>,
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs
index d8e911aa5..f4640dfa4 100644
--- a/crates/ra_hir_def/src/body/lower.rs
+++ b/crates/ra_hir_def/src/body/lower.rs
@@ -17,7 +17,7 @@ use test_utils::tested_by;
17use crate::{ 17use crate::{
18 body::{Body, BodySourceMap, Expander, PatPtr}, 18 body::{Body, BodySourceMap, Expander, PatPtr},
19 builtin_type::{BuiltinFloat, BuiltinInt}, 19 builtin_type::{BuiltinFloat, BuiltinInt},
20 db::DefDatabase2, 20 db::DefDatabase,
21 expr::{ 21 expr::{
22 ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, LogicOp, 22 ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, LogicOp,
23 MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, 23 MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement,
@@ -28,7 +28,7 @@ use crate::{
28}; 28};
29 29
30pub(super) fn lower( 30pub(super) fn lower(
31 db: &impl DefDatabase2, 31 db: &impl DefDatabase,
32 expander: Expander, 32 expander: Expander,
33 params: Option<ast::ParamList>, 33 params: Option<ast::ParamList>,
34 body: Option<ast::Expr>, 34 body: Option<ast::Expr>,
@@ -57,7 +57,7 @@ struct ExprCollector<DB> {
57 57
58impl<'a, DB> ExprCollector<&'a DB> 58impl<'a, DB> ExprCollector<&'a DB>
59where 59where
60 DB: DefDatabase2, 60 DB: DefDatabase,
61{ 61{
62 fn collect( 62 fn collect(
63 mut self, 63 mut self,
diff --git a/crates/ra_hir_def/src/body/scope.rs b/crates/ra_hir_def/src/body/scope.rs
index 58740b679..20d707bc4 100644
--- a/crates/ra_hir_def/src/body/scope.rs
+++ b/crates/ra_hir_def/src/body/scope.rs
@@ -7,7 +7,7 @@ use rustc_hash::FxHashMap;
7 7
8use crate::{ 8use crate::{
9 body::Body, 9 body::Body,
10 db::DefDatabase2, 10 db::DefDatabase,
11 expr::{Expr, ExprId, Pat, PatId, Statement}, 11 expr::{Expr, ExprId, Pat, PatId, Statement},
12 DefWithBodyId, 12 DefWithBodyId,
13}; 13};
@@ -45,7 +45,7 @@ pub struct ScopeData {
45} 45}
46 46
47impl ExprScopes { 47impl ExprScopes {
48 pub(crate) fn expr_scopes_query(db: &impl DefDatabase2, def: DefWithBodyId) -> Arc<ExprScopes> { 48 pub(crate) fn expr_scopes_query(db: &impl DefDatabase, def: DefWithBodyId) -> Arc<ExprScopes> {
49 let body = db.body(def); 49 let body = db.body(def);
50 Arc::new(ExprScopes::new(&*body)) 50 Arc::new(ExprScopes::new(&*body))
51 } 51 }
@@ -176,7 +176,7 @@ mod tests {
176 use ra_syntax::{algo::find_node_at_offset, ast, AstNode}; 176 use ra_syntax::{algo::find_node_at_offset, ast, AstNode};
177 use test_utils::{assert_eq_text, covers, extract_offset}; 177 use test_utils::{assert_eq_text, covers, extract_offset};
178 178
179 use crate::{db::DefDatabase2, test_db::TestDB, FunctionId, ModuleDefId}; 179 use crate::{db::DefDatabase, test_db::TestDB, FunctionId, ModuleDefId};
180 180
181 fn find_function(db: &TestDB, file_id: FileId) -> FunctionId { 181 fn find_function(db: &TestDB, file_id: FileId) -> FunctionId {
182 let krate = db.test_crate(); 182 let krate = db.test_crate();
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs
index 91bac7415..f0b3e198a 100644
--- a/crates/ra_hir_def/src/data.rs
+++ b/crates/ra_hir_def/src/data.rs
@@ -9,7 +9,7 @@ use hir_expand::{
9use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; 9use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner};
10 10
11use crate::{ 11use crate::{
12 db::DefDatabase2, 12 db::DefDatabase,
13 type_ref::{Mutability, TypeRef}, 13 type_ref::{Mutability, TypeRef},
14 AssocItemId, AstItemDef, ConstId, ConstLoc, ContainerId, FunctionId, FunctionLoc, HasSource, 14 AssocItemId, AstItemDef, ConstId, ConstLoc, ContainerId, FunctionId, FunctionLoc, HasSource,
15 ImplId, Intern, Lookup, StaticId, TraitId, TypeAliasId, TypeAliasLoc, 15 ImplId, Intern, Lookup, StaticId, TraitId, TypeAliasId, TypeAliasLoc,
@@ -26,7 +26,7 @@ pub struct FunctionData {
26} 26}
27 27
28impl FunctionData { 28impl FunctionData {
29 pub(crate) fn fn_data_query(db: &impl DefDatabase2, func: FunctionId) -> Arc<FunctionData> { 29 pub(crate) fn fn_data_query(db: &impl DefDatabase, func: FunctionId) -> Arc<FunctionData> {
30 let src = func.lookup(db).source(db); 30 let src = func.lookup(db).source(db);
31 let name = src.value.name().map(|n| n.as_name()).unwrap_or_else(Name::missing); 31 let name = src.value.name().map(|n| n.as_name()).unwrap_or_else(Name::missing);
32 let mut params = Vec::new(); 32 let mut params = Vec::new();
@@ -74,7 +74,7 @@ pub struct TypeAliasData {
74 74
75impl TypeAliasData { 75impl TypeAliasData {
76 pub(crate) fn type_alias_data_query( 76 pub(crate) fn type_alias_data_query(
77 db: &impl DefDatabase2, 77 db: &impl DefDatabase,
78 typ: TypeAliasId, 78 typ: TypeAliasId,
79 ) -> Arc<TypeAliasData> { 79 ) -> Arc<TypeAliasData> {
80 let node = typ.lookup(db).source(db).value; 80 let node = typ.lookup(db).source(db).value;
@@ -92,7 +92,7 @@ pub struct TraitData {
92} 92}
93 93
94impl TraitData { 94impl TraitData {
95 pub(crate) fn trait_data_query(db: &impl DefDatabase2, tr: TraitId) -> Arc<TraitData> { 95 pub(crate) fn trait_data_query(db: &impl DefDatabase, tr: TraitId) -> Arc<TraitData> {
96 let src = tr.source(db); 96 let src = tr.source(db);
97 let name = src.value.name().map(|n| n.as_name()); 97 let name = src.value.name().map(|n| n.as_name());
98 let auto = src.value.is_auto(); 98 let auto = src.value.is_auto();
@@ -144,7 +144,7 @@ pub struct ImplData {
144} 144}
145 145
146impl ImplData { 146impl ImplData {
147 pub(crate) fn impl_data_query(db: &impl DefDatabase2, id: ImplId) -> Arc<ImplData> { 147 pub(crate) fn impl_data_query(db: &impl DefDatabase, id: ImplId) -> Arc<ImplData> {
148 let src = id.source(db); 148 let src = id.source(db);
149 let items = db.ast_id_map(src.file_id); 149 let items = db.ast_id_map(src.file_id);
150 150
@@ -198,12 +198,12 @@ pub struct ConstData {
198} 198}
199 199
200impl ConstData { 200impl ConstData {
201 pub(crate) fn const_data_query(db: &impl DefDatabase2, konst: ConstId) -> Arc<ConstData> { 201 pub(crate) fn const_data_query(db: &impl DefDatabase, konst: ConstId) -> Arc<ConstData> {
202 let node = konst.lookup(db).source(db).value; 202 let node = konst.lookup(db).source(db).value;
203 const_data_for(&node) 203 const_data_for(&node)
204 } 204 }
205 205
206 pub(crate) fn static_data_query(db: &impl DefDatabase2, konst: StaticId) -> Arc<ConstData> { 206 pub(crate) fn static_data_query(db: &impl DefDatabase, konst: StaticId) -> Arc<ConstData> {
207 let node = konst.source(db).value; 207 let node = konst.source(db).value;
208 const_data_for(&node) 208 const_data_for(&node)
209 } 209 }
diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs
index 2c660ab88..7fec2e8c0 100644
--- a/crates/ra_hir_def/src/db.rs
+++ b/crates/ra_hir_def/src/db.rs
@@ -3,43 +3,46 @@ use std::sync::Arc;
3 3
4use hir_expand::{db::AstDatabase, HirFileId}; 4use hir_expand::{db::AstDatabase, HirFileId};
5use ra_db::{salsa, CrateId, SourceDatabase}; 5use ra_db::{salsa, CrateId, SourceDatabase};
6use ra_syntax::ast; 6use ra_syntax::{ast, SmolStr};
7 7
8use crate::{ 8use crate::{
9 adt::{EnumData, StructData}, 9 adt::{EnumData, StructData},
10 attr::Attrs,
10 body::{scope::ExprScopes, Body, BodySourceMap}, 11 body::{scope::ExprScopes, Body, BodySourceMap},
11 data::{ConstData, FunctionData, ImplData, TraitData, TypeAliasData}, 12 data::{ConstData, FunctionData, ImplData, TraitData, TypeAliasData},
13 docs::Documentation,
12 generics::GenericParams, 14 generics::GenericParams,
15 lang_item::{LangItemTarget, LangItems},
13 nameres::{ 16 nameres::{
14 raw::{ImportSourceMap, RawItems}, 17 raw::{ImportSourceMap, RawItems},
15 CrateDefMap, 18 CrateDefMap,
16 }, 19 },
17 ConstId, DefWithBodyId, EnumId, FunctionId, GenericDefId, ImplId, ItemLoc, StaticId, 20 AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, FunctionId, FunctionLoc, GenericDefId,
18 StructOrUnionId, TraitId, TypeAliasId, 21 ImplId, ItemLoc, ModuleId, StaticId, StructOrUnionId, TraitId, TypeAliasId, TypeAliasLoc,
19}; 22};
20 23
21#[salsa::query_group(InternDatabaseStorage)] 24#[salsa::query_group(InternDatabaseStorage)]
22pub trait InternDatabase: SourceDatabase { 25pub trait InternDatabase: SourceDatabase {
23 #[salsa::interned] 26 #[salsa::interned]
24 fn intern_function(&self, loc: crate::FunctionLoc) -> crate::FunctionId; 27 fn intern_function(&self, loc: FunctionLoc) -> FunctionId;
25 #[salsa::interned] 28 #[salsa::interned]
26 fn intern_struct_or_union(&self, loc: ItemLoc<ast::StructDef>) -> crate::StructOrUnionId; 29 fn intern_struct_or_union(&self, loc: ItemLoc<ast::StructDef>) -> StructOrUnionId;
27 #[salsa::interned] 30 #[salsa::interned]
28 fn intern_enum(&self, loc: ItemLoc<ast::EnumDef>) -> crate::EnumId; 31 fn intern_enum(&self, loc: ItemLoc<ast::EnumDef>) -> EnumId;
29 #[salsa::interned] 32 #[salsa::interned]
30 fn intern_const(&self, loc: crate::ConstLoc) -> crate::ConstId; 33 fn intern_const(&self, loc: ConstLoc) -> ConstId;
31 #[salsa::interned] 34 #[salsa::interned]
32 fn intern_static(&self, loc: ItemLoc<ast::StaticDef>) -> crate::StaticId; 35 fn intern_static(&self, loc: ItemLoc<ast::StaticDef>) -> StaticId;
33 #[salsa::interned] 36 #[salsa::interned]
34 fn intern_trait(&self, loc: ItemLoc<ast::TraitDef>) -> crate::TraitId; 37 fn intern_trait(&self, loc: ItemLoc<ast::TraitDef>) -> TraitId;
35 #[salsa::interned] 38 #[salsa::interned]
36 fn intern_type_alias(&self, loc: crate::TypeAliasLoc) -> crate::TypeAliasId; 39 fn intern_type_alias(&self, loc: TypeAliasLoc) -> TypeAliasId;
37 #[salsa::interned] 40 #[salsa::interned]
38 fn intern_impl(&self, loc: ItemLoc<ast::ImplBlock>) -> crate::ImplId; 41 fn intern_impl(&self, loc: ItemLoc<ast::ImplBlock>) -> ImplId;
39} 42}
40 43
41#[salsa::query_group(DefDatabase2Storage)] 44#[salsa::query_group(DefDatabaseStorage)]
42pub trait DefDatabase2: InternDatabase + AstDatabase { 45pub trait DefDatabase: InternDatabase + AstDatabase {
43 #[salsa::invoke(RawItems::raw_items_with_source_map_query)] 46 #[salsa::invoke(RawItems::raw_items_with_source_map_query)]
44 fn raw_items_with_source_map( 47 fn raw_items_with_source_map(
45 &self, 48 &self,
@@ -87,4 +90,21 @@ pub trait DefDatabase2: InternDatabase + AstDatabase {
87 90
88 #[salsa::invoke(GenericParams::generic_params_query)] 91 #[salsa::invoke(GenericParams::generic_params_query)]
89 fn generic_params(&self, def: GenericDefId) -> Arc<GenericParams>; 92 fn generic_params(&self, def: GenericDefId) -> Arc<GenericParams>;
93
94 #[salsa::invoke(Attrs::attrs_query)]
95 fn attrs(&self, def: AttrDefId) -> Attrs;
96
97 #[salsa::invoke(LangItems::module_lang_items_query)]
98 fn module_lang_items(&self, module: ModuleId) -> Option<Arc<LangItems>>;
99
100 #[salsa::invoke(LangItems::crate_lang_items_query)]
101 fn crate_lang_items(&self, krate: CrateId) -> Arc<LangItems>;
102
103 #[salsa::invoke(LangItems::lang_item_query)]
104 fn lang_item(&self, start_crate: CrateId, item: SmolStr) -> Option<LangItemTarget>;
105
106 // FIXME(https://github.com/rust-analyzer/rust-analyzer/issues/2148#issuecomment-550519102)
107 // Remove this query completely, in favor of `Attrs::docs` method
108 #[salsa::invoke(Documentation::documentation_query)]
109 fn documentation(&self, def: AttrDefId) -> Option<Documentation>;
90} 110}
diff --git a/crates/ra_hir_def/src/docs.rs b/crates/ra_hir_def/src/docs.rs
new file mode 100644
index 000000000..69846fd1b
--- /dev/null
+++ b/crates/ra_hir_def/src/docs.rs
@@ -0,0 +1,68 @@
1//! FIXME: write short doc here
2
3use std::sync::Arc;
4
5use hir_expand::either::Either;
6use ra_syntax::ast;
7
8use crate::{db::DefDatabase, AdtId, AstItemDef, AttrDefId, HasChildSource, HasSource, Lookup};
9
10/// Holds documentation
11#[derive(Debug, Clone, PartialEq, Eq)]
12pub struct Documentation(Arc<str>);
13
14impl Into<String> for Documentation {
15 fn into(self) -> String {
16 self.as_str().to_owned()
17 }
18}
19
20impl Documentation {
21 fn new(s: &str) -> Documentation {
22 Documentation(s.into())
23 }
24
25 pub fn as_str(&self) -> &str {
26 &*self.0
27 }
28
29 pub(crate) fn documentation_query(
30 db: &impl DefDatabase,
31 def: AttrDefId,
32 ) -> Option<Documentation> {
33 match def {
34 AttrDefId::ModuleId(module) => {
35 let def_map = db.crate_def_map(module.krate);
36 let src = def_map[module.module_id].declaration_source(db)?;
37 docs_from_ast(&src.value)
38 }
39 AttrDefId::StructFieldId(it) => {
40 let src = it.parent.child_source(db);
41 match &src.value[it.local_id] {
42 Either::A(_tuple) => None,
43 Either::B(record) => docs_from_ast(record),
44 }
45 }
46 AttrDefId::AdtId(it) => match it {
47 AdtId::StructId(it) => docs_from_ast(&it.0.source(db).value),
48 AdtId::EnumId(it) => docs_from_ast(&it.source(db).value),
49 AdtId::UnionId(it) => docs_from_ast(&it.0.source(db).value),
50 },
51 AttrDefId::EnumVariantId(it) => {
52 let src = it.parent.child_source(db);
53 docs_from_ast(&src.value[it.local_id])
54 }
55 AttrDefId::StaticId(it) => docs_from_ast(&it.source(db).value),
56 AttrDefId::TraitId(it) => docs_from_ast(&it.source(db).value),
57 AttrDefId::MacroDefId(it) => docs_from_ast(&it.ast_id.to_node(db)),
58 AttrDefId::ConstId(it) => docs_from_ast(&it.lookup(db).source(db).value),
59 AttrDefId::FunctionId(it) => docs_from_ast(&it.lookup(db).source(db).value),
60 AttrDefId::TypeAliasId(it) => docs_from_ast(&it.lookup(db).source(db).value),
61 AttrDefId::ImplId(_) => None,
62 }
63 }
64}
65
66pub(crate) fn docs_from_ast(node: &impl ast::DocCommentsOwner) -> Option<Documentation> {
67 node.doc_comment_text().map(|it| Documentation::new(&it))
68}
diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs
index 9e2e4c3cc..015fe772e 100644
--- a/crates/ra_hir_def/src/generics.rs
+++ b/crates/ra_hir_def/src/generics.rs
@@ -8,7 +8,7 @@ use hir_expand::name::{self, AsName, Name};
8use ra_syntax::ast::{self, NameOwner, TypeBoundsOwner, TypeParamsOwner}; 8use ra_syntax::ast::{self, NameOwner, TypeBoundsOwner, TypeParamsOwner};
9 9
10use crate::{ 10use crate::{
11 db::DefDatabase2, 11 db::DefDatabase,
12 type_ref::{TypeBound, TypeRef}, 12 type_ref::{TypeBound, TypeRef},
13 AdtId, AstItemDef, ContainerId, GenericDefId, HasSource, Lookup, 13 AdtId, AstItemDef, ContainerId, GenericDefId, HasSource, Lookup,
14}; 14};
@@ -42,7 +42,7 @@ pub struct WherePredicate {
42 42
43impl GenericParams { 43impl GenericParams {
44 pub(crate) fn generic_params_query( 44 pub(crate) fn generic_params_query(
45 db: &impl DefDatabase2, 45 db: &impl DefDatabase,
46 def: GenericDefId, 46 def: GenericDefId,
47 ) -> Arc<GenericParams> { 47 ) -> Arc<GenericParams> {
48 let parent_generics = parent_generic_def(db, def).map(|it| db.generic_params(it)); 48 let parent_generics = parent_generic_def(db, def).map(|it| db.generic_params(it));
@@ -50,7 +50,7 @@ impl GenericParams {
50 } 50 }
51 51
52 fn new( 52 fn new(
53 db: &impl DefDatabase2, 53 db: &impl DefDatabase,
54 def: GenericDefId, 54 def: GenericDefId,
55 parent_params: Option<Arc<GenericParams>>, 55 parent_params: Option<Arc<GenericParams>>,
56 ) -> GenericParams { 56 ) -> GenericParams {
@@ -168,7 +168,7 @@ impl GenericParams {
168 } 168 }
169} 169}
170 170
171fn parent_generic_def(db: &impl DefDatabase2, def: GenericDefId) -> Option<GenericDefId> { 171fn parent_generic_def(db: &impl DefDatabase, def: GenericDefId) -> Option<GenericDefId> {
172 let container = match def { 172 let container = match def {
173 GenericDefId::FunctionId(it) => it.lookup(db).container, 173 GenericDefId::FunctionId(it) => it.lookup(db).container,
174 GenericDefId::TypeAliasId(it) => it.lookup(db).container, 174 GenericDefId::TypeAliasId(it) => it.lookup(db).container,
diff --git a/crates/ra_hir_def/src/lang_item.rs b/crates/ra_hir_def/src/lang_item.rs
new file mode 100644
index 000000000..df951c533
--- /dev/null
+++ b/crates/ra_hir_def/src/lang_item.rs
@@ -0,0 +1,120 @@
1//! Collects lang items: items marked with `#[lang = "..."]` attribute.
2//!
3//! This attribute to tell the compiler about semi built-in std library
4//! features, such as Fn family of traits.
5use std::sync::Arc;
6
7use ra_syntax::SmolStr;
8use rustc_hash::FxHashMap;
9
10use crate::{
11 db::DefDatabase, AdtId, AttrDefId, CrateId, EnumId, FunctionId, ImplId, ModuleDefId, ModuleId,
12 StaticId, StructId, TraitId,
13};
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
16pub enum LangItemTarget {
17 EnumId(EnumId),
18 FunctionId(FunctionId),
19 ImplBlockId(ImplId),
20 StaticId(StaticId),
21 StructId(StructId),
22 TraitId(TraitId),
23}
24
25#[derive(Default, Debug, Clone, PartialEq, Eq)]
26pub struct LangItems {
27 items: FxHashMap<SmolStr, LangItemTarget>,
28}
29
30impl LangItems {
31 pub fn target<'a>(&'a self, item: &str) -> Option<&'a LangItemTarget> {
32 self.items.get(item)
33 }
34
35 /// Salsa query. This will look for lang items in a specific crate.
36 pub(crate) fn crate_lang_items_query(db: &impl DefDatabase, krate: CrateId) -> Arc<LangItems> {
37 let mut lang_items = LangItems::default();
38
39 let crate_def_map = db.crate_def_map(krate);
40
41 crate_def_map
42 .modules()
43 .filter_map(|module_id| db.module_lang_items(ModuleId { krate, module_id }))
44 .for_each(|it| lang_items.items.extend(it.items.iter().map(|(k, v)| (k.clone(), *v))));
45
46 Arc::new(lang_items)
47 }
48
49 pub(crate) fn module_lang_items_query(
50 db: &impl DefDatabase,
51 module: ModuleId,
52 ) -> Option<Arc<LangItems>> {
53 let mut lang_items = LangItems::default();
54 lang_items.collect_lang_items(db, module);
55 if lang_items.items.is_empty() {
56 None
57 } else {
58 Some(Arc::new(lang_items))
59 }
60 }
61
62 /// Salsa query. Look for a lang item, starting from the specified crate and recursively
63 /// traversing its dependencies.
64 pub(crate) fn lang_item_query(
65 db: &impl DefDatabase,
66 start_crate: CrateId,
67 item: SmolStr,
68 ) -> Option<LangItemTarget> {
69 let lang_items = db.crate_lang_items(start_crate);
70 let start_crate_target = lang_items.items.get(&item);
71 if let Some(target) = start_crate_target {
72 return Some(*target);
73 }
74 db.crate_graph()
75 .dependencies(start_crate)
76 .find_map(|dep| db.lang_item(dep.crate_id, item.clone()))
77 }
78
79 fn collect_lang_items(&mut self, db: &impl DefDatabase, module: ModuleId) {
80 // Look for impl targets
81 let def_map = db.crate_def_map(module.krate);
82 let module_data = &def_map[module.module_id];
83 for &impl_block in module_data.impls.iter() {
84 self.collect_lang_item(db, impl_block, LangItemTarget::ImplBlockId)
85 }
86
87 for def in module_data.scope.declarations() {
88 match def {
89 ModuleDefId::TraitId(trait_) => {
90 self.collect_lang_item(db, trait_, LangItemTarget::TraitId)
91 }
92 ModuleDefId::AdtId(AdtId::EnumId(e)) => {
93 self.collect_lang_item(db, e, LangItemTarget::EnumId)
94 }
95 ModuleDefId::AdtId(AdtId::StructId(s)) => {
96 self.collect_lang_item(db, s, LangItemTarget::StructId)
97 }
98 ModuleDefId::FunctionId(f) => {
99 self.collect_lang_item(db, f, LangItemTarget::FunctionId)
100 }
101 ModuleDefId::StaticId(s) => self.collect_lang_item(db, s, LangItemTarget::StaticId),
102 _ => {}
103 }
104 }
105 }
106
107 fn collect_lang_item<T>(
108 &mut self,
109 db: &impl DefDatabase,
110 item: T,
111 constructor: fn(T) -> LangItemTarget,
112 ) where
113 T: Into<AttrDefId> + Copy,
114 {
115 let attrs = db.attrs(item.into());
116 if let Some(lang_item_name) = attrs.find_string_value("lang") {
117 self.items.entry(lang_item_name).or_insert_with(|| constructor(item));
118 }
119 }
120}
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs
index 3a0420da0..1d195d65d 100644
--- a/crates/ra_hir_def/src/lib.rs
+++ b/crates/ra_hir_def/src/lib.rs
@@ -19,96 +19,42 @@ pub mod body;
19pub mod generics; 19pub mod generics;
20pub mod resolver; 20pub mod resolver;
21pub mod data; 21pub mod data;
22pub mod lang_item;
23pub mod docs;
24pub mod per_ns;
25
26mod trace;
27mod nameres;
22 28
23#[cfg(test)] 29#[cfg(test)]
24mod test_db; 30mod test_db;
25#[cfg(test)] 31#[cfg(test)]
26mod marks; 32mod marks;
27 33
28// FIXME: this should be private
29pub mod nameres;
30
31use std::hash::{Hash, Hasher}; 34use std::hash::{Hash, Hasher};
32 35
33use hir_expand::{ast_id_map::FileAstId, db::AstDatabase, AstId, HirFileId, Source}; 36use hir_expand::{ast_id_map::FileAstId, db::AstDatabase, AstId, HirFileId, MacroDefId, Source};
34use ra_arena::{impl_arena_id, RawId}; 37use ra_arena::{impl_arena_id, map::ArenaMap, RawId};
35use ra_db::{salsa, CrateId, FileId}; 38use ra_db::{salsa, CrateId};
36use ra_syntax::{ast, AstNode, SyntaxNode}; 39use ra_syntax::{ast, AstNode};
37 40
38use crate::{builtin_type::BuiltinType, db::InternDatabase}; 41use crate::{builtin_type::BuiltinType, db::InternDatabase};
39 42
40pub enum ModuleSource { 43#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
41 SourceFile(ast::SourceFile), 44pub struct LocalImportId(RawId);
42 Module(ast::Module), 45impl_arena_id!(LocalImportId);
43}
44
45impl ModuleSource {
46 pub fn new(
47 db: &impl db::DefDatabase2,
48 file_id: Option<FileId>,
49 decl_id: Option<AstId<ast::Module>>,
50 ) -> ModuleSource {
51 match (file_id, decl_id) {
52 (Some(file_id), _) => {
53 let source_file = db.parse(file_id).tree();
54 ModuleSource::SourceFile(source_file)
55 }
56 (None, Some(item_id)) => {
57 let module = item_id.to_node(db);
58 assert!(module.item_list().is_some(), "expected inline module");
59 ModuleSource::Module(module)
60 }
61 (None, None) => panic!(),
62 }
63 }
64
65 // FIXME: this methods do not belong here
66 pub fn from_position(
67 db: &impl db::DefDatabase2,
68 position: ra_db::FilePosition,
69 ) -> ModuleSource {
70 let parse = db.parse(position.file_id);
71 match &ra_syntax::algo::find_node_at_offset::<ast::Module>(
72 parse.tree().syntax(),
73 position.offset,
74 ) {
75 Some(m) if !m.has_semi() => ModuleSource::Module(m.clone()),
76 _ => {
77 let source_file = parse.tree();
78 ModuleSource::SourceFile(source_file)
79 }
80 }
81 }
82
83 pub fn from_child_node(db: &impl db::DefDatabase2, child: Source<&SyntaxNode>) -> ModuleSource {
84 if let Some(m) =
85 child.value.ancestors().filter_map(ast::Module::cast).find(|it| !it.has_semi())
86 {
87 ModuleSource::Module(m)
88 } else {
89 let file_id = child.file_id.original_file(db);
90 let source_file = db.parse(file_id).tree();
91 ModuleSource::SourceFile(source_file)
92 }
93 }
94
95 pub fn from_file_id(db: &impl db::DefDatabase2, file_id: FileId) -> ModuleSource {
96 let source_file = db.parse(file_id).tree();
97 ModuleSource::SourceFile(source_file)
98 }
99}
100 46
101#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 47#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
102pub struct ModuleId { 48pub struct ModuleId {
103 pub krate: CrateId, 49 pub krate: CrateId,
104 pub module_id: CrateModuleId, 50 pub module_id: LocalModuleId,
105} 51}
106 52
107/// An ID of a module, **local** to a specific crate 53/// An ID of a module, **local** to a specific crate
108// FIXME: rename to `LocalModuleId`. 54// FIXME: rename to `LocalModuleId`.
109#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 55#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
110pub struct CrateModuleId(RawId); 56pub struct LocalModuleId(RawId);
111impl_arena_id!(CrateModuleId); 57impl_arena_id!(LocalModuleId);
112 58
113macro_rules! impl_intern_key { 59macro_rules! impl_intern_key {
114 ($name:ident) => { 60 ($name:ident) => {
@@ -207,14 +153,14 @@ pub struct FunctionLoc {
207 153
208impl Intern for FunctionLoc { 154impl Intern for FunctionLoc {
209 type ID = FunctionId; 155 type ID = FunctionId;
210 fn intern(self, db: &impl db::DefDatabase2) -> FunctionId { 156 fn intern(self, db: &impl db::DefDatabase) -> FunctionId {
211 db.intern_function(self) 157 db.intern_function(self)
212 } 158 }
213} 159}
214 160
215impl Lookup for FunctionId { 161impl Lookup for FunctionId {
216 type Data = FunctionLoc; 162 type Data = FunctionLoc;
217 fn lookup(&self, db: &impl db::DefDatabase2) -> FunctionLoc { 163 fn lookup(&self, db: &impl db::DefDatabase) -> FunctionLoc {
218 db.lookup_intern_function(*self) 164 db.lookup_intern_function(*self)
219 } 165 }
220} 166}
@@ -278,8 +224,8 @@ pub enum VariantId {
278 224
279#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 225#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
280pub struct StructFieldId { 226pub struct StructFieldId {
281 parent: VariantId, 227 pub parent: VariantId,
282 local_id: LocalStructFieldId, 228 pub local_id: LocalStructFieldId,
283} 229}
284 230
285#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 231#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -297,14 +243,14 @@ pub struct ConstLoc {
297 243
298impl Intern for ConstLoc { 244impl Intern for ConstLoc {
299 type ID = ConstId; 245 type ID = ConstId;
300 fn intern(self, db: &impl db::DefDatabase2) -> ConstId { 246 fn intern(self, db: &impl db::DefDatabase) -> ConstId {
301 db.intern_const(self) 247 db.intern_const(self)
302 } 248 }
303} 249}
304 250
305impl Lookup for ConstId { 251impl Lookup for ConstId {
306 type Data = ConstLoc; 252 type Data = ConstLoc;
307 fn lookup(&self, db: &impl db::DefDatabase2) -> ConstLoc { 253 fn lookup(&self, db: &impl db::DefDatabase) -> ConstLoc {
308 db.lookup_intern_const(*self) 254 db.lookup_intern_const(*self)
309 } 255 }
310} 256}
@@ -345,14 +291,14 @@ pub struct TypeAliasLoc {
345 291
346impl Intern for TypeAliasLoc { 292impl Intern for TypeAliasLoc {
347 type ID = TypeAliasId; 293 type ID = TypeAliasId;
348 fn intern(self, db: &impl db::DefDatabase2) -> TypeAliasId { 294 fn intern(self, db: &impl db::DefDatabase) -> TypeAliasId {
349 db.intern_type_alias(self) 295 db.intern_type_alias(self)
350 } 296 }
351} 297}
352 298
353impl Lookup for TypeAliasId { 299impl Lookup for TypeAliasId {
354 type Data = TypeAliasLoc; 300 type Data = TypeAliasLoc;
355 fn lookup(&self, db: &impl db::DefDatabase2) -> TypeAliasLoc { 301 fn lookup(&self, db: &impl db::DefDatabase) -> TypeAliasLoc {
356 db.lookup_intern_type_alias(*self) 302 db.lookup_intern_type_alias(*self)
357 } 303 }
358} 304}
@@ -475,22 +421,51 @@ impl_froms!(
475 ConstId 421 ConstId
476); 422);
477 423
424#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
425pub enum AttrDefId {
426 ModuleId(ModuleId),
427 StructFieldId(StructFieldId),
428 AdtId(AdtId),
429 FunctionId(FunctionId),
430 EnumVariantId(EnumVariantId),
431 StaticId(StaticId),
432 ConstId(ConstId),
433 TraitId(TraitId),
434 TypeAliasId(TypeAliasId),
435 MacroDefId(MacroDefId),
436 ImplId(ImplId),
437}
438
439impl_froms!(
440 AttrDefId: ModuleId,
441 StructFieldId,
442 AdtId(StructId, EnumId, UnionId),
443 EnumVariantId,
444 StaticId,
445 ConstId,
446 FunctionId,
447 TraitId,
448 TypeAliasId,
449 MacroDefId,
450 ImplId
451);
452
478trait Intern { 453trait Intern {
479 type ID; 454 type ID;
480 fn intern(self, db: &impl db::DefDatabase2) -> Self::ID; 455 fn intern(self, db: &impl db::DefDatabase) -> Self::ID;
481} 456}
482 457
483pub trait Lookup { 458pub trait Lookup {
484 type Data; 459 type Data;
485 fn lookup(&self, db: &impl db::DefDatabase2) -> Self::Data; 460 fn lookup(&self, db: &impl db::DefDatabase) -> Self::Data;
486} 461}
487 462
488pub trait HasModule { 463pub trait HasModule {
489 fn module(&self, db: &impl db::DefDatabase2) -> ModuleId; 464 fn module(&self, db: &impl db::DefDatabase) -> ModuleId;
490} 465}
491 466
492impl HasModule for FunctionLoc { 467impl HasModule for FunctionLoc {
493 fn module(&self, db: &impl db::DefDatabase2) -> ModuleId { 468 fn module(&self, db: &impl db::DefDatabase) -> ModuleId {
494 match self.container { 469 match self.container {
495 ContainerId::ModuleId(it) => it, 470 ContainerId::ModuleId(it) => it,
496 ContainerId::ImplId(it) => it.module(db), 471 ContainerId::ImplId(it) => it.module(db),
@@ -500,7 +475,7 @@ impl HasModule for FunctionLoc {
500} 475}
501 476
502impl HasModule for TypeAliasLoc { 477impl HasModule for TypeAliasLoc {
503 fn module(&self, db: &impl db::DefDatabase2) -> ModuleId { 478 fn module(&self, db: &impl db::DefDatabase) -> ModuleId {
504 match self.container { 479 match self.container {
505 ContainerId::ModuleId(it) => it, 480 ContainerId::ModuleId(it) => it,
506 ContainerId::ImplId(it) => it.module(db), 481 ContainerId::ImplId(it) => it.module(db),
@@ -510,7 +485,7 @@ impl HasModule for TypeAliasLoc {
510} 485}
511 486
512impl HasModule for ConstLoc { 487impl HasModule for ConstLoc {
513 fn module(&self, db: &impl db::DefDatabase2) -> ModuleId { 488 fn module(&self, db: &impl db::DefDatabase) -> ModuleId {
514 match self.container { 489 match self.container {
515 ContainerId::ModuleId(it) => it, 490 ContainerId::ModuleId(it) => it,
516 ContainerId::ImplId(it) => it.module(db), 491 ContainerId::ImplId(it) => it.module(db),
@@ -521,13 +496,13 @@ impl HasModule for ConstLoc {
521 496
522pub trait HasSource { 497pub trait HasSource {
523 type Value; 498 type Value;
524 fn source(&self, db: &impl db::DefDatabase2) -> Source<Self::Value>; 499 fn source(&self, db: &impl db::DefDatabase) -> Source<Self::Value>;
525} 500}
526 501
527impl HasSource for FunctionLoc { 502impl HasSource for FunctionLoc {
528 type Value = ast::FnDef; 503 type Value = ast::FnDef;
529 504
530 fn source(&self, db: &impl db::DefDatabase2) -> Source<ast::FnDef> { 505 fn source(&self, db: &impl db::DefDatabase) -> Source<ast::FnDef> {
531 let node = self.ast_id.to_node(db); 506 let node = self.ast_id.to_node(db);
532 Source::new(self.ast_id.file_id(), node) 507 Source::new(self.ast_id.file_id(), node)
533 } 508 }
@@ -536,7 +511,7 @@ impl HasSource for FunctionLoc {
536impl HasSource for TypeAliasLoc { 511impl HasSource for TypeAliasLoc {
537 type Value = ast::TypeAliasDef; 512 type Value = ast::TypeAliasDef;
538 513
539 fn source(&self, db: &impl db::DefDatabase2) -> Source<ast::TypeAliasDef> { 514 fn source(&self, db: &impl db::DefDatabase) -> Source<ast::TypeAliasDef> {
540 let node = self.ast_id.to_node(db); 515 let node = self.ast_id.to_node(db);
541 Source::new(self.ast_id.file_id(), node) 516 Source::new(self.ast_id.file_id(), node)
542 } 517 }
@@ -545,8 +520,17 @@ impl HasSource for TypeAliasLoc {
545impl HasSource for ConstLoc { 520impl HasSource for ConstLoc {
546 type Value = ast::ConstDef; 521 type Value = ast::ConstDef;
547 522
548 fn source(&self, db: &impl db::DefDatabase2) -> Source<ast::ConstDef> { 523 fn source(&self, db: &impl db::DefDatabase) -> Source<ast::ConstDef> {
549 let node = self.ast_id.to_node(db); 524 let node = self.ast_id.to_node(db);
550 Source::new(self.ast_id.file_id(), node) 525 Source::new(self.ast_id.file_id(), node)
551 } 526 }
552} 527}
528
529pub trait HasChildSource {
530 type ChildId;
531 type Value;
532 fn child_source(
533 &self,
534 db: &impl db::DefDatabase,
535 ) -> Source<ArenaMap<Self::ChildId, Self::Value>>;
536}
diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs
index c01e020ef..3b2e99647 100644
--- a/crates/ra_hir_def/src/nameres.rs
+++ b/crates/ra_hir_def/src/nameres.rs
@@ -47,8 +47,7 @@
47//! path and, upon success, we run macro expansion and "collect module" phase on 47//! path and, upon success, we run macro expansion and "collect module" phase on
48//! the result 48//! the result
49 49
50pub mod raw; 50pub(crate) mod raw;
51pub mod per_ns;
52mod collector; 51mod collector;
53mod mod_resolution; 52mod mod_resolution;
54mod path_resolution; 53mod path_resolution;
@@ -58,7 +57,10 @@ mod tests;
58 57
59use std::sync::Arc; 58use std::sync::Arc;
60 59
61use hir_expand::{ast_id_map::FileAstId, diagnostics::DiagnosticSink, name::Name, MacroDefId}; 60use hir_expand::{
61 ast_id_map::FileAstId, diagnostics::DiagnosticSink, either::Either, name::Name, MacroDefId,
62 Source,
63};
62use once_cell::sync::Lazy; 64use once_cell::sync::Lazy;
63use ra_arena::Arena; 65use ra_arena::Arena;
64use ra_db::{CrateId, Edition, FileId}; 66use ra_db::{CrateId, Edition, FileId};
@@ -68,12 +70,11 @@ use rustc_hash::{FxHashMap, FxHashSet};
68 70
69use crate::{ 71use crate::{
70 builtin_type::BuiltinType, 72 builtin_type::BuiltinType,
71 db::DefDatabase2, 73 db::DefDatabase,
72 nameres::{ 74 nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode},
73 diagnostics::DefDiagnostic, path_resolution::ResolveMode, per_ns::PerNs, raw::ImportId,
74 },
75 path::Path, 75 path::Path,
76 AstId, CrateModuleId, FunctionId, ImplId, ModuleDefId, ModuleId, TraitId, 76 per_ns::PerNs,
77 AstId, FunctionId, ImplId, LocalImportId, LocalModuleId, ModuleDefId, ModuleId, TraitId,
77}; 78};
78 79
79/// Contains all top-level defs from a macro-expanded crate 80/// Contains all top-level defs from a macro-expanded crate
@@ -86,8 +87,8 @@ pub struct CrateDefMap {
86 /// a dependency (`std` or `core`). 87 /// a dependency (`std` or `core`).
87 prelude: Option<ModuleId>, 88 prelude: Option<ModuleId>,
88 extern_prelude: FxHashMap<Name, ModuleDefId>, 89 extern_prelude: FxHashMap<Name, ModuleDefId>,
89 root: CrateModuleId, 90 root: LocalModuleId,
90 modules: Arena<CrateModuleId, ModuleData>, 91 modules: Arena<LocalModuleId, ModuleData>,
91 92
92 /// Some macros are not well-behavior, which leads to infinite loop 93 /// Some macros are not well-behavior, which leads to infinite loop
93 /// e.g. macro_rules! foo { ($ty:ty) => { foo!($ty); } } 94 /// e.g. macro_rules! foo { ($ty:ty) => { foo!($ty); } }
@@ -104,24 +105,27 @@ pub struct CrateDefMap {
104 diagnostics: Vec<DefDiagnostic>, 105 diagnostics: Vec<DefDiagnostic>,
105} 106}
106 107
107impl std::ops::Index<CrateModuleId> for CrateDefMap { 108impl std::ops::Index<LocalModuleId> for CrateDefMap {
108 type Output = ModuleData; 109 type Output = ModuleData;
109 fn index(&self, id: CrateModuleId) -> &ModuleData { 110 fn index(&self, id: LocalModuleId) -> &ModuleData {
110 &self.modules[id] 111 &self.modules[id]
111 } 112 }
112} 113}
113 114
114#[derive(Default, Debug, PartialEq, Eq)] 115#[derive(Default, Debug, PartialEq, Eq)]
115pub struct ModuleData { 116pub struct ModuleData {
116 pub parent: Option<CrateModuleId>, 117 pub parent: Option<LocalModuleId>,
117 pub children: FxHashMap<Name, CrateModuleId>, 118 pub children: FxHashMap<Name, LocalModuleId>,
118 pub scope: ModuleScope, 119 pub scope: ModuleScope,
120
121 // FIXME: these can't be both null, we need a three-state enum here.
119 /// None for root 122 /// None for root
120 pub declaration: Option<AstId<ast::Module>>, 123 pub declaration: Option<AstId<ast::Module>>,
121 /// None for inline modules. 124 /// None for inline modules.
122 /// 125 ///
123 /// Note that non-inline modules, by definition, live inside non-macro file. 126 /// Note that non-inline modules, by definition, live inside non-macro file.
124 pub definition: Option<FileId>, 127 pub definition: Option<FileId>,
128
125 pub impls: Vec<ImplId>, 129 pub impls: Vec<ImplId>,
126} 130}
127 131
@@ -207,21 +211,21 @@ pub struct Resolution {
207 /// None for unresolved 211 /// None for unresolved
208 pub def: PerNs, 212 pub def: PerNs,
209 /// ident by which this is imported into local scope. 213 /// ident by which this is imported into local scope.
210 pub import: Option<ImportId>, 214 pub import: Option<LocalImportId>,
211} 215}
212 216
213impl CrateDefMap { 217impl CrateDefMap {
214 pub(crate) fn crate_def_map_query( 218 pub(crate) fn crate_def_map_query(
215 // Note that this doesn't have `+ AstDatabase`! 219 // Note that this doesn't have `+ AstDatabase`!
216 // This gurantess that `CrateDefMap` is stable across reparses. 220 // This gurantess that `CrateDefMap` is stable across reparses.
217 db: &impl DefDatabase2, 221 db: &impl DefDatabase,
218 krate: CrateId, 222 krate: CrateId,
219 ) -> Arc<CrateDefMap> { 223 ) -> Arc<CrateDefMap> {
220 let _p = profile("crate_def_map_query"); 224 let _p = profile("crate_def_map_query");
221 let def_map = { 225 let def_map = {
222 let crate_graph = db.crate_graph(); 226 let crate_graph = db.crate_graph();
223 let edition = crate_graph.edition(krate); 227 let edition = crate_graph.edition(krate);
224 let mut modules: Arena<CrateModuleId, ModuleData> = Arena::default(); 228 let mut modules: Arena<LocalModuleId, ModuleData> = Arena::default();
225 let root = modules.alloc(ModuleData::default()); 229 let root = modules.alloc(ModuleData::default());
226 CrateDefMap { 230 CrateDefMap {
227 krate, 231 krate,
@@ -242,7 +246,7 @@ impl CrateDefMap {
242 self.krate 246 self.krate
243 } 247 }
244 248
245 pub fn root(&self) -> CrateModuleId { 249 pub fn root(&self) -> LocalModuleId {
246 self.root 250 self.root
247 } 251 }
248 252
@@ -256,8 +260,8 @@ impl CrateDefMap {
256 260
257 pub fn add_diagnostics( 261 pub fn add_diagnostics(
258 &self, 262 &self,
259 db: &impl DefDatabase2, 263 db: &impl DefDatabase,
260 module: CrateModuleId, 264 module: LocalModuleId,
261 sink: &mut DiagnosticSink, 265 sink: &mut DiagnosticSink,
262 ) { 266 ) {
263 self.diagnostics.iter().for_each(|it| it.add_to(db, module, sink)) 267 self.diagnostics.iter().for_each(|it| it.add_to(db, module, sink))
@@ -265,19 +269,19 @@ impl CrateDefMap {
265 269
266 pub fn resolve_path( 270 pub fn resolve_path(
267 &self, 271 &self,
268 db: &impl DefDatabase2, 272 db: &impl DefDatabase,
269 original_module: CrateModuleId, 273 original_module: LocalModuleId,
270 path: &Path, 274 path: &Path,
271 ) -> (PerNs, Option<usize>) { 275 ) -> (PerNs, Option<usize>) {
272 let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path); 276 let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path);
273 (res.resolved_def, res.segment_index) 277 (res.resolved_def, res.segment_index)
274 } 278 }
275 279
276 pub fn modules(&self) -> impl Iterator<Item = CrateModuleId> + '_ { 280 pub fn modules(&self) -> impl Iterator<Item = LocalModuleId> + '_ {
277 self.modules.iter().map(|(id, _data)| id) 281 self.modules.iter().map(|(id, _data)| id)
278 } 282 }
279 283
280 pub fn modules_for_file(&self, file_id: FileId) -> impl Iterator<Item = CrateModuleId> + '_ { 284 pub fn modules_for_file(&self, file_id: FileId) -> impl Iterator<Item = LocalModuleId> + '_ {
281 self.modules 285 self.modules
282 .iter() 286 .iter()
283 .filter(move |(_id, data)| data.definition == Some(file_id)) 287 .filter(move |(_id, data)| data.definition == Some(file_id))
@@ -285,17 +289,40 @@ impl CrateDefMap {
285 } 289 }
286} 290}
287 291
292impl ModuleData {
293 /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items.
294 pub fn definition_source(
295 &self,
296 db: &impl DefDatabase,
297 ) -> Source<Either<ast::SourceFile, ast::Module>> {
298 if let Some(file_id) = self.definition {
299 let sf = db.parse(file_id).tree();
300 return Source::new(file_id.into(), Either::A(sf));
301 }
302 let decl = self.declaration.unwrap();
303 Source::new(decl.file_id(), Either::B(decl.to_node(db)))
304 }
305
306 /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`.
307 /// `None` for the crate root.
308 pub fn declaration_source(&self, db: &impl DefDatabase) -> Option<Source<ast::Module>> {
309 let decl = self.declaration?;
310 let value = decl.to_node(db);
311 Some(Source { file_id: decl.file_id(), value })
312 }
313}
314
288mod diagnostics { 315mod diagnostics {
289 use hir_expand::diagnostics::DiagnosticSink; 316 use hir_expand::diagnostics::DiagnosticSink;
290 use ra_db::RelativePathBuf; 317 use ra_db::RelativePathBuf;
291 use ra_syntax::{ast, AstPtr}; 318 use ra_syntax::{ast, AstPtr};
292 319
293 use crate::{db::DefDatabase2, diagnostics::UnresolvedModule, nameres::CrateModuleId, AstId}; 320 use crate::{db::DefDatabase, diagnostics::UnresolvedModule, nameres::LocalModuleId, AstId};
294 321
295 #[derive(Debug, PartialEq, Eq)] 322 #[derive(Debug, PartialEq, Eq)]
296 pub(super) enum DefDiagnostic { 323 pub(super) enum DefDiagnostic {
297 UnresolvedModule { 324 UnresolvedModule {
298 module: CrateModuleId, 325 module: LocalModuleId,
299 declaration: AstId<ast::Module>, 326 declaration: AstId<ast::Module>,
300 candidate: RelativePathBuf, 327 candidate: RelativePathBuf,
301 }, 328 },
@@ -304,8 +331,8 @@ mod diagnostics {
304 impl DefDiagnostic { 331 impl DefDiagnostic {
305 pub(super) fn add_to( 332 pub(super) fn add_to(
306 &self, 333 &self,
307 db: &impl DefDatabase2, 334 db: &impl DefDatabase,
308 target_module: CrateModuleId, 335 target_module: LocalModuleId,
309 sink: &mut DiagnosticSink, 336 sink: &mut DiagnosticSink,
310 ) { 337 ) {
311 match self { 338 match self {
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs
index 7902293e8..b02364e86 100644
--- a/crates/ra_hir_def/src/nameres/collector.rs
+++ b/crates/ra_hir_def/src/nameres/collector.rs
@@ -13,18 +13,19 @@ use test_utils::tested_by;
13 13
14use crate::{ 14use crate::{
15 attr::Attrs, 15 attr::Attrs,
16 db::DefDatabase2, 16 db::DefDatabase,
17 nameres::{ 17 nameres::{
18 diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint, 18 diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint,
19 per_ns::PerNs, raw, CrateDefMap, ModuleData, Resolution, ResolveMode, 19 raw, CrateDefMap, ModuleData, Resolution, ResolveMode,
20 }, 20 },
21 path::{Path, PathKind}, 21 path::{Path, PathKind},
22 AdtId, AstId, AstItemDef, ConstLoc, ContainerId, CrateModuleId, EnumId, EnumVariantId, 22 per_ns::PerNs,
23 FunctionLoc, ImplId, Intern, LocationCtx, ModuleDefId, ModuleId, StaticId, StructId, 23 AdtId, AstId, AstItemDef, ConstLoc, ContainerId, EnumId, EnumVariantId, FunctionLoc, ImplId,
24 Intern, LocalImportId, LocalModuleId, LocationCtx, ModuleDefId, ModuleId, StaticId, StructId,
24 StructOrUnionId, TraitId, TypeAliasLoc, UnionId, 25 StructOrUnionId, TraitId, TypeAliasLoc, UnionId,
25}; 26};
26 27
27pub(super) fn collect_defs(db: &impl DefDatabase2, mut def_map: CrateDefMap) -> CrateDefMap { 28pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap {
28 let crate_graph = db.crate_graph(); 29 let crate_graph = db.crate_graph();
29 30
30 // populate external prelude 31 // populate external prelude
@@ -94,10 +95,10 @@ impl MacroStackMonitor {
94struct DefCollector<'a, DB> { 95struct DefCollector<'a, DB> {
95 db: &'a DB, 96 db: &'a DB,
96 def_map: CrateDefMap, 97 def_map: CrateDefMap,
97 glob_imports: FxHashMap<CrateModuleId, Vec<(CrateModuleId, raw::ImportId)>>, 98 glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, LocalImportId)>>,
98 unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>, 99 unresolved_imports: Vec<(LocalModuleId, LocalImportId, raw::ImportData)>,
99 unexpanded_macros: Vec<(CrateModuleId, AstId<ast::MacroCall>, Path)>, 100 unexpanded_macros: Vec<(LocalModuleId, AstId<ast::MacroCall>, Path)>,
100 mod_dirs: FxHashMap<CrateModuleId, ModDir>, 101 mod_dirs: FxHashMap<LocalModuleId, ModDir>,
101 102
102 /// Some macro use `$tt:tt which mean we have to handle the macro perfectly 103 /// Some macro use `$tt:tt which mean we have to handle the macro perfectly
103 /// To prevent stack overflow, we add a deep counter here for prevent that. 104 /// To prevent stack overflow, we add a deep counter here for prevent that.
@@ -108,7 +109,7 @@ struct DefCollector<'a, DB> {
108 109
109impl<DB> DefCollector<'_, DB> 110impl<DB> DefCollector<'_, DB>
110where 111where
111 DB: DefDatabase2, 112 DB: DefDatabase,
112{ 113{
113 fn collect(&mut self) { 114 fn collect(&mut self) {
114 let crate_graph = self.db.crate_graph(); 115 let crate_graph = self.db.crate_graph();
@@ -173,7 +174,7 @@ where
173 /// ``` 174 /// ```
174 fn define_macro( 175 fn define_macro(
175 &mut self, 176 &mut self,
176 module_id: CrateModuleId, 177 module_id: LocalModuleId,
177 name: Name, 178 name: Name,
178 macro_: MacroDefId, 179 macro_: MacroDefId,
179 export: bool, 180 export: bool,
@@ -200,7 +201,7 @@ where
200 /// the definition of current module. 201 /// the definition of current module.
201 /// And also, `macro_use` on a module will import all legacy macros visable inside to 202 /// And also, `macro_use` on a module will import all legacy macros visable inside to
202 /// current legacy scope, with possible shadowing. 203 /// current legacy scope, with possible shadowing.
203 fn define_legacy_macro(&mut self, module_id: CrateModuleId, name: Name, macro_: MacroDefId) { 204 fn define_legacy_macro(&mut self, module_id: LocalModuleId, name: Name, macro_: MacroDefId) {
204 // Always shadowing 205 // Always shadowing
205 self.def_map.modules[module_id].scope.legacy_macros.insert(name, macro_); 206 self.def_map.modules[module_id].scope.legacy_macros.insert(name, macro_);
206 } 207 }
@@ -208,7 +209,7 @@ where
208 /// Import macros from `#[macro_use] extern crate`. 209 /// Import macros from `#[macro_use] extern crate`.
209 fn import_macros_from_extern_crate( 210 fn import_macros_from_extern_crate(
210 &mut self, 211 &mut self,
211 current_module_id: CrateModuleId, 212 current_module_id: LocalModuleId,
212 import: &raw::ImportData, 213 import: &raw::ImportData,
213 ) { 214 ) {
214 log::debug!( 215 log::debug!(
@@ -235,7 +236,7 @@ where
235 /// Exported macros are just all macros in the root module scope. 236 /// Exported macros are just all macros in the root module scope.
236 /// Note that it contains not only all `#[macro_export]` macros, but also all aliases 237 /// Note that it contains not only all `#[macro_export]` macros, but also all aliases
237 /// created by `use` in the root module, ignoring the visibility of `use`. 238 /// created by `use` in the root module, ignoring the visibility of `use`.
238 fn import_all_macros_exported(&mut self, current_module_id: CrateModuleId, krate: CrateId) { 239 fn import_all_macros_exported(&mut self, current_module_id: LocalModuleId, krate: CrateId) {
239 let def_map = self.db.crate_def_map(krate); 240 let def_map = self.db.crate_def_map(krate);
240 for (name, def) in def_map[def_map.root].scope.macros() { 241 for (name, def) in def_map[def_map.root].scope.macros() {
241 // `macro_use` only bring things into legacy scope. 242 // `macro_use` only bring things into legacy scope.
@@ -265,7 +266,7 @@ where
265 266
266 fn resolve_import( 267 fn resolve_import(
267 &self, 268 &self,
268 module_id: CrateModuleId, 269 module_id: LocalModuleId,
269 import: &raw::ImportData, 270 import: &raw::ImportData,
270 ) -> (PerNs, ReachedFixedPoint) { 271 ) -> (PerNs, ReachedFixedPoint) {
271 log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition); 272 log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition);
@@ -291,9 +292,9 @@ where
291 292
292 fn record_resolved_import( 293 fn record_resolved_import(
293 &mut self, 294 &mut self,
294 module_id: CrateModuleId, 295 module_id: LocalModuleId,
295 def: PerNs, 296 def: PerNs,
296 import_id: raw::ImportId, 297 import_id: LocalImportId,
297 import: &raw::ImportData, 298 import: &raw::ImportData,
298 ) { 299 ) {
299 if import.is_glob { 300 if import.is_glob {
@@ -387,8 +388,8 @@ where
387 388
388 fn update( 389 fn update(
389 &mut self, 390 &mut self,
390 module_id: CrateModuleId, 391 module_id: LocalModuleId,
391 import: Option<raw::ImportId>, 392 import: Option<LocalImportId>,
392 resolutions: &[(Name, Resolution)], 393 resolutions: &[(Name, Resolution)],
393 ) { 394 ) {
394 self.update_recursive(module_id, import, resolutions, 0) 395 self.update_recursive(module_id, import, resolutions, 0)
@@ -396,8 +397,8 @@ where
396 397
397 fn update_recursive( 398 fn update_recursive(
398 &mut self, 399 &mut self,
399 module_id: CrateModuleId, 400 module_id: LocalModuleId,
400 import: Option<raw::ImportId>, 401 import: Option<LocalImportId>,
401 resolutions: &[(Name, Resolution)], 402 resolutions: &[(Name, Resolution)],
402 depth: usize, 403 depth: usize,
403 ) { 404 ) {
@@ -484,7 +485,7 @@ where
484 485
485 fn collect_macro_expansion( 486 fn collect_macro_expansion(
486 &mut self, 487 &mut self,
487 module_id: CrateModuleId, 488 module_id: LocalModuleId,
488 macro_call_id: MacroCallId, 489 macro_call_id: MacroCallId,
489 macro_def_id: MacroDefId, 490 macro_def_id: MacroDefId,
490 ) { 491 ) {
@@ -522,7 +523,7 @@ where
522/// Walks a single module, populating defs, imports and macros 523/// Walks a single module, populating defs, imports and macros
523struct ModCollector<'a, D> { 524struct ModCollector<'a, D> {
524 def_collector: D, 525 def_collector: D,
525 module_id: CrateModuleId, 526 module_id: LocalModuleId,
526 file_id: HirFileId, 527 file_id: HirFileId,
527 raw_items: &'a raw::RawItems, 528 raw_items: &'a raw::RawItems,
528 mod_dir: ModDir, 529 mod_dir: ModDir,
@@ -530,7 +531,7 @@ struct ModCollector<'a, D> {
530 531
531impl<DB> ModCollector<'_, &'_ mut DefCollector<'_, DB>> 532impl<DB> ModCollector<'_, &'_ mut DefCollector<'_, DB>>
532where 533where
533 DB: DefDatabase2, 534 DB: DefDatabase,
534{ 535{
535 fn collect(&mut self, items: &[raw::RawItem]) { 536 fn collect(&mut self, items: &[raw::RawItem]) {
536 // Note: don't assert that inserted value is fresh: it's simply not true 537 // Note: don't assert that inserted value is fresh: it's simply not true
@@ -647,7 +648,7 @@ where
647 name: Name, 648 name: Name,
648 declaration: AstId<ast::Module>, 649 declaration: AstId<ast::Module>,
649 definition: Option<FileId>, 650 definition: Option<FileId>,
650 ) -> CrateModuleId { 651 ) -> LocalModuleId {
651 let modules = &mut self.def_collector.def_map.modules; 652 let modules = &mut self.def_collector.def_map.modules;
652 let res = modules.alloc(ModuleData::default()); 653 let res = modules.alloc(ModuleData::default());
653 modules[res].parent = Some(self.module_id); 654 modules[res].parent = Some(self.module_id);
@@ -772,7 +773,7 @@ where
772 self.def_collector.unexpanded_macros.push((self.module_id, ast_id, path)); 773 self.def_collector.unexpanded_macros.push((self.module_id, ast_id, path));
773 } 774 }
774 775
775 fn import_all_legacy_macros(&mut self, module_id: CrateModuleId) { 776 fn import_all_legacy_macros(&mut self, module_id: LocalModuleId) {
776 let macros = self.def_collector.def_map[module_id].scope.legacy_macros.clone(); 777 let macros = self.def_collector.def_map[module_id].scope.legacy_macros.clone();
777 for (name, macro_) in macros { 778 for (name, macro_) in macros {
778 self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_); 779 self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_);
@@ -798,12 +799,12 @@ mod tests {
798 use ra_db::{fixture::WithFixture, SourceDatabase}; 799 use ra_db::{fixture::WithFixture, SourceDatabase};
799 use rustc_hash::FxHashSet; 800 use rustc_hash::FxHashSet;
800 801
801 use crate::{db::DefDatabase2, test_db::TestDB}; 802 use crate::{db::DefDatabase, test_db::TestDB};
802 803
803 use super::*; 804 use super::*;
804 805
805 fn do_collect_defs( 806 fn do_collect_defs(
806 db: &impl DefDatabase2, 807 db: &impl DefDatabase,
807 def_map: CrateDefMap, 808 def_map: CrateDefMap,
808 monitor: MacroStackMonitor, 809 monitor: MacroStackMonitor,
809 ) -> CrateDefMap { 810 ) -> CrateDefMap {
@@ -827,7 +828,7 @@ mod tests {
827 828
828 let def_map = { 829 let def_map = {
829 let edition = db.crate_graph().edition(krate); 830 let edition = db.crate_graph().edition(krate);
830 let mut modules: Arena<CrateModuleId, ModuleData> = Arena::default(); 831 let mut modules: Arena<LocalModuleId, ModuleData> = Arena::default();
831 let root = modules.alloc(ModuleData::default()); 832 let root = modules.alloc(ModuleData::default());
832 CrateDefMap { 833 CrateDefMap {
833 krate, 834 krate,
diff --git a/crates/ra_hir_def/src/nameres/mod_resolution.rs b/crates/ra_hir_def/src/nameres/mod_resolution.rs
index b3b1379d0..14fb8ba3a 100644
--- a/crates/ra_hir_def/src/nameres/mod_resolution.rs
+++ b/crates/ra_hir_def/src/nameres/mod_resolution.rs
@@ -3,7 +3,7 @@ use hir_expand::name::Name;
3use ra_db::{FileId, RelativePathBuf}; 3use ra_db::{FileId, RelativePathBuf};
4use ra_syntax::SmolStr; 4use ra_syntax::SmolStr;
5 5
6use crate::{db::DefDatabase2, HirFileId}; 6use crate::{db::DefDatabase, HirFileId};
7 7
8#[derive(Clone, Debug)] 8#[derive(Clone, Debug)]
9pub(super) struct ModDir { 9pub(super) struct ModDir {
@@ -40,7 +40,7 @@ impl ModDir {
40 40
41 pub(super) fn resolve_declaration( 41 pub(super) fn resolve_declaration(
42 &self, 42 &self,
43 db: &impl DefDatabase2, 43 db: &impl DefDatabase,
44 file_id: HirFileId, 44 file_id: HirFileId,
45 name: &Name, 45 name: &Name,
46 attr_path: Option<&SmolStr>, 46 attr_path: Option<&SmolStr>,
diff --git a/crates/ra_hir_def/src/nameres/path_resolution.rs b/crates/ra_hir_def/src/nameres/path_resolution.rs
index 95692f826..9455f22bb 100644
--- a/crates/ra_hir_def/src/nameres/path_resolution.rs
+++ b/crates/ra_hir_def/src/nameres/path_resolution.rs
@@ -15,10 +15,11 @@ use ra_db::Edition;
15use test_utils::tested_by; 15use test_utils::tested_by;
16 16
17use crate::{ 17use crate::{
18 db::DefDatabase2, 18 db::DefDatabase,
19 nameres::{per_ns::PerNs, CrateDefMap}, 19 nameres::CrateDefMap,
20 path::{Path, PathKind}, 20 path::{Path, PathKind},
21 AdtId, CrateModuleId, EnumVariantId, ModuleDefId, ModuleId, 21 per_ns::PerNs,
22 AdtId, EnumVariantId, LocalModuleId, ModuleDefId, ModuleId,
22}; 23};
23 24
24#[derive(Debug, Clone, Copy, PartialEq, Eq)] 25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -63,9 +64,9 @@ impl CrateDefMap {
63 // the result. 64 // the result.
64 pub(super) fn resolve_path_fp_with_macro( 65 pub(super) fn resolve_path_fp_with_macro(
65 &self, 66 &self,
66 db: &impl DefDatabase2, 67 db: &impl DefDatabase,
67 mode: ResolveMode, 68 mode: ResolveMode,
68 original_module: CrateModuleId, 69 original_module: LocalModuleId,
69 path: &Path, 70 path: &Path,
70 ) -> ResolvePathResult { 71 ) -> ResolvePathResult {
71 let mut segments = path.segments.iter().enumerate(); 72 let mut segments = path.segments.iter().enumerate();
@@ -216,8 +217,8 @@ impl CrateDefMap {
216 217
217 fn resolve_name_in_module( 218 fn resolve_name_in_module(
218 &self, 219 &self,
219 db: &impl DefDatabase2, 220 db: &impl DefDatabase,
220 module: CrateModuleId, 221 module: LocalModuleId,
221 name: &Name, 222 name: &Name,
222 ) -> PerNs { 223 ) -> PerNs {
223 // Resolve in: 224 // Resolve in:
@@ -243,7 +244,7 @@ impl CrateDefMap {
243 from_crate_root.or(from_extern_prelude) 244 from_crate_root.or(from_extern_prelude)
244 } 245 }
245 246
246 fn resolve_in_prelude(&self, db: &impl DefDatabase2, name: &Name) -> PerNs { 247 fn resolve_in_prelude(&self, db: &impl DefDatabase, name: &Name) -> PerNs {
247 if let Some(prelude) = self.prelude { 248 if let Some(prelude) = self.prelude {
248 let keep; 249 let keep;
249 let def_map = if prelude.krate == self.krate { 250 let def_map = if prelude.krate == self.krate {
diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs
index 55a9634f8..552cbe544 100644
--- a/crates/ra_hir_def/src/nameres/raw.rs
+++ b/crates/ra_hir_def/src/nameres/raw.rs
@@ -12,15 +12,15 @@ use hir_expand::{
12use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; 12use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId};
13use ra_syntax::{ 13use ra_syntax::{
14 ast::{self, AttrsOwner, NameOwner}, 14 ast::{self, AttrsOwner, NameOwner},
15 AstNode, AstPtr, SourceFile, 15 AstNode, AstPtr,
16}; 16};
17use test_utils::tested_by; 17use test_utils::tested_by;
18 18
19use crate::{ 19use crate::{
20 attr::{Attr, Attrs}, 20 attr::{Attr, Attrs},
21 db::DefDatabase2, 21 db::DefDatabase,
22 path::Path, 22 path::Path,
23 FileAstId, HirFileId, ModuleSource, Source, 23 FileAstId, HirFileId, LocalImportId, Source,
24}; 24};
25 25
26/// `RawItems` is a set of top-level items in a file (except for impls). 26/// `RawItems` is a set of top-level items in a file (except for impls).
@@ -30,7 +30,7 @@ use crate::{
30#[derive(Debug, Default, PartialEq, Eq)] 30#[derive(Debug, Default, PartialEq, Eq)]
31pub struct RawItems { 31pub struct RawItems {
32 modules: Arena<Module, ModuleData>, 32 modules: Arena<Module, ModuleData>,
33 imports: Arena<ImportId, ImportData>, 33 imports: Arena<LocalImportId, ImportData>,
34 defs: Arena<Def, DefData>, 34 defs: Arena<Def, DefData>,
35 macros: Arena<Macro, MacroData>, 35 macros: Arena<Macro, MacroData>,
36 impls: Arena<Impl, ImplData>, 36 impls: Arena<Impl, ImplData>,
@@ -40,41 +40,31 @@ pub struct RawItems {
40 40
41#[derive(Debug, Default, PartialEq, Eq)] 41#[derive(Debug, Default, PartialEq, Eq)]
42pub struct ImportSourceMap { 42pub struct ImportSourceMap {
43 map: ArenaMap<ImportId, ImportSourcePtr>, 43 map: ArenaMap<LocalImportId, ImportSourcePtr>,
44} 44}
45 45
46type ImportSourcePtr = Either<AstPtr<ast::UseTree>, AstPtr<ast::ExternCrateItem>>; 46type ImportSourcePtr = Either<AstPtr<ast::UseTree>, AstPtr<ast::ExternCrateItem>>;
47type ImportSource = Either<ast::UseTree, ast::ExternCrateItem>;
48
49fn to_node(ptr: ImportSourcePtr, file: &SourceFile) -> ImportSource {
50 ptr.map(|ptr| ptr.to_node(file.syntax()), |ptr| ptr.to_node(file.syntax()))
51}
52 47
53impl ImportSourceMap { 48impl ImportSourceMap {
54 fn insert(&mut self, import: ImportId, ptr: ImportSourcePtr) { 49 fn insert(&mut self, import: LocalImportId, ptr: ImportSourcePtr) {
55 self.map.insert(import, ptr) 50 self.map.insert(import, ptr)
56 } 51 }
57 52
58 pub fn get(&self, source: &ModuleSource, import: ImportId) -> ImportSource { 53 pub fn get(&self, import: LocalImportId) -> ImportSourcePtr {
59 let file = match source { 54 self.map[import].clone()
60 ModuleSource::SourceFile(file) => file.clone(),
61 ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(),
62 };
63
64 to_node(self.map[import], &file)
65 } 55 }
66} 56}
67 57
68impl RawItems { 58impl RawItems {
69 pub(crate) fn raw_items_query( 59 pub(crate) fn raw_items_query(
70 db: &(impl DefDatabase2 + AstDatabase), 60 db: &(impl DefDatabase + AstDatabase),
71 file_id: HirFileId, 61 file_id: HirFileId,
72 ) -> Arc<RawItems> { 62 ) -> Arc<RawItems> {
73 db.raw_items_with_source_map(file_id).0 63 db.raw_items_with_source_map(file_id).0
74 } 64 }
75 65
76 pub(crate) fn raw_items_with_source_map_query( 66 pub(crate) fn raw_items_with_source_map_query(
77 db: &(impl DefDatabase2 + AstDatabase), 67 db: &(impl DefDatabase + AstDatabase),
78 file_id: HirFileId, 68 file_id: HirFileId,
79 ) -> (Arc<RawItems>, Arc<ImportSourceMap>) { 69 ) -> (Arc<RawItems>, Arc<ImportSourceMap>) {
80 let mut collector = RawItemsCollector { 70 let mut collector = RawItemsCollector {
@@ -106,9 +96,9 @@ impl Index<Module> for RawItems {
106 } 96 }
107} 97}
108 98
109impl Index<ImportId> for RawItems { 99impl Index<LocalImportId> for RawItems {
110 type Output = ImportData; 100 type Output = ImportData;
111 fn index(&self, idx: ImportId) -> &ImportData { 101 fn index(&self, idx: LocalImportId) -> &ImportData {
112 &self.imports[idx] 102 &self.imports[idx]
113 } 103 }
114} 104}
@@ -143,7 +133,7 @@ pub(super) struct RawItem {
143#[derive(Debug, PartialEq, Eq, Clone, Copy)] 133#[derive(Debug, PartialEq, Eq, Clone, Copy)]
144pub(super) enum RawItemKind { 134pub(super) enum RawItemKind {
145 Module(Module), 135 Module(Module),
146 Import(ImportId), 136 Import(LocalImportId),
147 Def(Def), 137 Def(Def),
148 Macro(Macro), 138 Macro(Macro),
149 Impl(Impl), 139 Impl(Impl),
@@ -159,10 +149,6 @@ pub(super) enum ModuleData {
159 Definition { name: Name, ast_id: FileAstId<ast::Module>, items: Vec<RawItem> }, 149 Definition { name: Name, ast_id: FileAstId<ast::Module>, items: Vec<RawItem> },
160} 150}
161 151
162#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
163pub struct ImportId(RawId);
164impl_arena_id!(ImportId);
165
166#[derive(Debug, Clone, PartialEq, Eq)] 152#[derive(Debug, Clone, PartialEq, Eq)]
167pub struct ImportData { 153pub struct ImportData {
168 pub(super) path: Path, 154 pub(super) path: Path,
diff --git a/crates/ra_hir_def/src/nameres/tests.rs b/crates/ra_hir_def/src/nameres/tests.rs
index 256f7d4be..f0b86af7c 100644
--- a/crates/ra_hir_def/src/nameres/tests.rs
+++ b/crates/ra_hir_def/src/nameres/tests.rs
@@ -10,7 +10,7 @@ use insta::assert_snapshot;
10use ra_db::{fixture::WithFixture, SourceDatabase}; 10use ra_db::{fixture::WithFixture, SourceDatabase};
11use test_utils::covers; 11use test_utils::covers;
12 12
13use crate::{db::DefDatabase2, nameres::*, test_db::TestDB, CrateModuleId}; 13use crate::{db::DefDatabase, nameres::*, test_db::TestDB, LocalModuleId};
14 14
15fn def_map(fixtute: &str) -> String { 15fn def_map(fixtute: &str) -> String {
16 let dm = compute_crate_def_map(fixtute); 16 let dm = compute_crate_def_map(fixtute);
@@ -28,7 +28,7 @@ fn render_crate_def_map(map: &CrateDefMap) -> String {
28 go(&mut buf, map, "\ncrate", map.root()); 28 go(&mut buf, map, "\ncrate", map.root());
29 return buf.trim().to_string(); 29 return buf.trim().to_string();
30 30
31 fn go(buf: &mut String, map: &CrateDefMap, path: &str, module: CrateModuleId) { 31 fn go(buf: &mut String, map: &CrateDefMap, path: &str, module: LocalModuleId) {
32 *buf += path; 32 *buf += path;
33 *buf += "\n"; 33 *buf += "\n";
34 34
diff --git a/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs
index eb7b85c07..e11530062 100644
--- a/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs
+++ b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs
@@ -665,7 +665,7 @@ fn unresolved_module_diagnostics() {
665 @r###" 665 @r###"
666 [ 666 [
667 UnresolvedModule { 667 UnresolvedModule {
668 module: CrateModuleId( 668 module: LocalModuleId(
669 0, 669 0,
670 ), 670 ),
671 declaration: AstId { 671 declaration: AstId {
diff --git a/crates/ra_hir_def/src/nameres/per_ns.rs b/crates/ra_hir_def/src/per_ns.rs
index 717ed1ef9..717ed1ef9 100644
--- a/crates/ra_hir_def/src/nameres/per_ns.rs
+++ b/crates/ra_hir_def/src/per_ns.rs
diff --git a/crates/ra_hir_def/src/resolver.rs b/crates/ra_hir_def/src/resolver.rs
index 7b5c3ec06..b56de44dd 100644
--- a/crates/ra_hir_def/src/resolver.rs
+++ b/crates/ra_hir_def/src/resolver.rs
@@ -11,14 +11,15 @@ use rustc_hash::FxHashSet;
11use crate::{ 11use crate::{
12 body::scope::{ExprScopes, ScopeId}, 12 body::scope::{ExprScopes, ScopeId},
13 builtin_type::BuiltinType, 13 builtin_type::BuiltinType,
14 db::DefDatabase2, 14 db::DefDatabase,
15 expr::{ExprId, PatId}, 15 expr::{ExprId, PatId},
16 generics::GenericParams, 16 generics::GenericParams,
17 nameres::{per_ns::PerNs, CrateDefMap}, 17 nameres::CrateDefMap,
18 path::{Path, PathKind}, 18 path::{Path, PathKind},
19 AdtId, AstItemDef, ConstId, ContainerId, CrateModuleId, DefWithBodyId, EnumId, EnumVariantId, 19 per_ns::PerNs,
20 FunctionId, GenericDefId, ImplId, Lookup, ModuleDefId, ModuleId, StaticId, StructId, TraitId, 20 AdtId, AstItemDef, ConstId, ContainerId, DefWithBodyId, EnumId, EnumVariantId, FunctionId,
21 TypeAliasId, 21 GenericDefId, ImplId, LocalModuleId, Lookup, ModuleDefId, ModuleId, StaticId, StructId,
22 TraitId, TypeAliasId,
22}; 23};
23 24
24#[derive(Debug, Clone, Default)] 25#[derive(Debug, Clone, Default)]
@@ -30,7 +31,7 @@ pub struct Resolver {
30#[derive(Debug, Clone)] 31#[derive(Debug, Clone)]
31pub(crate) struct ModuleItemMap { 32pub(crate) struct ModuleItemMap {
32 crate_def_map: Arc<CrateDefMap>, 33 crate_def_map: Arc<CrateDefMap>,
33 module_id: CrateModuleId, 34 module_id: LocalModuleId,
34} 35}
35 36
36#[derive(Debug, Clone)] 37#[derive(Debug, Clone)]
@@ -87,7 +88,7 @@ pub enum ValueNs {
87 88
88impl Resolver { 89impl Resolver {
89 /// Resolve known trait from std, like `std::futures::Future` 90 /// Resolve known trait from std, like `std::futures::Future`
90 pub fn resolve_known_trait(&self, db: &impl DefDatabase2, path: &Path) -> Option<TraitId> { 91 pub fn resolve_known_trait(&self, db: &impl DefDatabase, path: &Path) -> Option<TraitId> {
91 let res = self.resolve_module_path(db, path).take_types()?; 92 let res = self.resolve_module_path(db, path).take_types()?;
92 match res { 93 match res {
93 ModuleDefId::TraitId(it) => Some(it), 94 ModuleDefId::TraitId(it) => Some(it),
@@ -96,7 +97,7 @@ impl Resolver {
96 } 97 }
97 98
98 /// Resolve known struct from std, like `std::boxed::Box` 99 /// Resolve known struct from std, like `std::boxed::Box`
99 pub fn resolve_known_struct(&self, db: &impl DefDatabase2, path: &Path) -> Option<StructId> { 100 pub fn resolve_known_struct(&self, db: &impl DefDatabase, path: &Path) -> Option<StructId> {
100 let res = self.resolve_module_path(db, path).take_types()?; 101 let res = self.resolve_module_path(db, path).take_types()?;
101 match res { 102 match res {
102 ModuleDefId::AdtId(AdtId::StructId(it)) => Some(it), 103 ModuleDefId::AdtId(AdtId::StructId(it)) => Some(it),
@@ -105,7 +106,7 @@ impl Resolver {
105 } 106 }
106 107
107 /// Resolve known enum from std, like `std::result::Result` 108 /// Resolve known enum from std, like `std::result::Result`
108 pub fn resolve_known_enum(&self, db: &impl DefDatabase2, path: &Path) -> Option<EnumId> { 109 pub fn resolve_known_enum(&self, db: &impl DefDatabase, path: &Path) -> Option<EnumId> {
109 let res = self.resolve_module_path(db, path).take_types()?; 110 let res = self.resolve_module_path(db, path).take_types()?;
110 match res { 111 match res {
111 ModuleDefId::AdtId(AdtId::EnumId(it)) => Some(it), 112 ModuleDefId::AdtId(AdtId::EnumId(it)) => Some(it),
@@ -114,7 +115,7 @@ impl Resolver {
114 } 115 }
115 116
116 /// pub only for source-binder 117 /// pub only for source-binder
117 pub fn resolve_module_path(&self, db: &impl DefDatabase2, path: &Path) -> PerNs { 118 pub fn resolve_module_path(&self, db: &impl DefDatabase, path: &Path) -> PerNs {
118 let (item_map, module) = match self.module() { 119 let (item_map, module) = match self.module() {
119 Some(it) => it, 120 Some(it) => it,
120 None => return PerNs::none(), 121 None => return PerNs::none(),
@@ -128,7 +129,7 @@ impl Resolver {
128 129
129 pub fn resolve_path_in_type_ns( 130 pub fn resolve_path_in_type_ns(
130 &self, 131 &self,
131 db: &impl DefDatabase2, 132 db: &impl DefDatabase,
132 path: &Path, 133 path: &Path,
133 ) -> Option<(TypeNs, Option<usize>)> { 134 ) -> Option<(TypeNs, Option<usize>)> {
134 if path.is_type_relative() { 135 if path.is_type_relative() {
@@ -184,7 +185,7 @@ impl Resolver {
184 185
185 pub fn resolve_path_in_type_ns_fully( 186 pub fn resolve_path_in_type_ns_fully(
186 &self, 187 &self,
187 db: &impl DefDatabase2, 188 db: &impl DefDatabase,
188 path: &Path, 189 path: &Path,
189 ) -> Option<TypeNs> { 190 ) -> Option<TypeNs> {
190 let (res, unresolved) = self.resolve_path_in_type_ns(db, path)?; 191 let (res, unresolved) = self.resolve_path_in_type_ns(db, path)?;
@@ -196,7 +197,7 @@ impl Resolver {
196 197
197 pub fn resolve_path_in_value_ns<'p>( 198 pub fn resolve_path_in_value_ns<'p>(
198 &self, 199 &self,
199 db: &impl DefDatabase2, 200 db: &impl DefDatabase,
200 path: &'p Path, 201 path: &'p Path,
201 ) -> Option<ResolveValueResult> { 202 ) -> Option<ResolveValueResult> {
202 if path.is_type_relative() { 203 if path.is_type_relative() {
@@ -296,7 +297,7 @@ impl Resolver {
296 297
297 pub fn resolve_path_in_value_ns_fully( 298 pub fn resolve_path_in_value_ns_fully(
298 &self, 299 &self,
299 db: &impl DefDatabase2, 300 db: &impl DefDatabase,
300 path: &Path, 301 path: &Path,
301 ) -> Option<ValueNs> { 302 ) -> Option<ValueNs> {
302 match self.resolve_path_in_value_ns(db, path)? { 303 match self.resolve_path_in_value_ns(db, path)? {
@@ -305,18 +306,18 @@ impl Resolver {
305 } 306 }
306 } 307 }
307 308
308 pub fn resolve_path_as_macro(&self, db: &impl DefDatabase2, path: &Path) -> Option<MacroDefId> { 309 pub fn resolve_path_as_macro(&self, db: &impl DefDatabase, path: &Path) -> Option<MacroDefId> {
309 let (item_map, module) = self.module()?; 310 let (item_map, module) = self.module()?;
310 item_map.resolve_path(db, module, path).0.get_macros() 311 item_map.resolve_path(db, module, path).0.get_macros()
311 } 312 }
312 313
313 pub fn process_all_names(&self, db: &impl DefDatabase2, f: &mut dyn FnMut(Name, ScopeDef)) { 314 pub fn process_all_names(&self, db: &impl DefDatabase, f: &mut dyn FnMut(Name, ScopeDef)) {
314 for scope in self.scopes.iter().rev() { 315 for scope in self.scopes.iter().rev() {
315 scope.process_names(db, f); 316 scope.process_names(db, f);
316 } 317 }
317 } 318 }
318 319
319 pub fn traits_in_scope(&self, db: &impl DefDatabase2) -> FxHashSet<TraitId> { 320 pub fn traits_in_scope(&self, db: &impl DefDatabase) -> FxHashSet<TraitId> {
320 let mut traits = FxHashSet::default(); 321 let mut traits = FxHashSet::default();
321 for scope in &self.scopes { 322 for scope in &self.scopes {
322 if let Scope::ModuleScope(m) = scope { 323 if let Scope::ModuleScope(m) = scope {
@@ -330,7 +331,7 @@ impl Resolver {
330 traits 331 traits
331 } 332 }
332 333
333 fn module(&self) -> Option<(&CrateDefMap, CrateModuleId)> { 334 fn module(&self) -> Option<(&CrateDefMap, LocalModuleId)> {
334 self.scopes.iter().rev().find_map(|scope| match scope { 335 self.scopes.iter().rev().find_map(|scope| match scope {
335 Scope::ModuleScope(m) => Some((&*m.crate_def_map, m.module_id)), 336 Scope::ModuleScope(m) => Some((&*m.crate_def_map, m.module_id)),
336 337
@@ -378,7 +379,7 @@ pub enum ScopeDef {
378} 379}
379 380
380impl Scope { 381impl Scope {
381 fn process_names(&self, db: &impl DefDatabase2, f: &mut dyn FnMut(Name, ScopeDef)) { 382 fn process_names(&self, db: &impl DefDatabase, f: &mut dyn FnMut(Name, ScopeDef)) {
382 match self { 383 match self {
383 Scope::ModuleScope(m) => { 384 Scope::ModuleScope(m) => {
384 // FIXME: should we provide `self` here? 385 // FIXME: should we provide `self` here?
@@ -425,17 +426,13 @@ impl Scope {
425} 426}
426 427
427// needs arbitrary_self_types to be a method... or maybe move to the def? 428// needs arbitrary_self_types to be a method... or maybe move to the def?
428pub fn resolver_for_expr( 429pub fn resolver_for_expr(db: &impl DefDatabase, owner: DefWithBodyId, expr_id: ExprId) -> Resolver {
429 db: &impl DefDatabase2,
430 owner: DefWithBodyId,
431 expr_id: ExprId,
432) -> Resolver {
433 let scopes = db.expr_scopes(owner); 430 let scopes = db.expr_scopes(owner);
434 resolver_for_scope(db, owner, scopes.scope_for(expr_id)) 431 resolver_for_scope(db, owner, scopes.scope_for(expr_id))
435} 432}
436 433
437pub fn resolver_for_scope( 434pub fn resolver_for_scope(
438 db: &impl DefDatabase2, 435 db: &impl DefDatabase,
439 owner: DefWithBodyId, 436 owner: DefWithBodyId,
440 scope_id: Option<ScopeId>, 437 scope_id: Option<ScopeId>,
441) -> Resolver { 438) -> Resolver {
@@ -454,7 +451,7 @@ impl Resolver {
454 self 451 self
455 } 452 }
456 453
457 fn push_generic_params_scope(self, db: &impl DefDatabase2, def: GenericDefId) -> Resolver { 454 fn push_generic_params_scope(self, db: &impl DefDatabase, def: GenericDefId) -> Resolver {
458 let params = db.generic_params(def); 455 let params = db.generic_params(def);
459 if params.params.is_empty() { 456 if params.params.is_empty() {
460 self 457 self
@@ -470,7 +467,7 @@ impl Resolver {
470 fn push_module_scope( 467 fn push_module_scope(
471 self, 468 self,
472 crate_def_map: Arc<CrateDefMap>, 469 crate_def_map: Arc<CrateDefMap>,
473 module_id: CrateModuleId, 470 module_id: LocalModuleId,
474 ) -> Resolver { 471 ) -> Resolver {
475 self.push_scope(Scope::ModuleScope(ModuleItemMap { crate_def_map, module_id })) 472 self.push_scope(Scope::ModuleScope(ModuleItemMap { crate_def_map, module_id }))
476 } 473 }
@@ -487,24 +484,24 @@ impl Resolver {
487 484
488pub trait HasResolver { 485pub trait HasResolver {
489 /// Builds a resolver for type references inside this def. 486 /// Builds a resolver for type references inside this def.
490 fn resolver(self, db: &impl DefDatabase2) -> Resolver; 487 fn resolver(self, db: &impl DefDatabase) -> Resolver;
491} 488}
492 489
493impl HasResolver for ModuleId { 490impl HasResolver for ModuleId {
494 fn resolver(self, db: &impl DefDatabase2) -> Resolver { 491 fn resolver(self, db: &impl DefDatabase) -> Resolver {
495 let def_map = db.crate_def_map(self.krate); 492 let def_map = db.crate_def_map(self.krate);
496 Resolver::default().push_module_scope(def_map, self.module_id) 493 Resolver::default().push_module_scope(def_map, self.module_id)
497 } 494 }
498} 495}
499 496
500impl HasResolver for TraitId { 497impl HasResolver for TraitId {
501 fn resolver(self, db: &impl DefDatabase2) -> Resolver { 498 fn resolver(self, db: &impl DefDatabase) -> Resolver {
502 self.module(db).resolver(db).push_generic_params_scope(db, self.into()) 499 self.module(db).resolver(db).push_generic_params_scope(db, self.into())
503 } 500 }
504} 501}
505 502
506impl<T: Into<AdtId>> HasResolver for T { 503impl<T: Into<AdtId>> HasResolver for T {
507 fn resolver(self, db: &impl DefDatabase2) -> Resolver { 504 fn resolver(self, db: &impl DefDatabase) -> Resolver {
508 let def = self.into(); 505 let def = self.into();
509 let module = match def { 506 let module = match def {
510 AdtId::StructId(it) => it.0.module(db), 507 AdtId::StructId(it) => it.0.module(db),
@@ -520,13 +517,13 @@ impl<T: Into<AdtId>> HasResolver for T {
520} 517}
521 518
522impl HasResolver for FunctionId { 519impl HasResolver for FunctionId {
523 fn resolver(self, db: &impl DefDatabase2) -> Resolver { 520 fn resolver(self, db: &impl DefDatabase) -> Resolver {
524 self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into()) 521 self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into())
525 } 522 }
526} 523}
527 524
528impl HasResolver for DefWithBodyId { 525impl HasResolver for DefWithBodyId {
529 fn resolver(self, db: &impl DefDatabase2) -> Resolver { 526 fn resolver(self, db: &impl DefDatabase) -> Resolver {
530 match self { 527 match self {
531 DefWithBodyId::ConstId(c) => c.resolver(db), 528 DefWithBodyId::ConstId(c) => c.resolver(db),
532 DefWithBodyId::FunctionId(f) => f.resolver(db), 529 DefWithBodyId::FunctionId(f) => f.resolver(db),
@@ -536,25 +533,25 @@ impl HasResolver for DefWithBodyId {
536} 533}
537 534
538impl HasResolver for ConstId { 535impl HasResolver for ConstId {
539 fn resolver(self, db: &impl DefDatabase2) -> Resolver { 536 fn resolver(self, db: &impl DefDatabase) -> Resolver {
540 self.lookup(db).container.resolver(db) 537 self.lookup(db).container.resolver(db)
541 } 538 }
542} 539}
543 540
544impl HasResolver for StaticId { 541impl HasResolver for StaticId {
545 fn resolver(self, db: &impl DefDatabase2) -> Resolver { 542 fn resolver(self, db: &impl DefDatabase) -> Resolver {
546 self.module(db).resolver(db) 543 self.module(db).resolver(db)
547 } 544 }
548} 545}
549 546
550impl HasResolver for TypeAliasId { 547impl HasResolver for TypeAliasId {
551 fn resolver(self, db: &impl DefDatabase2) -> Resolver { 548 fn resolver(self, db: &impl DefDatabase) -> Resolver {
552 self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into()) 549 self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into())
553 } 550 }
554} 551}
555 552
556impl HasResolver for ContainerId { 553impl HasResolver for ContainerId {
557 fn resolver(self, db: &impl DefDatabase2) -> Resolver { 554 fn resolver(self, db: &impl DefDatabase) -> Resolver {
558 match self { 555 match self {
559 ContainerId::TraitId(it) => it.resolver(db), 556 ContainerId::TraitId(it) => it.resolver(db),
560 ContainerId::ImplId(it) => it.resolver(db), 557 ContainerId::ImplId(it) => it.resolver(db),
@@ -564,7 +561,7 @@ impl HasResolver for ContainerId {
564} 561}
565 562
566impl HasResolver for GenericDefId { 563impl HasResolver for GenericDefId {
567 fn resolver(self, db: &impl DefDatabase2) -> Resolver { 564 fn resolver(self, db: &impl DefDatabase) -> Resolver {
568 match self { 565 match self {
569 GenericDefId::FunctionId(inner) => inner.resolver(db), 566 GenericDefId::FunctionId(inner) => inner.resolver(db),
570 GenericDefId::AdtId(adt) => adt.resolver(db), 567 GenericDefId::AdtId(adt) => adt.resolver(db),
@@ -578,7 +575,7 @@ impl HasResolver for GenericDefId {
578} 575}
579 576
580impl HasResolver for ImplId { 577impl HasResolver for ImplId {
581 fn resolver(self, db: &impl DefDatabase2) -> Resolver { 578 fn resolver(self, db: &impl DefDatabase) -> Resolver {
582 self.module(db) 579 self.module(db)
583 .resolver(db) 580 .resolver(db)
584 .push_generic_params_scope(db, self.into()) 581 .push_generic_params_scope(db, self.into())
diff --git a/crates/ra_hir_def/src/test_db.rs b/crates/ra_hir_def/src/test_db.rs
index 8ee8e40d0..439e8a412 100644
--- a/crates/ra_hir_def/src/test_db.rs
+++ b/crates/ra_hir_def/src/test_db.rs
@@ -12,7 +12,7 @@ use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath
12 ra_db::SourceDatabaseStorage, 12 ra_db::SourceDatabaseStorage,
13 hir_expand::db::AstDatabaseStorage, 13 hir_expand::db::AstDatabaseStorage,
14 crate::db::InternDatabaseStorage, 14 crate::db::InternDatabaseStorage,
15 crate::db::DefDatabase2Storage 15 crate::db::DefDatabaseStorage
16)] 16)]
17#[derive(Debug, Default)] 17#[derive(Debug, Default)]
18pub struct TestDB { 18pub struct TestDB {
diff --git a/crates/ra_hir_def/src/trace.rs b/crates/ra_hir_def/src/trace.rs
new file mode 100644
index 000000000..fc26f5a48
--- /dev/null
+++ b/crates/ra_hir_def/src/trace.rs
@@ -0,0 +1,49 @@
1//! Trace is a pretty niche data structure which is used when lowering a CST
2//! into HIR.
3//!
4//! Lowering process calculates two bits of information:
5//! * the lowered syntax itself
6//! * a mapping between lowered syntax and original syntax
7//!
8//! Due to the way salsa works, the mapping is usually hot lava, as it contains
9//! absolute offsets. The `Trace` structure (inspired, at least in name, by
10//! Kotlin's `BindingTrace`) allows use the same code to compute both
11//! projections.
12use ra_arena::{map::ArenaMap, Arena, ArenaId, RawId};
13
14pub(crate) struct Trace<ID: ArenaId, T, V> {
15 for_arena: bool,
16 arena: Arena<ID, T>,
17 map: ArenaMap<ID, V>,
18 len: u32,
19}
20
21impl<ID: ra_arena::ArenaId, T, V> Trace<ID, T, V> {
22 pub(crate) fn new_for_arena() -> Trace<ID, T, V> {
23 Trace { for_arena: true, arena: Arena::default(), map: ArenaMap::default(), len: 0 }
24 }
25
26 pub(crate) fn new_for_map() -> Trace<ID, T, V> {
27 Trace { for_arena: false, arena: Arena::default(), map: ArenaMap::default(), len: 0 }
28 }
29
30 pub(crate) fn alloc(&mut self, value: impl Fn() -> V, data: impl Fn() -> T) {
31 if self.for_arena {
32 self.arena.alloc(data());
33 } else {
34 let id = ID::from_raw(RawId::from(self.len));
35 self.len += 1;
36 self.map.insert(id, value());
37 }
38 }
39
40 pub(crate) fn into_arena(self) -> Arena<ID, T> {
41 assert!(self.for_arena);
42 self.arena
43 }
44
45 pub(crate) fn into_map(self) -> ArenaMap<ID, V> {
46 assert!(!self.for_arena);
47 self.map
48 }
49}
diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs
index 4da56529d..c0e0436c0 100644
--- a/crates/ra_hir_expand/src/builtin_macro.rs
+++ b/crates/ra_hir_expand/src/builtin_macro.rs
@@ -8,47 +8,47 @@ use crate::{
8 8
9use crate::quote; 9use crate::quote;
10 10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 11macro_rules! register_builtin {
12pub enum BuiltinExpander { 12 ( $(($name:ident, $kind: ident) => $expand:ident),* ) => {
13 Column, 13 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
14 File, 14 pub enum BuiltinFnLikeExpander {
15 Line, 15 $($kind),*
16 Stringify, 16 }
17}
18 17
19impl BuiltinExpander { 18 impl BuiltinFnLikeExpander {
20 pub fn expand( 19 pub fn expand(
21 &self, 20 &self,
22 db: &dyn AstDatabase, 21 db: &dyn AstDatabase,
23 id: MacroCallId, 22 id: MacroCallId,
24 tt: &tt::Subtree, 23 tt: &tt::Subtree,
25 ) -> Result<tt::Subtree, mbe::ExpandError> { 24 ) -> Result<tt::Subtree, mbe::ExpandError> {
26 match self { 25 let expander = match *self {
27 BuiltinExpander::Column => column_expand(db, id, tt), 26 $( BuiltinFnLikeExpander::$kind => $expand, )*
28 BuiltinExpander::File => file_expand(db, id, tt), 27 };
29 BuiltinExpander::Line => line_expand(db, id, tt), 28 expander(db, id, tt)
30 BuiltinExpander::Stringify => stringify_expand(db, id, tt), 29 }
31 } 30 }
32 } 31
32 pub fn find_builtin_macro(
33 ident: &name::Name,
34 krate: CrateId,
35 ast_id: AstId<ast::MacroCall>,
36 ) -> Option<MacroDefId> {
37 let kind = match ident {
38 $( id if id == &name::$name => BuiltinFnLikeExpander::$kind, )*
39 _ => return None,
40 };
41
42 Some(MacroDefId { krate, ast_id, kind: MacroDefKind::BuiltIn(kind) })
43 }
44 };
33} 45}
34 46
35pub fn find_builtin_macro( 47register_builtin! {
36 ident: &name::Name, 48 (COLUMN_MACRO, Column) => column_expand,
37 krate: CrateId, 49 (FILE_MACRO, File) => file_expand,
38 ast_id: AstId<ast::MacroCall>, 50 (LINE_MACRO, Line) => line_expand,
39) -> Option<MacroDefId> { 51 (STRINGIFY_MACRO, Stringify) => stringify_expand
40 // FIXME: Better registering method
41 if ident == &name::COLUMN_MACRO {
42 Some(MacroDefId { krate, ast_id, kind: MacroDefKind::BuiltIn(BuiltinExpander::Column) })
43 } else if ident == &name::FILE_MACRO {
44 Some(MacroDefId { krate, ast_id, kind: MacroDefKind::BuiltIn(BuiltinExpander::File) })
45 } else if ident == &name::LINE_MACRO {
46 Some(MacroDefId { krate, ast_id, kind: MacroDefKind::BuiltIn(BuiltinExpander::Line) })
47 } else if ident == &name::STRINGIFY_MACRO {
48 Some(MacroDefId { krate, ast_id, kind: MacroDefKind::BuiltIn(BuiltinExpander::Stringify) })
49 } else {
50 None
51 }
52} 52}
53 53
54fn to_line_number(db: &dyn AstDatabase, file: HirFileId, pos: TextUnit) -> usize { 54fn to_line_number(db: &dyn AstDatabase, file: HirFileId, pos: TextUnit) -> usize {
@@ -171,3 +171,92 @@ fn file_expand(
171 171
172 Ok(expanded) 172 Ok(expanded)
173} 173}
174
175#[cfg(test)]
176mod tests {
177 use super::*;
178 use crate::{test_db::TestDB, MacroCallLoc};
179 use ra_db::{fixture::WithFixture, SourceDatabase};
180
181 fn expand_builtin_macro(s: &str, expander: BuiltinFnLikeExpander) -> String {
182 let (db, file_id) = TestDB::with_single_file(&s);
183 let parsed = db.parse(file_id);
184 let macro_calls: Vec<_> =
185 parsed.syntax_node().descendants().filter_map(|it| ast::MacroCall::cast(it)).collect();
186
187 let ast_id_map = db.ast_id_map(file_id.into());
188
189 // the first one should be a macro_rules
190 let def = MacroDefId {
191 krate: CrateId(0),
192 ast_id: AstId::new(file_id.into(), ast_id_map.ast_id(&macro_calls[0])),
193 kind: MacroDefKind::BuiltIn(expander),
194 };
195
196 let loc = MacroCallLoc {
197 def,
198 ast_id: AstId::new(file_id.into(), ast_id_map.ast_id(&macro_calls[1])),
199 };
200
201 let id = db.intern_macro(loc);
202 let parsed = db.parse_or_expand(id.as_file(MacroFileKind::Expr)).unwrap();
203
204 parsed.text().to_string()
205 }
206
207 #[test]
208 fn test_column_expand() {
209 let expanded = expand_builtin_macro(
210 r#"
211 #[rustc_builtin_macro]
212 macro_rules! column {() => {}}
213 column!()
214"#,
215 BuiltinFnLikeExpander::Column,
216 );
217
218 assert_eq!(expanded, "9");
219 }
220
221 #[test]
222 fn test_line_expand() {
223 let expanded = expand_builtin_macro(
224 r#"
225 #[rustc_builtin_macro]
226 macro_rules! line {() => {}}
227 line!()
228"#,
229 BuiltinFnLikeExpander::Line,
230 );
231
232 assert_eq!(expanded, "4");
233 }
234
235 #[test]
236 fn test_stringify_expand() {
237 let expanded = expand_builtin_macro(
238 r#"
239 #[rustc_builtin_macro]
240 macro_rules! stringify {() => {}}
241 stringify!(a b c)
242"#,
243 BuiltinFnLikeExpander::Stringify,
244 );
245
246 assert_eq!(expanded, "\"a b c\"");
247 }
248
249 #[test]
250 fn test_file_expand() {
251 let expanded = expand_builtin_macro(
252 r#"
253 #[rustc_builtin_macro]
254 macro_rules! file {() => {}}
255 file!()
256"#,
257 BuiltinFnLikeExpander::File,
258 );
259
260 assert_eq!(expanded, "\"\"");
261 }
262}
diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs
index e1d93a8ef..8e46fa177 100644
--- a/crates/ra_hir_expand/src/db.rs
+++ b/crates/ra_hir_expand/src/db.rs
@@ -9,14 +9,14 @@ use ra_prof::profile;
9use ra_syntax::{AstNode, Parse, SyntaxNode}; 9use ra_syntax::{AstNode, Parse, SyntaxNode};
10 10
11use crate::{ 11use crate::{
12 ast_id_map::AstIdMap, BuiltinExpander, HirFileId, HirFileIdRepr, MacroCallId, MacroCallLoc, 12 ast_id_map::AstIdMap, BuiltinFnLikeExpander, HirFileId, HirFileIdRepr, MacroCallId,
13 MacroDefId, MacroDefKind, MacroFile, MacroFileKind, 13 MacroCallLoc, MacroDefId, MacroDefKind, MacroFile, MacroFileKind,
14}; 14};
15 15
16#[derive(Debug, Clone, Eq, PartialEq)] 16#[derive(Debug, Clone, Eq, PartialEq)]
17pub enum TokenExpander { 17pub enum TokenExpander {
18 MacroRules(mbe::MacroRules), 18 MacroRules(mbe::MacroRules),
19 Builtin(BuiltinExpander), 19 Builtin(BuiltinFnLikeExpander),
20} 20}
21 21
22impl TokenExpander { 22impl TokenExpander {
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs
index 126d12fbb..4f3ccf1d0 100644
--- a/crates/ra_hir_expand/src/lib.rs
+++ b/crates/ra_hir_expand/src/lib.rs
@@ -24,7 +24,10 @@ use ra_syntax::{
24}; 24};
25 25
26use crate::ast_id_map::FileAstId; 26use crate::ast_id_map::FileAstId;
27use crate::builtin_macro::BuiltinExpander; 27use crate::builtin_macro::BuiltinFnLikeExpander;
28
29#[cfg(test)]
30mod test_db;
28 31
29/// Input to the analyzer is a set of files, where each file is identified by 32/// Input to the analyzer is a set of files, where each file is identified by
30/// `FileId` and contains source code. However, another source of source code in 33/// `FileId` and contains source code. However, another source of source code in
@@ -135,7 +138,7 @@ pub struct MacroDefId {
135#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 138#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
136pub enum MacroDefKind { 139pub enum MacroDefKind {
137 Declarative, 140 Declarative,
138 BuiltIn(BuiltinExpander), 141 BuiltIn(BuiltinFnLikeExpander),
139} 142}
140 143
141#[derive(Debug, Clone, PartialEq, Eq, Hash)] 144#[derive(Debug, Clone, PartialEq, Eq, Hash)]
diff --git a/crates/ra_hir_expand/src/test_db.rs b/crates/ra_hir_expand/src/test_db.rs
new file mode 100644
index 000000000..d23e75d9e
--- /dev/null
+++ b/crates/ra_hir_expand/src/test_db.rs
@@ -0,0 +1,50 @@
1//! Database used for testing `hir_expand`.
2
3use std::{
4 panic,
5 sync::{Arc, Mutex},
6};
7
8use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath};
9
10#[salsa::database(
11 ra_db::SourceDatabaseExtStorage,
12 ra_db::SourceDatabaseStorage,
13 crate::db::AstDatabaseStorage
14)]
15#[derive(Debug, Default)]
16pub struct TestDB {
17 runtime: salsa::Runtime<TestDB>,
18 events: Mutex<Option<Vec<salsa::Event<TestDB>>>>,
19}
20
21impl salsa::Database for TestDB {
22 fn salsa_runtime(&self) -> &salsa::Runtime<Self> {
23 &self.runtime
24 }
25
26 fn salsa_event(&self, event: impl Fn() -> salsa::Event<TestDB>) {
27 let mut events = self.events.lock().unwrap();
28 if let Some(events) = &mut *events {
29 events.push(event());
30 }
31 }
32}
33
34impl panic::RefUnwindSafe for TestDB {}
35
36impl FileLoader for TestDB {
37 fn file_text(&self, file_id: FileId) -> Arc<String> {
38 FileLoaderDelegate(self).file_text(file_id)
39 }
40 fn resolve_relative_path(
41 &self,
42 anchor: FileId,
43 relative_path: &RelativePath,
44 ) -> Option<FileId> {
45 FileLoaderDelegate(self).resolve_relative_path(anchor, relative_path)
46 }
47 fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> {
48 FileLoaderDelegate(self).relevant_crates(file_id)
49 }
50}
diff --git a/crates/ra_ide_api/src/completion/complete_path.rs b/crates/ra_ide_api/src/completion/complete_path.rs
index 802c7701a..63e25e0bf 100644
--- a/crates/ra_ide_api/src/completion/complete_path.rs
+++ b/crates/ra_ide_api/src/completion/complete_path.rs
@@ -1,6 +1,6 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir::{Adt, Either, PathResolution}; 3use hir::{Adt, Either, HasSource, PathResolution};
4use ra_syntax::AstNode; 4use ra_syntax::AstNode;
5use test_utils::tested_by; 5use test_utils::tested_by;
6 6
@@ -27,7 +27,7 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
27 } 27 }
28 if Some(module) == ctx.module { 28 if Some(module) == ctx.module {
29 if let Some(import) = import { 29 if let Some(import) = import {
30 if let Either::A(use_tree) = module.import_source(ctx.db, import) { 30 if let Either::A(use_tree) = import.source(ctx.db).value {
31 if use_tree.syntax().text_range().contains_inclusive(ctx.offset) { 31 if use_tree.syntax().text_range().contains_inclusive(ctx.offset) {
32 // for `use self::foo<|>`, don't suggest `foo` as a completion 32 // for `use self::foo<|>`, don't suggest `foo` as a completion
33 tested_by!(dont_complete_current_use); 33 tested_by!(dont_complete_current_use);
diff --git a/crates/ra_ide_api/src/db.rs b/crates/ra_ide_api/src/db.rs
index c96465b6a..c2a9dcdd1 100644
--- a/crates/ra_ide_api/src/db.rs
+++ b/crates/ra_ide_api/src/db.rs
@@ -22,7 +22,6 @@ use crate::{
22 hir::db::InternDatabaseStorage, 22 hir::db::InternDatabaseStorage,
23 hir::db::AstDatabaseStorage, 23 hir::db::AstDatabaseStorage,
24 hir::db::DefDatabaseStorage, 24 hir::db::DefDatabaseStorage,
25 hir::db::DefDatabase2Storage,
26 hir::db::HirDatabaseStorage 25 hir::db::HirDatabaseStorage
27)] 26)]
28#[derive(Debug)] 27#[derive(Debug)]
diff --git a/crates/ra_syntax/src/ast/edit.rs b/crates/ra_syntax/src/ast/edit.rs
index 6f005a2d8..95bf9db14 100644
--- a/crates/ra_syntax/src/ast/edit.rs
+++ b/crates/ra_syntax/src/ast/edit.rs
@@ -13,11 +13,21 @@ use crate::{
13 make::{self, tokens}, 13 make::{self, tokens},
14 AstNode, TypeBoundsOwner, 14 AstNode, TypeBoundsOwner,
15 }, 15 },
16 AstToken, Direction, InsertPosition, SmolStr, SyntaxElement, 16 AstToken, Direction, InsertPosition, SmolStr, SyntaxElement, SyntaxKind,
17 SyntaxKind::{ATTR, COMMENT, WHITESPACE}, 17 SyntaxKind::{ATTR, COMMENT, WHITESPACE},
18 SyntaxNode, SyntaxToken, T, 18 SyntaxNode, SyntaxToken, T,
19}; 19};
20 20
21impl ast::BinExpr {
22 #[must_use]
23 pub fn replace_op(&self, op: SyntaxKind) -> Option<ast::BinExpr> {
24 let op_node: SyntaxElement = self.op_details()?.0.into();
25 let to_insert: Option<SyntaxElement> = Some(tokens::op(op).into());
26 let replace_range = RangeInclusive::new(op_node.clone(), op_node);
27 Some(replace_children(self, replace_range, to_insert.into_iter()))
28 }
29}
30
21impl ast::FnDef { 31impl ast::FnDef {
22 #[must_use] 32 #[must_use]
23 pub fn with_body(&self, body: ast::Block) -> ast::FnDef { 33 pub fn with_body(&self, body: ast::Block) -> ast::FnDef {
diff --git a/crates/ra_syntax/src/ast/expr_extensions.rs b/crates/ra_syntax/src/ast/expr_extensions.rs
index 7c53aa934..2fd039837 100644
--- a/crates/ra_syntax/src/ast/expr_extensions.rs
+++ b/crates/ra_syntax/src/ast/expr_extensions.rs
@@ -127,7 +127,7 @@ pub enum BinOp {
127} 127}
128 128
129impl ast::BinExpr { 129impl ast::BinExpr {
130 fn op_details(&self) -> Option<(SyntaxToken, BinOp)> { 130 pub fn op_details(&self) -> Option<(SyntaxToken, BinOp)> {
131 self.syntax().children_with_tokens().filter_map(|it| it.into_token()).find_map(|c| { 131 self.syntax().children_with_tokens().filter_map(|it| it.into_token()).find_map(|c| {
132 let bin_op = match c.kind() { 132 let bin_op = match c.kind() {
133 T![||] => BinOp::BooleanOr, 133 T![||] => BinOp::BooleanOr,
diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs
index 9749327fa..40db570da 100644
--- a/crates/ra_syntax/src/ast/make.rs
+++ b/crates/ra_syntax/src/ast/make.rs
@@ -173,10 +173,21 @@ fn ast_from_text<N: AstNode>(text: &str) -> N {
173} 173}
174 174
175pub mod tokens { 175pub mod tokens {
176 use crate::{AstNode, Parse, SourceFile, SyntaxKind::*, SyntaxToken, T}; 176 use crate::{AstNode, Parse, SourceFile, SyntaxKind, SyntaxKind::*, SyntaxToken, T};
177 use once_cell::sync::Lazy; 177 use once_cell::sync::Lazy;
178 178
179 static SOURCE_FILE: Lazy<Parse<SourceFile>> = Lazy::new(|| SourceFile::parse(",\n; ;")); 179 static SOURCE_FILE: Lazy<Parse<SourceFile>> =
180 Lazy::new(|| SourceFile::parse("const C: () = (1 != 1, 2 == 2)\n;"));
181
182 pub fn op(op: SyntaxKind) -> SyntaxToken {
183 SOURCE_FILE
184 .tree()
185 .syntax()
186 .descendants_with_tokens()
187 .filter_map(|it| it.into_token())
188 .find(|it| it.kind() == op)
189 .unwrap()
190 }
180 191
181 pub fn comma() -> SyntaxToken { 192 pub fn comma() -> SyntaxToken {
182 SOURCE_FILE 193 SOURCE_FILE
diff --git a/docs/user/README.md b/docs/user/README.md
index bfb190449..913ecea18 100644
--- a/docs/user/README.md
+++ b/docs/user/README.md
@@ -132,6 +132,11 @@ to load path and require it in `init.el`
132 132
133## Vim and NeoVim 133## Vim and NeoVim
134 134
135Neovim 0.5 has a built in language server. For a quick start configuration of
136rust-analyzer, use [neovim/nvim-lsp](https://github.com/neovim/nvim-lsp#rust_analyzer).
137Once `neovim/nvim-lsp` is installed, you can use `call nvim_lsp#setup("rust_analyzer", {})`
138or `lua require'nvim_lsp'.rust_analyzer.setup({})` to quickly get set up.
139
135* Install coc.nvim by following the instructions at [coc.nvim] 140* Install coc.nvim by following the instructions at [coc.nvim]
136 - You will need nodejs installed. 141 - You will need nodejs installed.
137 - You may want to include some of the sample vim configurations [from here][coc-vim-conf] 142 - You may want to include some of the sample vim configurations [from here][coc-vim-conf]
diff --git a/docs/user/assists.md b/docs/user/assists.md
index 8da7578e2..6f4c30bee 100644
--- a/docs/user/assists.md
+++ b/docs/user/assists.md
@@ -329,6 +329,25 @@ fn main() {
329} 329}
330``` 330```
331 331
332## `invert_if`
333
334Apply invert_if
335This transforms if expressions of the form `if !x {A} else {B}` into `if x {B} else {A}`
336This also works with `!=`. This assist can only be applied with the cursor
337on `if`.
338
339```rust
340// BEFORE
341fn main() {
342 if┃ !y { A } else { B }
343}
344
345// AFTER
346fn main() {
347 if y { B } else { A }
348}
349```
350
332## `make_raw_string` 351## `make_raw_string`
333 352
334Adds `r#` to a plain string literal. 353Adds `r#` to a plain string literal.