aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSeivan Heidari <[email protected]>2019-11-15 15:30:21 +0000
committerSeivan Heidari <[email protected]>2019-11-15 15:30:21 +0000
commitcb26df950699586b314731fb70786e0db8eaa049 (patch)
tree29a1fd853757824572bfebc956d20458d827926f
parentc622413bc72ea56d5f62a16788d897cb61eca948 (diff)
parentc6f05abfbbfa2fd1ff06e1adeea7885151aaa768 (diff)
Merge branch 'master' of https://github.com/rust-analyzer/rust-analyzer into feature/themes
-rw-r--r--.gitattributes2
-rw-r--r--Cargo.lock8
-rw-r--r--crates/ra_assists/src/assists/add_new.rs379
-rw-r--r--crates/ra_assists/src/doc_tests/generated.rs22
-rw-r--r--crates/ra_assists/src/lib.rs2
-rw-r--r--crates/ra_db/src/fixture.rs12
-rw-r--r--crates/ra_hir/src/code_model.rs4
-rw-r--r--crates/ra_hir/src/expr.rs281
-rw-r--r--crates/ra_hir/src/expr/validation.rs137
-rw-r--r--crates/ra_hir/src/from_source.rs68
-rw-r--r--crates/ra_hir/src/resolve.rs23
-rw-r--r--crates/ra_hir/src/source_binder.rs38
-rw-r--r--crates/ra_hir/src/test_db.rs2
-rw-r--r--crates/ra_hir/src/ty/tests.rs54
-rw-r--r--crates/ra_hir_def/src/body/scope.rs219
-rw-r--r--crates/ra_hir_def/src/nameres.rs22
-rw-r--r--crates/ra_hir_def/src/nameres/collector.rs5
-rw-r--r--crates/ra_hir_def/src/nameres/tests/incremental.rs6
-rw-r--r--crates/ra_hir_def/src/nameres/tests/mod_resolution.rs2
-rw-r--r--crates/ra_hir_expand/src/quote.rs6
-rw-r--r--crates/ra_ide_api/src/completion/complete_dot.rs94
-rw-r--r--crates/ra_ide_api/src/completion/complete_fn_param.rs54
-rw-r--r--crates/ra_ide_api/src/completion/complete_keyword.rs960
-rw-r--r--crates/ra_ide_api/src/completion/complete_macro_in_item_position.rs95
-rw-r--r--crates/ra_ide_api/src/completion/complete_path.rs332
-rw-r--r--crates/ra_ide_api/src/completion/complete_pattern.rs60
-rw-r--r--crates/ra_ide_api/src/completion/complete_postfix.rs298
-rw-r--r--crates/ra_ide_api/src/completion/complete_record_literal.rs102
-rw-r--r--crates/ra_ide_api/src/completion/complete_record_pattern.rs56
-rw-r--r--crates/ra_ide_api/src/completion/complete_scope.rs56
-rw-r--r--crates/ra_ide_api/src/completion/complete_snippet.rs74
-rw-r--r--crates/ra_ide_api/src/completion/presentation.rs160
-rw-r--r--crates/ra_ide_api/src/diagnostics.rs44
-rw-r--r--crates/ra_ide_api/src/display/structure.rs372
-rw-r--r--crates/ra_ide_api/src/hover.rs204
-rw-r--r--crates/ra_ide_api/src/inlay_hints.rs314
-rw-r--r--crates/ra_ide_api/src/runnables.rs128
-rw-r--r--crates/ra_mbe/Cargo.toml2
-rw-r--r--crates/ra_prof/Cargo.toml38
-rw-r--r--docs/user/assists.md21
40 files changed, 2620 insertions, 2136 deletions
diff --git a/.gitattributes b/.gitattributes
index 183e9b521..e749e1dc9 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,2 +1,2 @@
1* text=auto eol=lf
1crates/ra_syntax/test_data/** -text eof=LF 2crates/ra_syntax/test_data/** -text eof=LF
2crates/ra_ide_api/src/snapshots/** -text eof=LF
diff --git a/Cargo.lock b/Cargo.lock
index 1dedf9772..d7ec266c0 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1135,7 +1135,7 @@ dependencies = [
1135 "ra_syntax 0.1.0", 1135 "ra_syntax 0.1.0",
1136 "ra_tt 0.1.0", 1136 "ra_tt 0.1.0",
1137 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1137 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
1138 "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", 1138 "smallvec 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
1139 "test_utils 0.1.0", 1139 "test_utils 0.1.0",
1140] 1140]
1141 1141
@@ -1604,6 +1604,11 @@ dependencies = [
1604] 1604]
1605 1605
1606[[package]] 1606[[package]]
1607name = "smallvec"
1608version = "1.0.0"
1609source = "registry+https://github.com/rust-lang/crates.io-index"
1610
1611[[package]]
1607name = "smol_str" 1612name = "smol_str"
1608version = "0.1.15" 1613version = "0.1.15"
1609source = "registry+https://github.com/rust-lang/crates.io-index" 1614source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2007,6 +2012,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
2007"checksum serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)" = "691b17f19fc1ec9d94ec0b5864859290dff279dbd7b03f017afda54eb36c3c35" 2012"checksum serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)" = "691b17f19fc1ec9d94ec0b5864859290dff279dbd7b03f017afda54eb36c3c35"
2008"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" 2013"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
2009"checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" 2014"checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6"
2015"checksum smallvec 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ecf3b85f68e8abaa7555aa5abdb1153079387e60b718283d732f03897fcfc86"
2010"checksum smol_str 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "34836c9a295c62c2ce3514471117c5cb269891e8421b2aafdd910050576c4d8b" 2016"checksum smol_str 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "34836c9a295c62c2ce3514471117c5cb269891e8421b2aafdd910050576c4d8b"
2011"checksum stacker 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d96fc4f13a0ac088e9a3cd9af1cc8c5cc1ab5deb2145cef661267dfc9c542f8a" 2017"checksum stacker 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d96fc4f13a0ac088e9a3cd9af1cc8c5cc1ab5deb2145cef661267dfc9c542f8a"
2012"checksum superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab16ced94dbd8a46c82fd81e3ed9a8727dac2977ea869d217bcc4ea1f122e81f" 2018"checksum superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab16ced94dbd8a46c82fd81e3ed9a8727dac2977ea869d217bcc4ea1f122e81f"
diff --git a/crates/ra_assists/src/assists/add_new.rs b/crates/ra_assists/src/assists/add_new.rs
new file mode 100644
index 000000000..a8839cfba
--- /dev/null
+++ b/crates/ra_assists/src/assists/add_new.rs
@@ -0,0 +1,379 @@
1use format_buf::format;
2use hir::{db::HirDatabase, FromSource};
3use join_to_string::join;
4use ra_syntax::{
5 ast::{
6 self, AstNode, NameOwner, StructKind, TypeAscriptionOwner, TypeParamsOwner, VisibilityOwner,
7 },
8 TextUnit, T,
9};
10use std::fmt::Write;
11
12use crate::{Assist, AssistCtx, AssistId};
13
14// Assist: add_new
15//
16// Adds a new inherent impl for a type.
17//
18// ```
19// struct Ctx<T: Clone> {
20// data: T,<|>
21// }
22// ```
23// ->
24// ```
25// struct Ctx<T: Clone> {
26// data: T,
27// }
28//
29// impl<T: Clone> Ctx<T> {
30// fn new(data: T) -> Self { Self { data } }
31// }
32//
33// ```
34pub(crate) fn add_new(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
35 let strukt = ctx.find_node_at_offset::<ast::StructDef>()?;
36
37 // We want to only apply this to non-union structs with named fields
38 let field_list = match (strukt.kind(), strukt.is_union()) {
39 (StructKind::Named(named), false) => named,
40 _ => return None,
41 };
42
43 // Return early if we've found an existing new fn
44 let impl_block = find_struct_impl(&ctx, &strukt)?;
45
46 ctx.add_assist(AssistId("add_new"), "add new fn", |edit| {
47 edit.target(strukt.syntax().text_range());
48
49 let mut buf = String::with_capacity(512);
50
51 if impl_block.is_some() {
52 buf.push('\n');
53 }
54
55 let vis = strukt.visibility().map(|v| format!("{} ", v.syntax()));
56 let vis = vis.as_ref().map(String::as_str).unwrap_or("");
57 write!(&mut buf, " {}fn new(", vis).unwrap();
58
59 join(field_list.fields().map(|f| {
60 format!(
61 "{}: {}",
62 f.name().unwrap().syntax().text(),
63 f.ascribed_type().unwrap().syntax().text()
64 )
65 }))
66 .separator(", ")
67 .to_buf(&mut buf);
68
69 buf.push_str(") -> Self { Self {");
70
71 join(field_list.fields().map(|f| f.name().unwrap().syntax().text()))
72 .separator(", ")
73 .surround_with(" ", " ")
74 .to_buf(&mut buf);
75
76 buf.push_str("} }");
77
78 let (start_offset, end_offset) = if let Some(impl_block) = impl_block {
79 buf.push('\n');
80 let start = impl_block
81 .syntax()
82 .descendants_with_tokens()
83 .find(|t| t.kind() == T!['{'])
84 .unwrap()
85 .text_range()
86 .end();
87
88 (start, TextUnit::from_usize(1))
89 } else {
90 buf = generate_impl_text(&strukt, &buf);
91 let start = strukt.syntax().text_range().end();
92
93 (start, TextUnit::from_usize(3))
94 };
95
96 edit.set_cursor(start_offset + TextUnit::of_str(&buf) - end_offset);
97 edit.insert(start_offset, buf);
98 })
99}
100
101// Generates the surrounding `impl Type { <code> }` including type and lifetime
102// parameters
103fn generate_impl_text(strukt: &ast::StructDef, code: &str) -> String {
104 let type_params = strukt.type_param_list();
105 let mut buf = String::with_capacity(code.len());
106 buf.push_str("\n\nimpl");
107 if let Some(type_params) = &type_params {
108 format!(buf, "{}", type_params.syntax());
109 }
110 buf.push_str(" ");
111 buf.push_str(strukt.name().unwrap().text().as_str());
112 if let Some(type_params) = type_params {
113 let lifetime_params = type_params
114 .lifetime_params()
115 .filter_map(|it| it.lifetime_token())
116 .map(|it| it.text().clone());
117 let type_params =
118 type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone());
119 join(lifetime_params.chain(type_params)).surround_with("<", ">").to_buf(&mut buf);
120 }
121
122 format!(&mut buf, " {{\n{}\n}}\n", code);
123
124 buf
125}
126
127// Uses a syntax-driven approach to find any impl blocks for the struct that
128// exist within the module/file
129//
130// Returns `None` if we've found an existing `new` fn
131//
132// FIXME: change the new fn checking to a more semantic approach when that's more
133// viable (e.g. we process proc macros, etc)
134fn find_struct_impl(
135 ctx: &AssistCtx<impl HirDatabase>,
136 strukt: &ast::StructDef,
137) -> Option<Option<ast::ImplBlock>> {
138 let db = ctx.db;
139 let module = strukt.syntax().ancestors().find(|node| {
140 ast::Module::can_cast(node.kind()) || ast::SourceFile::can_cast(node.kind())
141 })?;
142
143 let struct_ty = {
144 let src = hir::Source { file_id: ctx.frange.file_id.into(), ast: strukt.clone() };
145 hir::Struct::from_source(db, src).unwrap().ty(db)
146 };
147
148 let mut found_new_fn = false;
149
150 let block = module.descendants().filter_map(ast::ImplBlock::cast).find(|impl_blk| {
151 if found_new_fn {
152 return false;
153 }
154
155 let src = hir::Source { file_id: ctx.frange.file_id.into(), ast: impl_blk.clone() };
156 let blk = hir::ImplBlock::from_source(db, src).unwrap();
157
158 let same_ty = blk.target_ty(db) == struct_ty;
159 let not_trait_impl = blk.target_trait(db).is_none();
160
161 found_new_fn = has_new_fn(impl_blk);
162
163 same_ty && not_trait_impl
164 });
165
166 if found_new_fn {
167 None
168 } else {
169 Some(block)
170 }
171}
172
173fn has_new_fn(imp: &ast::ImplBlock) -> bool {
174 if let Some(il) = imp.item_list() {
175 for item in il.impl_items() {
176 if let ast::ImplItem::FnDef(f) = item {
177 if f.name().unwrap().text().eq_ignore_ascii_case("new") {
178 return true;
179 }
180 }
181 }
182 }
183
184 false
185}
186
187#[cfg(test)]
188mod tests {
189 use super::*;
190 use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target};
191
192 #[test]
193 #[rustfmt::skip]
194 fn test_add_new() {
195 // Check output of generation
196 check_assist(
197 add_new,
198"struct Foo {<|>}",
199"struct Foo {}
200
201impl Foo {
202 fn new() -> Self { Self { } }<|>
203}
204",
205 );
206 check_assist(
207 add_new,
208"struct Foo<T: Clone> {<|>}",
209"struct Foo<T: Clone> {}
210
211impl<T: Clone> Foo<T> {
212 fn new() -> Self { Self { } }<|>
213}
214",
215 );
216 check_assist(
217 add_new,
218"struct Foo<'a, T: Foo<'a>> {<|>}",
219"struct Foo<'a, T: Foo<'a>> {}
220
221impl<'a, T: Foo<'a>> Foo<'a, T> {
222 fn new() -> Self { Self { } }<|>
223}
224",
225 );
226 check_assist(
227 add_new,
228"struct Foo { baz: String <|>}",
229"struct Foo { baz: String }
230
231impl Foo {
232 fn new(baz: String) -> Self { Self { baz } }<|>
233}
234",
235 );
236 check_assist(
237 add_new,
238"struct Foo { baz: String, qux: Vec<i32> <|>}",
239"struct Foo { baz: String, qux: Vec<i32> }
240
241impl Foo {
242 fn new(baz: String, qux: Vec<i32>) -> Self { Self { baz, qux } }<|>
243}
244",
245 );
246
247 // Check that visibility modifiers don't get brought in for fields
248 check_assist(
249 add_new,
250"struct Foo { pub baz: String, pub qux: Vec<i32> <|>}",
251"struct Foo { pub baz: String, pub qux: Vec<i32> }
252
253impl Foo {
254 fn new(baz: String, qux: Vec<i32>) -> Self { Self { baz, qux } }<|>
255}
256",
257 );
258
259 // Check that it reuses existing impls
260 check_assist(
261 add_new,
262"struct Foo {<|>}
263
264impl Foo {}
265",
266"struct Foo {}
267
268impl Foo {
269 fn new() -> Self { Self { } }<|>
270}
271",
272 );
273 check_assist(
274 add_new,
275"struct Foo {<|>}
276
277impl Foo {
278 fn qux(&self) {}
279}
280",
281"struct Foo {}
282
283impl Foo {
284 fn new() -> Self { Self { } }<|>
285
286 fn qux(&self) {}
287}
288",
289 );
290
291 check_assist(
292 add_new,
293"struct Foo {<|>}
294
295impl Foo {
296 fn qux(&self) {}
297 fn baz() -> i32 {
298 5
299 }
300}
301",
302"struct Foo {}
303
304impl Foo {
305 fn new() -> Self { Self { } }<|>
306
307 fn qux(&self) {}
308 fn baz() -> i32 {
309 5
310 }
311}
312",
313 );
314
315 // Check visibility of new fn based on struct
316 check_assist(
317 add_new,
318"pub struct Foo {<|>}",
319"pub struct Foo {}
320
321impl Foo {
322 pub fn new() -> Self { Self { } }<|>
323}
324",
325 );
326 check_assist(
327 add_new,
328"pub(crate) struct Foo {<|>}",
329"pub(crate) struct Foo {}
330
331impl Foo {
332 pub(crate) fn new() -> Self { Self { } }<|>
333}
334",
335 );
336 }
337
338 #[test]
339 fn add_new_not_applicable_if_fn_exists() {
340 check_assist_not_applicable(
341 add_new,
342 "
343struct Foo {<|>}
344
345impl Foo {
346 fn new() -> Self {
347 Self
348 }
349}",
350 );
351
352 check_assist_not_applicable(
353 add_new,
354 "
355struct Foo {<|>}
356
357impl Foo {
358 fn New() -> Self {
359 Self
360 }
361}",
362 );
363 }
364
365 #[test]
366 fn add_new_target() {
367 check_assist_target(
368 add_new,
369 "
370struct SomeThingIrrelevant;
371/// Has a lifetime parameter
372struct Foo<'a, T: Foo<'a>> {<|>}
373struct EvenMoreIrrelevant;
374",
375 "/// Has a lifetime parameter
376struct Foo<'a, T: Foo<'a>> {}",
377 );
378 }
379}
diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs
index 1bee76f59..176761efb 100644
--- a/crates/ra_assists/src/doc_tests/generated.rs
+++ b/crates/ra_assists/src/doc_tests/generated.rs
@@ -157,6 +157,28 @@ fn process(map: HashMap<String, String>) {}
157} 157}
158 158
159#[test] 159#[test]
160fn doctest_add_new() {
161 check(
162 "add_new",
163 r#####"
164struct Ctx<T: Clone> {
165 data: T,<|>
166}
167"#####,
168 r#####"
169struct Ctx<T: Clone> {
170 data: T,
171}
172
173impl<T: Clone> Ctx<T> {
174 fn new(data: T) -> Self { Self { data } }
175}
176
177"#####,
178 )
179}
180
181#[test]
160fn doctest_apply_demorgan() { 182fn doctest_apply_demorgan() {
161 check( 183 check(
162 "apply_demorgan", 184 "apply_demorgan",
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index 39c1c283f..f2f0dacbf 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -95,6 +95,7 @@ mod assists {
95 mod add_derive; 95 mod add_derive;
96 mod add_explicit_type; 96 mod add_explicit_type;
97 mod add_impl; 97 mod add_impl;
98 mod add_new;
98 mod apply_demorgan; 99 mod apply_demorgan;
99 mod flip_comma; 100 mod flip_comma;
100 mod flip_binexpr; 101 mod flip_binexpr;
@@ -119,6 +120,7 @@ mod assists {
119 add_derive::add_derive, 120 add_derive::add_derive,
120 add_explicit_type::add_explicit_type, 121 add_explicit_type::add_explicit_type,
121 add_impl::add_impl, 122 add_impl::add_impl,
123 add_new::add_new,
122 apply_demorgan::apply_demorgan, 124 apply_demorgan::apply_demorgan,
123 change_visibility::change_visibility, 125 change_visibility::change_visibility,
124 fill_match_arms::fill_match_arms, 126 fill_match_arms::fill_match_arms,
diff --git a/crates/ra_db/src/fixture.rs b/crates/ra_db/src/fixture.rs
index ee883b615..ade187629 100644
--- a/crates/ra_db/src/fixture.rs
+++ b/crates/ra_db/src/fixture.rs
@@ -8,8 +8,8 @@ use rustc_hash::FxHashMap;
8use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER}; 8use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER};
9 9
10use crate::{ 10use crate::{
11 CrateGraph, Edition, FileId, FilePosition, RelativePathBuf, SourceDatabaseExt, SourceRoot, 11 CrateGraph, CrateId, Edition, FileId, FilePosition, RelativePathBuf, SourceDatabaseExt,
12 SourceRootId, 12 SourceRoot, SourceRootId,
13}; 13};
14 14
15pub const WORKSPACE: SourceRootId = SourceRootId(0); 15pub const WORKSPACE: SourceRootId = SourceRootId(0);
@@ -33,6 +33,14 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static {
33 let pos = with_files(&mut db, fixture); 33 let pos = with_files(&mut db, fixture);
34 (db, pos.unwrap()) 34 (db, pos.unwrap())
35 } 35 }
36
37 fn test_crate(&self) -> CrateId {
38 let crate_graph = self.crate_graph();
39 let mut it = crate_graph.iter();
40 let res = it.next().unwrap();
41 assert!(it.next().is_none());
42 res
43 }
36} 44}
37 45
38impl<DB: SourceDatabaseExt + Default + 'static> WithFixture for DB {} 46impl<DB: SourceDatabaseExt + Default + 'static> WithFixture for DB {}
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 962d5a8c1..078bd8609 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -23,7 +23,7 @@ use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner};
23use crate::{ 23use crate::{
24 adt::VariantDef, 24 adt::VariantDef,
25 db::{AstDatabase, DefDatabase, HirDatabase}, 25 db::{AstDatabase, DefDatabase, HirDatabase},
26 expr::{validation::ExprValidator, BindingAnnotation, Body, BodySourceMap, Pat, PatId}, 26 expr::{BindingAnnotation, Body, BodySourceMap, ExprValidator, Pat, PatId},
27 generics::{GenericDef, HasGenericParams}, 27 generics::{GenericDef, HasGenericParams},
28 ids::{ 28 ids::{
29 AstItemDef, ConstId, EnumId, FunctionId, MacroDefId, StaticId, StructId, TraitId, 29 AstItemDef, ConstId, EnumId, FunctionId, MacroDefId, StaticId, StructId, TraitId,
@@ -157,7 +157,7 @@ impl Module {
157 } 157 }
158 158
159 /// Finds a child module with the specified name. 159 /// Finds a child module with the specified name.
160 pub fn child(self, db: &impl HirDatabase, name: &Name) -> Option<Module> { 160 pub fn child(self, db: &impl DefDatabase, name: &Name) -> Option<Module> {
161 let def_map = db.crate_def_map(self.id.krate); 161 let def_map = db.crate_def_map(self.id.krate);
162 let child_id = def_map[self.id.module_id].children.get(name)?; 162 let child_id = def_map[self.id.module_id].children.get(name)?;
163 Some(self.with_module_id(*child_id)) 163 Some(self.with_module_id(*child_id))
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs
index 9262325f2..e3733779e 100644
--- a/crates/ra_hir/src/expr.rs
+++ b/crates/ra_hir/src/expr.rs
@@ -1,12 +1,19 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3pub(crate) mod validation;
4
5use std::sync::Arc; 3use std::sync::Arc;
6 4
5use hir_def::path::known;
6use hir_expand::diagnostics::DiagnosticSink;
7use ra_syntax::ast;
7use ra_syntax::AstPtr; 8use ra_syntax::AstPtr;
9use rustc_hash::FxHashSet;
8 10
9use crate::{db::HirDatabase, DefWithBody, HasBody, Resolver}; 11use crate::{
12 db::HirDatabase,
13 diagnostics::{MissingFields, MissingOkInTailExpr},
14 ty::{ApplicationTy, InferenceResult, Ty, TypeCtor},
15 Adt, DefWithBody, Function, HasBody, Name, Path, Resolver,
16};
10 17
11pub use hir_def::{ 18pub use hir_def::{
12 body::{ 19 body::{
@@ -38,196 +45,126 @@ pub(crate) fn resolver_for_scope(
38 let scopes = owner.expr_scopes(db); 45 let scopes = owner.expr_scopes(db);
39 let scope_chain = scopes.scope_chain(scope_id).collect::<Vec<_>>(); 46 let scope_chain = scopes.scope_chain(scope_id).collect::<Vec<_>>();
40 for scope in scope_chain.into_iter().rev() { 47 for scope in scope_chain.into_iter().rev() {
41 r = r.push_expr_scope(Arc::clone(&scopes), scope); 48 r = r.push_expr_scope(owner, Arc::clone(&scopes), scope);
42 } 49 }
43 r 50 r
44} 51}
45 52
46#[cfg(test)] 53pub(crate) struct ExprValidator<'a, 'b: 'a> {
47mod tests { 54 func: Function,
48 use hir_expand::Source; 55 infer: Arc<InferenceResult>,
49 use ra_db::{fixture::WithFixture, SourceDatabase}; 56 sink: &'a mut DiagnosticSink<'b>,
50 use ra_syntax::{algo::find_node_at_offset, ast, AstNode}; 57}
51 use test_utils::{assert_eq_text, extract_offset};
52
53 use crate::{source_binder::SourceAnalyzer, test_db::TestDB};
54
55 fn do_check(code: &str, expected: &[&str]) {
56 let (off, code) = extract_offset(code);
57 let code = {
58 let mut buf = String::new();
59 let off = u32::from(off) as usize;
60 buf.push_str(&code[..off]);
61 buf.push_str("marker");
62 buf.push_str(&code[off..]);
63 buf
64 };
65 58
66 let (db, file_id) = TestDB::with_single_file(&code); 59impl<'a, 'b> ExprValidator<'a, 'b> {
67 60 pub(crate) fn new(
68 let file = db.parse(file_id).ok().unwrap(); 61 func: Function,
69 let marker: ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap(); 62 infer: Arc<InferenceResult>,
70 let analyzer = SourceAnalyzer::new(&db, file_id, marker.syntax(), None); 63 sink: &'a mut DiagnosticSink<'b>,
71 64 ) -> ExprValidator<'a, 'b> {
72 let scopes = analyzer.scopes(); 65 ExprValidator { func, infer, sink }
73 let expr_id = analyzer
74 .body_source_map()
75 .node_expr(Source { file_id: file_id.into(), ast: &marker.into() })
76 .unwrap();
77 let scope = scopes.scope_for(expr_id);
78
79 let actual = scopes
80 .scope_chain(scope)
81 .flat_map(|scope| scopes.entries(scope))
82 .map(|it| it.name().to_string())
83 .collect::<Vec<_>>()
84 .join("\n");
85 let expected = expected.join("\n");
86 assert_eq_text!(&expected, &actual);
87 } 66 }
88 67
89 #[test] 68 pub(crate) fn validate_body(&mut self, db: &impl HirDatabase) {
90 fn test_lambda_scope() { 69 let body = self.func.body(db);
91 do_check(
92 r"
93 fn quux(foo: i32) {
94 let f = |bar, baz: i32| {
95 <|>
96 };
97 }",
98 &["bar", "baz", "foo"],
99 );
100 }
101 70
102 #[test] 71 for e in body.exprs() {
103 fn test_call_scope() { 72 if let (id, Expr::RecordLit { path, fields, spread }) = e {
104 do_check( 73 self.validate_record_literal(id, path, fields, *spread, db);
105 r" 74 }
106 fn quux() { 75 }
107 f(|x| <|> );
108 }",
109 &["x"],
110 );
111 }
112 76
113 #[test] 77 let body_expr = &body[body.body_expr()];
114 fn test_method_call_scope() { 78 if let Expr::Block { statements: _, tail: Some(t) } = body_expr {
115 do_check( 79 self.validate_results_in_tail_expr(body.body_expr(), *t, db);
116 r" 80 }
117 fn quux() {
118 z.f(|x| <|> );
119 }",
120 &["x"],
121 );
122 } 81 }
123 82
124 #[test] 83 fn validate_record_literal(
125 fn test_loop_scope() { 84 &mut self,
126 do_check( 85 id: ExprId,
127 r" 86 _path: &Option<Path>,
128 fn quux() { 87 fields: &[RecordLitField],
129 loop { 88 spread: Option<ExprId>,
130 let x = (); 89 db: &impl HirDatabase,
131 <|> 90 ) {
132 }; 91 if spread.is_some() {
133 }", 92 return;
134 &["x"], 93 }
135 ); 94
136 } 95 let struct_def = match self.infer[id].as_adt() {
96 Some((Adt::Struct(s), _)) => s,
97 _ => return,
98 };
137 99
138 #[test] 100 let lit_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect();
139 fn test_match() { 101 let missed_fields: Vec<Name> = struct_def
140 do_check( 102 .fields(db)
141 r" 103 .iter()
142 fn quux() { 104 .filter_map(|f| {
143 match () { 105 let name = f.name(db);
144 Some(x) => { 106 if lit_fields.contains(&name) {
145 <|> 107 None
108 } else {
109 Some(name)
110 }
111 })
112 .collect();
113 if missed_fields.is_empty() {
114 return;
115 }
116 let source_map = self.func.body_source_map(db);
117
118 if let Some(source_ptr) = source_map.expr_syntax(id) {
119 if let Some(expr) = source_ptr.ast.a() {
120 let root = source_ptr.file_syntax(db);
121 if let ast::Expr::RecordLit(record_lit) = expr.to_node(&root) {
122 if let Some(field_list) = record_lit.record_field_list() {
123 self.sink.push(MissingFields {
124 file: source_ptr.file_id,
125 field_list: AstPtr::new(&field_list),
126 missed_fields,
127 })
146 } 128 }
147 }; 129 }
148 }", 130 }
149 &["x"], 131 }
150 );
151 }
152
153 #[test]
154 fn test_shadow_variable() {
155 do_check(
156 r"
157 fn foo(x: String) {
158 let x : &str = &x<|>;
159 }",
160 &["x"],
161 );
162 } 132 }
163 133
164 fn do_check_local_name(code: &str, expected_offset: u32) { 134 fn validate_results_in_tail_expr(
165 let (off, code) = extract_offset(code); 135 &mut self,
166 136 body_id: ExprId,
167 let (db, file_id) = TestDB::with_single_file(&code); 137 id: ExprId,
168 let file = db.parse(file_id).ok().unwrap(); 138 db: &impl HirDatabase,
169 let expected_name = find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()) 139 ) {
170 .expect("failed to find a name at the target offset"); 140 // the mismatch will be on the whole block currently
171 let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap(); 141 let mismatch = match self.infer.type_mismatch_for_expr(body_id) {
172 let analyzer = SourceAnalyzer::new(&db, file_id, name_ref.syntax(), None); 142 Some(m) => m,
143 None => return,
144 };
173 145
174 let local_name_entry = analyzer.resolve_local_name(&name_ref).unwrap(); 146 let std_result_path = known::std_result_result();
175 let local_name =
176 local_name_entry.ptr().either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr());
177 assert_eq!(local_name.range(), expected_name.syntax().text_range());
178 }
179 147
180 #[test] 148 let resolver = self.func.resolver(db);
181 fn test_resolve_local_name() { 149 let std_result_enum = match resolver.resolve_known_enum(db, &std_result_path) {
182 do_check_local_name( 150 Some(it) => it,
183 r#" 151 _ => return,
184 fn foo(x: i32, y: u32) { 152 };
185 {
186 let z = x * 2;
187 }
188 {
189 let t = x<|> * 3;
190 }
191 }"#,
192 21,
193 );
194 }
195 153
196 #[test] 154 let std_result_ctor = TypeCtor::Adt(Adt::Enum(std_result_enum));
197 fn test_resolve_local_name_declaration() { 155 let params = match &mismatch.expected {
198 do_check_local_name( 156 Ty::Apply(ApplicationTy { ctor, parameters }) if ctor == &std_result_ctor => parameters,
199 r#" 157 _ => return,
200 fn foo(x: String) { 158 };
201 let x : &str = &x<|>;
202 }"#,
203 21,
204 );
205 }
206 159
207 #[test] 160 if params.len() == 2 && &params[0] == &mismatch.actual {
208 fn test_resolve_local_name_shadow() { 161 let source_map = self.func.body_source_map(db);
209 do_check_local_name(
210 r"
211 fn foo(x: String) {
212 let x : &str = &x;
213 x<|>
214 }
215 ",
216 53,
217 );
218 }
219 162
220 #[test] 163 if let Some(source_ptr) = source_map.expr_syntax(id) {
221 fn ref_patterns_contribute_bindings() { 164 if let Some(expr) = source_ptr.ast.a() {
222 do_check_local_name( 165 self.sink.push(MissingOkInTailExpr { file: source_ptr.file_id, expr });
223 r"
224 fn foo() {
225 if let Some(&from) = bar() {
226 from<|>;
227 } 166 }
228 } 167 }
229 ", 168 }
230 53,
231 );
232 } 169 }
233} 170}
diff --git a/crates/ra_hir/src/expr/validation.rs b/crates/ra_hir/src/expr/validation.rs
deleted file mode 100644
index 3054f1dce..000000000
--- a/crates/ra_hir/src/expr/validation.rs
+++ /dev/null
@@ -1,137 +0,0 @@
1//! FIXME: write short doc here
2
3use std::sync::Arc;
4
5use hir_def::path::known;
6use hir_expand::diagnostics::DiagnosticSink;
7use ra_syntax::ast;
8use rustc_hash::FxHashSet;
9
10use crate::{
11 db::HirDatabase,
12 diagnostics::{MissingFields, MissingOkInTailExpr},
13 expr::AstPtr,
14 ty::{ApplicationTy, InferenceResult, Ty, TypeCtor},
15 Adt, Function, Name, Path,
16};
17
18use super::{Expr, ExprId, RecordLitField};
19
20pub(crate) struct ExprValidator<'a, 'b: 'a> {
21 func: Function,
22 infer: Arc<InferenceResult>,
23 sink: &'a mut DiagnosticSink<'b>,
24}
25
26impl<'a, 'b> ExprValidator<'a, 'b> {
27 pub(crate) fn new(
28 func: Function,
29 infer: Arc<InferenceResult>,
30 sink: &'a mut DiagnosticSink<'b>,
31 ) -> ExprValidator<'a, 'b> {
32 ExprValidator { func, infer, sink }
33 }
34
35 pub(crate) fn validate_body(&mut self, db: &impl HirDatabase) {
36 let body = self.func.body(db);
37
38 for e in body.exprs() {
39 if let (id, Expr::RecordLit { path, fields, spread }) = e {
40 self.validate_record_literal(id, path, fields, *spread, db);
41 }
42 }
43
44 let body_expr = &body[body.body_expr()];
45 if let Expr::Block { statements: _, tail: Some(t) } = body_expr {
46 self.validate_results_in_tail_expr(body.body_expr(), *t, db);
47 }
48 }
49
50 fn validate_record_literal(
51 &mut self,
52 id: ExprId,
53 _path: &Option<Path>,
54 fields: &[RecordLitField],
55 spread: Option<ExprId>,
56 db: &impl HirDatabase,
57 ) {
58 if spread.is_some() {
59 return;
60 }
61
62 let struct_def = match self.infer[id].as_adt() {
63 Some((Adt::Struct(s), _)) => s,
64 _ => return,
65 };
66
67 let lit_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect();
68 let missed_fields: Vec<Name> = struct_def
69 .fields(db)
70 .iter()
71 .filter_map(|f| {
72 let name = f.name(db);
73 if lit_fields.contains(&name) {
74 None
75 } else {
76 Some(name)
77 }
78 })
79 .collect();
80 if missed_fields.is_empty() {
81 return;
82 }
83 let source_map = self.func.body_source_map(db);
84
85 if let Some(source_ptr) = source_map.expr_syntax(id) {
86 if let Some(expr) = source_ptr.ast.a() {
87 let root = source_ptr.file_syntax(db);
88 if let ast::Expr::RecordLit(record_lit) = expr.to_node(&root) {
89 if let Some(field_list) = record_lit.record_field_list() {
90 self.sink.push(MissingFields {
91 file: source_ptr.file_id,
92 field_list: AstPtr::new(&field_list),
93 missed_fields,
94 })
95 }
96 }
97 }
98 }
99 }
100
101 fn validate_results_in_tail_expr(
102 &mut self,
103 body_id: ExprId,
104 id: ExprId,
105 db: &impl HirDatabase,
106 ) {
107 // the mismatch will be on the whole block currently
108 let mismatch = match self.infer.type_mismatch_for_expr(body_id) {
109 Some(m) => m,
110 None => return,
111 };
112
113 let std_result_path = known::std_result_result();
114
115 let resolver = self.func.resolver(db);
116 let std_result_enum = match resolver.resolve_known_enum(db, &std_result_path) {
117 Some(it) => it,
118 _ => return,
119 };
120
121 let std_result_ctor = TypeCtor::Adt(Adt::Enum(std_result_enum));
122 let params = match &mismatch.expected {
123 Ty::Apply(ApplicationTy { ctor, parameters }) if ctor == &std_result_ctor => parameters,
124 _ => return,
125 };
126
127 if params.len() == 2 && &params[0] == &mismatch.actual {
128 let source_map = self.func.body_source_map(db);
129
130 if let Some(source_ptr) = source_map.expr_syntax(id) {
131 if let Some(expr) = source_ptr.ast.a() {
132 self.sink.push(MissingOkInTailExpr { file: source_ptr.file_id, expr });
133 }
134 }
135 }
136 }
137}
diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs
index 9793af858..7e5523c54 100644
--- a/crates/ra_hir/src/from_source.rs
+++ b/crates/ra_hir/src/from_source.rs
@@ -1,6 +1,6 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir_def::{StructId, StructOrUnionId, UnionId}; 3use hir_def::{ModuleId, StructId, StructOrUnionId, UnionId};
4use hir_expand::name::AsName; 4use hir_expand::name::AsName;
5use ra_syntax::{ 5use ra_syntax::{
6 ast::{self, AstNode, NameOwner}, 6 ast::{self, AstNode, NameOwner},
@@ -10,9 +10,9 @@ use ra_syntax::{
10use crate::{ 10use crate::{
11 db::{AstDatabase, DefDatabase, HirDatabase}, 11 db::{AstDatabase, DefDatabase, HirDatabase},
12 ids::{AstItemDef, LocationCtx}, 12 ids::{AstItemDef, LocationCtx},
13 AstId, Const, Crate, DefWithBody, Enum, EnumVariant, FieldSource, Function, HasBody, HasSource, 13 Const, DefWithBody, Enum, EnumVariant, FieldSource, Function, HasBody, HasSource, ImplBlock,
14 ImplBlock, Local, Module, ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, 14 Local, Module, ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, Union,
15 Union, VariantDef, 15 VariantDef,
16}; 16};
17 17
18pub trait FromSource: Sized { 18pub trait FromSource: Sized {
@@ -152,44 +152,48 @@ impl Local {
152} 152}
153 153
154impl Module { 154impl Module {
155 pub fn from_declaration(db: &impl HirDatabase, src: Source<ast::Module>) -> Option<Self> { 155 pub fn from_declaration(db: &impl DefDatabase, src: Source<ast::Module>) -> Option<Self> {
156 let src_parent = Source { 156 let parent_declaration = src.ast.syntax().ancestors().skip(1).find_map(ast::Module::cast);
157 file_id: src.file_id, 157
158 ast: ModuleSource::new(db, Some(src.file_id.original_file(db)), None), 158 let parent_module = match parent_declaration {
159 }; 159 Some(parent_declaration) => {
160 let parent_module = Module::from_definition(db, src_parent)?; 160 let src_parent = Source { file_id: src.file_id, ast: parent_declaration };
161 Module::from_declaration(db, src_parent)
162 }
163 _ => {
164 let src_parent = Source {
165 file_id: src.file_id,
166 ast: ModuleSource::new(db, Some(src.file_id.original_file(db)), None),
167 };
168 Module::from_definition(db, src_parent)
169 }
170 }?;
171
161 let child_name = src.ast.name()?; 172 let child_name = src.ast.name()?;
162 parent_module.child(db, &child_name.as_name()) 173 parent_module.child(db, &child_name.as_name())
163 } 174 }
164 175
165 pub fn from_definition( 176 pub fn from_definition(db: &impl DefDatabase, src: Source<ModuleSource>) -> Option<Self> {
166 db: &(impl DefDatabase + AstDatabase), 177 match src.ast {
167 src: Source<ModuleSource>,
168 ) -> Option<Self> {
169 let decl_id = match src.ast {
170 ModuleSource::Module(ref module) => { 178 ModuleSource::Module(ref module) => {
171 assert!(!module.has_semi()); 179 assert!(!module.has_semi());
172 let ast_id_map = db.ast_id_map(src.file_id); 180 return Module::from_declaration(
173 let item_id = AstId::new(src.file_id, ast_id_map.ast_id(module)); 181 db,
174 Some(item_id) 182 Source { file_id: src.file_id, ast: module.clone() },
183 );
175 } 184 }
176 ModuleSource::SourceFile(_) => None, 185 ModuleSource::SourceFile(_) => (),
177 }; 186 };
178 187
179 db.relevant_crates(src.file_id.original_file(db)).iter().find_map(|&crate_id| { 188 let original_file = src.file_id.original_file(db);
180 let def_map = db.crate_def_map(crate_id);
181
182 let (module_id, _module_data) =
183 def_map.modules.iter().find(|(_module_id, module_data)| {
184 if decl_id.is_some() {
185 module_data.declaration == decl_id
186 } else {
187 module_data.definition.map(|it| it.into()) == Some(src.file_id)
188 }
189 })?;
190 189
191 Some(Module::new(Crate { crate_id }, module_id)) 190 let (krate, module_id) =
192 }) 191 db.relevant_crates(original_file).iter().find_map(|&crate_id| {
192 let crate_def_map = db.crate_def_map(crate_id);
193 let local_module_id = crate_def_map.modules_for_file(original_file).next()?;
194 Some((crate_id, local_module_id))
195 })?;
196 Some(Module { id: ModuleId { krate, module_id } })
193 } 197 }
194} 198}
195 199
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs
index 2f3e12eb8..2fb913108 100644
--- a/crates/ra_hir/src/resolve.rs
+++ b/crates/ra_hir/src/resolve.rs
@@ -16,8 +16,8 @@ use crate::{
16 expr::{ExprScopes, PatId, ScopeId}, 16 expr::{ExprScopes, PatId, ScopeId},
17 generics::GenericParams, 17 generics::GenericParams,
18 impl_block::ImplBlock, 18 impl_block::ImplBlock,
19 Adt, Const, Enum, EnumVariant, Function, MacroDef, ModuleDef, PerNs, Static, Struct, Trait, 19 Adt, Const, DefWithBody, Enum, EnumVariant, Function, Local, MacroDef, ModuleDef, PerNs,
20 TypeAlias, 20 Static, Struct, Trait, TypeAlias,
21}; 21};
22 22
23#[derive(Debug, Clone, Default)] 23#[derive(Debug, Clone, Default)]
@@ -34,6 +34,7 @@ pub(crate) struct ModuleItemMap {
34 34
35#[derive(Debug, Clone)] 35#[derive(Debug, Clone)]
36pub(crate) struct ExprScope { 36pub(crate) struct ExprScope {
37 owner: DefWithBody,
37 expr_scopes: Arc<ExprScopes>, 38 expr_scopes: Arc<ExprScopes>,
38 scope_id: ScopeId, 39 scope_id: ScopeId,
39} 40}
@@ -53,7 +54,7 @@ pub(crate) enum Scope {
53} 54}
54 55
55#[derive(Debug, Clone, PartialEq, Eq, Hash)] 56#[derive(Debug, Clone, PartialEq, Eq, Hash)]
56pub enum TypeNs { 57pub(crate) enum TypeNs {
57 SelfType(ImplBlock), 58 SelfType(ImplBlock),
58 GenericParam(u32), 59 GenericParam(u32),
59 Adt(Adt), 60 Adt(Adt),
@@ -68,13 +69,13 @@ pub enum TypeNs {
68} 69}
69 70
70#[derive(Debug, Clone, PartialEq, Eq, Hash)] 71#[derive(Debug, Clone, PartialEq, Eq, Hash)]
71pub enum ResolveValueResult { 72pub(crate) enum ResolveValueResult {
72 ValueNs(ValueNs), 73 ValueNs(ValueNs),
73 Partial(TypeNs, usize), 74 Partial(TypeNs, usize),
74} 75}
75 76
76#[derive(Debug, Clone, PartialEq, Eq, Hash)] 77#[derive(Debug, Clone, PartialEq, Eq, Hash)]
77pub enum ValueNs { 78pub(crate) enum ValueNs {
78 LocalBinding(PatId), 79 LocalBinding(PatId),
79 Function(Function), 80 Function(Function),
80 Const(Const), 81 Const(Const),
@@ -399,10 +400,11 @@ impl Resolver {
399 400
400 pub(crate) fn push_expr_scope( 401 pub(crate) fn push_expr_scope(
401 self, 402 self,
403 owner: DefWithBody,
402 expr_scopes: Arc<ExprScopes>, 404 expr_scopes: Arc<ExprScopes>,
403 scope_id: ScopeId, 405 scope_id: ScopeId,
404 ) -> Resolver { 406 ) -> Resolver {
405 self.push_scope(Scope::ExprScope(ExprScope { expr_scopes, scope_id })) 407 self.push_scope(Scope::ExprScope(ExprScope { owner, expr_scopes, scope_id }))
406 } 408 }
407} 409}
408 410
@@ -413,7 +415,7 @@ pub enum ScopeDef {
413 GenericParam(u32), 415 GenericParam(u32),
414 ImplSelfType(ImplBlock), 416 ImplSelfType(ImplBlock),
415 AdtSelfType(Adt), 417 AdtSelfType(Adt),
416 LocalBinding(PatId), 418 Local(Local),
417 Unknown, 419 Unknown,
418} 420}
419 421
@@ -467,9 +469,10 @@ impl Scope {
467 Scope::AdtScope(i) => { 469 Scope::AdtScope(i) => {
468 f(name::SELF_TYPE, ScopeDef::AdtSelfType(*i)); 470 f(name::SELF_TYPE, ScopeDef::AdtSelfType(*i));
469 } 471 }
470 Scope::ExprScope(e) => { 472 Scope::ExprScope(scope) => {
471 e.expr_scopes.entries(e.scope_id).iter().for_each(|e| { 473 scope.expr_scopes.entries(scope.scope_id).iter().for_each(|e| {
472 f(e.name().clone(), ScopeDef::LocalBinding(e.pat())); 474 let local = Local { parent: scope.owner, pat_id: e.pat() };
475 f(e.name().clone(), ScopeDef::Local(local));
473 }); 476 });
474 } 477 }
475 } 478 }
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index ca40e3b54..662d3f880 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -19,7 +19,6 @@ use ra_syntax::{
19 SyntaxKind::*, 19 SyntaxKind::*,
20 SyntaxNode, SyntaxNodePtr, TextRange, TextUnit, 20 SyntaxNode, SyntaxNodePtr, TextRange, TextUnit,
21}; 21};
22use rustc_hash::FxHashSet;
23 22
24use crate::{ 23use crate::{
25 db::HirDatabase, 24 db::HirDatabase,
@@ -195,14 +194,6 @@ impl SourceAnalyzer {
195 Some(self.infer.as_ref()?[pat_id].clone()) 194 Some(self.infer.as_ref()?[pat_id].clone())
196 } 195 }
197 196
198 pub fn type_of_pat_by_id(
199 &self,
200 _db: &impl HirDatabase,
201 pat_id: expr::PatId,
202 ) -> Option<crate::Ty> {
203 Some(self.infer.as_ref()?[pat_id].clone())
204 }
205
206 pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { 197 pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> {
207 let expr_id = self.expr_id(&call.clone().into())?; 198 let expr_id = self.expr_id(&call.clone().into())?;
208 self.infer.as_ref()?.method_resolution(expr_id) 199 self.infer.as_ref()?.method_resolution(expr_id)
@@ -293,23 +284,15 @@ impl SourceAnalyzer {
293 self.resolve_hir_path(db, &hir_path) 284 self.resolve_hir_path(db, &hir_path)
294 } 285 }
295 286
296 pub fn resolve_local_name(&self, name_ref: &ast::NameRef) -> Option<ScopeEntryWithSyntax> { 287 fn resolve_local_name(&self, name_ref: &ast::NameRef) -> Option<ScopeEntryWithSyntax> {
297 let mut shadowed = FxHashSet::default();
298 let name = name_ref.as_name(); 288 let name = name_ref.as_name();
299 let source_map = self.body_source_map.as_ref()?; 289 let source_map = self.body_source_map.as_ref()?;
300 let scopes = self.scopes.as_ref()?; 290 let scopes = self.scopes.as_ref()?;
301 let scope = scope_for(scopes, source_map, self.file_id.into(), name_ref.syntax()); 291 let scope = scope_for(scopes, source_map, self.file_id.into(), name_ref.syntax())?;
302 let ret = scopes 292 let entry = scopes.resolve_name_in_scope(scope, &name)?;
303 .scope_chain(scope) 293 Some(ScopeEntryWithSyntax {
304 .flat_map(|scope| scopes.entries(scope).iter()) 294 name: entry.name().clone(),
305 .filter(|entry| shadowed.insert(entry.name())) 295 ptr: source_map.pat_syntax(entry.pat())?.ast,
306 .filter(|entry| entry.name() == &name)
307 .nth(0);
308 ret.and_then(|entry| {
309 Some(ScopeEntryWithSyntax {
310 name: entry.name().clone(),
311 ptr: source_map.pat_syntax(entry.pat())?.ast,
312 })
313 }) 296 })
314 } 297 }
315 298
@@ -317,9 +300,9 @@ impl SourceAnalyzer {
317 self.resolver.process_all_names(db, f) 300 self.resolver.process_all_names(db, f)
318 } 301 }
319 302
303 // FIXME: we only use this in `inline_local_variable` assist, ideally, we
304 // should switch to general reference search infra there.
320 pub fn find_all_refs(&self, pat: &ast::BindPat) -> Vec<ReferenceDescriptor> { 305 pub fn find_all_refs(&self, pat: &ast::BindPat) -> Vec<ReferenceDescriptor> {
321 // FIXME: at least, this should work with any DefWithBody, but ideally
322 // this should be hir-based altogether
323 let fn_def = pat.syntax().ancestors().find_map(ast::FnDef::cast).unwrap(); 306 let fn_def = pat.syntax().ancestors().find_map(ast::FnDef::cast).unwrap();
324 let ptr = Either::A(AstPtr::new(&ast::Pat::from(pat.clone()))); 307 let ptr = Either::A(AstPtr::new(&ast::Pat::from(pat.clone())));
325 fn_def 308 fn_def
@@ -421,11 +404,6 @@ impl SourceAnalyzer {
421 pub(crate) fn inference_result(&self) -> Arc<crate::ty::InferenceResult> { 404 pub(crate) fn inference_result(&self) -> Arc<crate::ty::InferenceResult> {
422 self.infer.clone().unwrap() 405 self.infer.clone().unwrap()
423 } 406 }
424
425 #[cfg(test)]
426 pub(crate) fn scopes(&self) -> Arc<ExprScopes> {
427 self.scopes.clone().unwrap()
428 }
429} 407}
430 408
431fn scope_for( 409fn scope_for(
diff --git a/crates/ra_hir/src/test_db.rs b/crates/ra_hir/src/test_db.rs
index 5237b303a..1caa2e875 100644
--- a/crates/ra_hir/src/test_db.rs
+++ b/crates/ra_hir/src/test_db.rs
@@ -81,7 +81,7 @@ impl TestDB {
81 let crate_graph = self.crate_graph(); 81 let crate_graph = self.crate_graph();
82 for krate in crate_graph.iter().next() { 82 for krate in crate_graph.iter().next() {
83 let crate_def_map = self.crate_def_map(krate); 83 let crate_def_map = self.crate_def_map(krate);
84 for (module_id, _) in crate_def_map.modules.iter() { 84 for module_id in crate_def_map.modules() {
85 let module_id = ModuleId { krate, module_id }; 85 let module_id = ModuleId { krate, module_id };
86 let module = crate::Module::from(module_id); 86 let module = crate::Module::from(module_id);
87 module.diagnostics( 87 module.diagnostics(
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 8863c3608..fe9346c78 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -254,7 +254,6 @@ fn test(a: u32, b: isize, c: !, d: &str) {
254 1.0f32; 254 1.0f32;
255}"#), 255}"#),
256 @r###" 256 @r###"
257
258 [9; 10) 'a': u32 257 [9; 10) 'a': u32
259 [17; 18) 'b': isize 258 [17; 18) 'b': isize
260 [27; 28) 'c': ! 259 [27; 28) 'c': !
@@ -317,7 +316,6 @@ fn test() {
317} 316}
318"#), 317"#),
319 @r###" 318 @r###"
320
321 [15; 20) '{ 1 }': u32 319 [15; 20) '{ 1 }': u32
322 [17; 18) '1': u32 320 [17; 18) '1': u32
323 [48; 53) '{ 1 }': u32 321 [48; 53) '{ 1 }': u32
@@ -354,7 +352,7 @@ fn test() {
354 [66; 74) 'S::foo()': i32 352 [66; 74) 'S::foo()': i32
355 [80; 88) '<S>::foo': fn foo() -> i32 353 [80; 88) '<S>::foo': fn foo() -> i32
356 [80; 90) '<S>::foo()': i32 354 [80; 90) '<S>::foo()': i32
357"### 355 "###
358 ); 356 );
359} 357}
360 358
@@ -409,7 +407,6 @@ fn test() {
409} 407}
410"#), 408"#),
411 @r###" 409 @r###"
412
413 [72; 154) '{ ...a.c; }': () 410 [72; 154) '{ ...a.c; }': ()
414 [82; 83) 'c': C 411 [82; 83) 'c': C
415 [86; 87) 'C': C(usize) -> C 412 [86; 87) 'C': C(usize) -> C
@@ -443,7 +440,6 @@ fn test() {
443 E::V2; 440 E::V2;
444}"#), 441}"#),
445 @r###" 442 @r###"
446
447 [48; 82) '{ E:...:V2; }': () 443 [48; 82) '{ E:...:V2; }': ()
448 [52; 70) 'E::V1 ...d: 1 }': E 444 [52; 70) 'E::V1 ...d: 1 }': E
449 [67; 68) '1': u32 445 [67; 68) '1': u32
@@ -471,7 +467,6 @@ fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) {
471} 467}
472"#), 468"#),
473 @r###" 469 @r###"
474
475 [9; 10) 'a': &u32 470 [9; 10) 'a': &u32
476 [18; 19) 'b': &mut u32 471 [18; 19) 'b': &mut u32
477 [31; 32) 'c': *const u32 472 [31; 32) 'c': *const u32
@@ -524,7 +519,6 @@ fn test() {
524} 519}
525"##), 520"##),
526 @r###" 521 @r###"
527
528 [11; 221) '{ ...o"#; }': () 522 [11; 221) '{ ...o"#; }': ()
529 [17; 21) '5i32': i32 523 [17; 21) '5i32': i32
530 [27; 31) '5f32': f32 524 [27; 31) '5f32': f32
@@ -568,7 +562,6 @@ fn test(x: SomeType) {
568} 562}
569"#), 563"#),
570 @r###" 564 @r###"
571
572 [27; 28) 'x': SomeType 565 [27; 28) 'x': SomeType
573 [40; 272) '{ ...lo"; }': () 566 [40; 272) '{ ...lo"; }': ()
574 [50; 51) 'b': bool 567 [50; 51) 'b': bool
@@ -632,7 +625,6 @@ fn test() -> &mut &f64 {
632} 625}
633"#), 626"#),
634 @r###" 627 @r###"
635
636 [14; 15) 'x': u32 628 [14; 15) 'x': u32
637 [22; 24) '{}': () 629 [22; 24) '{}': ()
638 [78; 231) '{ ...t &c }': &mut &f64 630 [78; 231) '{ ...t &c }': &mut &f64
@@ -679,7 +671,6 @@ impl S {
679} 671}
680"#), 672"#),
681 @r###" 673 @r###"
682
683 [34; 38) 'self': &S 674 [34; 38) 'self': &S
684 [40; 61) '{ ... }': () 675 [40; 61) '{ ... }': ()
685 [50; 54) 'self': &S 676 [50; 54) 'self': &S
@@ -719,7 +710,6 @@ fn test() -> bool {
719} 710}
720"#), 711"#),
721 @r###" 712 @r###"
722
723 [6; 7) 'x': bool 713 [6; 7) 'x': bool
724 [22; 34) '{ 0i32 }': i32 714 [22; 34) '{ 0i32 }': i32
725 [28; 32) '0i32': i32 715 [28; 32) '0i32': i32
@@ -802,7 +792,6 @@ fn test2(a1: *const A, a2: *mut A) {
802} 792}
803"#), 793"#),
804 @r###" 794 @r###"
805
806 [44; 45) 'a': A 795 [44; 45) 'a': A
807 [50; 213) '{ ...5.b; }': () 796 [50; 213) '{ ...5.b; }': ()
808 [60; 62) 'a1': A 797 [60; 62) 'a1': A
@@ -970,7 +959,7 @@ fn test(a: A<i32>) {
970 [374; 375) 'B': B<A<i32>>(T) -> B<T> 959 [374; 375) 'B': B<A<i32>>(T) -> B<T>
971 [374; 378) 'B(a)': B<A<i32>> 960 [374; 378) 'B(a)': B<A<i32>>
972 [376; 377) 'a': A<i32> 961 [376; 377) 'a': A<i32>
973"### 962 "###
974 ); 963 );
975} 964}
976 965
@@ -983,7 +972,6 @@ fn test() {
983} 972}
984"#), 973"#),
985 @r###" 974 @r###"
986
987 [11; 37) '{ l... {}; }': () 975 [11; 37) '{ l... {}; }': ()
988 [20; 21) 'x': () 976 [20; 21) 'x': ()
989 [24; 34) 'if true {}': () 977 [24; 34) 'if true {}': ()
@@ -1105,7 +1093,6 @@ fn test(a: A) {
1105} 1093}
1106"#), 1094"#),
1107 @r###" 1095 @r###"
1108
1109 [32; 36) 'self': A 1096 [32; 36) 'self': A
1110 [38; 39) 'x': u32 1097 [38; 39) 'x': u32
1111 [53; 55) '{}': () 1098 [53; 55) '{}': ()
@@ -1142,7 +1129,6 @@ fn test() {
1142} 1129}
1143"#), 1130"#),
1144 @r###" 1131 @r###"
1145
1146 [40; 44) 'self': &str 1132 [40; 44) 'self': &str
1147 [53; 55) '{}': () 1133 [53; 55) '{}': ()
1148 [69; 89) '{ ...o(); }': () 1134 [69; 89) '{ ...o(); }': ()
@@ -1166,7 +1152,6 @@ fn test(x: &str, y: isize) {
1166} 1152}
1167"#), 1153"#),
1168 @r###" 1154 @r###"
1169
1170 [9; 10) 'x': &str 1155 [9; 10) 'x': &str
1171 [18; 19) 'y': isize 1156 [18; 19) 'y': isize
1172 [28; 170) '{ ...d"); }': () 1157 [28; 170) '{ ...d"); }': ()
@@ -1367,7 +1352,6 @@ fn test() {
1367} 1352}
1368"#), 1353"#),
1369 @r###" 1354 @r###"
1370
1371 [28; 79) '{ ...(1); }': () 1355 [28; 79) '{ ...(1); }': ()
1372 [38; 42) 'A(n)': A<i32> 1356 [38; 42) 'A(n)': A<i32>
1373 [40; 41) 'n': &i32 1357 [40; 41) 'n': &i32
@@ -1396,7 +1380,6 @@ fn test() {
1396} 1380}
1397"#), 1381"#),
1398 @r###" 1382 @r###"
1399
1400 [11; 57) '{ ...= v; }': () 1383 [11; 57) '{ ...= v; }': ()
1401 [21; 22) 'v': &(i32, &i32) 1384 [21; 22) 'v': &(i32, &i32)
1402 [25; 33) '&(1, &2)': &(i32, &i32) 1385 [25; 33) '&(1, &2)': &(i32, &i32)
@@ -1441,7 +1424,6 @@ fn test() {
1441} 1424}
1442"#), 1425"#),
1443 @r###" 1426 @r###"
1444
1445 [68; 289) '{ ... d; }': () 1427 [68; 289) '{ ... d; }': ()
1446 [78; 79) 'e': E 1428 [78; 79) 'e': E
1447 [82; 95) 'E::A { x: 3 }': E 1429 [82; 95) 'E::A { x: 3 }': E
@@ -1488,7 +1470,6 @@ fn test(a1: A<u32>, i: i32) {
1488} 1470}
1489"#), 1471"#),
1490 @r###" 1472 @r###"
1491
1492 [36; 38) 'a1': A<u32> 1473 [36; 38) 'a1': A<u32>
1493 [48; 49) 'i': i32 1474 [48; 49) 'i': i32
1494 [56; 147) '{ ...3.x; }': () 1475 [56; 147) '{ ...3.x; }': ()
@@ -1569,7 +1550,6 @@ fn test(a1: A<u32>, o: Option<u64>) {
1569} 1550}
1570"#), 1551"#),
1571 @r###" 1552 @r###"
1572
1573 [79; 81) 'a1': A<u32> 1553 [79; 81) 'a1': A<u32>
1574 [91; 92) 'o': Option<u64> 1554 [91; 92) 'o': Option<u64>
1575 [107; 244) '{ ... }; }': () 1555 [107; 244) '{ ... }; }': ()
@@ -1604,7 +1584,6 @@ fn test() {
1604} 1584}
1605"#), 1585"#),
1606 @r###" 1586 @r###"
1607
1608 [10; 11) 't': T 1587 [10; 11) 't': T
1609 [21; 26) '{ t }': T 1588 [21; 26) '{ t }': T
1610 [23; 24) 't': T 1589 [23; 24) 't': T
@@ -1652,7 +1631,6 @@ fn test() -> i128 {
1652} 1631}
1653"#), 1632"#),
1654 @r###" 1633 @r###"
1655
1656 [74; 78) 'self': A<X, Y> 1634 [74; 78) 'self': A<X, Y>
1657 [85; 107) '{ ... }': X 1635 [85; 107) '{ ... }': X
1658 [95; 99) 'self': A<X, Y> 1636 [95; 99) 'self': A<X, Y>
@@ -1706,7 +1684,6 @@ fn test(o: Option<u32>) {
1706} 1684}
1707"#), 1685"#),
1708 @r###" 1686 @r###"
1709
1710 [78; 82) 'self': &Option<T> 1687 [78; 82) 'self': &Option<T>
1711 [98; 100) '{}': () 1688 [98; 100) '{}': ()
1712 [111; 112) 'o': Option<u32> 1689 [111; 112) 'o': Option<u32>
@@ -1744,7 +1721,6 @@ fn test() -> i128 {
1744} 1721}
1745"#), 1722"#),
1746 @r###" 1723 @r###"
1747
1748 [53; 57) 'self': A<T2> 1724 [53; 57) 'self': A<T2>
1749 [65; 87) '{ ... }': T2 1725 [65; 87) '{ ... }': T2
1750 [75; 79) 'self': A<T2> 1726 [75; 79) 'self': A<T2>
@@ -1921,7 +1897,6 @@ fn test() {
1921} 1897}
1922"#), 1898"#),
1923 @r###" 1899 @r###"
1924
1925 [56; 64) '{ A {} }': A 1900 [56; 64) '{ A {} }': A
1926 [58; 62) 'A {}': A 1901 [58; 62) 'A {}': A
1927 [126; 132) '{ 99 }': u32 1902 [126; 132) '{ 99 }': u32
@@ -1961,7 +1936,6 @@ fn test() {
1961} 1936}
1962"#), 1937"#),
1963 @r###" 1938 @r###"
1964
1965 [64; 67) 'val': T 1939 [64; 67) 'val': T
1966 [82; 109) '{ ... }': Gen<T> 1940 [82; 109) '{ ... }': Gen<T>
1967 [92; 103) 'Gen { val }': Gen<T> 1941 [92; 103) 'Gen { val }': Gen<T>
@@ -2129,7 +2103,6 @@ fn test(x: X) {
2129} 2103}
2130"#), 2104"#),
2131 @r###" 2105 @r###"
2132
2133 [20; 21) 'x': X 2106 [20; 21) 'x': X
2134 [26; 47) '{ ...eld; }': () 2107 [26; 47) '{ ...eld; }': ()
2135 [32; 33) 'x': X 2108 [32; 33) 'x': X
@@ -2151,7 +2124,6 @@ fn test() {
2151} 2124}
2152"#), 2125"#),
2153 @r###" 2126 @r###"
2154
2155 [11; 89) '{ ... } }': () 2127 [11; 89) '{ ... } }': ()
2156 [17; 21) 'X {}': {unknown} 2128 [17; 21) 'X {}': {unknown}
2157 [27; 87) 'match ... }': () 2129 [27; 87) 'match ... }': ()
@@ -2174,7 +2146,6 @@ fn quux() {
2174} 2146}
2175"#), 2147"#),
2176 @r###" 2148 @r###"
2177
2178 [11; 41) '{ ...+ y; }': () 2149 [11; 41) '{ ...+ y; }': ()
2179 [21; 22) 'y': i32 2150 [21; 22) 'y': i32
2180 [25; 27) '92': i32 2151 [25; 27) '92': i32
@@ -2300,7 +2271,6 @@ fn write() {
2300} 2271}
2301"#), 2272"#),
2302 @r###" 2273 @r###"
2303
2304 [54; 139) '{ ... } }': () 2274 [54; 139) '{ ... } }': ()
2305 [60; 137) 'match ... }': () 2275 [60; 137) 'match ... }': ()
2306 [66; 83) 'someth...nknown': Maybe<{unknown}> 2276 [66; 83) 'someth...nknown': Maybe<{unknown}>
@@ -2322,7 +2292,6 @@ fn test_line_buffer() {
2322} 2292}
2323"#), 2293"#),
2324 @r###" 2294 @r###"
2325
2326 [23; 53) '{ ...n']; }': () 2295 [23; 53) '{ ...n']; }': ()
2327 [29; 50) '&[0, b...b'\n']': &[u8;_] 2296 [29; 50) '&[0, b...b'\n']': &[u8;_]
2328 [30; 50) '[0, b'...b'\n']': [u8;_] 2297 [30; 50) '[0, b'...b'\n']': [u8;_]
@@ -2446,7 +2415,6 @@ fn test<R>(query_response: Canonical<QueryResponse<R>>) {
2446} 2415}
2447"#), 2416"#),
2448 @r###" 2417 @r###"
2449
2450 [92; 106) 'query_response': Canonical<QueryResponse<R>> 2418 [92; 106) 'query_response': Canonical<QueryResponse<R>>
2451 [137; 167) '{ ...lue; }': () 2419 [137; 167) '{ ...lue; }': ()
2452 [143; 164) '&query....value': &QueryResponse<R> 2420 [143; 164) '&query....value': &QueryResponse<R>
@@ -2472,7 +2440,6 @@ pub fn main_loop() {
2472} 2440}
2473"#), 2441"#),
2474 @r###" 2442 @r###"
2475
2476 [144; 146) '{}': () 2443 [144; 146) '{}': ()
2477 [169; 198) '{ ...t(); }': () 2444 [169; 198) '{ ...t(); }': ()
2478 [175; 193) 'FxHash...efault': fn default<{unknown}, FxHasher>() -> HashSet<T, H> 2445 [175; 193) 'FxHash...efault': fn default<{unknown}, FxHasher>() -> HashSet<T, H>
@@ -2518,7 +2485,6 @@ fn test() {
2518} 2485}
2519"#), 2486"#),
2520 @r###" 2487 @r###"
2521
2522 [49; 50) '0': u32 2488 [49; 50) '0': u32
2523 [80; 83) '101': u32 2489 [80; 83) '101': u32
2524 [95; 213) '{ ...NST; }': () 2490 [95; 213) '{ ...NST; }': ()
@@ -2549,7 +2515,6 @@ fn test() {
2549} 2515}
2550"#), 2516"#),
2551 @r###" 2517 @r###"
2552
2553 [29; 32) '101': u32 2518 [29; 32) '101': u32
2554 [70; 73) '101': u32 2519 [70; 73) '101': u32
2555 [85; 280) '{ ...MUT; }': () 2520 [85; 280) '{ ...MUT; }': ()
@@ -2588,7 +2553,6 @@ fn test() {
2588} 2553}
2589"#), 2554"#),
2590 @r###" 2555 @r###"
2591
2592 [31; 35) 'self': &Self 2556 [31; 35) 'self': &Self
2593 [110; 114) 'self': &Self 2557 [110; 114) 'self': &Self
2594 [170; 228) '{ ...i128 }': () 2558 [170; 228) '{ ...i128 }': ()
@@ -2636,7 +2600,6 @@ mod bar_test {
2636} 2600}
2637"#), 2601"#),
2638 @r###" 2602 @r###"
2639
2640 [63; 67) 'self': &Self 2603 [63; 67) 'self': &Self
2641 [169; 173) 'self': &Self 2604 [169; 173) 'self': &Self
2642 [300; 337) '{ ... }': () 2605 [300; 337) '{ ... }': ()
@@ -2664,7 +2627,6 @@ fn test() {
2664} 2627}
2665"#), 2628"#),
2666 @r###" 2629 @r###"
2667
2668 [33; 37) 'self': &Self 2630 [33; 37) 'self': &Self
2669 [92; 111) '{ ...d(); }': () 2631 [92; 111) '{ ...d(); }': ()
2670 [98; 99) 'S': S 2632 [98; 99) 'S': S
@@ -2694,7 +2656,6 @@ fn test() {
2694} 2656}
2695"#), 2657"#),
2696 @r###" 2658 @r###"
2697
2698 [43; 47) 'self': &Self 2659 [43; 47) 'self': &Self
2699 [82; 86) 'self': &Self 2660 [82; 86) 'self': &Self
2700 [210; 361) '{ ..., i8 }': () 2661 [210; 361) '{ ..., i8 }': ()
@@ -2725,7 +2686,6 @@ fn test() {
2725} 2686}
2726"#), 2687"#),
2727 @r###" 2688 @r###"
2728
2729 [33; 37) 'self': &Self 2689 [33; 37) 'self': &Self
2730 [102; 127) '{ ...d(); }': () 2690 [102; 127) '{ ...d(); }': ()
2731 [108; 109) 'S': S<u32>(T) -> S<T> 2691 [108; 109) 'S': S<u32>(T) -> S<T>
@@ -3130,7 +3090,6 @@ fn test<T: Iterable<Item=u32>>() {
3130} 3090}
3131"#), 3091"#),
3132 @r###" 3092 @r###"
3133
3134 [67; 100) '{ ...own; }': () 3093 [67; 100) '{ ...own; }': ()
3135 [77; 78) 'y': {unknown} 3094 [77; 78) 'y': {unknown}
3136 [90; 97) 'unknown': {unknown} 3095 [90; 97) 'unknown': {unknown}
@@ -3146,7 +3105,6 @@ const A: u32 = 1 + 1;
3146static B: u64 = { let x = 1; x }; 3105static B: u64 = { let x = 1; x };
3147"#), 3106"#),
3148 @r###" 3107 @r###"
3149
3150 [16; 17) '1': u32 3108 [16; 17) '1': u32
3151 [16; 21) '1 + 1': u32 3109 [16; 21) '1 + 1': u32
3152 [20; 21) '1': u32 3110 [20; 21) '1': u32
@@ -3170,7 +3128,6 @@ fn test() -> u64 {
3170} 3128}
3171"#), 3129"#),
3172 @r###" 3130 @r###"
3173
3174 [38; 87) '{ ... a.1 }': u64 3131 [38; 87) '{ ... a.1 }': u64
3175 [48; 49) 'a': S 3132 [48; 49) 'a': S
3176 [52; 53) 'S': S(i32, u64) -> S 3133 [52; 53) 'S': S(i32, u64) -> S
@@ -3225,7 +3182,6 @@ fn indexing_arrays() {
3225 assert_snapshot!( 3182 assert_snapshot!(
3226 infer("fn main() { &mut [9][2]; }"), 3183 infer("fn main() { &mut [9][2]; }"),
3227 @r###" 3184 @r###"
3228
3229 [10; 26) '{ &mut...[2]; }': () 3185 [10; 26) '{ &mut...[2]; }': ()
3230 [12; 23) '&mut [9][2]': &mut {unknown} 3186 [12; 23) '&mut [9][2]': &mut {unknown}
3231 [17; 20) '[9]': [i32;_] 3187 [17; 20) '[9]': [i32;_]
@@ -4822,9 +4778,9 @@ fn main() {
4822} 4778}
4823"#), 4779"#),
4824 @r###" 4780 @r###"
4825 ![0; 1) '6': i32 4781 ![0; 1) '6': i32
4826 [64; 88) '{ ...!(); }': () 4782 [64; 88) '{ ...!(); }': ()
4827 [74; 75) 'x': i32 4783 [74; 75) 'x': i32
4828 "### 4784 "###
4829 ); 4785 );
4830} 4786}
diff --git a/crates/ra_hir_def/src/body/scope.rs b/crates/ra_hir_def/src/body/scope.rs
index 09a39e721..10cb87d37 100644
--- a/crates/ra_hir_def/src/body/scope.rs
+++ b/crates/ra_hir_def/src/body/scope.rs
@@ -67,6 +67,11 @@ impl ExprScopes {
67 std::iter::successors(scope, move |&scope| self.scopes[scope].parent) 67 std::iter::successors(scope, move |&scope| self.scopes[scope].parent)
68 } 68 }
69 69
70 pub fn resolve_name_in_scope(&self, scope: ScopeId, name: &Name) -> Option<&ScopeEntry> {
71 self.scope_chain(Some(scope))
72 .find_map(|scope| self.entries(scope).iter().find(|it| it.name == *name))
73 }
74
70 pub fn scope_for(&self, expr: ExprId) -> Option<ScopeId> { 75 pub fn scope_for(&self, expr: ExprId) -> Option<ScopeId> {
71 self.scope_by_expr.get(&expr).copied() 76 self.scope_by_expr.get(&expr).copied()
72 } 77 }
@@ -163,3 +168,217 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope
163 e => e.walk_child_exprs(|e| compute_expr_scopes(e, body, scopes, scope)), 168 e => e.walk_child_exprs(|e| compute_expr_scopes(e, body, scopes, scope)),
164 }; 169 };
165} 170}
171
172#[cfg(test)]
173mod tests {
174 use hir_expand::{name::AsName, Source};
175 use ra_db::{fixture::WithFixture, FileId, SourceDatabase};
176 use ra_syntax::{algo::find_node_at_offset, ast, AstNode};
177 use test_utils::{assert_eq_text, extract_offset};
178
179 use crate::{db::DefDatabase2, test_db::TestDB, FunctionId, ModuleDefId};
180
181 fn find_function(db: &TestDB, file_id: FileId) -> FunctionId {
182 let krate = db.test_crate();
183 let crate_def_map = db.crate_def_map(krate);
184
185 let module = crate_def_map.modules_for_file(file_id).next().unwrap();
186 let (_, res) = crate_def_map[module].scope.entries().next().unwrap();
187 match res.def.take_values().unwrap() {
188 ModuleDefId::FunctionId(it) => it,
189 _ => panic!(),
190 }
191 }
192
193 fn do_check(code: &str, expected: &[&str]) {
194 let (off, code) = extract_offset(code);
195 let code = {
196 let mut buf = String::new();
197 let off = u32::from(off) as usize;
198 buf.push_str(&code[..off]);
199 buf.push_str("marker");
200 buf.push_str(&code[off..]);
201 buf
202 };
203
204 let (db, file_id) = TestDB::with_single_file(&code);
205
206 let file_syntax = db.parse(file_id).syntax_node();
207 let marker: ast::PathExpr = find_node_at_offset(&file_syntax, off).unwrap();
208 let function = find_function(&db, file_id);
209
210 let scopes = db.expr_scopes(function.into());
211 let (_body, source_map) = db.body_with_source_map(function.into());
212
213 let expr_id =
214 source_map.node_expr(Source { file_id: file_id.into(), ast: &marker.into() }).unwrap();
215 let scope = scopes.scope_for(expr_id);
216
217 let actual = scopes
218 .scope_chain(scope)
219 .flat_map(|scope| scopes.entries(scope))
220 .map(|it| it.name().to_string())
221 .collect::<Vec<_>>()
222 .join("\n");
223 let expected = expected.join("\n");
224 assert_eq_text!(&expected, &actual);
225 }
226
227 #[test]
228 fn test_lambda_scope() {
229 do_check(
230 r"
231 fn quux(foo: i32) {
232 let f = |bar, baz: i32| {
233 <|>
234 };
235 }",
236 &["bar", "baz", "foo"],
237 );
238 }
239
240 #[test]
241 fn test_call_scope() {
242 do_check(
243 r"
244 fn quux() {
245 f(|x| <|> );
246 }",
247 &["x"],
248 );
249 }
250
251 #[test]
252 fn test_method_call_scope() {
253 do_check(
254 r"
255 fn quux() {
256 z.f(|x| <|> );
257 }",
258 &["x"],
259 );
260 }
261
262 #[test]
263 fn test_loop_scope() {
264 do_check(
265 r"
266 fn quux() {
267 loop {
268 let x = ();
269 <|>
270 };
271 }",
272 &["x"],
273 );
274 }
275
276 #[test]
277 fn test_match() {
278 do_check(
279 r"
280 fn quux() {
281 match () {
282 Some(x) => {
283 <|>
284 }
285 };
286 }",
287 &["x"],
288 );
289 }
290
291 #[test]
292 fn test_shadow_variable() {
293 do_check(
294 r"
295 fn foo(x: String) {
296 let x : &str = &x<|>;
297 }",
298 &["x"],
299 );
300 }
301
302 fn do_check_local_name(code: &str, expected_offset: u32) {
303 let (off, code) = extract_offset(code);
304
305 let (db, file_id) = TestDB::with_single_file(&code);
306
307 let file = db.parse(file_id).ok().unwrap();
308 let expected_name = find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into())
309 .expect("failed to find a name at the target offset");
310 let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap();
311
312 let function = find_function(&db, file_id);
313
314 let scopes = db.expr_scopes(function.into());
315 let (_body, source_map) = db.body_with_source_map(function.into());
316
317 let expr_scope = {
318 let expr_ast = name_ref.syntax().ancestors().find_map(ast::Expr::cast).unwrap();
319 let expr_id =
320 source_map.node_expr(Source { file_id: file_id.into(), ast: &expr_ast }).unwrap();
321 scopes.scope_for(expr_id).unwrap()
322 };
323
324 let resolved = scopes.resolve_name_in_scope(expr_scope, &name_ref.as_name()).unwrap();
325 let pat_src = source_map.pat_syntax(resolved.pat()).unwrap();
326
327 let local_name = pat_src.ast.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr());
328 assert_eq!(local_name.range(), expected_name.syntax().text_range());
329 }
330
331 #[test]
332 fn test_resolve_local_name() {
333 do_check_local_name(
334 r#"
335 fn foo(x: i32, y: u32) {
336 {
337 let z = x * 2;
338 }
339 {
340 let t = x<|> * 3;
341 }
342 }"#,
343 21,
344 );
345 }
346
347 #[test]
348 fn test_resolve_local_name_declaration() {
349 do_check_local_name(
350 r#"
351 fn foo(x: String) {
352 let x : &str = &x<|>;
353 }"#,
354 21,
355 );
356 }
357
358 #[test]
359 fn test_resolve_local_name_shadow() {
360 do_check_local_name(
361 r"
362 fn foo(x: String) {
363 let x : &str = &x;
364 x<|>
365 }
366 ",
367 53,
368 );
369 }
370
371 #[test]
372 fn ref_patterns_contribute_bindings() {
373 do_check_local_name(
374 r"
375 fn foo() {
376 if let Some(&from) = bar() {
377 from<|>;
378 }
379 }
380 ",
381 53,
382 );
383 }
384}
diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs
index d3ecabb9b..21d5f62e0 100644
--- a/crates/ra_hir_def/src/nameres.rs
+++ b/crates/ra_hir_def/src/nameres.rs
@@ -58,7 +58,7 @@ mod tests;
58 58
59use std::sync::Arc; 59use std::sync::Arc;
60 60
61use hir_expand::{diagnostics::DiagnosticSink, name::Name, MacroDefId}; 61use hir_expand::{ast_id_map::FileAstId, diagnostics::DiagnosticSink, name::Name, MacroDefId};
62use once_cell::sync::Lazy; 62use once_cell::sync::Lazy;
63use ra_arena::Arena; 63use ra_arena::Arena;
64use ra_db::{CrateId, Edition, FileId}; 64use ra_db::{CrateId, Edition, FileId};
@@ -73,7 +73,7 @@ use crate::{
73 diagnostics::DefDiagnostic, path_resolution::ResolveMode, per_ns::PerNs, raw::ImportId, 73 diagnostics::DefDiagnostic, path_resolution::ResolveMode, per_ns::PerNs, raw::ImportId,
74 }, 74 },
75 path::Path, 75 path::Path,
76 AstId, CrateModuleId, ModuleDefId, ModuleId, TraitId, 76 AstId, CrateModuleId, FunctionId, ModuleDefId, ModuleId, TraitId,
77}; 77};
78 78
79/// Contains all top-level defs from a macro-expanded crate 79/// Contains all top-level defs from a macro-expanded crate
@@ -87,7 +87,7 @@ pub struct CrateDefMap {
87 prelude: Option<ModuleId>, 87 prelude: Option<ModuleId>,
88 extern_prelude: FxHashMap<Name, ModuleDefId>, 88 extern_prelude: FxHashMap<Name, ModuleDefId>,
89 root: CrateModuleId, 89 root: CrateModuleId,
90 pub modules: Arena<CrateModuleId, ModuleData>, 90 modules: Arena<CrateModuleId, ModuleData>,
91 91
92 /// Some macros are not well-behavior, which leads to infinite loop 92 /// Some macros are not well-behavior, which leads to infinite loop
93 /// e.g. macro_rules! foo { ($ty:ty) => { foo!($ty); } } 93 /// e.g. macro_rules! foo { ($ty:ty) => { foo!($ty); } }
@@ -124,6 +124,11 @@ pub struct ModuleData {
124 pub definition: Option<FileId>, 124 pub definition: Option<FileId>,
125} 125}
126 126
127#[derive(Default, Debug, PartialEq, Eq, Clone)]
128pub(crate) struct Declarations {
129 fns: FxHashMap<FileAstId<ast::FnDef>, FunctionId>,
130}
131
127#[derive(Debug, Default, PartialEq, Eq, Clone)] 132#[derive(Debug, Default, PartialEq, Eq, Clone)]
128pub struct ModuleScope { 133pub struct ModuleScope {
129 pub items: FxHashMap<Name, Resolution>, 134 pub items: FxHashMap<Name, Resolution>,
@@ -258,6 +263,17 @@ impl CrateDefMap {
258 let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path); 263 let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path);
259 (res.resolved_def, res.segment_index) 264 (res.resolved_def, res.segment_index)
260 } 265 }
266
267 pub fn modules(&self) -> impl Iterator<Item = CrateModuleId> + '_ {
268 self.modules.iter().map(|(id, _data)| id)
269 }
270
271 pub fn modules_for_file(&self, file_id: FileId) -> impl Iterator<Item = CrateModuleId> + '_ {
272 self.modules
273 .iter()
274 .filter(move |(_id, data)| data.definition == Some(file_id))
275 .map(|(id, _data)| id)
276 }
261} 277}
262 278
263mod diagnostics { 279mod diagnostics {
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs
index 37d0f3093..5c899aff3 100644
--- a/crates/ra_hir_def/src/nameres/collector.rs
+++ b/crates/ra_hir_def/src/nameres/collector.rs
@@ -664,7 +664,8 @@ where
664 let name = def.name.clone(); 664 let name = def.name.clone();
665 let def: PerNs = match def.kind { 665 let def: PerNs = match def.kind {
666 raw::DefKind::Function(ast_id) => { 666 raw::DefKind::Function(ast_id) => {
667 PerNs::values(FunctionId::from_ast_id(ctx, ast_id).into()) 667 let f = FunctionId::from_ast_id(ctx, ast_id);
668 PerNs::values(f.into())
668 } 669 }
669 raw::DefKind::Struct(ast_id) => { 670 raw::DefKind::Struct(ast_id) => {
670 let id = StructOrUnionId::from_ast_id(ctx, ast_id).into(); 671 let id = StructOrUnionId::from_ast_id(ctx, ast_id).into();
@@ -798,7 +799,7 @@ mod tests {
798 799
799 fn do_limited_resolve(code: &str, limit: u32, poison_limit: u32) -> CrateDefMap { 800 fn do_limited_resolve(code: &str, limit: u32, poison_limit: u32) -> CrateDefMap {
800 let (db, _file_id) = TestDB::with_single_file(&code); 801 let (db, _file_id) = TestDB::with_single_file(&code);
801 let krate = db.crate_graph().iter().next().unwrap(); 802 let krate = db.test_crate();
802 803
803 let def_map = { 804 let def_map = {
804 let edition = db.crate_graph().edition(krate); 805 let edition = db.crate_graph().edition(krate);
diff --git a/crates/ra_hir_def/src/nameres/tests/incremental.rs b/crates/ra_hir_def/src/nameres/tests/incremental.rs
index 80dcec62f..903a22771 100644
--- a/crates/ra_hir_def/src/nameres/tests/incremental.rs
+++ b/crates/ra_hir_def/src/nameres/tests/incremental.rs
@@ -1,12 +1,12 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use ra_db::{SourceDatabase, SourceDatabaseExt}; 3use ra_db::SourceDatabaseExt;
4 4
5use super::*; 5use super::*;
6 6
7fn check_def_map_is_not_recomputed(initial: &str, file_change: &str) { 7fn check_def_map_is_not_recomputed(initial: &str, file_change: &str) {
8 let (mut db, pos) = TestDB::with_position(initial); 8 let (mut db, pos) = TestDB::with_position(initial);
9 let krate = db.crate_graph().iter().next().unwrap(); 9 let krate = db.test_crate();
10 { 10 {
11 let events = db.log_executed(|| { 11 let events = db.log_executed(|| {
12 db.crate_def_map(krate); 12 db.crate_def_map(krate);
@@ -111,7 +111,7 @@ fn typing_inside_a_macro_should_not_invalidate_def_map() {
111 m!(X); 111 m!(X);
112 ", 112 ",
113 ); 113 );
114 let krate = db.crate_graph().iter().next().unwrap(); 114 let krate = db.test_crate();
115 { 115 {
116 let events = db.log_executed(|| { 116 let events = db.log_executed(|| {
117 let crate_def_map = db.crate_def_map(krate); 117 let crate_def_map = db.crate_def_map(krate);
diff --git a/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs
index dee364a14..eb7b85c07 100644
--- a/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs
+++ b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs
@@ -656,7 +656,7 @@ fn unresolved_module_diagnostics() {
656 //- /foo.rs 656 //- /foo.rs
657 ", 657 ",
658 ); 658 );
659 let krate = db.crate_graph().iter().next().unwrap(); 659 let krate = db.test_crate();
660 660
661 let crate_def_map = db.crate_def_map(krate); 661 let crate_def_map = db.crate_def_map(krate);
662 662
diff --git a/crates/ra_hir_expand/src/quote.rs b/crates/ra_hir_expand/src/quote.rs
index 9cd17f0e3..35133d216 100644
--- a/crates/ra_hir_expand/src/quote.rs
+++ b/crates/ra_hir_expand/src/quote.rs
@@ -241,10 +241,8 @@ mod tests {
241 // } 241 // }
242 let struct_name = mk_ident("Foo"); 242 let struct_name = mk_ident("Foo");
243 let fields = [mk_ident("name"), mk_ident("id")]; 243 let fields = [mk_ident("name"), mk_ident("id")];
244 let fields = fields 244 let fields =
245 .into_iter() 245 fields.iter().map(|it| quote!(#it: self.#it.clone(), ).token_trees.clone()).flatten();
246 .map(|it| quote!(#it: self.#it.clone(), ).token_trees.clone())
247 .flatten();
248 246
249 let list = tt::Subtree { delimiter: tt::Delimiter::Brace, token_trees: fields.collect() }; 247 let list = tt::Subtree { delimiter: tt::Delimiter::Brace, token_trees: fields.collect() };
250 248
diff --git a/crates/ra_ide_api/src/completion/complete_dot.rs b/crates/ra_ide_api/src/completion/complete_dot.rs
index b4df6ee2a..4e2c497e1 100644
--- a/crates/ra_ide_api/src/completion/complete_dot.rs
+++ b/crates/ra_ide_api/src/completion/complete_dot.rs
@@ -88,16 +88,16 @@ mod tests {
88 ", 88 ",
89 ), 89 ),
90 @r###" 90 @r###"
91 [ 91 [
92 CompletionItem { 92 CompletionItem {
93 label: "the_field", 93 label: "the_field",
94 source_range: [94; 94), 94 source_range: [94; 94),
95 delete: [94; 94), 95 delete: [94; 94),
96 insert: "the_field", 96 insert: "the_field",
97 kind: Field, 97 kind: Field,
98 detail: "u32", 98 detail: "u32",
99 }, 99 },
100 ] 100 ]
101 "### 101 "###
102 ); 102 );
103 } 103 }
@@ -349,24 +349,24 @@ mod tests {
349 ", 349 ",
350 ), 350 ),
351 @r###" 351 @r###"
352 [ 352 [
353 CompletionItem { 353 CompletionItem {
354 label: "0", 354 label: "0",
355 source_range: [75; 75), 355 source_range: [75; 75),
356 delete: [75; 75), 356 delete: [75; 75),
357 insert: "0", 357 insert: "0",
358 kind: Field, 358 kind: Field,
359 detail: "i32", 359 detail: "i32",
360 }, 360 },
361 CompletionItem { 361 CompletionItem {
362 label: "1", 362 label: "1",
363 source_range: [75; 75), 363 source_range: [75; 75),
364 delete: [75; 75), 364 delete: [75; 75),
365 insert: "1", 365 insert: "1",
366 kind: Field, 366 kind: Field,
367 detail: "f64", 367 detail: "f64",
368 }, 368 },
369 ] 369 ]
370 "### 370 "###
371 ); 371 );
372 } 372 }
@@ -419,16 +419,16 @@ mod tests {
419 ", 419 ",
420 ), 420 ),
421 @r###" 421 @r###"
422 [ 422 [
423 CompletionItem { 423 CompletionItem {
424 label: "the_field", 424 label: "the_field",
425 source_range: [106; 106), 425 source_range: [106; 106),
426 delete: [106; 106), 426 delete: [106; 106),
427 insert: "the_field", 427 insert: "the_field",
428 kind: Field, 428 kind: Field,
429 detail: "u32", 429 detail: "u32",
430 }, 430 },
431 ] 431 ]
432 "### 432 "###
433 ); 433 );
434 } 434 }
@@ -452,15 +452,15 @@ mod tests {
452 } 452 }
453 "###, CompletionKind::Keyword), 453 "###, CompletionKind::Keyword),
454 @r###" 454 @r###"
455 [ 455 [
456 CompletionItem { 456 CompletionItem {
457 label: "await", 457 label: "await",
458 source_range: [74; 74), 458 source_range: [74; 74),
459 delete: [74; 74), 459 delete: [74; 74),
460 insert: "await", 460 insert: "await",
461 detail: "expr.await", 461 detail: "expr.await",
462 }, 462 },
463 ] 463 ]
464 "### 464 "###
465 ) 465 )
466 } 466 }
diff --git a/crates/ra_ide_api/src/completion/complete_fn_param.rs b/crates/ra_ide_api/src/completion/complete_fn_param.rs
index 3e936e3ec..502458706 100644
--- a/crates/ra_ide_api/src/completion/complete_fn_param.rs
+++ b/crates/ra_ide_api/src/completion/complete_fn_param.rs
@@ -70,15 +70,15 @@ mod tests {
70 ", 70 ",
71 ), 71 ),
72 @r###" 72 @r###"
73 [ 73 [
74 CompletionItem { 74 CompletionItem {
75 label: "file_id: FileId", 75 label: "file_id: FileId",
76 source_range: [110; 114), 76 source_range: [110; 114),
77 delete: [110; 114), 77 delete: [110; 114),
78 insert: "file_id: FileId", 78 insert: "file_id: FileId",
79 lookup: "file_id", 79 lookup: "file_id",
80 }, 80 },
81 ] 81 ]
82 "### 82 "###
83 ); 83 );
84 } 84 }
@@ -94,15 +94,15 @@ mod tests {
94 ", 94 ",
95 ), 95 ),
96 @r###" 96 @r###"
97 [ 97 [
98 CompletionItem { 98 CompletionItem {
99 label: "file_id: FileId", 99 label: "file_id: FileId",
100 source_range: [110; 114), 100 source_range: [110; 114),
101 delete: [110; 114), 101 delete: [110; 114),
102 insert: "file_id: FileId", 102 insert: "file_id: FileId",
103 lookup: "file_id", 103 lookup: "file_id",
104 }, 104 },
105 ] 105 ]
106 "### 106 "###
107 ); 107 );
108 } 108 }
@@ -121,15 +121,15 @@ mod tests {
121 ", 121 ",
122 ), 122 ),
123 @r###" 123 @r###"
124 [ 124 [
125 CompletionItem { 125 CompletionItem {
126 label: "file_id: FileId", 126 label: "file_id: FileId",
127 source_range: [289; 293), 127 source_range: [289; 293),
128 delete: [289; 293), 128 delete: [289; 293),
129 insert: "file_id: FileId", 129 insert: "file_id: FileId",
130 lookup: "file_id", 130 lookup: "file_id",
131 }, 131 },
132 ] 132 ]
133 "### 133 "###
134 ); 134 );
135 } 135 }
diff --git a/crates/ra_ide_api/src/completion/complete_keyword.rs b/crates/ra_ide_api/src/completion/complete_keyword.rs
index 48c688a08..eb7cd9ac2 100644
--- a/crates/ra_ide_api/src/completion/complete_keyword.rs
+++ b/crates/ra_ide_api/src/completion/complete_keyword.rs
@@ -131,29 +131,31 @@ mod tests {
131 use <|> 131 use <|>
132 ", 132 ",
133 ), 133 ),
134 @r###"[ 134 @r###"
135 CompletionItem { 135 [
136 label: "crate", 136 CompletionItem {
137 source_range: [21; 21), 137 label: "crate",
138 delete: [21; 21), 138 source_range: [21; 21),
139 insert: "crate::", 139 delete: [21; 21),
140 kind: Keyword, 140 insert: "crate::",
141 }, 141 kind: Keyword,
142 CompletionItem { 142 },
143 label: "self", 143 CompletionItem {
144 source_range: [21; 21), 144 label: "self",
145 delete: [21; 21), 145 source_range: [21; 21),
146 insert: "self", 146 delete: [21; 21),
147 kind: Keyword, 147 insert: "self",
148 }, 148 kind: Keyword,
149 CompletionItem { 149 },
150 label: "super", 150 CompletionItem {
151 source_range: [21; 21), 151 label: "super",
152 delete: [21; 21), 152 source_range: [21; 21),
153 insert: "super::", 153 delete: [21; 21),
154 kind: Keyword, 154 insert: "super::",
155 }, 155 kind: Keyword,
156]"### 156 },
157 ]
158 "###
157 ); 159 );
158 160
159 assert_debug_snapshot!( 161 assert_debug_snapshot!(
@@ -162,22 +164,24 @@ mod tests {
162 use a::<|> 164 use a::<|>
163 ", 165 ",
164 ), 166 ),
165 @r###"[ 167 @r###"
166 CompletionItem { 168 [
167 label: "self", 169 CompletionItem {
168 source_range: [24; 24), 170 label: "self",
169 delete: [24; 24), 171 source_range: [24; 24),
170 insert: "self", 172 delete: [24; 24),
171 kind: Keyword, 173 insert: "self",
172 }, 174 kind: Keyword,
173 CompletionItem { 175 },
174 label: "super", 176 CompletionItem {
175 source_range: [24; 24), 177 label: "super",
176 delete: [24; 24), 178 source_range: [24; 24),
177 insert: "super::", 179 delete: [24; 24),
178 kind: Keyword, 180 insert: "super::",
179 }, 181 kind: Keyword,
180]"### 182 },
183 ]
184 "###
181 ); 185 );
182 186
183 assert_debug_snapshot!( 187 assert_debug_snapshot!(
@@ -186,22 +190,24 @@ mod tests {
186 use a::{b, <|>} 190 use a::{b, <|>}
187 ", 191 ",
188 ), 192 ),
189 @r###"[ 193 @r###"
190 CompletionItem { 194 [
191 label: "self", 195 CompletionItem {
192 source_range: [28; 28), 196 label: "self",
193 delete: [28; 28), 197 source_range: [28; 28),
194 insert: "self", 198 delete: [28; 28),
195 kind: Keyword, 199 insert: "self",
196 }, 200 kind: Keyword,
197 CompletionItem { 201 },
198 label: "super", 202 CompletionItem {
199 source_range: [28; 28), 203 label: "super",
200 delete: [28; 28), 204 source_range: [28; 28),
201 insert: "super::", 205 delete: [28; 28),
202 kind: Keyword, 206 insert: "super::",
203 }, 207 kind: Keyword,
204]"### 208 },
209 ]
210 "###
205 ); 211 );
206 } 212 }
207 213
@@ -215,43 +221,45 @@ mod tests {
215 } 221 }
216 ", 222 ",
217 ), 223 ),
218 @r###"[ 224 @r###"
219 CompletionItem { 225 [
220 label: "if", 226 CompletionItem {
221 source_range: [49; 49), 227 label: "if",
222 delete: [49; 49), 228 source_range: [49; 49),
223 insert: "if $0 {}", 229 delete: [49; 49),
224 kind: Keyword, 230 insert: "if $0 {}",
225 }, 231 kind: Keyword,
226 CompletionItem { 232 },
227 label: "loop", 233 CompletionItem {
228 source_range: [49; 49), 234 label: "loop",
229 delete: [49; 49), 235 source_range: [49; 49),
230 insert: "loop {$0}", 236 delete: [49; 49),
231 kind: Keyword, 237 insert: "loop {$0}",
232 }, 238 kind: Keyword,
233 CompletionItem { 239 },
234 label: "match", 240 CompletionItem {
235 source_range: [49; 49), 241 label: "match",
236 delete: [49; 49), 242 source_range: [49; 49),
237 insert: "match $0 {}", 243 delete: [49; 49),
238 kind: Keyword, 244 insert: "match $0 {}",
239 }, 245 kind: Keyword,
240 CompletionItem { 246 },
241 label: "return", 247 CompletionItem {
242 source_range: [49; 49), 248 label: "return",
243 delete: [49; 49), 249 source_range: [49; 49),
244 insert: "return;", 250 delete: [49; 49),
245 kind: Keyword, 251 insert: "return;",
246 }, 252 kind: Keyword,
247 CompletionItem { 253 },
248 label: "while", 254 CompletionItem {
249 source_range: [49; 49), 255 label: "while",
250 delete: [49; 49), 256 source_range: [49; 49),
251 insert: "while $0 {}", 257 delete: [49; 49),
252 kind: Keyword, 258 insert: "while $0 {}",
253 }, 259 kind: Keyword,
254]"### 260 },
261 ]
262 "###
255 ); 263 );
256 } 264 }
257 265
@@ -267,57 +275,59 @@ mod tests {
267 } 275 }
268 ", 276 ",
269 ), 277 ),
270 @r###"[ 278 @r###"
271 CompletionItem { 279 [
272 label: "else", 280 CompletionItem {
273 source_range: [108; 108), 281 label: "else",
274 delete: [108; 108), 282 source_range: [108; 108),
275 insert: "else {$0}", 283 delete: [108; 108),
276 kind: Keyword, 284 insert: "else {$0}",
277 }, 285 kind: Keyword,
278 CompletionItem { 286 },
279 label: "else if", 287 CompletionItem {
280 source_range: [108; 108), 288 label: "else if",
281 delete: [108; 108), 289 source_range: [108; 108),
282 insert: "else if $0 {}", 290 delete: [108; 108),
283 kind: Keyword, 291 insert: "else if $0 {}",
284 }, 292 kind: Keyword,
285 CompletionItem { 293 },
286 label: "if", 294 CompletionItem {
287 source_range: [108; 108), 295 label: "if",
288 delete: [108; 108), 296 source_range: [108; 108),
289 insert: "if $0 {}", 297 delete: [108; 108),
290 kind: Keyword, 298 insert: "if $0 {}",
291 }, 299 kind: Keyword,
292 CompletionItem { 300 },
293 label: "loop", 301 CompletionItem {
294 source_range: [108; 108), 302 label: "loop",
295 delete: [108; 108), 303 source_range: [108; 108),
296 insert: "loop {$0}", 304 delete: [108; 108),
297 kind: Keyword, 305 insert: "loop {$0}",
298 }, 306 kind: Keyword,
299 CompletionItem { 307 },
300 label: "match", 308 CompletionItem {
301 source_range: [108; 108), 309 label: "match",
302 delete: [108; 108), 310 source_range: [108; 108),
303 insert: "match $0 {}", 311 delete: [108; 108),
304 kind: Keyword, 312 insert: "match $0 {}",
305 }, 313 kind: Keyword,
306 CompletionItem { 314 },
307 label: "return", 315 CompletionItem {
308 source_range: [108; 108), 316 label: "return",
309 delete: [108; 108), 317 source_range: [108; 108),
310 insert: "return;", 318 delete: [108; 108),
311 kind: Keyword, 319 insert: "return;",
312 }, 320 kind: Keyword,
313 CompletionItem { 321 },
314 label: "while", 322 CompletionItem {
315 source_range: [108; 108), 323 label: "while",
316 delete: [108; 108), 324 source_range: [108; 108),
317 insert: "while $0 {}", 325 delete: [108; 108),
318 kind: Keyword, 326 insert: "while $0 {}",
319 }, 327 kind: Keyword,
320]"### 328 },
329 ]
330 "###
321 ); 331 );
322 } 332 }
323 333
@@ -332,43 +342,45 @@ mod tests {
332 } 342 }
333 ", 343 ",
334 ), 344 ),
335 @r###"[ 345 @r###"
336 CompletionItem { 346 [
337 label: "if", 347 CompletionItem {
338 source_range: [56; 56), 348 label: "if",
339 delete: [56; 56), 349 source_range: [56; 56),
340 insert: "if $0 {}", 350 delete: [56; 56),
341 kind: Keyword, 351 insert: "if $0 {}",
342 }, 352 kind: Keyword,
343 CompletionItem { 353 },
344 label: "loop", 354 CompletionItem {
345 source_range: [56; 56), 355 label: "loop",
346 delete: [56; 56), 356 source_range: [56; 56),
347 insert: "loop {$0}", 357 delete: [56; 56),
348 kind: Keyword, 358 insert: "loop {$0}",
349 }, 359 kind: Keyword,
350 CompletionItem { 360 },
351 label: "match", 361 CompletionItem {
352 source_range: [56; 56), 362 label: "match",
353 delete: [56; 56), 363 source_range: [56; 56),
354 insert: "match $0 {}", 364 delete: [56; 56),
355 kind: Keyword, 365 insert: "match $0 {}",
356 }, 366 kind: Keyword,
357 CompletionItem { 367 },
358 label: "return", 368 CompletionItem {
359 source_range: [56; 56), 369 label: "return",
360 delete: [56; 56), 370 source_range: [56; 56),
361 insert: "return $0;", 371 delete: [56; 56),
362 kind: Keyword, 372 insert: "return $0;",
363 }, 373 kind: Keyword,
364 CompletionItem { 374 },
365 label: "while", 375 CompletionItem {
366 source_range: [56; 56), 376 label: "while",
367 delete: [56; 56), 377 source_range: [56; 56),
368 insert: "while $0 {}", 378 delete: [56; 56),
369 kind: Keyword, 379 insert: "while $0 {}",
370 }, 380 kind: Keyword,
371]"### 381 },
382 ]
383 "###
372 ); 384 );
373 assert_debug_snapshot!( 385 assert_debug_snapshot!(
374 do_keyword_completion( 386 do_keyword_completion(
@@ -379,43 +391,45 @@ mod tests {
379 } 391 }
380 ", 392 ",
381 ), 393 ),
382 @r###"[ 394 @r###"
383 CompletionItem { 395 [
384 label: "if", 396 CompletionItem {
385 source_range: [49; 49), 397 label: "if",
386 delete: [49; 49), 398 source_range: [49; 49),
387 insert: "if $0 {}", 399 delete: [49; 49),
388 kind: Keyword, 400 insert: "if $0 {}",
389 }, 401 kind: Keyword,
390 CompletionItem { 402 },
391 label: "loop", 403 CompletionItem {
392 source_range: [49; 49), 404 label: "loop",
393 delete: [49; 49), 405 source_range: [49; 49),
394 insert: "loop {$0}", 406 delete: [49; 49),
395 kind: Keyword, 407 insert: "loop {$0}",
396 }, 408 kind: Keyword,
397 CompletionItem { 409 },
398 label: "match", 410 CompletionItem {
399 source_range: [49; 49), 411 label: "match",
400 delete: [49; 49), 412 source_range: [49; 49),
401 insert: "match $0 {}", 413 delete: [49; 49),
402 kind: Keyword, 414 insert: "match $0 {}",
403 }, 415 kind: Keyword,
404 CompletionItem { 416 },
405 label: "return", 417 CompletionItem {
406 source_range: [49; 49), 418 label: "return",
407 delete: [49; 49), 419 source_range: [49; 49),
408 insert: "return;", 420 delete: [49; 49),
409 kind: Keyword, 421 insert: "return;",
410 }, 422 kind: Keyword,
411 CompletionItem { 423 },
412 label: "while", 424 CompletionItem {
413 source_range: [49; 49), 425 label: "while",
414 delete: [49; 49), 426 source_range: [49; 49),
415 insert: "while $0 {}", 427 delete: [49; 49),
416 kind: Keyword, 428 insert: "while $0 {}",
417 }, 429 kind: Keyword,
418]"### 430 },
431 ]
432 "###
419 ); 433 );
420 } 434 }
421 435
@@ -431,43 +445,45 @@ mod tests {
431 } 445 }
432 ", 446 ",
433 ), 447 ),
434 @r###"[ 448 @r###"
435 CompletionItem { 449 [
436 label: "if", 450 CompletionItem {
437 source_range: [97; 97), 451 label: "if",
438 delete: [97; 97), 452 source_range: [97; 97),
439 insert: "if $0 {}", 453 delete: [97; 97),
440 kind: Keyword, 454 insert: "if $0 {}",
441 }, 455 kind: Keyword,
442 CompletionItem { 456 },
443 label: "loop", 457 CompletionItem {
444 source_range: [97; 97), 458 label: "loop",
445 delete: [97; 97), 459 source_range: [97; 97),
446 insert: "loop {$0}", 460 delete: [97; 97),
447 kind: Keyword, 461 insert: "loop {$0}",
448 }, 462 kind: Keyword,
449 CompletionItem { 463 },
450 label: "match", 464 CompletionItem {
451 source_range: [97; 97), 465 label: "match",
452 delete: [97; 97), 466 source_range: [97; 97),
453 insert: "match $0 {}", 467 delete: [97; 97),
454 kind: Keyword, 468 insert: "match $0 {}",
455 }, 469 kind: Keyword,
456 CompletionItem { 470 },
457 label: "return", 471 CompletionItem {
458 source_range: [97; 97), 472 label: "return",
459 delete: [97; 97), 473 source_range: [97; 97),
460 insert: "return $0", 474 delete: [97; 97),
461 kind: Keyword, 475 insert: "return $0",
462 }, 476 kind: Keyword,
463 CompletionItem { 477 },
464 label: "while", 478 CompletionItem {
465 source_range: [97; 97), 479 label: "while",
466 delete: [97; 97), 480 source_range: [97; 97),
467 insert: "while $0 {}", 481 delete: [97; 97),
468 kind: Keyword, 482 insert: "while $0 {}",
469 }, 483 kind: Keyword,
470]"### 484 },
485 ]
486 "###
471 ); 487 );
472 } 488 }
473 489
@@ -483,43 +499,45 @@ mod tests {
483 } 499 }
484 ", 500 ",
485 ), 501 ),
486 @r###"[ 502 @r###"
487 CompletionItem { 503 [
488 label: "if", 504 CompletionItem {
489 source_range: [95; 95), 505 label: "if",
490 delete: [95; 95), 506 source_range: [95; 95),
491 insert: "if $0 {}", 507 delete: [95; 95),
492 kind: Keyword, 508 insert: "if $0 {}",
493 }, 509 kind: Keyword,
494 CompletionItem { 510 },
495 label: "loop", 511 CompletionItem {
496 source_range: [95; 95), 512 label: "loop",
497 delete: [95; 95), 513 source_range: [95; 95),
498 insert: "loop {$0}", 514 delete: [95; 95),
499 kind: Keyword, 515 insert: "loop {$0}",
500 }, 516 kind: Keyword,
501 CompletionItem { 517 },
502 label: "match", 518 CompletionItem {
503 source_range: [95; 95), 519 label: "match",
504 delete: [95; 95), 520 source_range: [95; 95),
505 insert: "match $0 {}", 521 delete: [95; 95),
506 kind: Keyword, 522 insert: "match $0 {}",
507 }, 523 kind: Keyword,
508 CompletionItem { 524 },
509 label: "return", 525 CompletionItem {
510 source_range: [95; 95), 526 label: "return",
511 delete: [95; 95), 527 source_range: [95; 95),
512 insert: "return $0;", 528 delete: [95; 95),
513 kind: Keyword, 529 insert: "return $0;",
514 }, 530 kind: Keyword,
515 CompletionItem { 531 },
516 label: "while", 532 CompletionItem {
517 source_range: [95; 95), 533 label: "while",
518 delete: [95; 95), 534 source_range: [95; 95),
519 insert: "while $0 {}", 535 delete: [95; 95),
520 kind: Keyword, 536 insert: "while $0 {}",
521 }, 537 kind: Keyword,
522]"### 538 },
539 ]
540 "###
523 ); 541 );
524 assert_debug_snapshot!( 542 assert_debug_snapshot!(
525 do_keyword_completion( 543 do_keyword_completion(
@@ -533,43 +551,45 @@ mod tests {
533 } 551 }
534 ", 552 ",
535 ), 553 ),
536 @r###"[ 554 @r###"
537 CompletionItem { 555 [
538 label: "if", 556 CompletionItem {
539 source_range: [95; 95), 557 label: "if",
540 delete: [95; 95), 558 source_range: [95; 95),
541 insert: "if $0 {}", 559 delete: [95; 95),
542 kind: Keyword, 560 insert: "if $0 {}",
543 }, 561 kind: Keyword,
544 CompletionItem { 562 },
545 label: "loop", 563 CompletionItem {
546 source_range: [95; 95), 564 label: "loop",
547 delete: [95; 95), 565 source_range: [95; 95),
548 insert: "loop {$0}", 566 delete: [95; 95),
549 kind: Keyword, 567 insert: "loop {$0}",
550 }, 568 kind: Keyword,
551 CompletionItem { 569 },
552 label: "match", 570 CompletionItem {
553 source_range: [95; 95), 571 label: "match",
554 delete: [95; 95), 572 source_range: [95; 95),
555 insert: "match $0 {}", 573 delete: [95; 95),
556 kind: Keyword, 574 insert: "match $0 {}",
557 }, 575 kind: Keyword,
558 CompletionItem { 576 },
559 label: "return", 577 CompletionItem {
560 source_range: [95; 95), 578 label: "return",
561 delete: [95; 95), 579 source_range: [95; 95),
562 insert: "return $0;", 580 delete: [95; 95),
563 kind: Keyword, 581 insert: "return $0;",
564 }, 582 kind: Keyword,
565 CompletionItem { 583 },
566 label: "while", 584 CompletionItem {
567 source_range: [95; 95), 585 label: "while",
568 delete: [95; 95), 586 source_range: [95; 95),
569 insert: "while $0 {}", 587 delete: [95; 95),
570 kind: Keyword, 588 insert: "while $0 {}",
571 }, 589 kind: Keyword,
572]"### 590 },
591 ]
592 "###
573 ); 593 );
574 } 594 }
575 595
@@ -583,57 +603,59 @@ mod tests {
583 } 603 }
584 ", 604 ",
585 ), 605 ),
586 @r###"[ 606 @r###"
587 CompletionItem { 607 [
588 label: "break", 608 CompletionItem {
589 source_range: [63; 63), 609 label: "break",
590 delete: [63; 63), 610 source_range: [63; 63),
591 insert: "break;", 611 delete: [63; 63),
592 kind: Keyword, 612 insert: "break;",
593 }, 613 kind: Keyword,
594 CompletionItem { 614 },
595 label: "continue", 615 CompletionItem {
596 source_range: [63; 63), 616 label: "continue",
597 delete: [63; 63), 617 source_range: [63; 63),
598 insert: "continue;", 618 delete: [63; 63),
599 kind: Keyword, 619 insert: "continue;",
600 }, 620 kind: Keyword,
601 CompletionItem { 621 },
602 label: "if", 622 CompletionItem {
603 source_range: [63; 63), 623 label: "if",
604 delete: [63; 63), 624 source_range: [63; 63),
605 insert: "if $0 {}", 625 delete: [63; 63),
606 kind: Keyword, 626 insert: "if $0 {}",
607 }, 627 kind: Keyword,
608 CompletionItem { 628 },
609 label: "loop", 629 CompletionItem {
610 source_range: [63; 63), 630 label: "loop",
611 delete: [63; 63), 631 source_range: [63; 63),
612 insert: "loop {$0}", 632 delete: [63; 63),
613 kind: Keyword, 633 insert: "loop {$0}",
614 }, 634 kind: Keyword,
615 CompletionItem { 635 },
616 label: "match", 636 CompletionItem {
617 source_range: [63; 63), 637 label: "match",
618 delete: [63; 63), 638 source_range: [63; 63),
619 insert: "match $0 {}", 639 delete: [63; 63),
620 kind: Keyword, 640 insert: "match $0 {}",
621 }, 641 kind: Keyword,
622 CompletionItem { 642 },
623 label: "return", 643 CompletionItem {
624 source_range: [63; 63), 644 label: "return",
625 delete: [63; 63), 645 source_range: [63; 63),
626 insert: "return $0;", 646 delete: [63; 63),
627 kind: Keyword, 647 insert: "return $0;",
628 }, 648 kind: Keyword,
629 CompletionItem { 649 },
630 label: "while", 650 CompletionItem {
631 source_range: [63; 63), 651 label: "while",
632 delete: [63; 63), 652 source_range: [63; 63),
633 insert: "while $0 {}", 653 delete: [63; 63),
634 kind: Keyword, 654 insert: "while $0 {}",
635 }, 655 kind: Keyword,
636]"### 656 },
657 ]
658 "###
637 ); 659 );
638 660
639 // No completion: lambda isolates control flow 661 // No completion: lambda isolates control flow
@@ -645,43 +667,45 @@ mod tests {
645 } 667 }
646 ", 668 ",
647 ), 669 ),
648 @r###"[ 670 @r###"
649 CompletionItem { 671 [
650 label: "if", 672 CompletionItem {
651 source_range: [68; 68), 673 label: "if",
652 delete: [68; 68), 674 source_range: [68; 68),
653 insert: "if $0 {}", 675 delete: [68; 68),
654 kind: Keyword, 676 insert: "if $0 {}",
655 }, 677 kind: Keyword,
656 CompletionItem { 678 },
657 label: "loop", 679 CompletionItem {
658 source_range: [68; 68), 680 label: "loop",
659 delete: [68; 68), 681 source_range: [68; 68),
660 insert: "loop {$0}", 682 delete: [68; 68),
661 kind: Keyword, 683 insert: "loop {$0}",
662 }, 684 kind: Keyword,
663 CompletionItem { 685 },
664 label: "match", 686 CompletionItem {
665 source_range: [68; 68), 687 label: "match",
666 delete: [68; 68), 688 source_range: [68; 68),
667 insert: "match $0 {}", 689 delete: [68; 68),
668 kind: Keyword, 690 insert: "match $0 {}",
669 }, 691 kind: Keyword,
670 CompletionItem { 692 },
671 label: "return", 693 CompletionItem {
672 source_range: [68; 68), 694 label: "return",
673 delete: [68; 68), 695 source_range: [68; 68),
674 insert: "return $0;", 696 delete: [68; 68),
675 kind: Keyword, 697 insert: "return $0;",
676 }, 698 kind: Keyword,
677 CompletionItem { 699 },
678 label: "while", 700 CompletionItem {
679 source_range: [68; 68), 701 label: "while",
680 delete: [68; 68), 702 source_range: [68; 68),
681 insert: "while $0 {}", 703 delete: [68; 68),
682 kind: Keyword, 704 insert: "while $0 {}",
683 }, 705 kind: Keyword,
684]"### 706 },
707 ]
708 "###
685 ); 709 );
686 } 710 }
687 711
@@ -699,57 +723,59 @@ mod tests {
699 } 723 }
700 ", 724 ",
701 ), 725 ),
702 @r###"[ 726 @r###"
703 CompletionItem { 727 [
704 label: "break", 728 CompletionItem {
705 source_range: [122; 124), 729 label: "break",
706 delete: [122; 124), 730 source_range: [122; 124),
707 insert: "break", 731 delete: [122; 124),
708 kind: Keyword, 732 insert: "break",
709 }, 733 kind: Keyword,
710 CompletionItem { 734 },
711 label: "continue", 735 CompletionItem {
712 source_range: [122; 124), 736 label: "continue",
713 delete: [122; 124), 737 source_range: [122; 124),
714 insert: "continue", 738 delete: [122; 124),
715 kind: Keyword, 739 insert: "continue",
716 }, 740 kind: Keyword,
717 CompletionItem { 741 },
718 label: "if", 742 CompletionItem {
719 source_range: [122; 124), 743 label: "if",
720 delete: [122; 124), 744 source_range: [122; 124),
721 insert: "if $0 {}", 745 delete: [122; 124),
722 kind: Keyword, 746 insert: "if $0 {}",
723 }, 747 kind: Keyword,
724 CompletionItem { 748 },
725 label: "loop", 749 CompletionItem {
726 source_range: [122; 124), 750 label: "loop",
727 delete: [122; 124), 751 source_range: [122; 124),
728 insert: "loop {$0}", 752 delete: [122; 124),
729 kind: Keyword, 753 insert: "loop {$0}",
730 }, 754 kind: Keyword,
731 CompletionItem { 755 },
732 label: "match", 756 CompletionItem {
733 source_range: [122; 124), 757 label: "match",
734 delete: [122; 124), 758 source_range: [122; 124),
735 insert: "match $0 {}", 759 delete: [122; 124),
736 kind: Keyword, 760 insert: "match $0 {}",
737 }, 761 kind: Keyword,
738 CompletionItem { 762 },
739 label: "return", 763 CompletionItem {
740 source_range: [122; 124), 764 label: "return",
741 delete: [122; 124), 765 source_range: [122; 124),
742 insert: "return", 766 delete: [122; 124),
743 kind: Keyword, 767 insert: "return",
744 }, 768 kind: Keyword,
745 CompletionItem { 769 },
746 label: "while", 770 CompletionItem {
747 source_range: [122; 124), 771 label: "while",
748 delete: [122; 124), 772 source_range: [122; 124),
749 insert: "while $0 {}", 773 delete: [122; 124),
750 kind: Keyword, 774 insert: "while $0 {}",
751 }, 775 kind: Keyword,
752]"### 776 },
777 ]
778 "###
753 ) 779 )
754 } 780 }
755} 781}
diff --git a/crates/ra_ide_api/src/completion/complete_macro_in_item_position.rs b/crates/ra_ide_api/src/completion/complete_macro_in_item_position.rs
index 09f743c66..faadd1e3f 100644
--- a/crates/ra_ide_api/src/completion/complete_macro_in_item_position.rs
+++ b/crates/ra_ide_api/src/completion/complete_macro_in_item_position.rs
@@ -37,16 +37,18 @@ mod tests {
37 <|> 37 <|>
38 " 38 "
39 ), 39 ),
40 @r##"[ 40 @r###"
41 CompletionItem { 41 [
42 label: "foo!", 42 CompletionItem {
43 source_range: [46; 46), 43 label: "foo!",
44 delete: [46; 46), 44 source_range: [46; 46),
45 insert: "foo!($0)", 45 delete: [46; 46),
46 kind: Macro, 46 insert: "foo!($0)",
47 detail: "macro_rules! foo", 47 kind: Macro,
48 }, 48 detail: "macro_rules! foo",
49]"## 49 },
50 ]
51 "###
50 ); 52 );
51 } 53 }
52 54
@@ -75,19 +77,21 @@ mod tests {
75 <|> 77 <|>
76 " 78 "
77 ), 79 ),
78 @r##"[ 80 @r###"
79 CompletionItem { 81 [
80 label: "vec!", 82 CompletionItem {
81 source_range: [280; 280), 83 label: "vec!",
82 delete: [280; 280), 84 source_range: [280; 280),
83 insert: "vec![$0]", 85 delete: [280; 280),
84 kind: Macro, 86 insert: "vec![$0]",
85 detail: "macro_rules! vec", 87 kind: Macro,
86 documentation: Documentation( 88 detail: "macro_rules! vec",
87 "Creates a [`Vec`] containing the arguments.\n\n- Create a [`Vec`] containing a given list of elements:\n\n```\nlet v = vec![1, 2, 3];\nassert_eq!(v[0], 1);\nassert_eq!(v[1], 2);\nassert_eq!(v[2], 3);\n```", 89 documentation: Documentation(
88 ), 90 "Creates a [`Vec`] containing the arguments.\n\n- Create a [`Vec`] containing a given list of elements:\n\n```\nlet v = vec![1, 2, 3];\nassert_eq!(v[0], 1);\nassert_eq!(v[1], 2);\nassert_eq!(v[2], 3);\n```",
89 }, 91 ),
90]"## 92 },
93 ]
94 "###
91 ); 95 );
92 } 96 }
93 97
@@ -110,28 +114,29 @@ mod tests {
110 } 114 }
111 " 115 "
112 ), 116 ),
113 @r###"[ 117 @r###"
114 CompletionItem { 118 [
115 label: "foo!", 119 CompletionItem {
116 source_range: [163; 163), 120 label: "foo!",
117 delete: [163; 163), 121 source_range: [163; 163),
118 insert: "foo! {$0}", 122 delete: [163; 163),
119 kind: Macro, 123 insert: "foo! {$0}",
120 detail: "macro_rules! foo", 124 kind: Macro,
121 documentation: Documentation( 125 detail: "macro_rules! foo",
122 "Foo\n\nNot call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`.\nCall as `let _=foo! { hello world };`", 126 documentation: Documentation(
123 ), 127 "Foo\n\nNot call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`.\nCall as `let _=foo! { hello world };`",
124 }, 128 ),
125 CompletionItem { 129 },
126 label: "main()", 130 CompletionItem {
127 source_range: [163; 163), 131 label: "main()",
128 delete: [163; 163), 132 source_range: [163; 163),
129 insert: "main()$0", 133 delete: [163; 163),
130 kind: Function, 134 insert: "main()$0",
131 lookup: "main", 135 kind: Function,
132 detail: "fn main()", 136 lookup: "main",
133 }, 137 detail: "fn main()",
134] 138 },
139 ]
135 "### 140 "###
136 ); 141 );
137 } 142 }
diff --git a/crates/ra_ide_api/src/completion/complete_path.rs b/crates/ra_ide_api/src/completion/complete_path.rs
index 09ca40179..5d974cf6d 100644
--- a/crates/ra_ide_api/src/completion/complete_path.rs
+++ b/crates/ra_ide_api/src/completion/complete_path.rs
@@ -152,18 +152,20 @@ mod tests {
152 } 152 }
153 " 153 "
154 ), 154 ),
155 @r###"[ 155 @r###"
156 CompletionItem { 156 [
157 label: "my", 157 CompletionItem {
158 source_range: [27; 29), 158 label: "my",
159 delete: [27; 29), 159 source_range: [27; 29),
160 insert: "my", 160 delete: [27; 29),
161 kind: Module, 161 insert: "my",
162 documentation: Documentation( 162 kind: Module,
163 "Some simple\ndocs describing `mod my`.", 163 documentation: Documentation(
164 ), 164 "Some simple\ndocs describing `mod my`.",
165 }, 165 ),
166]"### 166 },
167 ]
168 "###
167 ); 169 );
168 } 170 }
169 171
@@ -179,15 +181,17 @@ mod tests {
179 } 181 }
180 " 182 "
181 ), 183 ),
182 @r###"[ 184 @r###"
183 CompletionItem { 185 [
184 label: "Bar", 186 CompletionItem {
185 source_range: [30; 30), 187 label: "Bar",
186 delete: [30; 30), 188 source_range: [30; 30),
187 insert: "Bar", 189 delete: [30; 30),
188 kind: Struct, 190 insert: "Bar",
189 }, 191 kind: Struct,
190]"### 192 },
193 ]
194 "###
191 ); 195 );
192 } 196 }
193 197
@@ -203,22 +207,24 @@ mod tests {
203 use crate::Sp<|> 207 use crate::Sp<|>
204 " 208 "
205 ), 209 ),
206 @r###"[ 210 @r###"
207 CompletionItem { 211 [
208 label: "Spam", 212 CompletionItem {
209 source_range: [11; 13), 213 label: "Spam",
210 delete: [11; 13), 214 source_range: [11; 13),
211 insert: "Spam", 215 delete: [11; 13),
212 kind: Struct, 216 insert: "Spam",
213 }, 217 kind: Struct,
214 CompletionItem { 218 },
215 label: "foo", 219 CompletionItem {
216 source_range: [11; 13), 220 label: "foo",
217 delete: [11; 13), 221 source_range: [11; 13),
218 insert: "foo", 222 delete: [11; 13),
219 kind: Module, 223 insert: "foo",
220 }, 224 kind: Module,
221]"### 225 },
226 ]
227 "###
222 ); 228 );
223 } 229 }
224 230
@@ -234,22 +240,24 @@ mod tests {
234 use crate::{Sp<|>}; 240 use crate::{Sp<|>};
235 " 241 "
236 ), 242 ),
237 @r###"[ 243 @r###"
238 CompletionItem { 244 [
239 label: "Spam", 245 CompletionItem {
240 source_range: [12; 14), 246 label: "Spam",
241 delete: [12; 14), 247 source_range: [12; 14),
242 insert: "Spam", 248 delete: [12; 14),
243 kind: Struct, 249 insert: "Spam",
244 }, 250 kind: Struct,
245 CompletionItem { 251 },
246 label: "foo", 252 CompletionItem {
247 source_range: [12; 14), 253 label: "foo",
248 delete: [12; 14), 254 source_range: [12; 14),
249 insert: "foo", 255 delete: [12; 14),
250 kind: Module, 256 insert: "foo",
251 }, 257 kind: Module,
252]"### 258 },
259 ]
260 "###
253 ); 261 );
254 } 262 }
255 263
@@ -269,15 +277,17 @@ mod tests {
269 use crate::{bar::{baz::Sp<|>}}; 277 use crate::{bar::{baz::Sp<|>}};
270 " 278 "
271 ), 279 ),
272 @r###"[ 280 @r###"
273 CompletionItem { 281 [
274 label: "Spam", 282 CompletionItem {
275 source_range: [23; 25), 283 label: "Spam",
276 delete: [23; 25), 284 source_range: [23; 25),
277 insert: "Spam", 285 delete: [23; 25),
278 kind: Struct, 286 insert: "Spam",
279 }, 287 kind: Struct,
280]"### 288 },
289 ]
290 "###
281 ); 291 );
282 } 292 }
283 293
@@ -297,30 +307,32 @@ mod tests {
297 fn foo() { let _ = E::<|> } 307 fn foo() { let _ = E::<|> }
298 " 308 "
299 ), 309 ),
300 @r###"[ 310 @r###"
301 CompletionItem { 311 [
302 label: "Bar", 312 CompletionItem {
303 source_range: [116; 116), 313 label: "Bar",
304 delete: [116; 116), 314 source_range: [116; 116),
305 insert: "Bar", 315 delete: [116; 116),
306 kind: EnumVariant, 316 insert: "Bar",
307 detail: "(i32)", 317 kind: EnumVariant,
308 documentation: Documentation( 318 detail: "(i32)",
309 "Bar Variant with i32", 319 documentation: Documentation(
310 ), 320 "Bar Variant with i32",
311 }, 321 ),
312 CompletionItem { 322 },
313 label: "Foo", 323 CompletionItem {
314 source_range: [116; 116), 324 label: "Foo",
315 delete: [116; 116), 325 source_range: [116; 116),
316 insert: "Foo", 326 delete: [116; 116),
317 kind: EnumVariant, 327 insert: "Foo",
318 detail: "()", 328 kind: EnumVariant,
319 documentation: Documentation( 329 detail: "()",
320 "Foo Variant", 330 documentation: Documentation(
321 ), 331 "Foo Variant",
322 }, 332 ),
323]"### 333 },
334 ]
335 "###
324 ); 336 );
325 } 337 }
326 338
@@ -343,41 +355,43 @@ mod tests {
343 fn foo() { let _ = E::<|> } 355 fn foo() { let _ = E::<|> }
344 " 356 "
345 ), 357 ),
346 @r###"[ 358 @r###"
347 CompletionItem { 359 [
348 label: "Bar", 360 CompletionItem {
349 source_range: [180; 180), 361 label: "Bar",
350 delete: [180; 180), 362 source_range: [180; 180),
351 insert: "Bar", 363 delete: [180; 180),
352 kind: EnumVariant, 364 insert: "Bar",
353 detail: "(i32, u32)", 365 kind: EnumVariant,
354 documentation: Documentation( 366 detail: "(i32, u32)",
355 "Bar Variant with i32 and u32", 367 documentation: Documentation(
356 ), 368 "Bar Variant with i32 and u32",
357 }, 369 ),
358 CompletionItem { 370 },
359 label: "Foo", 371 CompletionItem {
360 source_range: [180; 180), 372 label: "Foo",
361 delete: [180; 180), 373 source_range: [180; 180),
362 insert: "Foo", 374 delete: [180; 180),
363 kind: EnumVariant, 375 insert: "Foo",
364 detail: "()", 376 kind: EnumVariant,
365 documentation: Documentation( 377 detail: "()",
366 "Foo Variant (empty)", 378 documentation: Documentation(
367 ), 379 "Foo Variant (empty)",
368 }, 380 ),
369 CompletionItem { 381 },
370 label: "S", 382 CompletionItem {
371 source_range: [180; 180), 383 label: "S",
372 delete: [180; 180), 384 source_range: [180; 180),
373 insert: "S", 385 delete: [180; 180),
374 kind: EnumVariant, 386 insert: "S",
375 detail: "(S)", 387 kind: EnumVariant,
376 documentation: Documentation( 388 detail: "(S)",
377 "", 389 documentation: Documentation(
378 ), 390 "",
379 }, 391 ),
380]"### 392 },
393 ]
394 "###
381 ); 395 );
382 } 396 }
383 397
@@ -434,19 +448,21 @@ mod tests {
434 fn foo() { let _ = S::<|> } 448 fn foo() { let _ = S::<|> }
435 " 449 "
436 ), 450 ),
437 @r###"[ 451 @r###"
438 CompletionItem { 452 [
439 label: "C", 453 CompletionItem {
440 source_range: [107; 107), 454 label: "C",
441 delete: [107; 107), 455 source_range: [107; 107),
442 insert: "C", 456 delete: [107; 107),
443 kind: Const, 457 insert: "C",
444 detail: "const C: i32 = 42;", 458 kind: Const,
445 documentation: Documentation( 459 detail: "const C: i32 = 42;",
446 "An associated const", 460 documentation: Documentation(
447 ), 461 "An associated const",
448 }, 462 ),
449]"### 463 },
464 ]
465 "###
450 ); 466 );
451 } 467 }
452 468
@@ -467,19 +483,21 @@ mod tests {
467 fn foo() { let _ = S::<|> } 483 fn foo() { let _ = S::<|> }
468 " 484 "
469 ), 485 ),
470 @r###"[ 486 @r###"
471 CompletionItem { 487 [
472 label: "T", 488 CompletionItem {
473 source_range: [101; 101), 489 label: "T",
474 delete: [101; 101), 490 source_range: [101; 101),
475 insert: "T", 491 delete: [101; 101),
476 kind: TypeAlias, 492 insert: "T",
477 detail: "type T = i32;", 493 kind: TypeAlias,
478 documentation: Documentation( 494 detail: "type T = i32;",
479 "An associated type", 495 documentation: Documentation(
480 ), 496 "An associated type",
481 }, 497 ),
482]"### 498 },
499 ]
500 "###
483 ); 501 );
484 } 502 }
485 503
@@ -569,15 +587,17 @@ mod tests {
569 } 587 }
570 " 588 "
571 ), 589 ),
572 @r###"[ 590 @r###"
573 CompletionItem { 591 [
574 label: "bar", 592 CompletionItem {
575 source_range: [9; 9), 593 label: "bar",
576 delete: [9; 9), 594 source_range: [9; 9),
577 insert: "bar", 595 delete: [9; 9),
578 kind: Module, 596 insert: "bar",
579 }, 597 kind: Module,
580]"### 598 },
599 ]
600 "###
581 ); 601 );
582 } 602 }
583 603
diff --git a/crates/ra_ide_api/src/completion/complete_pattern.rs b/crates/ra_ide_api/src/completion/complete_pattern.rs
index 513ad6e5f..fd03b1c40 100644
--- a/crates/ra_ide_api/src/completion/complete_pattern.rs
+++ b/crates/ra_ide_api/src/completion/complete_pattern.rs
@@ -54,36 +54,36 @@ mod tests {
54 ", 54 ",
55 ); 55 );
56 assert_debug_snapshot!(completions, @r###" 56 assert_debug_snapshot!(completions, @r###"
57 [ 57 [
58 CompletionItem { 58 CompletionItem {
59 label: "E", 59 label: "E",
60 source_range: [246; 246), 60 source_range: [246; 246),
61 delete: [246; 246), 61 delete: [246; 246),
62 insert: "E", 62 insert: "E",
63 kind: Enum, 63 kind: Enum,
64 }, 64 },
65 CompletionItem { 65 CompletionItem {
66 label: "X", 66 label: "X",
67 source_range: [246; 246), 67 source_range: [246; 246),
68 delete: [246; 246), 68 delete: [246; 246),
69 insert: "X", 69 insert: "X",
70 kind: EnumVariant, 70 kind: EnumVariant,
71 }, 71 },
72 CompletionItem { 72 CompletionItem {
73 label: "Z", 73 label: "Z",
74 source_range: [246; 246), 74 source_range: [246; 246),
75 delete: [246; 246), 75 delete: [246; 246),
76 insert: "Z", 76 insert: "Z",
77 kind: Const, 77 kind: Const,
78 }, 78 },
79 CompletionItem { 79 CompletionItem {
80 label: "m", 80 label: "m",
81 source_range: [246; 246), 81 source_range: [246; 246),
82 delete: [246; 246), 82 delete: [246; 246),
83 insert: "m", 83 insert: "m",
84 kind: Module, 84 kind: Module,
85 }, 85 },
86 ] 86 ]
87 "###); 87 "###);
88 } 88 }
89} 89}
diff --git a/crates/ra_ide_api/src/completion/complete_postfix.rs b/crates/ra_ide_api/src/completion/complete_postfix.rs
index 99fed8689..17b75cf7e 100644
--- a/crates/ra_ide_api/src/completion/complete_postfix.rs
+++ b/crates/ra_ide_api/src/completion/complete_postfix.rs
@@ -104,64 +104,66 @@ mod tests {
104 } 104 }
105 "#, 105 "#,
106 ), 106 ),
107 @r###"[ 107 @r###"
108 CompletionItem { 108 [
109 label: "box", 109 CompletionItem {
110 source_range: [89; 89), 110 label: "box",
111 delete: [85; 89), 111 source_range: [89; 89),
112 insert: "Box::new(bar)", 112 delete: [85; 89),
113 detail: "Box::new(expr)", 113 insert: "Box::new(bar)",
114 }, 114 detail: "Box::new(expr)",
115 CompletionItem { 115 },
116 label: "dbg", 116 CompletionItem {
117 source_range: [89; 89), 117 label: "dbg",
118 delete: [85; 89), 118 source_range: [89; 89),
119 insert: "dbg!(bar)", 119 delete: [85; 89),
120 detail: "dbg!(expr)", 120 insert: "dbg!(bar)",
121 }, 121 detail: "dbg!(expr)",
122 CompletionItem { 122 },
123 label: "if", 123 CompletionItem {
124 source_range: [89; 89), 124 label: "if",
125 delete: [85; 89), 125 source_range: [89; 89),
126 insert: "if bar {$0}", 126 delete: [85; 89),
127 detail: "if expr {}", 127 insert: "if bar {$0}",
128 }, 128 detail: "if expr {}",
129 CompletionItem { 129 },
130 label: "match", 130 CompletionItem {
131 source_range: [89; 89), 131 label: "match",
132 delete: [85; 89), 132 source_range: [89; 89),
133 insert: "match bar {\n ${1:_} => {$0\\},\n}", 133 delete: [85; 89),
134 detail: "match expr {}", 134 insert: "match bar {\n ${1:_} => {$0\\},\n}",
135 }, 135 detail: "match expr {}",
136 CompletionItem { 136 },
137 label: "not", 137 CompletionItem {
138 source_range: [89; 89), 138 label: "not",
139 delete: [85; 89), 139 source_range: [89; 89),
140 insert: "!bar", 140 delete: [85; 89),
141 detail: "!expr", 141 insert: "!bar",
142 }, 142 detail: "!expr",
143 CompletionItem { 143 },
144 label: "ref", 144 CompletionItem {
145 source_range: [89; 89), 145 label: "ref",
146 delete: [85; 89), 146 source_range: [89; 89),
147 insert: "&bar", 147 delete: [85; 89),
148 detail: "&expr", 148 insert: "&bar",
149 }, 149 detail: "&expr",
150 CompletionItem { 150 },
151 label: "refm", 151 CompletionItem {
152 source_range: [89; 89), 152 label: "refm",
153 delete: [85; 89), 153 source_range: [89; 89),
154 insert: "&mut bar", 154 delete: [85; 89),
155 detail: "&mut expr", 155 insert: "&mut bar",
156 }, 156 detail: "&mut expr",
157 CompletionItem { 157 },
158 label: "while", 158 CompletionItem {
159 source_range: [89; 89), 159 label: "while",
160 delete: [85; 89), 160 source_range: [89; 89),
161 insert: "while bar {\n$0\n}", 161 delete: [85; 89),
162 detail: "while expr {}", 162 insert: "while bar {\n$0\n}",
163 }, 163 detail: "while expr {}",
164]"### 164 },
165 ]
166 "###
165 ); 167 );
166 } 168 }
167 169
@@ -176,50 +178,52 @@ mod tests {
176 } 178 }
177 "#, 179 "#,
178 ), 180 ),
179 @r###"[ 181 @r###"
180 CompletionItem { 182 [
181 label: "box", 183 CompletionItem {
182 source_range: [91; 91), 184 label: "box",
183 delete: [87; 91), 185 source_range: [91; 91),
184 insert: "Box::new(bar)", 186 delete: [87; 91),
185 detail: "Box::new(expr)", 187 insert: "Box::new(bar)",
186 }, 188 detail: "Box::new(expr)",
187 CompletionItem { 189 },
188 label: "dbg", 190 CompletionItem {
189 source_range: [91; 91), 191 label: "dbg",
190 delete: [87; 91), 192 source_range: [91; 91),
191 insert: "dbg!(bar)", 193 delete: [87; 91),
192 detail: "dbg!(expr)", 194 insert: "dbg!(bar)",
193 }, 195 detail: "dbg!(expr)",
194 CompletionItem { 196 },
195 label: "match", 197 CompletionItem {
196 source_range: [91; 91), 198 label: "match",
197 delete: [87; 91), 199 source_range: [91; 91),
198 insert: "match bar {\n ${1:_} => {$0\\},\n}", 200 delete: [87; 91),
199 detail: "match expr {}", 201 insert: "match bar {\n ${1:_} => {$0\\},\n}",
200 }, 202 detail: "match expr {}",
201 CompletionItem { 203 },
202 label: "not", 204 CompletionItem {
203 source_range: [91; 91), 205 label: "not",
204 delete: [87; 91), 206 source_range: [91; 91),
205 insert: "!bar", 207 delete: [87; 91),
206 detail: "!expr", 208 insert: "!bar",
207 }, 209 detail: "!expr",
208 CompletionItem { 210 },
209 label: "ref", 211 CompletionItem {
210 source_range: [91; 91), 212 label: "ref",
211 delete: [87; 91), 213 source_range: [91; 91),
212 insert: "&bar", 214 delete: [87; 91),
213 detail: "&expr", 215 insert: "&bar",
214 }, 216 detail: "&expr",
215 CompletionItem { 217 },
216 label: "refm", 218 CompletionItem {
217 source_range: [91; 91), 219 label: "refm",
218 delete: [87; 91), 220 source_range: [91; 91),
219 insert: "&mut bar", 221 delete: [87; 91),
220 detail: "&mut expr", 222 insert: "&mut bar",
221 }, 223 detail: "&mut expr",
222]"### 224 },
225 ]
226 "###
223 ); 227 );
224 } 228 }
225 229
@@ -233,50 +237,52 @@ mod tests {
233 } 237 }
234 "#, 238 "#,
235 ), 239 ),
236 @r###"[ 240 @r###"
237 CompletionItem { 241 [
238 label: "box", 242 CompletionItem {
239 source_range: [52; 52), 243 label: "box",
240 delete: [49; 52), 244 source_range: [52; 52),
241 insert: "Box::new(42)", 245 delete: [49; 52),
242 detail: "Box::new(expr)", 246 insert: "Box::new(42)",
243 }, 247 detail: "Box::new(expr)",
244 CompletionItem { 248 },
245 label: "dbg", 249 CompletionItem {
246 source_range: [52; 52), 250 label: "dbg",
247 delete: [49; 52), 251 source_range: [52; 52),
248 insert: "dbg!(42)", 252 delete: [49; 52),
249 detail: "dbg!(expr)", 253 insert: "dbg!(42)",
250 }, 254 detail: "dbg!(expr)",
251 CompletionItem { 255 },
252 label: "match", 256 CompletionItem {
253 source_range: [52; 52), 257 label: "match",
254 delete: [49; 52), 258 source_range: [52; 52),
255 insert: "match 42 {\n ${1:_} => {$0\\},\n}", 259 delete: [49; 52),
256 detail: "match expr {}", 260 insert: "match 42 {\n ${1:_} => {$0\\},\n}",
257 }, 261 detail: "match expr {}",
258 CompletionItem { 262 },
259 label: "not", 263 CompletionItem {
260 source_range: [52; 52), 264 label: "not",
261 delete: [49; 52), 265 source_range: [52; 52),
262 insert: "!42", 266 delete: [49; 52),
263 detail: "!expr", 267 insert: "!42",
264 }, 268 detail: "!expr",
265 CompletionItem { 269 },
266 label: "ref", 270 CompletionItem {
267 source_range: [52; 52), 271 label: "ref",
268 delete: [49; 52), 272 source_range: [52; 52),
269 insert: "&42", 273 delete: [49; 52),
270 detail: "&expr", 274 insert: "&42",
271 }, 275 detail: "&expr",
272 CompletionItem { 276 },
273 label: "refm", 277 CompletionItem {
274 source_range: [52; 52), 278 label: "refm",
275 delete: [49; 52), 279 source_range: [52; 52),
276 insert: "&mut 42", 280 delete: [49; 52),
277 detail: "&mut expr", 281 insert: "&mut 42",
278 }, 282 detail: "&mut expr",
279]"### 283 },
284 ]
285 "###
280 ); 286 );
281 } 287 }
282} 288}
diff --git a/crates/ra_ide_api/src/completion/complete_record_literal.rs b/crates/ra_ide_api/src/completion/complete_record_literal.rs
index 0295b8101..45a4a9738 100644
--- a/crates/ra_ide_api/src/completion/complete_record_literal.rs
+++ b/crates/ra_ide_api/src/completion/complete_record_literal.rs
@@ -45,17 +45,17 @@ mod tests {
45 ", 45 ",
46 ); 46 );
47 assert_debug_snapshot!(completions, @r###" 47 assert_debug_snapshot!(completions, @r###"
48 [ 48 [
49 CompletionItem { 49 CompletionItem {
50 label: "the_field", 50 label: "the_field",
51 source_range: [142; 145), 51 source_range: [142; 145),
52 delete: [142; 145), 52 delete: [142; 145),
53 insert: "the_field", 53 insert: "the_field",
54 kind: Field, 54 kind: Field,
55 detail: "u32", 55 detail: "u32",
56 deprecated: true, 56 deprecated: true,
57 }, 57 },
58 ] 58 ]
59 "###); 59 "###);
60 } 60 }
61 61
@@ -70,16 +70,16 @@ mod tests {
70 ", 70 ",
71 ); 71 );
72 assert_debug_snapshot!(completions, @r###" 72 assert_debug_snapshot!(completions, @r###"
73 [ 73 [
74 CompletionItem { 74 CompletionItem {
75 label: "the_field", 75 label: "the_field",
76 source_range: [83; 86), 76 source_range: [83; 86),
77 delete: [83; 86), 77 delete: [83; 86),
78 insert: "the_field", 78 insert: "the_field",
79 kind: Field, 79 kind: Field,
80 detail: "u32", 80 detail: "u32",
81 }, 81 },
82 ] 82 ]
83 "###); 83 "###);
84 } 84 }
85 85
@@ -96,16 +96,16 @@ mod tests {
96 ", 96 ",
97 ); 97 );
98 assert_debug_snapshot!(completions, @r###" 98 assert_debug_snapshot!(completions, @r###"
99 [ 99 [
100 CompletionItem { 100 CompletionItem {
101 label: "a", 101 label: "a",
102 source_range: [119; 119), 102 source_range: [119; 119),
103 delete: [119; 119), 103 delete: [119; 119),
104 insert: "a", 104 insert: "a",
105 kind: Field, 105 kind: Field,
106 detail: "u32", 106 detail: "u32",
107 }, 107 },
108 ] 108 ]
109 "###); 109 "###);
110 } 110 }
111 111
@@ -122,16 +122,16 @@ mod tests {
122 ", 122 ",
123 ); 123 );
124 assert_debug_snapshot!(completions, @r###" 124 assert_debug_snapshot!(completions, @r###"
125 [ 125 [
126 CompletionItem { 126 CompletionItem {
127 label: "b", 127 label: "b",
128 source_range: [119; 119), 128 source_range: [119; 119),
129 delete: [119; 119), 129 delete: [119; 119),
130 insert: "b", 130 insert: "b",
131 kind: Field, 131 kind: Field,
132 detail: "u32", 132 detail: "u32",
133 }, 133 },
134 ] 134 ]
135 "###); 135 "###);
136 } 136 }
137 137
@@ -147,16 +147,16 @@ mod tests {
147 ", 147 ",
148 ); 148 );
149 assert_debug_snapshot!(completions, @r###" 149 assert_debug_snapshot!(completions, @r###"
150 [ 150 [
151 CompletionItem { 151 CompletionItem {
152 label: "a", 152 label: "a",
153 source_range: [93; 93), 153 source_range: [93; 93),
154 delete: [93; 93), 154 delete: [93; 93),
155 insert: "a", 155 insert: "a",
156 kind: Field, 156 kind: Field,
157 detail: "u32", 157 detail: "u32",
158 }, 158 },
159 ] 159 ]
160 "###); 160 "###);
161 } 161 }
162} 162}
diff --git a/crates/ra_ide_api/src/completion/complete_record_pattern.rs b/crates/ra_ide_api/src/completion/complete_record_pattern.rs
index d20fa796c..aa0fd6d24 100644
--- a/crates/ra_ide_api/src/completion/complete_record_pattern.rs
+++ b/crates/ra_ide_api/src/completion/complete_record_pattern.rs
@@ -44,16 +44,16 @@ mod tests {
44 ", 44 ",
45 ); 45 );
46 assert_debug_snapshot!(completions, @r###" 46 assert_debug_snapshot!(completions, @r###"
47 [ 47 [
48 CompletionItem { 48 CompletionItem {
49 label: "foo", 49 label: "foo",
50 source_range: [117; 118), 50 source_range: [117; 118),
51 delete: [117; 118), 51 delete: [117; 118),
52 insert: "foo", 52 insert: "foo",
53 kind: Field, 53 kind: Field,
54 detail: "u32", 54 detail: "u32",
55 }, 55 },
56 ] 56 ]
57 "###); 57 "###);
58 } 58 }
59 59
@@ -73,24 +73,24 @@ mod tests {
73 ", 73 ",
74 ); 74 );
75 assert_debug_snapshot!(completions, @r###" 75 assert_debug_snapshot!(completions, @r###"
76 [ 76 [
77 CompletionItem { 77 CompletionItem {
78 label: "bar", 78 label: "bar",
79 source_range: [161; 161), 79 source_range: [161; 161),
80 delete: [161; 161), 80 delete: [161; 161),
81 insert: "bar", 81 insert: "bar",
82 kind: Field, 82 kind: Field,
83 detail: "()", 83 detail: "()",
84 }, 84 },
85 CompletionItem { 85 CompletionItem {
86 label: "foo", 86 label: "foo",
87 source_range: [161; 161), 87 source_range: [161; 161),
88 delete: [161; 161), 88 delete: [161; 161),
89 insert: "foo", 89 insert: "foo",
90 kind: Field, 90 kind: Field,
91 detail: "u32", 91 detail: "u32",
92 }, 92 },
93 ] 93 ]
94 "###); 94 "###);
95 } 95 }
96} 96}
diff --git a/crates/ra_ide_api/src/completion/complete_scope.rs b/crates/ra_ide_api/src/completion/complete_scope.rs
index 3e205efd1..8c57c907d 100644
--- a/crates/ra_ide_api/src/completion/complete_scope.rs
+++ b/crates/ra_ide_api/src/completion/complete_scope.rs
@@ -409,15 +409,17 @@ mod tests {
409 // nothing here 409 // nothing here
410 " 410 "
411 ), 411 ),
412 @r#"[ 412 @r###"
413 CompletionItem { 413 [
414 label: "other_crate", 414 CompletionItem {
415 source_range: [4; 4), 415 label: "other_crate",
416 delete: [4; 4), 416 source_range: [4; 4),
417 insert: "other_crate", 417 delete: [4; 4),
418 kind: Module, 418 insert: "other_crate",
419 }, 419 kind: Module,
420]"# 420 },
421 ]
422 "###
421 ); 423 );
422 } 424 }
423 425
@@ -530,23 +532,25 @@ mod tests {
530 fn completes_self_in_methods() { 532 fn completes_self_in_methods() {
531 assert_debug_snapshot!( 533 assert_debug_snapshot!(
532 do_reference_completion(r"impl S { fn foo(&self) { <|> } }"), 534 do_reference_completion(r"impl S { fn foo(&self) { <|> } }"),
533 @r#"[ 535 @r###"
534 CompletionItem { 536 [
535 label: "Self", 537 CompletionItem {
536 source_range: [25; 25), 538 label: "Self",
537 delete: [25; 25), 539 source_range: [25; 25),
538 insert: "Self", 540 delete: [25; 25),
539 kind: TypeParam, 541 insert: "Self",
540 }, 542 kind: TypeParam,
541 CompletionItem { 543 },
542 label: "self", 544 CompletionItem {
543 source_range: [25; 25), 545 label: "self",
544 delete: [25; 25), 546 source_range: [25; 25),
545 insert: "self", 547 delete: [25; 25),
546 kind: Binding, 548 insert: "self",
547 detail: "&{unknown}", 549 kind: Binding,
548 }, 550 detail: "&{unknown}",
549]"# 551 },
552 ]
553 "###
550 ); 554 );
551 } 555 }
552 556
diff --git a/crates/ra_ide_api/src/completion/complete_snippet.rs b/crates/ra_ide_api/src/completion/complete_snippet.rs
index 2df79b6c3..1f2988b36 100644
--- a/crates/ra_ide_api/src/completion/complete_snippet.rs
+++ b/crates/ra_ide_api/src/completion/complete_snippet.rs
@@ -52,22 +52,24 @@ mod tests {
52 fn completes_snippets_in_expressions() { 52 fn completes_snippets_in_expressions() {
53 assert_debug_snapshot!( 53 assert_debug_snapshot!(
54 do_snippet_completion(r"fn foo(x: i32) { <|> }"), 54 do_snippet_completion(r"fn foo(x: i32) { <|> }"),
55 @r#"[ 55 @r###"
56 CompletionItem { 56 [
57 label: "pd", 57 CompletionItem {
58 source_range: [17; 17), 58 label: "pd",
59 delete: [17; 17), 59 source_range: [17; 17),
60 insert: "eprintln!(\"$0 = {:?}\", $0);", 60 delete: [17; 17),
61 kind: Snippet, 61 insert: "eprintln!(\"$0 = {:?}\", $0);",
62 }, 62 kind: Snippet,
63 CompletionItem { 63 },
64 label: "ppd", 64 CompletionItem {
65 source_range: [17; 17), 65 label: "ppd",
66 delete: [17; 17), 66 source_range: [17; 17),
67 insert: "eprintln!(\"$0 = {:#?}\", $0);", 67 delete: [17; 17),
68 kind: Snippet, 68 insert: "eprintln!(\"$0 = {:#?}\", $0);",
69 }, 69 kind: Snippet,
70]"# 70 },
71 ]
72 "###
71 ); 73 );
72 } 74 }
73 75
@@ -75,11 +77,11 @@ mod tests {
75 fn should_not_complete_snippets_in_path() { 77 fn should_not_complete_snippets_in_path() {
76 assert_debug_snapshot!( 78 assert_debug_snapshot!(
77 do_snippet_completion(r"fn foo(x: i32) { ::foo<|> }"), 79 do_snippet_completion(r"fn foo(x: i32) { ::foo<|> }"),
78 @r#"[]"# 80 @"[]"
79 ); 81 );
80 assert_debug_snapshot!( 82 assert_debug_snapshot!(
81 do_snippet_completion(r"fn foo(x: i32) { ::<|> }"), 83 do_snippet_completion(r"fn foo(x: i32) { ::<|> }"),
82 @r#"[]"# 84 @"[]"
83 ); 85 );
84 } 86 }
85 87
@@ -94,23 +96,25 @@ mod tests {
94 } 96 }
95 " 97 "
96 ), 98 ),
97 @r###"[ 99 @r###"
98 CompletionItem { 100 [
99 label: "Test function", 101 CompletionItem {
100 source_range: [78; 78), 102 label: "Test function",
101 delete: [78; 78), 103 source_range: [78; 78),
102 insert: "#[test]\nfn ${1:feature}() {\n $0\n}", 104 delete: [78; 78),
103 kind: Snippet, 105 insert: "#[test]\nfn ${1:feature}() {\n $0\n}",
104 lookup: "tfn", 106 kind: Snippet,
105 }, 107 lookup: "tfn",
106 CompletionItem { 108 },
107 label: "pub(crate)", 109 CompletionItem {
108 source_range: [78; 78), 110 label: "pub(crate)",
109 delete: [78; 78), 111 source_range: [78; 78),
110 insert: "pub(crate) $0", 112 delete: [78; 78),
111 kind: Snippet, 113 insert: "pub(crate) $0",
112 }, 114 kind: Snippet,
113]"### 115 },
116 ]
117 "###
114 ); 118 );
115 } 119 }
116} 120}
diff --git a/crates/ra_ide_api/src/completion/presentation.rs b/crates/ra_ide_api/src/completion/presentation.rs
index d861303b7..501b7da4e 100644
--- a/crates/ra_ide_api/src/completion/presentation.rs
+++ b/crates/ra_ide_api/src/completion/presentation.rs
@@ -68,7 +68,7 @@ impl Completions {
68 ScopeDef::ModuleDef(TypeAlias(..)) => CompletionItemKind::TypeAlias, 68 ScopeDef::ModuleDef(TypeAlias(..)) => CompletionItemKind::TypeAlias,
69 ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType, 69 ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType,
70 ScopeDef::GenericParam(..) => CompletionItemKind::TypeParam, 70 ScopeDef::GenericParam(..) => CompletionItemKind::TypeParam,
71 ScopeDef::LocalBinding(..) => CompletionItemKind::Binding, 71 ScopeDef::Local(..) => CompletionItemKind::Binding,
72 // (does this need its own kind?) 72 // (does this need its own kind?)
73 ScopeDef::AdtSelfType(..) | ScopeDef::ImplSelfType(..) => CompletionItemKind::TypeParam, 73 ScopeDef::AdtSelfType(..) | ScopeDef::ImplSelfType(..) => CompletionItemKind::TypeParam,
74 ScopeDef::MacroDef(mac) => { 74 ScopeDef::MacroDef(mac) => {
@@ -96,13 +96,11 @@ impl Completions {
96 96
97 let mut completion_item = 97 let mut completion_item =
98 CompletionItem::new(completion_kind, ctx.source_range(), local_name.clone()); 98 CompletionItem::new(completion_kind, ctx.source_range(), local_name.clone());
99 if let ScopeDef::LocalBinding(pat_id) = resolution { 99 if let ScopeDef::Local(local) = resolution {
100 let ty = ctx 100 let ty = local.ty(ctx.db);
101 .analyzer 101 if ty != Ty::Unknown {
102 .type_of_pat_by_id(ctx.db, pat_id.clone()) 102 completion_item = completion_item.detail(ty.display(ctx.db).to_string());
103 .filter(|t| t != &Ty::Unknown) 103 }
104 .map(|t| t.display(ctx.db).to_string());
105 completion_item = completion_item.set_detail(ty);
106 }; 104 };
107 105
108 // If not an import, add parenthesis automatically. 106 // If not an import, add parenthesis automatically.
@@ -325,38 +323,38 @@ mod tests {
325 "#, 323 "#,
326 ), 324 ),
327 @r###" 325 @r###"
328 [ 326 [
329 CompletionItem { 327 CompletionItem {
330 label: "main()", 328 label: "main()",
331 source_range: [203; 206), 329 source_range: [203; 206),
332 delete: [203; 206), 330 delete: [203; 206),
333 insert: "main()$0", 331 insert: "main()$0",
334 kind: Function, 332 kind: Function,
335 lookup: "main", 333 lookup: "main",
336 detail: "fn main()", 334 detail: "fn main()",
337 }, 335 },
338 CompletionItem { 336 CompletionItem {
339 label: "something_deprecated()", 337 label: "something_deprecated()",
340 source_range: [203; 206), 338 source_range: [203; 206),
341 delete: [203; 206), 339 delete: [203; 206),
342 insert: "something_deprecated()$0", 340 insert: "something_deprecated()$0",
343 kind: Function, 341 kind: Function,
344 lookup: "something_deprecated", 342 lookup: "something_deprecated",
345 detail: "fn something_deprecated()", 343 detail: "fn something_deprecated()",
346 deprecated: true, 344 deprecated: true,
347 }, 345 },
348 CompletionItem { 346 CompletionItem {
349 label: "something_else_deprecated()", 347 label: "something_else_deprecated()",
350 source_range: [203; 206), 348 source_range: [203; 206),
351 delete: [203; 206), 349 delete: [203; 206),
352 insert: "something_else_deprecated()$0", 350 insert: "something_else_deprecated()$0",
353 kind: Function, 351 kind: Function,
354 lookup: "something_else_deprecated", 352 lookup: "something_else_deprecated",
355 detail: "fn something_else_deprecated()", 353 detail: "fn something_else_deprecated()",
356 deprecated: true, 354 deprecated: true,
357 }, 355 },
358 ] 356 ]
359 "### 357 "###
360 ); 358 );
361 } 359 }
362 360
@@ -461,16 +459,18 @@ mod tests {
461 use crate::m::f<|>; 459 use crate::m::f<|>;
462 " 460 "
463 ), 461 ),
464 @r#"[ 462 @r###"
465 CompletionItem { 463 [
466 label: "foo", 464 CompletionItem {
467 source_range: [40; 41), 465 label: "foo",
468 delete: [40; 41), 466 source_range: [40; 41),
469 insert: "foo", 467 delete: [40; 41),
470 kind: Function, 468 insert: "foo",
471 detail: "pub fn foo()", 469 kind: Function,
472 }, 470 detail: "pub fn foo()",
473]"# 471 },
472 ]
473 "###
474 ); 474 );
475 } 475 }
476 476
@@ -486,24 +486,26 @@ mod tests {
486 } 486 }
487 " 487 "
488 ), 488 ),
489 @r#"[ 489 @r###"
490 CompletionItem { 490 [
491 label: "frobnicate", 491 CompletionItem {
492 source_range: [35; 39), 492 label: "frobnicate",
493 delete: [35; 39), 493 source_range: [35; 39),
494 insert: "frobnicate", 494 delete: [35; 39),
495 kind: Function, 495 insert: "frobnicate",
496 detail: "fn frobnicate()", 496 kind: Function,
497 }, 497 detail: "fn frobnicate()",
498 CompletionItem { 498 },
499 label: "main", 499 CompletionItem {
500 source_range: [35; 39), 500 label: "main",
501 delete: [35; 39), 501 source_range: [35; 39),
502 insert: "main", 502 delete: [35; 39),
503 kind: Function, 503 insert: "main",
504 detail: "fn main()", 504 kind: Function,
505 }, 505 detail: "fn main()",
506]"# 506 },
507 ]
508 "###
507 ); 509 );
508 assert_debug_snapshot!( 510 assert_debug_snapshot!(
509 do_reference_completion( 511 do_reference_completion(
@@ -516,16 +518,18 @@ mod tests {
516 } 518 }
517 " 519 "
518 ), 520 ),
519 @r#"[ 521 @r###"
520 CompletionItem { 522 [
521 label: "new", 523 CompletionItem {
522 source_range: [67; 69), 524 label: "new",
523 delete: [67; 69), 525 source_range: [67; 69),
524 insert: "new", 526 delete: [67; 69),
525 kind: Function, 527 insert: "new",
526 detail: "fn new() -> Foo", 528 kind: Function,
527 }, 529 detail: "fn new() -> Foo",
528]"# 530 },
531 ]
532 "###
529 ); 533 );
530 } 534 }
531 535
diff --git a/crates/ra_ide_api/src/diagnostics.rs b/crates/ra_ide_api/src/diagnostics.rs
index 2890a3d2b..e52ffefb3 100644
--- a/crates/ra_ide_api/src/diagnostics.rs
+++ b/crates/ra_ide_api/src/diagnostics.rs
@@ -526,28 +526,28 @@ mod tests {
526 let (analysis, file_id) = single_file("mod foo;"); 526 let (analysis, file_id) = single_file("mod foo;");
527 let diagnostics = analysis.diagnostics(file_id).unwrap(); 527 let diagnostics = analysis.diagnostics(file_id).unwrap();
528 assert_debug_snapshot!(diagnostics, @r###" 528 assert_debug_snapshot!(diagnostics, @r###"
529 [ 529 [
530 Diagnostic { 530 Diagnostic {
531 message: "unresolved module", 531 message: "unresolved module",
532 range: [0; 8), 532 range: [0; 8),
533 fix: Some( 533 fix: Some(
534 SourceChange { 534 SourceChange {
535 label: "create module", 535 label: "create module",
536 source_file_edits: [], 536 source_file_edits: [],
537 file_system_edits: [ 537 file_system_edits: [
538 CreateFile { 538 CreateFile {
539 source_root: SourceRootId( 539 source_root: SourceRootId(
540 0, 540 0,
541 ), 541 ),
542 path: "foo.rs", 542 path: "foo.rs",
543 }, 543 },
544 ], 544 ],
545 cursor_position: None, 545 cursor_position: None,
546 }, 546 },
547 ), 547 ),
548 severity: Error, 548 severity: Error,
549 }, 549 },
550 ] 550 ]
551 "###); 551 "###);
552 } 552 }
553 553
diff --git a/crates/ra_ide_api/src/display/structure.rs b/crates/ra_ide_api/src/display/structure.rs
index ddd8b7b20..a80d65ac7 100644
--- a/crates/ra_ide_api/src/display/structure.rs
+++ b/crates/ra_ide_api/src/display/structure.rs
@@ -209,191 +209,193 @@ fn very_obsolete() {}
209 .unwrap(); 209 .unwrap();
210 let structure = file_structure(&file); 210 let structure = file_structure(&file);
211 assert_debug_snapshot!(structure, 211 assert_debug_snapshot!(structure,
212 @r#"[ 212 @r###"
213 StructureNode { 213 [
214 parent: None, 214 StructureNode {
215 label: "Foo", 215 parent: None,
216 navigation_range: [8; 11), 216 label: "Foo",
217 node_range: [1; 26), 217 navigation_range: [8; 11),
218 kind: STRUCT_DEF, 218 node_range: [1; 26),
219 detail: None, 219 kind: STRUCT_DEF,
220 deprecated: false, 220 detail: None,
221 }, 221 deprecated: false,
222 StructureNode { 222 },
223 parent: Some( 223 StructureNode {
224 0, 224 parent: Some(
225 ), 225 0,
226 label: "x", 226 ),
227 navigation_range: [18; 19), 227 label: "x",
228 node_range: [18; 24), 228 navigation_range: [18; 19),
229 kind: RECORD_FIELD_DEF, 229 node_range: [18; 24),
230 detail: Some( 230 kind: RECORD_FIELD_DEF,
231 "i32", 231 detail: Some(
232 ), 232 "i32",
233 deprecated: false, 233 ),
234 }, 234 deprecated: false,
235 StructureNode { 235 },
236 parent: None, 236 StructureNode {
237 label: "m", 237 parent: None,
238 navigation_range: [32; 33), 238 label: "m",
239 node_range: [28; 158), 239 navigation_range: [32; 33),
240 kind: MODULE, 240 node_range: [28; 158),
241 detail: None, 241 kind: MODULE,
242 deprecated: false, 242 detail: None,
243 }, 243 deprecated: false,
244 StructureNode { 244 },
245 parent: Some( 245 StructureNode {
246 2, 246 parent: Some(
247 ), 247 2,
248 label: "bar1", 248 ),
249 navigation_range: [43; 47), 249 label: "bar1",
250 node_range: [40; 52), 250 navigation_range: [43; 47),
251 kind: FN_DEF, 251 node_range: [40; 52),
252 detail: Some( 252 kind: FN_DEF,
253 "fn()", 253 detail: Some(
254 ), 254 "fn()",
255 deprecated: false, 255 ),
256 }, 256 deprecated: false,
257 StructureNode { 257 },
258 parent: Some( 258 StructureNode {
259 2, 259 parent: Some(
260 ), 260 2,
261 label: "bar2", 261 ),
262 navigation_range: [60; 64), 262 label: "bar2",
263 node_range: [57; 81), 263 navigation_range: [60; 64),
264 kind: FN_DEF, 264 node_range: [57; 81),
265 detail: Some( 265 kind: FN_DEF,
266 "fn<T>(t: T) -> T", 266 detail: Some(
267 ), 267 "fn<T>(t: T) -> T",
268 deprecated: false, 268 ),
269 }, 269 deprecated: false,
270 StructureNode { 270 },
271 parent: Some( 271 StructureNode {
272 2, 272 parent: Some(
273 ), 273 2,
274 label: "bar3", 274 ),
275 navigation_range: [89; 93), 275 label: "bar3",
276 node_range: [86; 156), 276 navigation_range: [89; 93),
277 kind: FN_DEF, 277 node_range: [86; 156),
278 detail: Some( 278 kind: FN_DEF,
279 "fn<A, B>(a: A, b: B) -> Vec< u32 >", 279 detail: Some(
280 ), 280 "fn<A, B>(a: A, b: B) -> Vec< u32 >",
281 deprecated: false, 281 ),
282 }, 282 deprecated: false,
283 StructureNode { 283 },
284 parent: None, 284 StructureNode {
285 label: "E", 285 parent: None,
286 navigation_range: [165; 166), 286 label: "E",
287 node_range: [160; 180), 287 navigation_range: [165; 166),
288 kind: ENUM_DEF, 288 node_range: [160; 180),
289 detail: None, 289 kind: ENUM_DEF,
290 deprecated: false, 290 detail: None,
291 }, 291 deprecated: false,
292 StructureNode { 292 },
293 parent: Some( 293 StructureNode {
294 6, 294 parent: Some(
295 ), 295 6,
296 label: "X", 296 ),
297 navigation_range: [169; 170), 297 label: "X",
298 node_range: [169; 170), 298 navigation_range: [169; 170),
299 kind: ENUM_VARIANT, 299 node_range: [169; 170),
300 detail: None, 300 kind: ENUM_VARIANT,
301 deprecated: false, 301 detail: None,
302 }, 302 deprecated: false,
303 StructureNode { 303 },
304 parent: Some( 304 StructureNode {
305 6, 305 parent: Some(
306 ), 306 6,
307 label: "Y", 307 ),
308 navigation_range: [172; 173), 308 label: "Y",
309 node_range: [172; 178), 309 navigation_range: [172; 173),
310 kind: ENUM_VARIANT, 310 node_range: [172; 178),
311 detail: None, 311 kind: ENUM_VARIANT,
312 deprecated: false, 312 detail: None,
313 }, 313 deprecated: false,
314 StructureNode { 314 },
315 parent: None, 315 StructureNode {
316 label: "T", 316 parent: None,
317 navigation_range: [186; 187), 317 label: "T",
318 node_range: [181; 193), 318 navigation_range: [186; 187),
319 kind: TYPE_ALIAS_DEF, 319 node_range: [181; 193),
320 detail: Some( 320 kind: TYPE_ALIAS_DEF,
321 "()", 321 detail: Some(
322 ), 322 "()",
323 deprecated: false, 323 ),
324 }, 324 deprecated: false,
325 StructureNode { 325 },
326 parent: None, 326 StructureNode {
327 label: "S", 327 parent: None,
328 navigation_range: [201; 202), 328 label: "S",
329 node_range: [194; 213), 329 navigation_range: [201; 202),
330 kind: STATIC_DEF, 330 node_range: [194; 213),
331 detail: Some( 331 kind: STATIC_DEF,
332 "i32", 332 detail: Some(
333 ), 333 "i32",
334 deprecated: false, 334 ),
335 }, 335 deprecated: false,
336 StructureNode { 336 },
337 parent: None, 337 StructureNode {
338 label: "C", 338 parent: None,
339 navigation_range: [220; 221), 339 label: "C",
340 node_range: [214; 232), 340 navigation_range: [220; 221),
341 kind: CONST_DEF, 341 node_range: [214; 232),
342 detail: Some( 342 kind: CONST_DEF,
343 "i32", 343 detail: Some(
344 ), 344 "i32",
345 deprecated: false, 345 ),
346 }, 346 deprecated: false,
347 StructureNode { 347 },
348 parent: None, 348 StructureNode {
349 label: "impl E", 349 parent: None,
350 navigation_range: [239; 240), 350 label: "impl E",
351 node_range: [234; 243), 351 navigation_range: [239; 240),
352 kind: IMPL_BLOCK, 352 node_range: [234; 243),
353 detail: None, 353 kind: IMPL_BLOCK,
354 deprecated: false, 354 detail: None,
355 }, 355 deprecated: false,
356 StructureNode { 356 },
357 parent: None, 357 StructureNode {
358 label: "impl fmt::Debug for E", 358 parent: None,
359 navigation_range: [265; 266), 359 label: "impl fmt::Debug for E",
360 node_range: [245; 269), 360 navigation_range: [265; 266),
361 kind: IMPL_BLOCK, 361 node_range: [245; 269),
362 detail: None, 362 kind: IMPL_BLOCK,
363 deprecated: false, 363 detail: None,
364 }, 364 deprecated: false,
365 StructureNode { 365 },
366 parent: None, 366 StructureNode {
367 label: "mc", 367 parent: None,
368 navigation_range: [284; 286), 368 label: "mc",
369 node_range: [271; 303), 369 navigation_range: [284; 286),
370 kind: MACRO_CALL, 370 node_range: [271; 303),
371 detail: None, 371 kind: MACRO_CALL,
372 deprecated: false, 372 detail: None,
373 }, 373 deprecated: false,
374 StructureNode { 374 },
375 parent: None, 375 StructureNode {
376 label: "obsolete", 376 parent: None,
377 navigation_range: [322; 330), 377 label: "obsolete",
378 node_range: [305; 335), 378 navigation_range: [322; 330),
379 kind: FN_DEF, 379 node_range: [305; 335),
380 detail: Some( 380 kind: FN_DEF,
381 "fn()", 381 detail: Some(
382 ), 382 "fn()",
383 deprecated: true, 383 ),
384 }, 384 deprecated: true,
385 StructureNode { 385 },
386 parent: None, 386 StructureNode {
387 label: "very_obsolete", 387 parent: None,
388 navigation_range: [375; 388), 388 label: "very_obsolete",
389 node_range: [337; 393), 389 navigation_range: [375; 388),
390 kind: FN_DEF, 390 node_range: [337; 393),
391 detail: Some( 391 kind: FN_DEF,
392 "fn()", 392 detail: Some(
393 ), 393 "fn()",
394 deprecated: true, 394 ),
395 }, 395 deprecated: true,
396]"# 396 },
397 ]
398 "###
397 ); 399 );
398 } 400 }
399} 401}
diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs
index 086e6dec3..07d511fb3 100644
--- a/crates/ra_ide_api/src/hover.rs
+++ b/crates/ra_ide_api/src/hover.rs
@@ -5,7 +5,7 @@ use ra_db::SourceDatabase;
5use ra_syntax::{ 5use ra_syntax::{
6 algo::{ancestors_at_offset, find_covering_element, find_node_at_offset}, 6 algo::{ancestors_at_offset, find_covering_element, find_node_at_offset},
7 ast::{self, DocCommentsOwner}, 7 ast::{self, DocCommentsOwner},
8 match_ast, AstNode, 8 AstNode,
9}; 9};
10 10
11use crate::{ 11use crate::{
@@ -14,7 +14,7 @@ use crate::{
14 description_from_symbol, docs_from_symbol, macro_label, rust_code_markup, 14 description_from_symbol, docs_from_symbol, macro_label, rust_code_markup,
15 rust_code_markup_with_doc, ShortLabel, 15 rust_code_markup_with_doc, ShortLabel,
16 }, 16 },
17 references::{classify_name_ref, NameKind::*}, 17 references::{classify_name, classify_name_ref, NameKind, NameKind::*},
18 FilePosition, FileRange, RangeInfo, 18 FilePosition, FileRange, RangeInfo,
19}; 19};
20 20
@@ -92,65 +92,88 @@ fn hover_text(docs: Option<String>, desc: Option<String>) -> Option<String> {
92 } 92 }
93} 93}
94 94
95fn hover_text_from_name_kind(
96 db: &RootDatabase,
97 name_kind: NameKind,
98 no_fallback: &mut bool,
99) -> Option<String> {
100 return match name_kind {
101 Macro(it) => {
102 let src = it.source(db);
103 hover_text(src.ast.doc_comment_text(), Some(macro_label(&src.ast)))
104 }
105 Field(it) => {
106 let src = it.source(db);
107 match src.ast {
108 hir::FieldSource::Named(it) => hover_text(it.doc_comment_text(), it.short_label()),
109 _ => None,
110 }
111 }
112 AssocItem(it) => match it {
113 hir::AssocItem::Function(it) => from_def_source(db, it),
114 hir::AssocItem::Const(it) => from_def_source(db, it),
115 hir::AssocItem::TypeAlias(it) => from_def_source(db, it),
116 },
117 Def(it) => match it {
118 hir::ModuleDef::Module(it) => match it.definition_source(db).ast {
119 hir::ModuleSource::Module(it) => {
120 hover_text(it.doc_comment_text(), it.short_label())
121 }
122 _ => None,
123 },
124 hir::ModuleDef::Function(it) => from_def_source(db, it),
125 hir::ModuleDef::Adt(Adt::Struct(it)) => from_def_source(db, it),
126 hir::ModuleDef::Adt(Adt::Union(it)) => from_def_source(db, it),
127 hir::ModuleDef::Adt(Adt::Enum(it)) => from_def_source(db, it),
128 hir::ModuleDef::EnumVariant(it) => from_def_source(db, it),
129 hir::ModuleDef::Const(it) => from_def_source(db, it),
130 hir::ModuleDef::Static(it) => from_def_source(db, it),
131 hir::ModuleDef::Trait(it) => from_def_source(db, it),
132 hir::ModuleDef::TypeAlias(it) => from_def_source(db, it),
133 hir::ModuleDef::BuiltinType(it) => Some(it.to_string()),
134 },
135 SelfType(ty) => match ty.as_adt() {
136 Some((adt_def, _)) => match adt_def {
137 hir::Adt::Struct(it) => from_def_source(db, it),
138 hir::Adt::Union(it) => from_def_source(db, it),
139 hir::Adt::Enum(it) => from_def_source(db, it),
140 },
141 _ => None,
142 },
143 Local(_) => {
144 // Hover for these shows type names
145 *no_fallback = true;
146 None
147 }
148 GenericParam(_) => {
149 // FIXME: Hover for generic param
150 None
151 }
152 };
153
154 fn from_def_source<A, D>(db: &RootDatabase, def: D) -> Option<String>
155 where
156 D: HasSource<Ast = A>,
157 A: ast::DocCommentsOwner + ast::NameOwner + ShortLabel,
158 {
159 let src = def.source(db);
160 hover_text(src.ast.doc_comment_text(), src.ast.short_label())
161 }
162}
163
95pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<HoverResult>> { 164pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<HoverResult>> {
96 let parse = db.parse(position.file_id); 165 let parse = db.parse(position.file_id);
97 let file = parse.tree(); 166 let file = parse.tree();
167
98 let mut res = HoverResult::new(); 168 let mut res = HoverResult::new();
99 169
100 let mut range = None; 170 let mut range = if let Some(name_ref) =
101 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset) { 171 find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset)
172 {
102 let mut no_fallback = false; 173 let mut no_fallback = false;
103 let name_kind = classify_name_ref(db, position.file_id, &name_ref).map(|d| d.kind); 174 if let Some(name_kind) = classify_name_ref(db, position.file_id, &name_ref).map(|d| d.kind)
104 match name_kind { 175 {
105 Some(Macro(it)) => { 176 res.extend(hover_text_from_name_kind(db, name_kind, &mut no_fallback))
106 let src = it.source(db);
107 res.extend(hover_text(src.ast.doc_comment_text(), Some(macro_label(&src.ast))));
108 }
109 Some(Field(it)) => {
110 let src = it.source(db);
111 if let hir::FieldSource::Named(it) = src.ast {
112 res.extend(hover_text(it.doc_comment_text(), it.short_label()));
113 }
114 }
115 Some(AssocItem(it)) => res.extend(match it {
116 hir::AssocItem::Function(it) => from_def_source(db, it),
117 hir::AssocItem::Const(it) => from_def_source(db, it),
118 hir::AssocItem::TypeAlias(it) => from_def_source(db, it),
119 }),
120 Some(Def(it)) => match it {
121 hir::ModuleDef::Module(it) => {
122 if let hir::ModuleSource::Module(it) = it.definition_source(db).ast {
123 res.extend(hover_text(it.doc_comment_text(), it.short_label()))
124 }
125 }
126 hir::ModuleDef::Function(it) => res.extend(from_def_source(db, it)),
127 hir::ModuleDef::Adt(Adt::Struct(it)) => res.extend(from_def_source(db, it)),
128 hir::ModuleDef::Adt(Adt::Union(it)) => res.extend(from_def_source(db, it)),
129 hir::ModuleDef::Adt(Adt::Enum(it)) => res.extend(from_def_source(db, it)),
130 hir::ModuleDef::EnumVariant(it) => res.extend(from_def_source(db, it)),
131 hir::ModuleDef::Const(it) => res.extend(from_def_source(db, it)),
132 hir::ModuleDef::Static(it) => res.extend(from_def_source(db, it)),
133 hir::ModuleDef::Trait(it) => res.extend(from_def_source(db, it)),
134 hir::ModuleDef::TypeAlias(it) => res.extend(from_def_source(db, it)),
135 hir::ModuleDef::BuiltinType(it) => res.extend(Some(it.to_string())),
136 },
137 Some(SelfType(ty)) => {
138 if let Some((adt_def, _)) = ty.as_adt() {
139 res.extend(match adt_def {
140 hir::Adt::Struct(it) => from_def_source(db, it),
141 hir::Adt::Union(it) => from_def_source(db, it),
142 hir::Adt::Enum(it) => from_def_source(db, it),
143 })
144 }
145 }
146 Some(Local(_)) => {
147 // Hover for these shows type names
148 no_fallback = true;
149 }
150 Some(GenericParam(_)) => {
151 // FIXME: Hover for generic param
152 }
153 None => {}
154 } 177 }
155 178
156 if res.is_empty() && !no_fallback { 179 if res.is_empty() && !no_fallback {
@@ -164,55 +187,24 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
164 } 187 }
165 188
166 if !res.is_empty() { 189 if !res.is_empty() {
167 range = Some(name_ref.syntax().text_range()) 190 Some(name_ref.syntax().text_range())
191 } else {
192 None
168 } 193 }
169 } else if let Some(name) = find_node_at_offset::<ast::Name>(file.syntax(), position.offset) { 194 } else if let Some(name) = find_node_at_offset::<ast::Name>(file.syntax(), position.offset) {
170 if let Some(parent) = name.syntax().parent() { 195 if let Some(name_kind) = classify_name(db, position.file_id, &name).map(|d| d.kind) {
171 let text = match_ast! { 196 let mut _b: bool = true;
172 match parent { 197 res.extend(hover_text_from_name_kind(db, name_kind, &mut _b));
173 ast::StructDef(it) => {
174 hover_text(it.doc_comment_text(), it.short_label())
175 },
176 ast::EnumDef(it) => {
177 hover_text(it.doc_comment_text(), it.short_label())
178 },
179 ast::EnumVariant(it) => {
180 hover_text(it.doc_comment_text(), it.short_label())
181 },
182 ast::FnDef(it) => {
183 hover_text(it.doc_comment_text(), it.short_label())
184 },
185 ast::TypeAliasDef(it) => {
186 hover_text(it.doc_comment_text(), it.short_label())
187 },
188 ast::ConstDef(it) => {
189 hover_text(it.doc_comment_text(), it.short_label())
190 },
191 ast::StaticDef(it) => {
192 hover_text(it.doc_comment_text(), it.short_label())
193 },
194 ast::TraitDef(it) => {
195 hover_text(it.doc_comment_text(), it.short_label())
196 },
197 ast::RecordFieldDef(it) => {
198 hover_text(it.doc_comment_text(), it.short_label())
199 },
200 ast::Module(it) => {
201 hover_text(it.doc_comment_text(), it.short_label())
202 },
203 ast::MacroCall(it) => {
204 hover_text(it.doc_comment_text(), None)
205 },
206 _ => None,
207 }
208 };
209 res.extend(text);
210 } 198 }
211 199
212 if !res.is_empty() && range.is_none() { 200 if !res.is_empty() {
213 range = Some(name.syntax().text_range()); 201 Some(name.syntax().text_range())
202 } else {
203 None
214 } 204 }
215 } 205 } else {
206 None
207 };
216 208
217 if range.is_none() { 209 if range.is_none() {
218 let node = ancestors_at_offset(file.syntax(), position.offset).find(|n| { 210 let node = ancestors_at_offset(file.syntax(), position.offset).find(|n| {
@@ -221,23 +213,13 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
221 let frange = FileRange { file_id: position.file_id, range: node.text_range() }; 213 let frange = FileRange { file_id: position.file_id, range: node.text_range() };
222 res.extend(type_of(db, frange).map(rust_code_markup)); 214 res.extend(type_of(db, frange).map(rust_code_markup));
223 range = Some(node.text_range()); 215 range = Some(node.text_range());
224 } 216 };
225 217
226 let range = range?; 218 let range = range?;
227 if res.is_empty() { 219 if res.is_empty() {
228 return None; 220 return None;
229 } 221 }
230 let res = RangeInfo::new(range, res); 222 Some(RangeInfo::new(range, res))
231 return Some(res);
232
233 fn from_def_source<A, D>(db: &RootDatabase, def: D) -> Option<String>
234 where
235 D: HasSource<Ast = A>,
236 A: ast::DocCommentsOwner + ast::NameOwner + ShortLabel,
237 {
238 let src = def.source(db);
239 hover_text(src.ast.doc_comment_text(), src.ast.short_label())
240 }
241} 223}
242 224
243pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> { 225pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> {
diff --git a/crates/ra_ide_api/src/inlay_hints.rs b/crates/ra_ide_api/src/inlay_hints.rs
index f1c0dc164..2ff10b89a 100644
--- a/crates/ra_ide_api/src/inlay_hints.rs
+++ b/crates/ra_ide_api/src/inlay_hints.rs
@@ -214,58 +214,60 @@ fn main() {
214}"#, 214}"#,
215 ); 215 );
216 216
217 assert_debug_snapshot!(analysis.inlay_hints(file_id).unwrap(), @r#"[ 217 assert_debug_snapshot!(analysis.inlay_hints(file_id).unwrap(), @r###"
218 InlayHint { 218 [
219 range: [193; 197), 219 InlayHint {
220 kind: TypeHint, 220 range: [193; 197),
221 label: "i32", 221 kind: TypeHint,
222 }, 222 label: "i32",
223 InlayHint { 223 },
224 range: [236; 244), 224 InlayHint {
225 kind: TypeHint, 225 range: [236; 244),
226 label: "i32", 226 kind: TypeHint,
227 }, 227 label: "i32",
228 InlayHint { 228 },
229 range: [275; 279), 229 InlayHint {
230 kind: TypeHint, 230 range: [275; 279),
231 label: "&str", 231 kind: TypeHint,
232 }, 232 label: "&str",
233 InlayHint { 233 },
234 range: [539; 543), 234 InlayHint {
235 kind: TypeHint, 235 range: [539; 543),
236 label: "(i32, char)", 236 kind: TypeHint,
237 }, 237 label: "(i32, char)",
238 InlayHint { 238 },
239 range: [566; 567), 239 InlayHint {
240 kind: TypeHint, 240 range: [566; 567),
241 label: "i32", 241 kind: TypeHint,
242 }, 242 label: "i32",
243 InlayHint { 243 },
244 range: [570; 571), 244 InlayHint {
245 kind: TypeHint, 245 range: [570; 571),
246 label: "i32", 246 kind: TypeHint,
247 }, 247 label: "i32",
248 InlayHint { 248 },
249 range: [573; 574), 249 InlayHint {
250 kind: TypeHint, 250 range: [573; 574),
251 label: "i32", 251 kind: TypeHint,
252 }, 252 label: "i32",
253 InlayHint { 253 },
254 range: [584; 585), 254 InlayHint {
255 kind: TypeHint, 255 range: [584; 585),
256 label: "i32", 256 kind: TypeHint,
257 }, 257 label: "i32",
258 InlayHint { 258 },
259 range: [577; 578), 259 InlayHint {
260 kind: TypeHint, 260 range: [577; 578),
261 label: "f64", 261 kind: TypeHint,
262 }, 262 label: "f64",
263 InlayHint { 263 },
264 range: [580; 581), 264 InlayHint {
265 kind: TypeHint, 265 range: [580; 581),
266 label: "f64", 266 kind: TypeHint,
267 }, 267 label: "f64",
268]"# 268 },
269 ]
270 "###
269 ); 271 );
270 } 272 }
271 273
@@ -281,18 +283,20 @@ fn main() {
281}"#, 283}"#,
282 ); 284 );
283 285
284 assert_debug_snapshot!(analysis.inlay_hints(file_id).unwrap(), @r#"[ 286 assert_debug_snapshot!(analysis.inlay_hints(file_id).unwrap(), @r###"
285 InlayHint { 287 [
286 range: [21; 30), 288 InlayHint {
287 kind: TypeHint, 289 range: [21; 30),
288 label: "i32", 290 kind: TypeHint,
289 }, 291 label: "i32",
290 InlayHint { 292 },
291 range: [57; 66), 293 InlayHint {
292 kind: TypeHint, 294 range: [57; 66),
293 label: "i32", 295 kind: TypeHint,
294 }, 296 label: "i32",
295]"# 297 },
298 ]
299 "###
296 ); 300 );
297 } 301 }
298 302
@@ -308,18 +312,20 @@ fn main() {
308}"#, 312}"#,
309 ); 313 );
310 314
311 assert_debug_snapshot!(analysis.inlay_hints(file_id).unwrap(), @r#"[ 315 assert_debug_snapshot!(analysis.inlay_hints(file_id).unwrap(), @r###"
312 InlayHint { 316 [
313 range: [21; 30), 317 InlayHint {
314 kind: TypeHint, 318 range: [21; 30),
315 label: "i32", 319 kind: TypeHint,
316 }, 320 label: "i32",
317 InlayHint { 321 },
318 range: [44; 53), 322 InlayHint {
319 kind: TypeHint, 323 range: [44; 53),
320 label: "i32", 324 kind: TypeHint,
321 }, 325 label: "i32",
322]"# 326 },
327 ]
328 "###
323 ); 329 );
324 } 330 }
325 331
@@ -354,33 +360,35 @@ fn main() {
354}"#, 360}"#,
355 ); 361 );
356 362
357 assert_debug_snapshot!(analysis.inlay_hints(file_id).unwrap(), @r#"[ 363 assert_debug_snapshot!(analysis.inlay_hints(file_id).unwrap(), @r###"
358 InlayHint { 364 [
359 range: [166; 170), 365 InlayHint {
360 kind: TypeHint, 366 range: [166; 170),
361 label: "CustomOption<Test>", 367 kind: TypeHint,
362 }, 368 label: "CustomOption<Test>",
363 InlayHint { 369 },
364 range: [334; 338), 370 InlayHint {
365 kind: TypeHint, 371 range: [334; 338),
366 label: "&Test", 372 kind: TypeHint,
367 }, 373 label: "&Test",
368 InlayHint { 374 },
369 range: [389; 390), 375 InlayHint {
370 kind: TypeHint, 376 range: [389; 390),
371 label: "&CustomOption<u32>", 377 kind: TypeHint,
372 }, 378 label: "&CustomOption<u32>",
373 InlayHint { 379 },
374 range: [392; 393), 380 InlayHint {
375 kind: TypeHint, 381 range: [392; 393),
376 label: "&u8", 382 kind: TypeHint,
377 }, 383 label: "&u8",
378 InlayHint { 384 },
379 range: [531; 532), 385 InlayHint {
380 kind: TypeHint, 386 range: [531; 532),
381 label: "&u32", 387 kind: TypeHint,
382 }, 388 label: "&u32",
383]"# 389 },
390 ]
391 "###
384 ); 392 );
385 } 393 }
386 394
@@ -416,33 +424,33 @@ fn main() {
416 ); 424 );
417 425
418 assert_debug_snapshot!(analysis.inlay_hints(file_id).unwrap(), @r###" 426 assert_debug_snapshot!(analysis.inlay_hints(file_id).unwrap(), @r###"
419 [ 427 [
420 InlayHint { 428 InlayHint {
421 range: [166; 170), 429 range: [166; 170),
422 kind: TypeHint, 430 kind: TypeHint,
423 label: "CustomOption<Test>", 431 label: "CustomOption<Test>",
424 }, 432 },
425 InlayHint { 433 InlayHint {
426 range: [343; 347), 434 range: [343; 347),
427 kind: TypeHint, 435 kind: TypeHint,
428 label: "&Test", 436 label: "&Test",
429 }, 437 },
430 InlayHint { 438 InlayHint {
431 range: [401; 402), 439 range: [401; 402),
432 kind: TypeHint, 440 kind: TypeHint,
433 label: "&CustomOption<u32>", 441 label: "&CustomOption<u32>",
434 }, 442 },
435 InlayHint { 443 InlayHint {
436 range: [404; 405), 444 range: [404; 405),
437 kind: TypeHint, 445 kind: TypeHint,
438 label: "&u8", 446 label: "&u8",
439 }, 447 },
440 InlayHint { 448 InlayHint {
441 range: [549; 550), 449 range: [549; 550),
442 kind: TypeHint, 450 kind: TypeHint,
443 label: "&u32", 451 label: "&u32",
444 }, 452 },
445 ] 453 ]
446 "### 454 "###
447 ); 455 );
448 } 456 }
@@ -478,28 +486,30 @@ fn main() {
478}"#, 486}"#,
479 ); 487 );
480 488
481 assert_debug_snapshot!(analysis.inlay_hints(file_id).unwrap(), @r#"[ 489 assert_debug_snapshot!(analysis.inlay_hints(file_id).unwrap(), @r###"
482 InlayHint { 490 [
483 range: [311; 315), 491 InlayHint {
484 kind: TypeHint, 492 range: [311; 315),
485 label: "Test", 493 kind: TypeHint,
486 }, 494 label: "Test",
487 InlayHint { 495 },
488 range: [358; 359), 496 InlayHint {
489 kind: TypeHint, 497 range: [358; 359),
490 label: "CustomOption<u32>", 498 kind: TypeHint,
491 }, 499 label: "CustomOption<u32>",
492 InlayHint { 500 },
493 range: [361; 362), 501 InlayHint {
494 kind: TypeHint, 502 range: [361; 362),
495 label: "u8", 503 kind: TypeHint,
496 }, 504 label: "u8",
497 InlayHint { 505 },
498 range: [484; 485), 506 InlayHint {
499 kind: TypeHint, 507 range: [484; 485),
500 label: "u32", 508 kind: TypeHint,
501 }, 509 label: "u32",
502]"# 510 },
511 ]
512 "###
503 ); 513 );
504 } 514 }
505} 515}
diff --git a/crates/ra_ide_api/src/runnables.rs b/crates/ra_ide_api/src/runnables.rs
index 1b5c8deea..366ac8048 100644
--- a/crates/ra_ide_api/src/runnables.rs
+++ b/crates/ra_ide_api/src/runnables.rs
@@ -97,24 +97,26 @@ mod tests {
97 ); 97 );
98 let runnables = analysis.runnables(pos.file_id).unwrap(); 98 let runnables = analysis.runnables(pos.file_id).unwrap();
99 assert_debug_snapshot!(&runnables, 99 assert_debug_snapshot!(&runnables,
100 @r#"[ 100 @r###"
101 Runnable { 101 [
102 range: [1; 21), 102 Runnable {
103 kind: Bin, 103 range: [1; 21),
104 }, 104 kind: Bin,
105 Runnable { 105 },
106 range: [22; 46), 106 Runnable {
107 kind: Test { 107 range: [22; 46),
108 name: "test_foo", 108 kind: Test {
109 }, 109 name: "test_foo",
110 }, 110 },
111 Runnable { 111 },
112 range: [47; 81), 112 Runnable {
113 kind: Test { 113 range: [47; 81),
114 name: "test_foo", 114 kind: Test {
115 }, 115 name: "test_foo",
116 }, 116 },
117]"# 117 },
118 ]
119 "###
118 ); 120 );
119 } 121 }
120 122
@@ -132,20 +134,22 @@ mod tests {
132 ); 134 );
133 let runnables = analysis.runnables(pos.file_id).unwrap(); 135 let runnables = analysis.runnables(pos.file_id).unwrap();
134 assert_debug_snapshot!(&runnables, 136 assert_debug_snapshot!(&runnables,
135 @r#"[ 137 @r###"
136 Runnable { 138 [
137 range: [1; 59), 139 Runnable {
138 kind: TestMod { 140 range: [1; 59),
139 path: "test_mod", 141 kind: TestMod {
140 }, 142 path: "test_mod",
141 }, 143 },
142 Runnable { 144 },
143 range: [28; 57), 145 Runnable {
144 kind: Test { 146 range: [28; 57),
145 name: "test_foo1", 147 kind: Test {
146 }, 148 name: "test_foo1",
147 }, 149 },
148]"# 150 },
151 ]
152 "###
149 ); 153 );
150 } 154 }
151 155
@@ -165,20 +169,22 @@ mod tests {
165 ); 169 );
166 let runnables = analysis.runnables(pos.file_id).unwrap(); 170 let runnables = analysis.runnables(pos.file_id).unwrap();
167 assert_debug_snapshot!(&runnables, 171 assert_debug_snapshot!(&runnables,
168 @r#"[ 172 @r###"
169 Runnable { 173 [
170 range: [23; 85), 174 Runnable {
171 kind: TestMod { 175 range: [23; 85),
172 path: "foo::test_mod", 176 kind: TestMod {
173 }, 177 path: "foo::test_mod",
174 }, 178 },
175 Runnable { 179 },
176 range: [46; 79), 180 Runnable {
177 kind: Test { 181 range: [46; 79),
178 name: "test_foo1", 182 kind: Test {
179 }, 183 name: "test_foo1",
180 }, 184 },
181]"# 185 },
186 ]
187 "###
182 ); 188 );
183 } 189 }
184 190
@@ -200,20 +206,22 @@ mod tests {
200 ); 206 );
201 let runnables = analysis.runnables(pos.file_id).unwrap(); 207 let runnables = analysis.runnables(pos.file_id).unwrap();
202 assert_debug_snapshot!(&runnables, 208 assert_debug_snapshot!(&runnables,
203 @r#"[ 209 @r###"
204 Runnable { 210 [
205 range: [41; 115), 211 Runnable {
206 kind: TestMod { 212 range: [41; 115),
207 path: "foo::bar::test_mod", 213 kind: TestMod {
208 }, 214 path: "foo::bar::test_mod",
209 }, 215 },
210 Runnable { 216 },
211 range: [68; 105), 217 Runnable {
212 kind: Test { 218 range: [68; 105),
213 name: "test_foo1", 219 kind: Test {
214 }, 220 name: "test_foo1",
215 }, 221 },
216]"# 222 },
223 ]
224 "###
217 ); 225 );
218 } 226 }
219 227
diff --git a/crates/ra_mbe/Cargo.toml b/crates/ra_mbe/Cargo.toml
index e8ef2457b..b02e45ee3 100644
--- a/crates/ra_mbe/Cargo.toml
+++ b/crates/ra_mbe/Cargo.toml
@@ -9,7 +9,7 @@ ra_syntax = { path = "../ra_syntax" }
9ra_parser = { path = "../ra_parser" } 9ra_parser = { path = "../ra_parser" }
10tt = { path = "../ra_tt", package = "ra_tt" } 10tt = { path = "../ra_tt", package = "ra_tt" }
11rustc-hash = "1.0.0" 11rustc-hash = "1.0.0"
12smallvec = "0.6.9" 12smallvec = "1.0.0"
13log = "0.4.5" 13log = "0.4.5"
14 14
15[dev-dependencies] 15[dev-dependencies]
diff --git a/crates/ra_prof/Cargo.toml b/crates/ra_prof/Cargo.toml
index bb241258c..751bcdeb8 100644
--- a/crates/ra_prof/Cargo.toml
+++ b/crates/ra_prof/Cargo.toml
@@ -1,19 +1,19 @@
1[package] 1[package]
2edition = "2018" 2edition = "2018"
3name = "ra_prof" 3name = "ra_prof"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6publish = false 6publish = false
7 7
8[dependencies] 8[dependencies]
9once_cell = "1.0.1" 9once_cell = "1.0.1"
10itertools = "0.8.0" 10itertools = "0.8.0"
11backtrace = "0.3.28" 11backtrace = "0.3.28"
12 12
13[target.'cfg(not(target_env = "msvc"))'.dependencies] 13[target.'cfg(not(target_env = "msvc"))'.dependencies]
14jemallocator = { version = "0.3.2", optional = true } 14jemallocator = { version = "0.3.2", optional = true }
15jemalloc-ctl = { version = "0.3.2", optional = true } 15jemalloc-ctl = { version = "0.3.2", optional = true }
16 16
17[features] 17[features]
18jemalloc = [ "jemallocator", "jemalloc-ctl" ] 18jemalloc = [ "jemallocator", "jemalloc-ctl" ]
19cpu_profiler = [] 19cpu_profiler = []
diff --git a/docs/user/assists.md b/docs/user/assists.md
index 303353e74..8da7578e2 100644
--- a/docs/user/assists.md
+++ b/docs/user/assists.md
@@ -150,6 +150,27 @@ use std::collections::HashMap;
150fn process(map: HashMap<String, String>) {} 150fn process(map: HashMap<String, String>) {}
151``` 151```
152 152
153## `add_new`
154
155Adds a new inherent impl for a type.
156
157```rust
158// BEFORE
159struct Ctx<T: Clone> {
160 data: T,┃
161}
162
163// AFTER
164struct Ctx<T: Clone> {
165 data: T,
166}
167
168impl<T: Clone> Ctx<T> {
169 fn new(data: T) -> Self { Self { data } }
170}
171
172```
173
153## `apply_demorgan` 174## `apply_demorgan`
154 175
155Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws). 176Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws).