aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/release.yaml7
-rw-r--r--crates/assists/src/handlers/add_lifetime_to_type.rs228
-rw-r--r--crates/assists/src/lib.rs2
-rw-r--r--crates/assists/src/tests/generated.rs19
-rw-r--r--crates/completion/src/completions/dot.rs22
-rw-r--r--crates/completion/src/completions/flyimport.rs16
-rw-r--r--crates/completion/src/completions/fn_param.rs4
-rw-r--r--crates/completion/src/completions/mod_.rs10
-rw-r--r--crates/completion/src/completions/qualified_path.rs54
-rw-r--r--crates/completion/src/completions/record.rs8
-rw-r--r--crates/completion/src/completions/trait_impl.rs13
-rw-r--r--crates/completion/src/completions/unqualified_path.rs88
-rw-r--r--crates/completion/src/item.rs75
-rw-r--r--crates/completion/src/lib.rs91
-rw-r--r--crates/completion/src/render.rs119
-rw-r--r--crates/completion/src/render/const_.rs5
-rw-r--r--crates/completion/src/render/enum_variant.rs5
-rw-r--r--crates/completion/src/render/function.rs10
-rw-r--r--crates/completion/src/render/macro_.rs5
-rw-r--r--crates/completion/src/render/type_alias.rs5
-rw-r--r--crates/hir/src/attrs.rs6
-rw-r--r--crates/hir/src/code_model.rs67
-rw-r--r--crates/hir/src/has_source.rs6
-rw-r--r--crates/hir/src/semantics/source_to_def.rs10
-rw-r--r--crates/hir_def/src/attr.rs2
-rw-r--r--crates/hir_def/src/body.rs2
-rw-r--r--crates/hir_def/src/child_by_source.rs2
-rw-r--r--crates/hir_def/src/find_path.rs10
-rw-r--r--crates/hir_def/src/import_map.rs2
-rw-r--r--crates/hir_def/src/lib.rs22
-rw-r--r--crates/hir_def/src/nameres/collector.rs2
-rw-r--r--crates/hir_def/src/nameres/path_resolution.rs4
-rw-r--r--crates/hir_def/src/resolver.rs19
-rw-r--r--crates/hir_def/src/visibility.rs2
-rw-r--r--crates/hir_ty/src/display.rs2
-rw-r--r--crates/hir_ty/src/infer/expr.rs5
-rw-r--r--crates/hir_ty/src/lib.rs14
-rw-r--r--crates/hir_ty/src/lower.rs2
-rw-r--r--crates/hir_ty/src/method_resolution.rs6
-rw-r--r--crates/hir_ty/src/test_db.rs2
-rw-r--r--crates/hir_ty/src/tests.rs8
-rw-r--r--crates/hir_ty/src/tests/simple.rs24
-rw-r--r--crates/hir_ty/src/traits/chalk.rs4
-rw-r--r--crates/ide/src/display/navigation_target.rs25
-rw-r--r--crates/ide/src/doc_links.rs23
-rw-r--r--crates/ide/src/file_structure.rs3
-rw-r--r--crates/ide/src/goto_definition.rs90
-rw-r--r--crates/ide/src/hover.rs29
-rw-r--r--crates/ide/src/lib.rs2
-rw-r--r--crates/ide/src/runnables.rs4
-rw-r--r--crates/ide/src/syntax_highlighting.rs4
-rw-r--r--crates/ide/src/syntax_highlighting/format.rs3
-rw-r--r--crates/ide/src/syntax_highlighting/highlight.rs4
-rw-r--r--crates/ide/src/syntax_highlighting/tags.rs2
-rw-r--r--crates/ide_db/src/lib.rs24
-rw-r--r--crates/project_model/src/build_data.rs206
-rw-r--r--crates/project_model/src/cargo_workspace.rs197
-rw-r--r--crates/project_model/src/lib.rs1
-rw-r--r--crates/project_model/src/workspace.rs20
-rw-r--r--crates/rust-analyzer/src/bin/main.rs7
-rw-r--r--crates/rust-analyzer/src/handlers.rs3
-rw-r--r--crates/rust-analyzer/src/to_proto.rs45
-rw-r--r--crates/stdx/src/lib.rs1
-rw-r--r--docs/dev/style.md22
64 files changed, 1089 insertions, 635 deletions
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index a97ed24ba..94b6aa7c4 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -94,6 +94,7 @@ jobs:
94 toolchain: stable 94 toolchain: stable
95 profile: minimal 95 profile: minimal
96 override: true 96 override: true
97 components: rust-src
97 98
98 - name: Install Nodejs 99 - name: Install Nodejs
99 uses: actions/setup-node@v1 100 uses: actions/setup-node@v1
@@ -108,10 +109,12 @@ jobs:
108 if: github.ref != 'refs/heads/release' 109 if: github.ref != 'refs/heads/release'
109 run: cargo xtask dist --nightly --client 0.3.$GITHUB_RUN_NUMBER-nightly 110 run: cargo xtask dist --nightly --client 0.3.$GITHUB_RUN_NUMBER-nightly
110 111
111 - name: Nightly analysis-stats check 112 - name: Run analysis-stats on rust-analyzer
112 if: github.ref != 'refs/heads/release'
113 run: target/${{ env.RA_TARGET }}/release/rust-analyzer analysis-stats . 113 run: target/${{ env.RA_TARGET }}/release/rust-analyzer analysis-stats .
114 114
115 - name: Run analysis-stats on rust std library
116 run: target/${{ env.RA_TARGET }}/release/rust-analyzer analysis-stats --with-deps $(rustc --print sysroot)/lib/rustlib/src/rust/library/std
117
115 - name: Upload artifacts 118 - name: Upload artifacts
116 uses: actions/upload-artifact@v1 119 uses: actions/upload-artifact@v1
117 with: 120 with:
diff --git a/crates/assists/src/handlers/add_lifetime_to_type.rs b/crates/assists/src/handlers/add_lifetime_to_type.rs
new file mode 100644
index 000000000..c1603e972
--- /dev/null
+++ b/crates/assists/src/handlers/add_lifetime_to_type.rs
@@ -0,0 +1,228 @@
1use ast::FieldList;
2use syntax::ast::{self, AstNode, GenericParamsOwner, NameOwner, RefType, Type};
3
4use crate::{AssistContext, AssistId, AssistKind, Assists};
5
6// Assist: add_lifetime_to_type
7//
8// Adds a new lifetime to a struct, enum or union.
9//
10// ```
11// struct Point {
12// x: &$0u32,
13// y: u32,
14// }
15// ```
16// ->
17// ```
18// struct Point<'a> {
19// x: &'a u32,
20// y: u32,
21// }
22// ```
23pub(crate) fn add_lifetime_to_type(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
24 let ref_type_focused = ctx.find_node_at_offset::<ast::RefType>()?;
25 if ref_type_focused.lifetime().is_some() {
26 return None;
27 }
28
29 let node = ctx.find_node_at_offset::<ast::AdtDef>()?;
30 let has_lifetime = node
31 .generic_param_list()
32 .map(|gen_list| gen_list.lifetime_params().count() > 0)
33 .unwrap_or_default();
34
35 if has_lifetime {
36 return None;
37 }
38
39 let ref_types = fetch_borrowed_types(&node)?;
40 let target = node.syntax().text_range();
41
42 acc.add(
43 AssistId("add_lifetime_to_type", AssistKind::Generate),
44 "Add lifetime`",
45 target,
46 |builder| {
47 match node.generic_param_list() {
48 Some(gen_param) => {
49 if let Some(left_angle) = gen_param.l_angle_token() {
50 builder.insert(left_angle.text_range().end(), "'a, ");
51 }
52 }
53 None => {
54 if let Some(name) = node.name() {
55 builder.insert(name.syntax().text_range().end(), "<'a>");
56 }
57 }
58 }
59
60 for ref_type in ref_types {
61 if let Some(amp_token) = ref_type.amp_token() {
62 builder.insert(amp_token.text_range().end(), "'a ");
63 }
64 }
65 },
66 )
67}
68
69fn fetch_borrowed_types(node: &ast::AdtDef) -> Option<Vec<RefType>> {
70 let ref_types: Vec<RefType> = match node {
71 ast::AdtDef::Enum(enum_) => {
72 let variant_list = enum_.variant_list()?;
73 variant_list
74 .variants()
75 .filter_map(|variant| {
76 let field_list = variant.field_list()?;
77
78 find_ref_types_from_field_list(&field_list)
79 })
80 .flatten()
81 .collect()
82 }
83 ast::AdtDef::Struct(strukt) => {
84 let field_list = strukt.field_list()?;
85 find_ref_types_from_field_list(&field_list)?
86 }
87 ast::AdtDef::Union(un) => {
88 let record_field_list = un.record_field_list()?;
89 record_field_list
90 .fields()
91 .filter_map(|r_field| {
92 if let Type::RefType(ref_type) = r_field.ty()? {
93 if ref_type.lifetime().is_none() {
94 return Some(ref_type);
95 }
96 }
97
98 None
99 })
100 .collect()
101 }
102 };
103
104 if ref_types.is_empty() {
105 None
106 } else {
107 Some(ref_types)
108 }
109}
110
111fn find_ref_types_from_field_list(field_list: &FieldList) -> Option<Vec<RefType>> {
112 let ref_types: Vec<RefType> = match field_list {
113 ast::FieldList::RecordFieldList(record_list) => record_list
114 .fields()
115 .filter_map(|f| {
116 if let Type::RefType(ref_type) = f.ty()? {
117 if ref_type.lifetime().is_none() {
118 return Some(ref_type);
119 }
120 }
121
122 None
123 })
124 .collect(),
125 ast::FieldList::TupleFieldList(tuple_field_list) => tuple_field_list
126 .fields()
127 .filter_map(|f| {
128 if let Type::RefType(ref_type) = f.ty()? {
129 if ref_type.lifetime().is_none() {
130 return Some(ref_type);
131 }
132 }
133
134 None
135 })
136 .collect(),
137 };
138
139 if ref_types.is_empty() {
140 None
141 } else {
142 Some(ref_types)
143 }
144}
145
146#[cfg(test)]
147mod tests {
148 use crate::tests::{check_assist, check_assist_not_applicable};
149
150 use super::*;
151
152 #[test]
153 fn add_lifetime_to_struct() {
154 check_assist(
155 add_lifetime_to_type,
156 "struct Foo { a: &$0i32 }",
157 "struct Foo<'a> { a: &'a i32 }",
158 );
159
160 check_assist(
161 add_lifetime_to_type,
162 "struct Foo { a: &$0i32, b: &usize }",
163 "struct Foo<'a> { a: &'a i32, b: &'a usize }",
164 );
165
166 check_assist(
167 add_lifetime_to_type,
168 "struct Foo { a: &$0i32, b: usize }",
169 "struct Foo<'a> { a: &'a i32, b: usize }",
170 );
171
172 check_assist(
173 add_lifetime_to_type,
174 "struct Foo<T> { a: &$0T, b: usize }",
175 "struct Foo<'a, T> { a: &'a T, b: usize }",
176 );
177
178 check_assist_not_applicable(add_lifetime_to_type, "struct Foo<'a> { a: &$0'a i32 }");
179 check_assist_not_applicable(add_lifetime_to_type, "struct Foo { a: &'a$0 i32 }");
180 }
181
182 #[test]
183 fn add_lifetime_to_enum() {
184 check_assist(
185 add_lifetime_to_type,
186 "enum Foo { Bar { a: i32 }, Other, Tuple(u32, &$0u32)}",
187 "enum Foo<'a> { Bar { a: i32 }, Other, Tuple(u32, &'a u32)}",
188 );
189
190 check_assist(
191 add_lifetime_to_type,
192 "enum Foo { Bar { a: &$0i32 }}",
193 "enum Foo<'a> { Bar { a: &'a i32 }}",
194 );
195
196 check_assist(
197 add_lifetime_to_type,
198 "enum Foo<T> { Bar { a: &$0i32, b: &T }}",
199 "enum Foo<'a, T> { Bar { a: &'a i32, b: &'a T }}",
200 );
201
202 check_assist_not_applicable(add_lifetime_to_type, "enum Foo<'a> { Bar { a: &$0'a i32 }}");
203 check_assist_not_applicable(add_lifetime_to_type, "enum Foo { Bar, $0Misc }");
204 }
205
206 #[test]
207 fn add_lifetime_to_union() {
208 check_assist(
209 add_lifetime_to_type,
210 "union Foo { a: &$0i32 }",
211 "union Foo<'a> { a: &'a i32 }",
212 );
213
214 check_assist(
215 add_lifetime_to_type,
216 "union Foo { a: &$0i32, b: &usize }",
217 "union Foo<'a> { a: &'a i32, b: &'a usize }",
218 );
219
220 check_assist(
221 add_lifetime_to_type,
222 "union Foo<T> { a: &$0T, b: usize }",
223 "union Foo<'a, T> { a: &'a T, b: usize }",
224 );
225
226 check_assist_not_applicable(add_lifetime_to_type, "struct Foo<'a> { a: &'a $0i32 }");
227 }
228}
diff --git a/crates/assists/src/lib.rs b/crates/assists/src/lib.rs
index 14178a651..559b9651e 100644
--- a/crates/assists/src/lib.rs
+++ b/crates/assists/src/lib.rs
@@ -108,6 +108,7 @@ mod handlers {
108 pub(crate) type Handler = fn(&mut Assists, &AssistContext) -> Option<()>; 108 pub(crate) type Handler = fn(&mut Assists, &AssistContext) -> Option<()>;
109 109
110 mod add_explicit_type; 110 mod add_explicit_type;
111 mod add_lifetime_to_type;
111 mod add_missing_impl_members; 112 mod add_missing_impl_members;
112 mod add_turbo_fish; 113 mod add_turbo_fish;
113 mod apply_demorgan; 114 mod apply_demorgan;
@@ -164,6 +165,7 @@ mod handlers {
164 &[ 165 &[
165 // These are alphabetic for the foolish consistency 166 // These are alphabetic for the foolish consistency
166 add_explicit_type::add_explicit_type, 167 add_explicit_type::add_explicit_type,
168 add_lifetime_to_type::add_lifetime_to_type,
167 add_turbo_fish::add_turbo_fish, 169 add_turbo_fish::add_turbo_fish,
168 apply_demorgan::apply_demorgan, 170 apply_demorgan::apply_demorgan,
169 auto_import::auto_import, 171 auto_import::auto_import,
diff --git a/crates/assists/src/tests/generated.rs b/crates/assists/src/tests/generated.rs
index d48d063b4..9aa807f10 100644
--- a/crates/assists/src/tests/generated.rs
+++ b/crates/assists/src/tests/generated.rs
@@ -104,6 +104,25 @@ impl Trait<u32> for () {
104} 104}
105 105
106#[test] 106#[test]
107fn doctest_add_lifetime_to_type() {
108 check_doc_test(
109 "add_lifetime_to_type",
110 r#####"
111struct Point {
112 x: &$0u32,
113 y: u32,
114}
115"#####,
116 r#####"
117struct Point<'a> {
118 x: &'a u32,
119 y: u32,
120}
121"#####,
122 )
123}
124
125#[test]
107fn doctest_add_turbo_fish() { 126fn doctest_add_turbo_fish() {
108 check_doc_test( 127 check_doc_test(
109 "add_turbo_fish", 128 "add_turbo_fish",
diff --git a/crates/completion/src/completions/dot.rs b/crates/completion/src/completions/dot.rs
index d04eef65a..0880a3830 100644
--- a/crates/completion/src/completions/dot.rs
+++ b/crates/completion/src/completions/dot.rs
@@ -83,7 +83,7 @@ fn foo(s: S) { s.$0 }
83"#, 83"#,
84 expect![[r#" 84 expect![[r#"
85 fd foo u32 85 fd foo u32
86 me bar() fn bar(&self) 86 me bar() -> ()
87 "#]], 87 "#]],
88 ); 88 );
89 } 89 }
@@ -99,7 +99,7 @@ impl S {
99"#, 99"#,
100 expect![[r#" 100 expect![[r#"
101 fd the_field (u32,) 101 fd the_field (u32,)
102 me foo() fn foo(self) 102 me foo() -> ()
103 "#]], 103 "#]],
104 ) 104 )
105 } 105 }
@@ -115,7 +115,7 @@ impl A {
115"#, 115"#,
116 expect![[r#" 116 expect![[r#"
117 fd the_field (u32, i32) 117 fd the_field (u32, i32)
118 me foo() fn foo(&self) 118 me foo() -> ()
119 "#]], 119 "#]],
120 ) 120 )
121 } 121 }
@@ -165,7 +165,7 @@ mod m {
165fn foo(a: A) { a.$0 } 165fn foo(a: A) { a.$0 }
166"#, 166"#,
167 expect![[r#" 167 expect![[r#"
168 me the_method() pub(crate) fn the_method(&self) 168 me the_method() -> ()
169 "#]], 169 "#]],
170 ); 170 );
171 } 171 }
@@ -198,7 +198,7 @@ impl A<i32> {
198fn foo(a: A<u32>) { a.$0 } 198fn foo(a: A<u32>) { a.$0 }
199"#, 199"#,
200 expect![[r#" 200 expect![[r#"
201 me the_method() fn the_method(&self) 201 me the_method() -> ()
202 "#]], 202 "#]],
203 ) 203 )
204 } 204 }
@@ -213,7 +213,7 @@ impl Trait for A {}
213fn foo(a: A) { a.$0 } 213fn foo(a: A) { a.$0 }
214"#, 214"#,
215 expect![[r#" 215 expect![[r#"
216 me the_method() fn the_method(&self) 216 me the_method() -> ()
217 "#]], 217 "#]],
218 ); 218 );
219 } 219 }
@@ -228,7 +228,7 @@ impl<T> Trait for T {}
228fn foo(a: &A) { a.$0 } 228fn foo(a: &A) { a.$0 }
229", 229",
230 expect![[r#" 230 expect![[r#"
231 me the_method() fn the_method(&self) 231 me the_method() -> ()
232 "#]], 232 "#]],
233 ); 233 );
234 } 234 }
@@ -246,7 +246,7 @@ impl Trait for A {}
246fn foo(a: A) { a.$0 } 246fn foo(a: A) { a.$0 }
247", 247",
248 expect![[r#" 248 expect![[r#"
249 me the_method() fn the_method(&self) 249 me the_method() -> ()
250 "#]], 250 "#]],
251 ); 251 );
252 } 252 }
@@ -300,7 +300,7 @@ impl T {
300} 300}
301"#, 301"#,
302 expect![[r#" 302 expect![[r#"
303 me blah() pub fn blah(&self) 303 me blah() -> ()
304 "#]], 304 "#]],
305 ); 305 );
306 } 306 }
@@ -409,7 +409,7 @@ fn foo() {
409} 409}
410"#, 410"#,
411 expect![[r#" 411 expect![[r#"
412 me the_method() pub fn the_method(&self) 412 me the_method() -> ()
413 "#]], 413 "#]],
414 ); 414 );
415 } 415 }
@@ -424,7 +424,7 @@ macro_rules! make_s { () => { S }; }
424fn main() { make_s!().f$0; } 424fn main() { make_s!().f$0; }
425"#, 425"#,
426 expect![[r#" 426 expect![[r#"
427 me foo() fn foo(&self) 427 me foo() -> ()
428 "#]], 428 "#]],
429 ) 429 )
430 } 430 }
diff --git a/crates/completion/src/completions/flyimport.rs b/crates/completion/src/completions/flyimport.rs
index dc0b38a16..6591127b1 100644
--- a/crates/completion/src/completions/flyimport.rs
+++ b/crates/completion/src/completions/flyimport.rs
@@ -366,8 +366,8 @@ fn main() {
366 check( 366 check(
367 fixture, 367 fixture,
368 expect![[r#" 368 expect![[r#"
369 fn weird_function() (dep::test_mod::TestTrait) fn weird_function() 369 fn weird_function() (dep::test_mod::TestTrait) -> ()
370 "#]], 370 "#]],
371 ); 371 );
372 372
373 check_edit( 373 check_edit(
@@ -459,8 +459,8 @@ fn main() {
459 check( 459 check(
460 fixture, 460 fixture,
461 expect![[r#" 461 expect![[r#"
462 me random_method() (dep::test_mod::TestTrait) fn random_method(&self) 462 me random_method() (dep::test_mod::TestTrait) -> ()
463 "#]], 463 "#]],
464 ); 464 );
465 465
466 check_edit( 466 check_edit(
@@ -629,8 +629,8 @@ fn main() {
629} 629}
630 "#, 630 "#,
631 expect![[r#" 631 expect![[r#"
632 me random_method() (dep::test_mod::TestTrait) fn random_method(&self) DEPRECATED 632 me random_method() (dep::test_mod::TestTrait) -> () DEPRECATED
633 "#]], 633 "#]],
634 ); 634 );
635 635
636 check( 636 check(
@@ -660,8 +660,8 @@ fn main() {
660"#, 660"#,
661 expect![[r#" 661 expect![[r#"
662 ct SPECIAL_CONST (dep::test_mod::TestTrait) DEPRECATED 662 ct SPECIAL_CONST (dep::test_mod::TestTrait) DEPRECATED
663 fn weird_function() (dep::test_mod::TestTrait) fn weird_function() DEPRECATED 663 fn weird_function() (dep::test_mod::TestTrait) -> () DEPRECATED
664 "#]], 664 "#]],
665 ); 665 );
666 } 666 }
667} 667}
diff --git a/crates/completion/src/completions/fn_param.rs b/crates/completion/src/completions/fn_param.rs
index 5505c3559..38e33a93e 100644
--- a/crates/completion/src/completions/fn_param.rs
+++ b/crates/completion/src/completions/fn_param.rs
@@ -6,7 +6,7 @@ use syntax::{
6 match_ast, AstNode, 6 match_ast, AstNode,
7}; 7};
8 8
9use crate::{CompletionContext, CompletionItem, CompletionKind, Completions}; 9use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions};
10 10
11/// Complete repeated parameters, both name and type. For example, if all 11/// Complete repeated parameters, both name and type. For example, if all
12/// functions in a file have a `spam: &mut Spam` parameter, a completion with 12/// functions in a file have a `spam: &mut Spam` parameter, a completion with
@@ -58,7 +58,7 @@ pub(crate) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext)
58 }) 58 })
59 .for_each(|(label, lookup)| { 59 .for_each(|(label, lookup)| {
60 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label) 60 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label)
61 .kind(crate::CompletionItemKind::Binding) 61 .kind(CompletionItemKind::Binding)
62 .lookup_by(lookup) 62 .lookup_by(lookup)
63 .add_to(acc) 63 .add_to(acc)
64 }); 64 });
diff --git a/crates/completion/src/completions/mod_.rs b/crates/completion/src/completions/mod_.rs
index 00e951ca9..352fc7c77 100644
--- a/crates/completion/src/completions/mod_.rs
+++ b/crates/completion/src/completions/mod_.rs
@@ -3,11 +3,13 @@
3use std::iter; 3use std::iter;
4 4
5use hir::{Module, ModuleSource}; 5use hir::{Module, ModuleSource};
6use ide_db::base_db::{SourceDatabaseExt, VfsPath}; 6use ide_db::{
7use ide_db::RootDatabase; 7 base_db::{SourceDatabaseExt, VfsPath},
8 RootDatabase, SymbolKind,
9};
8use rustc_hash::FxHashSet; 10use rustc_hash::FxHashSet;
9 11
10use crate::{CompletionItem, CompletionItemKind}; 12use crate::CompletionItem;
11 13
12use crate::{context::CompletionContext, item::CompletionKind, Completions}; 14use crate::{context::CompletionContext, item::CompletionKind, Completions};
13 15
@@ -79,7 +81,7 @@ pub(crate) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Op
79 label.push(';'); 81 label.push(';');
80 } 82 }
81 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), &label) 83 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), &label)
82 .kind(CompletionItemKind::Module) 84 .kind(SymbolKind::Module)
83 .add_to(acc) 85 .add_to(acc)
84 }); 86 });
85 87
diff --git a/crates/completion/src/completions/qualified_path.rs b/crates/completion/src/completions/qualified_path.rs
index 33df26761..bbeaab496 100644
--- a/crates/completion/src/completions/qualified_path.rs
+++ b/crates/completion/src/completions/qualified_path.rs
@@ -359,8 +359,8 @@ impl S {
359fn foo() { let _ = S::$0 } 359fn foo() { let _ = S::$0 }
360"#, 360"#,
361 expect![[r#" 361 expect![[r#"
362 fn a() fn a() 362 fn a() -> ()
363 me b(…) fn b(&self) 363 me b(…) -> ()
364 ct C const C: i32 = 42; 364 ct C const C: i32 = 42;
365 ta T type T = i32; 365 ta T type T = i32;
366 "#]], 366 "#]],
@@ -387,7 +387,7 @@ mod m {
387fn foo() { let _ = S::$0 } 387fn foo() { let _ = S::$0 }
388"#, 388"#,
389 expect![[r#" 389 expect![[r#"
390 fn public_method() pub(crate) fn public_method() 390 fn public_method() -> ()
391 ct PUBLIC_CONST pub(crate) const PUBLIC_CONST: u32 = 1; 391 ct PUBLIC_CONST pub(crate) const PUBLIC_CONST: u32 = 1;
392 ta PublicType pub(crate) type PublicType = u32; 392 ta PublicType pub(crate) type PublicType = u32;
393 "#]], 393 "#]],
@@ -404,7 +404,7 @@ impl E { fn m() { } }
404fn foo() { let _ = E::$0 } 404fn foo() { let _ = E::$0 }
405 "#, 405 "#,
406 expect![[r#" 406 expect![[r#"
407 fn m() fn m() 407 fn m() -> ()
408 "#]], 408 "#]],
409 ); 409 );
410 } 410 }
@@ -419,7 +419,7 @@ impl U { fn m() { } }
419fn foo() { let _ = U::$0 } 419fn foo() { let _ = U::$0 }
420"#, 420"#,
421 expect![[r#" 421 expect![[r#"
422 fn m() fn m() 422 fn m() -> ()
423 "#]], 423 "#]],
424 ); 424 );
425 } 425 }
@@ -449,7 +449,7 @@ trait Trait { fn m(); }
449fn foo() { let _ = Trait::$0 } 449fn foo() { let _ = Trait::$0 }
450"#, 450"#,
451 expect![[r#" 451 expect![[r#"
452 fn m() fn m() 452 fn m() -> ()
453 "#]], 453 "#]],
454 ); 454 );
455 } 455 }
@@ -466,7 +466,7 @@ impl Trait for S {}
466fn foo() { let _ = S::$0 } 466fn foo() { let _ = S::$0 }
467"#, 467"#,
468 expect![[r#" 468 expect![[r#"
469 fn m() fn m() 469 fn m() -> ()
470 "#]], 470 "#]],
471 ); 471 );
472 } 472 }
@@ -483,7 +483,7 @@ impl Trait for S {}
483fn foo() { let _ = <S as Trait>::$0 } 483fn foo() { let _ = <S as Trait>::$0 }
484"#, 484"#,
485 expect![[r#" 485 expect![[r#"
486 fn m() fn m() 486 fn m() -> ()
487 "#]], 487 "#]],
488 ); 488 );
489 } 489 }
@@ -512,11 +512,11 @@ fn foo<T: Sub>() { T::$0 }
512 ta SubTy type SubTy; 512 ta SubTy type SubTy;
513 ta Ty type Ty; 513 ta Ty type Ty;
514 ct C2 const C2: (); 514 ct C2 const C2: ();
515 fn subfunc() fn subfunc() 515 fn subfunc() -> ()
516 me submethod(…) fn submethod(&self) 516 me submethod(…) -> ()
517 ct CONST const CONST: u8; 517 ct CONST const CONST: u8;
518 fn func() fn func() 518 fn func() -> ()
519 me method(…) fn method(&self) 519 me method(…) -> ()
520 "#]], 520 "#]],
521 ); 521 );
522 } 522 }
@@ -552,11 +552,11 @@ impl<T> Sub for Wrap<T> {
552 ta SubTy type SubTy; 552 ta SubTy type SubTy;
553 ta Ty type Ty; 553 ta Ty type Ty;
554 ct CONST const CONST: u8 = 0; 554 ct CONST const CONST: u8 = 0;
555 fn func() fn func() 555 fn func() -> ()
556 me method(…) fn method(&self) 556 me method(…) -> ()
557 ct C2 const C2: () = (); 557 ct C2 const C2: () = ();
558 fn subfunc() fn subfunc() 558 fn subfunc() -> ()
559 me submethod(…) fn submethod(&self) 559 me submethod(…) -> ()
560 "#]], 560 "#]],
561 ); 561 );
562 } 562 }
@@ -573,8 +573,8 @@ impl T { fn bar() {} }
573fn main() { T::$0; } 573fn main() { T::$0; }
574"#, 574"#,
575 expect![[r#" 575 expect![[r#"
576 fn foo() fn foo() 576 fn foo() -> ()
577 fn bar() fn bar() 577 fn bar() -> ()
578 "#]], 578 "#]],
579 ); 579 );
580 } 580 }
@@ -589,7 +589,7 @@ macro_rules! foo { () => {} }
589fn main() { let _ = crate::$0 } 589fn main() { let _ = crate::$0 }
590 "#, 590 "#,
591 expect![[r##" 591 expect![[r##"
592 fn main() fn main() 592 fn main() -> ()
593 ma foo!(…) #[macro_export] macro_rules! foo 593 ma foo!(…) #[macro_export] macro_rules! foo
594 "##]], 594 "##]],
595 ); 595 );
@@ -633,7 +633,7 @@ mod p {
633"#, 633"#,
634 expect![[r#" 634 expect![[r#"
635 ct RIGHT_CONST 635 ct RIGHT_CONST
636 fn right_fn() fn wrong_fn() 636 fn right_fn() -> ()
637 st RightType 637 st RightType
638 "#]], 638 "#]],
639 ); 639 );
@@ -680,8 +680,8 @@ fn main() { m!(self::f$0); }
680fn foo() {} 680fn foo() {}
681"#, 681"#,
682 expect![[r#" 682 expect![[r#"
683 fn main() fn main() 683 fn main() -> ()
684 fn foo() fn foo() 684 fn foo() -> ()
685 "#]], 685 "#]],
686 ); 686 );
687 } 687 }
@@ -699,7 +699,7 @@ mod m {
699"#, 699"#,
700 expect![[r#" 700 expect![[r#"
701 md z 701 md z
702 fn z() pub fn z() 702 fn z() -> ()
703 "#]], 703 "#]],
704 ); 704 );
705 } 705 }
@@ -719,7 +719,7 @@ fn foo() {
719} 719}
720"#, 720"#,
721 expect![[r#" 721 expect![[r#"
722 fn new() pub fn new() -> HashMap<K, V, RandomState> 722 fn new() -> HashMap<K, V, RandomState>
723 "#]], 723 "#]],
724 ); 724 );
725 } 725 }
@@ -752,8 +752,8 @@ fn main() {
752} 752}
753"#, 753"#,
754 expect![[r#" 754 expect![[r#"
755 fn main() fn main() 755 fn main() -> ()
756 fn foo(…) fn foo(a: i32, b: i32) 756 fn foo(…) -> ()
757 "#]], 757 "#]],
758 ); 758 );
759 } 759 }
@@ -776,7 +776,7 @@ impl Foo {
776 expect![[r#" 776 expect![[r#"
777 ev Bar () 777 ev Bar ()
778 ev Baz () 778 ev Baz ()
779 me foo(…) fn foo(self) 779 me foo(…) -> ()
780 "#]], 780 "#]],
781 ); 781 );
782 } 782 }
diff --git a/crates/completion/src/completions/record.rs b/crates/completion/src/completions/record.rs
index bb6354ded..0a7927eb8 100644
--- a/crates/completion/src/completions/record.rs
+++ b/crates/completion/src/completions/record.rs
@@ -1,10 +1,8 @@
1//! Complete fields in record literals and patterns. 1//! Complete fields in record literals and patterns.
2use ide_db::helpers::FamousDefs; 2use ide_db::{helpers::FamousDefs, SymbolKind};
3use syntax::ast::Expr; 3use syntax::ast::Expr;
4 4
5use crate::{ 5use crate::{item::CompletionKind, CompletionContext, CompletionItem, Completions};
6 item::CompletionKind, CompletionContext, CompletionItem, CompletionItemKind, Completions,
7};
8 6
9pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { 7pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
10 let missing_fields = match (ctx.record_pat_syntax.as_ref(), ctx.record_lit_syntax.as_ref()) { 8 let missing_fields = match (ctx.record_pat_syntax.as_ref(), ctx.record_lit_syntax.as_ref()) {
@@ -31,7 +29,7 @@ pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) ->
31 "..Default::default()", 29 "..Default::default()",
32 ) 30 )
33 .insert_text(completion_text) 31 .insert_text(completion_text)
34 .kind(CompletionItemKind::Field) 32 .kind(SymbolKind::Field)
35 .build(), 33 .build(),
36 ); 34 );
37 } 35 }
diff --git a/crates/completion/src/completions/trait_impl.rs b/crates/completion/src/completions/trait_impl.rs
index 135ae49dc..b999540b8 100644
--- a/crates/completion/src/completions/trait_impl.rs
+++ b/crates/completion/src/completions/trait_impl.rs
@@ -32,7 +32,7 @@
32//! ``` 32//! ```
33 33
34use hir::{self, HasAttrs, HasSource}; 34use hir::{self, HasAttrs, HasSource};
35use ide_db::traits::get_missing_assoc_items; 35use ide_db::{traits::get_missing_assoc_items, SymbolKind};
36use syntax::{ 36use syntax::{
37 ast::{self, edit, Impl}, 37 ast::{self, edit, Impl},
38 display::function_declaration, 38 display::function_declaration,
@@ -152,7 +152,7 @@ fn add_function_impl(
152 let completion_kind = if func.self_param(ctx.db).is_some() { 152 let completion_kind = if func.self_param(ctx.db).is_some() {
153 CompletionItemKind::Method 153 CompletionItemKind::Method
154 } else { 154 } else {
155 CompletionItemKind::Function 155 CompletionItemKind::SymbolKind(SymbolKind::Function)
156 }; 156 };
157 let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end()); 157 let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end());
158 158
@@ -188,7 +188,7 @@ fn add_type_alias_impl(
188 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()) 188 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
189 .text_edit(TextEdit::replace(range, snippet)) 189 .text_edit(TextEdit::replace(range, snippet))
190 .lookup_by(alias_name) 190 .lookup_by(alias_name)
191 .kind(CompletionItemKind::TypeAlias) 191 .kind(SymbolKind::TypeAlias)
192 .set_documentation(type_alias.docs(ctx.db)) 192 .set_documentation(type_alias.docs(ctx.db))
193 .add_to(acc); 193 .add_to(acc);
194} 194}
@@ -211,7 +211,7 @@ fn add_const_impl(
211 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()) 211 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
212 .text_edit(TextEdit::replace(range, snippet)) 212 .text_edit(TextEdit::replace(range, snippet))
213 .lookup_by(const_name) 213 .lookup_by(const_name)
214 .kind(CompletionItemKind::Const) 214 .kind(SymbolKind::Const)
215 .set_documentation(const_.docs(ctx.db)) 215 .set_documentation(const_.docs(ctx.db))
216 .add_to(acc); 216 .add_to(acc);
217 } 217 }
@@ -679,11 +679,6 @@ impl Test for () {
679 #[test] 679 #[test]
680 fn complete_without_name() { 680 fn complete_without_name() {
681 let test = |completion: &str, hint: &str, completed: &str, next_sibling: &str| { 681 let test = |completion: &str, hint: &str, completed: &str, next_sibling: &str| {
682 println!(
683 "completion='{}', hint='{}', next_sibling='{}'",
684 completion, hint, next_sibling
685 );
686
687 check_edit( 682 check_edit(
688 completion, 683 completion,
689 &format!( 684 &format!(
diff --git a/crates/completion/src/completions/unqualified_path.rs b/crates/completion/src/completions/unqualified_path.rs
index 809e1645a..5d62fab97 100644
--- a/crates/completion/src/completions/unqualified_path.rs
+++ b/crates/completion/src/completions/unqualified_path.rs
@@ -165,9 +165,9 @@ fn quux(x: i32) {
165} 165}
166"#, 166"#,
167 expect![[r#" 167 expect![[r#"
168 bn y i32 168 lc y i32
169 bn x i32 169 lc x i32
170 fn quux(…) fn quux(x: i32) 170 fn quux(…) -> ()
171 "#]], 171 "#]],
172 ); 172 );
173 } 173 }
@@ -187,9 +187,9 @@ fn quux() {
187} 187}
188"#, 188"#,
189 expect![[r#" 189 expect![[r#"
190 bn b i32 190 lc b i32
191 bn a 191 lc a
192 fn quux() fn quux() 192 fn quux() -> ()
193 "#]], 193 "#]],
194 ); 194 );
195 } 195 }
@@ -203,8 +203,8 @@ fn quux() {
203} 203}
204"#, 204"#,
205 expect![[r#" 205 expect![[r#"
206 bn x 206 lc x
207 fn quux() fn quux() 207 fn quux() -> ()
208 "#]], 208 "#]],
209 ); 209 );
210 } 210 }
@@ -235,14 +235,14 @@ fn main() {
235 r#"fn quux<T>() { $0 }"#, 235 r#"fn quux<T>() { $0 }"#,
236 expect![[r#" 236 expect![[r#"
237 tp T 237 tp T
238 fn quux() fn quux<T>() 238 fn quux() -> ()
239 "#]], 239 "#]],
240 ); 240 );
241 check( 241 check(
242 r#"fn quux<const C: usize>() { $0 }"#, 242 r#"fn quux<const C: usize>() { $0 }"#,
243 expect![[r#" 243 expect![[r#"
244 tp C 244 cp C
245 fn quux() fn quux<const C: usize>() 245 fn quux() -> ()
246 "#]], 246 "#]],
247 ); 247 );
248 } 248 }
@@ -253,7 +253,7 @@ fn main() {
253 check( 253 check(
254 r#"fn quux<'a>() { $0 }"#, 254 r#"fn quux<'a>() { $0 }"#,
255 expect![[r#" 255 expect![[r#"
256 fn quux() fn quux<'a>() 256 fn quux() -> ()
257 "#]], 257 "#]],
258 ); 258 );
259 } 259 }
@@ -263,7 +263,7 @@ fn main() {
263 check( 263 check(
264 r#"struct S<T> { x: $0}"#, 264 r#"struct S<T> { x: $0}"#,
265 expect![[r#" 265 expect![[r#"
266 tp Self 266 sp Self
267 tp T 267 tp T
268 st S<…> 268 st S<…>
269 "#]], 269 "#]],
@@ -275,7 +275,7 @@ fn main() {
275 check( 275 check(
276 r#"enum X { Y($0) }"#, 276 r#"enum X { Y($0) }"#,
277 expect![[r#" 277 expect![[r#"
278 tp Self 278 sp Self
279 en X 279 en X
280 "#]], 280 "#]],
281 ); 281 );
@@ -291,7 +291,7 @@ fn quux() { $0 }
291"#, 291"#,
292 expect![[r#" 292 expect![[r#"
293 st S 293 st S
294 fn quux() fn quux() 294 fn quux() -> ()
295 en E 295 en E
296 "#]], 296 "#]],
297 ); 297 );
@@ -344,7 +344,7 @@ mod m {
344} 344}
345"#, 345"#,
346 expect![[r#" 346 expect![[r#"
347 fn quux() fn quux() 347 fn quux() -> ()
348 st Bar 348 st Bar
349 "#]], 349 "#]],
350 ); 350 );
@@ -359,7 +359,7 @@ fn x() -> $0
359"#, 359"#,
360 expect![[r#" 360 expect![[r#"
361 st Foo 361 st Foo
362 fn x() fn x() 362 fn x() -> ()
363 "#]], 363 "#]],
364 ); 364 );
365 } 365 }
@@ -378,9 +378,9 @@ fn foo() {
378"#, 378"#,
379 // FIXME: should be only one bar here 379 // FIXME: should be only one bar here
380 expect![[r#" 380 expect![[r#"
381 bn bar i32 381 lc bar i32
382 bn bar i32 382 lc bar i32
383 fn foo() fn foo() 383 fn foo() -> ()
384 "#]], 384 "#]],
385 ); 385 );
386 } 386 }
@@ -390,8 +390,8 @@ fn foo() {
390 check( 390 check(
391 r#"impl S { fn foo(&self) { $0 } }"#, 391 r#"impl S { fn foo(&self) { $0 } }"#,
392 expect![[r#" 392 expect![[r#"
393 bn self &{unknown} 393 lc self &{unknown}
394 tp Self 394 sp Self
395 "#]], 395 "#]],
396 ); 396 );
397 } 397 }
@@ -410,7 +410,7 @@ use prelude::*;
410mod prelude { struct Option; } 410mod prelude { struct Option; }
411"#, 411"#,
412 expect![[r#" 412 expect![[r#"
413 fn foo() fn foo() 413 fn foo() -> ()
414 md std 414 md std
415 st Option 415 st Option
416 "#]], 416 "#]],
@@ -440,7 +440,7 @@ mod macros {
440} 440}
441"#, 441"#,
442 expect![[r##" 442 expect![[r##"
443 fn f() fn f() 443 fn f() -> ()
444 ma concat!(…) #[macro_export] macro_rules! concat 444 ma concat!(…) #[macro_export] macro_rules! concat
445 md std 445 md std
446 "##]], 446 "##]],
@@ -467,7 +467,7 @@ use prelude::*;
467mod prelude { struct String; } 467mod prelude { struct String; }
468"#, 468"#,
469 expect![[r#" 469 expect![[r#"
470 fn foo() fn foo() 470 fn foo() -> ()
471 md std 471 md std
472 md core 472 md core
473 st String 473 st String
@@ -498,7 +498,7 @@ fn main() { let v = $0 }
498 expect![[r##" 498 expect![[r##"
499 md m1 499 md m1
500 ma baz!(…) #[macro_export] macro_rules! baz 500 ma baz!(…) #[macro_export] macro_rules! baz
501 fn main() fn main() 501 fn main() -> ()
502 md m2 502 md m2
503 ma bar!(…) macro_rules! bar 503 ma bar!(…) macro_rules! bar
504 ma foo!(…) macro_rules! foo 504 ma foo!(…) macro_rules! foo
@@ -514,7 +514,7 @@ macro_rules! foo { () => {} }
514fn foo() { $0 } 514fn foo() { $0 }
515"#, 515"#,
516 expect![[r#" 516 expect![[r#"
517 fn foo() fn foo() 517 fn foo() -> ()
518 ma foo!(…) macro_rules! foo 518 ma foo!(…) macro_rules! foo
519 "#]], 519 "#]],
520 ); 520 );
@@ -528,7 +528,7 @@ macro_rules! foo { () => {} }
528fn main() { let x: $0 } 528fn main() { let x: $0 }
529"#, 529"#,
530 expect![[r#" 530 expect![[r#"
531 fn main() fn main() 531 fn main() -> ()
532 ma foo!(…) macro_rules! foo 532 ma foo!(…) macro_rules! foo
533 "#]], 533 "#]],
534 ); 534 );
@@ -542,7 +542,7 @@ macro_rules! foo { () => {} }
542fn main() { $0 } 542fn main() { $0 }
543"#, 543"#,
544 expect![[r#" 544 expect![[r#"
545 fn main() fn main() 545 fn main() -> ()
546 ma foo!(…) macro_rules! foo 546 ma foo!(…) macro_rules! foo
547 "#]], 547 "#]],
548 ); 548 );
@@ -558,8 +558,8 @@ fn main() {
558} 558}
559"#, 559"#,
560 expect![[r#" 560 expect![[r#"
561 fn frobnicate() fn frobnicate() 561 fn frobnicate() -> ()
562 fn main() fn main() 562 fn main() -> ()
563 "#]], 563 "#]],
564 ); 564 );
565 } 565 }
@@ -575,9 +575,9 @@ fn quux(x: i32) {
575} 575}
576"#, 576"#,
577 expect![[r#" 577 expect![[r#"
578 bn y i32 578 lc y i32
579 bn x i32 579 lc x i32
580 fn quux(…) fn quux(x: i32) 580 fn quux(…) -> ()
581 ma m!(…) macro_rules! m 581 ma m!(…) macro_rules! m
582 "#]], 582 "#]],
583 ); 583 );
@@ -594,9 +594,9 @@ fn quux(x: i32) {
594} 594}
595", 595",
596 expect![[r#" 596 expect![[r#"
597 bn y i32 597 lc y i32
598 bn x i32 598 lc x i32
599 fn quux(…) fn quux(x: i32) 599 fn quux(…) -> ()
600 ma m!(…) macro_rules! m 600 ma m!(…) macro_rules! m
601 "#]], 601 "#]],
602 ); 602 );
@@ -613,9 +613,9 @@ fn quux(x: i32) {
613} 613}
614"#, 614"#,
615 expect![[r#" 615 expect![[r#"
616 bn y i32 616 lc y i32
617 bn x i32 617 lc x i32
618 fn quux(…) fn quux(x: i32) 618 fn quux(…) -> ()
619 ma m!(…) macro_rules! m 619 ma m!(…) macro_rules! m
620 "#]], 620 "#]],
621 ); 621 );
@@ -630,7 +630,7 @@ use spam::Quux;
630fn main() { $0 } 630fn main() { $0 }
631"#, 631"#,
632 expect![[r#" 632 expect![[r#"
633 fn main() fn main() 633 fn main() -> ()
634 ?? Quux 634 ?? Quux
635 "#]], 635 "#]],
636 ); 636 );
@@ -708,7 +708,7 @@ fn main() { let foo: Foo = Q$0 }
708 ev Foo::Baz () 708 ev Foo::Baz ()
709 ev Foo::Quux () 709 ev Foo::Quux ()
710 en Foo 710 en Foo
711 fn main() fn main() 711 fn main() -> ()
712 "#]], 712 "#]],
713 ) 713 )
714 } 714 }
@@ -723,7 +723,7 @@ fn f() -> m::E { V$0 }
723 expect![[r#" 723 expect![[r#"
724 ev m::E::V () 724 ev m::E::V ()
725 md m 725 md m
726 fn f() fn f() -> m::E 726 fn f() -> E
727 "#]], 727 "#]],
728 ) 728 )
729 } 729 }
@@ -750,7 +750,7 @@ struct MyStruct {}
750impl My$0 750impl My$0
751"#, 751"#,
752 expect![[r#" 752 expect![[r#"
753 tp Self 753 sp Self
754 tt MyTrait 754 tt MyTrait
755 st MyStruct 755 st MyStruct
756 "#]], 756 "#]],
diff --git a/crates/completion/src/item.rs b/crates/completion/src/item.rs
index 4147853e7..eeb952ec3 100644
--- a/crates/completion/src/item.rs
+++ b/crates/completion/src/item.rs
@@ -3,11 +3,14 @@
3use std::fmt; 3use std::fmt;
4 4
5use hir::{Documentation, ModPath, Mutability}; 5use hir::{Documentation, ModPath, Mutability};
6use ide_db::helpers::{ 6use ide_db::{
7 insert_use::{self, ImportScope, MergeBehavior}, 7 helpers::{
8 mod_path_to_ast, SnippetCap, 8 insert_use::{self, ImportScope, MergeBehavior},
9 mod_path_to_ast, SnippetCap,
10 },
11 SymbolKind,
9}; 12};
10use stdx::assert_never; 13use stdx::{assert_never, impl_from};
11use syntax::{algo, TextRange}; 14use syntax::{algo, TextRange};
12use text_edit::TextEdit; 15use text_edit::TextEdit;
13 16
@@ -117,49 +120,50 @@ pub enum CompletionScore {
117 120
118#[derive(Debug, Clone, Copy, PartialEq, Eq)] 121#[derive(Debug, Clone, Copy, PartialEq, Eq)]
119pub enum CompletionItemKind { 122pub enum CompletionItemKind {
120 Snippet, 123 SymbolKind(SymbolKind),
121 Keyword, 124 Attribute,
122 Module,
123 Function,
124 BuiltinType,
125 Struct,
126 Enum,
127 EnumVariant,
128 Binding, 125 Binding,
129 Field, 126 BuiltinType,
130 Static, 127 Keyword,
131 Const,
132 Trait,
133 TypeAlias,
134 Method, 128 Method,
135 TypeParam, 129 Snippet,
136 Macro,
137 Attribute,
138 UnresolvedReference, 130 UnresolvedReference,
139} 131}
140 132
133impl_from!(SymbolKind for CompletionItemKind);
134
141impl CompletionItemKind { 135impl CompletionItemKind {
142 #[cfg(test)] 136 #[cfg(test)]
143 pub(crate) fn tag(&self) -> &'static str { 137 pub(crate) fn tag(&self) -> &'static str {
144 match self { 138 match self {
139 CompletionItemKind::SymbolKind(kind) => match kind {
140 SymbolKind::Const => "ct",
141 SymbolKind::ConstParam => "cp",
142 SymbolKind::Enum => "en",
143 SymbolKind::Field => "fd",
144 SymbolKind::Function => "fn",
145 SymbolKind::Impl => "im",
146 SymbolKind::Label => "lb",
147 SymbolKind::LifetimeParam => "lt",
148 SymbolKind::Local => "lc",
149 SymbolKind::Macro => "ma",
150 SymbolKind::Module => "md",
151 SymbolKind::SelfParam => "sp",
152 SymbolKind::Static => "sc",
153 SymbolKind::Struct => "st",
154 SymbolKind::Trait => "tt",
155 SymbolKind::TypeAlias => "ta",
156 SymbolKind::TypeParam => "tp",
157 SymbolKind::Union => "un",
158 SymbolKind::ValueParam => "vp",
159 SymbolKind::Variant => "ev",
160 },
145 CompletionItemKind::Attribute => "at", 161 CompletionItemKind::Attribute => "at",
146 CompletionItemKind::Binding => "bn", 162 CompletionItemKind::Binding => "bn",
147 CompletionItemKind::BuiltinType => "bt", 163 CompletionItemKind::BuiltinType => "bt",
148 CompletionItemKind::Const => "ct",
149 CompletionItemKind::Enum => "en",
150 CompletionItemKind::EnumVariant => "ev",
151 CompletionItemKind::Field => "fd",
152 CompletionItemKind::Function => "fn",
153 CompletionItemKind::Keyword => "kw", 164 CompletionItemKind::Keyword => "kw",
154 CompletionItemKind::Macro => "ma",
155 CompletionItemKind::Method => "me", 165 CompletionItemKind::Method => "me",
156 CompletionItemKind::Module => "md",
157 CompletionItemKind::Snippet => "sn", 166 CompletionItemKind::Snippet => "sn",
158 CompletionItemKind::Static => "sc",
159 CompletionItemKind::Struct => "st",
160 CompletionItemKind::Trait => "tt",
161 CompletionItemKind::TypeAlias => "ta",
162 CompletionItemKind::TypeParam => "tp",
163 CompletionItemKind::UnresolvedReference => "??", 167 CompletionItemKind::UnresolvedReference => "??",
164 } 168 }
165 } 169 }
@@ -382,8 +386,8 @@ impl Builder {
382 self.insert_text_format = InsertTextFormat::Snippet; 386 self.insert_text_format = InsertTextFormat::Snippet;
383 self.insert_text(snippet) 387 self.insert_text(snippet)
384 } 388 }
385 pub(crate) fn kind(mut self, kind: CompletionItemKind) -> Builder { 389 pub(crate) fn kind(mut self, kind: impl Into<CompletionItemKind>) -> Builder {
386 self.kind = Some(kind); 390 self.kind = Some(kind.into());
387 self 391 self
388 } 392 }
389 pub(crate) fn text_edit(mut self, edit: TextEdit) -> Builder { 393 pub(crate) fn text_edit(mut self, edit: TextEdit) -> Builder {
@@ -394,14 +398,13 @@ impl Builder {
394 self.insert_text_format = InsertTextFormat::Snippet; 398 self.insert_text_format = InsertTextFormat::Snippet;
395 self.text_edit(edit) 399 self.text_edit(edit)
396 } 400 }
397 #[allow(unused)]
398 pub(crate) fn detail(self, detail: impl Into<String>) -> Builder { 401 pub(crate) fn detail(self, detail: impl Into<String>) -> Builder {
399 self.set_detail(Some(detail)) 402 self.set_detail(Some(detail))
400 } 403 }
401 pub(crate) fn set_detail(mut self, detail: Option<impl Into<String>>) -> Builder { 404 pub(crate) fn set_detail(mut self, detail: Option<impl Into<String>>) -> Builder {
402 self.detail = detail.map(Into::into); 405 self.detail = detail.map(Into::into);
403 if let Some(detail) = &self.detail { 406 if let Some(detail) = &self.detail {
404 if assert_never!(detail.contains('\n'), "multiline detail: {}", detail) { 407 if assert_never!(detail.contains('\n'), "multiline detail:\n{}", detail) {
405 self.detail = Some(detail.splitn(2, '\n').next().unwrap().to_string()); 408 self.detail = Some(detail.splitn(2, '\n').next().unwrap().to_string());
406 } 409 }
407 } 410 }
diff --git a/crates/completion/src/lib.rs b/crates/completion/src/lib.rs
index 2c4e54524..db8bfbbc3 100644
--- a/crates/completion/src/lib.rs
+++ b/crates/completion/src/lib.rs
@@ -209,25 +209,24 @@ mod tests {
209 fn test_completion_detail_from_macro_generated_struct_fn_doc_attr() { 209 fn test_completion_detail_from_macro_generated_struct_fn_doc_attr() {
210 check_detail_and_documentation( 210 check_detail_and_documentation(
211 r#" 211 r#"
212 //- /lib.rs 212macro_rules! bar {
213 macro_rules! bar { 213 () => {
214 () => { 214 struct Bar;
215 struct Bar; 215 impl Bar {
216 impl Bar { 216 #[doc = "Do the foo"]
217 #[doc = "Do the foo"] 217 fn foo(&self) {}
218 fn foo(&self) {} 218 }
219 } 219 }
220 } 220}
221 }
222 221
223 bar!(); 222bar!();
224 223
225 fn foo() { 224fn foo() {
226 let bar = Bar; 225 let bar = Bar;
227 bar.fo$0; 226 bar.fo$0;
228 } 227}
229 "#, 228"#,
230 DetailAndDocumentation { detail: "fn foo(&self)", documentation: "Do the foo" }, 229 DetailAndDocumentation { detail: "-> ()", documentation: "Do the foo" },
231 ); 230 );
232 } 231 }
233 232
@@ -235,52 +234,42 @@ mod tests {
235 fn test_completion_detail_from_macro_generated_struct_fn_doc_comment() { 234 fn test_completion_detail_from_macro_generated_struct_fn_doc_comment() {
236 check_detail_and_documentation( 235 check_detail_and_documentation(
237 r#" 236 r#"
238 //- /lib.rs 237macro_rules! bar {
239 macro_rules! bar { 238 () => {
240 () => { 239 struct Bar;
241 struct Bar; 240 impl Bar {
242 impl Bar { 241 /// Do the foo
243 /// Do the foo 242 fn foo(&self) {}
244 fn foo(&self) {} 243 }
245 } 244 }
246 } 245}
247 }
248 246
249 bar!(); 247bar!();
250 248
251 fn foo() { 249fn foo() {
252 let bar = Bar; 250 let bar = Bar;
253 bar.fo$0; 251 bar.fo$0;
254 } 252}
255 "#, 253"#,
256 DetailAndDocumentation { detail: "fn foo(&self)", documentation: " Do the foo" }, 254 DetailAndDocumentation { detail: "-> ()", documentation: " Do the foo" },
257 ); 255 );
258 } 256 }
259 257
260 #[test] 258 #[test]
261 fn test_no_completions_required() { 259 fn test_no_completions_required() {
262 // There must be no hint for 'in' keyword. 260 // There must be no hint for 'in' keyword.
263 check_no_completion( 261 check_no_completion(r#"fn foo() { for i i$0 }"#);
264 r#"
265 fn foo() {
266 for i i$0
267 }
268 "#,
269 );
270 // After 'in' keyword hints may be spawned. 262 // After 'in' keyword hints may be spawned.
271 check_detail_and_documentation( 263 check_detail_and_documentation(
272 r#" 264 r#"
273 /// Do the foo 265/// Do the foo
274 fn foo() -> &'static str { "foo" } 266fn foo() -> &'static str { "foo" }
275 267
276 fn bar() { 268fn bar() {
277 for c in fo$0 269 for c in fo$0
278 } 270}
279 "#, 271"#,
280 DetailAndDocumentation { 272 DetailAndDocumentation { detail: "-> &str", documentation: "Do the foo" },
281 detail: "fn foo() -> &'static str",
282 documentation: "Do the foo",
283 },
284 ); 273 );
285 } 274 }
286} 275}
diff --git a/crates/completion/src/render.rs b/crates/completion/src/render.rs
index 4f622d28a..6eb20df2b 100644
--- a/crates/completion/src/render.rs
+++ b/crates/completion/src/render.rs
@@ -13,7 +13,7 @@ mod builder_ext;
13use hir::{ 13use hir::{
14 AsAssocItem, Documentation, HasAttrs, HirDisplay, ModuleDef, Mutability, ScopeDef, Type, 14 AsAssocItem, Documentation, HasAttrs, HirDisplay, ModuleDef, Mutability, ScopeDef, Type,
15}; 15};
16use ide_db::{helpers::SnippetCap, RootDatabase}; 16use ide_db::{helpers::SnippetCap, RootDatabase, SymbolKind};
17use syntax::TextRange; 17use syntax::TextRange;
18use test_utils::mark; 18use test_utils::mark;
19 19
@@ -146,7 +146,7 @@ impl<'a> Render<'a> {
146 self.ctx.source_range(), 146 self.ctx.source_range(),
147 name.to_string(), 147 name.to_string(),
148 ) 148 )
149 .kind(CompletionItemKind::Field) 149 .kind(SymbolKind::Field)
150 .detail(ty.display(self.ctx.db()).to_string()) 150 .detail(ty.display(self.ctx.db()).to_string())
151 .set_documentation(field.docs(self.ctx.db())) 151 .set_documentation(field.docs(self.ctx.db()))
152 .set_deprecated(is_deprecated); 152 .set_deprecated(is_deprecated);
@@ -160,7 +160,7 @@ impl<'a> Render<'a> {
160 160
161 fn add_tuple_field(&mut self, field: usize, ty: &Type) -> CompletionItem { 161 fn add_tuple_field(&mut self, field: usize, ty: &Type) -> CompletionItem {
162 CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), field.to_string()) 162 CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), field.to_string())
163 .kind(CompletionItemKind::Field) 163 .kind(SymbolKind::Field)
164 .detail(ty.display(self.ctx.db()).to_string()) 164 .detail(ty.display(self.ctx.db()).to_string())
165 .build() 165 .build()
166 } 166 }
@@ -187,7 +187,7 @@ impl<'a> Render<'a> {
187 if self.ctx.completion.is_pat_binding_or_const 187 if self.ctx.completion.is_pat_binding_or_const
188 | self.ctx.completion.is_irrefutable_pat_binding => 188 | self.ctx.completion.is_irrefutable_pat_binding =>
189 { 189 {
190 CompletionItemKind::EnumVariant 190 CompletionItemKind::SymbolKind(SymbolKind::Variant)
191 } 191 }
192 ScopeDef::ModuleDef(Variant(var)) => { 192 ScopeDef::ModuleDef(Variant(var)) => {
193 let item = render_variant(self.ctx, import_to_add, Some(local_name), *var, None); 193 let item = render_variant(self.ctx, import_to_add, Some(local_name), *var, None);
@@ -198,20 +198,29 @@ impl<'a> Render<'a> {
198 return item; 198 return item;
199 } 199 }
200 200
201 ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::Module, 201 ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::SymbolKind(SymbolKind::Module),
202 ScopeDef::ModuleDef(Adt(hir::Adt::Struct(_))) => CompletionItemKind::Struct, 202 ScopeDef::ModuleDef(Adt(adt)) => CompletionItemKind::SymbolKind(match adt {
203 // FIXME: add CompletionItemKind::Union 203 hir::Adt::Struct(_) => SymbolKind::Struct,
204 ScopeDef::ModuleDef(Adt(hir::Adt::Union(_))) => CompletionItemKind::Struct, 204 // FIXME: add CompletionItemKind::Union
205 ScopeDef::ModuleDef(Adt(hir::Adt::Enum(_))) => CompletionItemKind::Enum, 205 hir::Adt::Union(_) => SymbolKind::Struct,
206 ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::Const, 206 hir::Adt::Enum(_) => SymbolKind::Enum,
207 ScopeDef::ModuleDef(Static(..)) => CompletionItemKind::Static, 207 }),
208 ScopeDef::ModuleDef(Trait(..)) => CompletionItemKind::Trait, 208 ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::SymbolKind(SymbolKind::Const),
209 ScopeDef::ModuleDef(TypeAlias(..)) => CompletionItemKind::TypeAlias, 209 ScopeDef::ModuleDef(Static(..)) => CompletionItemKind::SymbolKind(SymbolKind::Static),
210 ScopeDef::ModuleDef(Trait(..)) => CompletionItemKind::SymbolKind(SymbolKind::Trait),
211 ScopeDef::ModuleDef(TypeAlias(..)) => {
212 CompletionItemKind::SymbolKind(SymbolKind::TypeAlias)
213 }
210 ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType, 214 ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType,
211 ScopeDef::GenericParam(..) => CompletionItemKind::TypeParam, 215 ScopeDef::GenericParam(param) => CompletionItemKind::SymbolKind(match param {
212 ScopeDef::Local(..) => CompletionItemKind::Binding, 216 hir::GenericParam::TypeParam(_) => SymbolKind::TypeParam,
213 // (does this need its own kind?) 217 hir::GenericParam::LifetimeParam(_) => SymbolKind::LifetimeParam,
214 ScopeDef::AdtSelfType(..) | ScopeDef::ImplSelfType(..) => CompletionItemKind::TypeParam, 218 hir::GenericParam::ConstParam(_) => SymbolKind::ConstParam,
219 }),
220 ScopeDef::Local(..) => CompletionItemKind::SymbolKind(SymbolKind::Local),
221 ScopeDef::AdtSelfType(..) | ScopeDef::ImplSelfType(..) => {
222 CompletionItemKind::SymbolKind(SymbolKind::SelfParam)
223 }
215 ScopeDef::Unknown => { 224 ScopeDef::Unknown => {
216 let item = CompletionItem::new( 225 let item = CompletionItem::new(
217 CompletionKind::Reference, 226 CompletionKind::Reference,
@@ -400,7 +409,9 @@ fn main() { Foo::Fo$0 }
400 source_range: 54..56, 409 source_range: 54..56,
401 delete: 54..56, 410 delete: 54..56,
402 insert: "Foo", 411 insert: "Foo",
403 kind: EnumVariant, 412 kind: SymbolKind(
413 Variant,
414 ),
404 detail: "{ x: i32, y: i32 }", 415 detail: "{ x: i32, y: i32 }",
405 }, 416 },
406 ] 417 ]
@@ -423,7 +434,9 @@ fn main() { Foo::Fo$0 }
423 source_range: 46..48, 434 source_range: 46..48,
424 delete: 46..48, 435 delete: 46..48,
425 insert: "Foo($0)", 436 insert: "Foo($0)",
426 kind: EnumVariant, 437 kind: SymbolKind(
438 Variant,
439 ),
427 lookup: "Foo", 440 lookup: "Foo",
428 detail: "(i32, i32)", 441 detail: "(i32, i32)",
429 trigger_call_info: true, 442 trigger_call_info: true,
@@ -448,7 +461,9 @@ fn main() { Foo::Fo$0 }
448 source_range: 35..37, 461 source_range: 35..37,
449 delete: 35..37, 462 delete: 35..37,
450 insert: "Foo", 463 insert: "Foo",
451 kind: EnumVariant, 464 kind: SymbolKind(
465 Variant,
466 ),
452 detail: "()", 467 detail: "()",
453 }, 468 },
454 ] 469 ]
@@ -472,7 +487,9 @@ fn main() { let _: m::Spam = S$0 }
472 source_range: 75..76, 487 source_range: 75..76,
473 delete: 75..76, 488 delete: 75..76,
474 insert: "Spam::Bar($0)", 489 insert: "Spam::Bar($0)",
475 kind: EnumVariant, 490 kind: SymbolKind(
491 Variant,
492 ),
476 lookup: "Spam::Bar", 493 lookup: "Spam::Bar",
477 detail: "(i32)", 494 detail: "(i32)",
478 trigger_call_info: true, 495 trigger_call_info: true,
@@ -482,14 +499,18 @@ fn main() { let _: m::Spam = S$0 }
482 source_range: 75..76, 499 source_range: 75..76,
483 delete: 75..76, 500 delete: 75..76,
484 insert: "m", 501 insert: "m",
485 kind: Module, 502 kind: SymbolKind(
503 Module,
504 ),
486 }, 505 },
487 CompletionItem { 506 CompletionItem {
488 label: "m::Spam::Foo", 507 label: "m::Spam::Foo",
489 source_range: 75..76, 508 source_range: 75..76,
490 delete: 75..76, 509 delete: 75..76,
491 insert: "m::Spam::Foo", 510 insert: "m::Spam::Foo",
492 kind: EnumVariant, 511 kind: SymbolKind(
512 Variant,
513 ),
493 lookup: "Spam::Foo", 514 lookup: "Spam::Foo",
494 detail: "()", 515 detail: "()",
495 }, 516 },
@@ -498,9 +519,11 @@ fn main() { let _: m::Spam = S$0 }
498 source_range: 75..76, 519 source_range: 75..76,
499 delete: 75..76, 520 delete: 75..76,
500 insert: "main()$0", 521 insert: "main()$0",
501 kind: Function, 522 kind: SymbolKind(
523 Function,
524 ),
502 lookup: "main", 525 lookup: "main",
503 detail: "fn main()", 526 detail: "-> ()",
504 }, 527 },
505 ] 528 ]
506 "#]], 529 "#]],
@@ -525,18 +548,22 @@ fn main() { som$0 }
525 source_range: 127..130, 548 source_range: 127..130,
526 delete: 127..130, 549 delete: 127..130,
527 insert: "main()$0", 550 insert: "main()$0",
528 kind: Function, 551 kind: SymbolKind(
552 Function,
553 ),
529 lookup: "main", 554 lookup: "main",
530 detail: "fn main()", 555 detail: "-> ()",
531 }, 556 },
532 CompletionItem { 557 CompletionItem {
533 label: "something_deprecated()", 558 label: "something_deprecated()",
534 source_range: 127..130, 559 source_range: 127..130,
535 delete: 127..130, 560 delete: 127..130,
536 insert: "something_deprecated()$0", 561 insert: "something_deprecated()$0",
537 kind: Function, 562 kind: SymbolKind(
563 Function,
564 ),
538 lookup: "something_deprecated", 565 lookup: "something_deprecated",
539 detail: "fn something_deprecated()", 566 detail: "-> ()",
540 deprecated: true, 567 deprecated: true,
541 }, 568 },
542 CompletionItem { 569 CompletionItem {
@@ -544,9 +571,11 @@ fn main() { som$0 }
544 source_range: 127..130, 571 source_range: 127..130,
545 delete: 127..130, 572 delete: 127..130,
546 insert: "something_else_deprecated()$0", 573 insert: "something_else_deprecated()$0",
547 kind: Function, 574 kind: SymbolKind(
575 Function,
576 ),
548 lookup: "something_else_deprecated", 577 lookup: "something_else_deprecated",
549 detail: "fn something_else_deprecated()", 578 detail: "-> ()",
550 deprecated: true, 579 deprecated: true,
551 }, 580 },
552 ] 581 ]
@@ -565,7 +594,9 @@ fn foo() { A { the$0 } }
565 source_range: 57..60, 594 source_range: 57..60,
566 delete: 57..60, 595 delete: 57..60,
567 insert: "the_field", 596 insert: "the_field",
568 kind: Field, 597 kind: SymbolKind(
598 Field,
599 ),
569 detail: "u32", 600 detail: "u32",
570 deprecated: true, 601 deprecated: true,
571 }, 602 },
@@ -595,7 +626,7 @@ impl S {
595 insert: "bar()$0", 626 insert: "bar()$0",
596 kind: Method, 627 kind: Method,
597 lookup: "bar", 628 lookup: "bar",
598 detail: "fn bar(self)", 629 detail: "-> ()",
599 documentation: Documentation( 630 documentation: Documentation(
600 "Method docs", 631 "Method docs",
601 ), 632 ),
@@ -605,7 +636,9 @@ impl S {
605 source_range: 94..94, 636 source_range: 94..94,
606 delete: 94..94, 637 delete: 94..94,
607 insert: "foo", 638 insert: "foo",
608 kind: Field, 639 kind: SymbolKind(
640 Field,
641 ),
609 detail: "{unknown}", 642 detail: "{unknown}",
610 documentation: Documentation( 643 documentation: Documentation(
611 "Field docs", 644 "Field docs",
@@ -636,7 +669,9 @@ use self::E::*;
636 source_range: 10..12, 669 source_range: 10..12,
637 delete: 10..12, 670 delete: 10..12,
638 insert: "E", 671 insert: "E",
639 kind: Enum, 672 kind: SymbolKind(
673 Enum,
674 ),
640 documentation: Documentation( 675 documentation: Documentation(
641 "enum docs", 676 "enum docs",
642 ), 677 ),
@@ -646,7 +681,9 @@ use self::E::*;
646 source_range: 10..12, 681 source_range: 10..12,
647 delete: 10..12, 682 delete: 10..12,
648 insert: "V", 683 insert: "V",
649 kind: EnumVariant, 684 kind: SymbolKind(
685 Variant,
686 ),
650 detail: "()", 687 detail: "()",
651 documentation: Documentation( 688 documentation: Documentation(
652 "variant docs", 689 "variant docs",
@@ -657,7 +694,9 @@ use self::E::*;
657 source_range: 10..12, 694 source_range: 10..12,
658 delete: 10..12, 695 delete: 10..12,
659 insert: "my", 696 insert: "my",
660 kind: Module, 697 kind: SymbolKind(
698 Module,
699 ),
661 documentation: Documentation( 700 documentation: Documentation(
662 "mod docs", 701 "mod docs",
663 ), 702 ),
@@ -687,7 +726,7 @@ fn foo(s: S) { s.$0 }
687 insert: "the_method()$0", 726 insert: "the_method()$0",
688 kind: Method, 727 kind: Method,
689 lookup: "the_method", 728 lookup: "the_method",
690 detail: "fn the_method(&self)", 729 detail: "-> ()",
691 }, 730 },
692 ] 731 ]
693 "#]], 732 "#]],
@@ -883,7 +922,7 @@ struct WorldSnapshot { _f: () };
883fn go(world: &WorldSnapshot) { go(w$0) } 922fn go(world: &WorldSnapshot) { go(w$0) }
884"#, 923"#,
885 expect![[r#" 924 expect![[r#"
886 bn world [type+name] 925 lc world [type+name]
887 st WorldSnapshot [] 926 st WorldSnapshot []
888 fn go(…) [] 927 fn go(…) []
889 "#]], 928 "#]],
@@ -900,7 +939,7 @@ fn f(foo: &Foo) { f(foo, w$0) }
900 expect![[r#" 939 expect![[r#"
901 st Foo [] 940 st Foo []
902 fn f(…) [] 941 fn f(…) []
903 bn foo [] 942 lc foo []
904 "#]], 943 "#]],
905 ); 944 );
906 } 945 }
diff --git a/crates/completion/src/render/const_.rs b/crates/completion/src/render/const_.rs
index e46452d4e..5010b642a 100644
--- a/crates/completion/src/render/const_.rs
+++ b/crates/completion/src/render/const_.rs
@@ -1,13 +1,14 @@
1//! Renderer for `const` fields. 1//! Renderer for `const` fields.
2 2
3use hir::HasSource; 3use hir::HasSource;
4use ide_db::SymbolKind;
4use syntax::{ 5use syntax::{
5 ast::{Const, NameOwner}, 6 ast::{Const, NameOwner},
6 display::const_label, 7 display::const_label,
7}; 8};
8 9
9use crate::{ 10use crate::{
10 item::{CompletionItem, CompletionItemKind, CompletionKind}, 11 item::{CompletionItem, CompletionKind},
11 render::RenderContext, 12 render::RenderContext,
12}; 13};
13 14
@@ -36,7 +37,7 @@ impl<'a> ConstRender<'a> {
36 let detail = self.detail(); 37 let detail = self.detail();
37 38
38 let item = CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), name) 39 let item = CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), name)
39 .kind(CompletionItemKind::Const) 40 .kind(SymbolKind::Const)
40 .set_documentation(self.ctx.docs(self.const_)) 41 .set_documentation(self.ctx.docs(self.const_))
41 .set_deprecated( 42 .set_deprecated(
42 self.ctx.is_deprecated(self.const_) 43 self.ctx.is_deprecated(self.const_)
diff --git a/crates/completion/src/render/enum_variant.rs b/crates/completion/src/render/enum_variant.rs
index 89fb49773..adcddebd1 100644
--- a/crates/completion/src/render/enum_variant.rs
+++ b/crates/completion/src/render/enum_variant.rs
@@ -1,11 +1,12 @@
1//! Renderer for `enum` variants. 1//! Renderer for `enum` variants.
2 2
3use hir::{HasAttrs, HirDisplay, ModPath, StructKind}; 3use hir::{HasAttrs, HirDisplay, ModPath, StructKind};
4use ide_db::SymbolKind;
4use itertools::Itertools; 5use itertools::Itertools;
5use test_utils::mark; 6use test_utils::mark;
6 7
7use crate::{ 8use crate::{
8 item::{CompletionItem, CompletionItemKind, CompletionKind, ImportEdit}, 9 item::{CompletionItem, CompletionKind, ImportEdit},
9 render::{builder_ext::Params, RenderContext}, 10 render::{builder_ext::Params, RenderContext},
10}; 11};
11 12
@@ -60,7 +61,7 @@ impl<'a> EnumRender<'a> {
60 self.ctx.source_range(), 61 self.ctx.source_range(),
61 self.qualified_name.clone(), 62 self.qualified_name.clone(),
62 ) 63 )
63 .kind(CompletionItemKind::EnumVariant) 64 .kind(SymbolKind::Variant)
64 .set_documentation(self.variant.docs(self.ctx.db())) 65 .set_documentation(self.variant.docs(self.ctx.db()))
65 .set_deprecated(self.ctx.is_deprecated(self.variant)) 66 .set_deprecated(self.ctx.is_deprecated(self.variant))
66 .add_import(import_to_add) 67 .add_import(import_to_add)
diff --git a/crates/completion/src/render/function.rs b/crates/completion/src/render/function.rs
index 8f4c66211..e46e21d24 100644
--- a/crates/completion/src/render/function.rs
+++ b/crates/completion/src/render/function.rs
@@ -1,7 +1,8 @@
1//! Renderer for function calls. 1//! Renderer for function calls.
2 2
3use hir::{HasSource, Type}; 3use hir::{HasSource, HirDisplay, Type};
4use syntax::{ast::Fn, display::function_declaration}; 4use ide_db::SymbolKind;
5use syntax::ast::Fn;
5use test_utils::mark; 6use test_utils::mark;
6 7
7use crate::{ 8use crate::{
@@ -54,7 +55,8 @@ impl<'a> FunctionRender<'a> {
54 } 55 }
55 56
56 fn detail(&self) -> String { 57 fn detail(&self) -> String {
57 function_declaration(&self.ast_node) 58 let ty = self.func.ret_type(self.ctx.db());
59 format!("-> {}", ty.display(self.ctx.db()))
58 } 60 }
59 61
60 fn add_arg(&self, arg: &str, ty: &Type) -> String { 62 fn add_arg(&self, arg: &str, ty: &Type) -> String {
@@ -105,7 +107,7 @@ impl<'a> FunctionRender<'a> {
105 if self.func.self_param(self.ctx.db()).is_some() { 107 if self.func.self_param(self.ctx.db()).is_some() {
106 CompletionItemKind::Method 108 CompletionItemKind::Method
107 } else { 109 } else {
108 CompletionItemKind::Function 110 SymbolKind::Function.into()
109 } 111 }
110 } 112 }
111} 113}
diff --git a/crates/completion/src/render/macro_.rs b/crates/completion/src/render/macro_.rs
index f893e420a..a4535786f 100644
--- a/crates/completion/src/render/macro_.rs
+++ b/crates/completion/src/render/macro_.rs
@@ -1,11 +1,12 @@
1//! Renderer for macro invocations. 1//! Renderer for macro invocations.
2 2
3use hir::{Documentation, HasSource}; 3use hir::{Documentation, HasSource};
4use ide_db::SymbolKind;
4use syntax::display::macro_label; 5use syntax::display::macro_label;
5use test_utils::mark; 6use test_utils::mark;
6 7
7use crate::{ 8use crate::{
8 item::{CompletionItem, CompletionItemKind, CompletionKind, ImportEdit}, 9 item::{CompletionItem, CompletionKind, ImportEdit},
9 render::RenderContext, 10 render::RenderContext,
10}; 11};
11 12
@@ -41,7 +42,7 @@ impl<'a> MacroRender<'a> {
41 fn render(&self, import_to_add: Option<ImportEdit>) -> Option<CompletionItem> { 42 fn render(&self, import_to_add: Option<ImportEdit>) -> Option<CompletionItem> {
42 let mut builder = 43 let mut builder =
43 CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), &self.label()) 44 CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), &self.label())
44 .kind(CompletionItemKind::Macro) 45 .kind(SymbolKind::Macro)
45 .set_documentation(self.docs.clone()) 46 .set_documentation(self.docs.clone())
46 .set_deprecated(self.ctx.is_deprecated(self.macro_)) 47 .set_deprecated(self.ctx.is_deprecated(self.macro_))
47 .add_import(import_to_add) 48 .add_import(import_to_add)
diff --git a/crates/completion/src/render/type_alias.rs b/crates/completion/src/render/type_alias.rs
index 29287143a..bd97c3692 100644
--- a/crates/completion/src/render/type_alias.rs
+++ b/crates/completion/src/render/type_alias.rs
@@ -1,13 +1,14 @@
1//! Renderer for type aliases. 1//! Renderer for type aliases.
2 2
3use hir::HasSource; 3use hir::HasSource;
4use ide_db::SymbolKind;
4use syntax::{ 5use syntax::{
5 ast::{NameOwner, TypeAlias}, 6 ast::{NameOwner, TypeAlias},
6 display::type_label, 7 display::type_label,
7}; 8};
8 9
9use crate::{ 10use crate::{
10 item::{CompletionItem, CompletionItemKind, CompletionKind}, 11 item::{CompletionItem, CompletionKind},
11 render::RenderContext, 12 render::RenderContext,
12}; 13};
13 14
@@ -36,7 +37,7 @@ impl<'a> TypeAliasRender<'a> {
36 let detail = self.detail(); 37 let detail = self.detail();
37 38
38 let item = CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), name) 39 let item = CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), name)
39 .kind(CompletionItemKind::TypeAlias) 40 .kind(SymbolKind::TypeAlias)
40 .set_documentation(self.ctx.docs(self.type_alias)) 41 .set_documentation(self.ctx.docs(self.type_alias))
41 .set_deprecated( 42 .set_deprecated(
42 self.ctx.is_deprecated(self.type_alias) 43 self.ctx.is_deprecated(self.type_alias)
diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs
index 99fb65bac..9e6a3e155 100644
--- a/crates/hir/src/attrs.rs
+++ b/crates/hir/src/attrs.rs
@@ -2,6 +2,7 @@
2use hir_def::{ 2use hir_def::{
3 attr::{Attrs, Documentation}, 3 attr::{Attrs, Documentation},
4 path::ModPath, 4 path::ModPath,
5 per_ns::PerNs,
5 resolver::HasResolver, 6 resolver::HasResolver,
6 AttrDefId, GenericParamId, ModuleDefId, 7 AttrDefId, GenericParamId, ModuleDefId,
7}; 8};
@@ -112,6 +113,11 @@ fn resolve_doc_path(
112 let path = ast::Path::parse(link).ok()?; 113 let path = ast::Path::parse(link).ok()?;
113 let modpath = ModPath::from_src(path, &Hygiene::new_unhygienic()).unwrap(); 114 let modpath = ModPath::from_src(path, &Hygiene::new_unhygienic()).unwrap();
114 let resolved = resolver.resolve_module_path_in_items(db.upcast(), &modpath); 115 let resolved = resolver.resolve_module_path_in_items(db.upcast(), &modpath);
116 if resolved == PerNs::none() {
117 if let Some(trait_id) = resolver.resolve_module_path_in_trait_items(db.upcast(), &modpath) {
118 return Some(ModuleDefId::TraitId(trait_id));
119 };
120 }
115 let def = match ns { 121 let def = match ns {
116 Some(Namespace::Types) => resolved.take_types()?, 122 Some(Namespace::Types) => resolved.take_types()?,
117 Some(Namespace::Values) => resolved.take_values()?, 123 Some(Namespace::Values) => resolved.take_values()?,
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs
index aaa7013b6..d9b4cdfce 100644
--- a/crates/hir/src/code_model.rs
+++ b/crates/hir/src/code_model.rs
@@ -270,18 +270,18 @@ impl ModuleDef {
270 None => return, 270 None => return,
271 }; 271 };
272 272
273 hir_ty::diagnostics::validate_module_item(db, module.id.krate, id, sink) 273 hir_ty::diagnostics::validate_module_item(db, module.id.krate(), id, sink)
274 } 274 }
275} 275}
276 276
277impl Module { 277impl Module {
278 pub(crate) fn new(krate: Crate, crate_module_id: LocalModuleId) -> Module { 278 pub(crate) fn new(krate: Crate, crate_module_id: LocalModuleId) -> Module {
279 Module { id: ModuleId { krate: krate.id, local_id: crate_module_id } } 279 Module { id: ModuleId::top_level(krate.id, crate_module_id) }
280 } 280 }
281 281
282 /// Name of this module. 282 /// Name of this module.
283 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { 283 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
284 let def_map = db.crate_def_map(self.id.krate); 284 let def_map = self.id.def_map(db.upcast());
285 let parent = def_map[self.id.local_id].parent?; 285 let parent = def_map[self.id.local_id].parent?;
286 def_map[parent].children.iter().find_map(|(name, module_id)| { 286 def_map[parent].children.iter().find_map(|(name, module_id)| {
287 if *module_id == self.id.local_id { 287 if *module_id == self.id.local_id {
@@ -294,20 +294,20 @@ impl Module {
294 294
295 /// Returns the crate this module is part of. 295 /// Returns the crate this module is part of.
296 pub fn krate(self) -> Crate { 296 pub fn krate(self) -> Crate {
297 Crate { id: self.id.krate } 297 Crate { id: self.id.krate() }
298 } 298 }
299 299
300 /// Topmost parent of this module. Every module has a `crate_root`, but some 300 /// Topmost parent of this module. Every module has a `crate_root`, but some
301 /// might be missing `krate`. This can happen if a module's file is not included 301 /// might be missing `krate`. This can happen if a module's file is not included
302 /// in the module tree of any target in `Cargo.toml`. 302 /// in the module tree of any target in `Cargo.toml`.
303 pub fn crate_root(self, db: &dyn HirDatabase) -> Module { 303 pub fn crate_root(self, db: &dyn HirDatabase) -> Module {
304 let def_map = db.crate_def_map(self.id.krate); 304 let def_map = db.crate_def_map(self.id.krate());
305 self.with_module_id(def_map.root()) 305 self.with_module_id(def_map.root())
306 } 306 }
307 307
308 /// Iterates over all child modules. 308 /// Iterates over all child modules.
309 pub fn children(self, db: &dyn HirDatabase) -> impl Iterator<Item = Module> { 309 pub fn children(self, db: &dyn HirDatabase) -> impl Iterator<Item = Module> {
310 let def_map = db.crate_def_map(self.id.krate); 310 let def_map = self.id.def_map(db.upcast());
311 let children = def_map[self.id.local_id] 311 let children = def_map[self.id.local_id]
312 .children 312 .children
313 .iter() 313 .iter()
@@ -318,7 +318,8 @@ impl Module {
318 318
319 /// Finds a parent module. 319 /// Finds a parent module.
320 pub fn parent(self, db: &dyn HirDatabase) -> Option<Module> { 320 pub fn parent(self, db: &dyn HirDatabase) -> Option<Module> {
321 let def_map = db.crate_def_map(self.id.krate); 321 // FIXME: handle block expressions as modules (their parent is in a different DefMap)
322 let def_map = self.id.def_map(db.upcast());
322 let parent_id = def_map[self.id.local_id].parent?; 323 let parent_id = def_map[self.id.local_id].parent?;
323 Some(self.with_module_id(parent_id)) 324 Some(self.with_module_id(parent_id))
324 } 325 }
@@ -339,7 +340,7 @@ impl Module {
339 db: &dyn HirDatabase, 340 db: &dyn HirDatabase,
340 visible_from: Option<Module>, 341 visible_from: Option<Module>,
341 ) -> Vec<(Name, ScopeDef)> { 342 ) -> Vec<(Name, ScopeDef)> {
342 db.crate_def_map(self.id.krate)[self.id.local_id] 343 self.id.def_map(db.upcast())[self.id.local_id]
343 .scope 344 .scope
344 .entries() 345 .entries()
345 .filter_map(|(name, def)| { 346 .filter_map(|(name, def)| {
@@ -362,14 +363,14 @@ impl Module {
362 } 363 }
363 364
364 pub fn visibility_of(self, db: &dyn HirDatabase, def: &ModuleDef) -> Option<Visibility> { 365 pub fn visibility_of(self, db: &dyn HirDatabase, def: &ModuleDef) -> Option<Visibility> {
365 db.crate_def_map(self.id.krate)[self.id.local_id].scope.visibility_of(def.clone().into()) 366 self.id.def_map(db.upcast())[self.id.local_id].scope.visibility_of(def.clone().into())
366 } 367 }
367 368
368 pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { 369 pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) {
369 let _p = profile::span("Module::diagnostics").detail(|| { 370 let _p = profile::span("Module::diagnostics").detail(|| {
370 format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string())) 371 format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string()))
371 }); 372 });
372 let crate_def_map = db.crate_def_map(self.id.krate); 373 let crate_def_map = self.id.def_map(db.upcast());
373 crate_def_map.add_diagnostics(db.upcast(), self.id.local_id, sink); 374 crate_def_map.add_diagnostics(db.upcast(), self.id.local_id, sink);
374 for decl in self.declarations(db) { 375 for decl in self.declarations(db) {
375 match decl { 376 match decl {
@@ -396,12 +397,12 @@ impl Module {
396 } 397 }
397 398
398 pub fn declarations(self, db: &dyn HirDatabase) -> Vec<ModuleDef> { 399 pub fn declarations(self, db: &dyn HirDatabase) -> Vec<ModuleDef> {
399 let def_map = db.crate_def_map(self.id.krate); 400 let def_map = self.id.def_map(db.upcast());
400 def_map[self.id.local_id].scope.declarations().map(ModuleDef::from).collect() 401 def_map[self.id.local_id].scope.declarations().map(ModuleDef::from).collect()
401 } 402 }
402 403
403 pub fn impl_defs(self, db: &dyn HirDatabase) -> Vec<Impl> { 404 pub fn impl_defs(self, db: &dyn HirDatabase) -> Vec<Impl> {
404 let def_map = db.crate_def_map(self.id.krate); 405 let def_map = self.id.def_map(db.upcast());
405 def_map[self.id.local_id].scope.impls().map(Impl::from).collect() 406 def_map[self.id.local_id].scope.impls().map(Impl::from).collect()
406 } 407 }
407 408
@@ -457,7 +458,7 @@ impl Field {
457 }; 458 };
458 let substs = Substs::type_params(db, generic_def_id); 459 let substs = Substs::type_params(db, generic_def_id);
459 let ty = db.field_types(var_id)[self.id].clone().subst(&substs); 460 let ty = db.field_types(var_id)[self.id].clone().subst(&substs);
460 Type::new(db, self.parent.module(db).id.krate, var_id, ty) 461 Type::new(db, self.parent.module(db).id.krate(), var_id, ty)
461 } 462 }
462 463
463 pub fn parent_def(&self, _db: &dyn HirDatabase) -> VariantDef { 464 pub fn parent_def(&self, _db: &dyn HirDatabase) -> VariantDef {
@@ -502,7 +503,11 @@ impl Struct {
502 } 503 }
503 504
504 pub fn ty(self, db: &dyn HirDatabase) -> Type { 505 pub fn ty(self, db: &dyn HirDatabase) -> Type {
505 Type::from_def(db, self.id.lookup(db.upcast()).container.module(db.upcast()).krate, self.id) 506 Type::from_def(
507 db,
508 self.id.lookup(db.upcast()).container.module(db.upcast()).krate(),
509 self.id,
510 )
506 } 511 }
507 512
508 pub fn repr(self, db: &dyn HirDatabase) -> Option<ReprKind> { 513 pub fn repr(self, db: &dyn HirDatabase) -> Option<ReprKind> {
@@ -533,7 +538,11 @@ impl Union {
533 } 538 }
534 539
535 pub fn ty(self, db: &dyn HirDatabase) -> Type { 540 pub fn ty(self, db: &dyn HirDatabase) -> Type {
536 Type::from_def(db, self.id.lookup(db.upcast()).container.module(db.upcast()).krate, self.id) 541 Type::from_def(
542 db,
543 self.id.lookup(db.upcast()).container.module(db.upcast()).krate(),
544 self.id,
545 )
537 } 546 }
538 547
539 pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> { 548 pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
@@ -573,7 +582,11 @@ impl Enum {
573 } 582 }
574 583
575 pub fn ty(self, db: &dyn HirDatabase) -> Type { 584 pub fn ty(self, db: &dyn HirDatabase) -> Type {
576 Type::from_def(db, self.id.lookup(db.upcast()).container.module(db.upcast()).krate, self.id) 585 Type::from_def(
586 db,
587 self.id.lookup(db.upcast()).container.module(db.upcast()).krate(),
588 self.id,
589 )
577 } 590 }
578} 591}
579 592
@@ -632,7 +645,7 @@ impl Adt {
632 /// general set of completions, but will not look very nice when printed. 645 /// general set of completions, but will not look very nice when printed.
633 pub fn ty(self, db: &dyn HirDatabase) -> Type { 646 pub fn ty(self, db: &dyn HirDatabase) -> Type {
634 let id = AdtId::from(self); 647 let id = AdtId::from(self);
635 Type::from_def(db, id.module(db.upcast()).krate, id) 648 Type::from_def(db, id.module(db.upcast()).krate(), id)
636 } 649 }
637 650
638 pub fn module(self, db: &dyn HirDatabase) -> Module { 651 pub fn module(self, db: &dyn HirDatabase) -> Module {
@@ -750,7 +763,7 @@ impl Function {
750 let ctx = hir_ty::TyLoweringContext::new(db, &resolver); 763 let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
751 let environment = TraitEnvironment::lower(db, &resolver); 764 let environment = TraitEnvironment::lower(db, &resolver);
752 Type { 765 Type {
753 krate: self.id.lookup(db.upcast()).container.module(db.upcast()).krate, 766 krate: self.id.lookup(db.upcast()).container.module(db.upcast()).krate(),
754 ty: InEnvironment { value: Ty::from_hir_ext(&ctx, ret_type).0, environment }, 767 ty: InEnvironment { value: Ty::from_hir_ext(&ctx, ret_type).0, environment },
755 } 768 }
756 } 769 }
@@ -771,7 +784,7 @@ impl Function {
771 .iter() 784 .iter()
772 .map(|type_ref| { 785 .map(|type_ref| {
773 let ty = Type { 786 let ty = Type {
774 krate: self.id.lookup(db.upcast()).container.module(db.upcast()).krate, 787 krate: self.id.lookup(db.upcast()).container.module(db.upcast()).krate(),
775 ty: InEnvironment { 788 ty: InEnvironment {
776 value: Ty::from_hir_ext(&ctx, type_ref).0, 789 value: Ty::from_hir_ext(&ctx, type_ref).0,
777 environment: environment.clone(), 790 environment: environment.clone(),
@@ -795,7 +808,7 @@ impl Function {
795 } 808 }
796 809
797 pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { 810 pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) {
798 let krate = self.module(db).id.krate; 811 let krate = self.module(db).id.krate();
799 hir_def::diagnostics::validate_body(db.upcast(), self.id.into(), sink); 812 hir_def::diagnostics::validate_body(db.upcast(), self.id.into(), sink);
800 hir_ty::diagnostics::validate_module_item(db, krate, self.id.into(), sink); 813 hir_ty::diagnostics::validate_module_item(db, krate, self.id.into(), sink);
801 hir_ty::diagnostics::validate_body(db, self.id.into(), sink); 814 hir_ty::diagnostics::validate_body(db, self.id.into(), sink);
@@ -973,7 +986,7 @@ impl TypeAlias {
973 } 986 }
974 987
975 pub fn ty(self, db: &dyn HirDatabase) -> Type { 988 pub fn ty(self, db: &dyn HirDatabase) -> Type {
976 Type::from_def(db, self.id.lookup(db.upcast()).module(db.upcast()).krate, self.id) 989 Type::from_def(db, self.id.lookup(db.upcast()).module(db.upcast()).krate(), self.id)
977 } 990 }
978 991
979 pub fn name(self, db: &dyn HirDatabase) -> Name { 992 pub fn name(self, db: &dyn HirDatabase) -> Name {
@@ -1230,7 +1243,7 @@ impl Local {
1230 let def = DefWithBodyId::from(self.parent); 1243 let def = DefWithBodyId::from(self.parent);
1231 let infer = db.infer(def); 1244 let infer = db.infer(def);
1232 let ty = infer[self.pat_id].clone(); 1245 let ty = infer[self.pat_id].clone();
1233 let krate = def.module(db.upcast()).krate; 1246 let krate = def.module(db.upcast()).krate();
1234 Type::new(db, krate, def, ty) 1247 Type::new(db, krate, def, ty)
1235 } 1248 }
1236 1249
@@ -1318,7 +1331,7 @@ impl TypeParam {
1318 let environment = TraitEnvironment::lower(db, &resolver); 1331 let environment = TraitEnvironment::lower(db, &resolver);
1319 let ty = Ty::Placeholder(self.id); 1332 let ty = Ty::Placeholder(self.id);
1320 Type { 1333 Type {
1321 krate: self.id.parent.module(db.upcast()).krate, 1334 krate: self.id.parent.module(db.upcast()).krate(),
1322 ty: InEnvironment { value: ty, environment }, 1335 ty: InEnvironment { value: ty, environment },
1323 } 1336 }
1324 } 1337 }
@@ -1344,7 +1357,7 @@ impl TypeParam {
1344 let subst = Substs::type_params(db, self.id.parent); 1357 let subst = Substs::type_params(db, self.id.parent);
1345 let ty = ty.subst(&subst.prefix(local_idx)); 1358 let ty = ty.subst(&subst.prefix(local_idx));
1346 Some(Type { 1359 Some(Type {
1347 krate: self.id.parent.module(db.upcast()).krate, 1360 krate: self.id.parent.module(db.upcast()).krate(),
1348 ty: InEnvironment { value: ty, environment }, 1361 ty: InEnvironment { value: ty, environment },
1349 }) 1362 })
1350 } 1363 }
@@ -1405,7 +1418,7 @@ impl ConstParam {
1405 1418
1406 pub fn ty(self, db: &dyn HirDatabase) -> Type { 1419 pub fn ty(self, db: &dyn HirDatabase) -> Type {
1407 let def = self.id.parent; 1420 let def = self.id.parent;
1408 let krate = def.module(db.upcast()).krate; 1421 let krate = def.module(db.upcast()).krate();
1409 Type::new(db, krate, def, db.const_param_ty(self.id)) 1422 Type::new(db, krate, def, db.const_param_ty(self.id))
1410 } 1423 }
1411} 1424}
@@ -1440,7 +1453,7 @@ impl Impl {
1440 let environment = TraitEnvironment::lower(db, &resolver); 1453 let environment = TraitEnvironment::lower(db, &resolver);
1441 let ty = Ty::from_hir(&ctx, &impl_data.target_type); 1454 let ty = Ty::from_hir(&ctx, &impl_data.target_type);
1442 Type { 1455 Type {
1443 krate: self.id.lookup(db.upcast()).container.module(db.upcast()).krate, 1456 krate: self.id.lookup(db.upcast()).container.module(db.upcast()).krate(),
1444 ty: InEnvironment { value: ty, environment }, 1457 ty: InEnvironment { value: ty, environment },
1445 } 1458 }
1446 } 1459 }
@@ -1458,7 +1471,7 @@ impl Impl {
1458 } 1471 }
1459 1472
1460 pub fn krate(self, db: &dyn HirDatabase) -> Crate { 1473 pub fn krate(self, db: &dyn HirDatabase) -> Crate {
1461 Crate { id: self.module(db).id.krate } 1474 Crate { id: self.module(db).id.krate() }
1462 } 1475 }
1463 1476
1464 pub fn is_builtin_derive(self, db: &dyn HirDatabase) -> Option<InFile<ast::Attr>> { 1477 pub fn is_builtin_derive(self, db: &dyn HirDatabase) -> Option<InFile<ast::Attr>> {
diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs
index 7c57d8378..262002671 100644
--- a/crates/hir/src/has_source.rs
+++ b/crates/hir/src/has_source.rs
@@ -24,12 +24,12 @@ pub trait HasSource {
24impl Module { 24impl Module {
25 /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items. 25 /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items.
26 pub fn definition_source(self, db: &dyn HirDatabase) -> InFile<ModuleSource> { 26 pub fn definition_source(self, db: &dyn HirDatabase) -> InFile<ModuleSource> {
27 let def_map = db.crate_def_map(self.id.krate); 27 let def_map = self.id.def_map(db.upcast());
28 def_map[self.id.local_id].definition_source(db.upcast()) 28 def_map[self.id.local_id].definition_source(db.upcast())
29 } 29 }
30 30
31 pub fn is_mod_rs(self, db: &dyn HirDatabase) -> bool { 31 pub fn is_mod_rs(self, db: &dyn HirDatabase) -> bool {
32 let def_map = db.crate_def_map(self.id.krate); 32 let def_map = self.id.def_map(db.upcast());
33 match def_map[self.id.local_id].origin { 33 match def_map[self.id.local_id].origin {
34 ModuleOrigin::File { is_mod_rs, .. } => is_mod_rs, 34 ModuleOrigin::File { is_mod_rs, .. } => is_mod_rs,
35 _ => false, 35 _ => false,
@@ -39,7 +39,7 @@ impl Module {
39 /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`. 39 /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`.
40 /// `None` for the crate root. 40 /// `None` for the crate root.
41 pub fn declaration_source(self, db: &dyn HirDatabase) -> Option<InFile<ast::Module>> { 41 pub fn declaration_source(self, db: &dyn HirDatabase) -> Option<InFile<ast::Module>> {
42 let def_map = db.crate_def_map(self.id.krate); 42 let def_map = self.id.def_map(db.upcast());
43 def_map[self.id.local_id].declaration_source(db.upcast()) 43 def_map[self.id.local_id].declaration_source(db.upcast())
44 } 44 }
45} 45}
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs
index 9bf60c72a..faede3269 100644
--- a/crates/hir/src/semantics/source_to_def.rs
+++ b/crates/hir/src/semantics/source_to_def.rs
@@ -31,11 +31,12 @@ impl SourceToDefCtx<'_, '_> {
31 pub(super) fn file_to_def(&mut self, file: FileId) -> Option<ModuleId> { 31 pub(super) fn file_to_def(&mut self, file: FileId) -> Option<ModuleId> {
32 let _p = profile::span("SourceBinder::to_module_def"); 32 let _p = profile::span("SourceBinder::to_module_def");
33 let (krate, local_id) = self.db.relevant_crates(file).iter().find_map(|&crate_id| { 33 let (krate, local_id) = self.db.relevant_crates(file).iter().find_map(|&crate_id| {
34 // FIXME: inner items
34 let crate_def_map = self.db.crate_def_map(crate_id); 35 let crate_def_map = self.db.crate_def_map(crate_id);
35 let local_id = crate_def_map.modules_for_file(file).next()?; 36 let local_id = crate_def_map.modules_for_file(file).next()?;
36 Some((crate_id, local_id)) 37 Some((crate_id, local_id))
37 })?; 38 })?;
38 Some(ModuleId { krate, local_id }) 39 Some(ModuleId::top_level(krate, local_id))
39 } 40 }
40 41
41 pub(super) fn module_to_def(&mut self, src: InFile<ast::Module>) -> Option<ModuleId> { 42 pub(super) fn module_to_def(&mut self, src: InFile<ast::Module>) -> Option<ModuleId> {
@@ -60,9 +61,10 @@ impl SourceToDefCtx<'_, '_> {
60 }?; 61 }?;
61 62
62 let child_name = src.value.name()?.as_name(); 63 let child_name = src.value.name()?.as_name();
63 let def_map = self.db.crate_def_map(parent_module.krate); 64 let def_map = parent_module.def_map(self.db.upcast());
64 let child_id = *def_map[parent_module.local_id].children.get(&child_name)?; 65 let child_id = *def_map[parent_module.local_id].children.get(&child_name)?;
65 Some(ModuleId { krate: parent_module.krate, local_id: child_id }) 66 // FIXME: handle block expression modules
67 Some(ModuleId::top_level(parent_module.krate(), child_id))
66 } 68 }
67 69
68 pub(super) fn trait_to_def(&mut self, src: InFile<ast::Trait>) -> Option<TraitId> { 70 pub(super) fn trait_to_def(&mut self, src: InFile<ast::Trait>) -> Option<TraitId> {
@@ -185,7 +187,7 @@ impl SourceToDefCtx<'_, '_> {
185 ) -> Option<MacroDefId> { 187 ) -> Option<MacroDefId> {
186 let kind = MacroDefKind::Declarative; 188 let kind = MacroDefKind::Declarative;
187 let file_id = src.file_id.original_file(self.db.upcast()); 189 let file_id = src.file_id.original_file(self.db.upcast());
188 let krate = self.file_to_def(file_id)?.krate; 190 let krate = self.file_to_def(file_id)?.krate();
189 let file_ast_id = self.db.ast_id_map(src.file_id).ast_id(&src.value); 191 let file_ast_id = self.db.ast_id_map(src.file_id).ast_id(&src.value);
190 let ast_id = Some(AstId::new(src.file_id, file_ast_id.upcast())); 192 let ast_id = Some(AstId::new(src.file_id, file_ast_id.upcast()));
191 Some(MacroDefId { krate, ast_id, kind, local_inner: false }) 193 Some(MacroDefId { krate, ast_id, kind, local_inner: false })
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index c72649c41..6513daec8 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -196,7 +196,7 @@ impl Attrs {
196 pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs { 196 pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs {
197 let raw_attrs = match def { 197 let raw_attrs = match def {
198 AttrDefId::ModuleId(module) => { 198 AttrDefId::ModuleId(module) => {
199 let def_map = db.crate_def_map(module.krate); 199 let def_map = module.def_map(db);
200 let mod_data = &def_map[module.local_id]; 200 let mod_data = &def_map[module.local_id];
201 match mod_data.declaration_source(db) { 201 match mod_data.declaration_source(db) {
202 Some(it) => { 202 Some(it) => {
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs
index 2c2c999dd..d0c84ab0b 100644
--- a/crates/hir_def/src/body.rs
+++ b/crates/hir_def/src/body.rs
@@ -86,7 +86,7 @@ impl Expander {
86 module: ModuleId, 86 module: ModuleId,
87 ) -> Expander { 87 ) -> Expander {
88 let cfg_expander = CfgExpander::new(db, current_file_id, module.krate); 88 let cfg_expander = CfgExpander::new(db, current_file_id, module.krate);
89 let crate_def_map = db.crate_def_map(module.krate); 89 let crate_def_map = module.def_map(db);
90 let ast_id_map = db.ast_id_map(current_file_id); 90 let ast_id_map = db.ast_id_map(current_file_id);
91 Expander { 91 Expander {
92 cfg_expander, 92 cfg_expander,
diff --git a/crates/hir_def/src/child_by_source.rs b/crates/hir_def/src/child_by_source.rs
index dcb00a1d9..65d85c86a 100644
--- a/crates/hir_def/src/child_by_source.rs
+++ b/crates/hir_def/src/child_by_source.rs
@@ -74,7 +74,7 @@ impl ChildBySource for ImplId {
74 74
75impl ChildBySource for ModuleId { 75impl ChildBySource for ModuleId {
76 fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap { 76 fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap {
77 let crate_def_map = db.crate_def_map(self.krate); 77 let crate_def_map = self.def_map(db);
78 let module_data = &crate_def_map[self.local_id]; 78 let module_data = &crate_def_map[self.local_id];
79 module_data.scope.child_by_source(db) 79 module_data.scope.child_by_source(db)
80 } 80 }
diff --git a/crates/hir_def/src/find_path.rs b/crates/hir_def/src/find_path.rs
index db2d125ae..c01b6daf2 100644
--- a/crates/hir_def/src/find_path.rs
+++ b/crates/hir_def/src/find_path.rs
@@ -110,7 +110,7 @@ fn find_path_inner(
110 // Base cases: 110 // Base cases:
111 111
112 // - if the item is already in scope, return the name under which it is 112 // - if the item is already in scope, return the name under which it is
113 let def_map = db.crate_def_map(from.krate); 113 let def_map = from.def_map(db);
114 let from_scope: &crate::item_scope::ItemScope = &def_map[from.local_id].scope; 114 let from_scope: &crate::item_scope::ItemScope = &def_map[from.local_id].scope;
115 let scope_name = 115 let scope_name =
116 if let Some((name, _)) = from_scope.name_of(item) { Some(name.clone()) } else { None }; 116 if let Some((name, _)) = from_scope.name_of(item) { Some(name.clone()) } else { None };
@@ -145,7 +145,7 @@ fn find_path_inner(
145 145
146 // - if the item is in the prelude, return the name from there 146 // - if the item is in the prelude, return the name from there
147 if let Some(prelude_module) = def_map.prelude() { 147 if let Some(prelude_module) = def_map.prelude() {
148 let prelude_def_map = db.crate_def_map(prelude_module.krate); 148 let prelude_def_map = prelude_module.def_map(db);
149 let prelude_scope: &crate::item_scope::ItemScope = 149 let prelude_scope: &crate::item_scope::ItemScope =
150 &prelude_def_map[prelude_module.local_id].scope; 150 &prelude_def_map[prelude_module.local_id].scope;
151 if let Some((name, vis)) = prelude_scope.name_of(item) { 151 if let Some((name, vis)) = prelude_scope.name_of(item) {
@@ -283,7 +283,7 @@ fn find_local_import_locations(
283 // above `from` with any visibility. That means we do not need to descend into private siblings 283 // above `from` with any visibility. That means we do not need to descend into private siblings
284 // of `from` (and similar). 284 // of `from` (and similar).
285 285
286 let def_map = db.crate_def_map(from.krate); 286 let def_map = from.def_map(db);
287 287
288 // Compute the initial worklist. We start with all direct child modules of `from` as well as all 288 // Compute the initial worklist. We start with all direct child modules of `from` as well as all
289 // of its (recursive) parent modules. 289 // of its (recursive) parent modules.
@@ -312,7 +312,7 @@ fn find_local_import_locations(
312 &def_map[module.local_id] 312 &def_map[module.local_id]
313 } else { 313 } else {
314 // The crate might reexport a module defined in another crate. 314 // The crate might reexport a module defined in another crate.
315 ext_def_map = db.crate_def_map(module.krate); 315 ext_def_map = module.def_map(db);
316 &ext_def_map[module.local_id] 316 &ext_def_map[module.local_id]
317 }; 317 };
318 318
@@ -375,7 +375,7 @@ mod tests {
375 parsed_path_file.syntax_node().descendants().find_map(syntax::ast::Path::cast).unwrap(); 375 parsed_path_file.syntax_node().descendants().find_map(syntax::ast::Path::cast).unwrap();
376 let mod_path = ModPath::from_src(ast_path, &Hygiene::new_unhygienic()).unwrap(); 376 let mod_path = ModPath::from_src(ast_path, &Hygiene::new_unhygienic()).unwrap();
377 377
378 let crate_def_map = db.crate_def_map(module.krate); 378 let crate_def_map = module.def_map(&db);
379 let resolved = crate_def_map 379 let resolved = crate_def_map
380 .resolve_path( 380 .resolve_path(
381 &db, 381 &db,
diff --git a/crates/hir_def/src/import_map.rs b/crates/hir_def/src/import_map.rs
index 0251d016b..0b7830445 100644
--- a/crates/hir_def/src/import_map.rs
+++ b/crates/hir_def/src/import_map.rs
@@ -83,7 +83,7 @@ impl ImportMap {
83 &def_map[module.local_id] 83 &def_map[module.local_id]
84 } else { 84 } else {
85 // The crate might reexport a module defined in another crate. 85 // The crate might reexport a module defined in another crate.
86 ext_def_map = db.crate_def_map(module.krate); 86 ext_def_map = module.def_map(db);
87 &ext_def_map[module.local_id] 87 &ext_def_map[module.local_id]
88 }; 88 };
89 89
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index 08ed920c6..c8dbb2aeb 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -50,7 +50,10 @@ pub mod import_map;
50#[cfg(test)] 50#[cfg(test)]
51mod test_db; 51mod test_db;
52 52
53use std::hash::{Hash, Hasher}; 53use std::{
54 hash::{Hash, Hasher},
55 sync::Arc,
56};
54 57
55use base_db::{impl_intern_key, salsa, CrateId}; 58use base_db::{impl_intern_key, salsa, CrateId};
56use hir_expand::{ 59use hir_expand::{
@@ -58,6 +61,7 @@ use hir_expand::{
58 MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, 61 MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
59}; 62};
60use la_arena::Idx; 63use la_arena::Idx;
64use nameres::DefMap;
61use syntax::ast; 65use syntax::ast;
62 66
63use crate::builtin_type::BuiltinType; 67use crate::builtin_type::BuiltinType;
@@ -69,10 +73,24 @@ use stdx::impl_from;
69 73
70#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 74#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
71pub struct ModuleId { 75pub struct ModuleId {
72 pub krate: CrateId, 76 krate: CrateId,
73 pub local_id: LocalModuleId, 77 pub local_id: LocalModuleId,
74} 78}
75 79
80impl ModuleId {
81 pub fn top_level(krate: CrateId, local_id: LocalModuleId) -> Self {
82 Self { krate, local_id }
83 }
84
85 pub fn def_map(&self, db: &dyn db::DefDatabase) -> Arc<DefMap> {
86 db.crate_def_map(self.krate)
87 }
88
89 pub fn krate(&self) -> CrateId {
90 self.krate
91 }
92}
93
76/// An ID of a module, **local** to a specific crate 94/// An ID of a module, **local** to a specific crate
77pub type LocalModuleId = Idx<nameres::ModuleData>; 95pub type LocalModuleId = Idx<nameres::ModuleData>;
78 96
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index cd68efbe6..adfcf879a 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -578,7 +578,7 @@ impl DefCollector<'_> {
578 } else if m.krate != self.def_map.krate { 578 } else if m.krate != self.def_map.krate {
579 mark::hit!(glob_across_crates); 579 mark::hit!(glob_across_crates);
580 // glob import from other crate => we can just import everything once 580 // glob import from other crate => we can just import everything once
581 let item_map = self.db.crate_def_map(m.krate); 581 let item_map = m.def_map(self.db);
582 let scope = &item_map[m.local_id].scope; 582 let scope = &item_map[m.local_id].scope;
583 583
584 // Module scoped macros is included 584 // Module scoped macros is included
diff --git a/crates/hir_def/src/nameres/path_resolution.rs b/crates/hir_def/src/nameres/path_resolution.rs
index 7588e0088..7b5fe24a7 100644
--- a/crates/hir_def/src/nameres/path_resolution.rs
+++ b/crates/hir_def/src/nameres/path_resolution.rs
@@ -251,7 +251,7 @@ impl DefMap {
251 kind: PathKind::Super(0), 251 kind: PathKind::Super(0),
252 }; 252 };
253 log::debug!("resolving {:?} in other crate", path); 253 log::debug!("resolving {:?} in other crate", path);
254 let defp_map = db.crate_def_map(module.krate); 254 let defp_map = module.def_map(db);
255 let (def, s) = defp_map.resolve_path(db, module.local_id, &path, shadow); 255 let (def, s) = defp_map.resolve_path(db, module.local_id, &path, shadow);
256 return ResolvePathResult::with( 256 return ResolvePathResult::with(
257 def, 257 def,
@@ -364,7 +364,7 @@ impl DefMap {
364 self 364 self
365 } else { 365 } else {
366 // Extend lifetime 366 // Extend lifetime
367 keep = db.crate_def_map(prelude.krate); 367 keep = prelude.def_map(db);
368 &keep 368 &keep
369 }; 369 };
370 def_map[prelude.local_id].scope.get(name) 370 def_map[prelude.local_id].scope.get(name)
diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs
index d48029b7d..130c074f0 100644
--- a/crates/hir_def/src/resolver.rs
+++ b/crates/hir_def/src/resolver.rs
@@ -146,6 +146,19 @@ impl Resolver {
146 self.resolve_module_path(db, path, BuiltinShadowMode::Module) 146 self.resolve_module_path(db, path, BuiltinShadowMode::Module)
147 } 147 }
148 148
149 pub fn resolve_module_path_in_trait_items(
150 &self,
151 db: &dyn DefDatabase,
152 path: &ModPath,
153 ) -> Option<TraitId> {
154 let (item_map, module) = self.module_scope()?;
155 let (module_res, ..) = item_map.resolve_path(db, module, &path, BuiltinShadowMode::Module);
156 match module_res.take_types()? {
157 ModuleDefId::TraitId(it) => Some(it),
158 _ => None,
159 }
160 }
161
149 pub fn resolve_path_in_type_ns( 162 pub fn resolve_path_in_type_ns(
150 &self, 163 &self,
151 db: &dyn DefDatabase, 164 db: &dyn DefDatabase,
@@ -417,7 +430,7 @@ impl Resolver {
417 for scope in &self.scopes { 430 for scope in &self.scopes {
418 if let Scope::ModuleScope(m) = scope { 431 if let Scope::ModuleScope(m) = scope {
419 if let Some(prelude) = m.crate_def_map.prelude() { 432 if let Some(prelude) = m.crate_def_map.prelude() {
420 let prelude_def_map = db.crate_def_map(prelude.krate); 433 let prelude_def_map = prelude.def_map(db);
421 traits.extend(prelude_def_map[prelude.local_id].scope.traits()); 434 traits.extend(prelude_def_map[prelude.local_id].scope.traits());
422 } 435 }
423 traits.extend(m.crate_def_map[m.module_id].scope.traits()); 436 traits.extend(m.crate_def_map[m.module_id].scope.traits());
@@ -516,7 +529,7 @@ impl Scope {
516 f(name.clone(), ScopeDef::PerNs(def)); 529 f(name.clone(), ScopeDef::PerNs(def));
517 }); 530 });
518 if let Some(prelude) = m.crate_def_map.prelude() { 531 if let Some(prelude) = m.crate_def_map.prelude() {
519 let prelude_def_map = db.crate_def_map(prelude.krate); 532 let prelude_def_map = prelude.def_map(db);
520 prelude_def_map[prelude.local_id].scope.entries().for_each(|(name, def)| { 533 prelude_def_map[prelude.local_id].scope.entries().for_each(|(name, def)| {
521 let seen_tuple = (name.clone(), def); 534 let seen_tuple = (name.clone(), def);
522 if !seen.contains(&seen_tuple) { 535 if !seen.contains(&seen_tuple) {
@@ -620,7 +633,7 @@ pub trait HasResolver: Copy {
620 633
621impl HasResolver for ModuleId { 634impl HasResolver for ModuleId {
622 fn resolver(self, db: &dyn DefDatabase) -> Resolver { 635 fn resolver(self, db: &dyn DefDatabase) -> Resolver {
623 let def_map = db.crate_def_map(self.krate); 636 let def_map = self.def_map(db);
624 Resolver::default().push_module_scope(def_map, self.local_id) 637 Resolver::default().push_module_scope(def_map, self.local_id)
625 } 638 }
626} 639}
diff --git a/crates/hir_def/src/visibility.rs b/crates/hir_def/src/visibility.rs
index 3134fa43d..e79a91102 100644
--- a/crates/hir_def/src/visibility.rs
+++ b/crates/hir_def/src/visibility.rs
@@ -103,7 +103,7 @@ impl Visibility {
103 if from_module.krate != to_module.krate { 103 if from_module.krate != to_module.krate {
104 return false; 104 return false;
105 } 105 }
106 let def_map = db.crate_def_map(from_module.krate); 106 let def_map = from_module.def_map(db);
107 self.is_visible_from_def_map(&def_map, from_module.local_id) 107 self.is_visible_from_def_map(&def_map, from_module.local_id)
108 } 108 }
109 109
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs
index d2f1b4014..38a043c48 100644
--- a/crates/hir_ty/src/display.rs
+++ b/crates/hir_ty/src/display.rs
@@ -617,7 +617,7 @@ impl HirDisplay for FnSig {
617} 617}
618 618
619fn fn_traits(db: &dyn DefDatabase, trait_: TraitId) -> impl Iterator<Item = TraitId> { 619fn fn_traits(db: &dyn DefDatabase, trait_: TraitId) -> impl Iterator<Item = TraitId> {
620 let krate = trait_.lookup(db).container.module(db).krate; 620 let krate = trait_.lookup(db).container.module(db).krate();
621 let fn_traits = [ 621 let fn_traits = [
622 db.lang_item(krate, "fn".into()), 622 db.lang_item(krate, "fn".into()),
623 db.lang_item(krate, "fn_mut".into()), 623 db.lang_item(krate, "fn_mut".into()),
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index 9bf3b51b0..d7351d212 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -491,7 +491,10 @@ impl<'a> InferenceContext<'a> {
491 Expr::Box { expr } => { 491 Expr::Box { expr } => {
492 let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); 492 let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
493 if let Some(box_) = self.resolve_boxed_box() { 493 if let Some(box_) = self.resolve_boxed_box() {
494 Ty::apply_one(TypeCtor::Adt(box_), inner_ty) 494 let mut sb = Substs::build_for_type_ctor(self.db, TypeCtor::Adt(box_));
495 sb = sb.push(inner_ty);
496 sb = sb.fill(repeat_with(|| self.table.new_type_var()));
497 Ty::apply(TypeCtor::Adt(box_), sb.build())
495 } else { 498 } else {
496 Ty::Unknown 499 Ty::Unknown
497 } 500 }
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs
index e00c7e176..d47f975d2 100644
--- a/crates/hir_ty/src/lib.rs
+++ b/crates/hir_ty/src/lib.rs
@@ -211,19 +211,21 @@ impl TypeCtor {
211 | TypeCtor::Tuple { .. } => None, 211 | TypeCtor::Tuple { .. } => None,
212 // Closure's krate is irrelevant for coherence I would think? 212 // Closure's krate is irrelevant for coherence I would think?
213 TypeCtor::Closure { .. } => None, 213 TypeCtor::Closure { .. } => None,
214 TypeCtor::Adt(adt) => Some(adt.module(db.upcast()).krate), 214 TypeCtor::Adt(adt) => Some(adt.module(db.upcast()).krate()),
215 TypeCtor::FnDef(callable) => Some(callable.krate(db)), 215 TypeCtor::FnDef(callable) => Some(callable.krate(db)),
216 TypeCtor::AssociatedType(type_alias) => { 216 TypeCtor::AssociatedType(type_alias) => {
217 Some(type_alias.lookup(db.upcast()).module(db.upcast()).krate) 217 Some(type_alias.lookup(db.upcast()).module(db.upcast()).krate())
218 } 218 }
219 TypeCtor::ForeignType(type_alias) => { 219 TypeCtor::ForeignType(type_alias) => {
220 Some(type_alias.lookup(db.upcast()).module(db.upcast()).krate) 220 Some(type_alias.lookup(db.upcast()).module(db.upcast()).krate())
221 } 221 }
222 TypeCtor::OpaqueType(opaque_ty_id) => match opaque_ty_id { 222 TypeCtor::OpaqueType(opaque_ty_id) => match opaque_ty_id {
223 OpaqueTyId::ReturnTypeImplTrait(func, _) => { 223 OpaqueTyId::ReturnTypeImplTrait(func, _) => {
224 Some(func.lookup(db.upcast()).module(db.upcast()).krate) 224 Some(func.lookup(db.upcast()).module(db.upcast()).krate())
225 }
226 OpaqueTyId::AsyncBlockTypeImplTrait(def, _) => {
227 Some(def.module(db.upcast()).krate())
225 } 228 }
226 OpaqueTyId::AsyncBlockTypeImplTrait(def, _) => Some(def.module(db.upcast()).krate),
227 }, 229 },
228 } 230 }
229 } 231 }
@@ -870,7 +872,7 @@ impl Ty {
870 Ty::Apply(ApplicationTy { ctor: TypeCtor::OpaqueType(opaque_ty_id), .. }) => { 872 Ty::Apply(ApplicationTy { ctor: TypeCtor::OpaqueType(opaque_ty_id), .. }) => {
871 match opaque_ty_id { 873 match opaque_ty_id {
872 OpaqueTyId::AsyncBlockTypeImplTrait(def, _expr) => { 874 OpaqueTyId::AsyncBlockTypeImplTrait(def, _expr) => {
873 let krate = def.module(db.upcast()).krate; 875 let krate = def.module(db.upcast()).krate();
874 if let Some(future_trait) = db 876 if let Some(future_trait) = db
875 .lang_item(krate, "future_trait".into()) 877 .lang_item(krate, "future_trait".into())
876 .and_then(|item| item.as_trait()) 878 .and_then(|item| item.as_trait())
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index 7a734c8b9..dfb573ff3 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -1147,7 +1147,7 @@ impl CallableDefId {
1147 CallableDefId::StructId(s) => s.lookup(db).container.module(db), 1147 CallableDefId::StructId(s) => s.lookup(db).container.module(db),
1148 CallableDefId::EnumVariantId(e) => e.parent.lookup(db).container.module(db), 1148 CallableDefId::EnumVariantId(e) => e.parent.lookup(db).container.module(db),
1149 } 1149 }
1150 .krate 1150 .krate()
1151 } 1151 }
1152} 1152}
1153 1153
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs
index f06aeeb42..a302456b0 100644
--- a/crates/hir_ty/src/method_resolution.rs
+++ b/crates/hir_ty/src/method_resolution.rs
@@ -248,12 +248,12 @@ impl Ty {
248 let lang_item_targets = match self { 248 let lang_item_targets = match self {
249 Ty::Apply(a_ty) => match a_ty.ctor { 249 Ty::Apply(a_ty) => match a_ty.ctor {
250 TypeCtor::Adt(def_id) => { 250 TypeCtor::Adt(def_id) => {
251 return Some(std::iter::once(def_id.module(db.upcast()).krate).collect()) 251 return Some(std::iter::once(def_id.module(db.upcast()).krate()).collect())
252 } 252 }
253 TypeCtor::ForeignType(type_alias_id) => { 253 TypeCtor::ForeignType(type_alias_id) => {
254 return Some( 254 return Some(
255 std::iter::once( 255 std::iter::once(
256 type_alias_id.lookup(db.upcast()).module(db.upcast()).krate, 256 type_alias_id.lookup(db.upcast()).module(db.upcast()).krate(),
257 ) 257 )
258 .collect(), 258 .collect(),
259 ) 259 )
@@ -280,7 +280,7 @@ impl Ty {
280 LangItemTarget::ImplDefId(it) => Some(it), 280 LangItemTarget::ImplDefId(it) => Some(it),
281 _ => None, 281 _ => None,
282 }) 282 })
283 .map(|it| it.lookup(db.upcast()).container.module(db.upcast()).krate) 283 .map(|it| it.lookup(db.upcast()).container.module(db.upcast()).krate())
284 .collect(); 284 .collect();
285 Some(res) 285 Some(res)
286 } 286 }
diff --git a/crates/hir_ty/src/test_db.rs b/crates/hir_ty/src/test_db.rs
index 3bbcbc242..09696fcf4 100644
--- a/crates/hir_ty/src/test_db.rs
+++ b/crates/hir_ty/src/test_db.rs
@@ -83,7 +83,7 @@ impl TestDB {
83 let crate_def_map = self.crate_def_map(krate); 83 let crate_def_map = self.crate_def_map(krate);
84 for (local_id, data) in crate_def_map.modules() { 84 for (local_id, data) in crate_def_map.modules() {
85 if data.origin.file_id() == Some(file_id) { 85 if data.origin.file_id() == Some(file_id) {
86 return ModuleId { krate, local_id }; 86 return ModuleId::top_level(krate, local_id);
87 } 87 }
88 } 88 }
89 } 89 }
diff --git a/crates/hir_ty/src/tests.rs b/crates/hir_ty/src/tests.rs
index 4a3fcea8d..7386a4e7b 100644
--- a/crates/hir_ty/src/tests.rs
+++ b/crates/hir_ty/src/tests.rs
@@ -188,10 +188,10 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
188 }; 188 };
189 189
190 let module = db.module_for_file(file_id); 190 let module = db.module_for_file(file_id);
191 let crate_def_map = db.crate_def_map(module.krate); 191 let def_map = module.def_map(&db);
192 192
193 let mut defs: Vec<DefWithBodyId> = Vec::new(); 193 let mut defs: Vec<DefWithBodyId> = Vec::new();
194 visit_module(&db, &crate_def_map, module.local_id, &mut |it| defs.push(it)); 194 visit_module(&db, &def_map, module.local_id, &mut |it| defs.push(it));
195 defs.sort_by_key(|def| match def { 195 defs.sort_by_key(|def| match def {
196 DefWithBodyId::FunctionId(it) => { 196 DefWithBodyId::FunctionId(it) => {
197 let loc = it.lookup(&db); 197 let loc = it.lookup(&db);
@@ -321,7 +321,7 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() {
321 { 321 {
322 let events = db.log_executed(|| { 322 let events = db.log_executed(|| {
323 let module = db.module_for_file(pos.file_id); 323 let module = db.module_for_file(pos.file_id);
324 let crate_def_map = db.crate_def_map(module.krate); 324 let crate_def_map = module.def_map(&db);
325 visit_module(&db, &crate_def_map, module.local_id, &mut |def| { 325 visit_module(&db, &crate_def_map, module.local_id, &mut |def| {
326 db.infer(def); 326 db.infer(def);
327 }); 327 });
@@ -343,7 +343,7 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() {
343 { 343 {
344 let events = db.log_executed(|| { 344 let events = db.log_executed(|| {
345 let module = db.module_for_file(pos.file_id); 345 let module = db.module_for_file(pos.file_id);
346 let crate_def_map = db.crate_def_map(module.krate); 346 let crate_def_map = module.def_map(&db);
347 visit_module(&db, &crate_def_map, module.local_id, &mut |def| { 347 visit_module(&db, &crate_def_map, module.local_id, &mut |def| {
348 db.infer(def); 348 db.infer(def);
349 }); 349 });
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs
index 8d431b920..16682f76f 100644
--- a/crates/hir_ty/src/tests/simple.rs
+++ b/crates/hir_ty/src/tests/simple.rs
@@ -29,6 +29,30 @@ mod boxed {
29} 29}
30 30
31#[test] 31#[test]
32fn infer_box_with_allocator() {
33 check_types(
34 r#"
35//- /main.rs crate:main deps:std
36fn test() {
37 let x = box 1;
38 let t = (x, box x, box &1, box [1]);
39 t;
40} //^ (Box<i32, {unknown}>, Box<Box<i32, {unknown}>, {unknown}>, Box<&i32, {unknown}>, Box<[i32; _], {unknown}>)
41
42//- /std.rs crate:std
43#[prelude_import] use prelude::*;
44mod boxed {
45 #[lang = "owned_box"]
46 pub struct Box<T: ?Sized, A: Allocator> {
47 inner: *mut T,
48 allocator: A,
49 }
50}
51"#,
52 );
53}
54
55#[test]
32fn infer_adt_self() { 56fn infer_adt_self() {
33 check_types( 57 check_types(
34 r#" 58 r#"
diff --git a/crates/hir_ty/src/traits/chalk.rs b/crates/hir_ty/src/traits/chalk.rs
index 2196af677..cfb756158 100644
--- a/crates/hir_ty/src/traits/chalk.rs
+++ b/crates/hir_ty/src/traits/chalk.rs
@@ -426,7 +426,7 @@ pub(crate) fn trait_datum_query(
426 let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST); 426 let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST);
427 let flags = rust_ir::TraitFlags { 427 let flags = rust_ir::TraitFlags {
428 auto: trait_data.auto, 428 auto: trait_data.auto,
429 upstream: trait_.lookup(db.upcast()).container.module(db.upcast()).krate != krate, 429 upstream: trait_.lookup(db.upcast()).container.module(db.upcast()).krate() != krate,
430 non_enumerable: true, 430 non_enumerable: true,
431 coinductive: false, // only relevant for Chalk testing 431 coinductive: false, // only relevant for Chalk testing
432 // FIXME: set these flags correctly 432 // FIXME: set these flags correctly
@@ -549,7 +549,7 @@ fn impl_def_datum(
549 let generic_params = generics(db.upcast(), impl_id.into()); 549 let generic_params = generics(db.upcast(), impl_id.into());
550 let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST); 550 let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST);
551 let trait_ = trait_ref.trait_; 551 let trait_ = trait_ref.trait_;
552 let impl_type = if impl_id.lookup(db.upcast()).container.module(db.upcast()).krate == krate { 552 let impl_type = if impl_id.lookup(db.upcast()).container.module(db.upcast()).krate() == krate {
553 rust_ir::ImplType::Local 553 rust_ir::ImplType::Local
554 } else { 554 } else {
555 rust_ir::ImplType::External 555 rust_ir::ImplType::External
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs
index 9c568c90c..16fa828ad 100644
--- a/crates/ide/src/display/navigation_target.rs
+++ b/crates/ide/src/display/navigation_target.rs
@@ -7,6 +7,7 @@ use hir::{AssocItem, Documentation, FieldSource, HasAttrs, HasSource, InFile, Mo
7use ide_db::{ 7use ide_db::{
8 base_db::{FileId, FileRange, SourceDatabase}, 8 base_db::{FileId, FileRange, SourceDatabase},
9 symbol_index::FileSymbolKind, 9 symbol_index::FileSymbolKind,
10 SymbolKind,
10}; 11};
11use ide_db::{defs::Definition, RootDatabase}; 12use ide_db::{defs::Definition, RootDatabase};
12use syntax::{ 13use syntax::{
@@ -18,30 +19,6 @@ use crate::FileSymbol;
18 19
19use super::short_label::ShortLabel; 20use super::short_label::ShortLabel;
20 21
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
22pub enum SymbolKind {
23 Module,
24 Impl,
25 Field,
26 TypeParam,
27 ConstParam,
28 LifetimeParam,
29 ValueParam,
30 SelfParam,
31 Local,
32 Label,
33 Function,
34 Const,
35 Static,
36 Struct,
37 Enum,
38 Variant,
39 Union,
40 TypeAlias,
41 Trait,
42 Macro,
43}
44
45/// `NavigationTarget` represents and element in the editor's UI which you can 22/// `NavigationTarget` represents and element in the editor's UI which you can
46/// click on to navigate to a particular piece of code. 23/// click on to navigate to a particular piece of code.
47/// 24///
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs
index 1f08d7810..730e0dd0a 100644
--- a/crates/ide/src/doc_links.rs
+++ b/crates/ide/src/doc_links.rs
@@ -221,14 +221,31 @@ fn rewrite_intra_doc_link(
221 }?; 221 }?;
222 let krate = resolved.module(db)?.krate(); 222 let krate = resolved.module(db)?.krate();
223 let canonical_path = resolved.canonical_path(db)?; 223 let canonical_path = resolved.canonical_path(db)?;
224 let new_target = get_doc_url(db, &krate)? 224 let mut new_url = get_doc_url(db, &krate)?
225 .join(&format!("{}/", krate.display_name(db)?)) 225 .join(&format!("{}/", krate.display_name(db)?))
226 .ok()? 226 .ok()?
227 .join(&canonical_path.replace("::", "/")) 227 .join(&canonical_path.replace("::", "/"))
228 .ok()? 228 .ok()?
229 .join(&get_symbol_filename(db, &resolved)?) 229 .join(&get_symbol_filename(db, &resolved)?)
230 .ok()? 230 .ok()?;
231 .into_string(); 231
232 if let ModuleDef::Trait(t) = resolved {
233 let items = t.items(db);
234 if let Some(field_or_assoc_item) = items.iter().find_map(|assoc_item| {
235 if let Some(name) = assoc_item.name(db) {
236 if link.to_string() == format!("{}::{}", canonical_path, name) {
237 return Some(FieldOrAssocItem::AssocItem(*assoc_item));
238 }
239 }
240 None
241 }) {
242 if let Some(fragment) = get_symbol_fragment(db, &field_or_assoc_item) {
243 new_url = new_url.join(&fragment).ok()?;
244 }
245 };
246 }
247
248 let new_target = new_url.into_string();
232 let new_title = strip_prefixes_suffixes(title); 249 let new_title = strip_prefixes_suffixes(title);
233 Some((new_target, new_title.to_string())) 250 Some((new_target, new_title.to_string()))
234} 251}
diff --git a/crates/ide/src/file_structure.rs b/crates/ide/src/file_structure.rs
index 32556dad3..26793bdb4 100644
--- a/crates/ide/src/file_structure.rs
+++ b/crates/ide/src/file_structure.rs
@@ -1,10 +1,9 @@
1use ide_db::SymbolKind;
1use syntax::{ 2use syntax::{
2 ast::{self, AttrsOwner, GenericParamsOwner, NameOwner}, 3 ast::{self, AttrsOwner, GenericParamsOwner, NameOwner},
3 match_ast, AstNode, SourceFile, SyntaxNode, TextRange, WalkEvent, 4 match_ast, AstNode, SourceFile, SyntaxNode, TextRange, WalkEvent,
4}; 5};
5 6
6use crate::SymbolKind;
7
8#[derive(Debug, Clone)] 7#[derive(Debug, Clone)]
9pub struct StructureNode { 8pub struct StructureNode {
10 pub parent: Option<usize>, 9 pub parent: Option<usize>,
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index a1d2bce1d..1a997fa40 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -2,16 +2,14 @@ use either::Either;
2use hir::{HasAttrs, ModuleDef, Semantics}; 2use hir::{HasAttrs, ModuleDef, Semantics};
3use ide_db::{ 3use ide_db::{
4 defs::{Definition, NameClass, NameRefClass}, 4 defs::{Definition, NameClass, NameRefClass},
5 symbol_index, RootDatabase, 5 RootDatabase,
6}; 6};
7use syntax::{ 7use syntax::{
8 ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, TextSize, TokenAtOffset, T, 8 ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, TextSize, TokenAtOffset, T,
9}; 9};
10 10
11use crate::{ 11use crate::{
12 display::{ToNav, TryToNav}, 12 display::TryToNav, doc_links::extract_definitions_from_markdown, runnables::doc_owner_to_def,
13 doc_links::extract_definitions_from_markdown,
14 runnables::doc_owner_to_def,
15 FilePosition, NavigationTarget, RangeInfo, 13 FilePosition, NavigationTarget, RangeInfo,
16}; 14};
17 15
@@ -38,28 +36,26 @@ pub(crate) fn goto_definition(
38 return Some(RangeInfo::new(original_token.text_range(), vec![nav])); 36 return Some(RangeInfo::new(original_token.text_range(), vec![nav]));
39 } 37 }
40 38
41 let nav_targets = match_ast! { 39 let nav = match_ast! {
42 match parent { 40 match parent {
43 ast::NameRef(name_ref) => { 41 ast::NameRef(name_ref) => {
44 reference_definition(&sema, Either::Right(&name_ref)).to_vec() 42 reference_definition(&sema, Either::Right(&name_ref))
45 }, 43 },
46 ast::Name(name) => { 44 ast::Name(name) => {
47 let def = NameClass::classify(&sema, &name)?.referenced_or_defined(sema.db); 45 let def = NameClass::classify(&sema, &name)?.referenced_or_defined(sema.db);
48 let nav = def.try_to_nav(sema.db)?; 46 def.try_to_nav(sema.db)
49 vec![nav]
50 }, 47 },
51 ast::Lifetime(lt) => if let Some(name_class) = NameClass::classify_lifetime(&sema, &lt) { 48 ast::Lifetime(lt) => if let Some(name_class) = NameClass::classify_lifetime(&sema, &lt) {
52 let def = name_class.referenced_or_defined(sema.db); 49 let def = name_class.referenced_or_defined(sema.db);
53 let nav = def.try_to_nav(sema.db)?; 50 def.try_to_nav(sema.db)
54 vec![nav]
55 } else { 51 } else {
56 reference_definition(&sema, Either::Left(&lt)).to_vec() 52 reference_definition(&sema, Either::Left(&lt))
57 }, 53 },
58 _ => return None, 54 _ => return None,
59 } 55 }
60 }; 56 };
61 57
62 Some(RangeInfo::new(original_token.text_range(), nav_targets)) 58 Some(RangeInfo::new(original_token.text_range(), nav.into_iter().collect()))
63} 59}
64 60
65fn def_for_doc_comment( 61fn def_for_doc_comment(
@@ -120,42 +116,16 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
120 } 116 }
121} 117}
122 118
123#[derive(Debug)]
124pub(crate) enum ReferenceResult {
125 Exact(NavigationTarget),
126 Approximate(Vec<NavigationTarget>),
127}
128
129impl ReferenceResult {
130 fn to_vec(self) -> Vec<NavigationTarget> {
131 match self {
132 ReferenceResult::Exact(target) => vec![target],
133 ReferenceResult::Approximate(vec) => vec,
134 }
135 }
136}
137
138pub(crate) fn reference_definition( 119pub(crate) fn reference_definition(
139 sema: &Semantics<RootDatabase>, 120 sema: &Semantics<RootDatabase>,
140 name_ref: Either<&ast::Lifetime, &ast::NameRef>, 121 name_ref: Either<&ast::Lifetime, &ast::NameRef>,
141) -> ReferenceResult { 122) -> Option<NavigationTarget> {
142 let name_kind = name_ref.either( 123 let name_kind = name_ref.either(
143 |lifetime| NameRefClass::classify_lifetime(sema, lifetime), 124 |lifetime| NameRefClass::classify_lifetime(sema, lifetime),
144 |name_ref| NameRefClass::classify(sema, name_ref), 125 |name_ref| NameRefClass::classify(sema, name_ref),
145 ); 126 )?;
146 if let Some(def) = name_kind { 127 let def = name_kind.referenced(sema.db);
147 let def = def.referenced(sema.db); 128 def.try_to_nav(sema.db)
148 return match def.try_to_nav(sema.db) {
149 Some(nav) => ReferenceResult::Exact(nav),
150 None => ReferenceResult::Approximate(Vec::new()),
151 };
152 }
153
154 // Fallback index based approach:
155 let name = name_ref.either(ast::Lifetime::text, ast::NameRef::text);
156 let navs =
157 symbol_index::index_resolve(sema.db, name).into_iter().map(|s| s.to_nav(sema.db)).collect();
158 ReferenceResult::Approximate(navs)
159} 129}
160 130
161#[cfg(test)] 131#[cfg(test)]
@@ -192,12 +162,12 @@ mod tests {
192 fn goto_def_for_extern_crate() { 162 fn goto_def_for_extern_crate() {
193 check( 163 check(
194 r#" 164 r#"
195 //- /main.rs crate:main deps:std 165//- /main.rs crate:main deps:std
196 extern crate std$0; 166extern crate std$0;
197 //- /std/lib.rs crate:std 167//- /std/lib.rs crate:std
198 // empty 168// empty
199 //^ file 169//^ file
200 "#, 170"#,
201 ) 171 )
202 } 172 }
203 173
@@ -205,12 +175,12 @@ mod tests {
205 fn goto_def_for_renamed_extern_crate() { 175 fn goto_def_for_renamed_extern_crate() {
206 check( 176 check(
207 r#" 177 r#"
208 //- /main.rs crate:main deps:std 178//- /main.rs crate:main deps:std
209 extern crate std as abc$0; 179extern crate std as abc$0;
210 //- /std/lib.rs crate:std 180//- /std/lib.rs crate:std
211 // empty 181// empty
212 //^ file 182//^ file
213 "#, 183"#,
214 ) 184 )
215 } 185 }
216 186
@@ -297,13 +267,13 @@ fn bar() {
297 fn goto_def_for_macros_from_other_crates() { 267 fn goto_def_for_macros_from_other_crates() {
298 check( 268 check(
299 r#" 269 r#"
300//- /lib.rs 270//- /lib.rs crate:main deps:foo
301use foo::foo; 271use foo::foo;
302fn bar() { 272fn bar() {
303 $0foo!(); 273 $0foo!();
304} 274}
305 275
306//- /foo/lib.rs 276//- /foo/lib.rs crate:foo
307#[macro_export] 277#[macro_export]
308macro_rules! foo { () => { () } } 278macro_rules! foo { () => { () } }
309 //^^^ 279 //^^^
@@ -315,10 +285,10 @@ macro_rules! foo { () => { () } }
315 fn goto_def_for_macros_in_use_tree() { 285 fn goto_def_for_macros_in_use_tree() {
316 check( 286 check(
317 r#" 287 r#"
318//- /lib.rs 288//- /lib.rs crate:main deps:foo
319use foo::foo$0; 289use foo::foo$0;
320 290
321//- /foo/lib.rs 291//- /foo/lib.rs crate:foo
322#[macro_export] 292#[macro_export]
323macro_rules! foo { () => { () } } 293macro_rules! foo { () => { () } }
324 //^^^ 294 //^^^
@@ -976,10 +946,10 @@ type Alias<T> = T$0;
976 fn goto_def_for_macro_container() { 946 fn goto_def_for_macro_container() {
977 check( 947 check(
978 r#" 948 r#"
979//- /lib.rs 949//- /lib.rs crate:main deps:foo
980foo::module$0::mac!(); 950foo::module$0::mac!();
981 951
982//- /foo/lib.rs 952//- /foo/lib.rs crate:foo
983pub mod module { 953pub mod module {
984 //^^^^^^ 954 //^^^^^^
985 #[macro_export] 955 #[macro_export]
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index ec1631486..d47a4cb0f 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -1826,6 +1826,35 @@ pub struct B$0ar
1826 "#]], 1826 "#]],
1827 ); 1827 );
1828 } 1828 }
1829 #[test]
1830 fn test_hover_intra_link_reference_to_trait_method() {
1831 check(
1832 r#"
1833pub trait Foo {
1834 fn buzz() -> usize;
1835}
1836/// [Foo][buzz]
1837///
1838/// [buzz]: Foo::buzz
1839pub struct B$0ar
1840"#,
1841 expect![[r#"
1842 *Bar*
1843
1844 ```rust
1845 test
1846 ```
1847
1848 ```rust
1849 pub struct Bar
1850 ```
1851
1852 ---
1853
1854 [Foo](https://docs.rs/test/*/test/trait.Foo.html#tymethod.buzz)
1855 "#]],
1856 );
1857 }
1829 1858
1830 #[test] 1859 #[test]
1831 fn test_hover_external_url() { 1860 fn test_hover_external_url() {
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 567b8117e..989e94a31 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -65,7 +65,7 @@ use crate::display::ToNav;
65pub use crate::{ 65pub use crate::{
66 call_hierarchy::CallItem, 66 call_hierarchy::CallItem,
67 diagnostics::{Diagnostic, DiagnosticsConfig, Fix, Severity}, 67 diagnostics::{Diagnostic, DiagnosticsConfig, Fix, Severity},
68 display::navigation_target::{NavigationTarget, SymbolKind}, 68 display::navigation_target::NavigationTarget,
69 expand_macro::ExpandedMacro, 69 expand_macro::ExpandedMacro,
70 file_structure::StructureNode, 70 file_structure::StructureNode,
71 folding_ranges::{Fold, FoldKind}, 71 folding_ranges::{Fold, FoldKind},
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs
index 975abf47f..33170906d 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -3,7 +3,7 @@ use std::fmt;
3use assists::utils::test_related_attribute; 3use assists::utils::test_related_attribute;
4use cfg::CfgExpr; 4use cfg::CfgExpr;
5use hir::{AsAssocItem, HasAttrs, HasSource, Semantics}; 5use hir::{AsAssocItem, HasAttrs, HasSource, Semantics};
6use ide_db::{defs::Definition, RootDatabase}; 6use ide_db::{defs::Definition, RootDatabase, SymbolKind};
7use itertools::Itertools; 7use itertools::Itertools;
8use syntax::{ 8use syntax::{
9 ast::{self, AstNode, AttrsOwner}, 9 ast::{self, AstNode, AttrsOwner},
@@ -13,7 +13,7 @@ use test_utils::mark;
13 13
14use crate::{ 14use crate::{
15 display::{ToNav, TryToNav}, 15 display::{ToNav, TryToNav},
16 FileId, NavigationTarget, SymbolKind, 16 FileId, NavigationTarget,
17}; 17};
18 18
19#[derive(Debug, Clone)] 19#[derive(Debug, Clone)]
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index f2d4da78d..a3d4e4f77 100644
--- a/crates/ide/src/syntax_highlighting.rs
+++ b/crates/ide/src/syntax_highlighting.rs
@@ -13,7 +13,7 @@ mod html;
13mod tests; 13mod tests;
14 14
15use hir::{Name, Semantics}; 15use hir::{Name, Semantics};
16use ide_db::RootDatabase; 16use ide_db::{RootDatabase, SymbolKind};
17use rustc_hash::FxHashMap; 17use rustc_hash::FxHashMap;
18use syntax::{ 18use syntax::{
19 ast::{self, HasFormatSpecifier}, 19 ast::{self, HasFormatSpecifier},
@@ -27,7 +27,7 @@ use crate::{
27 format::highlight_format_string, highlights::Highlights, 27 format::highlight_format_string, highlights::Highlights,
28 macro_rules::MacroRulesHighlighter, tags::Highlight, 28 macro_rules::MacroRulesHighlighter, tags::Highlight,
29 }, 29 },
30 FileId, HlMod, HlTag, SymbolKind, 30 FileId, HlMod, HlTag,
31}; 31};
32 32
33pub(crate) use html::highlight_as_html; 33pub(crate) use html::highlight_as_html;
diff --git a/crates/ide/src/syntax_highlighting/format.rs b/crates/ide/src/syntax_highlighting/format.rs
index 8a9b5ca8c..8c67a0863 100644
--- a/crates/ide/src/syntax_highlighting/format.rs
+++ b/crates/ide/src/syntax_highlighting/format.rs
@@ -1,10 +1,11 @@
1//! Syntax highlighting for format macro strings. 1//! Syntax highlighting for format macro strings.
2use ide_db::SymbolKind;
2use syntax::{ 3use syntax::{
3 ast::{self, FormatSpecifier, HasFormatSpecifier}, 4 ast::{self, FormatSpecifier, HasFormatSpecifier},
4 AstNode, AstToken, TextRange, 5 AstNode, AstToken, TextRange,
5}; 6};
6 7
7use crate::{syntax_highlighting::highlights::Highlights, HlRange, HlTag, SymbolKind}; 8use crate::{syntax_highlighting::highlights::Highlights, HlRange, HlTag};
8 9
9pub(super) fn highlight_format_string( 10pub(super) fn highlight_format_string(
10 stack: &mut Highlights, 11 stack: &mut Highlights,
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs
index 8625ef5df..24fcbb584 100644
--- a/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/crates/ide/src/syntax_highlighting/highlight.rs
@@ -3,7 +3,7 @@
3use hir::{AsAssocItem, Semantics, VariantDef}; 3use hir::{AsAssocItem, Semantics, VariantDef};
4use ide_db::{ 4use ide_db::{
5 defs::{Definition, NameClass, NameRefClass}, 5 defs::{Definition, NameClass, NameRefClass},
6 RootDatabase, 6 RootDatabase, SymbolKind,
7}; 7};
8use rustc_hash::FxHashMap; 8use rustc_hash::FxHashMap;
9use syntax::{ 9use syntax::{
@@ -12,7 +12,7 @@ use syntax::{
12 SyntaxNode, SyntaxToken, T, 12 SyntaxNode, SyntaxToken, T,
13}; 13};
14 14
15use crate::{syntax_highlighting::tags::HlPunct, Highlight, HlMod, HlTag, SymbolKind}; 15use crate::{syntax_highlighting::tags::HlPunct, Highlight, HlMod, HlTag};
16 16
17pub(super) fn element( 17pub(super) fn element(
18 sema: &Semantics<RootDatabase>, 18 sema: &Semantics<RootDatabase>,
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs
index 8dd05ac52..3c02fdb11 100644
--- a/crates/ide/src/syntax_highlighting/tags.rs
+++ b/crates/ide/src/syntax_highlighting/tags.rs
@@ -3,7 +3,7 @@
3 3
4use std::{fmt, ops}; 4use std::{fmt, ops};
5 5
6use crate::SymbolKind; 6use ide_db::SymbolKind;
7 7
8#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] 8#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
9pub struct Highlight { 9pub struct Highlight {
diff --git a/crates/ide_db/src/lib.rs b/crates/ide_db/src/lib.rs
index 118c090d7..6eb34b06b 100644
--- a/crates/ide_db/src/lib.rs
+++ b/crates/ide_db/src/lib.rs
@@ -134,3 +134,27 @@ fn line_index(db: &dyn LineIndexDatabase, file_id: FileId) -> Arc<LineIndex> {
134 let text = db.file_text(file_id); 134 let text = db.file_text(file_id);
135 Arc::new(LineIndex::new(&*text)) 135 Arc::new(LineIndex::new(&*text))
136} 136}
137
138#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
139pub enum SymbolKind {
140 Const,
141 ConstParam,
142 Enum,
143 Field,
144 Function,
145 Impl,
146 Label,
147 LifetimeParam,
148 Local,
149 Macro,
150 Module,
151 SelfParam,
152 Static,
153 Struct,
154 Trait,
155 TypeAlias,
156 TypeParam,
157 Union,
158 ValueParam,
159 Variant,
160}
diff --git a/crates/project_model/src/build_data.rs b/crates/project_model/src/build_data.rs
new file mode 100644
index 000000000..cf32995e0
--- /dev/null
+++ b/crates/project_model/src/build_data.rs
@@ -0,0 +1,206 @@
1//! Handles build script specific information
2
3use std::{
4 ffi::OsStr,
5 io::BufReader,
6 path::{Path, PathBuf},
7 process::{Command, Stdio},
8};
9
10use anyhow::Result;
11use cargo_metadata::{BuildScript, Message, Package, PackageId};
12use itertools::Itertools;
13use paths::{AbsPath, AbsPathBuf};
14use rustc_hash::FxHashMap;
15use stdx::JodChild;
16
17use crate::{cfg_flag::CfgFlag, CargoConfig};
18
19#[derive(Debug, Clone, Default)]
20pub(crate) struct BuildDataMap {
21 data: FxHashMap<PackageId, BuildData>,
22}
23#[derive(Debug, Clone, Default, PartialEq, Eq)]
24pub struct BuildData {
25 /// List of config flags defined by this package's build script
26 pub cfgs: Vec<CfgFlag>,
27 /// List of cargo-related environment variables with their value
28 ///
29 /// If the package has a build script which defines environment variables,
30 /// they can also be found here.
31 pub envs: Vec<(String, String)>,
32 /// Directory where a build script might place its output
33 pub out_dir: Option<AbsPathBuf>,
34 /// Path to the proc-macro library file if this package exposes proc-macros
35 pub proc_macro_dylib_path: Option<AbsPathBuf>,
36}
37
38impl BuildDataMap {
39 pub(crate) fn new(
40 cargo_toml: &AbsPath,
41 cargo_features: &CargoConfig,
42 packages: &Vec<Package>,
43 progress: &dyn Fn(String),
44 ) -> Result<BuildDataMap> {
45 let mut cmd = Command::new(toolchain::cargo());
46 cmd.args(&["check", "--workspace", "--message-format=json", "--manifest-path"])
47 .arg(cargo_toml.as_ref());
48
49 // --all-targets includes tests, benches and examples in addition to the
50 // default lib and bins. This is an independent concept from the --targets
51 // flag below.
52 cmd.arg("--all-targets");
53
54 if let Some(target) = &cargo_features.target {
55 cmd.args(&["--target", target]);
56 }
57
58 if cargo_features.all_features {
59 cmd.arg("--all-features");
60 } else {
61 if cargo_features.no_default_features {
62 // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures`
63 // https://github.com/oli-obk/cargo_metadata/issues/79
64 cmd.arg("--no-default-features");
65 }
66 if !cargo_features.features.is_empty() {
67 cmd.arg("--features");
68 cmd.arg(cargo_features.features.join(" "));
69 }
70 }
71
72 cmd.stdout(Stdio::piped()).stderr(Stdio::null()).stdin(Stdio::null());
73
74 let mut child = cmd.spawn().map(JodChild)?;
75 let child_stdout = child.stdout.take().unwrap();
76 let stdout = BufReader::new(child_stdout);
77
78 let mut res = BuildDataMap::default();
79 for message in cargo_metadata::Message::parse_stream(stdout) {
80 if let Ok(message) = message {
81 match message {
82 Message::BuildScriptExecuted(BuildScript {
83 package_id,
84 out_dir,
85 cfgs,
86 env,
87 ..
88 }) => {
89 let cfgs = {
90 let mut acc = Vec::new();
91 for cfg in cfgs {
92 match cfg.parse::<CfgFlag>() {
93 Ok(it) => acc.push(it),
94 Err(err) => {
95 anyhow::bail!("invalid cfg from cargo-metadata: {}", err)
96 }
97 };
98 }
99 acc
100 };
101 let res = res.data.entry(package_id.clone()).or_default();
102 // cargo_metadata crate returns default (empty) path for
103 // older cargos, which is not absolute, so work around that.
104 if out_dir != PathBuf::default() {
105 let out_dir = AbsPathBuf::assert(out_dir);
106 res.out_dir = Some(out_dir);
107 res.cfgs = cfgs;
108 }
109
110 res.envs = env;
111 }
112 Message::CompilerArtifact(message) => {
113 progress(format!("metadata {}", message.target.name));
114
115 if message.target.kind.contains(&"proc-macro".to_string()) {
116 let package_id = message.package_id;
117 // Skip rmeta file
118 if let Some(filename) =
119 message.filenames.iter().find(|name| is_dylib(name))
120 {
121 let filename = AbsPathBuf::assert(filename.clone());
122 let res = res.data.entry(package_id.clone()).or_default();
123 res.proc_macro_dylib_path = Some(filename);
124 }
125 }
126 }
127 Message::CompilerMessage(message) => {
128 progress(message.target.name.clone());
129 }
130 Message::Unknown => (),
131 Message::BuildFinished(_) => {}
132 Message::TextLine(_) => {}
133 }
134 }
135 }
136 res.inject_cargo_env(packages);
137 Ok(res)
138 }
139
140 pub(crate) fn with_cargo_env(packages: &Vec<Package>) -> Self {
141 let mut res = Self::default();
142 res.inject_cargo_env(packages);
143 res
144 }
145
146 pub(crate) fn get(&self, id: &PackageId) -> Option<&BuildData> {
147 self.data.get(id)
148 }
149
150 fn inject_cargo_env(&mut self, packages: &Vec<Package>) {
151 for meta_pkg in packages {
152 let resource = self.data.entry(meta_pkg.id.clone()).or_default();
153 inject_cargo_env(meta_pkg, &mut resource.envs);
154
155 if let Some(out_dir) = &resource.out_dir {
156 // NOTE: cargo and rustc seem to hide non-UTF-8 strings from env! and option_env!()
157 if let Some(out_dir) = out_dir.to_str().map(|s| s.to_owned()) {
158 resource.envs.push(("OUT_DIR".to_string(), out_dir));
159 }
160 }
161 }
162 }
163}
164
165// FIXME: File a better way to know if it is a dylib
166fn is_dylib(path: &Path) -> bool {
167 match path.extension().and_then(OsStr::to_str).map(|it| it.to_string().to_lowercase()) {
168 None => false,
169 Some(ext) => matches!(ext.as_str(), "dll" | "dylib" | "so"),
170 }
171}
172
173/// Recreates the compile-time environment variables that Cargo sets.
174///
175/// Should be synced with <https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates>
176fn inject_cargo_env(package: &cargo_metadata::Package, env: &mut Vec<(String, String)>) {
177 // FIXME: Missing variables:
178 // CARGO, CARGO_PKG_HOMEPAGE, CARGO_CRATE_NAME, CARGO_BIN_NAME, CARGO_BIN_EXE_<name>
179
180 let mut manifest_dir = package.manifest_path.clone();
181 manifest_dir.pop();
182 if let Some(cargo_manifest_dir) = manifest_dir.to_str() {
183 env.push(("CARGO_MANIFEST_DIR".into(), cargo_manifest_dir.into()));
184 }
185
186 env.push(("CARGO_PKG_VERSION".into(), package.version.to_string()));
187 env.push(("CARGO_PKG_VERSION_MAJOR".into(), package.version.major.to_string()));
188 env.push(("CARGO_PKG_VERSION_MINOR".into(), package.version.minor.to_string()));
189 env.push(("CARGO_PKG_VERSION_PATCH".into(), package.version.patch.to_string()));
190
191 let pre = package.version.pre.iter().map(|id| id.to_string()).format(".");
192 env.push(("CARGO_PKG_VERSION_PRE".into(), pre.to_string()));
193
194 let authors = package.authors.join(";");
195 env.push(("CARGO_PKG_AUTHORS".into(), authors));
196
197 env.push(("CARGO_PKG_NAME".into(), package.name.clone()));
198 env.push(("CARGO_PKG_DESCRIPTION".into(), package.description.clone().unwrap_or_default()));
199 //env.push(("CARGO_PKG_HOMEPAGE".into(), package.homepage.clone().unwrap_or_default()));
200 env.push(("CARGO_PKG_REPOSITORY".into(), package.repository.clone().unwrap_or_default()));
201 env.push(("CARGO_PKG_LICENSE".into(), package.license.clone().unwrap_or_default()));
202
203 let license_file =
204 package.license_file.as_ref().map(|buf| buf.display().to_string()).unwrap_or_default();
205 env.push(("CARGO_PKG_LICENSE_FILE".into(), license_file));
206}
diff --git a/crates/project_model/src/cargo_workspace.rs b/crates/project_model/src/cargo_workspace.rs
index a09e1a9ff..c8a5333c4 100644
--- a/crates/project_model/src/cargo_workspace.rs
+++ b/crates/project_model/src/cargo_workspace.rs
@@ -1,24 +1,15 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use std::{ 3use std::{convert::TryInto, ops, process::Command};
4 convert::TryInto,
5 ffi::OsStr,
6 io::BufReader,
7 ops,
8 path::{Path, PathBuf},
9 process::{Command, Stdio},
10};
11 4
12use anyhow::{Context, Result}; 5use anyhow::{Context, Result};
13use base_db::Edition; 6use base_db::Edition;
14use cargo_metadata::{BuildScript, CargoOpt, Message, MetadataCommand, PackageId}; 7use cargo_metadata::{CargoOpt, MetadataCommand};
15use itertools::Itertools;
16use la_arena::{Arena, Idx}; 8use la_arena::{Arena, Idx};
17use paths::{AbsPath, AbsPathBuf}; 9use paths::{AbsPath, AbsPathBuf};
18use rustc_hash::FxHashMap; 10use rustc_hash::FxHashMap;
19use stdx::JodChild;
20 11
21use crate::cfg_flag::CfgFlag; 12use crate::build_data::{BuildData, BuildDataMap};
22use crate::utf8_stdout; 13use crate::utf8_stdout;
23 14
24/// `CargoWorkspace` represents the logical structure of, well, a Cargo 15/// `CargoWorkspace` represents the logical structure of, well, a Cargo
@@ -103,17 +94,8 @@ pub struct PackageData {
103 pub features: FxHashMap<String, Vec<String>>, 94 pub features: FxHashMap<String, Vec<String>>,
104 /// List of features enabled on this package 95 /// List of features enabled on this package
105 pub active_features: Vec<String>, 96 pub active_features: Vec<String>,
106 /// List of config flags defined by this package's build script 97 /// Build script related data for this package
107 pub cfgs: Vec<CfgFlag>, 98 pub build_data: BuildData,
108 /// List of cargo-related environment variables with their value
109 ///
110 /// If the package has a build script which defines environment variables,
111 /// they can also be found here.
112 pub envs: Vec<(String, String)>,
113 /// Directory where a build script might place its output
114 pub out_dir: Option<AbsPathBuf>,
115 /// Path to the proc-macro library file if this package exposes proc-macros
116 pub proc_macro_dylib_path: Option<AbsPathBuf>,
117} 99}
118 100
119#[derive(Debug, Clone, Eq, PartialEq)] 101#[derive(Debug, Clone, Eq, PartialEq)]
@@ -246,17 +228,11 @@ impl CargoWorkspace {
246 ) 228 )
247 })?; 229 })?;
248 230
249 let mut out_dir_by_id = FxHashMap::default(); 231 let resources = if config.load_out_dirs_from_check {
250 let mut cfgs = FxHashMap::default(); 232 BuildDataMap::new(cargo_toml, config, &meta.packages, progress)?
251 let mut envs = FxHashMap::default(); 233 } else {
252 let mut proc_macro_dylib_paths = FxHashMap::default(); 234 BuildDataMap::with_cargo_env(&meta.packages)
253 if config.load_out_dirs_from_check { 235 };
254 let resources = load_extern_resources(cargo_toml, config, progress)?;
255 out_dir_by_id = resources.out_dirs;
256 cfgs = resources.cfgs;
257 envs = resources.env;
258 proc_macro_dylib_paths = resources.proc_dylib_paths;
259 }
260 236
261 let mut pkg_by_id = FxHashMap::default(); 237 let mut pkg_by_id = FxHashMap::default();
262 let mut packages = Arena::default(); 238 let mut packages = Arena::default();
@@ -267,7 +243,7 @@ impl CargoWorkspace {
267 meta.packages.sort_by(|a, b| a.id.cmp(&b.id)); 243 meta.packages.sort_by(|a, b| a.id.cmp(&b.id));
268 for meta_pkg in meta.packages { 244 for meta_pkg in meta.packages {
269 let id = meta_pkg.id.clone(); 245 let id = meta_pkg.id.clone();
270 inject_cargo_env(&meta_pkg, envs.entry(id).or_default()); 246 let build_data = resources.get(&id).cloned().unwrap_or_default();
271 247
272 let cargo_metadata::Package { id, edition, name, manifest_path, version, .. } = 248 let cargo_metadata::Package { id, edition, name, manifest_path, version, .. } =
273 meta_pkg; 249 meta_pkg;
@@ -285,10 +261,7 @@ impl CargoWorkspace {
285 dependencies: Vec::new(), 261 dependencies: Vec::new(),
286 features: meta_pkg.features.into_iter().collect(), 262 features: meta_pkg.features.into_iter().collect(),
287 active_features: Vec::new(), 263 active_features: Vec::new(),
288 cfgs: cfgs.get(&id).cloned().unwrap_or_default(), 264 build_data,
289 envs: envs.get(&id).cloned().unwrap_or_default(),
290 out_dir: out_dir_by_id.get(&id).cloned(),
291 proc_macro_dylib_path: proc_macro_dylib_paths.get(&id).cloned(),
292 }); 265 });
293 let pkg_data = &mut packages[pkg]; 266 let pkg_data = &mut packages[pkg];
294 pkg_by_id.insert(id, pkg); 267 pkg_by_id.insert(id, pkg);
@@ -365,149 +338,3 @@ impl CargoWorkspace {
365 self.packages.iter().filter(|(_, v)| v.name == name).count() == 1 338 self.packages.iter().filter(|(_, v)| v.name == name).count() == 1
366 } 339 }
367} 340}
368
369#[derive(Debug, Clone, Default)]
370pub(crate) struct ExternResources {
371 out_dirs: FxHashMap<PackageId, AbsPathBuf>,
372 proc_dylib_paths: FxHashMap<PackageId, AbsPathBuf>,
373 cfgs: FxHashMap<PackageId, Vec<CfgFlag>>,
374 env: FxHashMap<PackageId, Vec<(String, String)>>,
375}
376
377pub(crate) fn load_extern_resources(
378 cargo_toml: &Path,
379 cargo_features: &CargoConfig,
380 progress: &dyn Fn(String),
381) -> Result<ExternResources> {
382 let mut cmd = Command::new(toolchain::cargo());
383 cmd.args(&["check", "--workspace", "--message-format=json", "--manifest-path"]).arg(cargo_toml);
384
385 // --all-targets includes tests, benches and examples in addition to the
386 // default lib and bins. This is an independent concept from the --targets
387 // flag below.
388 cmd.arg("--all-targets");
389
390 if let Some(target) = &cargo_features.target {
391 cmd.args(&["--target", target]);
392 }
393
394 if cargo_features.all_features {
395 cmd.arg("--all-features");
396 } else {
397 if cargo_features.no_default_features {
398 // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures`
399 // https://github.com/oli-obk/cargo_metadata/issues/79
400 cmd.arg("--no-default-features");
401 }
402 if !cargo_features.features.is_empty() {
403 cmd.arg("--features");
404 cmd.arg(cargo_features.features.join(" "));
405 }
406 }
407
408 cmd.stdout(Stdio::piped()).stderr(Stdio::null()).stdin(Stdio::null());
409
410 let mut child = cmd.spawn().map(JodChild)?;
411 let child_stdout = child.stdout.take().unwrap();
412 let stdout = BufReader::new(child_stdout);
413
414 let mut res = ExternResources::default();
415 for message in cargo_metadata::Message::parse_stream(stdout) {
416 if let Ok(message) = message {
417 match message {
418 Message::BuildScriptExecuted(BuildScript {
419 package_id,
420 out_dir,
421 cfgs,
422 env,
423 ..
424 }) => {
425 let cfgs = {
426 let mut acc = Vec::new();
427 for cfg in cfgs {
428 match cfg.parse::<CfgFlag>() {
429 Ok(it) => acc.push(it),
430 Err(err) => {
431 anyhow::bail!("invalid cfg from cargo-metadata: {}", err)
432 }
433 };
434 }
435 acc
436 };
437 // cargo_metadata crate returns default (empty) path for
438 // older cargos, which is not absolute, so work around that.
439 if out_dir != PathBuf::default() {
440 let out_dir = AbsPathBuf::assert(out_dir);
441 res.out_dirs.insert(package_id.clone(), out_dir);
442 res.cfgs.insert(package_id.clone(), cfgs);
443 }
444
445 res.env.insert(package_id, env);
446 }
447 Message::CompilerArtifact(message) => {
448 progress(format!("metadata {}", message.target.name));
449
450 if message.target.kind.contains(&"proc-macro".to_string()) {
451 let package_id = message.package_id;
452 // Skip rmeta file
453 if let Some(filename) = message.filenames.iter().find(|name| is_dylib(name))
454 {
455 let filename = AbsPathBuf::assert(filename.clone());
456 res.proc_dylib_paths.insert(package_id, filename);
457 }
458 }
459 }
460 Message::CompilerMessage(message) => {
461 progress(message.target.name.clone());
462 }
463 Message::Unknown => (),
464 Message::BuildFinished(_) => {}
465 Message::TextLine(_) => {}
466 }
467 }
468 }
469 Ok(res)
470}
471
472// FIXME: File a better way to know if it is a dylib
473fn is_dylib(path: &Path) -> bool {
474 match path.extension().and_then(OsStr::to_str).map(|it| it.to_string().to_lowercase()) {
475 None => false,
476 Some(ext) => matches!(ext.as_str(), "dll" | "dylib" | "so"),
477 }
478}
479
480/// Recreates the compile-time environment variables that Cargo sets.
481///
482/// Should be synced with <https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates>
483fn inject_cargo_env(package: &cargo_metadata::Package, env: &mut Vec<(String, String)>) {
484 // FIXME: Missing variables:
485 // CARGO, CARGO_PKG_HOMEPAGE, CARGO_CRATE_NAME, CARGO_BIN_NAME, CARGO_BIN_EXE_<name>
486
487 let mut manifest_dir = package.manifest_path.clone();
488 manifest_dir.pop();
489 if let Some(cargo_manifest_dir) = manifest_dir.to_str() {
490 env.push(("CARGO_MANIFEST_DIR".into(), cargo_manifest_dir.into()));
491 }
492
493 env.push(("CARGO_PKG_VERSION".into(), package.version.to_string()));
494 env.push(("CARGO_PKG_VERSION_MAJOR".into(), package.version.major.to_string()));
495 env.push(("CARGO_PKG_VERSION_MINOR".into(), package.version.minor.to_string()));
496 env.push(("CARGO_PKG_VERSION_PATCH".into(), package.version.patch.to_string()));
497
498 let pre = package.version.pre.iter().map(|id| id.to_string()).format(".");
499 env.push(("CARGO_PKG_VERSION_PRE".into(), pre.to_string()));
500
501 let authors = package.authors.join(";");
502 env.push(("CARGO_PKG_AUTHORS".into(), authors));
503
504 env.push(("CARGO_PKG_NAME".into(), package.name.clone()));
505 env.push(("CARGO_PKG_DESCRIPTION".into(), package.description.clone().unwrap_or_default()));
506 //env.push(("CARGO_PKG_HOMEPAGE".into(), package.homepage.clone().unwrap_or_default()));
507 env.push(("CARGO_PKG_REPOSITORY".into(), package.repository.clone().unwrap_or_default()));
508 env.push(("CARGO_PKG_LICENSE".into(), package.license.clone().unwrap_or_default()));
509
510 let license_file =
511 package.license_file.as_ref().map(|buf| buf.display().to_string()).unwrap_or_default();
512 env.push(("CARGO_PKG_LICENSE_FILE".into(), license_file));
513}
diff --git a/crates/project_model/src/lib.rs b/crates/project_model/src/lib.rs
index 970a7e140..525c336e6 100644
--- a/crates/project_model/src/lib.rs
+++ b/crates/project_model/src/lib.rs
@@ -6,6 +6,7 @@ mod project_json;
6mod sysroot; 6mod sysroot;
7mod workspace; 7mod workspace;
8mod rustc_cfg; 8mod rustc_cfg;
9mod build_data;
9 10
10use std::{ 11use std::{
11 fs::{read_dir, ReadDir}, 12 fs::{read_dir, ReadDir},
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs
index 073c48af7..bc5041e5a 100644
--- a/crates/project_model/src/workspace.rs
+++ b/crates/project_model/src/workspace.rs
@@ -178,7 +178,7 @@ impl ProjectWorkspace {
178 let pkg_root = cargo[pkg].root().to_path_buf(); 178 let pkg_root = cargo[pkg].root().to_path_buf();
179 179
180 let mut include = vec![pkg_root.clone()]; 180 let mut include = vec![pkg_root.clone()];
181 include.extend(cargo[pkg].out_dir.clone()); 181 include.extend(cargo[pkg].build_data.out_dir.clone());
182 182
183 let mut exclude = vec![pkg_root.join(".git")]; 183 let mut exclude = vec![pkg_root.join(".git")];
184 if is_member { 184 if is_member {
@@ -484,23 +484,21 @@ fn add_target_crate_root(
484 for feature in pkg.active_features.iter() { 484 for feature in pkg.active_features.iter() {
485 opts.insert_key_value("feature".into(), feature.into()); 485 opts.insert_key_value("feature".into(), feature.into());
486 } 486 }
487 opts.extend(pkg.cfgs.iter().cloned()); 487 opts.extend(pkg.build_data.cfgs.iter().cloned());
488 opts 488 opts
489 }; 489 };
490 490
491 let mut env = Env::default(); 491 let mut env = Env::default();
492 for (k, v) in &pkg.envs { 492 for (k, v) in &pkg.build_data.envs {
493 env.set(k, v.clone()); 493 env.set(k, v.clone());
494 } 494 }
495 if let Some(out_dir) = &pkg.out_dir {
496 // NOTE: cargo and rustc seem to hide non-UTF-8 strings from env! and option_env!()
497 if let Some(out_dir) = out_dir.to_str().map(|s| s.to_owned()) {
498 env.set("OUT_DIR", out_dir);
499 }
500 }
501 495
502 let proc_macro = 496 let proc_macro = pkg
503 pkg.proc_macro_dylib_path.as_ref().map(|it| proc_macro_loader(&it)).unwrap_or_default(); 497 .build_data
498 .proc_macro_dylib_path
499 .as_ref()
500 .map(|it| proc_macro_loader(&it))
501 .unwrap_or_default();
504 502
505 let display_name = CrateDisplayName::from_canonical_name(pkg.name.clone()); 503 let display_name = CrateDisplayName::from_canonical_name(pkg.name.clone());
506 let crate_id = crate_graph.add_crate_root( 504 let crate_id = crate_graph.add_crate_root(
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs
index 2f7f94a39..1d6e5478b 100644
--- a/crates/rust-analyzer/src/bin/main.rs
+++ b/crates/rust-analyzer/src/bin/main.rs
@@ -76,7 +76,12 @@ fn setup_logging(log_file: Option<PathBuf>) -> Result<()> {
76 profile::init(); 76 profile::init();
77 77
78 if !cfg!(debug_assertions) { 78 if !cfg!(debug_assertions) {
79 stdx::set_assert_hook(|loc, args| log::error!("assertion failed at {}: {}", loc, args)); 79 stdx::set_assert_hook(|loc, args| {
80 if env::var("RA_PROFILE").is_ok() {
81 panic!("assertion failed at {}: {}", loc, args)
82 }
83 log::error!("assertion failed at {}: {}", loc, args)
84 });
80 } 85 }
81 86
82 Ok(()) 87 Ok(())
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index 42451cd2d..809452e6d 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -10,8 +10,9 @@ use std::{
10 10
11use ide::{ 11use ide::{
12 FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData, LineIndex, NavigationTarget, 12 FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData, LineIndex, NavigationTarget,
13 Query, RangeInfo, Runnable, RunnableKind, SearchScope, SourceChange, SymbolKind, TextEdit, 13 Query, RangeInfo, Runnable, RunnableKind, SearchScope, SourceChange, TextEdit,
14}; 14};
15use ide_db::SymbolKind;
15use itertools::Itertools; 16use itertools::Itertools;
16use lsp_server::ErrorCode; 17use lsp_server::ErrorCode;
17use lsp_types::{ 18use lsp_types::{
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 0e3550002..96f915f1c 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -8,8 +8,9 @@ use ide::{
8 Assist, AssistKind, CallInfo, CompletionItem, CompletionItemKind, Documentation, FileId, 8 Assist, AssistKind, CallInfo, CompletionItem, CompletionItemKind, Documentation, FileId,
9 FileRange, FileSystemEdit, Fold, FoldKind, Highlight, HlMod, HlPunct, HlRange, HlTag, Indel, 9 FileRange, FileSystemEdit, Fold, FoldKind, Highlight, HlMod, HlPunct, HlRange, HlTag, Indel,
10 InlayHint, InlayKind, InsertTextFormat, LineIndex, Markup, NavigationTarget, ReferenceAccess, 10 InlayHint, InlayKind, InsertTextFormat, LineIndex, Markup, NavigationTarget, ReferenceAccess,
11 RenameError, Runnable, Severity, SourceChange, SymbolKind, TextEdit, TextRange, TextSize, 11 RenameError, Runnable, Severity, SourceChange, TextEdit, TextRange, TextSize,
12}; 12};
13use ide_db::SymbolKind;
13use itertools::Itertools; 14use itertools::Itertools;
14 15
15use crate::{ 16use crate::{
@@ -87,25 +88,35 @@ pub(crate) fn completion_item_kind(
87 completion_item_kind: CompletionItemKind, 88 completion_item_kind: CompletionItemKind,
88) -> lsp_types::CompletionItemKind { 89) -> lsp_types::CompletionItemKind {
89 match completion_item_kind { 90 match completion_item_kind {
90 CompletionItemKind::Keyword => lsp_types::CompletionItemKind::Keyword, 91 CompletionItemKind::Attribute => lsp_types::CompletionItemKind::EnumMember,
91 CompletionItemKind::Snippet => lsp_types::CompletionItemKind::Snippet,
92 CompletionItemKind::Module => lsp_types::CompletionItemKind::Module,
93 CompletionItemKind::Function => lsp_types::CompletionItemKind::Function,
94 CompletionItemKind::Struct => lsp_types::CompletionItemKind::Struct,
95 CompletionItemKind::Enum => lsp_types::CompletionItemKind::Enum,
96 CompletionItemKind::EnumVariant => lsp_types::CompletionItemKind::EnumMember,
97 CompletionItemKind::BuiltinType => lsp_types::CompletionItemKind::Struct,
98 CompletionItemKind::Binding => lsp_types::CompletionItemKind::Variable, 92 CompletionItemKind::Binding => lsp_types::CompletionItemKind::Variable,
99 CompletionItemKind::Field => lsp_types::CompletionItemKind::Field, 93 CompletionItemKind::BuiltinType => lsp_types::CompletionItemKind::Struct,
100 CompletionItemKind::Trait => lsp_types::CompletionItemKind::Interface, 94 CompletionItemKind::Keyword => lsp_types::CompletionItemKind::Keyword,
101 CompletionItemKind::TypeAlias => lsp_types::CompletionItemKind::Struct,
102 CompletionItemKind::Const => lsp_types::CompletionItemKind::Constant,
103 CompletionItemKind::Static => lsp_types::CompletionItemKind::Value,
104 CompletionItemKind::Method => lsp_types::CompletionItemKind::Method, 95 CompletionItemKind::Method => lsp_types::CompletionItemKind::Method,
105 CompletionItemKind::TypeParam => lsp_types::CompletionItemKind::TypeParameter, 96 CompletionItemKind::Snippet => lsp_types::CompletionItemKind::Snippet,
106 CompletionItemKind::Macro => lsp_types::CompletionItemKind::Method,
107 CompletionItemKind::Attribute => lsp_types::CompletionItemKind::EnumMember,
108 CompletionItemKind::UnresolvedReference => lsp_types::CompletionItemKind::Reference, 97 CompletionItemKind::UnresolvedReference => lsp_types::CompletionItemKind::Reference,
98 CompletionItemKind::SymbolKind(symbol) => match symbol {
99 SymbolKind::Const => lsp_types::CompletionItemKind::Constant,
100 SymbolKind::ConstParam => lsp_types::CompletionItemKind::TypeParameter,
101 SymbolKind::Enum => lsp_types::CompletionItemKind::Enum,
102 SymbolKind::Field => lsp_types::CompletionItemKind::Field,
103 SymbolKind::Function => lsp_types::CompletionItemKind::Function,
104 SymbolKind::Impl => lsp_types::CompletionItemKind::Text,
105 SymbolKind::Label => lsp_types::CompletionItemKind::Variable,
106 SymbolKind::LifetimeParam => lsp_types::CompletionItemKind::TypeParameter,
107 SymbolKind::Local => lsp_types::CompletionItemKind::Variable,
108 SymbolKind::Macro => lsp_types::CompletionItemKind::Method,
109 SymbolKind::Module => lsp_types::CompletionItemKind::Module,
110 SymbolKind::SelfParam => lsp_types::CompletionItemKind::Value,
111 SymbolKind::Static => lsp_types::CompletionItemKind::Value,
112 SymbolKind::Struct => lsp_types::CompletionItemKind::Struct,
113 SymbolKind::Trait => lsp_types::CompletionItemKind::Interface,
114 SymbolKind::TypeAlias => lsp_types::CompletionItemKind::Struct,
115 SymbolKind::TypeParam => lsp_types::CompletionItemKind::TypeParameter,
116 SymbolKind::Union => lsp_types::CompletionItemKind::Struct,
117 SymbolKind::ValueParam => lsp_types::CompletionItemKind::Value,
118 SymbolKind::Variant => lsp_types::CompletionItemKind::EnumMember,
119 },
109 } 120 }
110} 121}
111 122
diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs
index 73b121f8a..d42817078 100644
--- a/crates/stdx/src/lib.rs
+++ b/crates/stdx/src/lib.rs
@@ -196,6 +196,7 @@ impl ops::DerefMut for JodChild {
196impl Drop for JodChild { 196impl Drop for JodChild {
197 fn drop(&mut self) { 197 fn drop(&mut self) {
198 let _ = self.0.kill(); 198 let _ = self.0.kill();
199 let _ = self.0.wait();
199 } 200 }
200} 201}
201 202
diff --git a/docs/dev/style.md b/docs/dev/style.md
index 389649398..428cee3ad 100644
--- a/docs/dev/style.md
+++ b/docs/dev/style.md
@@ -6,6 +6,9 @@ Our approach to "clean code" is two-fold:
6It is explicitly OK for a reviewer to flag only some nits in the PR, and then send a follow-up cleanup PR for things which are easier to explain by example, cc-ing the original author. 6It is explicitly OK for a reviewer to flag only some nits in the PR, and then send a follow-up cleanup PR for things which are easier to explain by example, cc-ing the original author.
7Sending small cleanup PRs (like renaming a single local variable) is encouraged. 7Sending small cleanup PRs (like renaming a single local variable) is encouraged.
8 8
9When reviewing pull requests prefer extending this document to leaving
10non-reusable comments on the pull request itself.
11
9# General 12# General
10 13
11## Scale of Changes 14## Scale of Changes
@@ -139,6 +142,17 @@ There are many benefits to this:
139 142
140Formatting ensures that you can use your editor's "number of selected characters" feature to correlate offsets with test's source code. 143Formatting ensures that you can use your editor's "number of selected characters" feature to correlate offsets with test's source code.
141 144
145## Marked Tests
146
147Use
148[`mark::hit! / mark::check!`](https://github.com/rust-analyzer/rust-analyzer/blob/71fe719dd5247ed8615641d9303d7ca1aa201c2f/crates/test_utils/src/mark.rs)
149when testing specific conditions.
150Do not place several marks into a single test or condition.
151Do not reuse marks between several tests.
152
153**Rationale:** marks provide an easy way to find the canonical test for each bit of code.
154This makes it much easier to understand.
155
142## Function Preconditions 156## Function Preconditions
143 157
144Express function preconditions in types and force the caller to provide them (rather than checking in callee): 158Express function preconditions in types and force the caller to provide them (rather than checking in callee):
@@ -375,6 +389,14 @@ This allows for exceptionally good performance, but leads to increased compile t
375Runtime performance obeys 80%/20% rule -- only a small fraction of code is hot. 389Runtime performance obeys 80%/20% rule -- only a small fraction of code is hot.
376Compile time **does not** obey this rule -- all code has to be compiled. 390Compile time **does not** obey this rule -- all code has to be compiled.
377 391
392## Appropriate String Types
393
394When interfacing with OS APIs, use `OsString`, even if the original source of data is utf-8 encoded.
395**Rationale:** cleanly delineates the boundary when the data goes into the OS-land.
396
397Use `AbsPathBuf` and `AbsPath` over `std::Path`.
398**Rationale:** rust-analyzer is a long-lived process which handles several projects at the same time.
399It is important not to leak cwd by accident.
378 400
379# Premature Pessimization 401# Premature Pessimization
380 402