aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yaml6
-rw-r--r--Cargo.lock46
-rw-r--r--Cargo.toml2
-rw-r--r--crates/expect/Cargo.toml10
-rw-r--r--crates/expect/src/lib.rs348
-rw-r--r--crates/flycheck/src/lib.rs1
-rw-r--r--crates/ra_assists/src/assist_context.rs8
-rw-r--r--crates/ra_assists/src/ast_transform.rs16
-rw-r--r--crates/ra_assists/src/handlers/add_explicit_type.rs2
-rw-r--r--crates/ra_assists/src/handlers/add_function.rs4
-rw-r--r--crates/ra_assists/src/handlers/add_missing_impl_members.rs6
-rw-r--r--crates/ra_assists/src/handlers/add_new.rs2
-rw-r--r--crates/ra_assists/src/handlers/auto_import.rs12
-rw-r--r--crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs10
-rw-r--r--crates/ra_assists/src/handlers/fill_match_arms.rs8
-rw-r--r--crates/ra_assists/src/handlers/fix_visibility.rs24
-rw-r--r--crates/ra_assists/src/handlers/inline_local_variable.rs2
-rw-r--r--crates/ra_assists/src/handlers/reorder_fields.rs4
-rw-r--r--crates/ra_db/src/fixture.rs8
-rw-r--r--crates/ra_db/src/input.rs41
-rw-r--r--crates/ra_db/src/lib.rs2
-rw-r--r--crates/ra_hir/src/code_model.rs32
-rw-r--r--crates/ra_hir/src/db.rs8
-rw-r--r--crates/ra_hir/src/semantics.rs269
-rw-r--r--crates/ra_hir_def/src/item_scope.rs109
-rw-r--r--crates/ra_hir_def/src/item_tree/lower.rs2
-rw-r--r--crates/ra_hir_def/src/resolver.rs8
-rw-r--r--crates/ra_hir_expand/src/builtin_derive.rs2
-rw-r--r--crates/ra_hir_expand/src/diagnostics.rs2
-rw-r--r--crates/ra_hir_expand/src/name.rs2
-rw-r--r--crates/ra_hir_ty/src/autoderef.rs15
-rw-r--r--crates/ra_hir_ty/src/db.rs13
-rw-r--r--crates/ra_hir_ty/src/diagnostics.rs10
-rw-r--r--crates/ra_hir_ty/src/infer/unify.rs55
-rw-r--r--crates/ra_hir_ty/src/lib.rs22
-rw-r--r--crates/ra_hir_ty/src/method_resolution.rs235
-rw-r--r--crates/ra_hir_ty/src/test_db.rs22
-rw-r--r--crates/ra_hir_ty/src/tests.rs29
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs18
-rw-r--r--crates/ra_hir_ty/src/traits.rs16
-rw-r--r--crates/ra_hir_ty/src/traits/chalk.rs10
-rw-r--r--crates/ra_hir_ty/src/traits/chalk/mapping.rs43
-rw-r--r--crates/ra_ide/Cargo.toml1
-rw-r--r--crates/ra_ide/src/call_hierarchy.rs40
-rw-r--r--crates/ra_ide/src/completion.rs12
-rw-r--r--crates/ra_ide/src/completion/complete_keyword.rs6
-rw-r--r--crates/ra_ide/src/completion/completion_context.rs2
-rw-r--r--crates/ra_ide/src/completion/presentation.rs50
-rw-r--r--crates/ra_ide/src/diagnostics.rs42
-rw-r--r--crates/ra_ide/src/display/navigation_target.rs45
-rw-r--r--crates/ra_ide/src/display/structure.rs428
-rw-r--r--crates/ra_ide/src/expand_macro.rs241
-rw-r--r--crates/ra_ide/src/folding_ranges.rs161
-rw-r--r--crates/ra_ide/src/goto_definition.rs1052
-rw-r--r--crates/ra_ide/src/goto_implementation.rs197
-rw-r--r--crates/ra_ide/src/goto_type_definition.rs14
-rw-r--r--crates/ra_ide/src/hover.rs72
-rw-r--r--crates/ra_ide/src/inlay_hints.rs976
-rw-r--r--crates/ra_ide/src/lib.rs6
-rw-r--r--crates/ra_ide/src/mock_analysis.rs24
-rw-r--r--crates/ra_ide/src/references.rs9
-rw-r--r--crates/ra_ide/src/references/rename.rs44
-rw-r--r--crates/ra_ide/src/runnables.rs1036
-rw-r--r--crates/ra_ide/src/ssr.rs14
-rw-r--r--crates/ra_ide/src/syntax_highlighting/tests.rs22
-rw-r--r--crates/ra_ide/test_data/highlight_doctest.html (renamed from crates/ra_ide/src/snapshots/highlight_doctest.html)0
-rw-r--r--crates/ra_ide/test_data/highlight_injection.html (renamed from crates/ra_ide/src/snapshots/highlight_injection.html)0
-rw-r--r--crates/ra_ide/test_data/highlight_strings.html (renamed from crates/ra_ide/src/snapshots/highlight_strings.html)0
-rw-r--r--crates/ra_ide/test_data/highlight_unsafe.html (renamed from crates/ra_ide/src/snapshots/highlight_unsafe.html)0
-rw-r--r--crates/ra_ide/test_data/highlighting.html (renamed from crates/ra_ide/src/snapshots/highlighting.html)0
-rw-r--r--crates/ra_ide/test_data/rainbow_highlighting.html (renamed from crates/ra_ide/src/snapshots/rainbow_highlighting.html)0
-rw-r--r--crates/ra_ide_db/src/change.rs5
-rw-r--r--crates/ra_ide_db/src/imports_locator.rs88
-rw-r--r--crates/ra_ide_db/src/lib.rs8
-rw-r--r--crates/ra_ide_db/src/search.rs12
-rw-r--r--crates/ra_proc_macro_srv/src/tests/mod.rs6
-rw-r--r--crates/ra_proc_macro_srv/src/tests/utils.rs4
-rw-r--r--crates/ra_project_model/src/cargo_workspace.rs17
-rw-r--r--crates/ra_project_model/src/lib.rs13
-rw-r--r--crates/ra_project_model/src/project_json.rs23
-rw-r--r--crates/ra_ssr/Cargo.toml1
-rw-r--r--crates/ra_ssr/src/lib.rs162
-rw-r--r--crates/ra_ssr/src/matching.rs51
-rw-r--r--crates/ra_ssr/src/parsing.rs110
-rw-r--r--crates/ra_ssr/src/replacing.rs6
-rw-r--r--crates/ra_ssr/src/tests.rs212
-rw-r--r--crates/ra_syntax/src/tests.rs100
-rw-r--r--crates/rust-analyzer/Cargo.toml3
-rw-r--r--crates/rust-analyzer/src/bin/args.rs80
-rw-r--r--crates/rust-analyzer/src/bin/main.rs8
-rw-r--r--crates/rust-analyzer/src/cli.rs2
-rw-r--r--crates/rust-analyzer/src/cli/analysis_stats.rs31
-rw-r--r--crates/rust-analyzer/src/cli/ssr.rs71
-rw-r--r--crates/rust-analyzer/src/config.rs2
-rw-r--r--crates/rust-analyzer/src/global_state.rs2
-rw-r--r--crates/rust-analyzer/src/handlers.rs38
-rw-r--r--crates/rust-analyzer/src/lsp_ext.rs8
-rw-r--r--crates/rust-analyzer/src/main_loop.rs42
-rw-r--r--crates/rust-analyzer/src/reload.rs5
-rw-r--r--crates/rust-analyzer/src/to_proto.rs44
-rw-r--r--crates/test_utils/src/lib.rs164
-rw-r--r--crates/vfs/src/file_set.rs2
-rw-r--r--docs/dev/README.md7
-rw-r--r--docs/dev/lsp-extensions.md8
-rw-r--r--editors/code/package-lock.json966
-rw-r--r--editors/code/package.json30
-rw-r--r--editors/code/rollup.config.js3
-rw-r--r--editors/code/rust.tmGrammar.json4
-rw-r--r--editors/code/src/commands.ts4
-rw-r--r--editors/code/src/lsp_ext.ts3
-rw-r--r--editors/code/src/main.ts16
-rw-r--r--editors/code/src/run.ts6
112 files changed, 4407 insertions, 3938 deletions
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index ed9191c49..7f4e75341 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -116,9 +116,9 @@ jobs:
116 - run: npm ci 116 - run: npm ci
117 working-directory: ./editors/code 117 working-directory: ./editors/code
118 118
119 - run: npm audit || { sleep 10 && npm audit; } || { sleep 30 && npm audit; } 119# - run: npm audit || { sleep 10 && npm audit; } || { sleep 30 && npm audit; }
120 if: runner.os == 'Linux' 120# if: runner.os == 'Linux'
121 working-directory: ./editors/code 121# working-directory: ./editors/code
122 122
123 - run: npm run lint 123 - run: npm run lint
124 working-directory: ./editors/code 124 working-directory: ./editors/code
diff --git a/Cargo.lock b/Cargo.lock
index 9e0d0714a..61ae8157a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -52,17 +52,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
52checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" 52checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
53 53
54[[package]] 54[[package]]
55name = "atty"
56version = "0.2.14"
57source = "registry+https://github.com/rust-lang/crates.io-index"
58checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
59dependencies = [
60 "hermit-abi",
61 "libc",
62 "winapi 0.3.9",
63]
64
65[[package]]
66name = "autocfg" 55name = "autocfg"
67version = "1.0.0" 56version = "1.0.0"
68source = "registry+https://github.com/rust-lang/crates.io-index" 57source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -196,18 +185,6 @@ dependencies = [
196] 185]
197 186
198[[package]] 187[[package]]
199name = "clicolors-control"
200version = "1.0.1"
201source = "registry+https://github.com/rust-lang/crates.io-index"
202checksum = "90082ee5dcdd64dc4e9e0d37fbf3ee325419e39c0092191e0393df65518f741e"
203dependencies = [
204 "atty",
205 "lazy_static",
206 "libc",
207 "winapi 0.3.9",
208]
209
210[[package]]
211name = "cloudabi" 188name = "cloudabi"
212version = "0.1.0" 189version = "0.1.0"
213source = "registry+https://github.com/rust-lang/crates.io-index" 190source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -218,11 +195,10 @@ dependencies = [
218 195
219[[package]] 196[[package]]
220name = "console" 197name = "console"
221version = "0.10.3" 198version = "0.11.3"
222source = "registry+https://github.com/rust-lang/crates.io-index" 199source = "registry+https://github.com/rust-lang/crates.io-index"
223checksum = "2586208b33573b7f76ccfbe5adb076394c88deaf81b84d7213969805b0a952a7" 200checksum = "8c0994e656bba7b922d8dd1245db90672ffb701e684e45be58f20719d69abc5a"
224dependencies = [ 201dependencies = [
225 "clicolors-control",
226 "encode_unicode", 202 "encode_unicode",
227 "lazy_static", 203 "lazy_static",
228 "libc", 204 "libc",
@@ -352,6 +328,15 @@ dependencies = [
352] 328]
353 329
354[[package]] 330[[package]]
331name = "expect"
332version = "0.1.0"
333dependencies = [
334 "difference",
335 "once_cell",
336 "stdx",
337]
338
339[[package]]
355name = "filetime" 340name = "filetime"
356version = "0.2.10" 341version = "0.2.10"
357source = "registry+https://github.com/rust-lang/crates.io-index" 342source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -544,9 +529,9 @@ dependencies = [
544 529
545[[package]] 530[[package]]
546name = "insta" 531name = "insta"
547version = "0.16.0" 532version = "0.16.1"
548source = "registry+https://github.com/rust-lang/crates.io-index" 533source = "registry+https://github.com/rust-lang/crates.io-index"
549checksum = "8386e795fb3927131ea4cede203c529a333652eb6dc4ff29616b832b27e9b096" 534checksum = "617e921abc813f96a3b00958c079e7bf1e2db998f8a04f1546dd967373a418ee"
550dependencies = [ 535dependencies = [
551 "console", 536 "console",
552 "difference", 537 "difference",
@@ -1134,6 +1119,7 @@ name = "ra_ide"
1134version = "0.1.0" 1119version = "0.1.0"
1135dependencies = [ 1120dependencies = [
1136 "either", 1121 "either",
1122 "expect",
1137 "indexmap", 1123 "indexmap",
1138 "insta", 1124 "insta",
1139 "itertools", 1125 "itertools",
@@ -1262,6 +1248,7 @@ dependencies = [
1262 "ra_syntax", 1248 "ra_syntax",
1263 "ra_text_edit", 1249 "ra_text_edit",
1264 "rustc-hash", 1250 "rustc-hash",
1251 "test_utils",
1265] 1252]
1266 1253
1267[[package]] 1254[[package]]
@@ -1464,15 +1451,18 @@ dependencies = [
1464 "ra_hir_def", 1451 "ra_hir_def",
1465 "ra_hir_ty", 1452 "ra_hir_ty",
1466 "ra_ide", 1453 "ra_ide",
1454 "ra_ide_db",
1467 "ra_mbe", 1455 "ra_mbe",
1468 "ra_proc_macro_srv", 1456 "ra_proc_macro_srv",
1469 "ra_prof", 1457 "ra_prof",
1470 "ra_project_model", 1458 "ra_project_model",
1459 "ra_ssr",
1471 "ra_syntax", 1460 "ra_syntax",
1472 "ra_text_edit", 1461 "ra_text_edit",
1473 "ra_toolchain", 1462 "ra_toolchain",
1474 "ra_tt", 1463 "ra_tt",
1475 "rand", 1464 "rand",
1465 "rayon",
1476 "rustc-hash", 1466 "rustc-hash",
1477 "serde", 1467 "serde",
1478 "serde_json", 1468 "serde_json",
diff --git a/Cargo.toml b/Cargo.toml
index 5278b5a16..189f4ea2b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -24,6 +24,8 @@ opt-level = 0
24opt-level = 0 24opt-level = 0
25[profile.release.package.salsa-macros] 25[profile.release.package.salsa-macros]
26opt-level = 0 26opt-level = 0
27[profile.release.package.tracing-attributes]
28opt-level = 0
27[profile.release.package.xtask] 29[profile.release.package.xtask]
28opt-level = 0 30opt-level = 0
29 31
diff --git a/crates/expect/Cargo.toml b/crates/expect/Cargo.toml
new file mode 100644
index 000000000..caee43106
--- /dev/null
+++ b/crates/expect/Cargo.toml
@@ -0,0 +1,10 @@
1[package]
2name = "expect"
3version = "0.1.0"
4authors = ["rust-analyzer developers"]
5edition = "2018"
6
7[dependencies]
8once_cell = "1"
9difference = "2"
10stdx = { path = "../stdx" }
diff --git a/crates/expect/src/lib.rs b/crates/expect/src/lib.rs
new file mode 100644
index 000000000..a5e26fade
--- /dev/null
+++ b/crates/expect/src/lib.rs
@@ -0,0 +1,348 @@
1//! Snapshot testing library, see
2//! https://github.com/rust-analyzer/rust-analyzer/pull/5101
3use std::{
4 collections::HashMap,
5 env, fmt, fs, mem,
6 ops::Range,
7 panic,
8 path::{Path, PathBuf},
9 sync::Mutex,
10};
11
12use difference::Changeset;
13use once_cell::sync::Lazy;
14use stdx::{lines_with_ends, trim_indent};
15
16const HELP: &str = "
17You can update all `expect![[]]` tests by running:
18
19 env UPDATE_EXPECT=1 cargo test
20
21To update a single test, place the cursor on `expect` token and use `run` feature of rust-analyzer.
22";
23
24fn update_expect() -> bool {
25 env::var("UPDATE_EXPECT").is_ok()
26}
27
28/// expect![[r#"inline snapshot"#]]
29#[macro_export]
30macro_rules! expect {
31 [[$data:literal]] => {$crate::Expect {
32 position: $crate::Position {
33 file: file!(),
34 line: line!(),
35 column: column!(),
36 },
37 data: $data,
38 }};
39 [[]] => { $crate::expect![[""]] };
40}
41
42/// expect_file!["/crates/foo/test_data/bar.html"]
43#[macro_export]
44macro_rules! expect_file {
45 [$path:literal] => {$crate::ExpectFile { path: $path }};
46}
47
48#[derive(Debug)]
49pub struct Expect {
50 pub position: Position,
51 pub data: &'static str,
52}
53
54#[derive(Debug)]
55pub struct ExpectFile {
56 pub path: &'static str,
57}
58
59#[derive(Debug)]
60pub struct Position {
61 pub file: &'static str,
62 pub line: u32,
63 pub column: u32,
64}
65
66impl fmt::Display for Position {
67 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68 write!(f, "{}:{}:{}", self.file, self.line, self.column)
69 }
70}
71
72impl Expect {
73 pub fn assert_eq(&self, actual: &str) {
74 let trimmed = self.trimmed();
75 if &trimmed == actual {
76 return;
77 }
78 Runtime::fail_expect(self, &trimmed, actual);
79 }
80 pub fn assert_debug_eq(&self, actual: &impl fmt::Debug) {
81 let actual = format!("{:#?}\n", actual);
82 self.assert_eq(&actual)
83 }
84
85 fn trimmed(&self) -> String {
86 if !self.data.contains('\n') {
87 return self.data.to_string();
88 }
89 trim_indent(self.data)
90 }
91
92 fn locate(&self, file: &str) -> Location {
93 let mut target_line = None;
94 let mut line_start = 0;
95 for (i, line) in lines_with_ends(file).enumerate() {
96 if i == self.position.line as usize - 1 {
97 let pat = "expect![[";
98 let offset = line.find(pat).unwrap();
99 let literal_start = line_start + offset + pat.len();
100 let indent = line.chars().take_while(|&it| it == ' ').count();
101 target_line = Some((literal_start, indent));
102 break;
103 }
104 line_start += line.len();
105 }
106 let (literal_start, line_indent) = target_line.unwrap();
107 let literal_length =
108 file[literal_start..].find("]]").expect("Couldn't find matching `]]` for `expect![[`.");
109 let literal_range = literal_start..literal_start + literal_length;
110 Location { line_indent, literal_range }
111 }
112}
113
114impl ExpectFile {
115 pub fn assert_eq(&self, actual: &str) {
116 let expected = self.read();
117 if actual == expected {
118 return;
119 }
120 Runtime::fail_file(self, &expected, actual);
121 }
122 fn read(&self) -> String {
123 fs::read_to_string(self.abs_path()).unwrap_or_default().replace("\r\n", "\n")
124 }
125 fn write(&self, contents: &str) {
126 fs::write(self.abs_path(), contents).unwrap()
127 }
128 fn abs_path(&self) -> PathBuf {
129 workspace_root().join(self.path)
130 }
131}
132
133#[derive(Default)]
134struct Runtime {
135 help_printed: bool,
136 per_file: HashMap<&'static str, FileRuntime>,
137}
138static RT: Lazy<Mutex<Runtime>> = Lazy::new(Default::default);
139
140impl Runtime {
141 fn fail_expect(expect: &Expect, expected: &str, actual: &str) {
142 let mut rt = RT.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
143 if update_expect() {
144 println!("\x1b[1m\x1b[92mupdating\x1b[0m: {}", expect.position);
145 rt.per_file
146 .entry(expect.position.file)
147 .or_insert_with(|| FileRuntime::new(expect))
148 .update(expect, actual);
149 return;
150 }
151 rt.panic(expect.position.to_string(), expected, actual);
152 }
153
154 fn fail_file(expect: &ExpectFile, expected: &str, actual: &str) {
155 let mut rt = RT.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
156 if update_expect() {
157 println!("\x1b[1m\x1b[92mupdating\x1b[0m: {}", expect.path);
158 expect.write(actual);
159 return;
160 }
161 rt.panic(expect.path.to_string(), expected, actual);
162 }
163
164 fn panic(&mut self, position: String, expected: &str, actual: &str) {
165 let print_help = !mem::replace(&mut self.help_printed, true);
166 let help = if print_help { HELP } else { "" };
167
168 let diff = Changeset::new(actual, expected, "\n");
169
170 println!(
171 "\n
172\x1b[1m\x1b[91merror\x1b[97m: expect test failed\x1b[0m
173 \x1b[1m\x1b[34m-->\x1b[0m {}
174{}
175\x1b[1mExpect\x1b[0m:
176----
177{}
178----
179
180\x1b[1mActual\x1b[0m:
181----
182{}
183----
184
185\x1b[1mDiff\x1b[0m:
186----
187{}
188----
189",
190 position, help, expected, actual, diff
191 );
192 // Use resume_unwind instead of panic!() to prevent a backtrace, which is unnecessary noise.
193 panic::resume_unwind(Box::new(()));
194 }
195}
196
197struct FileRuntime {
198 path: PathBuf,
199 original_text: String,
200 patchwork: Patchwork,
201}
202
203impl FileRuntime {
204 fn new(expect: &Expect) -> FileRuntime {
205 let path = workspace_root().join(expect.position.file);
206 let original_text = fs::read_to_string(&path).unwrap();
207 let patchwork = Patchwork::new(original_text.clone());
208 FileRuntime { path, original_text, patchwork }
209 }
210 fn update(&mut self, expect: &Expect, actual: &str) {
211 let loc = expect.locate(&self.original_text);
212 let patch = format_patch(loc.line_indent.clone(), actual);
213 self.patchwork.patch(loc.literal_range, &patch);
214 fs::write(&self.path, &self.patchwork.text).unwrap()
215 }
216}
217
218#[derive(Debug)]
219struct Location {
220 line_indent: usize,
221 literal_range: Range<usize>,
222}
223
224#[derive(Debug)]
225struct Patchwork {
226 text: String,
227 indels: Vec<(Range<usize>, usize)>,
228}
229
230impl Patchwork {
231 fn new(text: String) -> Patchwork {
232 Patchwork { text, indels: Vec::new() }
233 }
234 fn patch(&mut self, mut range: Range<usize>, patch: &str) {
235 self.indels.push((range.clone(), patch.len()));
236 self.indels.sort_by_key(|(delete, _insert)| delete.start);
237
238 let (delete, insert) = self
239 .indels
240 .iter()
241 .take_while(|(delete, _)| delete.start < range.start)
242 .map(|(delete, insert)| (delete.end - delete.start, insert))
243 .fold((0usize, 0usize), |(x1, y1), (x2, y2)| (x1 + x2, y1 + y2));
244
245 for pos in &mut [&mut range.start, &mut range.end] {
246 **pos -= delete;
247 **pos += insert;
248 }
249
250 self.text.replace_range(range, &patch);
251 }
252}
253
254fn format_patch(line_indent: usize, patch: &str) -> String {
255 let mut max_hashes = 0;
256 let mut cur_hashes = 0;
257 for byte in patch.bytes() {
258 if byte != b'#' {
259 cur_hashes = 0;
260 continue;
261 }
262 cur_hashes += 1;
263 max_hashes = max_hashes.max(cur_hashes);
264 }
265 let hashes = &"#".repeat(max_hashes + 1);
266 let indent = &" ".repeat(line_indent);
267 let is_multiline = patch.contains('\n');
268
269 let mut buf = String::new();
270 buf.push('r');
271 buf.push_str(hashes);
272 buf.push('"');
273 if is_multiline {
274 buf.push('\n');
275 }
276 let mut final_newline = false;
277 for line in lines_with_ends(patch) {
278 if is_multiline {
279 buf.push_str(indent);
280 buf.push_str(" ");
281 }
282 buf.push_str(line);
283 final_newline = line.ends_with('\n');
284 }
285 if final_newline {
286 buf.push_str(indent);
287 }
288 buf.push('"');
289 buf.push_str(hashes);
290 buf
291}
292
293fn workspace_root() -> PathBuf {
294 Path::new(
295 &env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| env!("CARGO_MANIFEST_DIR").to_owned()),
296 )
297 .ancestors()
298 .nth(2)
299 .unwrap()
300 .to_path_buf()
301}
302
303#[cfg(test)]
304mod tests {
305 use super::*;
306
307 #[test]
308 fn test_format_patch() {
309 let patch = format_patch(0, "hello\nworld\n");
310 expect![[r##"
311 r#"
312 hello
313 world
314 "#"##]]
315 .assert_eq(&patch);
316
317 let patch = format_patch(4, "single line");
318 expect![[r##"r#"single line"#"##]].assert_eq(&patch);
319 }
320
321 #[test]
322 fn test_patchwork() {
323 let mut patchwork = Patchwork::new("one two three".to_string());
324 patchwork.patch(4..7, "zwei");
325 patchwork.patch(0..3, "один");
326 patchwork.patch(8..13, "3");
327 expect![[r#"
328 Patchwork {
329 text: "один zwei 3",
330 indels: [
331 (
332 0..3,
333 8,
334 ),
335 (
336 4..7,
337 4,
338 ),
339 (
340 8..13,
341 1,
342 ),
343 ],
344 }
345 "#]]
346 .assert_debug_eq(&patchwork);
347 }
348}
diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs
index 1023d3040..844b093d4 100644
--- a/crates/flycheck/src/lib.rs
+++ b/crates/flycheck/src/lib.rs
@@ -132,6 +132,7 @@ impl FlycheckActor {
132 self.cancel_check_process(); 132 self.cancel_check_process();
133 133
134 let mut command = self.check_command(); 134 let mut command = self.check_command();
135 log::info!("restart flycheck {:?}", command);
135 command.stdout(Stdio::piped()).stderr(Stdio::null()).stdin(Stdio::null()); 136 command.stdout(Stdio::piped()).stderr(Stdio::null()).stdin(Stdio::null());
136 if let Ok(child) = command.spawn().map(JodChild) { 137 if let Ok(child) = command.spawn().map(JodChild) {
137 self.cargo_handle = Some(CargoHandle::spawn(child)); 138 self.cargo_handle = Some(CargoHandle::spawn(child));
diff --git a/crates/ra_assists/src/assist_context.rs b/crates/ra_assists/src/assist_context.rs
index ee614de72..3640bb4d2 100644
--- a/crates/ra_assists/src/assist_context.rs
+++ b/crates/ra_assists/src/assist_context.rs
@@ -55,7 +55,6 @@ use crate::{
55pub(crate) struct AssistContext<'a> { 55pub(crate) struct AssistContext<'a> {
56 pub(crate) config: &'a AssistConfig, 56 pub(crate) config: &'a AssistConfig,
57 pub(crate) sema: Semantics<'a, RootDatabase>, 57 pub(crate) sema: Semantics<'a, RootDatabase>,
58 pub(crate) db: &'a RootDatabase,
59 pub(crate) frange: FileRange, 58 pub(crate) frange: FileRange,
60 source_file: SourceFile, 59 source_file: SourceFile,
61} 60}
@@ -67,8 +66,11 @@ impl<'a> AssistContext<'a> {
67 frange: FileRange, 66 frange: FileRange,
68 ) -> AssistContext<'a> { 67 ) -> AssistContext<'a> {
69 let source_file = sema.parse(frange.file_id); 68 let source_file = sema.parse(frange.file_id);
70 let db = sema.db; 69 AssistContext { config, sema, frange, source_file }
71 AssistContext { config, sema, db, frange, source_file } 70 }
71
72 pub(crate) fn db(&self) -> &RootDatabase {
73 self.sema.db
72 } 74 }
73 75
74 // NB, this ignores active selection. 76 // NB, this ignores active selection.
diff --git a/crates/ra_assists/src/ast_transform.rs b/crates/ra_assists/src/ast_transform.rs
index 00fa95b6c..01adb834c 100644
--- a/crates/ra_assists/src/ast_transform.rs
+++ b/crates/ra_assists/src/ast_transform.rs
@@ -2,7 +2,6 @@
2use rustc_hash::FxHashMap; 2use rustc_hash::FxHashMap;
3 3
4use hir::{HirDisplay, PathResolution, SemanticsScope}; 4use hir::{HirDisplay, PathResolution, SemanticsScope};
5use ra_ide_db::RootDatabase;
6use ra_syntax::{ 5use ra_syntax::{
7 algo::SyntaxRewriter, 6 algo::SyntaxRewriter,
8 ast::{self, AstNode}, 7 ast::{self, AstNode},
@@ -32,14 +31,14 @@ impl<'a> AstTransform<'a> for NullTransformer {
32} 31}
33 32
34pub struct SubstituteTypeParams<'a> { 33pub struct SubstituteTypeParams<'a> {
35 source_scope: &'a SemanticsScope<'a, RootDatabase>, 34 source_scope: &'a SemanticsScope<'a>,
36 substs: FxHashMap<hir::TypeParam, ast::TypeRef>, 35 substs: FxHashMap<hir::TypeParam, ast::TypeRef>,
37 previous: Box<dyn AstTransform<'a> + 'a>, 36 previous: Box<dyn AstTransform<'a> + 'a>,
38} 37}
39 38
40impl<'a> SubstituteTypeParams<'a> { 39impl<'a> SubstituteTypeParams<'a> {
41 pub fn for_trait_impl( 40 pub fn for_trait_impl(
42 source_scope: &'a SemanticsScope<'a, RootDatabase>, 41 source_scope: &'a SemanticsScope<'a>,
43 // FIXME: there's implicit invariant that `trait_` and `source_scope` match... 42 // FIXME: there's implicit invariant that `trait_` and `source_scope` match...
44 trait_: hir::Trait, 43 trait_: hir::Trait,
45 impl_def: ast::ImplDef, 44 impl_def: ast::ImplDef,
@@ -126,16 +125,13 @@ impl<'a> AstTransform<'a> for SubstituteTypeParams<'a> {
126} 125}
127 126
128pub struct QualifyPaths<'a> { 127pub struct QualifyPaths<'a> {
129 target_scope: &'a SemanticsScope<'a, RootDatabase>, 128 target_scope: &'a SemanticsScope<'a>,
130 source_scope: &'a SemanticsScope<'a, RootDatabase>, 129 source_scope: &'a SemanticsScope<'a>,
131 previous: Box<dyn AstTransform<'a> + 'a>, 130 previous: Box<dyn AstTransform<'a> + 'a>,
132} 131}
133 132
134impl<'a> QualifyPaths<'a> { 133impl<'a> QualifyPaths<'a> {
135 pub fn new( 134 pub fn new(target_scope: &'a SemanticsScope<'a>, source_scope: &'a SemanticsScope<'a>) -> Self {
136 target_scope: &'a SemanticsScope<'a, RootDatabase>,
137 source_scope: &'a SemanticsScope<'a, RootDatabase>,
138 ) -> Self {
139 Self { target_scope, source_scope, previous: Box::new(NullTransformer) } 135 Self { target_scope, source_scope, previous: Box::new(NullTransformer) }
140 } 136 }
141 137
@@ -156,7 +152,7 @@ impl<'a> QualifyPaths<'a> {
156 let resolution = self.source_scope.resolve_hir_path(&hir_path?)?; 152 let resolution = self.source_scope.resolve_hir_path(&hir_path?)?;
157 match resolution { 153 match resolution {
158 PathResolution::Def(def) => { 154 PathResolution::Def(def) => {
159 let found_path = from.find_use_path(self.source_scope.db, def)?; 155 let found_path = from.find_use_path(self.source_scope.db.upcast(), def)?;
160 let mut path = path_to_ast(found_path); 156 let mut path = path_to_ast(found_path);
161 157
162 let type_args = p 158 let type_args = p
diff --git a/crates/ra_assists/src/handlers/add_explicit_type.rs b/crates/ra_assists/src/handlers/add_explicit_type.rs
index 90b06a625..11df922a2 100644
--- a/crates/ra_assists/src/handlers/add_explicit_type.rs
+++ b/crates/ra_assists/src/handlers/add_explicit_type.rs
@@ -57,7 +57,7 @@ pub(crate) fn add_explicit_type(acc: &mut Assists, ctx: &AssistContext) -> Optio
57 return None; 57 return None;
58 } 58 }
59 59
60 let inferred_type = ty.display_source_code(ctx.db, module.into()).ok()?; 60 let inferred_type = ty.display_source_code(ctx.db(), module.into()).ok()?;
61 acc.add( 61 acc.add(
62 AssistId("add_explicit_type"), 62 AssistId("add_explicit_type"),
63 format!("Insert explicit type `{}`", inferred_type), 63 format!("Insert explicit type `{}`", inferred_type),
diff --git a/crates/ra_assists/src/handlers/add_function.rs b/crates/ra_assists/src/handlers/add_function.rs
index 1cfbd75aa..fc4e82309 100644
--- a/crates/ra_assists/src/handlers/add_function.rs
+++ b/crates/ra_assists/src/handlers/add_function.rs
@@ -117,7 +117,7 @@ impl FunctionBuilder {
117 let mut file = ctx.frange.file_id; 117 let mut file = ctx.frange.file_id;
118 let target = match &target_module { 118 let target = match &target_module {
119 Some(target_module) => { 119 Some(target_module) => {
120 let module_source = target_module.definition_source(ctx.db); 120 let module_source = target_module.definition_source(ctx.db());
121 let (in_file, target) = next_space_for_fn_in_module(ctx.sema.db, &module_source)?; 121 let (in_file, target) = next_space_for_fn_in_module(ctx.sema.db, &module_source)?;
122 file = in_file; 122 file = in_file;
123 target 123 target
@@ -269,7 +269,7 @@ fn fn_arg_type(
269 return None; 269 return None;
270 } 270 }
271 271
272 if let Ok(rendered) = ty.display_source_code(ctx.db, target_module.into()) { 272 if let Ok(rendered) = ty.display_source_code(ctx.db(), target_module.into()) {
273 Some(rendered) 273 Some(rendered)
274 } else { 274 } else {
275 None 275 None
diff --git a/crates/ra_assists/src/handlers/add_missing_impl_members.rs b/crates/ra_assists/src/handlers/add_missing_impl_members.rs
index abacd4065..77e092f62 100644
--- a/crates/ra_assists/src/handlers/add_missing_impl_members.rs
+++ b/crates/ra_assists/src/handlers/add_missing_impl_members.rs
@@ -128,9 +128,9 @@ fn add_missing_impl_members_inner(
128 let missing_items = get_missing_assoc_items(&ctx.sema, &impl_def) 128 let missing_items = get_missing_assoc_items(&ctx.sema, &impl_def)
129 .iter() 129 .iter()
130 .map(|i| match i { 130 .map(|i| match i {
131 hir::AssocItem::Function(i) => ast::AssocItem::FnDef(i.source(ctx.db).value), 131 hir::AssocItem::Function(i) => ast::AssocItem::FnDef(i.source(ctx.db()).value),
132 hir::AssocItem::TypeAlias(i) => ast::AssocItem::TypeAliasDef(i.source(ctx.db).value), 132 hir::AssocItem::TypeAlias(i) => ast::AssocItem::TypeAliasDef(i.source(ctx.db()).value),
133 hir::AssocItem::Const(i) => ast::AssocItem::ConstDef(i.source(ctx.db).value), 133 hir::AssocItem::Const(i) => ast::AssocItem::ConstDef(i.source(ctx.db()).value),
134 }) 134 })
135 .filter(|t| def_name(&t).is_some()) 135 .filter(|t| def_name(&t).is_some())
136 .filter(|t| match t { 136 .filter(|t| match t {
diff --git a/crates/ra_assists/src/handlers/add_new.rs b/crates/ra_assists/src/handlers/add_new.rs
index 837aa8377..e41b2aa06 100644
--- a/crates/ra_assists/src/handlers/add_new.rs
+++ b/crates/ra_assists/src/handlers/add_new.rs
@@ -122,7 +122,7 @@ fn generate_impl_text(strukt: &ast::StructDef, code: &str) -> String {
122// FIXME: change the new fn checking to a more semantic approach when that's more 122// FIXME: change the new fn checking to a more semantic approach when that's more
123// viable (e.g. we process proc macros, etc) 123// viable (e.g. we process proc macros, etc)
124fn find_struct_impl(ctx: &AssistContext, strukt: &ast::StructDef) -> Option<Option<ast::ImplDef>> { 124fn find_struct_impl(ctx: &AssistContext, strukt: &ast::StructDef) -> Option<Option<ast::ImplDef>> {
125 let db = ctx.db; 125 let db = ctx.db();
126 let module = strukt.syntax().ancestors().find(|node| { 126 let module = strukt.syntax().ancestors().find(|node| {
127 ast::Module::can_cast(node.kind()) || ast::SourceFile::can_cast(node.kind()) 127 ast::Module::can_cast(node.kind()) || ast::SourceFile::can_cast(node.kind())
128 })?; 128 })?;
diff --git a/crates/ra_assists/src/handlers/auto_import.rs b/crates/ra_assists/src/handlers/auto_import.rs
index d1cafa7d9..7b6499a08 100644
--- a/crates/ra_assists/src/handlers/auto_import.rs
+++ b/crates/ra_assists/src/handlers/auto_import.rs
@@ -5,7 +5,7 @@ use hir::{
5 AsAssocItem, AssocItemContainer, ModPath, Module, ModuleDef, PathResolution, Semantics, Trait, 5 AsAssocItem, AssocItemContainer, ModPath, Module, ModuleDef, PathResolution, Semantics, Trait,
6 Type, 6 Type,
7}; 7};
8use ra_ide_db::{imports_locator::ImportsLocator, RootDatabase}; 8use ra_ide_db::{imports_locator, RootDatabase};
9use ra_prof::profile; 9use ra_prof::profile;
10use ra_syntax::{ 10use ra_syntax::{
11 ast::{self, AstNode}, 11 ast::{self, AstNode},
@@ -35,8 +35,8 @@ use crate::{utils::insert_use_statement, AssistContext, AssistId, Assists, Group
35// # pub mod std { pub mod collections { pub struct HashMap { } } } 35// # pub mod std { pub mod collections { pub struct HashMap { } } }
36// ``` 36// ```
37pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 37pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
38 let auto_import_assets = AutoImportAssets::new(&ctx)?; 38 let auto_import_assets = AutoImportAssets::new(ctx)?;
39 let proposed_imports = auto_import_assets.search_for_imports(ctx.db); 39 let proposed_imports = auto_import_assets.search_for_imports(ctx);
40 if proposed_imports.is_empty() { 40 if proposed_imports.is_empty() {
41 return None; 41 return None;
42 } 42 }
@@ -127,11 +127,11 @@ impl AutoImportAssets {
127 GroupLabel(name) 127 GroupLabel(name)
128 } 128 }
129 129
130 fn search_for_imports(&self, db: &RootDatabase) -> BTreeSet<ModPath> { 130 fn search_for_imports(&self, ctx: &AssistContext) -> BTreeSet<ModPath> {
131 let _p = profile("auto_import::search_for_imports"); 131 let _p = profile("auto_import::search_for_imports");
132 let db = ctx.db();
132 let current_crate = self.module_with_name_to_import.krate(); 133 let current_crate = self.module_with_name_to_import.krate();
133 ImportsLocator::new(db, current_crate) 134 imports_locator::find_imports(&ctx.sema, current_crate, &self.get_search_query())
134 .find_imports(&self.get_search_query())
135 .into_iter() 135 .into_iter()
136 .filter_map(|candidate| match &self.import_candidate { 136 .filter_map(|candidate| match &self.import_candidate {
137 ImportCandidate::TraitAssocItem(assoc_item_type, _) => { 137 ImportCandidate::TraitAssocItem(assoc_item_type, _) => {
diff --git a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs
index 43b4584b4..ca19cf198 100644
--- a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -37,15 +37,15 @@ pub(crate) fn extract_struct_from_enum_variant(
37 }; 37 };
38 let variant_name = variant.name()?.to_string(); 38 let variant_name = variant.name()?.to_string();
39 let variant_hir = ctx.sema.to_def(&variant)?; 39 let variant_hir = ctx.sema.to_def(&variant)?;
40 if existing_struct_def(ctx.db, &variant_name, &variant_hir) { 40 if existing_struct_def(ctx.db(), &variant_name, &variant_hir) {
41 return None; 41 return None;
42 } 42 }
43 let enum_ast = variant.parent_enum(); 43 let enum_ast = variant.parent_enum();
44 let visibility = enum_ast.visibility(); 44 let visibility = enum_ast.visibility();
45 let enum_hir = ctx.sema.to_def(&enum_ast)?; 45 let enum_hir = ctx.sema.to_def(&enum_ast)?;
46 let variant_hir_name = variant_hir.name(ctx.db); 46 let variant_hir_name = variant_hir.name(ctx.db());
47 let enum_module_def = ModuleDef::from(enum_hir); 47 let enum_module_def = ModuleDef::from(enum_hir);
48 let current_module = enum_hir.module(ctx.db); 48 let current_module = enum_hir.module(ctx.db());
49 let target = variant.syntax().text_range(); 49 let target = variant.syntax().text_range();
50 acc.add( 50 acc.add(
51 AssistId("extract_struct_from_enum_variant"), 51 AssistId("extract_struct_from_enum_variant"),
@@ -53,7 +53,7 @@ pub(crate) fn extract_struct_from_enum_variant(
53 target, 53 target,
54 |builder| { 54 |builder| {
55 let definition = Definition::ModuleDef(ModuleDef::EnumVariant(variant_hir)); 55 let definition = Definition::ModuleDef(ModuleDef::EnumVariant(variant_hir));
56 let res = definition.find_usages(&ctx.db, None); 56 let res = definition.find_usages(&ctx.sema, None);
57 let start_offset = variant.parent_enum().syntax().text_range().start(); 57 let start_offset = variant.parent_enum().syntax().text_range().start();
58 let mut visited_modules_set = FxHashSet::default(); 58 let mut visited_modules_set = FxHashSet::default();
59 visited_modules_set.insert(current_module); 59 visited_modules_set.insert(current_module);
@@ -101,7 +101,7 @@ fn insert_import(
101 enum_module_def: &ModuleDef, 101 enum_module_def: &ModuleDef,
102 variant_hir_name: &Name, 102 variant_hir_name: &Name,
103) -> Option<()> { 103) -> Option<()> {
104 let db = ctx.db; 104 let db = ctx.db();
105 let mod_path = module.find_use_path(db, enum_module_def.clone()); 105 let mod_path = module.find_use_path(db, enum_module_def.clone());
106 if let Some(mut mod_path) = mod_path { 106 if let Some(mut mod_path) = mod_path {
107 mod_path.segments.pop(); 107 mod_path.segments.pop();
diff --git a/crates/ra_assists/src/handlers/fill_match_arms.rs b/crates/ra_assists/src/handlers/fill_match_arms.rs
index 64270c86f..5b1235682 100644
--- a/crates/ra_assists/src/handlers/fill_match_arms.rs
+++ b/crates/ra_assists/src/handlers/fill_match_arms.rs
@@ -51,11 +51,11 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<
51 let module = ctx.sema.scope(expr.syntax()).module()?; 51 let module = ctx.sema.scope(expr.syntax()).module()?;
52 52
53 let missing_arms: Vec<MatchArm> = if let Some(enum_def) = resolve_enum_def(&ctx.sema, &expr) { 53 let missing_arms: Vec<MatchArm> = if let Some(enum_def) = resolve_enum_def(&ctx.sema, &expr) {
54 let variants = enum_def.variants(ctx.db); 54 let variants = enum_def.variants(ctx.db());
55 55
56 let mut variants = variants 56 let mut variants = variants
57 .into_iter() 57 .into_iter()
58 .filter_map(|variant| build_pat(ctx.db, module, variant)) 58 .filter_map(|variant| build_pat(ctx.db(), module, variant))
59 .filter(|variant_pat| is_variant_missing(&mut arms, variant_pat)) 59 .filter(|variant_pat| is_variant_missing(&mut arms, variant_pat))
60 .map(|pat| make::match_arm(iter::once(pat), make::expr_empty_block())) 60 .map(|pat| make::match_arm(iter::once(pat), make::expr_empty_block()))
61 .collect::<Vec<_>>(); 61 .collect::<Vec<_>>();
@@ -84,11 +84,11 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<
84 // where each tuple represents a proposed match arm. 84 // where each tuple represents a proposed match arm.
85 enum_defs 85 enum_defs
86 .into_iter() 86 .into_iter()
87 .map(|enum_def| enum_def.variants(ctx.db)) 87 .map(|enum_def| enum_def.variants(ctx.db()))
88 .multi_cartesian_product() 88 .multi_cartesian_product()
89 .map(|variants| { 89 .map(|variants| {
90 let patterns = 90 let patterns =
91 variants.into_iter().filter_map(|variant| build_pat(ctx.db, module, variant)); 91 variants.into_iter().filter_map(|variant| build_pat(ctx.db(), module, variant));
92 ast::Pat::from(make::tuple_pat(patterns)) 92 ast::Pat::from(make::tuple_pat(patterns))
93 }) 93 })
94 .filter(|variant_pat| is_variant_missing(&mut arms, variant_pat)) 94 .filter(|variant_pat| is_variant_missing(&mut arms, variant_pat))
diff --git a/crates/ra_assists/src/handlers/fix_visibility.rs b/crates/ra_assists/src/handlers/fix_visibility.rs
index 19d4dac5e..c0f57c329 100644
--- a/crates/ra_assists/src/handlers/fix_visibility.rs
+++ b/crates/ra_assists/src/handlers/fix_visibility.rs
@@ -41,14 +41,14 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext) -> O
41 }; 41 };
42 42
43 let current_module = ctx.sema.scope(&path.syntax()).module()?; 43 let current_module = ctx.sema.scope(&path.syntax()).module()?;
44 let target_module = def.module(ctx.db)?; 44 let target_module = def.module(ctx.db())?;
45 45
46 let vis = target_module.visibility_of(ctx.db, &def)?; 46 let vis = target_module.visibility_of(ctx.db(), &def)?;
47 if vis.is_visible_from(ctx.db, current_module.into()) { 47 if vis.is_visible_from(ctx.db(), current_module.into()) {
48 return None; 48 return None;
49 }; 49 };
50 50
51 let (offset, target, target_file, target_name) = target_data_for_def(ctx.db, def)?; 51 let (offset, target, target_file, target_name) = target_data_for_def(ctx.db(), def)?;
52 52
53 let missing_visibility = 53 let missing_visibility =
54 if current_module.krate() == target_module.krate() { "pub(crate)" } else { "pub" }; 54 if current_module.krate() == target_module.krate() { "pub(crate)" } else { "pub" };
@@ -72,16 +72,16 @@ fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext) ->
72 let (record_field_def, _) = ctx.sema.resolve_record_field(&record_field)?; 72 let (record_field_def, _) = ctx.sema.resolve_record_field(&record_field)?;
73 73
74 let current_module = ctx.sema.scope(record_field.syntax()).module()?; 74 let current_module = ctx.sema.scope(record_field.syntax()).module()?;
75 let visibility = record_field_def.visibility(ctx.db); 75 let visibility = record_field_def.visibility(ctx.db());
76 if visibility.is_visible_from(ctx.db, current_module.into()) { 76 if visibility.is_visible_from(ctx.db(), current_module.into()) {
77 return None; 77 return None;
78 } 78 }
79 79
80 let parent = record_field_def.parent_def(ctx.db); 80 let parent = record_field_def.parent_def(ctx.db());
81 let parent_name = parent.name(ctx.db); 81 let parent_name = parent.name(ctx.db());
82 let target_module = parent.module(ctx.db); 82 let target_module = parent.module(ctx.db());
83 83
84 let in_file_source = record_field_def.source(ctx.db); 84 let in_file_source = record_field_def.source(ctx.db());
85 let (offset, target) = match in_file_source.value { 85 let (offset, target) = match in_file_source.value {
86 hir::FieldSource::Named(it) => { 86 hir::FieldSource::Named(it) => {
87 let s = it.syntax(); 87 let s = it.syntax();
@@ -95,9 +95,9 @@ fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext) ->
95 95
96 let missing_visibility = 96 let missing_visibility =
97 if current_module.krate() == target_module.krate() { "pub(crate)" } else { "pub" }; 97 if current_module.krate() == target_module.krate() { "pub(crate)" } else { "pub" };
98 let target_file = in_file_source.file_id.original_file(ctx.db); 98 let target_file = in_file_source.file_id.original_file(ctx.db());
99 99
100 let target_name = record_field_def.name(ctx.db); 100 let target_name = record_field_def.name(ctx.db());
101 let assist_label = 101 let assist_label =
102 format!("Change visibility of {}.{} to {}", parent_name, target_name, missing_visibility); 102 format!("Change visibility of {}.{} to {}", parent_name, target_name, missing_visibility);
103 103
diff --git a/crates/ra_assists/src/handlers/inline_local_variable.rs b/crates/ra_assists/src/handlers/inline_local_variable.rs
index d26e68847..259839535 100644
--- a/crates/ra_assists/src/handlers/inline_local_variable.rs
+++ b/crates/ra_assists/src/handlers/inline_local_variable.rs
@@ -44,7 +44,7 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> O
44 44
45 let def = ctx.sema.to_def(&bind_pat)?; 45 let def = ctx.sema.to_def(&bind_pat)?;
46 let def = Definition::Local(def); 46 let def = Definition::Local(def);
47 let refs = def.find_usages(ctx.db, None); 47 let refs = def.find_usages(&ctx.sema, None);
48 if refs.is_empty() { 48 if refs.is_empty() {
49 mark::hit!(test_not_applicable_if_variable_unused); 49 mark::hit!(test_not_applicable_if_variable_unused);
50 return None; 50 return None;
diff --git a/crates/ra_assists/src/handlers/reorder_fields.rs b/crates/ra_assists/src/handlers/reorder_fields.rs
index bc58ce5fe..b8cf30e7f 100644
--- a/crates/ra_assists/src/handlers/reorder_fields.rs
+++ b/crates/ra_assists/src/handlers/reorder_fields.rs
@@ -90,10 +90,10 @@ fn struct_definition(path: &ast::Path, sema: &Semantics<RootDatabase>) -> Option
90fn compute_fields_ranks(path: &ast::Path, ctx: &AssistContext) -> Option<FxHashMap<String, usize>> { 90fn compute_fields_ranks(path: &ast::Path, ctx: &AssistContext) -> Option<FxHashMap<String, usize>> {
91 Some( 91 Some(
92 struct_definition(path, &ctx.sema)? 92 struct_definition(path, &ctx.sema)?
93 .fields(ctx.db) 93 .fields(ctx.db())
94 .iter() 94 .iter()
95 .enumerate() 95 .enumerate()
96 .map(|(idx, field)| (field.name(ctx.db).to_string(), idx)) 96 .map(|(idx, field)| (field.name(ctx.db()).to_string(), idx))
97 .collect(), 97 .collect(),
98 ) 98 )
99} 99}
diff --git a/crates/ra_db/src/fixture.rs b/crates/ra_db/src/fixture.rs
index 4f4fb4494..209713987 100644
--- a/crates/ra_db/src/fixture.rs
+++ b/crates/ra_db/src/fixture.rs
@@ -149,15 +149,17 @@ fn with_files(
149 let crate_id = crate_graph.add_crate_root( 149 let crate_id = crate_graph.add_crate_root(
150 file_id, 150 file_id,
151 meta.edition, 151 meta.edition,
152 Some(CrateName::new(&krate).unwrap()), 152 Some(krate.clone()),
153 meta.cfg, 153 meta.cfg,
154 meta.env, 154 meta.env,
155 Default::default(), 155 Default::default(),
156 ); 156 );
157 let prev = crates.insert(krate.clone(), crate_id); 157 let crate_name = CrateName::new(&krate).unwrap();
158 let prev = crates.insert(crate_name.clone(), crate_id);
158 assert!(prev.is_none()); 159 assert!(prev.is_none());
159 for dep in meta.deps { 160 for dep in meta.deps {
160 crate_deps.push((krate.clone(), dep)) 161 let dep = CrateName::new(&dep).unwrap();
162 crate_deps.push((crate_name.clone(), dep))
161 } 163 }
162 } else if meta.path == "/main.rs" || meta.path == "/lib.rs" { 164 } else if meta.path == "/main.rs" || meta.path == "/lib.rs" {
163 assert!(default_crate_root.is_none()); 165 assert!(default_crate_root.is_none());
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs
index 7f3660118..aaa492759 100644
--- a/crates/ra_db/src/input.rs
+++ b/crates/ra_db/src/input.rs
@@ -67,7 +67,7 @@ pub struct CrateGraph {
67#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 67#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
68pub struct CrateId(pub u32); 68pub struct CrateId(pub u32);
69 69
70#[derive(Debug, Clone, PartialEq, Eq)] 70#[derive(Debug, Clone, PartialEq, Eq, Hash)]
71pub struct CrateName(SmolStr); 71pub struct CrateName(SmolStr);
72 72
73impl CrateName { 73impl CrateName {
@@ -94,6 +94,13 @@ impl fmt::Display for CrateName {
94 } 94 }
95} 95}
96 96
97impl ops::Deref for CrateName {
98 type Target = str;
99 fn deref(&self) -> &Self::Target {
100 &*self.0
101 }
102}
103
97#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 104#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
98pub struct ProcMacroId(pub u32); 105pub struct ProcMacroId(pub u32);
99 106
@@ -117,7 +124,7 @@ pub struct CrateData {
117 /// The name to display to the end user. 124 /// The name to display to the end user.
118 /// This actual crate name can be different in a particular dependent crate 125 /// This actual crate name can be different in a particular dependent crate
119 /// or may even be missing for some cases, such as a dummy crate for the code snippet. 126 /// or may even be missing for some cases, such as a dummy crate for the code snippet.
120 pub display_name: Option<CrateName>, 127 pub display_name: Option<String>,
121 pub cfg_options: CfgOptions, 128 pub cfg_options: CfgOptions,
122 pub env: Env, 129 pub env: Env,
123 pub dependencies: Vec<Dependency>, 130 pub dependencies: Vec<Dependency>,
@@ -138,7 +145,7 @@ pub struct Env {
138#[derive(Debug, Clone, PartialEq, Eq)] 145#[derive(Debug, Clone, PartialEq, Eq)]
139pub struct Dependency { 146pub struct Dependency {
140 pub crate_id: CrateId, 147 pub crate_id: CrateId,
141 pub name: SmolStr, 148 pub name: CrateName,
142} 149}
143 150
144impl CrateGraph { 151impl CrateGraph {
@@ -146,7 +153,7 @@ impl CrateGraph {
146 &mut self, 153 &mut self,
147 file_id: FileId, 154 file_id: FileId,
148 edition: Edition, 155 edition: Edition,
149 display_name: Option<CrateName>, 156 display_name: Option<String>,
150 cfg_options: CfgOptions, 157 cfg_options: CfgOptions,
151 env: Env, 158 env: Env,
152 proc_macro: Vec<(SmolStr, Arc<dyn ra_tt::TokenExpander>)>, 159 proc_macro: Vec<(SmolStr, Arc<dyn ra_tt::TokenExpander>)>,
@@ -178,7 +185,7 @@ impl CrateGraph {
178 if self.dfs_find(from, to, &mut FxHashSet::default()) { 185 if self.dfs_find(from, to, &mut FxHashSet::default()) {
179 return Err(CyclicDependenciesError); 186 return Err(CyclicDependenciesError);
180 } 187 }
181 self.arena.get_mut(&from).unwrap().add_dep(name.0, to); 188 self.arena.get_mut(&from).unwrap().add_dep(name, to);
182 Ok(()) 189 Ok(())
183 } 190 }
184 191
@@ -190,6 +197,23 @@ impl CrateGraph {
190 self.arena.keys().copied() 197 self.arena.keys().copied()
191 } 198 }
192 199
200 /// Returns an iterator over all transitive dependencies of the given crate.
201 pub fn transitive_deps(&self, of: CrateId) -> impl Iterator<Item = CrateId> + '_ {
202 let mut worklist = vec![of];
203 let mut deps = FxHashSet::default();
204
205 while let Some(krate) = worklist.pop() {
206 if !deps.insert(krate) {
207 continue;
208 }
209
210 worklist.extend(self[krate].dependencies.iter().map(|dep| dep.crate_id));
211 }
212
213 deps.remove(&of);
214 deps.into_iter()
215 }
216
193 // FIXME: this only finds one crate with the given root; we could have multiple 217 // FIXME: this only finds one crate with the given root; we could have multiple
194 pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> { 218 pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> {
195 let (&crate_id, _) = 219 let (&crate_id, _) =
@@ -247,7 +271,7 @@ impl CrateId {
247} 271}
248 272
249impl CrateData { 273impl CrateData {
250 fn add_dep(&mut self, name: SmolStr, crate_id: CrateId) { 274 fn add_dep(&mut self, name: CrateName, crate_id: CrateId) {
251 self.dependencies.push(Dependency { name, crate_id }) 275 self.dependencies.push(Dependency { name, crate_id })
252 } 276 }
253} 277}
@@ -429,7 +453,10 @@ mod tests {
429 .is_ok()); 453 .is_ok());
430 assert_eq!( 454 assert_eq!(
431 graph[crate1].dependencies, 455 graph[crate1].dependencies,
432 vec![Dependency { crate_id: crate2, name: "crate_name_with_dashes".into() }] 456 vec![Dependency {
457 crate_id: crate2,
458 name: CrateName::new("crate_name_with_dashes").unwrap()
459 }]
433 ); 460 );
434 } 461 }
435} 462}
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs
index 4a3ba57da..1ddacc1f6 100644
--- a/crates/ra_db/src/lib.rs
+++ b/crates/ra_db/src/lib.rs
@@ -80,7 +80,7 @@ pub struct FilePosition {
80 pub offset: TextSize, 80 pub offset: TextSize,
81} 81}
82 82
83#[derive(Clone, Copy, Debug)] 83#[derive(Clone, Copy, Debug, Eq, PartialEq)]
84pub struct FileRange { 84pub struct FileRange {
85 pub file_id: FileId, 85 pub file_id: FileId,
86 pub range: TextRange, 86 pub range: TextRange,
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index e86077dd6..1b3525011 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -31,7 +31,7 @@ use hir_ty::{
31 ApplicationTy, Canonical, GenericPredicate, InEnvironment, Substs, TraitEnvironment, Ty, 31 ApplicationTy, Canonical, GenericPredicate, InEnvironment, Substs, TraitEnvironment, Ty,
32 TyDefId, TypeCtor, 32 TyDefId, TypeCtor,
33}; 33};
34use ra_db::{CrateId, CrateName, Edition, FileId}; 34use ra_db::{CrateId, Edition, FileId};
35use ra_prof::profile; 35use ra_prof::profile;
36use ra_syntax::ast::{self, AttrsOwner, NameOwner}; 36use ra_syntax::ast::{self, AttrsOwner, NameOwner};
37use rustc_hash::FxHashSet; 37use rustc_hash::FxHashSet;
@@ -94,8 +94,8 @@ impl Crate {
94 db.crate_graph()[self.id].edition 94 db.crate_graph()[self.id].edition
95 } 95 }
96 96
97 pub fn display_name(self, db: &dyn HirDatabase) -> Option<CrateName> { 97 pub fn display_name(self, db: &dyn HirDatabase) -> Option<String> {
98 db.crate_graph()[self.id].display_name.as_ref().cloned() 98 db.crate_graph()[self.id].display_name.clone()
99 } 99 }
100 100
101 pub fn query_external_importables( 101 pub fn query_external_importables(
@@ -1053,12 +1053,14 @@ pub struct ImplDef {
1053 1053
1054impl ImplDef { 1054impl ImplDef {
1055 pub fn all_in_crate(db: &dyn HirDatabase, krate: Crate) -> Vec<ImplDef> { 1055 pub fn all_in_crate(db: &dyn HirDatabase, krate: Crate) -> Vec<ImplDef> {
1056 let impls = db.impls_in_crate(krate.id); 1056 let inherent = db.inherent_impls_in_crate(krate.id);
1057 impls.all_impls().map(Self::from).collect() 1057 let trait_ = db.trait_impls_in_crate(krate.id);
1058
1059 inherent.all_impls().chain(trait_.all_impls()).map(Self::from).collect()
1058 } 1060 }
1059 pub fn for_trait(db: &dyn HirDatabase, krate: Crate, trait_: Trait) -> Vec<ImplDef> { 1061 pub fn for_trait(db: &dyn HirDatabase, krate: Crate, trait_: Trait) -> Vec<ImplDef> {
1060 let impls = db.impls_in_crate(krate.id); 1062 let impls = db.trait_impls_in_crate(krate.id);
1061 impls.lookup_impl_defs_for_trait(trait_.id).map(Self::from).collect() 1063 impls.for_trait(trait_.id).map(Self::from).collect()
1062 } 1064 }
1063 1065
1064 pub fn target_trait(self, db: &dyn HirDatabase) -> Option<TypeRef> { 1066 pub fn target_trait(self, db: &dyn HirDatabase) -> Option<TypeRef> {
@@ -1187,7 +1189,7 @@ impl Type {
1187 None => return false, 1189 None => return false,
1188 }; 1190 };
1189 1191
1190 let canonical_ty = Canonical { value: self.ty.value.clone(), num_vars: 0 }; 1192 let canonical_ty = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) };
1191 method_resolution::implements_trait( 1193 method_resolution::implements_trait(
1192 &canonical_ty, 1194 &canonical_ty,
1193 db, 1195 db,
@@ -1211,7 +1213,7 @@ impl Type {
1211 self.ty.environment.clone(), 1213 self.ty.environment.clone(),
1212 hir_ty::Obligation::Trait(trait_ref), 1214 hir_ty::Obligation::Trait(trait_ref),
1213 ), 1215 ),
1214 num_vars: 0, 1216 kinds: Arc::new([]),
1215 }; 1217 };
1216 1218
1217 db.trait_solve(self.krate, goal).is_some() 1219 db.trait_solve(self.krate, goal).is_some()
@@ -1286,7 +1288,7 @@ impl Type {
1286 pub fn autoderef<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Type> + 'a { 1288 pub fn autoderef<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Type> + 'a {
1287 // There should be no inference vars in types passed here 1289 // There should be no inference vars in types passed here
1288 // FIXME check that? 1290 // FIXME check that?
1289 let canonical = Canonical { value: self.ty.value.clone(), num_vars: 0 }; 1291 let canonical = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) };
1290 let environment = self.ty.environment.clone(); 1292 let environment = self.ty.environment.clone();
1291 let ty = InEnvironment { value: canonical, environment }; 1293 let ty = InEnvironment { value: canonical, environment };
1292 autoderef(db, Some(self.krate), ty) 1294 autoderef(db, Some(self.krate), ty)
@@ -1303,10 +1305,10 @@ impl Type {
1303 mut callback: impl FnMut(AssocItem) -> Option<T>, 1305 mut callback: impl FnMut(AssocItem) -> Option<T>,
1304 ) -> Option<T> { 1306 ) -> Option<T> {
1305 for krate in self.ty.value.def_crates(db, krate.id)? { 1307 for krate in self.ty.value.def_crates(db, krate.id)? {
1306 let impls = db.impls_in_crate(krate); 1308 let impls = db.inherent_impls_in_crate(krate);
1307 1309
1308 for impl_def in impls.lookup_impl_defs(&self.ty.value) { 1310 for impl_def in impls.for_self_ty(&self.ty.value) {
1309 for &item in db.impl_data(impl_def).items.iter() { 1311 for &item in db.impl_data(*impl_def).items.iter() {
1310 if let Some(result) = callback(item.into()) { 1312 if let Some(result) = callback(item.into()) {
1311 return Some(result); 1313 return Some(result);
1312 } 1314 }
@@ -1327,7 +1329,7 @@ impl Type {
1327 // There should be no inference vars in types passed here 1329 // There should be no inference vars in types passed here
1328 // FIXME check that? 1330 // FIXME check that?
1329 // FIXME replace Unknown by bound vars here 1331 // FIXME replace Unknown by bound vars here
1330 let canonical = Canonical { value: self.ty.value.clone(), num_vars: 0 }; 1332 let canonical = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) };
1331 1333
1332 let env = self.ty.environment.clone(); 1334 let env = self.ty.environment.clone();
1333 let krate = krate.id; 1335 let krate = krate.id;
@@ -1358,7 +1360,7 @@ impl Type {
1358 // There should be no inference vars in types passed here 1360 // There should be no inference vars in types passed here
1359 // FIXME check that? 1361 // FIXME check that?
1360 // FIXME replace Unknown by bound vars here 1362 // FIXME replace Unknown by bound vars here
1361 let canonical = Canonical { value: self.ty.value.clone(), num_vars: 0 }; 1363 let canonical = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) };
1362 1364
1363 let env = self.ty.environment.clone(); 1365 let env = self.ty.environment.clone();
1364 let krate = krate.id; 1366 let krate = krate.id;
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index bb67952de..cb48ca065 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -16,10 +16,10 @@ pub use hir_expand::db::{
16pub use hir_ty::db::{ 16pub use hir_ty::db::{
17 AssociatedTyDataQuery, AssociatedTyValueQuery, CallableItemSignatureQuery, FieldTypesQuery, 17 AssociatedTyDataQuery, AssociatedTyValueQuery, CallableItemSignatureQuery, FieldTypesQuery,
18 GenericDefaultsQuery, GenericPredicatesForParamQuery, GenericPredicatesQuery, HirDatabase, 18 GenericDefaultsQuery, GenericPredicatesForParamQuery, GenericPredicatesQuery, HirDatabase,
19 HirDatabaseStorage, ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, ImplsFromDepsQuery, 19 HirDatabaseStorage, ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, InferQueryQuery,
20 ImplsInCrateQuery, InferQueryQuery, InternAssocTyValueQuery, InternChalkImplQuery, 20 InherentImplsInCrateQuery, InternAssocTyValueQuery, InternChalkImplQuery, InternTypeCtorQuery,
21 InternTypeCtorQuery, InternTypeParamIdQuery, ReturnTypeImplTraitsQuery, StructDatumQuery, 21 InternTypeParamIdQuery, ReturnTypeImplTraitsQuery, StructDatumQuery, TraitDatumQuery,
22 TraitDatumQuery, TraitSolveQuery, TyQuery, ValueTyQuery, 22 TraitImplsInCrateQuery, TraitImplsInDepsQuery, TraitSolveQuery, TyQuery, ValueTyQuery,
23}; 23};
24 24
25#[test] 25#[test]
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs
index 6a49c424a..3d78f71c1 100644
--- a/crates/ra_hir/src/semantics.rs
+++ b/crates/ra_hir/src/semantics.rs
@@ -83,6 +83,11 @@ impl PathResolution {
83/// Primary API to get semantic information, like types, from syntax trees. 83/// Primary API to get semantic information, like types, from syntax trees.
84pub struct Semantics<'db, DB> { 84pub struct Semantics<'db, DB> {
85 pub db: &'db DB, 85 pub db: &'db DB,
86 imp: SemanticsImpl<'db>,
87}
88
89pub struct SemanticsImpl<'db> {
90 pub db: &'db dyn HirDatabase,
86 s2d_cache: RefCell<SourceToDefCache>, 91 s2d_cache: RefCell<SourceToDefCache>,
87 cache: RefCell<FxHashMap<SyntaxNode, HirFileId>>, 92 cache: RefCell<FxHashMap<SyntaxNode, HirFileId>>,
88} 93}
@@ -95,20 +100,180 @@ impl<DB> fmt::Debug for Semantics<'_, DB> {
95 100
96impl<'db, DB: HirDatabase> Semantics<'db, DB> { 101impl<'db, DB: HirDatabase> Semantics<'db, DB> {
97 pub fn new(db: &DB) -> Semantics<DB> { 102 pub fn new(db: &DB) -> Semantics<DB> {
98 Semantics { db, s2d_cache: Default::default(), cache: Default::default() } 103 let impl_ = SemanticsImpl::new(db);
104 Semantics { db, imp: impl_ }
99 } 105 }
100 106
101 pub fn parse(&self, file_id: FileId) -> ast::SourceFile { 107 pub fn parse(&self, file_id: FileId) -> ast::SourceFile {
102 let tree = self.db.parse(file_id).tree(); 108 self.imp.parse(file_id)
103 self.cache(tree.syntax().clone(), file_id.into());
104 tree
105 } 109 }
106 110
107 pub fn ast<T: AstDiagnostic + Diagnostic>(&self, d: &T) -> <T as AstDiagnostic>::AST { 111 pub fn ast<T: AstDiagnostic + Diagnostic>(&self, d: &T) -> <T as AstDiagnostic>::AST {
108 let file_id = d.source().file_id; 112 let file_id = d.source().file_id;
109 let root = self.db.parse_or_expand(file_id).unwrap(); 113 let root = self.db.parse_or_expand(file_id).unwrap();
110 self.cache(root, file_id); 114 self.imp.cache(root, file_id);
111 d.ast(self.db) 115 d.ast(self.db.upcast())
116 }
117
118 pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> {
119 self.imp.expand(macro_call)
120 }
121
122 pub fn expand_hypothetical(
123 &self,
124 actual_macro_call: &ast::MacroCall,
125 hypothetical_args: &ast::TokenTree,
126 token_to_map: SyntaxToken,
127 ) -> Option<(SyntaxNode, SyntaxToken)> {
128 self.imp.expand_hypothetical(actual_macro_call, hypothetical_args, token_to_map)
129 }
130
131 pub fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken {
132 self.imp.descend_into_macros(token)
133 }
134
135 pub fn descend_node_at_offset<N: ast::AstNode>(
136 &self,
137 node: &SyntaxNode,
138 offset: TextSize,
139 ) -> Option<N> {
140 self.imp.descend_node_at_offset(node, offset).find_map(N::cast)
141 }
142
143 pub fn original_range(&self, node: &SyntaxNode) -> FileRange {
144 self.imp.original_range(node)
145 }
146
147 pub fn diagnostics_range(&self, diagnostics: &dyn Diagnostic) -> FileRange {
148 self.imp.diagnostics_range(diagnostics)
149 }
150
151 pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ {
152 self.imp.ancestors_with_macros(node)
153 }
154
155 pub fn ancestors_at_offset_with_macros(
156 &self,
157 node: &SyntaxNode,
158 offset: TextSize,
159 ) -> impl Iterator<Item = SyntaxNode> + '_ {
160 self.imp.ancestors_at_offset_with_macros(node, offset)
161 }
162
163 /// Find a AstNode by offset inside SyntaxNode, if it is inside *Macrofile*,
164 /// search up until it is of the target AstNode type
165 pub fn find_node_at_offset_with_macros<N: AstNode>(
166 &self,
167 node: &SyntaxNode,
168 offset: TextSize,
169 ) -> Option<N> {
170 self.imp.ancestors_at_offset_with_macros(node, offset).find_map(N::cast)
171 }
172
173 /// Find a AstNode by offset inside SyntaxNode, if it is inside *MacroCall*,
174 /// descend it and find again
175 pub fn find_node_at_offset_with_descend<N: AstNode>(
176 &self,
177 node: &SyntaxNode,
178 offset: TextSize,
179 ) -> Option<N> {
180 if let Some(it) = find_node_at_offset(&node, offset) {
181 return Some(it);
182 }
183
184 self.imp.descend_node_at_offset(node, offset).find_map(N::cast)
185 }
186
187 pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> {
188 self.imp.type_of_expr(expr)
189 }
190
191 pub fn type_of_pat(&self, pat: &ast::Pat) -> Option<Type> {
192 self.imp.type_of_pat(pat)
193 }
194
195 pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> {
196 self.imp.resolve_method_call(call)
197 }
198
199 pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<Field> {
200 self.imp.resolve_field(field)
201 }
202
203 pub fn resolve_record_field(&self, field: &ast::RecordField) -> Option<(Field, Option<Local>)> {
204 self.imp.resolve_record_field(field)
205 }
206
207 pub fn resolve_record_field_pat(&self, field: &ast::RecordFieldPat) -> Option<Field> {
208 self.imp.resolve_record_field_pat(field)
209 }
210
211 pub fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option<MacroDef> {
212 self.imp.resolve_macro_call(macro_call)
213 }
214
215 pub fn resolve_path(&self, path: &ast::Path) -> Option<PathResolution> {
216 self.imp.resolve_path(path)
217 }
218
219 pub fn resolve_variant(&self, record_lit: ast::RecordLit) -> Option<VariantId> {
220 self.imp.resolve_variant(record_lit)
221 }
222
223 pub fn lower_path(&self, path: &ast::Path) -> Option<Path> {
224 self.imp.lower_path(path)
225 }
226
227 pub fn resolve_bind_pat_to_const(&self, pat: &ast::BindPat) -> Option<ModuleDef> {
228 self.imp.resolve_bind_pat_to_const(pat)
229 }
230
231 // FIXME: use this instead?
232 // pub fn resolve_name_ref(&self, name_ref: &ast::NameRef) -> Option<???>;
233
234 pub fn record_literal_missing_fields(&self, literal: &ast::RecordLit) -> Vec<(Field, Type)> {
235 self.imp.record_literal_missing_fields(literal)
236 }
237
238 pub fn record_pattern_missing_fields(&self, pattern: &ast::RecordPat) -> Vec<(Field, Type)> {
239 self.imp.record_pattern_missing_fields(pattern)
240 }
241
242 pub fn to_def<T: ToDef>(&self, src: &T) -> Option<T::Def> {
243 let src = self.imp.find_file(src.syntax().clone()).with_value(src).cloned();
244 T::to_def(&self.imp, src)
245 }
246
247 pub fn to_module_def(&self, file: FileId) -> Option<Module> {
248 self.imp.to_module_def(file)
249 }
250
251 pub fn scope(&self, node: &SyntaxNode) -> SemanticsScope<'db> {
252 self.imp.scope(node)
253 }
254
255 pub fn scope_at_offset(&self, node: &SyntaxNode, offset: TextSize) -> SemanticsScope<'db> {
256 self.imp.scope_at_offset(node, offset)
257 }
258
259 pub fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db> {
260 self.imp.scope_for_def(def)
261 }
262
263 pub fn assert_contains_node(&self, node: &SyntaxNode) {
264 self.imp.assert_contains_node(node)
265 }
266}
267
268impl<'db> SemanticsImpl<'db> {
269 pub fn new(db: &'db dyn HirDatabase) -> Self {
270 Self { db, s2d_cache: Default::default(), cache: Default::default() }
271 }
272
273 pub fn parse(&self, file_id: FileId) -> ast::SourceFile {
274 let tree = self.db.parse(file_id).tree();
275 self.cache(tree.syntax().clone(), file_id.into());
276 tree
112 } 277 }
113 278
114 pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> { 279 pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> {
@@ -130,9 +295,15 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
130 self.find_file(actual_macro_call.syntax().clone()).with_value(actual_macro_call); 295 self.find_file(actual_macro_call.syntax().clone()).with_value(actual_macro_call);
131 let sa = self.analyze2(macro_call.map(|it| it.syntax()), None); 296 let sa = self.analyze2(macro_call.map(|it| it.syntax()), None);
132 let krate = sa.resolver.krate()?; 297 let krate = sa.resolver.krate()?;
133 let macro_call_id = macro_call 298 let macro_call_id = macro_call.as_call_id(self.db.upcast(), krate, |path| {
134 .as_call_id(self.db, krate, |path| sa.resolver.resolve_path_as_macro(self.db, &path))?; 299 sa.resolver.resolve_path_as_macro(self.db.upcast(), &path)
135 hir_expand::db::expand_hypothetical(self.db, macro_call_id, hypothetical_args, token_to_map) 300 })?;
301 hir_expand::db::expand_hypothetical(
302 self.db.upcast(),
303 macro_call_id,
304 hypothetical_args,
305 token_to_map,
306 )
136 } 307 }
137 308
138 pub fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken { 309 pub fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken {
@@ -147,7 +318,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
147 return None; 318 return None;
148 } 319 }
149 let file_id = sa.expand(self.db, token.with_value(&macro_call))?; 320 let file_id = sa.expand(self.db, token.with_value(&macro_call))?;
150 let token = file_id.expansion_info(self.db)?.map_token_down(token.as_ref())?; 321 let token = file_id.expansion_info(self.db.upcast())?.map_token_down(token.as_ref())?;
151 322
152 self.cache(find_root(&token.value.parent()), token.file_id); 323 self.cache(find_root(&token.value.parent()), token.file_id);
153 324
@@ -159,15 +330,16 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
159 token.value 330 token.value
160 } 331 }
161 332
162 pub fn descend_node_at_offset<N: ast::AstNode>( 333 pub fn descend_node_at_offset(
163 &self, 334 &self,
164 node: &SyntaxNode, 335 node: &SyntaxNode,
165 offset: TextSize, 336 offset: TextSize,
166 ) -> Option<N> { 337 ) -> impl Iterator<Item = SyntaxNode> + '_ {
167 // Handle macro token cases 338 // Handle macro token cases
168 node.token_at_offset(offset) 339 node.token_at_offset(offset)
169 .map(|token| self.descend_into_macros(token)) 340 .map(|token| self.descend_into_macros(token))
170 .find_map(|it| self.ancestors_with_macros(it.parent()).find_map(N::cast)) 341 .map(|it| self.ancestors_with_macros(it.parent()))
342 .flatten()
171 } 343 }
172 344
173 pub fn original_range(&self, node: &SyntaxNode) -> FileRange { 345 pub fn original_range(&self, node: &SyntaxNode) -> FileRange {
@@ -184,7 +356,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
184 356
185 pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ { 357 pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ {
186 let node = self.find_file(node); 358 let node = self.find_file(node);
187 node.ancestors_with_macros(self.db).map(|it| it.value) 359 node.ancestors_with_macros(self.db.upcast()).map(|it| it.value)
188 } 360 }
189 361
190 pub fn ancestors_at_offset_with_macros( 362 pub fn ancestors_at_offset_with_macros(
@@ -197,29 +369,6 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
197 .kmerge_by(|node1, node2| node1.text_range().len() < node2.text_range().len()) 369 .kmerge_by(|node1, node2| node1.text_range().len() < node2.text_range().len())
198 } 370 }
199 371
200 /// Find a AstNode by offset inside SyntaxNode, if it is inside *Macrofile*,
201 /// search up until it is of the target AstNode type
202 pub fn find_node_at_offset_with_macros<N: AstNode>(
203 &self,
204 node: &SyntaxNode,
205 offset: TextSize,
206 ) -> Option<N> {
207 self.ancestors_at_offset_with_macros(node, offset).find_map(N::cast)
208 }
209
210 /// Find a AstNode by offset inside SyntaxNode, if it is inside *MacroCall*,
211 /// descend it and find again
212 pub fn find_node_at_offset_with_descend<N: AstNode>(
213 &self,
214 node: &SyntaxNode,
215 offset: TextSize,
216 ) -> Option<N> {
217 if let Some(it) = find_node_at_offset(&node, offset) {
218 return Some(it);
219 }
220 self.descend_node_at_offset(&node, offset)
221 }
222
223 pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> { 372 pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> {
224 self.analyze(expr.syntax()).type_of(self.db, &expr) 373 self.analyze(expr.syntax()).type_of(self.db, &expr)
225 } 374 }
@@ -267,9 +416,6 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
267 self.analyze(pat.syntax()).resolve_bind_pat_to_const(self.db, pat) 416 self.analyze(pat.syntax()).resolve_bind_pat_to_const(self.db, pat)
268 } 417 }
269 418
270 // FIXME: use this instead?
271 // pub fn resolve_name_ref(&self, name_ref: &ast::NameRef) -> Option<???>;
272
273 pub fn record_literal_missing_fields(&self, literal: &ast::RecordLit) -> Vec<(Field, Type)> { 419 pub fn record_literal_missing_fields(&self, literal: &ast::RecordLit) -> Vec<(Field, Type)> {
274 self.analyze(literal.syntax()) 420 self.analyze(literal.syntax())
275 .record_literal_missing_fields(self.db, literal) 421 .record_literal_missing_fields(self.db, literal)
@@ -282,11 +428,6 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
282 .unwrap_or_default() 428 .unwrap_or_default()
283 } 429 }
284 430
285 pub fn to_def<T: ToDef>(&self, src: &T) -> Option<T::Def> {
286 let src = self.find_file(src.syntax().clone()).with_value(src).cloned();
287 T::to_def(self, src)
288 }
289
290 fn with_ctx<F: FnOnce(&mut SourceToDefCtx) -> T, T>(&self, f: F) -> T { 431 fn with_ctx<F: FnOnce(&mut SourceToDefCtx) -> T, T>(&self, f: F) -> T {
291 let mut cache = self.s2d_cache.borrow_mut(); 432 let mut cache = self.s2d_cache.borrow_mut();
292 let mut ctx = SourceToDefCtx { db: self.db, cache: &mut *cache }; 433 let mut ctx = SourceToDefCtx { db: self.db, cache: &mut *cache };
@@ -297,20 +438,20 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
297 self.with_ctx(|ctx| ctx.file_to_def(file)).map(Module::from) 438 self.with_ctx(|ctx| ctx.file_to_def(file)).map(Module::from)
298 } 439 }
299 440
300 pub fn scope(&self, node: &SyntaxNode) -> SemanticsScope<'db, DB> { 441 pub fn scope(&self, node: &SyntaxNode) -> SemanticsScope<'db> {
301 let node = self.find_file(node.clone()); 442 let node = self.find_file(node.clone());
302 let resolver = self.analyze2(node.as_ref(), None).resolver; 443 let resolver = self.analyze2(node.as_ref(), None).resolver;
303 SemanticsScope { db: self.db, resolver } 444 SemanticsScope { db: self.db, resolver }
304 } 445 }
305 446
306 pub fn scope_at_offset(&self, node: &SyntaxNode, offset: TextSize) -> SemanticsScope<'db, DB> { 447 pub fn scope_at_offset(&self, node: &SyntaxNode, offset: TextSize) -> SemanticsScope<'db> {
307 let node = self.find_file(node.clone()); 448 let node = self.find_file(node.clone());
308 let resolver = self.analyze2(node.as_ref(), Some(offset)).resolver; 449 let resolver = self.analyze2(node.as_ref(), Some(offset)).resolver;
309 SemanticsScope { db: self.db, resolver } 450 SemanticsScope { db: self.db, resolver }
310 } 451 }
311 452
312 pub fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db, DB> { 453 pub fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db> {
313 let resolver = def.id.resolver(self.db); 454 let resolver = def.id.resolver(self.db.upcast());
314 SemanticsScope { db: self.db, resolver } 455 SemanticsScope { db: self.db, resolver }
315 } 456 }
316 457
@@ -331,17 +472,17 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
331 ChildContainer::DefWithBodyId(def) => { 472 ChildContainer::DefWithBodyId(def) => {
332 return SourceAnalyzer::new_for_body(self.db, def, src, offset) 473 return SourceAnalyzer::new_for_body(self.db, def, src, offset)
333 } 474 }
334 ChildContainer::TraitId(it) => it.resolver(self.db), 475 ChildContainer::TraitId(it) => it.resolver(self.db.upcast()),
335 ChildContainer::ImplId(it) => it.resolver(self.db), 476 ChildContainer::ImplId(it) => it.resolver(self.db.upcast()),
336 ChildContainer::ModuleId(it) => it.resolver(self.db), 477 ChildContainer::ModuleId(it) => it.resolver(self.db.upcast()),
337 ChildContainer::EnumId(it) => it.resolver(self.db), 478 ChildContainer::EnumId(it) => it.resolver(self.db.upcast()),
338 ChildContainer::VariantId(it) => it.resolver(self.db), 479 ChildContainer::VariantId(it) => it.resolver(self.db.upcast()),
339 ChildContainer::GenericDefId(it) => it.resolver(self.db), 480 ChildContainer::GenericDefId(it) => it.resolver(self.db.upcast()),
340 }; 481 };
341 SourceAnalyzer::new_for_resolver(resolver, src) 482 SourceAnalyzer::new_for_resolver(resolver, src)
342 } 483 }
343 484
344 fn cache(&self, root_node: SyntaxNode, file_id: HirFileId) { 485 pub fn cache(&self, root_node: SyntaxNode, file_id: HirFileId) {
345 assert!(root_node.parent().is_none()); 486 assert!(root_node.parent().is_none());
346 let mut cache = self.cache.borrow_mut(); 487 let mut cache = self.cache.borrow_mut();
347 let prev = cache.insert(root_node, file_id); 488 let prev = cache.insert(root_node, file_id);
@@ -357,7 +498,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
357 cache.get(root_node).copied() 498 cache.get(root_node).copied()
358 } 499 }
359 500
360 fn find_file(&self, node: SyntaxNode) -> InFile<SyntaxNode> { 501 pub fn find_file(&self, node: SyntaxNode) -> InFile<SyntaxNode> {
361 let root_node = find_root(&node); 502 let root_node = find_root(&node);
362 let file_id = self.lookup(&root_node).unwrap_or_else(|| { 503 let file_id = self.lookup(&root_node).unwrap_or_else(|| {
363 panic!( 504 panic!(
@@ -382,14 +523,14 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
382pub trait ToDef: AstNode + Clone { 523pub trait ToDef: AstNode + Clone {
383 type Def; 524 type Def;
384 525
385 fn to_def<DB: HirDatabase>(sema: &Semantics<DB>, src: InFile<Self>) -> Option<Self::Def>; 526 fn to_def(sema: &SemanticsImpl, src: InFile<Self>) -> Option<Self::Def>;
386} 527}
387 528
388macro_rules! to_def_impls { 529macro_rules! to_def_impls {
389 ($(($def:path, $ast:path, $meth:ident)),* ,) => {$( 530 ($(($def:path, $ast:path, $meth:ident)),* ,) => {$(
390 impl ToDef for $ast { 531 impl ToDef for $ast {
391 type Def = $def; 532 type Def = $def;
392 fn to_def<DB: HirDatabase>(sema: &Semantics<DB>, src: InFile<Self>) -> Option<Self::Def> { 533 fn to_def(sema: &SemanticsImpl, src: InFile<Self>) -> Option<Self::Def> {
393 sema.with_ctx(|ctx| ctx.$meth(src)).map(<$def>::from) 534 sema.with_ctx(|ctx| ctx.$meth(src)).map(<$def>::from)
394 } 535 }
395 } 536 }
@@ -419,12 +560,12 @@ fn find_root(node: &SyntaxNode) -> SyntaxNode {
419 node.ancestors().last().unwrap() 560 node.ancestors().last().unwrap()
420} 561}
421 562
422pub struct SemanticsScope<'a, DB> { 563pub struct SemanticsScope<'a> {
423 pub db: &'a DB, 564 pub db: &'a dyn HirDatabase,
424 resolver: Resolver, 565 resolver: Resolver,
425} 566}
426 567
427impl<'a, DB: HirDatabase> SemanticsScope<'a, DB> { 568impl<'a> SemanticsScope<'a> {
428 pub fn module(&self) -> Option<Module> { 569 pub fn module(&self) -> Option<Module> {
429 Some(Module { id: self.resolver.module()? }) 570 Some(Module { id: self.resolver.module()? })
430 } 571 }
@@ -433,13 +574,13 @@ impl<'a, DB: HirDatabase> SemanticsScope<'a, DB> {
433 // FIXME: rename to visible_traits to not repeat scope? 574 // FIXME: rename to visible_traits to not repeat scope?
434 pub fn traits_in_scope(&self) -> FxHashSet<TraitId> { 575 pub fn traits_in_scope(&self) -> FxHashSet<TraitId> {
435 let resolver = &self.resolver; 576 let resolver = &self.resolver;
436 resolver.traits_in_scope(self.db) 577 resolver.traits_in_scope(self.db.upcast())
437 } 578 }
438 579
439 pub fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef)) { 580 pub fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef)) {
440 let resolver = &self.resolver; 581 let resolver = &self.resolver;
441 582
442 resolver.process_all_names(self.db, &mut |name, def| { 583 resolver.process_all_names(self.db.upcast(), &mut |name, def| {
443 let def = match def { 584 let def = match def {
444 resolver::ScopeDef::PerNs(it) => { 585 resolver::ScopeDef::PerNs(it) => {
445 let items = ScopeDef::all_items(it); 586 let items = ScopeDef::all_items(it);
diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs
index 4d446c707..beeb98559 100644
--- a/crates/ra_hir_def/src/item_scope.rs
+++ b/crates/ra_hir_def/src/item_scope.rs
@@ -1,6 +1,8 @@
1//! Describes items defined or visible (ie, imported) in a certain scope. 1//! Describes items defined or visible (ie, imported) in a certain scope.
2//! This is shared between modules and blocks. 2//! This is shared between modules and blocks.
3 3
4use std::collections::hash_map::Entry;
5
4use hir_expand::name::Name; 6use hir_expand::name::Name;
5use once_cell::sync::Lazy; 7use once_cell::sync::Lazy;
6use ra_db::CrateId; 8use ra_db::CrateId;
@@ -27,7 +29,11 @@ pub struct PerNsGlobImports {
27 29
28#[derive(Debug, Default, PartialEq, Eq)] 30#[derive(Debug, Default, PartialEq, Eq)]
29pub struct ItemScope { 31pub struct ItemScope {
30 visible: FxHashMap<Name, PerNs>, 32 types: FxHashMap<Name, (ModuleDefId, Visibility)>,
33 values: FxHashMap<Name, (ModuleDefId, Visibility)>,
34 macros: FxHashMap<Name, (MacroDefId, Visibility)>,
35 unresolved: FxHashSet<Name>,
36
31 defs: Vec<ModuleDefId>, 37 defs: Vec<ModuleDefId>,
32 impls: Vec<ImplId>, 38 impls: Vec<ImplId>,
33 /// Macros visible in current module in legacy textual scope 39 /// Macros visible in current module in legacy textual scope
@@ -65,14 +71,16 @@ pub(crate) enum BuiltinShadowMode {
65/// Other methods will only resolve values, types and module scoped macros only. 71/// Other methods will only resolve values, types and module scoped macros only.
66impl ItemScope { 72impl ItemScope {
67 pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a { 73 pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a {
68 //FIXME: shadowing 74 // FIXME: shadowing
69 self.visible.iter().map(|(n, def)| (n, *def)) 75 let keys: FxHashSet<_> = self
70 } 76 .types
71 77 .keys()
72 pub fn entries_without_primitives<'a>( 78 .chain(self.values.keys())
73 &'a self, 79 .chain(self.macros.keys())
74 ) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a { 80 .chain(self.unresolved.iter())
75 self.visible.iter().map(|(n, def)| (n, *def)) 81 .collect();
82
83 keys.into_iter().map(move |name| (name, self.get(name)))
76 } 84 }
77 85
78 pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ { 86 pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ {
@@ -91,7 +99,7 @@ impl ItemScope {
91 99
92 /// Iterate over all module scoped macros 100 /// Iterate over all module scoped macros
93 pub(crate) fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a { 101 pub(crate) fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
94 self.visible.iter().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_))) 102 self.entries().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_)))
95 } 103 }
96 104
97 /// Iterate over all legacy textual scoped macros visible at the end of the module 105 /// Iterate over all legacy textual scoped macros visible at the end of the module
@@ -101,12 +109,16 @@ impl ItemScope {
101 109
102 /// Get a name from current module scope, legacy macros are not included 110 /// Get a name from current module scope, legacy macros are not included
103 pub(crate) fn get(&self, name: &Name) -> PerNs { 111 pub(crate) fn get(&self, name: &Name) -> PerNs {
104 self.visible.get(name).copied().unwrap_or_else(PerNs::none) 112 PerNs {
113 types: self.types.get(name).copied(),
114 values: self.values.get(name).copied(),
115 macros: self.macros.get(name).copied(),
116 }
105 } 117 }
106 118
107 pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> { 119 pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> {
108 for (name, per_ns) in &self.visible { 120 for (name, per_ns) in self.entries() {
109 if let Some(vis) = item.match_with(*per_ns) { 121 if let Some(vis) = item.match_with(per_ns) {
110 return Some((name, vis)); 122 return Some((name, vis));
111 } 123 }
112 } 124 }
@@ -114,8 +126,8 @@ impl ItemScope {
114 } 126 }
115 127
116 pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a { 128 pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a {
117 self.visible.values().filter_map(|def| match def.take_types() { 129 self.types.values().filter_map(|(def, _)| match def {
118 Some(ModuleDefId::TraitId(t)) => Some(t), 130 ModuleDefId::TraitId(t) => Some(*t),
119 _ => None, 131 _ => None,
120 }) 132 })
121 } 133 }
@@ -138,21 +150,30 @@ impl ItemScope {
138 150
139 pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool { 151 pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool {
140 let mut changed = false; 152 let mut changed = false;
141 let existing = self.visible.entry(name).or_default();
142 153
143 if existing.types.is_none() && def.types.is_some() { 154 if let Some(types) = def.types {
144 existing.types = def.types; 155 self.types.entry(name.clone()).or_insert_with(|| {
145 changed = true; 156 changed = true;
157 types
158 });
146 } 159 }
147 160 if let Some(values) = def.values {
148 if existing.values.is_none() && def.values.is_some() { 161 self.values.entry(name.clone()).or_insert_with(|| {
149 existing.values = def.values; 162 changed = true;
150 changed = true; 163 values
164 });
165 }
166 if let Some(macros) = def.macros {
167 self.macros.entry(name.clone()).or_insert_with(|| {
168 changed = true;
169 macros
170 });
151 } 171 }
152 172
153 if existing.macros.is_none() && def.macros.is_some() { 173 if def.is_none() {
154 existing.macros = def.macros; 174 if self.unresolved.insert(name) {
155 changed = true; 175 changed = true;
176 }
156 } 177 }
157 178
158 changed 179 changed
@@ -166,17 +187,17 @@ impl ItemScope {
166 def_import_type: ImportType, 187 def_import_type: ImportType,
167 ) -> bool { 188 ) -> bool {
168 let mut changed = false; 189 let mut changed = false;
169 let existing = self.visible.entry(lookup.1.clone()).or_default();
170 190
171 macro_rules! check_changed { 191 macro_rules! check_changed {
172 ( 192 (
173 $changed:ident, 193 $changed:ident,
174 ( $existing:ident / $def:ident ) . $field:ident, 194 ( $this:ident / $def:ident ) . $field:ident,
175 $glob_imports:ident [ $lookup:ident ], 195 $glob_imports:ident [ $lookup:ident ],
176 $def_import_type:ident 196 $def_import_type:ident
177 ) => { 197 ) => {{
178 match ($existing.$field, $def.$field) { 198 let existing = $this.$field.entry($lookup.1.clone());
179 (None, Some(_)) => { 199 match (existing, $def.$field) {
200 (Entry::Vacant(entry), Some(_)) => {
180 match $def_import_type { 201 match $def_import_type {
181 ImportType::Glob => { 202 ImportType::Glob => {
182 $glob_imports.$field.insert($lookup.clone()); 203 $glob_imports.$field.insert($lookup.clone());
@@ -186,32 +207,42 @@ impl ItemScope {
186 } 207 }
187 } 208 }
188 209
189 $existing.$field = $def.$field; 210 if let Some(fld) = $def.$field {
211 entry.insert(fld);
212 }
190 $changed = true; 213 $changed = true;
191 } 214 }
192 (Some(_), Some(_)) 215 (Entry::Occupied(mut entry), Some(_))
193 if $glob_imports.$field.contains(&$lookup) 216 if $glob_imports.$field.contains(&$lookup)
194 && matches!($def_import_type, ImportType::Named) => 217 && matches!($def_import_type, ImportType::Named) =>
195 { 218 {
196 mark::hit!(import_shadowed); 219 mark::hit!(import_shadowed);
197 $glob_imports.$field.remove(&$lookup); 220 $glob_imports.$field.remove(&$lookup);
198 $existing.$field = $def.$field; 221 if let Some(fld) = $def.$field {
222 entry.insert(fld);
223 }
199 $changed = true; 224 $changed = true;
200 } 225 }
201 _ => {} 226 _ => {}
202 } 227 }
203 }; 228 }};
204 } 229 }
205 230
206 check_changed!(changed, (existing / def).types, glob_imports[lookup], def_import_type); 231 check_changed!(changed, (self / def).types, glob_imports[lookup], def_import_type);
207 check_changed!(changed, (existing / def).values, glob_imports[lookup], def_import_type); 232 check_changed!(changed, (self / def).values, glob_imports[lookup], def_import_type);
208 check_changed!(changed, (existing / def).macros, glob_imports[lookup], def_import_type); 233 check_changed!(changed, (self / def).macros, glob_imports[lookup], def_import_type);
234
235 if def.is_none() {
236 if self.unresolved.insert(lookup.1) {
237 changed = true;
238 }
239 }
209 240
210 changed 241 changed
211 } 242 }
212 243
213 pub(crate) fn resolutions<'a>(&'a self) -> impl Iterator<Item = (Name, PerNs)> + 'a { 244 pub(crate) fn resolutions<'a>(&'a self) -> impl Iterator<Item = (Name, PerNs)> + 'a {
214 self.visible.iter().map(|(name, res)| (name.clone(), *res)) 245 self.entries().map(|(name, res)| (name.clone(), res))
215 } 246 }
216 247
217 pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> { 248 pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> {
diff --git a/crates/ra_hir_def/src/item_tree/lower.rs b/crates/ra_hir_def/src/item_tree/lower.rs
index 5149dd141..06743d7fc 100644
--- a/crates/ra_hir_def/src/item_tree/lower.rs
+++ b/crates/ra_hir_def/src/item_tree/lower.rs
@@ -211,7 +211,7 @@ impl Ctx {
211 fn lower_record_field(&mut self, field: &ast::RecordFieldDef) -> Option<Field> { 211 fn lower_record_field(&mut self, field: &ast::RecordFieldDef) -> Option<Field> {
212 let name = field.name()?.as_name(); 212 let name = field.name()?.as_name();
213 let visibility = self.lower_visibility(field); 213 let visibility = self.lower_visibility(field);
214 let type_ref = self.lower_type_ref(&field.ascribed_type()?); 214 let type_ref = self.lower_type_ref_opt(field.ascribed_type());
215 let res = Field { name, type_ref, visibility }; 215 let res = Field { name, type_ref, visibility };
216 Some(res) 216 Some(res)
217 } 217 }
diff --git a/crates/ra_hir_def/src/resolver.rs b/crates/ra_hir_def/src/resolver.rs
index 15fdd9019..0bf51eb7b 100644
--- a/crates/ra_hir_def/src/resolver.rs
+++ b/crates/ra_hir_def/src/resolver.rs
@@ -511,11 +511,9 @@ impl Scope {
511 }); 511 });
512 } 512 }
513 } 513 }
514 Scope::LocalItemsScope(body) => { 514 Scope::LocalItemsScope(body) => body.item_scope.entries().for_each(|(name, def)| {
515 body.item_scope.entries_without_primitives().for_each(|(name, def)| { 515 f(name.clone(), ScopeDef::PerNs(def));
516 f(name.clone(), ScopeDef::PerNs(def)); 516 }),
517 })
518 }
519 Scope::GenericParams { params, def } => { 517 Scope::GenericParams { params, def } => {
520 for (local_id, param) in params.types.iter() { 518 for (local_id, param) in params.types.iter() {
521 if let Some(name) = &param.name { 519 if let Some(name) = &param.name {
diff --git a/crates/ra_hir_expand/src/builtin_derive.rs b/crates/ra_hir_expand/src/builtin_derive.rs
index 26b667b55..f2d664863 100644
--- a/crates/ra_hir_expand/src/builtin_derive.rs
+++ b/crates/ra_hir_expand/src/builtin_derive.rs
@@ -161,7 +161,7 @@ fn find_builtin_crate(db: &dyn AstDatabase, id: LazyMacroId) -> tt::TokenTree {
161 // XXX 161 // XXX
162 // All crates except core itself should have a dependency on core, 162 // All crates except core itself should have a dependency on core,
163 // We detect `core` by seeing whether it doesn't have such a dependency. 163 // We detect `core` by seeing whether it doesn't have such a dependency.
164 let tt = if cg[krate].dependencies.iter().any(|dep| dep.name == "core") { 164 let tt = if cg[krate].dependencies.iter().any(|dep| &*dep.name == "core") {
165 quote! { core } 165 quote! { core }
166 } else { 166 } else {
167 quote! { crate } 167 quote! { crate }
diff --git a/crates/ra_hir_expand/src/diagnostics.rs b/crates/ra_hir_expand/src/diagnostics.rs
index 99209c6e8..545cff9bd 100644
--- a/crates/ra_hir_expand/src/diagnostics.rs
+++ b/crates/ra_hir_expand/src/diagnostics.rs
@@ -28,7 +28,7 @@ pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static {
28 28
29pub trait AstDiagnostic { 29pub trait AstDiagnostic {
30 type AST; 30 type AST;
31 fn ast(&self, db: &impl AstDatabase) -> Self::AST; 31 fn ast(&self, db: &dyn AstDatabase) -> Self::AST;
32} 32}
33 33
34impl dyn Diagnostic { 34impl dyn Diagnostic {
diff --git a/crates/ra_hir_expand/src/name.rs b/crates/ra_hir_expand/src/name.rs
index 1b0303685..969a2e5b8 100644
--- a/crates/ra_hir_expand/src/name.rs
+++ b/crates/ra_hir_expand/src/name.rs
@@ -117,7 +117,7 @@ impl AsName for ast::FieldKind {
117 117
118impl AsName for ra_db::Dependency { 118impl AsName for ra_db::Dependency {
119 fn as_name(&self) -> Name { 119 fn as_name(&self) -> Name {
120 Name::new_text(self.name.clone()) 120 Name::new_text(SmolStr::new(&*self.name))
121 } 121 }
122} 122}
123 123
diff --git a/crates/ra_hir_ty/src/autoderef.rs b/crates/ra_hir_ty/src/autoderef.rs
index 1b0f84c5c..c727012c6 100644
--- a/crates/ra_hir_ty/src/autoderef.rs
+++ b/crates/ra_hir_ty/src/autoderef.rs
@@ -37,7 +37,7 @@ pub(crate) fn deref(
37 ty: InEnvironment<&Canonical<Ty>>, 37 ty: InEnvironment<&Canonical<Ty>>,
38) -> Option<Canonical<Ty>> { 38) -> Option<Canonical<Ty>> {
39 if let Some(derefed) = ty.value.value.builtin_deref() { 39 if let Some(derefed) = ty.value.value.builtin_deref() {
40 Some(Canonical { value: derefed, num_vars: ty.value.num_vars }) 40 Some(Canonical { value: derefed, kinds: ty.value.kinds.clone() })
41 } else { 41 } else {
42 deref_by_trait(db, krate, ty) 42 deref_by_trait(db, krate, ty)
43 } 43 }
@@ -68,8 +68,8 @@ fn deref_by_trait(
68 68
69 // Check that the type implements Deref at all 69 // Check that the type implements Deref at all
70 let trait_ref = TraitRef { trait_: deref_trait, substs: parameters.clone() }; 70 let trait_ref = TraitRef { trait_: deref_trait, substs: parameters.clone() };
71 let implements_goal = super::Canonical { 71 let implements_goal = Canonical {
72 num_vars: ty.value.num_vars, 72 kinds: ty.value.kinds.clone(),
73 value: InEnvironment { 73 value: InEnvironment {
74 value: Obligation::Trait(trait_ref), 74 value: Obligation::Trait(trait_ref),
75 environment: ty.environment.clone(), 75 environment: ty.environment.clone(),
@@ -81,7 +81,7 @@ fn deref_by_trait(
81 81
82 // Now do the assoc type projection 82 // Now do the assoc type projection
83 let projection = super::traits::ProjectionPredicate { 83 let projection = super::traits::ProjectionPredicate {
84 ty: Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, ty.value.num_vars)), 84 ty: Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, ty.value.kinds.len())),
85 projection_ty: super::ProjectionTy { associated_ty: target, parameters }, 85 projection_ty: super::ProjectionTy { associated_ty: target, parameters },
86 }; 86 };
87 87
@@ -89,7 +89,8 @@ fn deref_by_trait(
89 89
90 let in_env = InEnvironment { value: obligation, environment: ty.environment }; 90 let in_env = InEnvironment { value: obligation, environment: ty.environment };
91 91
92 let canonical = super::Canonical { num_vars: 1 + ty.value.num_vars, value: in_env }; 92 let canonical =
93 Canonical::new(in_env, ty.value.kinds.iter().copied().chain(Some(super::TyKind::General)));
93 94
94 let solution = db.trait_solve(krate, canonical)?; 95 let solution = db.trait_solve(krate, canonical)?;
95 96
@@ -110,7 +111,7 @@ fn deref_by_trait(
110 // assumptions will be broken. We would need to properly introduce 111 // assumptions will be broken. We would need to properly introduce
111 // new variables in that case 112 // new variables in that case
112 113
113 for i in 1..vars.0.num_vars { 114 for i in 1..vars.0.kinds.len() {
114 if vars.0.value[i - 1] != Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, i - 1)) 115 if vars.0.value[i - 1] != Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, i - 1))
115 { 116 {
116 warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.value, solution); 117 warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.value, solution);
@@ -119,7 +120,7 @@ fn deref_by_trait(
119 } 120 }
120 Some(Canonical { 121 Some(Canonical {
121 value: vars.0.value[vars.0.value.len() - 1].clone(), 122 value: vars.0.value[vars.0.value.len() - 1].clone(),
122 num_vars: vars.0.num_vars, 123 kinds: vars.0.kinds.clone(),
123 }) 124 })
124 } 125 }
125 Solution::Ambig(_) => { 126 Solution::Ambig(_) => {
diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs
index cad553273..dc06c0ee7 100644
--- a/crates/ra_hir_ty/src/db.rs
+++ b/crates/ra_hir_ty/src/db.rs
@@ -11,7 +11,7 @@ use ra_db::{impl_intern_key, salsa, CrateId, Upcast};
11use ra_prof::profile; 11use ra_prof::profile;
12 12
13use crate::{ 13use crate::{
14 method_resolution::CrateImplDefs, 14 method_resolution::{InherentImpls, TraitImpls},
15 traits::{chalk, AssocTyValue, Impl}, 15 traits::{chalk, AssocTyValue, Impl},
16 Binders, CallableDef, GenericPredicate, InferenceResult, OpaqueTyId, PolyFnSig, 16 Binders, CallableDef, GenericPredicate, InferenceResult, OpaqueTyId, PolyFnSig,
17 ReturnTypeImplTraits, TraitRef, Ty, TyDefId, TypeCtor, ValueTyDefId, 17 ReturnTypeImplTraits, TraitRef, Ty, TyDefId, TypeCtor, ValueTyDefId,
@@ -67,11 +67,14 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
67 #[salsa::invoke(crate::lower::generic_defaults_query)] 67 #[salsa::invoke(crate::lower::generic_defaults_query)]
68 fn generic_defaults(&self, def: GenericDefId) -> Arc<[Binders<Ty>]>; 68 fn generic_defaults(&self, def: GenericDefId) -> Arc<[Binders<Ty>]>;
69 69
70 #[salsa::invoke(crate::method_resolution::CrateImplDefs::impls_in_crate_query)] 70 #[salsa::invoke(InherentImpls::inherent_impls_in_crate_query)]
71 fn impls_in_crate(&self, krate: CrateId) -> Arc<CrateImplDefs>; 71 fn inherent_impls_in_crate(&self, krate: CrateId) -> Arc<InherentImpls>;
72 72
73 #[salsa::invoke(crate::method_resolution::CrateImplDefs::impls_from_deps_query)] 73 #[salsa::invoke(TraitImpls::trait_impls_in_crate_query)]
74 fn impls_from_deps(&self, krate: CrateId) -> Arc<CrateImplDefs>; 74 fn trait_impls_in_crate(&self, krate: CrateId) -> Arc<TraitImpls>;
75
76 #[salsa::invoke(TraitImpls::trait_impls_in_deps_query)]
77 fn trait_impls_in_deps(&self, krate: CrateId) -> Arc<TraitImpls>;
75 78
76 // Interned IDs for Chalk integration 79 // Interned IDs for Chalk integration
77 #[salsa::interned] 80 #[salsa::interned]
diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs
index a59efb347..0289911de 100644
--- a/crates/ra_hir_ty/src/diagnostics.rs
+++ b/crates/ra_hir_ty/src/diagnostics.rs
@@ -32,7 +32,7 @@ impl Diagnostic for NoSuchField {
32impl AstDiagnostic for NoSuchField { 32impl AstDiagnostic for NoSuchField {
33 type AST = ast::RecordField; 33 type AST = ast::RecordField;
34 34
35 fn ast(&self, db: &impl AstDatabase) -> Self::AST { 35 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
36 let root = db.parse_or_expand(self.source().file_id).unwrap(); 36 let root = db.parse_or_expand(self.source().file_id).unwrap();
37 let node = self.source().value.to_node(&root); 37 let node = self.source().value.to_node(&root);
38 ast::RecordField::cast(node).unwrap() 38 ast::RecordField::cast(node).unwrap()
@@ -65,7 +65,7 @@ impl Diagnostic for MissingFields {
65impl AstDiagnostic for MissingFields { 65impl AstDiagnostic for MissingFields {
66 type AST = ast::RecordFieldList; 66 type AST = ast::RecordFieldList;
67 67
68 fn ast(&self, db: &impl AstDatabase) -> Self::AST { 68 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
69 let root = db.parse_or_expand(self.source().file_id).unwrap(); 69 let root = db.parse_or_expand(self.source().file_id).unwrap();
70 let node = self.source().value.to_node(&root); 70 let node = self.source().value.to_node(&root);
71 ast::RecordFieldList::cast(node).unwrap() 71 ast::RecordFieldList::cast(node).unwrap()
@@ -135,7 +135,7 @@ impl Diagnostic for MissingOkInTailExpr {
135impl AstDiagnostic for MissingOkInTailExpr { 135impl AstDiagnostic for MissingOkInTailExpr {
136 type AST = ast::Expr; 136 type AST = ast::Expr;
137 137
138 fn ast(&self, db: &impl AstDatabase) -> Self::AST { 138 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
139 let root = db.parse_or_expand(self.file).unwrap(); 139 let root = db.parse_or_expand(self.file).unwrap();
140 let node = self.source().value.to_node(&root); 140 let node = self.source().value.to_node(&root);
141 ast::Expr::cast(node).unwrap() 141 ast::Expr::cast(node).unwrap()
@@ -163,7 +163,7 @@ impl Diagnostic for BreakOutsideOfLoop {
163impl AstDiagnostic for BreakOutsideOfLoop { 163impl AstDiagnostic for BreakOutsideOfLoop {
164 type AST = ast::Expr; 164 type AST = ast::Expr;
165 165
166 fn ast(&self, db: &impl AstDatabase) -> Self::AST { 166 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
167 let root = db.parse_or_expand(self.file).unwrap(); 167 let root = db.parse_or_expand(self.file).unwrap();
168 let node = self.source().value.to_node(&root); 168 let node = self.source().value.to_node(&root);
169 ast::Expr::cast(node).unwrap() 169 ast::Expr::cast(node).unwrap()
@@ -191,7 +191,7 @@ impl Diagnostic for MissingUnsafe {
191impl AstDiagnostic for MissingUnsafe { 191impl AstDiagnostic for MissingUnsafe {
192 type AST = ast::Expr; 192 type AST = ast::Expr;
193 193
194 fn ast(&self, db: &impl AstDatabase) -> Self::AST { 194 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
195 let root = db.parse_or_expand(self.source().file_id).unwrap(); 195 let root = db.parse_or_expand(self.source().file_id).unwrap();
196 let node = self.source().value.to_node(&root); 196 let node = self.source().value.to_node(&root);
197 ast::Expr::cast(node).unwrap() 197 ast::Expr::cast(node).unwrap()
diff --git a/crates/ra_hir_ty/src/infer/unify.rs b/crates/ra_hir_ty/src/infer/unify.rs
index 269495ca0..2e895d911 100644
--- a/crates/ra_hir_ty/src/infer/unify.rs
+++ b/crates/ra_hir_ty/src/infer/unify.rs
@@ -9,7 +9,7 @@ use test_utils::mark;
9use super::{InferenceContext, Obligation}; 9use super::{InferenceContext, Obligation};
10use crate::{ 10use crate::{
11 BoundVar, Canonical, DebruijnIndex, GenericPredicate, InEnvironment, InferTy, Substs, Ty, 11 BoundVar, Canonical, DebruijnIndex, GenericPredicate, InEnvironment, InferTy, Substs, Ty,
12 TypeCtor, TypeWalk, 12 TyKind, TypeCtor, TypeWalk,
13}; 13};
14 14
15impl<'a> InferenceContext<'a> { 15impl<'a> InferenceContext<'a> {
@@ -86,10 +86,20 @@ where
86 } 86 }
87 87
88 fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> { 88 fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> {
89 Canonicalized { 89 let kinds = self
90 value: Canonical { value: result, num_vars: self.free_vars.len() }, 90 .free_vars
91 free_vars: self.free_vars, 91 .iter()
92 } 92 .map(|v| match v {
93 // mapping MaybeNeverTypeVar to the same kind as general ones
94 // should be fine, because as opposed to int or float type vars,
95 // they don't restrict what kind of type can go into them, they
96 // just affect fallback.
97 InferTy::TypeVar(_) | InferTy::MaybeNeverTypeVar(_) => TyKind::General,
98 InferTy::IntVar(_) => TyKind::Integer,
99 InferTy::FloatVar(_) => TyKind::Float,
100 })
101 .collect();
102 Canonicalized { value: Canonical { value: result, kinds }, free_vars: self.free_vars }
93 } 103 }
94 104
95 pub(crate) fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> { 105 pub(crate) fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> {
@@ -131,26 +141,41 @@ impl<T> Canonicalized<T> {
131 ty 141 ty
132 } 142 }
133 143
134 pub fn apply_solution(&self, ctx: &mut InferenceContext<'_>, solution: Canonical<Vec<Ty>>) { 144 pub fn apply_solution(&self, ctx: &mut InferenceContext<'_>, solution: Canonical<Substs>) {
135 // the solution may contain new variables, which we need to convert to new inference vars 145 // the solution may contain new variables, which we need to convert to new inference vars
136 let new_vars = Substs((0..solution.num_vars).map(|_| ctx.table.new_type_var()).collect()); 146 let new_vars = Substs(
147 solution
148 .kinds
149 .iter()
150 .map(|k| match k {
151 TyKind::General => ctx.table.new_type_var(),
152 TyKind::Integer => ctx.table.new_integer_var(),
153 TyKind::Float => ctx.table.new_float_var(),
154 })
155 .collect(),
156 );
137 for (i, ty) in solution.value.into_iter().enumerate() { 157 for (i, ty) in solution.value.into_iter().enumerate() {
138 let var = self.free_vars[i]; 158 let var = self.free_vars[i];
139 // eagerly replace projections in the type; we may be getting types 159 // eagerly replace projections in the type; we may be getting types
140 // e.g. from where clauses where this hasn't happened yet 160 // e.g. from where clauses where this hasn't happened yet
141 let ty = ctx.normalize_associated_types_in(ty.subst_bound_vars(&new_vars)); 161 let ty = ctx.normalize_associated_types_in(ty.clone().subst_bound_vars(&new_vars));
142 ctx.table.unify(&Ty::Infer(var), &ty); 162 ctx.table.unify(&Ty::Infer(var), &ty);
143 } 163 }
144 } 164 }
145} 165}
146 166
147pub fn unify(ty1: &Canonical<Ty>, ty2: &Canonical<Ty>) -> Option<Substs> { 167pub fn unify(tys: &Canonical<(Ty, Ty)>) -> Option<Substs> {
148 let mut table = InferenceTable::new(); 168 let mut table = InferenceTable::new();
149 let num_vars = ty1.num_vars.max(ty2.num_vars); 169 let vars = Substs(
150 let vars = 170 tys.kinds
151 Substs::builder(num_vars).fill(std::iter::repeat_with(|| table.new_type_var())).build(); 171 .iter()
152 let ty1_with_vars = ty1.value.clone().subst_bound_vars(&vars); 172 // we always use type vars here because we want everything to
153 let ty2_with_vars = ty2.value.clone().subst_bound_vars(&vars); 173 // fallback to Unknown in the end (kind of hacky, as below)
174 .map(|_| table.new_type_var())
175 .collect(),
176 );
177 let ty1_with_vars = tys.value.0.clone().subst_bound_vars(&vars);
178 let ty2_with_vars = tys.value.1.clone().subst_bound_vars(&vars);
154 if !table.unify(&ty1_with_vars, &ty2_with_vars) { 179 if !table.unify(&ty1_with_vars, &ty2_with_vars) {
155 return None; 180 return None;
156 } 181 }
@@ -162,7 +187,7 @@ pub fn unify(ty1: &Canonical<Ty>, ty2: &Canonical<Ty>) -> Option<Substs> {
162 } 187 }
163 } 188 }
164 Some( 189 Some(
165 Substs::builder(ty1.num_vars) 190 Substs::builder(tys.kinds.len())
166 .fill(vars.iter().map(|v| table.resolve_ty_completely(v.clone()))) 191 .fill(vars.iter().map(|v| table.resolve_ty_completely(v.clone())))
167 .build(), 192 .build(),
168 ) 193 )
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index c9513b752..7f3f5e771 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -662,13 +662,27 @@ impl TypeWalk for GenericPredicate {
662 662
663/// Basically a claim (currently not validated / checked) that the contained 663/// Basically a claim (currently not validated / checked) that the contained
664/// type / trait ref contains no inference variables; any inference variables it 664/// type / trait ref contains no inference variables; any inference variables it
665/// contained have been replaced by bound variables, and `num_vars` tells us how 665/// contained have been replaced by bound variables, and `kinds` tells us how
666/// many there are. This is used to erase irrelevant differences between types 666/// many there are and whether they were normal or float/int variables. This is
667/// before using them in queries. 667/// used to erase irrelevant differences between types before using them in
668/// queries.
668#[derive(Debug, Clone, PartialEq, Eq, Hash)] 669#[derive(Debug, Clone, PartialEq, Eq, Hash)]
669pub struct Canonical<T> { 670pub struct Canonical<T> {
670 pub value: T, 671 pub value: T,
671 pub num_vars: usize, 672 pub kinds: Arc<[TyKind]>,
673}
674
675impl<T> Canonical<T> {
676 pub fn new(value: T, kinds: impl IntoIterator<Item = TyKind>) -> Self {
677 Self { value, kinds: kinds.into_iter().collect() }
678 }
679}
680
681#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
682pub enum TyKind {
683 General,
684 Integer,
685 Float,
672} 686}
673 687
674/// A function signature as seen by type inference: Several parameter types and 688/// A function signature as seen by type inference: Several parameter types and
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs
index c19519cf1..a45febbf7 100644
--- a/crates/ra_hir_ty/src/method_resolution.rs
+++ b/crates/ra_hir_ty/src/method_resolution.rs
@@ -2,7 +2,7 @@
2//! For details about how this works in rustc, see the method lookup page in the 2//! For details about how this works in rustc, see the method lookup page in the
3//! [rustc guide](https://rust-lang.github.io/rustc-guide/method-lookup.html) 3//! [rustc guide](https://rust-lang.github.io/rustc-guide/method-lookup.html)
4//! and the corresponding code mostly in librustc_typeck/check/method/probe.rs. 4//! and the corresponding code mostly in librustc_typeck/check/method/probe.rs.
5use std::sync::Arc; 5use std::{iter, sync::Arc};
6 6
7use arrayvec::ArrayVec; 7use arrayvec::ArrayVec;
8use hir_def::{ 8use hir_def::{
@@ -17,7 +17,8 @@ use rustc_hash::{FxHashMap, FxHashSet};
17use super::Substs; 17use super::Substs;
18use crate::{ 18use crate::{
19 autoderef, db::HirDatabase, primitive::FloatBitness, utils::all_super_traits, ApplicationTy, 19 autoderef, db::HirDatabase, primitive::FloatBitness, utils::all_super_traits, ApplicationTy,
20 Canonical, DebruijnIndex, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk, 20 Canonical, DebruijnIndex, InEnvironment, TraitEnvironment, TraitRef, Ty, TyKind, TypeCtor,
21 TypeWalk,
21}; 22};
22 23
23/// This is used as a key for indexing impls. 24/// This is used as a key for indexing impls.
@@ -38,136 +39,131 @@ impl TyFingerprint {
38 } 39 }
39} 40}
40 41
41/// A queryable and mergeable collection of impls. 42/// Trait impls defined or available in some crate.
42#[derive(Debug, PartialEq, Eq)] 43#[derive(Debug, Eq, PartialEq)]
43pub struct CrateImplDefs { 44pub struct TraitImpls {
44 inherent_impls: FxHashMap<TyFingerprint, Vec<ImplId>>, 45 // If the `Option<TyFingerprint>` is `None`, the impl may apply to any self type.
45 impls_by_trait: FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Vec<ImplId>>>, 46 map: FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Vec<ImplId>>>,
46} 47}
47 48
48impl CrateImplDefs { 49impl TraitImpls {
49 pub(crate) fn impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<CrateImplDefs> { 50 pub(crate) fn trait_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
50 let _p = profile("impls_in_crate_query"); 51 let _p = profile("trait_impls_in_crate_query");
51 let mut res = CrateImplDefs { 52 let mut impls = Self { map: FxHashMap::default() };
52 inherent_impls: FxHashMap::default(),
53 impls_by_trait: FxHashMap::default(),
54 };
55 res.fill(db, krate);
56 53
57 Arc::new(res) 54 let crate_def_map = db.crate_def_map(krate);
55 for (_module_id, module_data) in crate_def_map.modules.iter() {
56 for impl_id in module_data.scope.impls() {
57 let target_trait = match db.impl_trait(impl_id) {
58 Some(tr) => tr.value.trait_,
59 None => continue,
60 };
61 let self_ty = db.impl_self_ty(impl_id);
62 let self_ty_fp = TyFingerprint::for_impl(&self_ty.value);
63 impls
64 .map
65 .entry(target_trait)
66 .or_default()
67 .entry(self_ty_fp)
68 .or_default()
69 .push(impl_id);
70 }
71 }
72
73 Arc::new(impls)
58 } 74 }
59 75
60 /// Collects all impls from transitive dependencies of `krate` that may be used by `krate`. 76 pub(crate) fn trait_impls_in_deps_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
61 /// 77 let _p = profile("trait_impls_in_deps_query");
62 /// The full set of impls that can be used by `krate` is the returned map plus all the impls
63 /// from `krate` itself.
64 pub(crate) fn impls_from_deps_query(
65 db: &dyn HirDatabase,
66 krate: CrateId,
67 ) -> Arc<CrateImplDefs> {
68 let _p = profile("impls_from_deps_query");
69 let crate_graph = db.crate_graph(); 78 let crate_graph = db.crate_graph();
70 let mut res = CrateImplDefs { 79 let mut res = Self { map: FxHashMap::default() };
71 inherent_impls: FxHashMap::default(),
72 impls_by_trait: FxHashMap::default(),
73 };
74 80
75 // For each dependency, calculate `impls_from_deps` recursively, then add its own 81 for krate in crate_graph.transitive_deps(krate) {
76 // `impls_in_crate`. 82 res.merge(&db.trait_impls_in_crate(krate));
77 // As we might visit crates multiple times, `merge` has to deduplicate impls to avoid
78 // wasting memory.
79 for dep in &crate_graph[krate].dependencies {
80 res.merge(&db.impls_from_deps(dep.crate_id));
81 res.merge(&db.impls_in_crate(dep.crate_id));
82 } 83 }
83 84
84 Arc::new(res) 85 Arc::new(res)
85 } 86 }
86 87
87 fn fill(&mut self, db: &dyn HirDatabase, krate: CrateId) {
88 let crate_def_map = db.crate_def_map(krate);
89 for (_module_id, module_data) in crate_def_map.modules.iter() {
90 for impl_id in module_data.scope.impls() {
91 match db.impl_trait(impl_id) {
92 Some(tr) => {
93 let self_ty = db.impl_self_ty(impl_id);
94 let self_ty_fp = TyFingerprint::for_impl(&self_ty.value);
95 self.impls_by_trait
96 .entry(tr.value.trait_)
97 .or_default()
98 .entry(self_ty_fp)
99 .or_default()
100 .push(impl_id);
101 }
102 None => {
103 let self_ty = db.impl_self_ty(impl_id);
104 if let Some(self_ty_fp) = TyFingerprint::for_impl(&self_ty.value) {
105 self.inherent_impls.entry(self_ty_fp).or_default().push(impl_id);
106 }
107 }
108 }
109 }
110 }
111 }
112
113 fn merge(&mut self, other: &Self) { 88 fn merge(&mut self, other: &Self) {
114 for (fp, impls) in &other.inherent_impls { 89 for (trait_, other_map) in &other.map {
115 let vec = self.inherent_impls.entry(*fp).or_default(); 90 let map = self.map.entry(*trait_).or_default();
116 vec.extend(impls);
117 vec.sort();
118 vec.dedup();
119 }
120
121 for (trait_, other_map) in &other.impls_by_trait {
122 let map = self.impls_by_trait.entry(*trait_).or_default();
123 for (fp, impls) in other_map { 91 for (fp, impls) in other_map {
124 let vec = map.entry(*fp).or_default(); 92 let vec = map.entry(*fp).or_default();
125 vec.extend(impls); 93 vec.extend(impls);
126 vec.sort();
127 vec.dedup();
128 } 94 }
129 } 95 }
130 } 96 }
131 97
132 pub fn lookup_impl_defs(&self, ty: &Ty) -> impl Iterator<Item = ImplId> + '_ { 98 /// Queries all impls of the given trait.
133 let fingerprint = TyFingerprint::for_impl(ty); 99 pub fn for_trait(&self, trait_: TraitId) -> impl Iterator<Item = ImplId> + '_ {
134 fingerprint.and_then(|f| self.inherent_impls.get(&f)).into_iter().flatten().copied() 100 self.map
135 } 101 .get(&trait_)
136
137 pub fn lookup_impl_defs_for_trait(&self, tr: TraitId) -> impl Iterator<Item = ImplId> + '_ {
138 self.impls_by_trait
139 .get(&tr)
140 .into_iter() 102 .into_iter()
141 .flat_map(|m| m.values().flat_map(|v| v.iter().copied())) 103 .flat_map(|map| map.values().flat_map(|v| v.iter().copied()))
142 } 104 }
143 105
144 pub fn lookup_impl_defs_for_trait_and_ty( 106 /// Queries all impls of `trait_` that may apply to `self_ty`.
107 pub fn for_trait_and_self_ty(
145 &self, 108 &self,
146 tr: TraitId, 109 trait_: TraitId,
147 fp: TyFingerprint, 110 self_ty: TyFingerprint,
148 ) -> impl Iterator<Item = ImplId> + '_ { 111 ) -> impl Iterator<Item = ImplId> + '_ {
149 self.impls_by_trait 112 self.map
150 .get(&tr) 113 .get(&trait_)
151 .and_then(|m| m.get(&Some(fp)))
152 .into_iter() 114 .into_iter()
153 .flatten() 115 .flat_map(move |map| map.get(&None).into_iter().chain(map.get(&Some(self_ty))))
154 .copied() 116 .flat_map(|v| v.iter().copied())
155 .chain( 117 }
156 self.impls_by_trait 118
157 .get(&tr) 119 pub fn all_impls(&self) -> impl Iterator<Item = ImplId> + '_ {
158 .and_then(|m| m.get(&None)) 120 self.map.values().flat_map(|map| map.values().flat_map(|v| v.iter().copied()))
159 .into_iter() 121 }
160 .flatten() 122}
161 .copied(), 123
162 ) 124/// Inherent impls defined in some crate.
125///
126/// Inherent impls can only be defined in the crate that also defines the self type of the impl
127/// (note that some primitives are considered to be defined by both libcore and liballoc).
128///
129/// This makes inherent impl lookup easier than trait impl lookup since we only have to consider a
130/// single crate.
131#[derive(Debug, Eq, PartialEq)]
132pub struct InherentImpls {
133 map: FxHashMap<TyFingerprint, Vec<ImplId>>,
134}
135
136impl InherentImpls {
137 pub(crate) fn inherent_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
138 let mut map: FxHashMap<_, Vec<_>> = FxHashMap::default();
139
140 let crate_def_map = db.crate_def_map(krate);
141 for (_module_id, module_data) in crate_def_map.modules.iter() {
142 for impl_id in module_data.scope.impls() {
143 let data = db.impl_data(impl_id);
144 if data.target_trait.is_some() {
145 continue;
146 }
147
148 let self_ty = db.impl_self_ty(impl_id);
149 if let Some(fp) = TyFingerprint::for_impl(&self_ty.value) {
150 map.entry(fp).or_default().push(impl_id);
151 }
152 }
153 }
154
155 Arc::new(Self { map })
156 }
157
158 pub fn for_self_ty(&self, self_ty: &Ty) -> &[ImplId] {
159 match TyFingerprint::for_impl(self_ty) {
160 Some(fp) => self.map.get(&fp).map(|vec| vec.as_ref()).unwrap_or(&[]),
161 None => &[],
162 }
163 } 163 }
164 164
165 pub fn all_impls<'a>(&'a self) -> impl Iterator<Item = ImplId> + 'a { 165 pub fn all_impls(&self) -> impl Iterator<Item = ImplId> + '_ {
166 self.inherent_impls 166 self.map.values().flat_map(|v| v.iter().copied())
167 .values()
168 .chain(self.impls_by_trait.values().flat_map(|m| m.values()))
169 .flatten()
170 .copied()
171 } 167 }
172} 168}
173 169
@@ -377,7 +373,7 @@ fn iterate_method_candidates_with_autoref(
377 return true; 373 return true;
378 } 374 }
379 let refed = Canonical { 375 let refed = Canonical {
380 num_vars: deref_chain[0].num_vars, 376 kinds: deref_chain[0].kinds.clone(),
381 value: Ty::apply_one(TypeCtor::Ref(Mutability::Shared), deref_chain[0].value.clone()), 377 value: Ty::apply_one(TypeCtor::Ref(Mutability::Shared), deref_chain[0].value.clone()),
382 }; 378 };
383 if iterate_method_candidates_by_receiver( 379 if iterate_method_candidates_by_receiver(
@@ -393,7 +389,7 @@ fn iterate_method_candidates_with_autoref(
393 return true; 389 return true;
394 } 390 }
395 let ref_muted = Canonical { 391 let ref_muted = Canonical {
396 num_vars: deref_chain[0].num_vars, 392 kinds: deref_chain[0].kinds.clone(),
397 value: Ty::apply_one(TypeCtor::Ref(Mutability::Mut), deref_chain[0].value.clone()), 393 value: Ty::apply_one(TypeCtor::Ref(Mutability::Mut), deref_chain[0].value.clone()),
398 }; 394 };
399 if iterate_method_candidates_by_receiver( 395 if iterate_method_candidates_by_receiver(
@@ -524,9 +520,9 @@ fn iterate_inherent_methods(
524 None => return false, 520 None => return false,
525 }; 521 };
526 for krate in def_crates { 522 for krate in def_crates {
527 let impls = db.impls_in_crate(krate); 523 let impls = db.inherent_impls_in_crate(krate);
528 524
529 for impl_def in impls.lookup_impl_defs(&self_ty.value) { 525 for &impl_def in impls.for_self_ty(&self_ty.value) {
530 for &item in db.impl_data(impl_def).items.iter() { 526 for &item in db.impl_data(impl_def).items.iter() {
531 if !is_valid_candidate(db, name, receiver_ty, item, self_ty) { 527 if !is_valid_candidate(db, name, receiver_ty, item, self_ty) {
532 continue; 528 continue;
@@ -612,18 +608,19 @@ pub(crate) fn inherent_impl_substs(
612 // we create a var for each type parameter of the impl; we need to keep in 608 // we create a var for each type parameter of the impl; we need to keep in
613 // mind here that `self_ty` might have vars of its own 609 // mind here that `self_ty` might have vars of its own
614 let vars = Substs::build_for_def(db, impl_id) 610 let vars = Substs::build_for_def(db, impl_id)
615 .fill_with_bound_vars(DebruijnIndex::INNERMOST, self_ty.num_vars) 611 .fill_with_bound_vars(DebruijnIndex::INNERMOST, self_ty.kinds.len())
616 .build(); 612 .build();
617 let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars); 613 let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars);
618 let self_ty_with_vars = 614 let mut kinds = self_ty.kinds.to_vec();
619 Canonical { num_vars: vars.len() + self_ty.num_vars, value: self_ty_with_vars }; 615 kinds.extend(iter::repeat(TyKind::General).take(vars.len()));
620 let substs = super::infer::unify(&self_ty_with_vars, self_ty); 616 let tys = Canonical { kinds: kinds.into(), value: (self_ty_with_vars, self_ty.value.clone()) };
617 let substs = super::infer::unify(&tys);
621 // We only want the substs for the vars we added, not the ones from self_ty. 618 // We only want the substs for the vars we added, not the ones from self_ty.
622 // Also, if any of the vars we added are still in there, we replace them by 619 // Also, if any of the vars we added are still in there, we replace them by
623 // Unknown. I think this can only really happen if self_ty contained 620 // Unknown. I think this can only really happen if self_ty contained
624 // Unknown, and in that case we want the result to contain Unknown in those 621 // Unknown, and in that case we want the result to contain Unknown in those
625 // places again. 622 // places again.
626 substs.map(|s| fallback_bound_vars(s.suffix(vars.len()), self_ty.num_vars)) 623 substs.map(|s| fallback_bound_vars(s.suffix(vars.len()), self_ty.kinds.len()))
627} 624}
628 625
629/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past 626/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past
@@ -683,15 +680,15 @@ fn generic_implements_goal(
683 trait_: TraitId, 680 trait_: TraitId,
684 self_ty: Canonical<Ty>, 681 self_ty: Canonical<Ty>,
685) -> Canonical<InEnvironment<super::Obligation>> { 682) -> Canonical<InEnvironment<super::Obligation>> {
686 let num_vars = self_ty.num_vars; 683 let mut kinds = self_ty.kinds.to_vec();
687 let substs = super::Substs::build_for_def(db, trait_) 684 let substs = super::Substs::build_for_def(db, trait_)
688 .push(self_ty.value) 685 .push(self_ty.value)
689 .fill_with_bound_vars(DebruijnIndex::INNERMOST, num_vars) 686 .fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len())
690 .build(); 687 .build();
691 let num_vars = substs.len() - 1 + self_ty.num_vars; 688 kinds.extend(iter::repeat(TyKind::General).take(substs.len() - 1));
692 let trait_ref = TraitRef { trait_, substs }; 689 let trait_ref = TraitRef { trait_, substs };
693 let obligation = super::Obligation::Trait(trait_ref); 690 let obligation = super::Obligation::Trait(trait_ref);
694 Canonical { num_vars, value: InEnvironment::new(env, obligation) } 691 Canonical { kinds: kinds.into(), value: InEnvironment::new(env, obligation) }
695} 692}
696 693
697fn autoderef_method_receiver( 694fn autoderef_method_receiver(
@@ -704,9 +701,9 @@ fn autoderef_method_receiver(
704 if let Some(Ty::Apply(ApplicationTy { ctor: TypeCtor::Array, parameters })) = 701 if let Some(Ty::Apply(ApplicationTy { ctor: TypeCtor::Array, parameters })) =
705 deref_chain.last().map(|ty| &ty.value) 702 deref_chain.last().map(|ty| &ty.value)
706 { 703 {
707 let num_vars = deref_chain.last().unwrap().num_vars; 704 let kinds = deref_chain.last().unwrap().kinds.clone();
708 let unsized_ty = Ty::apply(TypeCtor::Slice, parameters.clone()); 705 let unsized_ty = Ty::apply(TypeCtor::Slice, parameters.clone());
709 deref_chain.push(Canonical { value: unsized_ty, num_vars }) 706 deref_chain.push(Canonical { value: unsized_ty, kinds })
710 } 707 }
711 deref_chain 708 deref_chain
712} 709}
diff --git a/crates/ra_hir_ty/src/test_db.rs b/crates/ra_hir_ty/src/test_db.rs
index 0481a7b12..fddf0604d 100644
--- a/crates/ra_hir_ty/src/test_db.rs
+++ b/crates/ra_hir_ty/src/test_db.rs
@@ -8,8 +8,10 @@ use std::{
8use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId, ModuleId}; 8use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId, ModuleId};
9use hir_expand::{db::AstDatabase, diagnostics::DiagnosticSink}; 9use hir_expand::{db::AstDatabase, diagnostics::DiagnosticSink};
10use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast}; 10use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast};
11use rustc_hash::FxHashSet; 11use ra_syntax::TextRange;
12use rustc_hash::{FxHashMap, FxHashSet};
12use stdx::format_to; 13use stdx::format_to;
14use test_utils::extract_annotations;
13 15
14use crate::{ 16use crate::{
15 db::HirDatabase, diagnostics::Diagnostic, expr::ExprValidator, 17 db::HirDatabase, diagnostics::Diagnostic, expr::ExprValidator,
@@ -155,17 +157,27 @@ impl TestDB {
155 (buf, count) 157 (buf, count)
156 } 158 }
157 159
158 pub fn all_files(&self) -> Vec<FileId> { 160 pub fn extract_annotations(&self) -> FxHashMap<FileId, Vec<(TextRange, String)>> {
159 let mut res = Vec::new(); 161 let mut files = Vec::new();
160 let crate_graph = self.crate_graph(); 162 let crate_graph = self.crate_graph();
161 for krate in crate_graph.iter() { 163 for krate in crate_graph.iter() {
162 let crate_def_map = self.crate_def_map(krate); 164 let crate_def_map = self.crate_def_map(krate);
163 for (module_id, _) in crate_def_map.modules.iter() { 165 for (module_id, _) in crate_def_map.modules.iter() {
164 let file_id = crate_def_map[module_id].origin.file_id(); 166 let file_id = crate_def_map[module_id].origin.file_id();
165 res.extend(file_id) 167 files.extend(file_id)
166 } 168 }
167 } 169 }
168 res 170 files
171 .into_iter()
172 .filter_map(|file_id| {
173 let text = self.file_text(file_id);
174 let annotations = extract_annotations(&text);
175 if annotations.is_empty() {
176 return None;
177 }
178 Some((file_id, annotations))
179 })
180 .collect()
169 } 181 }
170} 182}
171 183
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs
index 5424e6bb1..eeac34d14 100644
--- a/crates/ra_hir_ty/src/tests.rs
+++ b/crates/ra_hir_ty/src/tests.rs
@@ -28,7 +28,6 @@ use ra_syntax::{
28 SyntaxNode, 28 SyntaxNode,
29}; 29};
30use stdx::format_to; 30use stdx::format_to;
31use test_utils::extract_annotations;
32 31
33use crate::{ 32use crate::{
34 db::HirDatabase, display::HirDisplay, infer::TypeMismatch, test_db::TestDB, InferenceResult, Ty, 33 db::HirDatabase, display::HirDisplay, infer::TypeMismatch, test_db::TestDB, InferenceResult, Ty,
@@ -49,9 +48,7 @@ fn check_types_source_code(ra_fixture: &str) {
49fn check_types_impl(ra_fixture: &str, display_source: bool) { 48fn check_types_impl(ra_fixture: &str, display_source: bool) {
50 let db = TestDB::with_files(ra_fixture); 49 let db = TestDB::with_files(ra_fixture);
51 let mut checked_one = false; 50 let mut checked_one = false;
52 for file_id in db.all_files() { 51 for (file_id, annotations) in db.extract_annotations() {
53 let text = db.parse(file_id).syntax_node().to_string();
54 let annotations = extract_annotations(&text);
55 for (range, expected) in annotations { 52 for (range, expected) in annotations {
56 let ty = type_at_range(&db, FileRange { file_id, range }); 53 let ty = type_at_range(&db, FileRange { file_id, range });
57 let actual = if display_source { 54 let actual = if display_source {
@@ -511,6 +508,30 @@ fn no_such_field_with_feature_flag_diagnostics_on_struct_fields() {
511} 508}
512 509
513#[test] 510#[test]
511fn no_such_field_with_type_macro() {
512 let diagnostics = TestDB::with_files(
513 r"
514 macro_rules! Type {
515 () => { u32 };
516 }
517
518 struct Foo {
519 bar: Type![],
520 }
521 impl Foo {
522 fn new() -> Self {
523 Foo { bar: 0 }
524 }
525 }
526 ",
527 )
528 .diagnostics()
529 .0;
530
531 assert_snapshot!(diagnostics, @r###""###);
532}
533
534#[test]
514fn missing_record_pat_field_diagnostic() { 535fn missing_record_pat_field_diagnostic() {
515 let diagnostics = TestDB::with_files( 536 let diagnostics = TestDB::with_files(
516 r" 537 r"
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs
index 01c919a7e..766790576 100644
--- a/crates/ra_hir_ty/src/tests/traits.rs
+++ b/crates/ra_hir_ty/src/tests/traits.rs
@@ -3029,3 +3029,21 @@ fn infer_dyn_fn_output() {
3029 "### 3029 "###
3030 ); 3030 );
3031} 3031}
3032
3033#[test]
3034fn variable_kinds() {
3035 check_types(
3036 r#"
3037trait Trait<T> { fn get(self, t: T) -> T; }
3038struct S;
3039impl Trait<u128> for S {}
3040impl Trait<f32> for S {}
3041fn test() {
3042 S.get(1);
3043 //^^^^^^^^ u128
3044 S.get(1.);
3045 //^^^^^^^^ f32
3046}
3047 "#,
3048 );
3049}
diff --git a/crates/ra_hir_ty/src/traits.rs b/crates/ra_hir_ty/src/traits.rs
index 6f43c3a22..2a6d7faef 100644
--- a/crates/ra_hir_ty/src/traits.rs
+++ b/crates/ra_hir_ty/src/traits.rs
@@ -1,5 +1,5 @@
1//! Trait solving using Chalk. 1//! Trait solving using Chalk.
2use std::{panic, sync::Arc}; 2use std::sync::Arc;
3 3
4use chalk_ir::cast::Cast; 4use chalk_ir::cast::Cast;
5use hir_def::{ 5use hir_def::{
@@ -8,7 +8,7 @@ use hir_def::{
8use ra_db::{impl_intern_key, salsa, CrateId}; 8use ra_db::{impl_intern_key, salsa, CrateId};
9use ra_prof::profile; 9use ra_prof::profile;
10 10
11use crate::{db::HirDatabase, DebruijnIndex}; 11use crate::{db::HirDatabase, DebruijnIndex, Substs};
12 12
13use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk}; 13use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk};
14 14
@@ -190,15 +190,7 @@ fn solution_from_chalk(
190 solution: chalk_solve::Solution<Interner>, 190 solution: chalk_solve::Solution<Interner>,
191) -> Solution { 191) -> Solution {
192 let convert_subst = |subst: chalk_ir::Canonical<chalk_ir::Substitution<Interner>>| { 192 let convert_subst = |subst: chalk_ir::Canonical<chalk_ir::Substitution<Interner>>| {
193 let value = subst 193 let result = from_chalk(db, subst);
194 .value
195 .iter(&Interner)
196 .map(|p| match p.ty(&Interner) {
197 Some(ty) => from_chalk(db, ty.clone()),
198 None => unimplemented!(),
199 })
200 .collect();
201 let result = Canonical { value, num_vars: subst.binders.len(&Interner) };
202 SolutionVariables(result) 194 SolutionVariables(result)
203 }; 195 };
204 match solution { 196 match solution {
@@ -222,7 +214,7 @@ fn solution_from_chalk(
222} 214}
223 215
224#[derive(Clone, Debug, PartialEq, Eq)] 216#[derive(Clone, Debug, PartialEq, Eq)]
225pub struct SolutionVariables(pub Canonical<Vec<Ty>>); 217pub struct SolutionVariables(pub Canonical<Substs>);
226 218
227#[derive(Clone, Debug, PartialEq, Eq)] 219#[derive(Clone, Debug, PartialEq, Eq)]
228/// A (possible) solution for a proposed goal. 220/// A (possible) solution for a proposed goal.
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs
index 8ef4941c0..c97b81d57 100644
--- a/crates/ra_hir_ty/src/traits/chalk.rs
+++ b/crates/ra_hir_ty/src/traits/chalk.rs
@@ -77,8 +77,8 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
77 // Note: Since we're using impls_for_trait, only impls where the trait 77 // Note: Since we're using impls_for_trait, only impls where the trait
78 // can be resolved should ever reach Chalk. `impl_datum` relies on that 78 // can be resolved should ever reach Chalk. `impl_datum` relies on that
79 // and will panic if the trait can't be resolved. 79 // and will panic if the trait can't be resolved.
80 let in_deps = self.db.impls_from_deps(self.krate); 80 let in_deps = self.db.trait_impls_in_deps(self.krate);
81 let in_self = self.db.impls_in_crate(self.krate); 81 let in_self = self.db.trait_impls_in_crate(self.krate);
82 let impl_maps = [in_deps, in_self]; 82 let impl_maps = [in_deps, in_self];
83 83
84 let id_to_chalk = |id: hir_def::ImplId| Impl::ImplDef(id).to_chalk(self.db); 84 let id_to_chalk = |id: hir_def::ImplId| Impl::ImplDef(id).to_chalk(self.db);
@@ -87,14 +87,12 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
87 Some(fp) => impl_maps 87 Some(fp) => impl_maps
88 .iter() 88 .iter()
89 .flat_map(|crate_impl_defs| { 89 .flat_map(|crate_impl_defs| {
90 crate_impl_defs.lookup_impl_defs_for_trait_and_ty(trait_, fp).map(id_to_chalk) 90 crate_impl_defs.for_trait_and_self_ty(trait_, fp).map(id_to_chalk)
91 }) 91 })
92 .collect(), 92 .collect(),
93 None => impl_maps 93 None => impl_maps
94 .iter() 94 .iter()
95 .flat_map(|crate_impl_defs| { 95 .flat_map(|crate_impl_defs| crate_impl_defs.for_trait(trait_).map(id_to_chalk))
96 crate_impl_defs.lookup_impl_defs_for_trait(trait_).map(id_to_chalk)
97 })
98 .collect(), 96 .collect(),
99 }; 97 };
100 98
diff --git a/crates/ra_hir_ty/src/traits/chalk/mapping.rs b/crates/ra_hir_ty/src/traits/chalk/mapping.rs
index ac82ea831..433d6aa03 100644
--- a/crates/ra_hir_ty/src/traits/chalk/mapping.rs
+++ b/crates/ra_hir_ty/src/traits/chalk/mapping.rs
@@ -17,7 +17,7 @@ use crate::{
17 primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness}, 17 primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness},
18 traits::{builtin, AssocTyValue, Canonical, Impl, Obligation}, 18 traits::{builtin, AssocTyValue, Canonical, Impl, Obligation},
19 ApplicationTy, CallableDef, GenericPredicate, InEnvironment, OpaqueTy, OpaqueTyId, 19 ApplicationTy, CallableDef, GenericPredicate, InEnvironment, OpaqueTy, OpaqueTyId,
20 ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, 20 ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TyKind, TypeCtor,
21}; 21};
22 22
23use super::interner::*; 23use super::interner::*;
@@ -555,22 +555,39 @@ where
555 type Chalk = chalk_ir::Canonical<T::Chalk>; 555 type Chalk = chalk_ir::Canonical<T::Chalk>;
556 556
557 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Canonical<T::Chalk> { 557 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Canonical<T::Chalk> {
558 let parameter = chalk_ir::CanonicalVarKind::new( 558 let kinds = self
559 chalk_ir::VariableKind::Ty(chalk_ir::TyKind::General), 559 .kinds
560 chalk_ir::UniverseIndex::ROOT, 560 .iter()
561 ); 561 .map(|k| match k {
562 TyKind::General => chalk_ir::TyKind::General,
563 TyKind::Integer => chalk_ir::TyKind::Integer,
564 TyKind::Float => chalk_ir::TyKind::Float,
565 })
566 .map(|tk| {
567 chalk_ir::CanonicalVarKind::new(
568 chalk_ir::VariableKind::Ty(tk),
569 chalk_ir::UniverseIndex::ROOT,
570 )
571 });
562 let value = self.value.to_chalk(db); 572 let value = self.value.to_chalk(db);
563 chalk_ir::Canonical { 573 chalk_ir::Canonical { value, binders: chalk_ir::CanonicalVarKinds::from(&Interner, kinds) }
564 value,
565 binders: chalk_ir::CanonicalVarKinds::from(&Interner, vec![parameter; self.num_vars]),
566 }
567 } 574 }
568 575
569 fn from_chalk(db: &dyn HirDatabase, canonical: chalk_ir::Canonical<T::Chalk>) -> Canonical<T> { 576 fn from_chalk(db: &dyn HirDatabase, canonical: chalk_ir::Canonical<T::Chalk>) -> Canonical<T> {
570 Canonical { 577 let kinds = canonical
571 num_vars: canonical.binders.len(&Interner), 578 .binders
572 value: from_chalk(db, canonical.value), 579 .iter(&Interner)
573 } 580 .map(|k| match k.kind {
581 chalk_ir::VariableKind::Ty(tk) => match tk {
582 chalk_ir::TyKind::General => TyKind::General,
583 chalk_ir::TyKind::Integer => TyKind::Integer,
584 chalk_ir::TyKind::Float => TyKind::Float,
585 },
586 chalk_ir::VariableKind::Lifetime => panic!("unexpected lifetime from Chalk"),
587 chalk_ir::VariableKind::Const(_) => panic!("unexpected const from Chalk"),
588 })
589 .collect();
590 Canonical { kinds, value: from_chalk(db, canonical.value) }
574 } 591 }
575} 592}
576 593
diff --git a/crates/ra_ide/Cargo.toml b/crates/ra_ide/Cargo.toml
index bbc6a5c9b..8e8892309 100644
--- a/crates/ra_ide/Cargo.toml
+++ b/crates/ra_ide/Cargo.toml
@@ -28,6 +28,7 @@ ra_cfg = { path = "../ra_cfg" }
28ra_fmt = { path = "../ra_fmt" } 28ra_fmt = { path = "../ra_fmt" }
29ra_prof = { path = "../ra_prof" } 29ra_prof = { path = "../ra_prof" }
30test_utils = { path = "../test_utils" } 30test_utils = { path = "../test_utils" }
31expect = { path = "../expect" }
31ra_assists = { path = "../ra_assists" } 32ra_assists = { path = "../ra_assists" }
32ra_ssr = { path = "../ra_ssr" } 33ra_ssr = { path = "../ra_ssr" }
33 34
diff --git a/crates/ra_ide/src/call_hierarchy.rs b/crates/ra_ide/src/call_hierarchy.rs
index 1e3a31602..884353808 100644
--- a/crates/ra_ide/src/call_hierarchy.rs
+++ b/crates/ra_ide/src/call_hierarchy.rs
@@ -39,10 +39,11 @@ pub(crate) fn call_hierarchy(
39 39
40pub(crate) fn incoming_calls(db: &RootDatabase, position: FilePosition) -> Option<Vec<CallItem>> { 40pub(crate) fn incoming_calls(db: &RootDatabase, position: FilePosition) -> Option<Vec<CallItem>> {
41 let sema = Semantics::new(db); 41 let sema = Semantics::new(db);
42
42 // 1. Find all refs 43 // 1. Find all refs
43 // 2. Loop through refs and determine unique fndef. This will become our `from: CallHierarchyItem,` in the reply. 44 // 2. Loop through refs and determine unique fndef. This will become our `from: CallHierarchyItem,` in the reply.
44 // 3. Add ranges relative to the start of the fndef. 45 // 3. Add ranges relative to the start of the fndef.
45 let refs = references::find_all_refs(db, position, None)?; 46 let refs = references::find_all_refs(&sema, position, None)?;
46 47
47 let mut calls = CallLocations::default(); 48 let mut calls = CallLocations::default();
48 49
@@ -355,4 +356,41 @@ fn caller3() {
355 &["caller3 FN_DEF FileId(1) 66..83 69..76 : [52..59]"], 356 &["caller3 FN_DEF FileId(1) 66..83 69..76 : [52..59]"],
356 ); 357 );
357 } 358 }
359
360 #[test]
361 fn test_call_hierarchy_issue_5103() {
362 check_hierarchy(
363 r#"
364fn a() {
365 b()
366}
367
368fn b() {}
369
370fn main() {
371 a<|>()
372}
373"#,
374 "a FN_DEF FileId(1) 0..18 3..4",
375 &["main FN_DEF FileId(1) 31..52 34..38 : [47..48]"],
376 &["b FN_DEF FileId(1) 20..29 23..24 : [13..14]"],
377 );
378
379 check_hierarchy(
380 r#"
381fn a() {
382 b<|>()
383}
384
385fn b() {}
386
387fn main() {
388 a()
389}
390"#,
391 "b FN_DEF FileId(1) 20..29 23..24",
392 &["a FN_DEF FileId(1) 0..18 3..4 : [13..14]"],
393 &[],
394 );
395 }
358} 396}
diff --git a/crates/ra_ide/src/completion.rs b/crates/ra_ide/src/completion.rs
index e1fcf379d..9ebb8ebb7 100644
--- a/crates/ra_ide/src/completion.rs
+++ b/crates/ra_ide/src/completion.rs
@@ -63,11 +63,11 @@ pub use crate::completion::{
63// There also snippet completions: 63// There also snippet completions:
64// 64//
65// .Expressions 65// .Expressions
66// - `pd` -> `println!("{:?}")` 66// - `pd` -> `eprintln!(" = {:?}", );")`
67// - `ppd` -> `println!("{:#?}")` 67// - `ppd` -> `eprintln!(" = {:#?}", );`
68// 68//
69// .Items 69// .Items
70// - `tfn` -> `#[test] fn f(){}` 70// - `tfn` -> `#[test] fn feature(){}`
71// - `tmod` -> 71// - `tmod` ->
72// ```rust 72// ```rust
73// #[cfg(test)] 73// #[cfg(test)]
@@ -75,7 +75,7 @@ pub use crate::completion::{
75// use super::*; 75// use super::*;
76// 76//
77// #[test] 77// #[test]
78// fn test_fn() {} 78// fn test_name() {}
79// } 79// }
80// ``` 80// ```
81 81
@@ -137,8 +137,8 @@ mod tests {
137 documentation: &'a str, 137 documentation: &'a str,
138 } 138 }
139 139
140 fn check_detail_and_documentation(fixture: &str, expected: DetailAndDocumentation) { 140 fn check_detail_and_documentation(ra_fixture: &str, expected: DetailAndDocumentation) {
141 let (analysis, position) = analysis_and_position(fixture); 141 let (analysis, position) = analysis_and_position(ra_fixture);
142 let config = CompletionConfig::default(); 142 let config = CompletionConfig::default();
143 let completions = analysis.completions(&config, position).unwrap().unwrap(); 143 let completions = analysis.completions(&config, position).unwrap().unwrap();
144 for item in completions { 144 for item in completions {
diff --git a/crates/ra_ide/src/completion/complete_keyword.rs b/crates/ra_ide/src/completion/complete_keyword.rs
index 3b174f916..e599cc3d1 100644
--- a/crates/ra_ide/src/completion/complete_keyword.rs
+++ b/crates/ra_ide/src/completion/complete_keyword.rs
@@ -1,6 +1,6 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use ra_syntax::ast; 3use ra_syntax::{ast, SyntaxKind};
4 4
5use crate::completion::{ 5use crate::completion::{
6 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, 6 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
@@ -37,6 +37,10 @@ pub(super) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionC
37} 37}
38 38
39pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) { 39pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) {
40 if ctx.token.kind() == SyntaxKind::COMMENT {
41 return;
42 }
43
40 let has_trait_or_impl_parent = ctx.has_impl_parent || ctx.has_trait_parent; 44 let has_trait_or_impl_parent = ctx.has_impl_parent || ctx.has_trait_parent;
41 if ctx.trait_as_prev_sibling || ctx.impl_as_prev_sibling { 45 if ctx.trait_as_prev_sibling || ctx.impl_as_prev_sibling {
42 add_keyword(ctx, acc, "where", "where "); 46 add_keyword(ctx, acc, "where", "where ");
diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs
index 560fb19e6..ef22ea54d 100644
--- a/crates/ra_ide/src/completion/completion_context.rs
+++ b/crates/ra_ide/src/completion/completion_context.rs
@@ -213,7 +213,7 @@ impl<'a> CompletionContext<'a> {
213 } 213 }
214 } 214 }
215 215
216 pub(crate) fn scope(&self) -> SemanticsScope<'_, RootDatabase> { 216 pub(crate) fn scope(&self) -> SemanticsScope<'_> {
217 self.sema.scope_at_offset(&self.token.parent(), self.offset) 217 self.sema.scope_at_offset(&self.token.parent(), self.offset)
218 } 218 }
219 219
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs
index 4fdc2f0bb..b18279746 100644
--- a/crates/ra_ide/src/completion/presentation.rs
+++ b/crates/ra_ide/src/completion/presentation.rs
@@ -1516,4 +1516,54 @@ mod tests {
1516 "### 1516 "###
1517 ); 1517 );
1518 } 1518 }
1519
1520 #[test]
1521 fn no_keyword_autocompletion_on_line_comments() {
1522 assert_debug_snapshot!(
1523 do_completion(
1524 r"
1525 fn test() {
1526 let x = 2; // A comment<|>
1527 }
1528 ",
1529 CompletionKind::Keyword
1530 ),
1531 @r###"
1532 []
1533 "###
1534 );
1535 }
1536
1537 #[test]
1538 fn no_keyword_autocompletion_on_multi_line_comments() {
1539 assert_debug_snapshot!(
1540 do_completion(
1541 r"
1542 /*
1543 Some multi-line comment<|>
1544 */
1545 ",
1546 CompletionKind::Keyword
1547 ),
1548 @r###"
1549 []
1550 "###
1551 );
1552 }
1553
1554 #[test]
1555 fn no_keyword_autocompletion_on_doc_comments() {
1556 assert_debug_snapshot!(
1557 do_completion(
1558 r"
1559 /// Some doc comment
1560 /// let test<|> = 1
1561 ",
1562 CompletionKind::Keyword
1563 ),
1564 @r###"
1565 []
1566 "###
1567 );
1568 }
1519} 1569}
diff --git a/crates/ra_ide/src/diagnostics.rs b/crates/ra_ide/src/diagnostics.rs
index 05fb799d6..46f8c31c7 100644
--- a/crates/ra_ide/src/diagnostics.rs
+++ b/crates/ra_ide/src/diagnostics.rs
@@ -324,10 +324,10 @@ mod tests {
324 /// * a diagnostic is produced 324 /// * a diagnostic is produced
325 /// * this diagnostic touches the input cursor position 325 /// * this diagnostic touches the input cursor position
326 /// * that the contents of the file containing the cursor match `after` after the diagnostic fix is applied 326 /// * that the contents of the file containing the cursor match `after` after the diagnostic fix is applied
327 fn check_apply_diagnostic_fix_from_position(fixture: &str, after: &str) { 327 fn check_apply_diagnostic_fix_from_position(ra_fixture: &str, after: &str) {
328 let after = trim_indent(after); 328 let after = trim_indent(after);
329 329
330 let (analysis, file_position) = analysis_and_position(fixture); 330 let (analysis, file_position) = analysis_and_position(ra_fixture);
331 let diagnostic = analysis.diagnostics(file_position.file_id).unwrap().pop().unwrap(); 331 let diagnostic = analysis.diagnostics(file_position.file_id).unwrap().pop().unwrap();
332 let mut fix = diagnostic.fix.unwrap(); 332 let mut fix = diagnostic.fix.unwrap();
333 let edit = fix.source_change.source_file_edits.pop().unwrap().edit; 333 let edit = fix.source_change.source_file_edits.pop().unwrap().edit;
@@ -365,14 +365,14 @@ mod tests {
365 365
366 /// Takes a multi-file input fixture with annotated cursor position and checks that no diagnostics 366 /// Takes a multi-file input fixture with annotated cursor position and checks that no diagnostics
367 /// apply to the file containing the cursor. 367 /// apply to the file containing the cursor.
368 fn check_no_diagnostic_for_target_file(fixture: &str) { 368 fn check_no_diagnostic_for_target_file(ra_fixture: &str) {
369 let (analysis, file_position) = analysis_and_position(fixture); 369 let (analysis, file_position) = analysis_and_position(ra_fixture);
370 let diagnostics = analysis.diagnostics(file_position.file_id).unwrap(); 370 let diagnostics = analysis.diagnostics(file_position.file_id).unwrap();
371 assert_eq!(diagnostics.len(), 0); 371 assert_eq!(diagnostics.len(), 0);
372 } 372 }
373 373
374 fn check_no_diagnostic(content: &str) { 374 fn check_no_diagnostic(ra_fixture: &str) {
375 let (analysis, file_id) = single_file(content); 375 let (analysis, file_id) = single_file(ra_fixture);
376 let diagnostics = analysis.diagnostics(file_id).unwrap(); 376 let diagnostics = analysis.diagnostics(file_id).unwrap();
377 assert_eq!(diagnostics.len(), 0, "expected no diagnostic, found one"); 377 assert_eq!(diagnostics.len(), 0, "expected no diagnostic, found one");
378 } 378 }
@@ -473,7 +473,8 @@ mod tests {
473 473
474 #[test] 474 #[test]
475 fn test_wrap_return_type_not_applicable_when_expr_type_does_not_match_ok_type() { 475 fn test_wrap_return_type_not_applicable_when_expr_type_does_not_match_ok_type() {
476 let content = r#" 476 check_no_diagnostic_for_target_file(
477 r"
477 //- /main.rs 478 //- /main.rs
478 use core::result::Result::{self, Ok, Err}; 479 use core::result::Result::{self, Ok, Err};
479 480
@@ -485,13 +486,14 @@ mod tests {
485 pub mod result { 486 pub mod result {
486 pub enum Result<T, E> { Ok(T), Err(E) } 487 pub enum Result<T, E> { Ok(T), Err(E) }
487 } 488 }
488 "#; 489 ",
489 check_no_diagnostic_for_target_file(content); 490 );
490 } 491 }
491 492
492 #[test] 493 #[test]
493 fn test_wrap_return_type_not_applicable_when_return_type_is_not_result() { 494 fn test_wrap_return_type_not_applicable_when_return_type_is_not_result() {
494 let content = r#" 495 check_no_diagnostic_for_target_file(
496 r"
495 //- /main.rs 497 //- /main.rs
496 use core::result::Result::{self, Ok, Err}; 498 use core::result::Result::{self, Ok, Err};
497 499
@@ -508,8 +510,8 @@ mod tests {
508 pub mod result { 510 pub mod result {
509 pub enum Result<T, E> { Ok(T), Err(E) } 511 pub enum Result<T, E> { Ok(T), Err(E) }
510 } 512 }
511 "#; 513 ",
512 check_no_diagnostic_for_target_file(content); 514 );
513 } 515 }
514 516
515 #[test] 517 #[test]
@@ -618,7 +620,8 @@ mod tests {
618 620
619 #[test] 621 #[test]
620 fn test_fill_struct_fields_no_diagnostic() { 622 fn test_fill_struct_fields_no_diagnostic() {
621 let content = r" 623 check_no_diagnostic(
624 r"
622 struct TestStruct { 625 struct TestStruct {
623 one: i32, 626 one: i32,
624 two: i64, 627 two: i64,
@@ -628,14 +631,14 @@ mod tests {
628 let one = 1; 631 let one = 1;
629 let s = TestStruct{ one, two: 2 }; 632 let s = TestStruct{ one, two: 2 };
630 } 633 }
631 "; 634 ",
632 635 );
633 check_no_diagnostic(content);
634 } 636 }
635 637
636 #[test] 638 #[test]
637 fn test_fill_struct_fields_no_diagnostic_on_spread() { 639 fn test_fill_struct_fields_no_diagnostic_on_spread() {
638 let content = r" 640 check_no_diagnostic(
641 r"
639 struct TestStruct { 642 struct TestStruct {
640 one: i32, 643 one: i32,
641 two: i64, 644 two: i64,
@@ -645,9 +648,8 @@ mod tests {
645 let one = 1; 648 let one = 1;
646 let s = TestStruct{ ..a }; 649 let s = TestStruct{ ..a };
647 } 650 }
648 "; 651 ",
649 652 );
650 check_no_diagnostic(content);
651 } 653 }
652 654
653 #[test] 655 #[test]
diff --git a/crates/ra_ide/src/display/navigation_target.rs b/crates/ra_ide/src/display/navigation_target.rs
index 0b52b01ab..8bf2428ed 100644
--- a/crates/ra_ide/src/display/navigation_target.rs
+++ b/crates/ra_ide/src/display/navigation_target.rs
@@ -11,7 +11,7 @@ use ra_syntax::{
11 TextRange, 11 TextRange,
12}; 12};
13 13
14use crate::{FileRange, FileSymbol}; 14use crate::FileSymbol;
15 15
16use super::short_label::ShortLabel; 16use super::short_label::ShortLabel;
17 17
@@ -47,6 +47,19 @@ impl NavigationTarget {
47 pub fn range(&self) -> TextRange { 47 pub fn range(&self) -> TextRange {
48 self.focus_range.unwrap_or(self.full_range) 48 self.focus_range.unwrap_or(self.full_range)
49 } 49 }
50 /// A "most interesting" range withing the `full_range`.
51 ///
52 /// Typically, `full_range` is the whole syntax node,
53 /// including doc comments, and `focus_range` is the range of the identifier.
54 pub fn focus_range(&self) -> Option<TextRange> {
55 self.focus_range
56 }
57 pub fn full_range(&self) -> TextRange {
58 self.full_range
59 }
60 pub fn file_id(&self) -> FileId {
61 self.file_id
62 }
50 63
51 pub fn name(&self) -> &SmolStr { 64 pub fn name(&self) -> &SmolStr {
52 &self.name 65 &self.name
@@ -60,18 +73,6 @@ impl NavigationTarget {
60 self.kind 73 self.kind
61 } 74 }
62 75
63 pub fn file_id(&self) -> FileId {
64 self.file_id
65 }
66
67 pub fn file_range(&self) -> FileRange {
68 FileRange { file_id: self.file_id, range: self.full_range }
69 }
70
71 pub fn full_range(&self) -> TextRange {
72 self.full_range
73 }
74
75 pub fn docs(&self) -> Option<&str> { 76 pub fn docs(&self) -> Option<&str> {
76 self.docs.as_deref() 77 self.docs.as_deref()
77 } 78 }
@@ -80,14 +81,6 @@ impl NavigationTarget {
80 self.description.as_deref() 81 self.description.as_deref()
81 } 82 }
82 83
83 /// A "most interesting" range withing the `full_range`.
84 ///
85 /// Typically, `full_range` is the whole syntax node,
86 /// including doc comments, and `focus_range` is the range of the identifier.
87 pub fn focus_range(&self) -> Option<TextRange> {
88 self.focus_range
89 }
90
91 pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget { 84 pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget {
92 let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); 85 let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default();
93 if let Some(src) = module.declaration_source(db) { 86 if let Some(src) = module.declaration_source(db) {
@@ -278,16 +271,22 @@ impl ToNav for hir::Module {
278impl ToNav for hir::ImplDef { 271impl ToNav for hir::ImplDef {
279 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 272 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
280 let src = self.source(db); 273 let src = self.source(db);
281 let frange = if let Some(item) = self.is_builtin_derive(db) { 274 let derive_attr = self.is_builtin_derive(db);
275 let frange = if let Some(item) = &derive_attr {
282 original_range(db, item.syntax()) 276 original_range(db, item.syntax())
283 } else { 277 } else {
284 original_range(db, src.as_ref().map(|it| it.syntax())) 278 original_range(db, src.as_ref().map(|it| it.syntax()))
285 }; 279 };
280 let focus_range = if derive_attr.is_some() {
281 None
282 } else {
283 src.value.target_type().map(|ty| original_range(db, src.with_value(ty.syntax())).range)
284 };
286 285
287 NavigationTarget::from_syntax( 286 NavigationTarget::from_syntax(
288 frange.file_id, 287 frange.file_id,
289 "impl".into(), 288 "impl".into(),
290 None, 289 focus_range,
291 frange.range, 290 frange.range,
292 src.value.syntax().kind(), 291 src.value.syntax().kind(),
293 ) 292 )
diff --git a/crates/ra_ide/src/display/structure.rs b/crates/ra_ide/src/display/structure.rs
index aad5a8e4d..c22a5d17b 100644
--- a/crates/ra_ide/src/display/structure.rs
+++ b/crates/ra_ide/src/display/structure.rs
@@ -173,12 +173,19 @@ fn structure_node(node: &SyntaxNode) -> Option<StructureNode> {
173 173
174#[cfg(test)] 174#[cfg(test)]
175mod tests { 175mod tests {
176 use expect::{expect, Expect};
177
176 use super::*; 178 use super::*;
177 use insta::assert_debug_snapshot; 179
180 fn check(ra_fixture: &str, expect: Expect) {
181 let file = SourceFile::parse(ra_fixture).ok().unwrap();
182 let structure = file_structure(&file);
183 expect.assert_debug_eq(&structure)
184 }
178 185
179 #[test] 186 #[test]
180 fn test_file_structure() { 187 fn test_file_structure() {
181 let file = SourceFile::parse( 188 check(
182 r#" 189 r#"
183struct Foo { 190struct Foo {
184 x: i32 191 x: i32
@@ -223,216 +230,211 @@ fn obsolete() {}
223#[deprecated(note = "for awhile")] 230#[deprecated(note = "for awhile")]
224fn very_obsolete() {} 231fn very_obsolete() {}
225"#, 232"#,
226 ) 233 expect![[r#"
227 .ok() 234 [
228 .unwrap(); 235 StructureNode {
229 let structure = file_structure(&file); 236 parent: None,
230 assert_debug_snapshot!(structure, 237 label: "Foo",
231 @r###" 238 navigation_range: 8..11,
232 [ 239 node_range: 1..26,
233 StructureNode { 240 kind: STRUCT_DEF,
234 parent: None, 241 detail: None,
235 label: "Foo", 242 deprecated: false,
236 navigation_range: 8..11, 243 },
237 node_range: 1..26, 244 StructureNode {
238 kind: STRUCT_DEF, 245 parent: Some(
239 detail: None, 246 0,
240 deprecated: false, 247 ),
241 }, 248 label: "x",
242 StructureNode { 249 navigation_range: 18..19,
243 parent: Some( 250 node_range: 18..24,
244 0, 251 kind: RECORD_FIELD_DEF,
245 ), 252 detail: Some(
246 label: "x", 253 "i32",
247 navigation_range: 18..19, 254 ),
248 node_range: 18..24, 255 deprecated: false,
249 kind: RECORD_FIELD_DEF, 256 },
250 detail: Some( 257 StructureNode {
251 "i32", 258 parent: None,
252 ), 259 label: "m",
253 deprecated: false, 260 navigation_range: 32..33,
254 }, 261 node_range: 28..158,
255 StructureNode { 262 kind: MODULE,
256 parent: None, 263 detail: None,
257 label: "m", 264 deprecated: false,
258 navigation_range: 32..33, 265 },
259 node_range: 28..158, 266 StructureNode {
260 kind: MODULE, 267 parent: Some(
261 detail: None, 268 2,
262 deprecated: false, 269 ),
263 }, 270 label: "bar1",
264 StructureNode { 271 navigation_range: 43..47,
265 parent: Some( 272 node_range: 40..52,
266 2, 273 kind: FN_DEF,
267 ), 274 detail: Some(
268 label: "bar1", 275 "fn()",
269 navigation_range: 43..47, 276 ),
270 node_range: 40..52, 277 deprecated: false,
271 kind: FN_DEF, 278 },
272 detail: Some( 279 StructureNode {
273 "fn()", 280 parent: Some(
274 ), 281 2,
275 deprecated: false, 282 ),
276 }, 283 label: "bar2",
277 StructureNode { 284 navigation_range: 60..64,
278 parent: Some( 285 node_range: 57..81,
279 2, 286 kind: FN_DEF,
280 ), 287 detail: Some(
281 label: "bar2", 288 "fn<T>(t: T) -> T",
282 navigation_range: 60..64, 289 ),
283 node_range: 57..81, 290 deprecated: false,
284 kind: FN_DEF, 291 },
285 detail: Some( 292 StructureNode {
286 "fn<T>(t: T) -> T", 293 parent: Some(
287 ), 294 2,
288 deprecated: false, 295 ),
289 }, 296 label: "bar3",
290 StructureNode { 297 navigation_range: 89..93,
291 parent: Some( 298 node_range: 86..156,
292 2, 299 kind: FN_DEF,
293 ), 300 detail: Some(
294 label: "bar3", 301 "fn<A, B>(a: A, b: B) -> Vec< u32 >",
295 navigation_range: 89..93, 302 ),
296 node_range: 86..156, 303 deprecated: false,
297 kind: FN_DEF, 304 },
298 detail: Some( 305 StructureNode {
299 "fn<A, B>(a: A, b: B) -> Vec< u32 >", 306 parent: None,
300 ), 307 label: "E",
301 deprecated: false, 308 navigation_range: 165..166,
302 }, 309 node_range: 160..180,
303 StructureNode { 310 kind: ENUM_DEF,
304 parent: None, 311 detail: None,
305 label: "E", 312 deprecated: false,
306 navigation_range: 165..166, 313 },
307 node_range: 160..180, 314 StructureNode {
308 kind: ENUM_DEF, 315 parent: Some(
309 detail: None, 316 6,
310 deprecated: false, 317 ),
311 }, 318 label: "X",
312 StructureNode { 319 navigation_range: 169..170,
313 parent: Some( 320 node_range: 169..170,
314 6, 321 kind: ENUM_VARIANT,
315 ), 322 detail: None,
316 label: "X", 323 deprecated: false,
317 navigation_range: 169..170, 324 },
318 node_range: 169..170, 325 StructureNode {
319 kind: ENUM_VARIANT, 326 parent: Some(
320 detail: None, 327 6,
321 deprecated: false, 328 ),
322 }, 329 label: "Y",
323 StructureNode { 330 navigation_range: 172..173,
324 parent: Some( 331 node_range: 172..178,
325 6, 332 kind: ENUM_VARIANT,
326 ), 333 detail: None,
327 label: "Y", 334 deprecated: false,
328 navigation_range: 172..173, 335 },
329 node_range: 172..178, 336 StructureNode {
330 kind: ENUM_VARIANT, 337 parent: None,
331 detail: None, 338 label: "T",
332 deprecated: false, 339 navigation_range: 186..187,
333 }, 340 node_range: 181..193,
334 StructureNode { 341 kind: TYPE_ALIAS_DEF,
335 parent: None, 342 detail: Some(
336 label: "T", 343 "()",
337 navigation_range: 186..187, 344 ),
338 node_range: 181..193, 345 deprecated: false,
339 kind: TYPE_ALIAS_DEF, 346 },
340 detail: Some( 347 StructureNode {
341 "()", 348 parent: None,
342 ), 349 label: "S",
343 deprecated: false, 350 navigation_range: 201..202,
344 }, 351 node_range: 194..213,
345 StructureNode { 352 kind: STATIC_DEF,
346 parent: None, 353 detail: Some(
347 label: "S", 354 "i32",
348 navigation_range: 201..202, 355 ),
349 node_range: 194..213, 356 deprecated: false,
350 kind: STATIC_DEF, 357 },
351 detail: Some( 358 StructureNode {
352 "i32", 359 parent: None,
353 ), 360 label: "C",
354 deprecated: false, 361 navigation_range: 220..221,
355 }, 362 node_range: 214..232,
356 StructureNode { 363 kind: CONST_DEF,
357 parent: None, 364 detail: Some(
358 label: "C", 365 "i32",
359 navigation_range: 220..221, 366 ),
360 node_range: 214..232, 367 deprecated: false,
361 kind: CONST_DEF, 368 },
362 detail: Some( 369 StructureNode {
363 "i32", 370 parent: None,
364 ), 371 label: "impl E",
365 deprecated: false, 372 navigation_range: 239..240,
366 }, 373 node_range: 234..243,
367 StructureNode { 374 kind: IMPL_DEF,
368 parent: None, 375 detail: None,
369 label: "impl E", 376 deprecated: false,
370 navigation_range: 239..240, 377 },
371 node_range: 234..243, 378 StructureNode {
372 kind: IMPL_DEF, 379 parent: None,
373 detail: None, 380 label: "impl fmt::Debug for E",
374 deprecated: false, 381 navigation_range: 265..266,
375 }, 382 node_range: 245..269,
376 StructureNode { 383 kind: IMPL_DEF,
377 parent: None, 384 detail: None,
378 label: "impl fmt::Debug for E", 385 deprecated: false,
379 navigation_range: 265..266, 386 },
380 node_range: 245..269, 387 StructureNode {
381 kind: IMPL_DEF, 388 parent: None,
382 detail: None, 389 label: "mc",
383 deprecated: false, 390 navigation_range: 284..286,
384 }, 391 node_range: 271..303,
385 StructureNode { 392 kind: MACRO_CALL,
386 parent: None, 393 detail: None,
387 label: "mc", 394 deprecated: false,
388 navigation_range: 284..286, 395 },
389 node_range: 271..303, 396 StructureNode {
390 kind: MACRO_CALL, 397 parent: None,
391 detail: None, 398 label: "mcexp",
392 deprecated: false, 399 navigation_range: 334..339,
393 }, 400 node_range: 305..356,
394 StructureNode { 401 kind: MACRO_CALL,
395 parent: None, 402 detail: None,
396 label: "mcexp", 403 deprecated: false,
397 navigation_range: 334..339, 404 },
398 node_range: 305..356, 405 StructureNode {
399 kind: MACRO_CALL, 406 parent: None,
400 detail: None, 407 label: "mcexp",
401 deprecated: false, 408 navigation_range: 387..392,
402 }, 409 node_range: 358..409,
403 StructureNode { 410 kind: MACRO_CALL,
404 parent: None, 411 detail: None,
405 label: "mcexp", 412 deprecated: false,
406 navigation_range: 387..392, 413 },
407 node_range: 358..409, 414 StructureNode {
408 kind: MACRO_CALL, 415 parent: None,
409 detail: None, 416 label: "obsolete",
410 deprecated: false, 417 navigation_range: 428..436,
411 }, 418 node_range: 411..441,
412 StructureNode { 419 kind: FN_DEF,
413 parent: None, 420 detail: Some(
414 label: "obsolete", 421 "fn()",
415 navigation_range: 428..436, 422 ),
416 node_range: 411..441, 423 deprecated: true,
417 kind: FN_DEF, 424 },
418 detail: Some( 425 StructureNode {
419 "fn()", 426 parent: None,
420 ), 427 label: "very_obsolete",
421 deprecated: true, 428 navigation_range: 481..494,
422 }, 429 node_range: 443..499,
423 StructureNode { 430 kind: FN_DEF,
424 parent: None, 431 detail: Some(
425 label: "very_obsolete", 432 "fn()",
426 navigation_range: 481..494, 433 ),
427 node_range: 443..499, 434 deprecated: true,
428 kind: FN_DEF, 435 },
429 detail: Some( 436 ]
430 "fn()", 437 "#]],
431 ), 438 );
432 deprecated: true,
433 },
434 ]
435 "###
436 );
437 } 439 }
438} 440}
diff --git a/crates/ra_ide/src/expand_macro.rs b/crates/ra_ide/src/expand_macro.rs
index 54a47aac0..043515f54 100644
--- a/crates/ra_ide/src/expand_macro.rs
+++ b/crates/ra_ide/src/expand_macro.rs
@@ -2,7 +2,9 @@ use hir::Semantics;
2use ra_ide_db::RootDatabase; 2use ra_ide_db::RootDatabase;
3use ra_syntax::{ 3use ra_syntax::{
4 algo::{find_node_at_offset, SyntaxRewriter}, 4 algo::{find_node_at_offset, SyntaxRewriter},
5 ast, AstNode, NodeOrToken, SyntaxKind, SyntaxNode, WalkEvent, T, 5 ast, AstNode, NodeOrToken, SyntaxKind,
6 SyntaxKind::*,
7 SyntaxNode, WalkEvent, T,
6}; 8};
7 9
8use crate::FilePosition; 10use crate::FilePosition;
@@ -65,8 +67,6 @@ fn expand_macro_recur(
65// FIXME: It would also be cool to share logic here and in the mbe tests, 67// FIXME: It would also be cool to share logic here and in the mbe tests,
66// which are pretty unreadable at the moment. 68// which are pretty unreadable at the moment.
67fn insert_whitespaces(syn: SyntaxNode) -> String { 69fn insert_whitespaces(syn: SyntaxNode) -> String {
68 use SyntaxKind::*;
69
70 let mut res = String::new(); 70 let mut res = String::new();
71 let mut token_iter = syn 71 let mut token_iter = syn
72 .preorder_with_tokens() 72 .preorder_with_tokens()
@@ -120,175 +120,164 @@ fn insert_whitespaces(syn: SyntaxNode) -> String {
120 120
121#[cfg(test)] 121#[cfg(test)]
122mod tests { 122mod tests {
123 use insta::assert_snapshot; 123 use expect::{expect, Expect};
124 124
125 use crate::mock_analysis::analysis_and_position; 125 use crate::mock_analysis::analysis_and_position;
126 126
127 use super::*; 127 fn check(ra_fixture: &str, expect: Expect) {
128 128 let (analysis, pos) = analysis_and_position(ra_fixture);
129 fn check_expand_macro(fixture: &str) -> ExpandedMacro { 129 let expansion = analysis.expand_macro(pos).unwrap().unwrap();
130 let (analysis, pos) = analysis_and_position(fixture); 130 let actual = format!("{}\n{}", expansion.name, expansion.expansion);
131 analysis.expand_macro(pos).unwrap().unwrap() 131 expect.assert_eq(&actual);
132 } 132 }
133 133
134 #[test] 134 #[test]
135 fn macro_expand_recursive_expansion() { 135 fn macro_expand_recursive_expansion() {
136 let res = check_expand_macro( 136 check(
137 r#" 137 r#"
138 //- /lib.rs 138macro_rules! bar {
139 macro_rules! bar { 139 () => { fn b() {} }
140 () => { fn b() {} } 140}
141 } 141macro_rules! foo {
142 macro_rules! foo { 142 () => { bar!(); }
143 () => { bar!(); } 143}
144 } 144macro_rules! baz {
145 macro_rules! baz { 145 () => { foo!(); }
146 () => { foo!(); } 146}
147 } 147f<|>oo!();
148 f<|>oo!(); 148"#,
149 "#, 149 expect![[r#"
150 foo
151 fn b(){}
152 "#]],
150 ); 153 );
151
152 assert_eq!(res.name, "foo");
153 assert_snapshot!(res.expansion, @r###"
154fn b(){}
155"###);
156 } 154 }
157 155
158 #[test] 156 #[test]
159 fn macro_expand_multiple_lines() { 157 fn macro_expand_multiple_lines() {
160 let res = check_expand_macro( 158 check(
161 r#" 159 r#"
162 //- /lib.rs 160macro_rules! foo {
163 macro_rules! foo { 161 () => {
164 () => { 162 fn some_thing() -> u32 {
165 fn some_thing() -> u32 { 163 let a = 0;
166 let a = 0; 164 a + 10
167 a + 10
168 }
169 }
170 } 165 }
171 f<|>oo!(); 166 }
167}
168f<|>oo!();
172 "#, 169 "#,
170 expect![[r#"
171 foo
172 fn some_thing() -> u32 {
173 let a = 0;
174 a+10
175 }"#]],
173 ); 176 );
174
175 assert_eq!(res.name, "foo");
176 assert_snapshot!(res.expansion, @r###"
177fn some_thing() -> u32 {
178 let a = 0;
179 a+10
180}
181"###);
182 } 177 }
183 178
184 #[test] 179 #[test]
185 fn macro_expand_match_ast() { 180 fn macro_expand_match_ast() {
186 let res = check_expand_macro( 181 check(
187 r#" 182 r#"
188 //- /lib.rs 183macro_rules! match_ast {
189 macro_rules! match_ast { 184 (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) };
190 (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) }; 185 (match ($node:expr) {
186 $( ast::$ast:ident($it:ident) => $res:block, )*
187 _ => $catch_all:expr $(,)?
188 }) => {{
189 $( if let Some($it) = ast::$ast::cast($node.clone()) $res else )*
190 { $catch_all }
191 }};
192}
191 193
192 (match ($node:expr) { 194fn main() {
193 $( ast::$ast:ident($it:ident) => $res:block, )* 195 mat<|>ch_ast! {
194 _ => $catch_all:expr $(,)? 196 match container {
195 }) => {{ 197 ast::TraitDef(it) => {},
196 $( if let Some($it) = ast::$ast::cast($node.clone()) $res else )* 198 ast::ImplDef(it) => {},
197 { $catch_all } 199 _ => { continue },
198 }};
199 } 200 }
200
201 fn main() {
202 mat<|>ch_ast! {
203 match container {
204 ast::TraitDef(it) => {},
205 ast::ImplDef(it) => {},
206 _ => { continue },
207 }
208 }
209 }
210 "#,
211 );
212
213 assert_eq!(res.name, "match_ast");
214 assert_snapshot!(res.expansion, @r###"
215{
216 if let Some(it) = ast::TraitDef::cast(container.clone()){}
217 else if let Some(it) = ast::ImplDef::cast(container.clone()){}
218 else {
219 {
220 continue
221 } 201 }
222 }
223} 202}
224"###); 203"#,
204 expect![[r#"
205 match_ast
206 {
207 if let Some(it) = ast::TraitDef::cast(container.clone()){}
208 else if let Some(it) = ast::ImplDef::cast(container.clone()){}
209 else {
210 {
211 continue
212 }
213 }
214 }"#]],
215 );
225 } 216 }
226 217
227 #[test] 218 #[test]
228 fn macro_expand_match_ast_inside_let_statement() { 219 fn macro_expand_match_ast_inside_let_statement() {
229 let res = check_expand_macro( 220 check(
230 r#" 221 r#"
231 //- /lib.rs 222macro_rules! match_ast {
232 macro_rules! match_ast { 223 (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) };
233 (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) }; 224 (match ($node:expr) {}) => {{}};
234 (match ($node:expr) {}) => {{}}; 225}
235 }
236 226
237 fn main() { 227fn main() {
238 let p = f(|it| { 228 let p = f(|it| {
239 let res = mat<|>ch_ast! { match c {}}; 229 let res = mat<|>ch_ast! { match c {}};
240 Some(res) 230 Some(res)
241 })?; 231 })?;
242 } 232}
243 "#, 233"#,
234 expect![[r#"
235 match_ast
236 {}
237 "#]],
244 ); 238 );
245
246 assert_eq!(res.name, "match_ast");
247 assert_snapshot!(res.expansion, @r###"{}"###);
248 } 239 }
249 240
250 #[test] 241 #[test]
251 fn macro_expand_inner_macro_fail_to_expand() { 242 fn macro_expand_inner_macro_fail_to_expand() {
252 let res = check_expand_macro( 243 check(
253 r#" 244 r#"
254 //- /lib.rs 245macro_rules! bar {
255 macro_rules! bar { 246 (BAD) => {};
256 (BAD) => {}; 247}
257 } 248macro_rules! foo {
258 macro_rules! foo { 249 () => {bar!()};
259 () => {bar!()}; 250}
260 }
261 251
262 fn main() { 252fn main() {
263 let res = fo<|>o!(); 253 let res = fo<|>o!();
264 } 254}
265 "#, 255"#,
256 expect![[r#"
257 foo
258 "#]],
266 ); 259 );
267
268 assert_eq!(res.name, "foo");
269 assert_snapshot!(res.expansion, @r###""###);
270 } 260 }
271 261
272 #[test] 262 #[test]
273 fn macro_expand_with_dollar_crate() { 263 fn macro_expand_with_dollar_crate() {
274 let res = check_expand_macro( 264 check(
275 r#" 265 r#"
276 //- /lib.rs 266#[macro_export]
277 #[macro_export] 267macro_rules! bar {
278 macro_rules! bar { 268 () => {0};
279 () => {0}; 269}
280 } 270macro_rules! foo {
281 macro_rules! foo { 271 () => {$crate::bar!()};
282 () => {$crate::bar!()}; 272}
283 }
284 273
285 fn main() { 274fn main() {
286 let res = fo<|>o!(); 275 let res = fo<|>o!();
287 } 276}
288 "#, 277"#,
278 expect![[r#"
279 foo
280 0 "#]],
289 ); 281 );
290
291 assert_eq!(res.name, "foo");
292 assert_snapshot!(res.expansion, @r###"0"###);
293 } 282 }
294} 283}
diff --git a/crates/ra_ide/src/folding_ranges.rs b/crates/ra_ide/src/folding_ranges.rs
index 8657377de..5cec689f8 100644
--- a/crates/ra_ide/src/folding_ranges.rs
+++ b/crates/ra_ide/src/folding_ranges.rs
@@ -15,6 +15,7 @@ pub enum FoldKind {
15 Imports, 15 Imports,
16 Mods, 16 Mods,
17 Block, 17 Block,
18 ArgList,
18} 19}
19 20
20#[derive(Debug)] 21#[derive(Debug)]
@@ -83,6 +84,7 @@ fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
83 match kind { 84 match kind {
84 COMMENT => Some(FoldKind::Comment), 85 COMMENT => Some(FoldKind::Comment),
85 USE_ITEM => Some(FoldKind::Imports), 86 USE_ITEM => Some(FoldKind::Imports),
87 ARG_LIST => Some(FoldKind::ArgList),
86 RECORD_FIELD_DEF_LIST 88 RECORD_FIELD_DEF_LIST
87 | RECORD_FIELD_PAT_LIST 89 | RECORD_FIELD_PAT_LIST
88 | ITEM_LIST 90 | ITEM_LIST
@@ -196,89 +198,85 @@ fn contiguous_range_for_comment(
196 198
197#[cfg(test)] 199#[cfg(test)]
198mod tests { 200mod tests {
201 use test_utils::extract_tags;
202
199 use super::*; 203 use super::*;
200 use test_utils::extract_ranges;
201 204
202 fn do_check(text: &str, fold_kinds: &[FoldKind]) { 205 fn check(ra_fixture: &str) {
203 let (ranges, text) = extract_ranges(text, "fold"); 206 let (ranges, text) = extract_tags(ra_fixture, "fold");
207
204 let parse = SourceFile::parse(&text); 208 let parse = SourceFile::parse(&text);
205 let folds = folding_ranges(&parse.tree()); 209 let folds = folding_ranges(&parse.tree());
206
207 assert_eq!( 210 assert_eq!(
208 folds.len(), 211 folds.len(),
209 ranges.len(), 212 ranges.len(),
210 "The amount of folds is different than the expected amount" 213 "The amount of folds is different than the expected amount"
211 ); 214 );
212 assert_eq!( 215
213 folds.len(), 216 for (fold, (range, attr)) in folds.iter().zip(ranges.into_iter()) {
214 fold_kinds.len(),
215 "The amount of fold kinds is different than the expected amount"
216 );
217 for ((fold, range), fold_kind) in
218 folds.iter().zip(ranges.into_iter()).zip(fold_kinds.iter())
219 {
220 assert_eq!(fold.range.start(), range.start()); 217 assert_eq!(fold.range.start(), range.start());
221 assert_eq!(fold.range.end(), range.end()); 218 assert_eq!(fold.range.end(), range.end());
222 assert_eq!(&fold.kind, fold_kind); 219
220 let kind = match fold.kind {
221 FoldKind::Comment => "comment",
222 FoldKind::Imports => "imports",
223 FoldKind::Mods => "mods",
224 FoldKind::Block => "block",
225 FoldKind::ArgList => "arglist",
226 };
227 assert_eq!(kind, &attr.unwrap());
223 } 228 }
224 } 229 }
225 230
226 #[test] 231 #[test]
227 fn test_fold_comments() { 232 fn test_fold_comments() {
228 let text = r#" 233 check(
229<fold>// Hello 234 r#"
235<fold comment>// Hello
230// this is a multiline 236// this is a multiline
231// comment 237// comment
232//</fold> 238//</fold>
233 239
234// But this is not 240// But this is not
235 241
236fn main() <fold>{ 242fn main() <fold block>{
237 <fold>// We should 243 <fold comment>// We should
238 // also 244 // also
239 // fold 245 // fold
240 // this one.</fold> 246 // this one.</fold>
241 <fold>//! But this one is different 247 <fold comment>//! But this one is different
242 //! because it has another flavor</fold> 248 //! because it has another flavor</fold>
243 <fold>/* As does this 249 <fold comment>/* As does this
244 multiline comment */</fold> 250 multiline comment */</fold>
245}</fold>"#; 251}</fold>"#,
246 252 );
247 let fold_kinds = &[
248 FoldKind::Comment,
249 FoldKind::Block,
250 FoldKind::Comment,
251 FoldKind::Comment,
252 FoldKind::Comment,
253 ];
254 do_check(text, fold_kinds);
255 } 253 }
256 254
257 #[test] 255 #[test]
258 fn test_fold_imports() { 256 fn test_fold_imports() {
259 let text = r#" 257 check(
260<fold>use std::<fold>{ 258 r#"
259<fold imports>use std::<fold block>{
261 str, 260 str,
262 vec, 261 vec,
263 io as iop 262 io as iop
264}</fold>;</fold> 263}</fold>;</fold>
265 264
266fn main() <fold>{ 265fn main() <fold block>{
267}</fold>"#; 266}</fold>"#,
268 267 );
269 let folds = &[FoldKind::Imports, FoldKind::Block, FoldKind::Block];
270 do_check(text, folds);
271 } 268 }
272 269
273 #[test] 270 #[test]
274 fn test_fold_mods() { 271 fn test_fold_mods() {
275 let text = r#" 272 check(
273 r#"
276 274
277pub mod foo; 275pub mod foo;
278<fold>mod after_pub; 276<fold mods>mod after_pub;
279mod after_pub_next;</fold> 277mod after_pub_next;</fold>
280 278
281<fold>mod before_pub; 279<fold mods>mod before_pub;
282mod before_pub_next;</fold> 280mod before_pub_next;</fold>
283pub mod bar; 281pub mod bar;
284 282
@@ -286,90 +284,93 @@ mod not_folding_single;
286pub mod foobar; 284pub mod foobar;
287pub not_folding_single_next; 285pub not_folding_single_next;
288 286
289<fold>#[cfg(test)] 287<fold mods>#[cfg(test)]
290mod with_attribute; 288mod with_attribute;
291mod with_attribute_next;</fold> 289mod with_attribute_next;</fold>
292 290
293fn main() <fold>{ 291fn main() <fold block>{
294}</fold>"#; 292}</fold>"#,
295 293 );
296 let folds = &[FoldKind::Mods, FoldKind::Mods, FoldKind::Mods, FoldKind::Block];
297 do_check(text, folds);
298 } 294 }
299 295
300 #[test] 296 #[test]
301 fn test_fold_import_groups() { 297 fn test_fold_import_groups() {
302 let text = r#" 298 check(
303<fold>use std::str; 299 r#"
300<fold imports>use std::str;
304use std::vec; 301use std::vec;
305use std::io as iop;</fold> 302use std::io as iop;</fold>
306 303
307<fold>use std::mem; 304<fold imports>use std::mem;
308use std::f64;</fold> 305use std::f64;</fold>
309 306
310use std::collections::HashMap; 307use std::collections::HashMap;
311// Some random comment 308// Some random comment
312use std::collections::VecDeque; 309use std::collections::VecDeque;
313 310
314fn main() <fold>{ 311fn main() <fold block>{
315}</fold>"#; 312}</fold>"#,
316 313 );
317 let folds = &[FoldKind::Imports, FoldKind::Imports, FoldKind::Block];
318 do_check(text, folds);
319 } 314 }
320 315
321 #[test] 316 #[test]
322 fn test_fold_import_and_groups() { 317 fn test_fold_import_and_groups() {
323 let text = r#" 318 check(
324<fold>use std::str; 319 r#"
320<fold imports>use std::str;
325use std::vec; 321use std::vec;
326use std::io as iop;</fold> 322use std::io as iop;</fold>
327 323
328<fold>use std::mem; 324<fold imports>use std::mem;
329use std::f64;</fold> 325use std::f64;</fold>
330 326
331<fold>use std::collections::<fold>{ 327<fold imports>use std::collections::<fold block>{
332 HashMap, 328 HashMap,
333 VecDeque, 329 VecDeque,
334}</fold>;</fold> 330}</fold>;</fold>
335// Some random comment 331// Some random comment
336 332
337fn main() <fold>{ 333fn main() <fold block>{
338}</fold>"#; 334}</fold>"#,
339 335 );
340 let folds = &[
341 FoldKind::Imports,
342 FoldKind::Imports,
343 FoldKind::Imports,
344 FoldKind::Block,
345 FoldKind::Block,
346 ];
347 do_check(text, folds);
348 } 336 }
349 337
350 #[test] 338 #[test]
351 fn test_folds_macros() { 339 fn test_folds_macros() {
352 let text = r#" 340 check(
353macro_rules! foo <fold>{ 341 r#"
342macro_rules! foo <fold block>{
354 ($($tt:tt)*) => { $($tt)* } 343 ($($tt:tt)*) => { $($tt)* }
355}</fold> 344}</fold>
356"#; 345"#,
357 346 );
358 let folds = &[FoldKind::Block];
359 do_check(text, folds);
360 } 347 }
361 348
362 #[test] 349 #[test]
363 fn test_fold_match_arms() { 350 fn test_fold_match_arms() {
364 let text = r#" 351 check(
365fn main() <fold>{ 352 r#"
366 match 0 <fold>{ 353fn main() <fold block>{
354 match 0 <fold block>{
367 0 => 0, 355 0 => 0,
368 _ => 1, 356 _ => 1,
369 }</fold> 357 }</fold>
370}</fold>"#; 358}</fold>"#,
359 );
360 }
371 361
372 let folds = &[FoldKind::Block, FoldKind::Block]; 362 #[test]
373 do_check(text, folds); 363 fn fold_big_calls() {
364 check(
365 r#"
366fn main() <fold block>{
367 frobnicate<fold arglist>(
368 1,
369 2,
370 3,
371 )</fold>
372}</fold>
373 "#,
374 )
374 } 375 }
375} 376}
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs
index bea7fbfa7..4c78fa214 100644
--- a/crates/ra_ide/src/goto_definition.rs
+++ b/crates/ra_ide/src/goto_definition.rs
@@ -103,205 +103,149 @@ pub(crate) fn reference_definition(
103 103
104#[cfg(test)] 104#[cfg(test)]
105mod tests { 105mod tests {
106 use test_utils::assert_eq_text; 106 use ra_db::FileRange;
107 107 use ra_syntax::{TextRange, TextSize};
108 use crate::mock_analysis::analysis_and_position; 108
109 109 use crate::mock_analysis::MockAnalysis;
110 fn check_goto(ra_fixture: &str, expected: &str, expected_range: &str) { 110
111 let (analysis, pos) = analysis_and_position(ra_fixture); 111 fn check(ra_fixture: &str) {
112 let (mock, position) = MockAnalysis::with_files_and_position(ra_fixture);
113 let (mut expected, data) = mock.annotation();
114 let analysis = mock.analysis();
115 match data.as_str() {
116 "" => (),
117 "file" => {
118 expected.range =
119 TextRange::up_to(TextSize::of(&*analysis.file_text(expected.file_id).unwrap()))
120 }
121 data => panic!("bad data: {}", data),
122 }
112 123
113 let mut navs = analysis.goto_definition(pos).unwrap().unwrap().info; 124 let mut navs = analysis.goto_definition(position).unwrap().unwrap().info;
114 if navs.len() == 0 { 125 if navs.len() == 0 {
115 panic!("unresolved reference") 126 panic!("unresolved reference")
116 } 127 }
117 assert_eq!(navs.len(), 1); 128 assert_eq!(navs.len(), 1);
118 129
119 let nav = navs.pop().unwrap(); 130 let nav = navs.pop().unwrap();
120 let file_text = analysis.file_text(nav.file_id()).unwrap(); 131 assert_eq!(expected, FileRange { file_id: nav.file_id(), range: nav.range() });
121
122 let mut actual = file_text[nav.full_range()].to_string();
123 if let Some(focus) = nav.focus_range() {
124 actual += "|";
125 actual += &file_text[focus];
126 }
127
128 if !expected_range.contains("...") {
129 test_utils::assert_eq_text!(&actual, expected_range);
130 } else {
131 let mut parts = expected_range.split("...");
132 let prefix = parts.next().unwrap();
133 let suffix = parts.next().unwrap();
134 assert!(
135 actual.starts_with(prefix) && actual.ends_with(suffix),
136 "\nExpected: {}\n Actual: {}\n",
137 expected_range,
138 actual
139 );
140 }
141
142 nav.assert_match(expected);
143 } 132 }
144 133
145 #[test] 134 #[test]
146 fn goto_def_in_items() { 135 fn goto_def_in_items() {
147 check_goto( 136 check(
148 " 137 r#"
149 //- /lib.rs 138struct Foo;
150 struct Foo; 139 //^^^
151 enum E { X(Foo<|>) } 140enum E { X(Foo<|>) }
152 ", 141"#,
153 "Foo STRUCT_DEF FileId(1) 0..11 7..10",
154 "struct Foo;|Foo",
155 ); 142 );
156 } 143 }
157 144
158 #[test] 145 #[test]
159 fn goto_def_at_start_of_item() { 146 fn goto_def_at_start_of_item() {
160 check_goto( 147 check(
161 " 148 r#"
162 //- /lib.rs 149struct Foo;
163 struct Foo; 150 //^^^
164 enum E { X(<|>Foo) } 151enum E { X(<|>Foo) }
165 ", 152"#,
166 "Foo STRUCT_DEF FileId(1) 0..11 7..10",
167 "struct Foo;|Foo",
168 ); 153 );
169 } 154 }
170 155
171 #[test] 156 #[test]
172 fn goto_definition_resolves_correct_name() { 157 fn goto_definition_resolves_correct_name() {
173 check_goto( 158 check(
174 " 159 r#"
175 //- /lib.rs 160//- /lib.rs
176 use a::Foo; 161use a::Foo;
177 mod a; 162mod a;
178 mod b; 163mod b;
179 enum E { X(Foo<|>) } 164enum E { X(Foo<|>) }
180 165
181 //- /a.rs 166//- /a.rs
182 struct Foo; 167struct Foo;
183 168 //^^^
184 //- /b.rs 169//- /b.rs
185 struct Foo; 170struct Foo;
186 ", 171"#,
187 "Foo STRUCT_DEF FileId(2) 0..11 7..10",
188 "struct Foo;|Foo",
189 ); 172 );
190 } 173 }
191 174
192 #[test] 175 #[test]
193 fn goto_def_for_module_declaration() { 176 fn goto_def_for_module_declaration() {
194 check_goto( 177 check(
195 r#" 178 r#"
196//- /lib.rs 179//- /lib.rs
197mod <|>foo; 180mod <|>foo;
198 181
199//- /foo.rs 182//- /foo.rs
200// empty 183// empty
184//^ file
201"#, 185"#,
202 "foo SOURCE_FILE FileId(2) 0..9",
203 "// empty\n",
204 ); 186 );
205 187
206 check_goto( 188 check(
207 r#" 189 r#"
208//- /lib.rs 190//- /lib.rs
209mod <|>foo; 191mod <|>foo;
210 192
211//- /foo/mod.rs 193//- /foo/mod.rs
212// empty 194// empty
195//^ file
213"#, 196"#,
214 "foo SOURCE_FILE FileId(2) 0..9",
215 "// empty\n",
216 ); 197 );
217 } 198 }
218 199
219 #[test] 200 #[test]
220 fn goto_def_for_macros() { 201 fn goto_def_for_macros() {
221 check_goto( 202 check(
222 " 203 r#"
223 //- /lib.rs 204macro_rules! foo { () => { () } }
224 macro_rules! foo { () => { () } } 205 //^^^
225 206fn bar() {
226 fn bar() { 207 <|>foo!();
227 <|>foo!(); 208}
228 } 209"#,
229 ",
230 "foo MACRO_CALL FileId(1) 0..33 13..16",
231 "macro_rules! foo { () => { () } }|foo",
232 ); 210 );
233 } 211 }
234 212
235 #[test] 213 #[test]
236 fn goto_def_for_macros_from_other_crates() { 214 fn goto_def_for_macros_from_other_crates() {
237 check_goto( 215 check(
238 "
239 //- /lib.rs
240 use foo::foo;
241 fn bar() {
242 <|>foo!();
243 }
244
245 //- /foo/lib.rs
246 #[macro_export]
247 macro_rules! foo { () => { () } }
248 ",
249 "foo MACRO_CALL FileId(2) 0..49 29..32",
250 "#[macro_export]\nmacro_rules! foo { () => { () } }|foo",
251 );
252 }
253
254 #[test]
255 fn goto_def_for_use_alias() {
256 check_goto(
257 r#" 216 r#"
258//- /lib.rs 217//- /lib.rs
259use foo as bar<|>; 218use foo::foo;
219fn bar() {
220 <|>foo!();
221}
260 222
261//- /foo/lib.rs 223//- /foo/lib.rs
262#[macro_export] 224#[macro_export]
263macro_rules! foo { () => { () } } 225macro_rules! foo { () => { () } }
226 //^^^
264"#, 227"#,
265 "SOURCE_FILE FileId(2) 0..50",
266 "#[macro_export]\nmacro_rules! foo { () => { () } }\n",
267 );
268 }
269
270 #[test]
271 fn goto_def_for_use_alias_foo_macro() {
272 check_goto(
273 "
274 //- /lib.rs
275 use foo::foo as bar<|>;
276
277 //- /foo/lib.rs
278 #[macro_export]
279 macro_rules! foo { () => { () } }
280 ",
281 "foo MACRO_CALL FileId(2) 0..49 29..32",
282 "#[macro_export]\nmacro_rules! foo { () => { () } }|foo",
283 ); 228 );
284 } 229 }
285 230
286 #[test] 231 #[test]
287 fn goto_def_for_macros_in_use_tree() { 232 fn goto_def_for_macros_in_use_tree() {
288 check_goto( 233 check(
289 " 234 r#"
290 //- /lib.rs 235//- /lib.rs
291 use foo::foo<|>; 236use foo::foo<|>;
292 237
293 //- /foo/lib.rs 238//- /foo/lib.rs
294 #[macro_export] 239#[macro_export]
295 macro_rules! foo { () => { () } } 240macro_rules! foo { () => { () } }
296 ", 241 //^^^
297 "foo MACRO_CALL FileId(2) 0..49 29..32", 242"#,
298 "#[macro_export]\nmacro_rules! foo { () => { () } }|foo",
299 ); 243 );
300 } 244 }
301 245
302 #[test] 246 #[test]
303 fn goto_def_for_macro_defined_fn_with_arg() { 247 fn goto_def_for_macro_defined_fn_with_arg() {
304 check_goto( 248 check(
305 r#" 249 r#"
306//- /lib.rs 250//- /lib.rs
307macro_rules! define_fn { 251macro_rules! define_fn {
@@ -309,522 +253,478 @@ macro_rules! define_fn {
309} 253}
310 254
311define_fn!(foo); 255define_fn!(foo);
256 //^^^
312 257
313fn bar() { 258fn bar() {
314 <|>foo(); 259 <|>foo();
315} 260}
316"#, 261"#,
317 "foo FN_DEF FileId(1) 65..81 76..79",
318 "define_fn!(foo);|foo",
319 ); 262 );
320 } 263 }
321 264
322 #[test] 265 #[test]
323 fn goto_def_for_macro_defined_fn_no_arg() { 266 fn goto_def_for_macro_defined_fn_no_arg() {
324 check_goto( 267 check(
325 r#" 268 r#"
326//- /lib.rs 269//- /lib.rs
327macro_rules! define_fn { 270macro_rules! define_fn {
328 () => (fn foo() {}) 271 () => (fn foo() {})
329} 272}
330 273
331define_fn!(); 274 define_fn!();
275//^^^^^^^^^^^^^
332 276
333fn bar() { 277fn bar() {
334 <|>foo(); 278 <|>foo();
335} 279}
336"#, 280"#,
337 "foo FN_DEF FileId(1) 52..65 52..65",
338 "define_fn!();|define_fn!();",
339 ); 281 );
340 } 282 }
341 283
342 #[test] 284 #[test]
343 fn goto_definition_works_for_macro_inside_pattern() { 285 fn goto_definition_works_for_macro_inside_pattern() {
344 check_goto( 286 check(
345 " 287 r#"
346 //- /lib.rs 288//- /lib.rs
347 macro_rules! foo {() => {0}} 289macro_rules! foo {() => {0}}
348 290 //^^^
349 fn bar() { 291
350 match (0,1) { 292fn bar() {
351 (<|>foo!(), _) => {} 293 match (0,1) {
352 } 294 (<|>foo!(), _) => {}
353 } 295 }
354 ", 296}
355 "foo MACRO_CALL FileId(1) 0..28 13..16", 297"#,
356 "macro_rules! foo {() => {0}}|foo",
357 ); 298 );
358 } 299 }
359 300
360 #[test] 301 #[test]
361 fn goto_definition_works_for_macro_inside_match_arm_lhs() { 302 fn goto_definition_works_for_macro_inside_match_arm_lhs() {
362 check_goto( 303 check(
363 " 304 r#"
364 //- /lib.rs 305//- /lib.rs
365 macro_rules! foo {() => {0}} 306macro_rules! foo {() => {0}}
366 307 //^^^
367 fn bar() { 308fn bar() {
368 match 0 { 309 match 0 {
369 <|>foo!() => {} 310 <|>foo!() => {}
370 } 311 }
371 } 312}
372 ", 313"#,
373 "foo MACRO_CALL FileId(1) 0..28 13..16", 314 );
374 "macro_rules! foo {() => {0}}|foo", 315 }
316
317 #[test]
318 fn goto_def_for_use_alias() {
319 check(
320 r#"
321//- /lib.rs
322use foo as bar<|>;
323
324//- /foo/lib.rs
325// empty
326//^ file
327"#,
328 );
329 }
330
331 #[test]
332 fn goto_def_for_use_alias_foo_macro() {
333 check(
334 r#"
335//- /lib.rs
336use foo::foo as bar<|>;
337
338//- /foo/lib.rs
339#[macro_export]
340macro_rules! foo { () => { () } }
341 //^^^
342"#,
375 ); 343 );
376 } 344 }
377 345
378 #[test] 346 #[test]
379 fn goto_def_for_methods() { 347 fn goto_def_for_methods() {
380 check_goto( 348 check(
381 " 349 r#"
382 //- /lib.rs 350//- /lib.rs
383 struct Foo; 351struct Foo;
384 impl Foo { 352impl Foo {
385 fn frobnicate(&self) { } 353 fn frobnicate(&self) { }
386 } 354 //^^^^^^^^^^
355}
387 356
388 fn bar(foo: &Foo) { 357fn bar(foo: &Foo) {
389 foo.frobnicate<|>(); 358 foo.frobnicate<|>();
390 } 359}
391 ", 360"#,
392 "frobnicate FN_DEF FileId(1) 27..51 30..40",
393 "fn frobnicate(&self) { }|frobnicate",
394 ); 361 );
395 } 362 }
396 363
397 #[test] 364 #[test]
398 fn goto_def_for_fields() { 365 fn goto_def_for_fields() {
399 check_goto( 366 check(
400 r" 367 r#"
401 //- /lib.rs 368struct Foo {
402 struct Foo { 369 spam: u32,
403 spam: u32, 370} //^^^^
404 }
405 371
406 fn bar(foo: &Foo) { 372fn bar(foo: &Foo) {
407 foo.spam<|>; 373 foo.spam<|>;
408 } 374}
409 ", 375"#,
410 "spam RECORD_FIELD_DEF FileId(1) 17..26 17..21",
411 "spam: u32|spam",
412 ); 376 );
413 } 377 }
414 378
415 #[test] 379 #[test]
416 fn goto_def_for_record_fields() { 380 fn goto_def_for_record_fields() {
417 check_goto( 381 check(
418 r" 382 r#"
419 //- /lib.rs 383//- /lib.rs
420 struct Foo { 384struct Foo {
421 spam: u32, 385 spam: u32,
422 } 386} //^^^^
423 387
424 fn bar() -> Foo { 388fn bar() -> Foo {
425 Foo { 389 Foo {
426 spam<|>: 0, 390 spam<|>: 0,
427 } 391 }
428 } 392}
429 ", 393"#,
430 "spam RECORD_FIELD_DEF FileId(1) 17..26 17..21",
431 "spam: u32|spam",
432 ); 394 );
433 } 395 }
434 396
435 #[test] 397 #[test]
436 fn goto_def_for_record_pat_fields() { 398 fn goto_def_for_record_pat_fields() {
437 check_goto( 399 check(
438 r" 400 r#"
439 //- /lib.rs 401//- /lib.rs
440 struct Foo { 402struct Foo {
441 spam: u32, 403 spam: u32,
442 } 404} //^^^^
443 405
444 fn bar(foo: Foo) -> Foo { 406fn bar(foo: Foo) -> Foo {
445 let Foo { spam<|>: _, } = foo 407 let Foo { spam<|>: _, } = foo
446 } 408}
447 ", 409"#,
448 "spam RECORD_FIELD_DEF FileId(1) 17..26 17..21",
449 "spam: u32|spam",
450 ); 410 );
451 } 411 }
452 412
453 #[test] 413 #[test]
454 fn goto_def_for_record_fields_macros() { 414 fn goto_def_for_record_fields_macros() {
455 check_goto( 415 check(
456 r" 416 r"
457 //- /lib.rs 417macro_rules! m { () => { 92 };}
458 macro_rules! m { () => { 92 };} 418struct Foo { spam: u32 }
459 struct Foo { spam: u32 } 419 //^^^^
460 420
461 fn bar() -> Foo { 421fn bar() -> Foo {
462 Foo { spam<|>: m!() } 422 Foo { spam<|>: m!() }
463 } 423}
464 ", 424",
465 "spam RECORD_FIELD_DEF FileId(1) 45..54 45..49",
466 "spam: u32|spam",
467 ); 425 );
468 } 426 }
469 427
470 #[test] 428 #[test]
471 fn goto_for_tuple_fields() { 429 fn goto_for_tuple_fields() {
472 check_goto( 430 check(
473 " 431 r#"
474 //- /lib.rs 432struct Foo(u32);
475 struct Foo(u32); 433 //^^^
476 434
477 fn bar() { 435fn bar() {
478 let foo = Foo(0); 436 let foo = Foo(0);
479 foo.<|>0; 437 foo.<|>0;
480 } 438}
481 ", 439"#,
482 "TUPLE_FIELD_DEF FileId(1) 11..14",
483 "u32",
484 ); 440 );
485 } 441 }
486 442
487 #[test] 443 #[test]
488 fn goto_def_for_ufcs_inherent_methods() { 444 fn goto_def_for_ufcs_inherent_methods() {
489 check_goto( 445 check(
490 " 446 r#"
491 //- /lib.rs 447struct Foo;
492 struct Foo; 448impl Foo {
493 impl Foo { 449 fn frobnicate() { }
494 fn frobnicate() { } 450} //^^^^^^^^^^
495 }
496 451
497 fn bar(foo: &Foo) { 452fn bar(foo: &Foo) {
498 Foo::frobnicate<|>(); 453 Foo::frobnicate<|>();
499 } 454}
500 ", 455"#,
501 "frobnicate FN_DEF FileId(1) 27..46 30..40",
502 "fn frobnicate() { }|frobnicate",
503 ); 456 );
504 } 457 }
505 458
506 #[test] 459 #[test]
507 fn goto_def_for_ufcs_trait_methods_through_traits() { 460 fn goto_def_for_ufcs_trait_methods_through_traits() {
508 check_goto( 461 check(
509 " 462 r#"
510 //- /lib.rs 463trait Foo {
511 trait Foo { 464 fn frobnicate();
512 fn frobnicate(); 465} //^^^^^^^^^^
513 }
514 466
515 fn bar() { 467fn bar() {
516 Foo::frobnicate<|>(); 468 Foo::frobnicate<|>();
517 } 469}
518 ", 470"#,
519 "frobnicate FN_DEF FileId(1) 16..32 19..29",
520 "fn frobnicate();|frobnicate",
521 ); 471 );
522 } 472 }
523 473
524 #[test] 474 #[test]
525 fn goto_def_for_ufcs_trait_methods_through_self() { 475 fn goto_def_for_ufcs_trait_methods_through_self() {
526 check_goto( 476 check(
527 " 477 r#"
528 //- /lib.rs 478struct Foo;
529 struct Foo; 479trait Trait {
530 trait Trait { 480 fn frobnicate();
531 fn frobnicate(); 481} //^^^^^^^^^^
532 } 482impl Trait for Foo {}
533 impl Trait for Foo {}
534 483
535 fn bar() { 484fn bar() {
536 Foo::frobnicate<|>(); 485 Foo::frobnicate<|>();
537 } 486}
538 ", 487"#,
539 "frobnicate FN_DEF FileId(1) 30..46 33..43",
540 "fn frobnicate();|frobnicate",
541 ); 488 );
542 } 489 }
543 490
544 #[test] 491 #[test]
545 fn goto_definition_on_self() { 492 fn goto_definition_on_self() {
546 check_goto( 493 check(
547 " 494 r#"
548 //- /lib.rs 495struct Foo;
549 struct Foo; 496impl Foo {
550 impl Foo { 497 //^^^
551 pub fn new() -> Self { 498 pub fn new() -> Self {
552 Self<|> {} 499 Self<|> {}
553 } 500 }
554 } 501}
555 ", 502"#,
556 "impl IMPL_DEF FileId(1) 12..73", 503 );
557 "impl Foo {...}", 504 check(
558 ); 505 r#"
559 506struct Foo;
560 check_goto( 507impl Foo {
561 " 508 //^^^
562 //- /lib.rs 509 pub fn new() -> Self<|> {
563 struct Foo; 510 Self {}
564 impl Foo { 511 }
565 pub fn new() -> Self<|> { 512}
566 Self {} 513"#,
567 } 514 );
568 } 515
569 ", 516 check(
570 "impl IMPL_DEF FileId(1) 12..73", 517 r#"
571 "impl Foo {...}", 518enum Foo { A }
572 ); 519impl Foo {
573 520 //^^^
574 check_goto( 521 pub fn new() -> Self<|> {
575 " 522 Foo::A
576 //- /lib.rs 523 }
577 enum Foo { A } 524}
578 impl Foo { 525"#,
579 pub fn new() -> Self<|> { 526 );
580 Foo::A 527
581 } 528 check(
582 } 529 r#"
583 ", 530enum Foo { A }
584 "impl IMPL_DEF FileId(1) 15..75", 531impl Foo {
585 "impl Foo {...}", 532 //^^^
586 ); 533 pub fn thing(a: &Self<|>) {
587 534 }
588 check_goto( 535}
589 " 536"#,
590 //- /lib.rs
591 enum Foo { A }
592 impl Foo {
593 pub fn thing(a: &Self<|>) {
594 }
595 }
596 ",
597 "impl IMPL_DEF FileId(1) 15..62",
598 "impl Foo {...}",
599 ); 537 );
600 } 538 }
601 539
602 #[test] 540 #[test]
603 fn goto_definition_on_self_in_trait_impl() { 541 fn goto_definition_on_self_in_trait_impl() {
604 check_goto( 542 check(
605 " 543 r#"
606 //- /lib.rs 544struct Foo;
607 struct Foo; 545trait Make {
608 trait Make { 546 fn new() -> Self;
609 fn new() -> Self; 547}
610 } 548impl Make for Foo {
611 impl Make for Foo { 549 //^^^
612 fn new() -> Self { 550 fn new() -> Self {
613 Self<|> {} 551 Self<|> {}
614 } 552 }
615 } 553}
616 ", 554"#,
617 "impl IMPL_DEF FileId(1) 49..115",
618 "impl Make for Foo {...}",
619 ); 555 );
620 556
621 check_goto( 557 check(
622 " 558 r#"
623 //- /lib.rs 559struct Foo;
624 struct Foo; 560trait Make {
625 trait Make { 561 fn new() -> Self;
626 fn new() -> Self; 562}
627 } 563impl Make for Foo {
628 impl Make for Foo { 564 //^^^
629 fn new() -> Self<|> { 565 fn new() -> Self<|> {
630 Self {} 566 Self {}
631 } 567 }
632 } 568}
633 ", 569"#,
634 "impl IMPL_DEF FileId(1) 49..115",
635 "impl Make for Foo {...}",
636 ); 570 );
637 } 571 }
638 572
639 #[test] 573 #[test]
640 fn goto_def_when_used_on_definition_name_itself() { 574 fn goto_def_when_used_on_definition_name_itself() {
641 check_goto( 575 check(
642 " 576 r#"
643 //- /lib.rs 577struct Foo<|> { value: u32 }
644 struct Foo<|> { value: u32 } 578 //^^^
645 ", 579 "#,
646 "Foo STRUCT_DEF FileId(1) 0..25 7..10",
647 "struct Foo { value: u32 }|Foo",
648 ); 580 );
649 581
650 check_goto( 582 check(
651 r#" 583 r#"
652 //- /lib.rs 584struct Foo {
653 struct Foo { 585 field<|>: string,
654 field<|>: string, 586} //^^^^^
655 } 587"#,
656 "#,
657 "field RECORD_FIELD_DEF FileId(1) 17..30 17..22",
658 "field: string|field",
659 ); 588 );
660 589
661 check_goto( 590 check(
662 " 591 r#"
663 //- /lib.rs 592fn foo_test<|>() { }
664 fn foo_test<|>() { } 593 //^^^^^^^^
665 ", 594"#,
666 "foo_test FN_DEF FileId(1) 0..17 3..11",
667 "fn foo_test() { }|foo_test",
668 ); 595 );
669 596
670 check_goto( 597 check(
671 " 598 r#"
672 //- /lib.rs 599enum Foo<|> { Variant }
673 enum Foo<|> { 600 //^^^
674 Variant, 601"#,
675 }
676 ",
677 "Foo ENUM_DEF FileId(1) 0..25 5..8",
678 "enum Foo {...}|Foo",
679 );
680
681 check_goto(
682 "
683 //- /lib.rs
684 enum Foo {
685 Variant1,
686 Variant2<|>,
687 Variant3,
688 }
689 ",
690 "Variant2 ENUM_VARIANT FileId(1) 29..37 29..37",
691 "Variant2|Variant2",
692 ); 602 );
693 603
694 check_goto( 604 check(
695 r#" 605 r#"
696 //- /lib.rs 606enum Foo {
697 static INNER<|>: &str = ""; 607 Variant1,
698 "#, 608 Variant2<|>,
699 "INNER STATIC_DEF FileId(1) 0..24 7..12", 609 //^^^^^^^^
700 "static INNER: &str = \"\";|INNER", 610 Variant3,
611}
612"#,
701 ); 613 );
702 614
703 check_goto( 615 check(
704 r#" 616 r#"
705 //- /lib.rs 617static INNER<|>: &str = "";
706 const INNER<|>: &str = ""; 618 //^^^^^
707 "#, 619"#,
708 "INNER CONST_DEF FileId(1) 0..23 6..11",
709 "const INNER: &str = \"\";|INNER",
710 ); 620 );
711 621
712 check_goto( 622 check(
713 r#" 623 r#"
714 //- /lib.rs 624const INNER<|>: &str = "";
715 type Thing<|> = Option<()>; 625 //^^^^^
716 "#, 626"#,
717 "Thing TYPE_ALIAS_DEF FileId(1) 0..24 5..10",
718 "type Thing = Option<()>;|Thing",
719 ); 627 );
720 628
721 check_goto( 629 check(
722 r#" 630 r#"
723 //- /lib.rs 631type Thing<|> = Option<()>;
724 trait Foo<|> { } 632 //^^^^^
725 "#, 633"#,
726 "Foo TRAIT_DEF FileId(1) 0..13 6..9",
727 "trait Foo { }|Foo",
728 ); 634 );
729 635
730 check_goto( 636 check(
731 r#" 637 r#"
732 //- /lib.rs 638trait Foo<|> { }
733 mod bar<|> { } 639 //^^^
734 "#, 640"#,
735 "bar MODULE FileId(1) 0..11 4..7", 641 );
736 "mod bar { }|bar", 642
643 check(
644 r#"
645mod bar<|> { }
646 //^^^
647"#,
737 ); 648 );
738 } 649 }
739 650
740 #[test] 651 #[test]
741 fn goto_from_macro() { 652 fn goto_from_macro() {
742 check_goto( 653 check(
743 " 654 r#"
744 //- /lib.rs 655macro_rules! id {
745 macro_rules! id { 656 ($($tt:tt)*) => { $($tt)* }
746 ($($tt:tt)*) => { $($tt)* } 657}
747 } 658fn foo() {}
748 fn foo() {} 659 //^^^
749 id! { 660id! {
750 fn bar() { 661 fn bar() {
751 fo<|>o(); 662 fo<|>o();
752 } 663 }
753 } 664}
754 mod confuse_index { fn foo(); } 665mod confuse_index { fn foo(); }
755 ", 666"#,
756 "foo FN_DEF FileId(1) 52..63 55..58",
757 "fn foo() {}|foo",
758 ); 667 );
759 } 668 }
760 669
761 #[test] 670 #[test]
762 fn goto_through_format() { 671 fn goto_through_format() {
763 check_goto( 672 check(
764 " 673 r#"
765 //- /lib.rs 674#[macro_export]
766 #[macro_export] 675macro_rules! format {
767 macro_rules! format { 676 ($($arg:tt)*) => ($crate::fmt::format($crate::__export::format_args!($($arg)*)))
768 ($($arg:tt)*) => ($crate::fmt::format($crate::__export::format_args!($($arg)*))) 677}
769 } 678#[rustc_builtin_macro]
770 #[rustc_builtin_macro] 679#[macro_export]
771 #[macro_export] 680macro_rules! format_args {
772 macro_rules! format_args { 681 ($fmt:expr) => ({ /* compiler built-in */ });
773 ($fmt:expr) => ({ /* compiler built-in */ }); 682 ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ })
774 ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }) 683}
775 } 684pub mod __export {
776 pub mod __export { 685 pub use crate::format_args;
777 pub use crate::format_args; 686 fn foo() {} // for index confusion
778 fn foo() {} // for index confusion 687}
779 } 688fn foo() -> i8 {}
780 fn foo() -> i8 {} 689 //^^^
781 fn test() { 690fn test() {
782 format!(\"{}\", fo<|>o()) 691 format!("{}", fo<|>o())
783 } 692}
784 ", 693"#,
785 "foo FN_DEF FileId(1) 398..415 401..404",
786 "fn foo() -> i8 {}|foo",
787 ); 694 );
788 } 695 }
789 696
790 #[test] 697 #[test]
791 fn goto_for_type_param() { 698 fn goto_for_type_param() {
792 check_goto( 699 check(
793 r#" 700 r#"
794 //- /lib.rs 701struct Foo<T: Clone> { t: <|>T }
795 struct Foo<T: Clone> { 702 //^
796 t: <|>T, 703"#,
797 }
798 "#,
799 "T TYPE_PARAM FileId(1) 11..19 11..12",
800 "T: Clone|T",
801 ); 704 );
802 } 705 }
803 706
804 #[test] 707 #[test]
805 fn goto_within_macro() { 708 fn goto_within_macro() {
806 check_goto( 709 check(
807 r#" 710 r#"
808//- /lib.rs
809macro_rules! id { 711macro_rules! id {
810 ($($tt:tt)*) => ($($tt)*) 712 ($($tt:tt)*) => ($($tt)*)
811} 713}
812 714
813fn foo() { 715fn foo() {
814 let x = 1; 716 let x = 1;
717 //^
815 id!({ 718 id!({
816 let y = <|>x; 719 let y = <|>x;
817 let z = y; 720 let z = y;
818 }); 721 });
819} 722}
820"#, 723"#,
821 "x BIND_PAT FileId(1) 70..71",
822 "x",
823 ); 724 );
824 725
825 check_goto( 726 check(
826 r#" 727 r#"
827//- /lib.rs
828macro_rules! id { 728macro_rules! id {
829 ($($tt:tt)*) => ($($tt)*) 729 ($($tt:tt)*) => ($($tt)*)
830} 730}
@@ -833,159 +733,125 @@ fn foo() {
833 let x = 1; 733 let x = 1;
834 id!({ 734 id!({
835 let y = x; 735 let y = x;
736 //^
836 let z = <|>y; 737 let z = <|>y;
837 }); 738 });
838} 739}
839"#, 740"#,
840 "y BIND_PAT FileId(1) 99..100",
841 "y",
842 ); 741 );
843 } 742 }
844 743
845 #[test] 744 #[test]
846 fn goto_def_in_local_fn() { 745 fn goto_def_in_local_fn() {
847 check_goto( 746 check(
848 " 747 r#"
849 //- /lib.rs 748fn main() {
850 fn main() { 749 fn foo() {
851 fn foo() { 750 let x = 92;
852 let x = 92; 751 //^
853 <|>x; 752 <|>x;
854 } 753 }
855 } 754}
856 ", 755"#,
857 "x BIND_PAT FileId(1) 39..40",
858 "x",
859 ); 756 );
860 } 757 }
861 758
862 #[test] 759 #[test]
863 fn goto_def_in_local_macro() { 760 fn goto_def_in_local_macro() {
864 check_goto( 761 check(
865 r" 762 r#"
866 //- /lib.rs 763fn bar() {
867 fn bar() { 764 macro_rules! foo { () => { () } }
868 macro_rules! foo { () => { () } } 765 //^^^
869 <|>foo!(); 766 <|>foo!();
870 } 767}
871 ", 768"#,
872 "foo MACRO_CALL FileId(1) 15..48 28..31",
873 "macro_rules! foo { () => { () } }|foo",
874 ); 769 );
875 } 770 }
876 771
877 #[test] 772 #[test]
878 fn goto_def_for_field_init_shorthand() { 773 fn goto_def_for_field_init_shorthand() {
879 check_goto( 774 check(
880 " 775 r#"
881 //- /lib.rs 776struct Foo { x: i32 }
882 struct Foo { x: i32 } 777fn main() {
883 fn main() { 778 let x = 92;
884 let x = 92; 779 //^
885 Foo { x<|> }; 780 Foo { x<|> };
886 } 781}
887 ", 782"#,
888 "x BIND_PAT FileId(1) 42..43",
889 "x",
890 ) 783 )
891 } 784 }
892 785
893 #[test] 786 #[test]
894 fn goto_def_for_enum_variant_field() { 787 fn goto_def_for_enum_variant_field() {
895 check_goto( 788 check(
896 " 789 r#"
897 //- /lib.rs 790enum Foo {
898 enum Foo { 791 Bar { x: i32 }
899 Bar { x: i32 } 792} //^
900 } 793fn baz(foo: Foo) {
901 fn baz(foo: Foo) { 794 match foo {
902 match foo { 795 Foo::Bar { x<|> } => x
903 Foo::Bar { x<|> } => x 796 };
904 }; 797}
905 } 798"#,
906 ",
907 "x RECORD_FIELD_DEF FileId(1) 21..27 21..22",
908 "x: i32|x",
909 ); 799 );
910 } 800 }
911 801
912 #[test] 802 #[test]
913 fn goto_def_for_enum_variant_self_pattern_const() { 803 fn goto_def_for_enum_variant_self_pattern_const() {
914 check_goto( 804 check(
915 " 805 r#"
916 //- /lib.rs 806enum Foo { Bar }
917 enum Foo { 807 //^^^
918 Bar, 808impl Foo {
919 } 809 fn baz(self) {
920 impl Foo { 810 match self { Self::Bar<|> => {} }
921 fn baz(self) { 811 }
922 match self { 812}
923 Self::Bar<|> => {} 813"#,
924 }
925 }
926 }
927 ",
928 "Bar ENUM_VARIANT FileId(1) 15..18 15..18",
929 "Bar|Bar",
930 ); 814 );
931 } 815 }
932 816
933 #[test] 817 #[test]
934 fn goto_def_for_enum_variant_self_pattern_record() { 818 fn goto_def_for_enum_variant_self_pattern_record() {
935 check_goto( 819 check(
936 " 820 r#"
937 //- /lib.rs 821enum Foo { Bar { val: i32 } }
938 enum Foo { 822 //^^^
939 Bar { val: i32 }, 823impl Foo {
940 } 824 fn baz(self) -> i32 {
941 impl Foo { 825 match self { Self::Bar<|> { val } => {} }
942 fn baz(self) -> i32 { 826 }
943 match self { 827}
944 Self::Bar<|> { val } => {} 828"#,
945 }
946 }
947 }
948 ",
949 "Bar ENUM_VARIANT FileId(1) 15..31 15..18",
950 "Bar { val: i32 }|Bar",
951 ); 829 );
952 } 830 }
953 831
954 #[test] 832 #[test]
955 fn goto_def_for_enum_variant_self_expr_const() { 833 fn goto_def_for_enum_variant_self_expr_const() {
956 check_goto( 834 check(
957 " 835 r#"
958 //- /lib.rs 836enum Foo { Bar }
959 enum Foo { 837 //^^^
960 Bar, 838impl Foo {
961 } 839 fn baz(self) { Self::Bar<|>; }
962 impl Foo { 840}
963 fn baz(self) { 841"#,
964 Self::Bar<|>;
965 }
966 }
967 ",
968 "Bar ENUM_VARIANT FileId(1) 15..18 15..18",
969 "Bar|Bar",
970 ); 842 );
971 } 843 }
972 844
973 #[test] 845 #[test]
974 fn goto_def_for_enum_variant_self_expr_record() { 846 fn goto_def_for_enum_variant_self_expr_record() {
975 check_goto( 847 check(
976 " 848 r#"
977 //- /lib.rs 849enum Foo { Bar { val: i32 } }
978 enum Foo { 850 //^^^
979 Bar { val: i32 }, 851impl Foo {
980 } 852 fn baz(self) { Self::Bar<|> {val: 4}; }
981 impl Foo { 853}
982 fn baz(self) { 854"#,
983 Self::Bar<|> {val: 4};
984 }
985 }
986 ",
987 "Bar ENUM_VARIANT FileId(1) 15..31 15..18",
988 "Bar { val: i32 }|Bar",
989 ); 855 );
990 } 856 }
991} 857}
diff --git a/crates/ra_ide/src/goto_implementation.rs b/crates/ra_ide/src/goto_implementation.rs
index 0cec0657e..9acc960fc 100644
--- a/crates/ra_ide/src/goto_implementation.rs
+++ b/crates/ra_ide/src/goto_implementation.rs
@@ -74,135 +74,156 @@ fn impls_for_trait(
74 74
75#[cfg(test)] 75#[cfg(test)]
76mod tests { 76mod tests {
77 use crate::mock_analysis::analysis_and_position; 77 use ra_db::FileRange;
78 78
79 fn check_goto(fixture: &str, expected: &[&str]) { 79 use crate::mock_analysis::MockAnalysis;
80 let (analysis, pos) = analysis_and_position(fixture);
81 80
82 let mut navs = analysis.goto_implementation(pos).unwrap().unwrap().info; 81 fn check(ra_fixture: &str) {
83 assert_eq!(navs.len(), expected.len()); 82 let (mock, position) = MockAnalysis::with_files_and_position(ra_fixture);
84 navs.sort_by_key(|nav| (nav.file_id(), nav.full_range().start())); 83 let annotations = mock.annotations();
85 navs.into_iter().enumerate().for_each(|(i, nav)| nav.assert_match(expected[i])); 84 let analysis = mock.analysis();
85
86 let navs = analysis.goto_implementation(position).unwrap().unwrap().info;
87
88 let key = |frange: &FileRange| (frange.file_id, frange.range.start());
89
90 let mut expected = annotations
91 .into_iter()
92 .map(|(range, data)| {
93 assert!(data.is_empty());
94 range
95 })
96 .collect::<Vec<_>>();
97 expected.sort_by_key(key);
98
99 let mut actual = navs
100 .into_iter()
101 .map(|nav| FileRange { file_id: nav.file_id(), range: nav.range() })
102 .collect::<Vec<_>>();
103 actual.sort_by_key(key);
104
105 assert_eq!(expected, actual);
86 } 106 }
87 107
88 #[test] 108 #[test]
89 fn goto_implementation_works() { 109 fn goto_implementation_works() {
90 check_goto( 110 check(
91 " 111 r#"
92 //- /lib.rs 112struct Foo<|>;
93 struct Foo<|>; 113impl Foo {}
94 impl Foo {} 114 //^^^
95 ", 115"#,
96 &["impl IMPL_DEF FileId(1) 12..23"],
97 ); 116 );
98 } 117 }
99 118
100 #[test] 119 #[test]
101 fn goto_implementation_works_multiple_blocks() { 120 fn goto_implementation_works_multiple_blocks() {
102 check_goto( 121 check(
103 " 122 r#"
104 //- /lib.rs 123struct Foo<|>;
105 struct Foo<|>; 124impl Foo {}
106 impl Foo {} 125 //^^^
107 impl Foo {} 126impl Foo {}
108 ", 127 //^^^
109 &["impl IMPL_DEF FileId(1) 12..23", "impl IMPL_DEF FileId(1) 24..35"], 128"#,
110 ); 129 );
111 } 130 }
112 131
113 #[test] 132 #[test]
114 fn goto_implementation_works_multiple_mods() { 133 fn goto_implementation_works_multiple_mods() {
115 check_goto( 134 check(
116 " 135 r#"
117 //- /lib.rs 136struct Foo<|>;
118 struct Foo<|>; 137mod a {
119 mod a { 138 impl super::Foo {}
120 impl super::Foo {} 139 //^^^^^^^^^^
121 } 140}
122 mod b { 141mod b {
123 impl super::Foo {} 142 impl super::Foo {}
124 } 143 //^^^^^^^^^^
125 ", 144}
126 &["impl IMPL_DEF FileId(1) 24..42", "impl IMPL_DEF FileId(1) 57..75"], 145"#,
127 ); 146 );
128 } 147 }
129 148
130 #[test] 149 #[test]
131 fn goto_implementation_works_multiple_files() { 150 fn goto_implementation_works_multiple_files() {
132 check_goto( 151 check(
133 " 152 r#"
134 //- /lib.rs 153//- /lib.rs
135 struct Foo<|>; 154struct Foo<|>;
136 mod a; 155mod a;
137 mod b; 156mod b;
138 //- /a.rs 157//- /a.rs
139 impl crate::Foo {} 158impl crate::Foo {}
140 //- /b.rs 159 //^^^^^^^^^^
141 impl crate::Foo {} 160//- /b.rs
142 ", 161impl crate::Foo {}
143 &["impl IMPL_DEF FileId(2) 0..18", "impl IMPL_DEF FileId(3) 0..18"], 162 //^^^^^^^^^^
163"#,
144 ); 164 );
145 } 165 }
146 166
147 #[test] 167 #[test]
148 fn goto_implementation_for_trait() { 168 fn goto_implementation_for_trait() {
149 check_goto( 169 check(
150 " 170 r#"
151 //- /lib.rs 171trait T<|> {}
152 trait T<|> {} 172struct Foo;
153 struct Foo; 173impl T for Foo {}
154 impl T for Foo {} 174 //^^^
155 ", 175"#,
156 &["impl IMPL_DEF FileId(1) 23..40"],
157 ); 176 );
158 } 177 }
159 178
160 #[test] 179 #[test]
161 fn goto_implementation_for_trait_multiple_files() { 180 fn goto_implementation_for_trait_multiple_files() {
162 check_goto( 181 check(
163 " 182 r#"
164 //- /lib.rs 183//- /lib.rs
165 trait T<|> {}; 184trait T<|> {};
166 struct Foo; 185struct Foo;
167 mod a; 186mod a;
168 mod b; 187mod b;
169 //- /a.rs 188//- /a.rs
170 impl crate::T for crate::Foo {} 189impl crate::T for crate::Foo {}
171 //- /b.rs 190 //^^^^^^^^^^
172 impl crate::T for crate::Foo {} 191//- /b.rs
173 ", 192impl crate::T for crate::Foo {}
174 &["impl IMPL_DEF FileId(2) 0..31", "impl IMPL_DEF FileId(3) 0..31"], 193 //^^^^^^^^^^
194 "#,
175 ); 195 );
176 } 196 }
177 197
178 #[test] 198 #[test]
179 fn goto_implementation_all_impls() { 199 fn goto_implementation_all_impls() {
180 check_goto( 200 check(
181 " 201 r#"
182 //- /lib.rs 202//- /lib.rs
183 trait T {} 203trait T {}
184 struct Foo<|>; 204struct Foo<|>;
185 impl Foo {} 205impl Foo {}
186 impl T for Foo {} 206 //^^^
187 impl T for &Foo {} 207impl T for Foo {}
188 ", 208 //^^^
189 &[ 209impl T for &Foo {}
190 "impl IMPL_DEF FileId(1) 23..34", 210 //^^^^
191 "impl IMPL_DEF FileId(1) 35..52", 211"#,
192 "impl IMPL_DEF FileId(1) 53..71",
193 ],
194 ); 212 );
195 } 213 }
196 214
197 #[test] 215 #[test]
198 fn goto_implementation_to_builtin_derive() { 216 fn goto_implementation_to_builtin_derive() {
199 check_goto( 217 check(
200 " 218 r#"
201 //- /lib.rs 219 #[derive(Copy)]
202 #[derive(Copy)] 220//^^^^^^^^^^^^^^^
203 struct Foo<|>; 221struct Foo<|>;
204 ", 222
205 &["impl IMPL_DEF FileId(1) 0..15"], 223mod marker {
224 trait Copy {}
225}
226"#,
206 ); 227 );
207 } 228 }
208} 229}
diff --git a/crates/ra_ide/src/goto_type_definition.rs b/crates/ra_ide/src/goto_type_definition.rs
index 91a3097fb..7eb40d637 100644
--- a/crates/ra_ide/src/goto_type_definition.rs
+++ b/crates/ra_ide/src/goto_type_definition.rs
@@ -55,8 +55,8 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
55mod tests { 55mod tests {
56 use crate::mock_analysis::analysis_and_position; 56 use crate::mock_analysis::analysis_and_position;
57 57
58 fn check_goto(fixture: &str, expected: &str) { 58 fn check_goto(ra_fixture: &str, expected: &str) {
59 let (analysis, pos) = analysis_and_position(fixture); 59 let (analysis, pos) = analysis_and_position(ra_fixture);
60 60
61 let mut navs = analysis.goto_type_definition(pos).unwrap().unwrap().info; 61 let mut navs = analysis.goto_type_definition(pos).unwrap().unwrap().info;
62 assert_eq!(navs.len(), 1); 62 assert_eq!(navs.len(), 1);
@@ -67,7 +67,7 @@ mod tests {
67 #[test] 67 #[test]
68 fn goto_type_definition_works_simple() { 68 fn goto_type_definition_works_simple() {
69 check_goto( 69 check_goto(
70 " 70 r"
71 //- /lib.rs 71 //- /lib.rs
72 struct Foo; 72 struct Foo;
73 fn foo() { 73 fn foo() {
@@ -82,7 +82,7 @@ mod tests {
82 #[test] 82 #[test]
83 fn goto_type_definition_works_simple_ref() { 83 fn goto_type_definition_works_simple_ref() {
84 check_goto( 84 check_goto(
85 " 85 r"
86 //- /lib.rs 86 //- /lib.rs
87 struct Foo; 87 struct Foo;
88 fn foo() { 88 fn foo() {
@@ -97,7 +97,7 @@ mod tests {
97 #[test] 97 #[test]
98 fn goto_type_definition_works_through_macro() { 98 fn goto_type_definition_works_through_macro() {
99 check_goto( 99 check_goto(
100 " 100 r"
101 //- /lib.rs 101 //- /lib.rs
102 macro_rules! id { 102 macro_rules! id {
103 ($($tt:tt)*) => { $($tt)* } 103 ($($tt:tt)*) => { $($tt)* }
@@ -116,7 +116,7 @@ mod tests {
116 #[test] 116 #[test]
117 fn goto_type_definition_for_param() { 117 fn goto_type_definition_for_param() {
118 check_goto( 118 check_goto(
119 " 119 r"
120 //- /lib.rs 120 //- /lib.rs
121 struct Foo; 121 struct Foo;
122 fn foo(<|>f: Foo) {} 122 fn foo(<|>f: Foo) {}
@@ -128,7 +128,7 @@ mod tests {
128 #[test] 128 #[test]
129 fn goto_type_definition_for_tuple_field() { 129 fn goto_type_definition_for_tuple_field() {
130 check_goto( 130 check_goto(
131 " 131 r"
132 //- /lib.rs 132 //- /lib.rs
133 struct Foo; 133 struct Foo;
134 struct Bar(Foo); 134 struct Bar(Foo);
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs
index c3e36a387..eaba2b61e 100644
--- a/crates/ra_ide/src/hover.rs
+++ b/crates/ra_ide/src/hover.rs
@@ -417,8 +417,8 @@ mod tests {
417 assert_eq!(offset, position.into()); 417 assert_eq!(offset, position.into());
418 } 418 }
419 419
420 fn check_hover_result(fixture: &str, expected: &[&str]) -> (String, Vec<HoverAction>) { 420 fn check_hover_result(ra_fixture: &str, expected: &[&str]) -> (String, Vec<HoverAction>) {
421 let (analysis, position) = analysis_and_position(fixture); 421 let (analysis, position) = analysis_and_position(ra_fixture);
422 let hover = analysis.hover(position).unwrap().unwrap(); 422 let hover = analysis.hover(position).unwrap().unwrap();
423 let mut results = Vec::from(hover.info.results()); 423 let mut results = Vec::from(hover.info.results());
424 results.sort(); 424 results.sort();
@@ -435,8 +435,8 @@ mod tests {
435 (content[hover.range].to_string(), hover.info.actions().to_vec()) 435 (content[hover.range].to_string(), hover.info.actions().to_vec())
436 } 436 }
437 437
438 fn check_hover_no_result(fixture: &str) { 438 fn check_hover_no_result(ra_fixture: &str) {
439 let (analysis, position) = analysis_and_position(fixture); 439 let (analysis, position) = analysis_and_position(ra_fixture);
440 assert!(analysis.hover(position).unwrap().is_none()); 440 assert!(analysis.hover(position).unwrap().is_none());
441 } 441 }
442 442
@@ -923,7 +923,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
923 #[test] 923 #[test]
924 fn test_hover_through_macro() { 924 fn test_hover_through_macro() {
925 let (hover_on, _) = check_hover_result( 925 let (hover_on, _) = check_hover_result(
926 " 926 r"
927 //- /lib.rs 927 //- /lib.rs
928 macro_rules! id { 928 macro_rules! id {
929 ($($tt:tt)*) => { $($tt)* } 929 ($($tt:tt)*) => { $($tt)* }
@@ -944,7 +944,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
944 #[test] 944 #[test]
945 fn test_hover_through_expr_in_macro() { 945 fn test_hover_through_expr_in_macro() {
946 let (hover_on, _) = check_hover_result( 946 let (hover_on, _) = check_hover_result(
947 " 947 r"
948 //- /lib.rs 948 //- /lib.rs
949 macro_rules! id { 949 macro_rules! id {
950 ($($tt:tt)*) => { $($tt)* } 950 ($($tt:tt)*) => { $($tt)* }
@@ -962,7 +962,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
962 #[test] 962 #[test]
963 fn test_hover_through_expr_in_macro_recursive() { 963 fn test_hover_through_expr_in_macro_recursive() {
964 let (hover_on, _) = check_hover_result( 964 let (hover_on, _) = check_hover_result(
965 " 965 r"
966 //- /lib.rs 966 //- /lib.rs
967 macro_rules! id_deep { 967 macro_rules! id_deep {
968 ($($tt:tt)*) => { $($tt)* } 968 ($($tt:tt)*) => { $($tt)* }
@@ -983,7 +983,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
983 #[test] 983 #[test]
984 fn test_hover_through_func_in_macro_recursive() { 984 fn test_hover_through_func_in_macro_recursive() {
985 let (hover_on, _) = check_hover_result( 985 let (hover_on, _) = check_hover_result(
986 " 986 r"
987 //- /lib.rs 987 //- /lib.rs
988 macro_rules! id_deep { 988 macro_rules! id_deep {
989 ($($tt:tt)*) => { $($tt)* } 989 ($($tt:tt)*) => { $($tt)* }
@@ -1026,7 +1026,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
1026 #[test] 1026 #[test]
1027 fn test_hover_through_assert_macro() { 1027 fn test_hover_through_assert_macro() {
1028 let (hover_on, _) = check_hover_result( 1028 let (hover_on, _) = check_hover_result(
1029 r#" 1029 r"
1030 //- /lib.rs 1030 //- /lib.rs
1031 #[rustc_builtin_macro] 1031 #[rustc_builtin_macro]
1032 macro_rules! assert {} 1032 macro_rules! assert {}
@@ -1035,7 +1035,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
1035 fn foo() { 1035 fn foo() {
1036 assert!(ba<|>r()); 1036 assert!(ba<|>r());
1037 } 1037 }
1038 "#, 1038 ",
1039 &["fn bar() -> bool"], 1039 &["fn bar() -> bool"],
1040 ); 1040 );
1041 1041
@@ -1077,14 +1077,14 @@ fn func(foo: i32) { if true { <|>foo; }; }
1077 #[test] 1077 #[test]
1078 fn test_hover_function_show_qualifiers() { 1078 fn test_hover_function_show_qualifiers() {
1079 check_hover_result( 1079 check_hover_result(
1080 " 1080 r"
1081 //- /lib.rs 1081 //- /lib.rs
1082 async fn foo<|>() {} 1082 async fn foo<|>() {}
1083 ", 1083 ",
1084 &["async fn foo()"], 1084 &["async fn foo()"],
1085 ); 1085 );
1086 check_hover_result( 1086 check_hover_result(
1087 " 1087 r"
1088 //- /lib.rs 1088 //- /lib.rs
1089 pub const unsafe fn foo<|>() {} 1089 pub const unsafe fn foo<|>() {}
1090 ", 1090 ",
@@ -1102,7 +1102,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
1102 #[test] 1102 #[test]
1103 fn test_hover_trait_show_qualifiers() { 1103 fn test_hover_trait_show_qualifiers() {
1104 let (_, actions) = check_hover_result( 1104 let (_, actions) = check_hover_result(
1105 " 1105 r"
1106 //- /lib.rs 1106 //- /lib.rs
1107 unsafe trait foo<|>() {} 1107 unsafe trait foo<|>() {}
1108 ", 1108 ",
@@ -1114,7 +1114,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
1114 #[test] 1114 #[test]
1115 fn test_hover_mod_with_same_name_as_function() { 1115 fn test_hover_mod_with_same_name_as_function() {
1116 check_hover_result( 1116 check_hover_result(
1117 " 1117 r"
1118 //- /lib.rs 1118 //- /lib.rs
1119 use self::m<|>y::Bar; 1119 use self::m<|>y::Bar;
1120 1120
@@ -1237,7 +1237,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
1237 #[test] 1237 #[test]
1238 fn test_hover_trait_has_impl_action() { 1238 fn test_hover_trait_has_impl_action() {
1239 let (_, actions) = check_hover_result( 1239 let (_, actions) = check_hover_result(
1240 " 1240 r"
1241 //- /lib.rs 1241 //- /lib.rs
1242 trait foo<|>() {} 1242 trait foo<|>() {}
1243 ", 1243 ",
@@ -1249,7 +1249,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
1249 #[test] 1249 #[test]
1250 fn test_hover_struct_has_impl_action() { 1250 fn test_hover_struct_has_impl_action() {
1251 let (_, actions) = check_hover_result( 1251 let (_, actions) = check_hover_result(
1252 " 1252 r"
1253 //- /lib.rs 1253 //- /lib.rs
1254 struct foo<|>() {} 1254 struct foo<|>() {}
1255 ", 1255 ",
@@ -1261,7 +1261,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
1261 #[test] 1261 #[test]
1262 fn test_hover_union_has_impl_action() { 1262 fn test_hover_union_has_impl_action() {
1263 let (_, actions) = check_hover_result( 1263 let (_, actions) = check_hover_result(
1264 " 1264 r"
1265 //- /lib.rs 1265 //- /lib.rs
1266 union foo<|>() {} 1266 union foo<|>() {}
1267 ", 1267 ",
@@ -1273,7 +1273,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
1273 #[test] 1273 #[test]
1274 fn test_hover_enum_has_impl_action() { 1274 fn test_hover_enum_has_impl_action() {
1275 let (_, actions) = check_hover_result( 1275 let (_, actions) = check_hover_result(
1276 " 1276 r"
1277 //- /lib.rs 1277 //- /lib.rs
1278 enum foo<|>() { 1278 enum foo<|>() {
1279 A, 1279 A,
@@ -1288,7 +1288,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
1288 #[test] 1288 #[test]
1289 fn test_hover_test_has_action() { 1289 fn test_hover_test_has_action() {
1290 let (_, actions) = check_hover_result( 1290 let (_, actions) = check_hover_result(
1291 " 1291 r"
1292 //- /lib.rs 1292 //- /lib.rs
1293 #[test] 1293 #[test]
1294 fn foo_<|>test() {} 1294 fn foo_<|>test() {}
@@ -1332,7 +1332,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
1332 #[test] 1332 #[test]
1333 fn test_hover_test_mod_has_action() { 1333 fn test_hover_test_mod_has_action() {
1334 let (_, actions) = check_hover_result( 1334 let (_, actions) = check_hover_result(
1335 " 1335 r"
1336 //- /lib.rs 1336 //- /lib.rs
1337 mod tests<|> { 1337 mod tests<|> {
1338 #[test] 1338 #[test]
@@ -1373,7 +1373,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
1373 #[test] 1373 #[test]
1374 fn test_hover_struct_has_goto_type_action() { 1374 fn test_hover_struct_has_goto_type_action() {
1375 let (_, actions) = check_hover_result( 1375 let (_, actions) = check_hover_result(
1376 " 1376 r"
1377 //- /main.rs 1377 //- /main.rs
1378 struct S{ f1: u32 } 1378 struct S{ f1: u32 }
1379 1379
@@ -1416,7 +1416,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
1416 #[test] 1416 #[test]
1417 fn test_hover_generic_struct_has_goto_type_actions() { 1417 fn test_hover_generic_struct_has_goto_type_actions() {
1418 let (_, actions) = check_hover_result( 1418 let (_, actions) = check_hover_result(
1419 " 1419 r"
1420 //- /main.rs 1420 //- /main.rs
1421 struct Arg(u32); 1421 struct Arg(u32);
1422 struct S<T>{ f1: T } 1422 struct S<T>{ f1: T }
@@ -1479,7 +1479,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
1479 #[test] 1479 #[test]
1480 fn test_hover_generic_struct_has_flattened_goto_type_actions() { 1480 fn test_hover_generic_struct_has_flattened_goto_type_actions() {
1481 let (_, actions) = check_hover_result( 1481 let (_, actions) = check_hover_result(
1482 " 1482 r"
1483 //- /main.rs 1483 //- /main.rs
1484 struct Arg(u32); 1484 struct Arg(u32);
1485 struct S<T>{ f1: T } 1485 struct S<T>{ f1: T }
@@ -1542,7 +1542,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
1542 #[test] 1542 #[test]
1543 fn test_hover_tuple_has_goto_type_actions() { 1543 fn test_hover_tuple_has_goto_type_actions() {
1544 let (_, actions) = check_hover_result( 1544 let (_, actions) = check_hover_result(
1545 " 1545 r"
1546 //- /main.rs 1546 //- /main.rs
1547 struct A(u32); 1547 struct A(u32);
1548 struct B(u32); 1548 struct B(u32);
@@ -1627,7 +1627,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
1627 #[test] 1627 #[test]
1628 fn test_hover_return_impl_trait_has_goto_type_action() { 1628 fn test_hover_return_impl_trait_has_goto_type_action() {
1629 let (_, actions) = check_hover_result( 1629 let (_, actions) = check_hover_result(
1630 " 1630 r"
1631 //- /main.rs 1631 //- /main.rs
1632 trait Foo {} 1632 trait Foo {}
1633 1633
@@ -1672,7 +1672,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
1672 #[test] 1672 #[test]
1673 fn test_hover_generic_return_impl_trait_has_goto_type_action() { 1673 fn test_hover_generic_return_impl_trait_has_goto_type_action() {
1674 let (_, actions) = check_hover_result( 1674 let (_, actions) = check_hover_result(
1675 " 1675 r"
1676 //- /main.rs 1676 //- /main.rs
1677 trait Foo<T> {} 1677 trait Foo<T> {}
1678 struct S; 1678 struct S;
@@ -1737,7 +1737,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
1737 #[test] 1737 #[test]
1738 fn test_hover_return_impl_traits_has_goto_type_action() { 1738 fn test_hover_return_impl_traits_has_goto_type_action() {
1739 let (_, actions) = check_hover_result( 1739 let (_, actions) = check_hover_result(
1740 " 1740 r"
1741 //- /main.rs 1741 //- /main.rs
1742 trait Foo {} 1742 trait Foo {}
1743 trait Bar {} 1743 trait Bar {}
@@ -1802,7 +1802,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
1802 #[test] 1802 #[test]
1803 fn test_hover_generic_return_impl_traits_has_goto_type_action() { 1803 fn test_hover_generic_return_impl_traits_has_goto_type_action() {
1804 let (_, actions) = check_hover_result( 1804 let (_, actions) = check_hover_result(
1805 " 1805 r"
1806 //- /main.rs 1806 //- /main.rs
1807 trait Foo<T> {} 1807 trait Foo<T> {}
1808 trait Bar<T> {} 1808 trait Bar<T> {}
@@ -1907,7 +1907,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
1907 #[test] 1907 #[test]
1908 fn test_hover_arg_impl_trait_has_goto_type_action() { 1908 fn test_hover_arg_impl_trait_has_goto_type_action() {
1909 let (_, actions) = check_hover_result( 1909 let (_, actions) = check_hover_result(
1910 " 1910 r"
1911 //- /lib.rs 1911 //- /lib.rs
1912 trait Foo {} 1912 trait Foo {}
1913 fn foo(ar<|>g: &impl Foo) {} 1913 fn foo(ar<|>g: &impl Foo) {}
@@ -1947,7 +1947,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
1947 #[test] 1947 #[test]
1948 fn test_hover_arg_impl_traits_has_goto_type_action() { 1948 fn test_hover_arg_impl_traits_has_goto_type_action() {
1949 let (_, actions) = check_hover_result( 1949 let (_, actions) = check_hover_result(
1950 " 1950 r"
1951 //- /lib.rs 1951 //- /lib.rs
1952 trait Foo {} 1952 trait Foo {}
1953 trait Bar<T> {} 1953 trait Bar<T> {}
@@ -2028,7 +2028,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
2028 #[test] 2028 #[test]
2029 fn test_hover_arg_generic_impl_trait_has_goto_type_action() { 2029 fn test_hover_arg_generic_impl_trait_has_goto_type_action() {
2030 let (_, actions) = check_hover_result( 2030 let (_, actions) = check_hover_result(
2031 " 2031 r"
2032 //- /lib.rs 2032 //- /lib.rs
2033 trait Foo<T> {} 2033 trait Foo<T> {}
2034 struct S {} 2034 struct S {}
@@ -2088,7 +2088,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
2088 #[test] 2088 #[test]
2089 fn test_hover_dyn_return_has_goto_type_action() { 2089 fn test_hover_dyn_return_has_goto_type_action() {
2090 let (_, actions) = check_hover_result( 2090 let (_, actions) = check_hover_result(
2091 " 2091 r"
2092 //- /main.rs 2092 //- /main.rs
2093 trait Foo {} 2093 trait Foo {}
2094 struct S; 2094 struct S;
@@ -2156,7 +2156,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
2156 #[test] 2156 #[test]
2157 fn test_hover_dyn_arg_has_goto_type_action() { 2157 fn test_hover_dyn_arg_has_goto_type_action() {
2158 let (_, actions) = check_hover_result( 2158 let (_, actions) = check_hover_result(
2159 " 2159 r"
2160 //- /lib.rs 2160 //- /lib.rs
2161 trait Foo {} 2161 trait Foo {}
2162 fn foo(ar<|>g: &dyn Foo) {} 2162 fn foo(ar<|>g: &dyn Foo) {}
@@ -2196,7 +2196,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
2196 #[test] 2196 #[test]
2197 fn test_hover_generic_dyn_arg_has_goto_type_action() { 2197 fn test_hover_generic_dyn_arg_has_goto_type_action() {
2198 let (_, actions) = check_hover_result( 2198 let (_, actions) = check_hover_result(
2199 " 2199 r"
2200 //- /lib.rs 2200 //- /lib.rs
2201 trait Foo<T> {} 2201 trait Foo<T> {}
2202 struct S {} 2202 struct S {}
@@ -2256,7 +2256,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
2256 #[test] 2256 #[test]
2257 fn test_hover_goto_type_action_links_order() { 2257 fn test_hover_goto_type_action_links_order() {
2258 let (_, actions) = check_hover_result( 2258 let (_, actions) = check_hover_result(
2259 " 2259 r"
2260 //- /lib.rs 2260 //- /lib.rs
2261 trait ImplTrait<T> {} 2261 trait ImplTrait<T> {}
2262 trait DynTrait<T> {} 2262 trait DynTrait<T> {}
@@ -2357,7 +2357,7 @@ fn func(foo: i32) { if true { <|>foo; }; }
2357 #[test] 2357 #[test]
2358 fn test_hover_associated_type_has_goto_type_action() { 2358 fn test_hover_associated_type_has_goto_type_action() {
2359 let (_, actions) = check_hover_result( 2359 let (_, actions) = check_hover_result(
2360 " 2360 r"
2361 //- /main.rs 2361 //- /main.rs
2362 trait Foo { 2362 trait Foo {
2363 type Item; 2363 type Item;
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs
index c87652555..62d364bfa 100644
--- a/crates/ra_ide/src/inlay_hints.rs
+++ b/crates/ra_ide/src/inlay_hints.rs
@@ -3,7 +3,7 @@ use ra_ide_db::RootDatabase;
3use ra_prof::profile; 3use ra_prof::profile;
4use ra_syntax::{ 4use ra_syntax::{
5 ast::{self, ArgListOwner, AstNode, TypeAscriptionOwner}, 5 ast::{self, ArgListOwner, AstNode, TypeAscriptionOwner},
6 match_ast, Direction, NodeOrToken, SmolStr, SyntaxKind, TextRange, 6 match_ast, Direction, NodeOrToken, SmolStr, SyntaxKind, TextRange, T,
7}; 7};
8 8
9use crate::{FileId, FunctionSignature}; 9use crate::{FileId, FunctionSignature};
@@ -112,7 +112,7 @@ fn get_chaining_hints(
112 // Ignoring extra whitespace and comments 112 // Ignoring extra whitespace and comments
113 let next = tokens.next()?.kind(); 113 let next = tokens.next()?.kind();
114 let next_next = tokens.next()?.kind(); 114 let next_next = tokens.next()?.kind();
115 if next == SyntaxKind::WHITESPACE && next_next == SyntaxKind::DOT { 115 if next == SyntaxKind::WHITESPACE && next_next == T![.] {
116 let ty = sema.type_of_expr(&expr)?; 116 let ty = sema.type_of_expr(&expr)?;
117 if ty.is_unknown() { 117 if ty.is_unknown() {
118 return None; 118 return None;
@@ -345,583 +345,251 @@ fn get_fn_signature(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option<
345 345
346#[cfg(test)] 346#[cfg(test)]
347mod tests { 347mod tests {
348 use crate::inlay_hints::InlayHintsConfig; 348 use expect::{expect, Expect};
349 use insta::assert_debug_snapshot; 349 use test_utils::extract_annotations;
350 350
351 use crate::mock_analysis::single_file; 351 use crate::{inlay_hints::InlayHintsConfig, mock_analysis::single_file};
352
353 fn check(ra_fixture: &str) {
354 check_with_config(ra_fixture, InlayHintsConfig::default());
355 }
356
357 fn check_with_config(ra_fixture: &str, config: InlayHintsConfig) {
358 let (analysis, file_id) = single_file(ra_fixture);
359 let expected = extract_annotations(&*analysis.file_text(file_id).unwrap());
360 let inlay_hints = analysis.inlay_hints(file_id, &config).unwrap();
361 let actual =
362 inlay_hints.into_iter().map(|it| (it.range, it.label.to_string())).collect::<Vec<_>>();
363 assert_eq!(expected, actual);
364 }
365
366 fn check_expect(ra_fixture: &str, config: InlayHintsConfig, expect: Expect) {
367 let (analysis, file_id) = single_file(ra_fixture);
368 let inlay_hints = analysis.inlay_hints(file_id, &config).unwrap();
369 expect.assert_debug_eq(&inlay_hints)
370 }
352 371
353 #[test] 372 #[test]
354 fn param_hints_only() { 373 fn param_hints_only() {
355 let (analysis, file_id) = single_file( 374 check_with_config(
356 r#" 375 r#"
357 fn foo(a: i32, b: i32) -> i32 { a + b } 376fn foo(a: i32, b: i32) -> i32 { a + b }
358 fn main() { 377fn main() {
359 let _x = foo(4, 4); 378 let _x = foo(
360 }"#, 379 4,
361 ); 380 //^ a
362 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ parameter_hints: true, type_hints: false, chaining_hints: false, max_length: None}).unwrap(), @r###" 381 4,
363 [ 382 //^ b
364 InlayHint { 383 );
365 range: 69..70, 384}"#,
366 kind: ParameterHint, 385 InlayHintsConfig {
367 label: "a", 386 parameter_hints: true,
368 }, 387 type_hints: false,
369 InlayHint { 388 chaining_hints: false,
370 range: 72..73, 389 max_length: None,
371 kind: ParameterHint,
372 label: "b",
373 }, 390 },
374 ] 391 );
375 "###);
376 } 392 }
377 393
378 #[test] 394 #[test]
379 fn hints_disabled() { 395 fn hints_disabled() {
380 let (analysis, file_id) = single_file( 396 check_with_config(
381 r#" 397 r#"
382 fn foo(a: i32, b: i32) -> i32 { a + b } 398fn foo(a: i32, b: i32) -> i32 { a + b }
383 fn main() { 399fn main() {
384 let _x = foo(4, 4); 400 let _x = foo(4, 4);
385 }"#, 401}"#,
402 InlayHintsConfig {
403 type_hints: false,
404 parameter_hints: false,
405 chaining_hints: false,
406 max_length: None,
407 },
386 ); 408 );
387 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ type_hints: false, parameter_hints: false, chaining_hints: false, max_length: None}).unwrap(), @r###"[]"###);
388 } 409 }
389 410
390 #[test] 411 #[test]
391 fn type_hints_only() { 412 fn type_hints_only() {
392 let (analysis, file_id) = single_file( 413 check_with_config(
393 r#" 414 r#"
394 fn foo(a: i32, b: i32) -> i32 { a + b } 415fn foo(a: i32, b: i32) -> i32 { a + b }
395 fn main() { 416fn main() {
396 let _x = foo(4, 4); 417 let _x = foo(4, 4);
397 }"#, 418 //^^ i32
398 ); 419}"#,
399 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ type_hints: true, parameter_hints: false, chaining_hints: false, max_length: None}).unwrap(), @r###" 420 InlayHintsConfig {
400 [ 421 type_hints: true,
401 InlayHint { 422 parameter_hints: false,
402 range: 60..62, 423 chaining_hints: false,
403 kind: TypeHint, 424 max_length: None,
404 label: "i32",
405 }, 425 },
406 ] 426 );
407 "###);
408 } 427 }
428
409 #[test] 429 #[test]
410 fn default_generic_types_should_not_be_displayed() { 430 fn default_generic_types_should_not_be_displayed() {
411 let (analysis, file_id) = single_file( 431 check(
412 r#" 432 r#"
413struct Test<K, T = u8> { 433struct Test<K, T = u8> { k: K, t: T }
414 k: K,
415 t: T,
416}
417 434
418fn main() { 435fn main() {
419 let zz = Test { t: 23u8, k: 33 }; 436 let zz = Test { t: 23u8, k: 33 };
437 //^^ Test<i32>
420 let zz_ref = &zz; 438 let zz_ref = &zz;
439 //^^^^^^ &Test<i32>
421}"#, 440}"#,
422 ); 441 );
423
424 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###"
425 [
426 InlayHint {
427 range: 68..70,
428 kind: TypeHint,
429 label: "Test<i32>",
430 },
431 InlayHint {
432 range: 106..112,
433 kind: TypeHint,
434 label: "&Test<i32>",
435 },
436 ]
437 "###
438 );
439 } 442 }
440 443
441 #[test] 444 #[test]
442 fn let_statement() { 445 fn let_statement() {
443 let (analysis, file_id) = single_file( 446 check(
444 r#" 447 r#"
445#[derive(PartialEq)] 448#[derive(PartialEq)]
446enum CustomOption<T> { 449enum Option<T> { None, Some(T) }
447 None,
448 Some(T),
449}
450 450
451#[derive(PartialEq)] 451#[derive(PartialEq)]
452struct Test { 452struct Test { a: Option<u32>, b: u8 }
453 a: CustomOption<u32>,
454 b: u8,
455}
456 453
457fn main() { 454fn main() {
458 struct InnerStruct {} 455 struct InnerStruct {}
459 456
460 let test = 54; 457 let test = 54;
458 //^^^^ i32
461 let test: i32 = 33; 459 let test: i32 = 33;
462 let mut test = 33; 460 let mut test = 33;
461 //^^^^^^^^ i32
463 let _ = 22; 462 let _ = 22;
464 let test = "test"; 463 let test = "test";
464 //^^^^ &str
465 let test = InnerStruct {}; 465 let test = InnerStruct {};
466 466
467 let test = vec![222]; 467 let test = unresolved();
468 let test: Vec<_> = (0..3).collect();
469 let test = (0..3).collect::<Vec<i128>>();
470 let test = (0..3).collect::<Vec<_>>();
471
472 let mut test = Vec::new();
473 test.push(333);
474 468
475 let test = (42, 'a'); 469 let test = (42, 'a');
476 let (a, (b, c, (d, e), f)) = (2, (3, 4, (6.6, 7.7), 5)); 470 //^^^^ (i32, char)
471 let (a, (b, (c,)) = (2, (3, (9.2,));
472 //^ i32 ^ i32 ^ f64
477 let &x = &92; 473 let &x = &92;
474 //^ i32
478}"#, 475}"#,
479 ); 476 );
480
481 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###"
482 [
483 InlayHint {
484 range: 192..196,
485 kind: TypeHint,
486 label: "i32",
487 },
488 InlayHint {
489 range: 235..243,
490 kind: TypeHint,
491 label: "i32",
492 },
493 InlayHint {
494 range: 274..278,
495 kind: TypeHint,
496 label: "&str",
497 },
498 InlayHint {
499 range: 538..542,
500 kind: TypeHint,
501 label: "(i32, char)",
502 },
503 InlayHint {
504 range: 565..566,
505 kind: TypeHint,
506 label: "i32",
507 },
508 InlayHint {
509 range: 569..570,
510 kind: TypeHint,
511 label: "i32",
512 },
513 InlayHint {
514 range: 572..573,
515 kind: TypeHint,
516 label: "i32",
517 },
518 InlayHint {
519 range: 576..577,
520 kind: TypeHint,
521 label: "f64",
522 },
523 InlayHint {
524 range: 579..580,
525 kind: TypeHint,
526 label: "f64",
527 },
528 InlayHint {
529 range: 583..584,
530 kind: TypeHint,
531 label: "i32",
532 },
533 InlayHint {
534 range: 626..627,
535 kind: TypeHint,
536 label: "i32",
537 },
538 ]
539 "###
540 );
541 } 477 }
542 478
543 #[test] 479 #[test]
544 fn closure_parameters() { 480 fn closure_parameters() {
545 let (analysis, file_id) = single_file( 481 check(
546 r#" 482 r#"
547fn main() { 483fn main() {
548 let mut start = 0; 484 let mut start = 0;
549 (0..2).for_each(|increment| { 485 //^^^^^^^^^ i32
550 start += increment; 486 (0..2).for_each(|increment| { start += increment; });
551 }); 487 //^^^^^^^^^ i32
488
489 let multiply =
490 //^^^^^^^^ |…| -> i32
491 | a, b| a * b
492 //^ i32 ^ i32
493 ;
552 494
553 let multiply = |a, b, c, d| a * b * c * d; 495 let _: i32 = multiply(1, 2);
554 let _: i32 = multiply(1, 2, 3, 4);
555 let multiply_ref = &multiply; 496 let multiply_ref = &multiply;
497 //^^^^^^^^^^^^ &|…| -> i32
556 498
557 let return_42 = || 42; 499 let return_42 = || 42;
500 //^^^^^^^^^ || -> i32
558}"#, 501}"#,
559 ); 502 );
560
561 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###"
562 [
563 InlayHint {
564 range: 20..29,
565 kind: TypeHint,
566 label: "i32",
567 },
568 InlayHint {
569 range: 56..65,
570 kind: TypeHint,
571 label: "i32",
572 },
573 InlayHint {
574 range: 114..122,
575 kind: TypeHint,
576 label: "|…| -> i32",
577 },
578 InlayHint {
579 range: 126..127,
580 kind: TypeHint,
581 label: "i32",
582 },
583 InlayHint {
584 range: 129..130,
585 kind: TypeHint,
586 label: "i32",
587 },
588 InlayHint {
589 range: 132..133,
590 kind: TypeHint,
591 label: "i32",
592 },
593 InlayHint {
594 range: 135..136,
595 kind: TypeHint,
596 label: "i32",
597 },
598 InlayHint {
599 range: 200..212,
600 kind: TypeHint,
601 label: "&|…| -> i32",
602 },
603 InlayHint {
604 range: 235..244,
605 kind: TypeHint,
606 label: "|| -> i32",
607 },
608 ]
609 "###
610 );
611 } 503 }
612 504
613 #[test] 505 #[test]
614 fn for_expression() { 506 fn for_expression() {
615 let (analysis, file_id) = single_file( 507 check(
616 r#" 508 r#"
617fn main() { 509fn main() {
618 let mut start = 0; 510 let mut start = 0;
619 for increment in 0..2 { 511 //^^^^^^^^^ i32
620 start += increment; 512 for increment in 0..2 { start += increment; }
621 } 513 //^^^^^^^^^ i32
622}"#, 514}"#,
623 ); 515 );
624
625 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###"
626 [
627 InlayHint {
628 range: 20..29,
629 kind: TypeHint,
630 label: "i32",
631 },
632 InlayHint {
633 range: 43..52,
634 kind: TypeHint,
635 label: "i32",
636 },
637 ]
638 "###
639 );
640 } 516 }
641 517
642 #[test] 518 #[test]
643 fn if_expr() { 519 fn if_expr() {
644 let (analysis, file_id) = single_file( 520 check(
645 r#" 521 r#"
646#[derive(PartialEq)] 522enum Option<T> { None, Some(T) }
647enum CustomOption<T> { 523use Option::*;
648 None,
649 Some(T),
650}
651
652#[derive(PartialEq)]
653struct Test {
654 a: CustomOption<u32>,
655 b: u8,
656}
657 524
658use CustomOption::*; 525struct Test { a: Option<u32>, b: u8 }
659 526
660fn main() { 527fn main() {
661 let test = Some(Test { a: Some(3), b: 1 }); 528 let test = Some(Test { a: Some(3), b: 1 });
529 //^^^^ Option<Test>
662 if let None = &test {}; 530 if let None = &test {};
663 if let test = &test {}; 531 if let test = &test {};
532 //^^^^ &Option<Test>
664 if let Some(test) = &test {}; 533 if let Some(test) = &test {};
665 if let Some(Test { a, b }) = &test {}; 534 //^^^^ &Test
666 if let Some(Test { a: x, b: y }) = &test {}; 535 if let Some(Test { a, b }) = &test {};
667 if let Some(Test { a: Some(x), b: y }) = &test {}; 536 //^ &Option<u32> ^ &u8
668 if let Some(Test { a: None, b: y }) = &test {}; 537 if let Some(Test { a: x, b: y }) = &test {};
538 //^ &Option<u32> ^ &u8
539 if let Some(Test { a: Some(x), b: y }) = &test {};
540 //^ &u32 ^ &u8
541 if let Some(Test { a: None, b: y }) = &test {};
542 //^ &u8
669 if let Some(Test { b: y, .. }) = &test {}; 543 if let Some(Test { b: y, .. }) = &test {};
670 544 //^ &u8
671 if test == None {} 545 if test == None {}
672}"#, 546}"#,
673 ); 547 );
674
675 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###"
676 [
677 InlayHint {
678 range: 187..191,
679 kind: TypeHint,
680 label: "CustomOption<Test>",
681 },
682 InlayHint {
683 range: 266..270,
684 kind: TypeHint,
685 label: "&CustomOption<Test>",
686 },
687 InlayHint {
688 range: 299..303,
689 kind: TypeHint,
690 label: "&Test",
691 },
692 InlayHint {
693 range: 340..341,
694 kind: TypeHint,
695 label: "&CustomOption<u32>",
696 },
697 InlayHint {
698 range: 343..344,
699 kind: TypeHint,
700 label: "&u8",
701 },
702 InlayHint {
703 range: 386..387,
704 kind: TypeHint,
705 label: "&CustomOption<u32>",
706 },
707 InlayHint {
708 range: 392..393,
709 kind: TypeHint,
710 label: "&u8",
711 },
712 InlayHint {
713 range: 440..441,
714 kind: TypeHint,
715 label: "&u32",
716 },
717 InlayHint {
718 range: 447..448,
719 kind: TypeHint,
720 label: "&u8",
721 },
722 InlayHint {
723 range: 499..500,
724 kind: TypeHint,
725 label: "&u8",
726 },
727 InlayHint {
728 range: 542..543,
729 kind: TypeHint,
730 label: "&u8",
731 },
732 ]
733 "###
734 );
735 } 548 }
736 549
737 #[test] 550 #[test]
738 fn while_expr() { 551 fn while_expr() {
739 let (analysis, file_id) = single_file( 552 check(
740 r#" 553 r#"
741#[derive(PartialEq)] 554enum Option<T> { None, Some(T) }
742enum CustomOption<T> { 555use Option::*;
743 None,
744 Some(T),
745}
746 556
747#[derive(PartialEq)] 557struct Test { a: Option<u32>, b: u8 }
748struct Test {
749 a: CustomOption<u32>,
750 b: u8,
751}
752
753use CustomOption::*;
754 558
755fn main() { 559fn main() {
756 let test = Some(Test { a: Some(3), b: 1 }); 560 let test = Some(Test { a: Some(3), b: 1 });
757 while let None = &test {}; 561 //^^^^ Option<Test>
758 while let test = &test {}; 562 while let Some(Test { a: Some(x), b: y }) = &test {};
759 while let Some(test) = &test {}; 563 //^ &u32 ^ &u8
760 while let Some(Test { a, b }) = &test {};
761 while let Some(Test { a: x, b: y }) = &test {};
762 while let Some(Test { a: Some(x), b: y }) = &test {};
763 while let Some(Test { a: None, b: y }) = &test {};
764 while let Some(Test { b: y, .. }) = &test {};
765
766 while test == None {}
767}"#, 564}"#,
768 ); 565 );
769
770 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###"
771 [
772 InlayHint {
773 range: 187..191,
774 kind: TypeHint,
775 label: "CustomOption<Test>",
776 },
777 InlayHint {
778 range: 272..276,
779 kind: TypeHint,
780 label: "&CustomOption<Test>",
781 },
782 InlayHint {
783 range: 308..312,
784 kind: TypeHint,
785 label: "&Test",
786 },
787 InlayHint {
788 range: 352..353,
789 kind: TypeHint,
790 label: "&CustomOption<u32>",
791 },
792 InlayHint {
793 range: 355..356,
794 kind: TypeHint,
795 label: "&u8",
796 },
797 InlayHint {
798 range: 401..402,
799 kind: TypeHint,
800 label: "&CustomOption<u32>",
801 },
802 InlayHint {
803 range: 407..408,
804 kind: TypeHint,
805 label: "&u8",
806 },
807 InlayHint {
808 range: 458..459,
809 kind: TypeHint,
810 label: "&u32",
811 },
812 InlayHint {
813 range: 465..466,
814 kind: TypeHint,
815 label: "&u8",
816 },
817 InlayHint {
818 range: 520..521,
819 kind: TypeHint,
820 label: "&u8",
821 },
822 InlayHint {
823 range: 566..567,
824 kind: TypeHint,
825 label: "&u8",
826 },
827 ]
828 "###
829 );
830 } 566 }
831 567
832 #[test] 568 #[test]
833 fn match_arm_list() { 569 fn match_arm_list() {
834 let (analysis, file_id) = single_file( 570 check(
835 r#" 571 r#"
836#[derive(PartialEq)] 572enum Option<T> { None, Some(T) }
837enum CustomOption<T> { 573use Option::*;
838 None,
839 Some(T),
840}
841
842#[derive(PartialEq)]
843struct Test {
844 a: CustomOption<u32>,
845 b: u8,
846}
847 574
848use CustomOption::*; 575struct Test { a: Option<u32>, b: u8 }
849 576
850fn main() { 577fn main() {
851 match Some(Test { a: Some(3), b: 1 }) { 578 match Some(Test { a: Some(3), b: 1 }) {
852 None => (), 579 None => (),
853 test => (), 580 test => (),
854 Some(test) => (), 581 //^^^^ Option<Test>
855 Some(Test { a, b }) => (),
856 Some(Test { a: x, b: y }) => (),
857 Some(Test { a: Some(x), b: y }) => (), 582 Some(Test { a: Some(x), b: y }) => (),
858 Some(Test { a: None, b: y }) => (), 583 //^ u32 ^ u8
859 Some(Test { b: y, .. }) => (),
860 _ => {} 584 _ => {}
861 } 585 }
862}"#, 586}"#,
863 ); 587 );
864
865 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###"
866 [
867 InlayHint {
868 range: 251..255,
869 kind: TypeHint,
870 label: "CustomOption<Test>",
871 },
872 InlayHint {
873 range: 276..280,
874 kind: TypeHint,
875 label: "Test",
876 },
877 InlayHint {
878 range: 309..310,
879 kind: TypeHint,
880 label: "CustomOption<u32>",
881 },
882 InlayHint {
883 range: 312..313,
884 kind: TypeHint,
885 label: "u8",
886 },
887 InlayHint {
888 range: 347..348,
889 kind: TypeHint,
890 label: "CustomOption<u32>",
891 },
892 InlayHint {
893 range: 353..354,
894 kind: TypeHint,
895 label: "u8",
896 },
897 InlayHint {
898 range: 393..394,
899 kind: TypeHint,
900 label: "u32",
901 },
902 InlayHint {
903 range: 400..401,
904 kind: TypeHint,
905 label: "u8",
906 },
907 InlayHint {
908 range: 444..445,
909 kind: TypeHint,
910 label: "u8",
911 },
912 InlayHint {
913 range: 479..480,
914 kind: TypeHint,
915 label: "u8",
916 },
917 ]
918 "###
919 );
920 } 588 }
921 589
922 #[test] 590 #[test]
923 fn hint_truncation() { 591 fn hint_truncation() {
924 let (analysis, file_id) = single_file( 592 check_with_config(
925 r#" 593 r#"
926struct Smol<T>(T); 594struct Smol<T>(T);
927 595
@@ -929,52 +597,26 @@ struct VeryLongOuterName<T>(T);
929 597
930fn main() { 598fn main() {
931 let a = Smol(0u32); 599 let a = Smol(0u32);
600 //^ Smol<u32>
932 let b = VeryLongOuterName(0usize); 601 let b = VeryLongOuterName(0usize);
602 //^ VeryLongOuterName<…>
933 let c = Smol(Smol(0u32)) 603 let c = Smol(Smol(0u32))
604 //^ Smol<Smol<…>>
934}"#, 605}"#,
935 ); 606 InlayHintsConfig { max_length: Some(8), ..Default::default() },
936
937 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig { max_length: Some(8), ..Default::default() }).unwrap(), @r###"
938 [
939 InlayHint {
940 range: 73..74,
941 kind: TypeHint,
942 label: "Smol<u32>",
943 },
944 InlayHint {
945 range: 97..98,
946 kind: TypeHint,
947 label: "VeryLongOuterName<…>",
948 },
949 InlayHint {
950 range: 136..137,
951 kind: TypeHint,
952 label: "Smol<Smol<…>>",
953 },
954 ]
955 "###
956 ); 607 );
957 } 608 }
958 609
959 #[test] 610 #[test]
960 fn function_call_parameter_hint() { 611 fn function_call_parameter_hint() {
961 let (analysis, file_id) = single_file( 612 check(
962 r#" 613 r#"
963enum CustomOption<T> { 614enum Option<T> { None, Some(T) }
964 None, 615use Option::*;
965 Some(T),
966}
967use CustomOption::*;
968 616
969struct FileId {} 617struct FileId {}
970struct SmolStr {} 618struct SmolStr {}
971 619
972impl From<&str> for SmolStr {
973 fn from(_: &str) -> Self {
974 unimplemented!()
975 }
976}
977
978struct TextRange {} 620struct TextRange {}
979struct SyntaxKind {} 621struct SyntaxKind {}
980struct NavigationTarget {} 622struct NavigationTarget {}
@@ -982,18 +624,15 @@ struct NavigationTarget {}
982struct Test {} 624struct Test {}
983 625
984impl Test { 626impl Test {
985 fn method(&self, mut param: i32) -> i32 { 627 fn method(&self, mut param: i32) -> i32 { param * 2 }
986 param * 2
987 }
988 628
989 fn from_syntax( 629 fn from_syntax(
990 file_id: FileId, 630 file_id: FileId,
991 name: SmolStr, 631 name: SmolStr,
992 focus_range: CustomOption<TextRange>, 632 focus_range: Option<TextRange>,
993 full_range: TextRange, 633 full_range: TextRange,
994 kind: SyntaxKind, 634 kind: SyntaxKind,
995 docs: CustomOption<String>, 635 docs: Option<String>,
996 description: CustomOption<String>,
997 ) -> NavigationTarget { 636 ) -> NavigationTarget {
998 NavigationTarget {} 637 NavigationTarget {}
999 } 638 }
@@ -1005,108 +644,35 @@ fn test_func(mut foo: i32, bar: i32, msg: &str, _: i32, last: i32) -> i32 {
1005 644
1006fn main() { 645fn main() {
1007 let not_literal = 1; 646 let not_literal = 1;
1008 let _: i32 = test_func(1, 2, "hello", 3, not_literal); 647 //^^^^^^^^^^^ i32
648 let _: i32 = test_func(1, 2, "hello", 3, not_literal);
649 //^ foo ^ bar ^^^^^^^ msg ^^^^^^^^^^^ last
1009 let t: Test = Test {}; 650 let t: Test = Test {};
1010 t.method(123); 651 t.method(123);
1011 Test::method(&t, 3456); 652 //^^^ param
1012 653 Test::method(&t, 3456);
654 //^^ &self ^^^^ param
1013 Test::from_syntax( 655 Test::from_syntax(
1014 FileId {}, 656 FileId {},
657 //^^^^^^^^^ file_id
1015 "impl".into(), 658 "impl".into(),
659 //^^^^^^^^^^^^^ name
1016 None, 660 None,
661 //^^^^ focus_range
1017 TextRange {}, 662 TextRange {},
663 //^^^^^^^^^^^^ full_range
1018 SyntaxKind {}, 664 SyntaxKind {},
665 //^^^^^^^^^^^^^ kind
1019 None, 666 None,
1020 None, 667 //^^^^ docs
1021 ); 668 );
1022}"#, 669}"#,
1023 ); 670 );
1024
1025 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###"
1026 [
1027 InlayHint {
1028 range: 797..808,
1029 kind: TypeHint,
1030 label: "i32",
1031 },
1032 InlayHint {
1033 range: 841..842,
1034 kind: ParameterHint,
1035 label: "foo",
1036 },
1037 InlayHint {
1038 range: 844..845,
1039 kind: ParameterHint,
1040 label: "bar",
1041 },
1042 InlayHint {
1043 range: 847..854,
1044 kind: ParameterHint,
1045 label: "msg",
1046 },
1047 InlayHint {
1048 range: 859..870,
1049 kind: ParameterHint,
1050 label: "last",
1051 },
1052 InlayHint {
1053 range: 913..916,
1054 kind: ParameterHint,
1055 label: "param",
1056 },
1057 InlayHint {
1058 range: 936..938,
1059 kind: ParameterHint,
1060 label: "&self",
1061 },
1062 InlayHint {
1063 range: 940..944,
1064 kind: ParameterHint,
1065 label: "param",
1066 },
1067 InlayHint {
1068 range: 979..988,
1069 kind: ParameterHint,
1070 label: "file_id",
1071 },
1072 InlayHint {
1073 range: 998..1011,
1074 kind: ParameterHint,
1075 label: "name",
1076 },
1077 InlayHint {
1078 range: 1021..1025,
1079 kind: ParameterHint,
1080 label: "focus_range",
1081 },
1082 InlayHint {
1083 range: 1035..1047,
1084 kind: ParameterHint,
1085 label: "full_range",
1086 },
1087 InlayHint {
1088 range: 1057..1070,
1089 kind: ParameterHint,
1090 label: "kind",
1091 },
1092 InlayHint {
1093 range: 1080..1084,
1094 kind: ParameterHint,
1095 label: "docs",
1096 },
1097 InlayHint {
1098 range: 1094..1098,
1099 kind: ParameterHint,
1100 label: "description",
1101 },
1102 ]
1103 "###
1104 );
1105 } 671 }
1106 672
1107 #[test] 673 #[test]
1108 fn omitted_parameters_hints_heuristics() { 674 fn omitted_parameters_hints_heuristics() {
1109 let (analysis, file_id) = single_file( 675 check_with_config(
1110 r#" 676 r#"
1111fn map(f: i32) {} 677fn map(f: i32) {}
1112fn filter(predicate: i32) {} 678fn filter(predicate: i32) {}
@@ -1187,23 +753,16 @@ fn main() {
1187 let _: f64 = a.div_euclid(b); 753 let _: f64 = a.div_euclid(b);
1188 let _: f64 = a.abs_sub(b); 754 let _: f64 = a.abs_sub(b);
1189}"#, 755}"#,
1190 ); 756 InlayHintsConfig { max_length: Some(8), ..Default::default() },
1191
1192 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig { max_length: Some(8), ..Default::default() }).unwrap(), @r###"
1193 []
1194 "###
1195 ); 757 );
1196 } 758 }
1197 759
1198 #[test] 760 #[test]
1199 fn unit_structs_have_no_type_hints() { 761 fn unit_structs_have_no_type_hints() {
1200 let (analysis, file_id) = single_file( 762 check_with_config(
1201 r#" 763 r#"
1202enum CustomResult<T, E> { 764enum Result<T, E> { Ok(T), Err(E) }
1203 Ok(T), 765use Result::*;
1204 Err(E),
1205}
1206use CustomResult::*;
1207 766
1208struct SyntheticSyntax; 767struct SyntheticSyntax;
1209 768
@@ -1213,136 +772,157 @@ fn main() {
1213 Err(SyntheticSyntax) => (), 772 Err(SyntheticSyntax) => (),
1214 } 773 }
1215}"#, 774}"#,
1216 ); 775 InlayHintsConfig { max_length: Some(8), ..Default::default() },
1217
1218 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig { max_length: Some(8), ..Default::default() }).unwrap(), @r###"
1219 []
1220 "###
1221 ); 776 );
1222 } 777 }
1223 778
1224 #[test] 779 #[test]
1225 fn chaining_hints_ignore_comments() { 780 fn chaining_hints_ignore_comments() {
1226 let (analysis, file_id) = single_file( 781 check_expect(
1227 r#" 782 r#"
1228 struct A(B); 783struct A(B);
1229 impl A { fn into_b(self) -> B { self.0 } } 784impl A { fn into_b(self) -> B { self.0 } }
1230 struct B(C); 785struct B(C);
1231 impl B { fn into_c(self) -> C { self.0 } } 786impl B { fn into_c(self) -> C { self.0 } }
1232 struct C; 787struct C;
1233 788
1234 fn main() { 789fn main() {
1235 let c = A(B(C)) 790 let c = A(B(C))
1236 .into_b() // This is a comment 791 .into_b() // This is a comment
1237 .into_c(); 792 .into_c();
1238 }"#, 793}
794"#,
795 InlayHintsConfig {
796 parameter_hints: false,
797 type_hints: false,
798 chaining_hints: true,
799 max_length: None,
800 },
801 expect![[r#"
802 [
803 InlayHint {
804 range: 147..172,
805 kind: ChainingHint,
806 label: "B",
807 },
808 InlayHint {
809 range: 147..154,
810 kind: ChainingHint,
811 label: "A",
812 },
813 ]
814 "#]],
1239 ); 815 );
1240 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###"
1241 [
1242 InlayHint {
1243 range: 147..172,
1244 kind: ChainingHint,
1245 label: "B",
1246 },
1247 InlayHint {
1248 range: 147..154,
1249 kind: ChainingHint,
1250 label: "A",
1251 },
1252 ]
1253 "###);
1254 } 816 }
1255 817
1256 #[test] 818 #[test]
1257 fn chaining_hints_without_newlines() { 819 fn chaining_hints_without_newlines() {
1258 let (analysis, file_id) = single_file( 820 check_with_config(
1259 r#" 821 r#"
1260 struct A(B); 822struct A(B);
1261 impl A { fn into_b(self) -> B { self.0 } } 823impl A { fn into_b(self) -> B { self.0 } }
1262 struct B(C); 824struct B(C);
1263 impl B { fn into_c(self) -> C { self.0 } } 825impl B { fn into_c(self) -> C { self.0 } }
1264 struct C; 826struct C;
1265 827
1266 fn main() { 828fn main() {
1267 let c = A(B(C)).into_b().into_c(); 829 let c = A(B(C)).into_b().into_c();
1268 }"#, 830}"#,
831 InlayHintsConfig {
832 parameter_hints: false,
833 type_hints: false,
834 chaining_hints: true,
835 max_length: None,
836 },
1269 ); 837 );
1270 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###"[]"###);
1271 } 838 }
1272 839
1273 #[test] 840 #[test]
1274 fn struct_access_chaining_hints() { 841 fn struct_access_chaining_hints() {
1275 let (analysis, file_id) = single_file( 842 check_expect(
1276 r#" 843 r#"
1277 struct A { pub b: B } 844struct A { pub b: B }
1278 struct B { pub c: C } 845struct B { pub c: C }
1279 struct C(pub bool); 846struct C(pub bool);
1280 struct D; 847struct D;
1281 848
1282 impl D { 849impl D {
1283 fn foo(&self) -> i32 { 42 } 850 fn foo(&self) -> i32 { 42 }
1284 } 851}
1285 852
1286 fn main() { 853fn main() {
1287 let x = A { b: B { c: C(true) } } 854 let x = A { b: B { c: C(true) } }
1288 .b 855 .b
1289 .c 856 .c
1290 .0; 857 .0;
1291 let x = D 858 let x = D
1292 .foo(); 859 .foo();
1293 }"#, 860}"#,
861 InlayHintsConfig {
862 parameter_hints: false,
863 type_hints: false,
864 chaining_hints: true,
865 max_length: None,
866 },
867 expect![[r#"
868 [
869 InlayHint {
870 range: 143..190,
871 kind: ChainingHint,
872 label: "C",
873 },
874 InlayHint {
875 range: 143..179,
876 kind: ChainingHint,
877 label: "B",
878 },
879 ]
880 "#]],
1294 ); 881 );
1295 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###"
1296 [
1297 InlayHint {
1298 range: 143..190,
1299 kind: ChainingHint,
1300 label: "C",
1301 },
1302 InlayHint {
1303 range: 143..179,
1304 kind: ChainingHint,
1305 label: "B",
1306 },
1307 ]
1308 "###);
1309 } 882 }
1310 883
1311 #[test] 884 #[test]
1312 fn generic_chaining_hints() { 885 fn generic_chaining_hints() {
1313 let (analysis, file_id) = single_file( 886 check_expect(
1314 r#" 887 r#"
1315 struct A<T>(T); 888struct A<T>(T);
1316 struct B<T>(T); 889struct B<T>(T);
1317 struct C<T>(T); 890struct C<T>(T);
1318 struct X<T,R>(T, R); 891struct X<T,R>(T, R);
1319 892
1320 impl<T> A<T> { 893impl<T> A<T> {
1321 fn new(t: T) -> Self { A(t) } 894 fn new(t: T) -> Self { A(t) }
1322 fn into_b(self) -> B<T> { B(self.0) } 895 fn into_b(self) -> B<T> { B(self.0) }
1323 } 896}
1324 impl<T> B<T> { 897impl<T> B<T> {
1325 fn into_c(self) -> C<T> { C(self.0) } 898 fn into_c(self) -> C<T> { C(self.0) }
1326 } 899}
1327 fn main() { 900fn main() {
1328 let c = A::new(X(42, true)) 901 let c = A::new(X(42, true))
1329 .into_b() 902 .into_b()
1330 .into_c(); 903 .into_c();
1331 }"#, 904}
905"#,
906 InlayHintsConfig {
907 parameter_hints: false,
908 type_hints: false,
909 chaining_hints: true,
910 max_length: None,
911 },
912 expect![[r#"
913 [
914 InlayHint {
915 range: 246..283,
916 kind: ChainingHint,
917 label: "B<X<i32, bool>>",
918 },
919 InlayHint {
920 range: 246..265,
921 kind: ChainingHint,
922 label: "A<X<i32, bool>>",
923 },
924 ]
925 "#]],
1332 ); 926 );
1333 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###"
1334 [
1335 InlayHint {
1336 range: 246..283,
1337 kind: ChainingHint,
1338 label: "B<X<i32, bool>>",
1339 },
1340 InlayHint {
1341 range: 246..265,
1342 kind: ChainingHint,
1343 label: "A<X<i32, bool>>",
1344 },
1345 ]
1346 "###);
1347 } 927 }
1348} 928}
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs
index ecac5134e..8660278f1 100644
--- a/crates/ra_ide/src/lib.rs
+++ b/crates/ra_ide/src/lib.rs
@@ -75,7 +75,7 @@ pub use crate::{
75 }, 75 },
76}; 76};
77 77
78pub use hir::Documentation; 78pub use hir::{Documentation, Semantics};
79pub use ra_assists::{Assist, AssistConfig, AssistId, ResolvedAssist}; 79pub use ra_assists::{Assist, AssistConfig, AssistId, ResolvedAssist};
80pub use ra_db::{ 80pub use ra_db::{
81 Canceled, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRoot, 81 Canceled, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRoot,
@@ -385,7 +385,9 @@ impl Analysis {
385 position: FilePosition, 385 position: FilePosition,
386 search_scope: Option<SearchScope>, 386 search_scope: Option<SearchScope>,
387 ) -> Cancelable<Option<ReferenceSearchResult>> { 387 ) -> Cancelable<Option<ReferenceSearchResult>> {
388 self.with_db(|db| references::find_all_refs(db, position, search_scope).map(|it| it.info)) 388 self.with_db(|db| {
389 references::find_all_refs(&Semantics::new(db), position, search_scope).map(|it| it.info)
390 })
389 } 391 }
390 392
391 /// Returns a short text describing element at position. 393 /// Returns a short text describing element at position.
diff --git a/crates/ra_ide/src/mock_analysis.rs b/crates/ra_ide/src/mock_analysis.rs
index 889b84c59..a393d3dba 100644
--- a/crates/ra_ide/src/mock_analysis.rs
+++ b/crates/ra_ide/src/mock_analysis.rs
@@ -3,7 +3,9 @@ use std::sync::Arc;
3 3
4use ra_cfg::CfgOptions; 4use ra_cfg::CfgOptions;
5use ra_db::{CrateName, Env, FileSet, SourceRoot, VfsPath}; 5use ra_db::{CrateName, Env, FileSet, SourceRoot, VfsPath};
6use test_utils::{extract_range_or_offset, Fixture, RangeOrOffset, CURSOR_MARKER}; 6use test_utils::{
7 extract_annotations, extract_range_or_offset, Fixture, RangeOrOffset, CURSOR_MARKER,
8};
7 9
8use crate::{ 10use crate::{
9 Analysis, AnalysisChange, AnalysisHost, CrateGraph, Edition, FileId, FilePosition, FileRange, 11 Analysis, AnalysisChange, AnalysisHost, CrateGraph, Edition, FileId, FilePosition, FileRange,
@@ -77,6 +79,24 @@ impl MockAnalysis {
77 .expect("no file in this mock"); 79 .expect("no file in this mock");
78 FileId(idx as u32 + 1) 80 FileId(idx as u32 + 1)
79 } 81 }
82 pub fn annotations(&self) -> Vec<(FileRange, String)> {
83 self.files
84 .iter()
85 .enumerate()
86 .flat_map(|(idx, fixture)| {
87 let file_id = FileId(idx as u32 + 1);
88 let annotations = extract_annotations(&fixture.text);
89 annotations
90 .into_iter()
91 .map(move |(range, data)| (FileRange { file_id, range }, data))
92 })
93 .collect()
94 }
95 pub fn annotation(&self) -> (FileRange, String) {
96 let mut all = self.annotations();
97 assert_eq!(all.len(), 1);
98 all.pop().unwrap()
99 }
80 pub fn analysis_host(self) -> AnalysisHost { 100 pub fn analysis_host(self) -> AnalysisHost {
81 let mut host = AnalysisHost::default(); 101 let mut host = AnalysisHost::default();
82 let mut change = AnalysisChange::new(); 102 let mut change = AnalysisChange::new();
@@ -110,7 +130,7 @@ impl MockAnalysis {
110 let other_crate = crate_graph.add_crate_root( 130 let other_crate = crate_graph.add_crate_root(
111 file_id, 131 file_id,
112 edition, 132 edition,
113 Some(CrateName::new(crate_name).unwrap()), 133 Some(crate_name.to_string()),
114 cfg, 134 cfg,
115 env, 135 env,
116 Default::default(), 136 Default::default(),
diff --git a/crates/ra_ide/src/references.rs b/crates/ra_ide/src/references.rs
index 3433fdae3..c2b0d5efe 100644
--- a/crates/ra_ide/src/references.rs
+++ b/crates/ra_ide/src/references.rs
@@ -86,12 +86,11 @@ impl IntoIterator for ReferenceSearchResult {
86} 86}
87 87
88pub(crate) fn find_all_refs( 88pub(crate) fn find_all_refs(
89 db: &RootDatabase, 89 sema: &Semantics<RootDatabase>,
90 position: FilePosition, 90 position: FilePosition,
91 search_scope: Option<SearchScope>, 91 search_scope: Option<SearchScope>,
92) -> Option<RangeInfo<ReferenceSearchResult>> { 92) -> Option<RangeInfo<ReferenceSearchResult>> {
93 let _p = profile("find_all_refs"); 93 let _p = profile("find_all_refs");
94 let sema = Semantics::new(db);
95 let syntax = sema.parse(position.file_id).syntax().clone(); 94 let syntax = sema.parse(position.file_id).syntax().clone();
96 95
97 let (opt_name, search_kind) = if let Some(name) = 96 let (opt_name, search_kind) = if let Some(name) =
@@ -108,15 +107,15 @@ pub(crate) fn find_all_refs(
108 let RangeInfo { range, info: def } = find_name(&sema, &syntax, position, opt_name)?; 107 let RangeInfo { range, info: def } = find_name(&sema, &syntax, position, opt_name)?;
109 108
110 let references = def 109 let references = def
111 .find_usages(db, search_scope) 110 .find_usages(sema, search_scope)
112 .into_iter() 111 .into_iter()
113 .filter(|r| search_kind == ReferenceKind::Other || search_kind == r.kind) 112 .filter(|r| search_kind == ReferenceKind::Other || search_kind == r.kind)
114 .collect(); 113 .collect();
115 114
116 let decl_range = def.try_to_nav(db)?.range(); 115 let decl_range = def.try_to_nav(sema.db)?.range();
117 116
118 let declaration = Declaration { 117 let declaration = Declaration {
119 nav: def.try_to_nav(db)?, 118 nav: def.try_to_nav(sema.db)?,
120 kind: ReferenceKind::Other, 119 kind: ReferenceKind::Other,
121 access: decl_access(&def, &syntax, decl_range), 120 access: decl_access(&def, &syntax, decl_range),
122 }; 121 };
diff --git a/crates/ra_ide/src/references/rename.rs b/crates/ra_ide/src/references/rename.rs
index 7ebc0adcf..b6a2266b4 100644
--- a/crates/ra_ide/src/references/rename.rs
+++ b/crates/ra_ide/src/references/rename.rs
@@ -24,23 +24,24 @@ pub(crate) fn rename(
24 position: FilePosition, 24 position: FilePosition,
25 new_name: &str, 25 new_name: &str,
26) -> Option<RangeInfo<SourceChange>> { 26) -> Option<RangeInfo<SourceChange>> {
27 let sema = Semantics::new(db);
28
27 match lex_single_valid_syntax_kind(new_name)? { 29 match lex_single_valid_syntax_kind(new_name)? {
28 SyntaxKind::IDENT | SyntaxKind::UNDERSCORE => (), 30 SyntaxKind::IDENT | SyntaxKind::UNDERSCORE => (),
29 SyntaxKind::SELF_KW => return rename_to_self(db, position), 31 SyntaxKind::SELF_KW => return rename_to_self(&sema, position),
30 _ => return None, 32 _ => return None,
31 } 33 }
32 34
33 let sema = Semantics::new(db);
34 let source_file = sema.parse(position.file_id); 35 let source_file = sema.parse(position.file_id);
35 let syntax = source_file.syntax(); 36 let syntax = source_file.syntax();
36 if let Some(module) = find_module_at_offset(&sema, position, syntax) { 37 if let Some(module) = find_module_at_offset(&sema, position, syntax) {
37 rename_mod(db, position, module, new_name) 38 rename_mod(&sema, position, module, new_name)
38 } else if let Some(self_token) = 39 } else if let Some(self_token) =
39 syntax.token_at_offset(position.offset).find(|t| t.kind() == SyntaxKind::SELF_KW) 40 syntax.token_at_offset(position.offset).find(|t| t.kind() == SyntaxKind::SELF_KW)
40 { 41 {
41 rename_self_to_param(db, position, self_token, new_name) 42 rename_self_to_param(&sema, position, self_token, new_name)
42 } else { 43 } else {
43 rename_reference(sema.db, position, new_name) 44 rename_reference(&sema, position, new_name)
44 } 45 }
45} 46}
46 47
@@ -97,7 +98,7 @@ fn source_edit_from_reference(reference: Reference, new_name: &str) -> SourceFil
97} 98}
98 99
99fn rename_mod( 100fn rename_mod(
100 db: &RootDatabase, 101 sema: &Semantics<RootDatabase>,
101 position: FilePosition, 102 position: FilePosition,
102 module: Module, 103 module: Module,
103 new_name: &str, 104 new_name: &str,
@@ -105,12 +106,12 @@ fn rename_mod(
105 let mut source_file_edits = Vec::new(); 106 let mut source_file_edits = Vec::new();
106 let mut file_system_edits = Vec::new(); 107 let mut file_system_edits = Vec::new();
107 108
108 let src = module.definition_source(db); 109 let src = module.definition_source(sema.db);
109 let file_id = src.file_id.original_file(db); 110 let file_id = src.file_id.original_file(sema.db);
110 match src.value { 111 match src.value {
111 ModuleSource::SourceFile(..) => { 112 ModuleSource::SourceFile(..) => {
112 // mod is defined in path/to/dir/mod.rs 113 // mod is defined in path/to/dir/mod.rs
113 let dst = if module.is_mod_rs(db) { 114 let dst = if module.is_mod_rs(sema.db) {
114 format!("../{}/mod.rs", new_name) 115 format!("../{}/mod.rs", new_name)
115 } else { 116 } else {
116 format!("{}.rs", new_name) 117 format!("{}.rs", new_name)
@@ -122,17 +123,17 @@ fn rename_mod(
122 ModuleSource::Module(..) => {} 123 ModuleSource::Module(..) => {}
123 } 124 }
124 125
125 if let Some(src) = module.declaration_source(db) { 126 if let Some(src) = module.declaration_source(sema.db) {
126 let file_id = src.file_id.original_file(db); 127 let file_id = src.file_id.original_file(sema.db);
127 let name = src.value.name()?; 128 let name = src.value.name()?;
128 let edit = SourceFileEdit { 129 let edit = SourceFileEdit {
129 file_id: file_id, 130 file_id,
130 edit: TextEdit::replace(name.syntax().text_range(), new_name.into()), 131 edit: TextEdit::replace(name.syntax().text_range(), new_name.into()),
131 }; 132 };
132 source_file_edits.push(edit); 133 source_file_edits.push(edit);
133 } 134 }
134 135
135 let RangeInfo { range, info: refs } = find_all_refs(db, position, None)?; 136 let RangeInfo { range, info: refs } = find_all_refs(sema, position, None)?;
136 let ref_edits = refs 137 let ref_edits = refs
137 .references 138 .references
138 .into_iter() 139 .into_iter()
@@ -142,8 +143,10 @@ fn rename_mod(
142 Some(RangeInfo::new(range, SourceChange::from_edits(source_file_edits, file_system_edits))) 143 Some(RangeInfo::new(range, SourceChange::from_edits(source_file_edits, file_system_edits)))
143} 144}
144 145
145fn rename_to_self(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<SourceChange>> { 146fn rename_to_self(
146 let sema = Semantics::new(db); 147 sema: &Semantics<RootDatabase>,
148 position: FilePosition,
149) -> Option<RangeInfo<SourceChange>> {
147 let source_file = sema.parse(position.file_id); 150 let source_file = sema.parse(position.file_id);
148 let syn = source_file.syntax(); 151 let syn = source_file.syntax();
149 152
@@ -158,7 +161,7 @@ fn rename_to_self(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo
158 _ => return None, // not renaming other types 161 _ => return None, // not renaming other types
159 }; 162 };
160 163
161 let RangeInfo { range, info: refs } = find_all_refs(db, position, None)?; 164 let RangeInfo { range, info: refs } = find_all_refs(sema, position, None)?;
162 165
163 let param_range = first_param.syntax().text_range(); 166 let param_range = first_param.syntax().text_range();
164 let (param_ref, usages): (Vec<Reference>, Vec<Reference>) = refs 167 let (param_ref, usages): (Vec<Reference>, Vec<Reference>) = refs
@@ -210,16 +213,15 @@ fn text_edit_from_self_param(
210} 213}
211 214
212fn rename_self_to_param( 215fn rename_self_to_param(
213 db: &RootDatabase, 216 sema: &Semantics<RootDatabase>,
214 position: FilePosition, 217 position: FilePosition,
215 self_token: SyntaxToken, 218 self_token: SyntaxToken,
216 new_name: &str, 219 new_name: &str,
217) -> Option<RangeInfo<SourceChange>> { 220) -> Option<RangeInfo<SourceChange>> {
218 let sema = Semantics::new(db);
219 let source_file = sema.parse(position.file_id); 221 let source_file = sema.parse(position.file_id);
220 let syn = source_file.syntax(); 222 let syn = source_file.syntax();
221 223
222 let text = db.file_text(position.file_id); 224 let text = sema.db.file_text(position.file_id);
223 let fn_def = find_node_at_offset::<ast::FnDef>(syn, position.offset)?; 225 let fn_def = find_node_at_offset::<ast::FnDef>(syn, position.offset)?;
224 let search_range = fn_def.syntax().text_range(); 226 let search_range = fn_def.syntax().text_range();
225 227
@@ -249,11 +251,11 @@ fn rename_self_to_param(
249} 251}
250 252
251fn rename_reference( 253fn rename_reference(
252 db: &RootDatabase, 254 sema: &Semantics<RootDatabase>,
253 position: FilePosition, 255 position: FilePosition,
254 new_name: &str, 256 new_name: &str,
255) -> Option<RangeInfo<SourceChange>> { 257) -> Option<RangeInfo<SourceChange>> {
256 let RangeInfo { range, info: refs } = find_all_refs(db, position, None)?; 258 let RangeInfo { range, info: refs } = find_all_refs(sema, position, None)?;
257 259
258 let edit = refs 260 let edit = refs
259 .into_iter() 261 .into_iter()
diff --git a/crates/ra_ide/src/runnables.rs b/crates/ra_ide/src/runnables.rs
index f569a3f17..ed15d6494 100644
--- a/crates/ra_ide/src/runnables.rs
+++ b/crates/ra_ide/src/runnables.rs
@@ -251,13 +251,21 @@ fn runnable_mod(
251 251
252#[cfg(test)] 252#[cfg(test)]
253mod tests { 253mod tests {
254 use insta::assert_debug_snapshot; 254 use expect::{expect, Expect};
255 255
256 use crate::mock_analysis::analysis_and_position; 256 use crate::mock_analysis::analysis_and_position;
257 257
258 use super::{Runnable, RunnableAction, BENCH, BIN, DOCTEST, TEST}; 258 use super::{RunnableAction, BENCH, BIN, DOCTEST, TEST};
259 259
260 fn assert_actions(runnables: &[Runnable], actions: &[&RunnableAction]) { 260 fn check(
261 ra_fixture: &str,
262 // FIXME: fold this into `expect` as well
263 actions: &[&RunnableAction],
264 expect: Expect,
265 ) {
266 let (analysis, position) = analysis_and_position(ra_fixture);
267 let runnables = analysis.runnables(position.file_id).unwrap();
268 expect.assert_debug_eq(&runnables);
261 assert_eq!( 269 assert_eq!(
262 actions, 270 actions,
263 runnables.into_iter().map(|it| it.action()).collect::<Vec<_>>().as_slice() 271 runnables.into_iter().map(|it| it.action()).collect::<Vec<_>>().as_slice()
@@ -266,579 +274,557 @@ mod tests {
266 274
267 #[test] 275 #[test]
268 fn test_runnables() { 276 fn test_runnables() {
269 let (analysis, pos) = analysis_and_position( 277 check(
270 r#" 278 r#"
271 //- /lib.rs 279//- /lib.rs
272 <|> //empty 280<|>
273 fn main() {} 281fn main() {}
274 282
275 #[test] 283#[test]
276 fn test_foo() {} 284fn test_foo() {}
277 285
278 #[test] 286#[test]
279 #[ignore] 287#[ignore]
280 fn test_foo() {} 288fn test_foo() {}
281 289
282 #[bench] 290#[bench]
283 fn bench() {} 291fn bench() {}
284 "#, 292"#,
285 ); 293 &[&BIN, &TEST, &TEST, &BENCH],
286 let runnables = analysis.runnables(pos.file_id).unwrap(); 294 expect![[r#"
287 assert_debug_snapshot!(&runnables, 295 [
288 @r###" 296 Runnable {
289 [ 297 nav: NavigationTarget {
290 Runnable { 298 file_id: FileId(
291 nav: NavigationTarget { 299 1,
292 file_id: FileId( 300 ),
293 1, 301 full_range: 1..13,
294 ), 302 name: "main",
295 full_range: 1..21, 303 kind: FN_DEF,
296 name: "main", 304 focus_range: Some(
297 kind: FN_DEF, 305 4..8,
298 focus_range: Some( 306 ),
299 12..16, 307 container_name: None,
300 ), 308 description: None,
301 container_name: None, 309 docs: None,
302 description: None, 310 },
303 docs: None, 311 kind: Bin,
304 }, 312 cfg_exprs: [],
305 kind: Bin,
306 cfg_exprs: [],
307 },
308 Runnable {
309 nav: NavigationTarget {
310 file_id: FileId(
311 1,
312 ),
313 full_range: 23..47,
314 name: "test_foo",
315 kind: FN_DEF,
316 focus_range: Some(
317 34..42,
318 ),
319 container_name: None,
320 description: None,
321 docs: None,
322 },
323 kind: Test {
324 test_id: Path(
325 "test_foo",
326 ),
327 attr: TestAttr {
328 ignore: false,
329 }, 313 },
330 }, 314 Runnable {
331 cfg_exprs: [], 315 nav: NavigationTarget {
332 }, 316 file_id: FileId(
333 Runnable { 317 1,
334 nav: NavigationTarget { 318 ),
335 file_id: FileId( 319 full_range: 15..39,
336 1, 320 name: "test_foo",
337 ), 321 kind: FN_DEF,
338 full_range: 49..83, 322 focus_range: Some(
339 name: "test_foo", 323 26..34,
340 kind: FN_DEF, 324 ),
341 focus_range: Some( 325 container_name: None,
342 70..78, 326 description: None,
343 ), 327 docs: None,
344 container_name: None, 328 },
345 description: None, 329 kind: Test {
346 docs: None, 330 test_id: Path(
347 }, 331 "test_foo",
348 kind: Test { 332 ),
349 test_id: Path( 333 attr: TestAttr {
350 "test_foo", 334 ignore: false,
351 ), 335 },
352 attr: TestAttr { 336 },
353 ignore: true, 337 cfg_exprs: [],
338 },
339 Runnable {
340 nav: NavigationTarget {
341 file_id: FileId(
342 1,
343 ),
344 full_range: 41..75,
345 name: "test_foo",
346 kind: FN_DEF,
347 focus_range: Some(
348 62..70,
349 ),
350 container_name: None,
351 description: None,
352 docs: None,
353 },
354 kind: Test {
355 test_id: Path(
356 "test_foo",
357 ),
358 attr: TestAttr {
359 ignore: true,
360 },
361 },
362 cfg_exprs: [],
354 }, 363 },
355 }, 364 Runnable {
356 cfg_exprs: [], 365 nav: NavigationTarget {
357 }, 366 file_id: FileId(
358 Runnable { 367 1,
359 nav: NavigationTarget { 368 ),
360 file_id: FileId( 369 full_range: 77..99,
361 1, 370 name: "bench",
362 ), 371 kind: FN_DEF,
363 full_range: 85..107, 372 focus_range: Some(
364 name: "bench", 373 89..94,
365 kind: FN_DEF, 374 ),
366 focus_range: Some( 375 container_name: None,
367 97..102, 376 description: None,
368 ), 377 docs: None,
369 container_name: None, 378 },
370 description: None, 379 kind: Bench {
371 docs: None, 380 test_id: Path(
372 }, 381 "bench",
373 kind: Bench { 382 ),
374 test_id: Path( 383 },
375 "bench", 384 cfg_exprs: [],
376 ), 385 },
377 }, 386 ]
378 cfg_exprs: [], 387 "#]],
379 }, 388 );
380 ]
381 "###
382 );
383 assert_actions(&runnables, &[&BIN, &TEST, &TEST, &BENCH]);
384 } 389 }
385 390
386 #[test] 391 #[test]
387 fn test_runnables_doc_test() { 392 fn test_runnables_doc_test() {
388 let (analysis, pos) = analysis_and_position( 393 check(
389 r#" 394 r#"
390 //- /lib.rs 395//- /lib.rs
391 <|> //empty 396<|>
392 fn main() {} 397fn main() {}
393 398
394 /// ``` 399/// ```
395 /// let x = 5; 400/// let x = 5;
396 /// ``` 401/// ```
397 fn foo() {} 402fn foo() {}
398 "#, 403"#,
404 &[&BIN, &DOCTEST],
405 expect![[r#"
406 [
407 Runnable {
408 nav: NavigationTarget {
409 file_id: FileId(
410 1,
411 ),
412 full_range: 1..13,
413 name: "main",
414 kind: FN_DEF,
415 focus_range: Some(
416 4..8,
417 ),
418 container_name: None,
419 description: None,
420 docs: None,
421 },
422 kind: Bin,
423 cfg_exprs: [],
424 },
425 Runnable {
426 nav: NavigationTarget {
427 file_id: FileId(
428 1,
429 ),
430 full_range: 15..57,
431 name: "foo",
432 kind: FN_DEF,
433 focus_range: None,
434 container_name: None,
435 description: None,
436 docs: None,
437 },
438 kind: DocTest {
439 test_id: Path(
440 "foo",
441 ),
442 },
443 cfg_exprs: [],
444 },
445 ]
446 "#]],
399 ); 447 );
400 let runnables = analysis.runnables(pos.file_id).unwrap();
401 assert_debug_snapshot!(&runnables,
402 @r###"
403 [
404 Runnable {
405 nav: NavigationTarget {
406 file_id: FileId(
407 1,
408 ),
409 full_range: 1..21,
410 name: "main",
411 kind: FN_DEF,
412 focus_range: Some(
413 12..16,
414 ),
415 container_name: None,
416 description: None,
417 docs: None,
418 },
419 kind: Bin,
420 cfg_exprs: [],
421 },
422 Runnable {
423 nav: NavigationTarget {
424 file_id: FileId(
425 1,
426 ),
427 full_range: 23..65,
428 name: "foo",
429 kind: FN_DEF,
430 focus_range: None,
431 container_name: None,
432 description: None,
433 docs: None,
434 },
435 kind: DocTest {
436 test_id: Path(
437 "foo",
438 ),
439 },
440 cfg_exprs: [],
441 },
442 ]
443 "###
444 );
445 assert_actions(&runnables, &[&BIN, &DOCTEST]);
446 } 448 }
447 449
448 #[test] 450 #[test]
449 fn test_runnables_doc_test_in_impl() { 451 fn test_runnables_doc_test_in_impl() {
450 let (analysis, pos) = analysis_and_position( 452 check(
451 r#" 453 r#"
452 //- /lib.rs 454//- /lib.rs
453 <|> //empty 455<|>
454 fn main() {} 456fn main() {}
455 457
456 struct Data; 458struct Data;
457 impl Data { 459impl Data {
458 /// ``` 460 /// ```
459 /// let x = 5; 461 /// let x = 5;
460 /// ``` 462 /// ```
461 fn foo() {} 463 fn foo() {}
462 } 464}
463 "#, 465"#,
466 &[&BIN, &DOCTEST],
467 expect![[r#"
468 [
469 Runnable {
470 nav: NavigationTarget {
471 file_id: FileId(
472 1,
473 ),
474 full_range: 1..13,
475 name: "main",
476 kind: FN_DEF,
477 focus_range: Some(
478 4..8,
479 ),
480 container_name: None,
481 description: None,
482 docs: None,
483 },
484 kind: Bin,
485 cfg_exprs: [],
486 },
487 Runnable {
488 nav: NavigationTarget {
489 file_id: FileId(
490 1,
491 ),
492 full_range: 44..98,
493 name: "foo",
494 kind: FN_DEF,
495 focus_range: None,
496 container_name: None,
497 description: None,
498 docs: None,
499 },
500 kind: DocTest {
501 test_id: Path(
502 "Data::foo",
503 ),
504 },
505 cfg_exprs: [],
506 },
507 ]
508 "#]],
464 ); 509 );
465 let runnables = analysis.runnables(pos.file_id).unwrap();
466 assert_debug_snapshot!(&runnables,
467 @r###"
468 [
469 Runnable {
470 nav: NavigationTarget {
471 file_id: FileId(
472 1,
473 ),
474 full_range: 1..21,
475 name: "main",
476 kind: FN_DEF,
477 focus_range: Some(
478 12..16,
479 ),
480 container_name: None,
481 description: None,
482 docs: None,
483 },
484 kind: Bin,
485 cfg_exprs: [],
486 },
487 Runnable {
488 nav: NavigationTarget {
489 file_id: FileId(
490 1,
491 ),
492 full_range: 52..106,
493 name: "foo",
494 kind: FN_DEF,
495 focus_range: None,
496 container_name: None,
497 description: None,
498 docs: None,
499 },
500 kind: DocTest {
501 test_id: Path(
502 "Data::foo",
503 ),
504 },
505 cfg_exprs: [],
506 },
507 ]
508 "###
509 );
510 assert_actions(&runnables, &[&BIN, &DOCTEST]);
511 } 510 }
512 511
513 #[test] 512 #[test]
514 fn test_runnables_module() { 513 fn test_runnables_module() {
515 let (analysis, pos) = analysis_and_position( 514 check(
516 r#" 515 r#"
517 //- /lib.rs 516//- /lib.rs
518 <|> //empty 517<|>
519 mod test_mod { 518mod test_mod {
520 #[test] 519 #[test]
521 fn test_foo1() {} 520 fn test_foo1() {}
522 } 521}
523 "#, 522"#,
524 ); 523 &[&TEST, &TEST],
525 let runnables = analysis.runnables(pos.file_id).unwrap(); 524 expect![[r#"
526 assert_debug_snapshot!(&runnables, 525 [
527 @r###" 526 Runnable {
528 [ 527 nav: NavigationTarget {
529 Runnable { 528 file_id: FileId(
530 nav: NavigationTarget { 529 1,
531 file_id: FileId( 530 ),
532 1, 531 full_range: 1..51,
533 ), 532 name: "test_mod",
534 full_range: 1..59, 533 kind: MODULE,
535 name: "test_mod", 534 focus_range: Some(
536 kind: MODULE, 535 5..13,
537 focus_range: Some( 536 ),
538 13..21, 537 container_name: None,
539 ), 538 description: None,
540 container_name: None, 539 docs: None,
541 description: None, 540 },
542 docs: None, 541 kind: TestMod {
543 }, 542 path: "test_mod",
544 kind: TestMod { 543 },
545 path: "test_mod", 544 cfg_exprs: [],
546 }, 545 },
547 cfg_exprs: [], 546 Runnable {
548 }, 547 nav: NavigationTarget {
549 Runnable { 548 file_id: FileId(
550 nav: NavigationTarget { 549 1,
551 file_id: FileId( 550 ),
552 1, 551 full_range: 20..49,
553 ), 552 name: "test_foo1",
554 full_range: 28..57, 553 kind: FN_DEF,
555 name: "test_foo1", 554 focus_range: Some(
556 kind: FN_DEF, 555 35..44,
557 focus_range: Some( 556 ),
558 43..52, 557 container_name: None,
559 ), 558 description: None,
560 container_name: None, 559 docs: None,
561 description: None, 560 },
562 docs: None, 561 kind: Test {
563 }, 562 test_id: Path(
564 kind: Test { 563 "test_mod::test_foo1",
565 test_id: Path( 564 ),
566 "test_mod::test_foo1", 565 attr: TestAttr {
567 ), 566 ignore: false,
568 attr: TestAttr { 567 },
569 ignore: false, 568 },
569 cfg_exprs: [],
570 }, 570 },
571 }, 571 ]
572 cfg_exprs: [], 572 "#]],
573 }, 573 );
574 ]
575 "###
576 );
577 assert_actions(&runnables, &[&TEST, &TEST]);
578 } 574 }
579 575
580 #[test] 576 #[test]
581 fn test_runnables_one_depth_layer_module() { 577 fn test_runnables_one_depth_layer_module() {
582 let (analysis, pos) = analysis_and_position( 578 check(
583 r#" 579 r#"
584 //- /lib.rs 580//- /lib.rs
585 <|> //empty 581<|>
586 mod foo { 582mod foo {
587 mod test_mod { 583 mod test_mod {
588 #[test] 584 #[test]
589 fn test_foo1() {} 585 fn test_foo1() {}
590 } 586 }
591 } 587}
592 "#, 588"#,
593 ); 589 &[&TEST, &TEST],
594 let runnables = analysis.runnables(pos.file_id).unwrap(); 590 expect![[r#"
595 assert_debug_snapshot!(&runnables, 591 [
596 @r###" 592 Runnable {
597 [ 593 nav: NavigationTarget {
598 Runnable { 594 file_id: FileId(
599 nav: NavigationTarget { 595 1,
600 file_id: FileId( 596 ),
601 1, 597 full_range: 15..77,
602 ), 598 name: "test_mod",
603 full_range: 23..85, 599 kind: MODULE,
604 name: "test_mod", 600 focus_range: Some(
605 kind: MODULE, 601 19..27,
606 focus_range: Some( 602 ),
607 27..35, 603 container_name: None,
608 ), 604 description: None,
609 container_name: None, 605 docs: None,
610 description: None, 606 },
611 docs: None, 607 kind: TestMod {
612 }, 608 path: "foo::test_mod",
613 kind: TestMod { 609 },
614 path: "foo::test_mod", 610 cfg_exprs: [],
615 }, 611 },
616 cfg_exprs: [], 612 Runnable {
617 }, 613 nav: NavigationTarget {
618 Runnable { 614 file_id: FileId(
619 nav: NavigationTarget { 615 1,
620 file_id: FileId( 616 ),
621 1, 617 full_range: 38..71,
622 ), 618 name: "test_foo1",
623 full_range: 46..79, 619 kind: FN_DEF,
624 name: "test_foo1", 620 focus_range: Some(
625 kind: FN_DEF, 621 57..66,
626 focus_range: Some( 622 ),
627 65..74, 623 container_name: None,
628 ), 624 description: None,
629 container_name: None, 625 docs: None,
630 description: None, 626 },
631 docs: None, 627 kind: Test {
632 }, 628 test_id: Path(
633 kind: Test { 629 "foo::test_mod::test_foo1",
634 test_id: Path( 630 ),
635 "foo::test_mod::test_foo1", 631 attr: TestAttr {
636 ), 632 ignore: false,
637 attr: TestAttr { 633 },
638 ignore: false, 634 },
635 cfg_exprs: [],
639 }, 636 },
640 }, 637 ]
641 cfg_exprs: [], 638 "#]],
642 }, 639 );
643 ]
644 "###
645 );
646 assert_actions(&runnables, &[&TEST, &TEST]);
647 } 640 }
648 641
649 #[test] 642 #[test]
650 fn test_runnables_multiple_depth_module() { 643 fn test_runnables_multiple_depth_module() {
651 let (analysis, pos) = analysis_and_position( 644 check(
652 r#" 645 r#"
653 //- /lib.rs 646//- /lib.rs
654 <|> //empty 647<|>
655 mod foo { 648mod foo {
656 mod bar { 649 mod bar {
657 mod test_mod { 650 mod test_mod {
658 #[test] 651 #[test]
659 fn test_foo1() {} 652 fn test_foo1() {}
660 }
661 }
662 } 653 }
663 "#, 654 }
664 ); 655}
665 let runnables = analysis.runnables(pos.file_id).unwrap(); 656"#,
666 assert_debug_snapshot!(&runnables, 657 &[&TEST, &TEST],
667 @r###" 658 expect![[r#"
668 [ 659 [
669 Runnable { 660 Runnable {
670 nav: NavigationTarget { 661 nav: NavigationTarget {
671 file_id: FileId( 662 file_id: FileId(
672 1, 663 1,
673 ), 664 ),
674 full_range: 41..115, 665 full_range: 33..107,
675 name: "test_mod", 666 name: "test_mod",
676 kind: MODULE, 667 kind: MODULE,
677 focus_range: Some( 668 focus_range: Some(
678 45..53, 669 37..45,
679 ), 670 ),
680 container_name: None, 671 container_name: None,
681 description: None, 672 description: None,
682 docs: None, 673 docs: None,
683 }, 674 },
684 kind: TestMod { 675 kind: TestMod {
685 path: "foo::bar::test_mod", 676 path: "foo::bar::test_mod",
686 }, 677 },
687 cfg_exprs: [], 678 cfg_exprs: [],
688 }, 679 },
689 Runnable { 680 Runnable {
690 nav: NavigationTarget { 681 nav: NavigationTarget {
691 file_id: FileId( 682 file_id: FileId(
692 1, 683 1,
693 ), 684 ),
694 full_range: 68..105, 685 full_range: 60..97,
695 name: "test_foo1", 686 name: "test_foo1",
696 kind: FN_DEF, 687 kind: FN_DEF,
697 focus_range: Some( 688 focus_range: Some(
698 91..100, 689 83..92,
699 ), 690 ),
700 container_name: None, 691 container_name: None,
701 description: None, 692 description: None,
702 docs: None, 693 docs: None,
703 }, 694 },
704 kind: Test { 695 kind: Test {
705 test_id: Path( 696 test_id: Path(
706 "foo::bar::test_mod::test_foo1", 697 "foo::bar::test_mod::test_foo1",
707 ), 698 ),
708 attr: TestAttr { 699 attr: TestAttr {
709 ignore: false, 700 ignore: false,
701 },
702 },
703 cfg_exprs: [],
710 }, 704 },
711 }, 705 ]
712 cfg_exprs: [], 706 "#]],
713 }, 707 );
714 ]
715 "###
716 );
717 assert_actions(&runnables, &[&TEST, &TEST]);
718 } 708 }
719 709
720 #[test] 710 #[test]
721 fn test_runnables_with_feature() { 711 fn test_runnables_with_feature() {
722 let (analysis, pos) = analysis_and_position( 712 check(
723 r#" 713 r#"
724 //- /lib.rs crate:foo cfg:feature=foo 714//- /lib.rs crate:foo cfg:feature=foo
725 <|> //empty 715<|>
726 #[test] 716#[test]
727 #[cfg(feature = "foo")] 717#[cfg(feature = "foo")]
728 fn test_foo1() {} 718fn test_foo1() {}
729 "#, 719"#,
730 ); 720 &[&TEST],
731 let runnables = analysis.runnables(pos.file_id).unwrap(); 721 expect![[r#"
732 assert_debug_snapshot!(&runnables, 722 [
733 @r###" 723 Runnable {
734 [ 724 nav: NavigationTarget {
735 Runnable { 725 file_id: FileId(
736 nav: NavigationTarget { 726 1,
737 file_id: FileId( 727 ),
738 1, 728 full_range: 1..50,
739 ), 729 name: "test_foo1",
740 full_range: 1..58, 730 kind: FN_DEF,
741 name: "test_foo1", 731 focus_range: Some(
742 kind: FN_DEF, 732 36..45,
743 focus_range: Some( 733 ),
744 44..53, 734 container_name: None,
745 ), 735 description: None,
746 container_name: None, 736 docs: None,
747 description: None, 737 },
748 docs: None, 738 kind: Test {
749 }, 739 test_id: Path(
750 kind: Test { 740 "test_foo1",
751 test_id: Path( 741 ),
752 "test_foo1", 742 attr: TestAttr {
753 ), 743 ignore: false,
754 attr: TestAttr { 744 },
755 ignore: false, 745 },
756 }, 746 cfg_exprs: [
757 }, 747 KeyValue {
758 cfg_exprs: [ 748 key: "feature",
759 KeyValue { 749 value: "foo",
760 key: "feature", 750 },
761 value: "foo", 751 ],
762 }, 752 },
763 ], 753 ]
764 }, 754 "#]],
765 ] 755 );
766 "###
767 );
768 assert_actions(&runnables, &[&TEST]);
769 } 756 }
770 757
771 #[test] 758 #[test]
772 fn test_runnables_with_features() { 759 fn test_runnables_with_features() {
773 let (analysis, pos) = analysis_and_position( 760 check(
774 r#" 761 r#"
775 //- /lib.rs crate:foo cfg:feature=foo,feature=bar 762//- /lib.rs crate:foo cfg:feature=foo,feature=bar
776 <|> //empty 763<|>
777 #[test] 764#[test]
778 #[cfg(all(feature = "foo", feature = "bar"))] 765#[cfg(all(feature = "foo", feature = "bar"))]
779 fn test_foo1() {} 766fn test_foo1() {}
780 "#, 767"#,
781 ); 768 &[&TEST],
782 let runnables = analysis.runnables(pos.file_id).unwrap(); 769 expect![[r#"
783 assert_debug_snapshot!(&runnables, 770 [
784 @r###" 771 Runnable {
785 [ 772 nav: NavigationTarget {
786 Runnable { 773 file_id: FileId(
787 nav: NavigationTarget { 774 1,
788 file_id: FileId( 775 ),
789 1, 776 full_range: 1..72,
790 ), 777 name: "test_foo1",
791 full_range: 1..80, 778 kind: FN_DEF,
792 name: "test_foo1", 779 focus_range: Some(
793 kind: FN_DEF, 780 58..67,
794 focus_range: Some( 781 ),
795 66..75, 782 container_name: None,
796 ), 783 description: None,
797 container_name: None, 784 docs: None,
798 description: None, 785 },
799 docs: None, 786 kind: Test {
800 }, 787 test_id: Path(
801 kind: Test { 788 "test_foo1",
802 test_id: Path( 789 ),
803 "test_foo1", 790 attr: TestAttr {
804 ), 791 ignore: false,
805 attr: TestAttr {
806 ignore: false,
807 },
808 },
809 cfg_exprs: [
810 All(
811 [
812 KeyValue {
813 key: "feature",
814 value: "foo",
815 },
816 KeyValue {
817 key: "feature",
818 value: "bar",
819 }, 792 },
793 },
794 cfg_exprs: [
795 All(
796 [
797 KeyValue {
798 key: "feature",
799 value: "foo",
800 },
801 KeyValue {
802 key: "feature",
803 value: "bar",
804 },
805 ],
806 ),
820 ], 807 ],
821 ), 808 },
822 ], 809 ]
823 }, 810 "#]],
824 ] 811 );
825 "###
826 );
827 assert_actions(&runnables, &[&TEST]);
828 } 812 }
829 813
830 #[test] 814 #[test]
831 fn test_runnables_no_test_function_in_module() { 815 fn test_runnables_no_test_function_in_module() {
832 let (analysis, pos) = analysis_and_position( 816 check(
833 r#" 817 r#"
834 //- /lib.rs 818//- /lib.rs
835 <|> //empty 819<|>
836 mod test_mod { 820mod test_mod {
837 fn foo1() {} 821 fn foo1() {}
838 } 822}
839 "#, 823"#,
824 &[],
825 expect![[r#"
826 []
827 "#]],
840 ); 828 );
841 let runnables = analysis.runnables(pos.file_id).unwrap();
842 assert!(runnables.is_empty())
843 } 829 }
844} 830}
diff --git a/crates/ra_ide/src/ssr.rs b/crates/ra_ide/src/ssr.rs
index 6cb96608b..b3e9e5dfe 100644
--- a/crates/ra_ide/src/ssr.rs
+++ b/crates/ra_ide/src/ssr.rs
@@ -4,12 +4,24 @@ use ra_ide_db::{symbol_index::SymbolsDatabase, RootDatabase};
4use crate::SourceFileEdit; 4use crate::SourceFileEdit;
5use ra_ssr::{MatchFinder, SsrError, SsrRule}; 5use ra_ssr::{MatchFinder, SsrError, SsrRule};
6 6
7// Feature: Structural Seach and Replace 7// Feature: Structural Search and Replace
8// 8//
9// Search and replace with named wildcards that will match any expression, type, path, pattern or item. 9// Search and replace with named wildcards that will match any expression, type, path, pattern or item.
10// The syntax for a structural search replace command is `<search_pattern> ==>> <replace_pattern>`. 10// The syntax for a structural search replace command is `<search_pattern> ==>> <replace_pattern>`.
11// A `$<name>` placeholder in the search pattern will match any AST node and `$<name>` will reference it in the replacement. 11// A `$<name>` placeholder in the search pattern will match any AST node and `$<name>` will reference it in the replacement.
12// Within a macro call, a placeholder will match up until whatever token follows the placeholder. 12// Within a macro call, a placeholder will match up until whatever token follows the placeholder.
13//
14// Placeholders may be given constraints by writing them as `${<name>:<constraint1>:<constraint2>...}`.
15//
16// Supported constraints:
17//
18// |===
19// | Constraint | Restricts placeholder
20//
21// | kind(literal) | Is a literal (e.g. `42` or `"forty two"`)
22// | not(a) | Negates the constraint `a`
23// |===
24//
13// Available via the command `rust-analyzer.ssr`. 25// Available via the command `rust-analyzer.ssr`.
14// 26//
15// ```rust 27// ```rust
diff --git a/crates/ra_ide/src/syntax_highlighting/tests.rs b/crates/ra_ide/src/syntax_highlighting/tests.rs
index b7fad9719..aa7c887d6 100644
--- a/crates/ra_ide/src/syntax_highlighting/tests.rs
+++ b/crates/ra_ide/src/syntax_highlighting/tests.rs
@@ -1,6 +1,7 @@
1use std::fs; 1use std::fs;
2 2
3use test_utils::{assert_eq_text, project_dir, read_text}; 3use expect::{expect_file, ExpectFile};
4use test_utils::project_dir;
4 5
5use crate::{mock_analysis::single_file, FileRange, TextRange}; 6use crate::{mock_analysis::single_file, FileRange, TextRange};
6 7
@@ -91,7 +92,7 @@ impl<T> Option<T> {
91} 92}
92"# 93"#
93 .trim(), 94 .trim(),
94 "crates/ra_ide/src/snapshots/highlighting.html", 95 expect_file!["crates/ra_ide/test_data/highlighting.html"],
95 false, 96 false,
96 ); 97 );
97} 98}
@@ -114,7 +115,7 @@ fn bar() {
114} 115}
115"# 116"#
116 .trim(), 117 .trim(),
117 "crates/ra_ide/src/snapshots/rainbow_highlighting.html", 118 expect_file!["crates/ra_ide/test_data/rainbow_highlighting.html"],
118 true, 119 true,
119 ); 120 );
120} 121}
@@ -167,7 +168,7 @@ fn main() {
167 ); 168 );
168}"## 169}"##
169 .trim(), 170 .trim(),
170 "crates/ra_ide/src/snapshots/highlight_injection.html", 171 expect_file!["crates/ra_ide/test_data/highlight_injection.html"],
171 false, 172 false,
172 ); 173 );
173} 174}
@@ -250,7 +251,7 @@ fn main() {
250 println!("{ничоси}", ничоси = 92); 251 println!("{ничоси}", ничоси = 92);
251}"# 252}"#
252 .trim(), 253 .trim(),
253 "crates/ra_ide/src/snapshots/highlight_strings.html", 254 expect_file!["crates/ra_ide/test_data/highlight_strings.html"],
254 false, 255 false,
255 ); 256 );
256} 257}
@@ -278,7 +279,7 @@ fn main() {
278} 279}
279"# 280"#
280 .trim(), 281 .trim(),
281 "crates/ra_ide/src/snapshots/highlight_unsafe.html", 282 expect_file!["crates/ra_ide/test_data/highlight_unsafe.html"],
282 false, 283 false,
283 ); 284 );
284} 285}
@@ -354,7 +355,7 @@ macro_rules! noop {
354} 355}
355"# 356"#
356 .trim(), 357 .trim(),
357 "crates/ra_ide/src/snapshots/highlight_doctest.html", 358 expect_file!["crates/ra_ide/test_data/highlight_doctest.html"],
358 false, 359 false,
359 ); 360 );
360} 361}
@@ -362,11 +363,8 @@ macro_rules! noop {
362/// Highlights the code given by the `ra_fixture` argument, renders the 363/// Highlights the code given by the `ra_fixture` argument, renders the
363/// result as HTML, and compares it with the HTML file given as `snapshot`. 364/// result as HTML, and compares it with the HTML file given as `snapshot`.
364/// Note that the `snapshot` file is overwritten by the rendered HTML. 365/// Note that the `snapshot` file is overwritten by the rendered HTML.
365fn check_highlighting(ra_fixture: &str, snapshot: &str, rainbow: bool) { 366fn check_highlighting(ra_fixture: &str, expect: ExpectFile, rainbow: bool) {
366 let (analysis, file_id) = single_file(ra_fixture); 367 let (analysis, file_id) = single_file(ra_fixture);
367 let dst_file = project_dir().join(snapshot);
368 let actual_html = &analysis.highlight_as_html(file_id, rainbow).unwrap(); 368 let actual_html = &analysis.highlight_as_html(file_id, rainbow).unwrap();
369 let expected_html = &read_text(&dst_file); 369 expect.assert_eq(actual_html)
370 fs::write(dst_file, &actual_html).unwrap();
371 assert_eq_text!(expected_html, actual_html);
372} 370}
diff --git a/crates/ra_ide/src/snapshots/highlight_doctest.html b/crates/ra_ide/test_data/highlight_doctest.html
index e8155def7..e8155def7 100644
--- a/crates/ra_ide/src/snapshots/highlight_doctest.html
+++ b/crates/ra_ide/test_data/highlight_doctest.html
diff --git a/crates/ra_ide/src/snapshots/highlight_injection.html b/crates/ra_ide/test_data/highlight_injection.html
index 1b0349bae..1b0349bae 100644
--- a/crates/ra_ide/src/snapshots/highlight_injection.html
+++ b/crates/ra_ide/test_data/highlight_injection.html
diff --git a/crates/ra_ide/src/snapshots/highlight_strings.html b/crates/ra_ide/test_data/highlight_strings.html
index d184b5691..d184b5691 100644
--- a/crates/ra_ide/src/snapshots/highlight_strings.html
+++ b/crates/ra_ide/test_data/highlight_strings.html
diff --git a/crates/ra_ide/src/snapshots/highlight_unsafe.html b/crates/ra_ide/test_data/highlight_unsafe.html
index 6936e949f..6936e949f 100644
--- a/crates/ra_ide/src/snapshots/highlight_unsafe.html
+++ b/crates/ra_ide/test_data/highlight_unsafe.html
diff --git a/crates/ra_ide/src/snapshots/highlighting.html b/crates/ra_ide/test_data/highlighting.html
index 8d0b38f95..8d0b38f95 100644
--- a/crates/ra_ide/src/snapshots/highlighting.html
+++ b/crates/ra_ide/test_data/highlighting.html
diff --git a/crates/ra_ide/src/snapshots/rainbow_highlighting.html b/crates/ra_ide/test_data/rainbow_highlighting.html
index 9516c7441..9516c7441 100644
--- a/crates/ra_ide/src/snapshots/rainbow_highlighting.html
+++ b/crates/ra_ide/test_data/rainbow_highlighting.html
diff --git a/crates/ra_ide_db/src/change.rs b/crates/ra_ide_db/src/change.rs
index b507000f2..dbe6eacc5 100644
--- a/crates/ra_ide_db/src/change.rs
+++ b/crates/ra_ide_db/src/change.rs
@@ -243,8 +243,9 @@ impl RootDatabase {
243 hir::db::GenericPredicatesForParamQuery 243 hir::db::GenericPredicatesForParamQuery
244 hir::db::GenericPredicatesQuery 244 hir::db::GenericPredicatesQuery
245 hir::db::GenericDefaultsQuery 245 hir::db::GenericDefaultsQuery
246 hir::db::ImplsInCrateQuery 246 hir::db::InherentImplsInCrateQuery
247 hir::db::ImplsFromDepsQuery 247 hir::db::TraitImplsInCrateQuery
248 hir::db::TraitImplsInDepsQuery
248 hir::db::InternTypeCtorQuery 249 hir::db::InternTypeCtorQuery
249 hir::db::InternTypeParamIdQuery 250 hir::db::InternTypeParamIdQuery
250 hir::db::InternChalkImplQuery 251 hir::db::InternChalkImplQuery
diff --git a/crates/ra_ide_db/src/imports_locator.rs b/crates/ra_ide_db/src/imports_locator.rs
index fff112e66..1fba71ff8 100644
--- a/crates/ra_ide_db/src/imports_locator.rs
+++ b/crates/ra_ide_db/src/imports_locator.rs
@@ -13,57 +13,53 @@ use crate::{
13use either::Either; 13use either::Either;
14use rustc_hash::FxHashSet; 14use rustc_hash::FxHashSet;
15 15
16pub struct ImportsLocator<'a> { 16pub fn find_imports<'a>(
17 sema: Semantics<'a, RootDatabase>, 17 sema: &Semantics<'a, RootDatabase>,
18 krate: Crate, 18 krate: Crate,
19} 19 name_to_import: &str,
20 20) -> Vec<Either<ModuleDef, MacroDef>> {
21impl<'a> ImportsLocator<'a> { 21 let _p = profile("search_for_imports");
22 pub fn new(db: &'a RootDatabase, krate: Crate) -> Self { 22 let db = sema.db;
23 Self { sema: Semantics::new(db), krate }
24 }
25 23
26 pub fn find_imports(&mut self, name_to_import: &str) -> Vec<Either<ModuleDef, MacroDef>> { 24 // Query dependencies first.
27 let _p = profile("search_for_imports"); 25 let mut candidates: FxHashSet<_> =
28 let db = self.sema.db; 26 krate.query_external_importables(db, name_to_import).collect();
29 27
30 // Query dependencies first. 28 // Query the local crate using the symbol index.
31 let mut candidates: FxHashSet<_> = 29 let local_results = {
32 self.krate.query_external_importables(db, name_to_import).collect(); 30 let mut query = Query::new(name_to_import.to_string());
31 query.exact();
32 query.limit(40);
33 symbol_index::crate_symbols(db, krate.into(), query)
34 };
33 35
34 // Query the local crate using the symbol index. 36 candidates.extend(
35 let local_results = { 37 local_results
36 let mut query = Query::new(name_to_import.to_string()); 38 .into_iter()
37 query.exact(); 39 .filter_map(|import_candidate| get_name_definition(sema, &import_candidate))
38 query.limit(40); 40 .filter_map(|name_definition_to_import| match name_definition_to_import {
39 symbol_index::crate_symbols(db, self.krate.into(), query) 41 Definition::ModuleDef(module_def) => Some(Either::Left(module_def)),
40 }; 42 Definition::Macro(macro_def) => Some(Either::Right(macro_def)),
43 _ => None,
44 }),
45 );
41 46
42 candidates.extend( 47 candidates.into_iter().collect()
43 local_results 48}
44 .into_iter()
45 .filter_map(|import_candidate| self.get_name_definition(&import_candidate))
46 .filter_map(|name_definition_to_import| match name_definition_to_import {
47 Definition::ModuleDef(module_def) => Some(Either::Left(module_def)),
48 Definition::Macro(macro_def) => Some(Either::Right(macro_def)),
49 _ => None,
50 }),
51 );
52
53 candidates.into_iter().collect()
54 }
55 49
56 fn get_name_definition(&mut self, import_candidate: &FileSymbol) -> Option<Definition> { 50fn get_name_definition<'a>(
57 let _p = profile("get_name_definition"); 51 sema: &Semantics<'a, RootDatabase>,
58 let file_id = import_candidate.file_id; 52 import_candidate: &FileSymbol,
53) -> Option<Definition> {
54 let _p = profile("get_name_definition");
55 let file_id = import_candidate.file_id;
59 56
60 let candidate_node = import_candidate.ptr.to_node(self.sema.parse(file_id).syntax()); 57 let candidate_node = import_candidate.ptr.to_node(sema.parse(file_id).syntax());
61 let candidate_name_node = if candidate_node.kind() != NAME { 58 let candidate_name_node = if candidate_node.kind() != NAME {
62 candidate_node.children().find(|it| it.kind() == NAME)? 59 candidate_node.children().find(|it| it.kind() == NAME)?
63 } else { 60 } else {
64 candidate_node 61 candidate_node
65 }; 62 };
66 let name = ast::Name::cast(candidate_name_node)?; 63 let name = ast::Name::cast(candidate_name_node)?;
67 classify_name(&self.sema, &name)?.into_definition() 64 classify_name(sema, &name)?.into_definition()
68 }
69} 65}
diff --git a/crates/ra_ide_db/src/lib.rs b/crates/ra_ide_db/src/lib.rs
index a808de4f1..c78071ad6 100644
--- a/crates/ra_ide_db/src/lib.rs
+++ b/crates/ra_ide_db/src/lib.rs
@@ -13,7 +13,7 @@ mod wasm_shims;
13 13
14use std::sync::Arc; 14use std::sync::Arc;
15 15
16use hir::db::{AstDatabase, DefDatabase}; 16use hir::db::{AstDatabase, DefDatabase, HirDatabase};
17use ra_db::{ 17use ra_db::{
18 salsa::{self, Database, Durability}, 18 salsa::{self, Database, Durability},
19 Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, 19 Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase,
@@ -52,6 +52,12 @@ impl Upcast<dyn DefDatabase> for RootDatabase {
52 } 52 }
53} 53}
54 54
55impl Upcast<dyn HirDatabase> for RootDatabase {
56 fn upcast(&self) -> &(dyn HirDatabase + 'static) {
57 &*self
58 }
59}
60
55impl FileLoader for RootDatabase { 61impl FileLoader for RootDatabase {
56 fn file_text(&self, file_id: FileId) -> Arc<String> { 62 fn file_text(&self, file_id: FileId) -> Arc<String> {
57 FileLoaderDelegate(self).file_text(file_id) 63 FileLoaderDelegate(self).file_text(file_id)
diff --git a/crates/ra_ide_db/src/search.rs b/crates/ra_ide_db/src/search.rs
index 44d5c35e6..81553150b 100644
--- a/crates/ra_ide_db/src/search.rs
+++ b/crates/ra_ide_db/src/search.rs
@@ -180,20 +180,20 @@ impl Definition {
180 180
181 pub fn find_usages( 181 pub fn find_usages(
182 &self, 182 &self,
183 db: &RootDatabase, 183 sema: &Semantics<RootDatabase>,
184 search_scope: Option<SearchScope>, 184 search_scope: Option<SearchScope>,
185 ) -> Vec<Reference> { 185 ) -> Vec<Reference> {
186 let _p = profile("Definition::find_usages"); 186 let _p = profile("Definition::find_usages");
187 187
188 let search_scope = { 188 let search_scope = {
189 let base = self.search_scope(db); 189 let base = self.search_scope(sema.db);
190 match search_scope { 190 match search_scope {
191 None => base, 191 None => base,
192 Some(scope) => base.intersection(&scope), 192 Some(scope) => base.intersection(&scope),
193 } 193 }
194 }; 194 };
195 195
196 let name = match self.name(db) { 196 let name = match self.name(sema.db) {
197 None => return Vec::new(), 197 None => return Vec::new(),
198 Some(it) => it.to_string(), 198 Some(it) => it.to_string(),
199 }; 199 };
@@ -202,11 +202,10 @@ impl Definition {
202 let mut refs = vec![]; 202 let mut refs = vec![];
203 203
204 for (file_id, search_range) in search_scope { 204 for (file_id, search_range) in search_scope {
205 let text = db.file_text(file_id); 205 let text = sema.db.file_text(file_id);
206 let search_range = 206 let search_range =
207 search_range.unwrap_or(TextRange::up_to(TextSize::of(text.as_str()))); 207 search_range.unwrap_or(TextRange::up_to(TextSize::of(text.as_str())));
208 208
209 let sema = Semantics::new(db);
210 let tree = Lazy::new(|| sema.parse(file_id).syntax().clone()); 209 let tree = Lazy::new(|| sema.parse(file_id).syntax().clone());
211 210
212 for (idx, _) in text.match_indices(pat) { 211 for (idx, _) in text.match_indices(pat) {
@@ -222,9 +221,6 @@ impl Definition {
222 continue; 221 continue;
223 }; 222 };
224 223
225 // FIXME: reuse sb
226 // See https://github.com/rust-lang/rust/pull/68198#issuecomment-574269098
227
228 match classify_name_ref(&sema, &name_ref) { 224 match classify_name_ref(&sema, &name_ref) {
229 Some(NameRefClass::Definition(def)) if &def == self => { 225 Some(NameRefClass::Definition(def)) if &def == self => {
230 let kind = if is_record_lit_name_ref(&name_ref) 226 let kind = if is_record_lit_name_ref(&name_ref)
diff --git a/crates/ra_proc_macro_srv/src/tests/mod.rs b/crates/ra_proc_macro_srv/src/tests/mod.rs
index 82cefbb29..8e6f28abd 100644
--- a/crates/ra_proc_macro_srv/src/tests/mod.rs
+++ b/crates/ra_proc_macro_srv/src/tests/mod.rs
@@ -11,7 +11,7 @@ fn test_derive_serialize_proc_macro() {
11 "serde_derive", 11 "serde_derive",
12 "Serialize", 12 "Serialize",
13 "1.0", 13 "1.0",
14 r##"struct Foo {}"##, 14 r"struct Foo {}",
15 include_str!("fixtures/test_serialize_proc_macro.txt"), 15 include_str!("fixtures/test_serialize_proc_macro.txt"),
16 ); 16 );
17} 17}
@@ -22,9 +22,7 @@ fn test_derive_serialize_proc_macro_failed() {
22 "serde_derive", 22 "serde_derive",
23 "Serialize", 23 "Serialize",
24 "1.0", 24 "1.0",
25 r##" 25 r"struct {}",
26 struct {}
27"##,
28 r##" 26 r##"
29SUBTREE $ 27SUBTREE $
30 IDENT compile_error 4294967295 28 IDENT compile_error 4294967295
diff --git a/crates/ra_proc_macro_srv/src/tests/utils.rs b/crates/ra_proc_macro_srv/src/tests/utils.rs
index 8d85f2d8a..dcb00671f 100644
--- a/crates/ra_proc_macro_srv/src/tests/utils.rs
+++ b/crates/ra_proc_macro_srv/src/tests/utils.rs
@@ -44,12 +44,12 @@ pub fn assert_expand(
44 crate_name: &str, 44 crate_name: &str,
45 macro_name: &str, 45 macro_name: &str,
46 version: &str, 46 version: &str,
47 fixture: &str, 47 ra_fixture: &str,
48 expect: &str, 48 expect: &str,
49) { 49) {
50 let path = fixtures::dylib_path(crate_name, version); 50 let path = fixtures::dylib_path(crate_name, version);
51 let expander = dylib::Expander::new(&path).unwrap(); 51 let expander = dylib::Expander::new(&path).unwrap();
52 let fixture = parse_string(fixture).unwrap(); 52 let fixture = parse_string(ra_fixture).unwrap();
53 53
54 let res = expander.expand(macro_name, &fixture.subtree, None).unwrap(); 54 let res = expander.expand(macro_name, &fixture.subtree, None).unwrap();
55 assert_eq_text!(&format!("{:?}", res), &expect.trim()); 55 assert_eq_text!(&format!("{:?}", res), &expect.trim());
diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs
index 3b124020d..47a1d393d 100644
--- a/crates/ra_project_model/src/cargo_workspace.rs
+++ b/crates/ra_project_model/src/cargo_workspace.rs
@@ -1,6 +1,11 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use std::{ffi::OsStr, ops, path::Path, process::Command}; 3use std::{
4 ffi::OsStr,
5 ops,
6 path::{Path, PathBuf},
7 process::Command,
8};
4 9
5use anyhow::{Context, Result}; 10use anyhow::{Context, Result};
6use cargo_metadata::{BuildScript, CargoOpt, Message, MetadataCommand, PackageId}; 11use cargo_metadata::{BuildScript, CargoOpt, Message, MetadataCommand, PackageId};
@@ -308,9 +313,13 @@ pub fn load_extern_resources(
308 if let Ok(message) = message { 313 if let Ok(message) = message {
309 match message { 314 match message {
310 Message::BuildScriptExecuted(BuildScript { package_id, out_dir, cfgs, .. }) => { 315 Message::BuildScriptExecuted(BuildScript { package_id, out_dir, cfgs, .. }) => {
311 let out_dir = AbsPathBuf::assert(out_dir); 316 // cargo_metadata crate returns default (empty) path for
312 res.out_dirs.insert(package_id.clone(), out_dir); 317 // older cargos, which is not absolute, so work around that.
313 res.cfgs.insert(package_id, cfgs); 318 if out_dir != PathBuf::default() {
319 let out_dir = AbsPathBuf::assert(out_dir);
320 res.out_dirs.insert(package_id.clone(), out_dir);
321 res.cfgs.insert(package_id, cfgs);
322 }
314 } 323 }
315 Message::CompilerArtifact(message) => { 324 Message::CompilerArtifact(message) => {
316 if message.target.kind.contains(&"proc-macro".to_string()) { 325 if message.target.kind.contains(&"proc-macro".to_string()) {
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs
index 8b85b4831..8dbf4e6ea 100644
--- a/crates/ra_project_model/src/lib.rs
+++ b/crates/ra_project_model/src/lib.rs
@@ -288,10 +288,7 @@ impl ProjectWorkspace {
288 if let (Some(&from), Some(&to)) = 288 if let (Some(&from), Some(&to)) =
289 (crates.get(&from_crate_id), crates.get(&to_crate_id)) 289 (crates.get(&from_crate_id), crates.get(&to_crate_id))
290 { 290 {
291 if crate_graph 291 if crate_graph.add_dep(from, dep.name.clone(), to).is_err() {
292 .add_dep(from, CrateName::new(&dep.name).unwrap(), to)
293 .is_err()
294 {
295 log::error!( 292 log::error!(
296 "cyclic dependency {:?} -> {:?}", 293 "cyclic dependency {:?} -> {:?}",
297 from_crate_id, 294 from_crate_id,
@@ -312,13 +309,11 @@ impl ProjectWorkspace {
312 309
313 let env = Env::default(); 310 let env = Env::default();
314 let proc_macro = vec![]; 311 let proc_macro = vec![];
315 let crate_name = CrateName::new(&sysroot[krate].name) 312 let name = sysroot[krate].name.clone();
316 .expect("Sysroot crate names should not contain dashes");
317
318 let crate_id = crate_graph.add_crate_root( 313 let crate_id = crate_graph.add_crate_root(
319 file_id, 314 file_id,
320 Edition::Edition2018, 315 Edition::Edition2018,
321 Some(crate_name), 316 Some(name),
322 cfg_options.clone(), 317 cfg_options.clone(),
323 env, 318 env,
324 proc_macro, 319 proc_macro,
@@ -392,7 +387,7 @@ impl ProjectWorkspace {
392 let crate_id = crate_graph.add_crate_root( 387 let crate_id = crate_graph.add_crate_root(
393 file_id, 388 file_id,
394 edition, 389 edition,
395 Some(CrateName::normalize_dashes(&cargo[pkg].name)), 390 Some(cargo[pkg].name.clone()),
396 cfg_options, 391 cfg_options,
397 env, 392 env,
398 proc_macro.clone(), 393 proc_macro.clone(),
diff --git a/crates/ra_project_model/src/project_json.rs b/crates/ra_project_model/src/project_json.rs
index 4b5dcd634..b0fe09333 100644
--- a/crates/ra_project_model/src/project_json.rs
+++ b/crates/ra_project_model/src/project_json.rs
@@ -4,13 +4,13 @@ use std::path::PathBuf;
4 4
5use paths::{AbsPath, AbsPathBuf}; 5use paths::{AbsPath, AbsPathBuf};
6use ra_cfg::CfgOptions; 6use ra_cfg::CfgOptions;
7use ra_db::{CrateId, Dependency, Edition}; 7use ra_db::{CrateId, CrateName, Dependency, Edition};
8use rustc_hash::FxHashSet; 8use rustc_hash::FxHashSet;
9use serde::Deserialize; 9use serde::{de, Deserialize};
10use stdx::split_delim; 10use stdx::split_delim;
11 11
12/// Roots and crates that compose this Rust project. 12/// Roots and crates that compose this Rust project.
13#[derive(Clone, Debug)] 13#[derive(Clone, Debug, Eq, PartialEq)]
14pub struct ProjectJson { 14pub struct ProjectJson {
15 pub(crate) roots: Vec<Root>, 15 pub(crate) roots: Vec<Root>,
16 pub(crate) crates: Vec<Crate>, 16 pub(crate) crates: Vec<Crate>,
@@ -18,14 +18,14 @@ pub struct ProjectJson {
18 18
19/// A root points to the directory which contains Rust crates. rust-analyzer watches all files in 19/// A root points to the directory which contains Rust crates. rust-analyzer watches all files in
20/// all roots. Roots might be nested. 20/// all roots. Roots might be nested.
21#[derive(Clone, Debug)] 21#[derive(Clone, Debug, Eq, PartialEq)]
22pub struct Root { 22pub struct Root {
23 pub(crate) path: AbsPathBuf, 23 pub(crate) path: AbsPathBuf,
24} 24}
25 25
26/// A crate points to the root module of a crate and lists the dependencies of the crate. This is 26/// A crate points to the root module of a crate and lists the dependencies of the crate. This is
27/// useful in creating the crate graph. 27/// useful in creating the crate graph.
28#[derive(Clone, Debug)] 28#[derive(Clone, Debug, Eq, PartialEq)]
29pub struct Crate { 29pub struct Crate {
30 pub(crate) root_module: AbsPathBuf, 30 pub(crate) root_module: AbsPathBuf,
31 pub(crate) edition: Edition, 31 pub(crate) edition: Edition,
@@ -50,7 +50,7 @@ impl ProjectJson {
50 .into_iter() 50 .into_iter()
51 .map(|dep_data| Dependency { 51 .map(|dep_data| Dependency {
52 crate_id: CrateId(dep_data.krate as u32), 52 crate_id: CrateId(dep_data.krate as u32),
53 name: dep_data.name.into(), 53 name: dep_data.name,
54 }) 54 })
55 .collect::<Vec<_>>(), 55 .collect::<Vec<_>>(),
56 cfg: { 56 cfg: {
@@ -113,5 +113,14 @@ struct DepData {
113 /// Identifies a crate by position in the crates array. 113 /// Identifies a crate by position in the crates array.
114 #[serde(rename = "crate")] 114 #[serde(rename = "crate")]
115 krate: usize, 115 krate: usize,
116 name: String, 116 #[serde(deserialize_with = "deserialize_crate_name")]
117 name: CrateName,
118}
119
120fn deserialize_crate_name<'de, D>(de: D) -> Result<CrateName, D::Error>
121where
122 D: de::Deserializer<'de>,
123{
124 let name = String::deserialize(de)?;
125 CrateName::new(&name).map_err(|err| de::Error::custom(format!("invalid crate name: {:?}", err)))
117} 126}
diff --git a/crates/ra_ssr/Cargo.toml b/crates/ra_ssr/Cargo.toml
index 3c2f15a83..fe098aaee 100644
--- a/crates/ra_ssr/Cargo.toml
+++ b/crates/ra_ssr/Cargo.toml
@@ -17,3 +17,4 @@ ra_db = { path = "../ra_db" }
17ra_ide_db = { path = "../ra_ide_db" } 17ra_ide_db = { path = "../ra_ide_db" }
18hir = { path = "../ra_hir", package = "ra_hir" } 18hir = { path = "../ra_hir", package = "ra_hir" }
19rustc-hash = "1.1.0" 19rustc-hash = "1.1.0"
20test_utils = { path = "../test_utils" }
diff --git a/crates/ra_ssr/src/lib.rs b/crates/ra_ssr/src/lib.rs
index e148f4564..422e15ee6 100644
--- a/crates/ra_ssr/src/lib.rs
+++ b/crates/ra_ssr/src/lib.rs
@@ -9,10 +9,11 @@ mod replacing;
9#[cfg(test)] 9#[cfg(test)]
10mod tests; 10mod tests;
11 11
12use crate::matching::Match; 12pub use crate::matching::Match;
13use crate::matching::{record_match_fails_reasons_scope, MatchFailureReason};
13use hir::Semantics; 14use hir::Semantics;
14use ra_db::{FileId, FileRange}; 15use ra_db::{FileId, FileRange};
15use ra_syntax::{ast, AstNode, SmolStr, SyntaxNode}; 16use ra_syntax::{ast, AstNode, SmolStr, SyntaxKind, SyntaxNode, TextRange};
16use ra_text_edit::TextEdit; 17use ra_text_edit::TextEdit;
17use rustc_hash::FxHashMap; 18use rustc_hash::FxHashMap;
18 19
@@ -26,7 +27,7 @@ pub struct SsrRule {
26} 27}
27 28
28#[derive(Debug)] 29#[derive(Debug)]
29struct SsrPattern { 30pub struct SsrPattern {
30 raw: parsing::RawSearchPattern, 31 raw: parsing::RawSearchPattern,
31 /// Placeholders keyed by the stand-in ident that we use in Rust source code. 32 /// Placeholders keyed by the stand-in ident that we use in Rust source code.
32 placeholders_by_stand_in: FxHashMap<SmolStr, parsing::Placeholder>, 33 placeholders_by_stand_in: FxHashMap<SmolStr, parsing::Placeholder>,
@@ -45,7 +46,7 @@ pub struct SsrError(String);
45 46
46#[derive(Debug, Default)] 47#[derive(Debug, Default)]
47pub struct SsrMatches { 48pub struct SsrMatches {
48 matches: Vec<Match>, 49 pub matches: Vec<Match>,
49} 50}
50 51
51/// Searches a crate for pattern matches and possibly replaces them with something else. 52/// Searches a crate for pattern matches and possibly replaces them with something else.
@@ -64,6 +65,12 @@ impl<'db> MatchFinder<'db> {
64 self.rules.push(rule); 65 self.rules.push(rule);
65 } 66 }
66 67
68 /// Adds a search pattern. For use if you intend to only call `find_matches_in_file`. If you
69 /// intend to do replacement, use `add_rule` instead.
70 pub fn add_search_pattern(&mut self, pattern: SsrPattern) {
71 self.add_rule(SsrRule { pattern, template: "()".parse().unwrap() })
72 }
73
67 pub fn edits_for_file(&self, file_id: FileId) -> Option<TextEdit> { 74 pub fn edits_for_file(&self, file_id: FileId) -> Option<TextEdit> {
68 let matches = self.find_matches_in_file(file_id); 75 let matches = self.find_matches_in_file(file_id);
69 if matches.matches.is_empty() { 76 if matches.matches.is_empty() {
@@ -74,7 +81,7 @@ impl<'db> MatchFinder<'db> {
74 } 81 }
75 } 82 }
76 83
77 fn find_matches_in_file(&self, file_id: FileId) -> SsrMatches { 84 pub fn find_matches_in_file(&self, file_id: FileId) -> SsrMatches {
78 let file = self.sema.parse(file_id); 85 let file = self.sema.parse(file_id);
79 let code = file.syntax(); 86 let code = file.syntax();
80 let mut matches = SsrMatches::default(); 87 let mut matches = SsrMatches::default();
@@ -82,6 +89,32 @@ impl<'db> MatchFinder<'db> {
82 matches 89 matches
83 } 90 }
84 91
92 /// Finds all nodes in `file_id` whose text is exactly equal to `snippet` and attempts to match
93 /// them, while recording reasons why they don't match. This API is useful for command
94 /// line-based debugging where providing a range is difficult.
95 pub fn debug_where_text_equal(&self, file_id: FileId, snippet: &str) -> Vec<MatchDebugInfo> {
96 use ra_db::SourceDatabaseExt;
97 let file = self.sema.parse(file_id);
98 let mut res = Vec::new();
99 let file_text = self.sema.db.file_text(file_id);
100 let mut remaining_text = file_text.as_str();
101 let mut base = 0;
102 let len = snippet.len() as u32;
103 while let Some(offset) = remaining_text.find(snippet) {
104 let start = base + offset as u32;
105 let end = start + len;
106 self.output_debug_for_nodes_at_range(
107 file.syntax(),
108 FileRange { file_id, range: TextRange::new(start.into(), end.into()) },
109 &None,
110 &mut res,
111 );
112 remaining_text = &remaining_text[offset + snippet.len()..];
113 base = end;
114 }
115 res
116 }
117
85 fn find_matches( 118 fn find_matches(
86 &self, 119 &self,
87 code: &SyntaxNode, 120 code: &SyntaxNode,
@@ -128,6 +161,59 @@ impl<'db> MatchFinder<'db> {
128 self.find_matches(&child, restrict_range, matches_out); 161 self.find_matches(&child, restrict_range, matches_out);
129 } 162 }
130 } 163 }
164
165 fn output_debug_for_nodes_at_range(
166 &self,
167 node: &SyntaxNode,
168 range: FileRange,
169 restrict_range: &Option<FileRange>,
170 out: &mut Vec<MatchDebugInfo>,
171 ) {
172 for node in node.children() {
173 let node_range = self.sema.original_range(&node);
174 if node_range.file_id != range.file_id || !node_range.range.contains_range(range.range)
175 {
176 continue;
177 }
178 if node_range.range == range.range {
179 for rule in &self.rules {
180 let pattern =
181 rule.pattern.tree_for_kind_with_reason(node.kind()).map(|p| p.clone());
182 out.push(MatchDebugInfo {
183 matched: matching::get_match(true, rule, &node, restrict_range, &self.sema)
184 .map_err(|e| MatchFailureReason {
185 reason: e.reason.unwrap_or_else(|| {
186 "Match failed, but no reason was given".to_owned()
187 }),
188 }),
189 pattern,
190 node: node.clone(),
191 });
192 }
193 } else if let Some(macro_call) = ast::MacroCall::cast(node.clone()) {
194 if let Some(expanded) = self.sema.expand(&macro_call) {
195 if let Some(tt) = macro_call.token_tree() {
196 self.output_debug_for_nodes_at_range(
197 &expanded,
198 range,
199 &Some(self.sema.original_range(tt.syntax())),
200 out,
201 );
202 }
203 }
204 } else {
205 self.output_debug_for_nodes_at_range(&node, range, restrict_range, out);
206 }
207 }
208 }
209}
210
211pub struct MatchDebugInfo {
212 node: SyntaxNode,
213 /// Our search pattern parsed as the same kind of syntax node as `node`. e.g. expression, item,
214 /// etc. Will be absent if the pattern can't be parsed as that kind.
215 pattern: Result<SyntaxNode, MatchFailureReason>,
216 matched: Result<Match, MatchFailureReason>,
131} 217}
132 218
133impl std::fmt::Display for SsrError { 219impl std::fmt::Display for SsrError {
@@ -136,4 +222,70 @@ impl std::fmt::Display for SsrError {
136 } 222 }
137} 223}
138 224
225impl std::fmt::Debug for MatchDebugInfo {
226 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
227 write!(f, "========= PATTERN ==========\n")?;
228 match &self.pattern {
229 Ok(pattern) => {
230 write!(f, "{:#?}", pattern)?;
231 }
232 Err(err) => {
233 write!(f, "{}", err.reason)?;
234 }
235 }
236 write!(
237 f,
238 "\n============ AST ===========\n\
239 {:#?}\n============================\n",
240 self.node
241 )?;
242 match &self.matched {
243 Ok(_) => write!(f, "Node matched")?,
244 Err(reason) => write!(f, "Node failed to match because: {}", reason.reason)?,
245 }
246 Ok(())
247 }
248}
249
250impl SsrPattern {
251 fn tree_for_kind_with_reason(
252 &self,
253 kind: SyntaxKind,
254 ) -> Result<&SyntaxNode, MatchFailureReason> {
255 record_match_fails_reasons_scope(true, || self.tree_for_kind(kind))
256 .map_err(|e| MatchFailureReason { reason: e.reason.unwrap() })
257 }
258}
259
260impl SsrMatches {
261 /// Returns `self` with any nested matches removed and made into top-level matches.
262 pub fn flattened(self) -> SsrMatches {
263 let mut out = SsrMatches::default();
264 self.flatten_into(&mut out);
265 out
266 }
267
268 fn flatten_into(self, out: &mut SsrMatches) {
269 for mut m in self.matches {
270 for p in m.placeholder_values.values_mut() {
271 std::mem::replace(&mut p.inner_matches, SsrMatches::default()).flatten_into(out);
272 }
273 out.matches.push(m);
274 }
275 }
276}
277
278impl Match {
279 pub fn matched_text(&self) -> String {
280 self.matched_node.text().to_string()
281 }
282}
283
139impl std::error::Error for SsrError {} 284impl std::error::Error for SsrError {}
285
286#[cfg(test)]
287impl MatchDebugInfo {
288 pub(crate) fn match_failure_reason(&self) -> Option<&str> {
289 self.matched.as_ref().err().map(|r| r.reason.as_str())
290 }
291}
diff --git a/crates/ra_ssr/src/matching.rs b/crates/ra_ssr/src/matching.rs
index bb87bda43..ce53d46d2 100644
--- a/crates/ra_ssr/src/matching.rs
+++ b/crates/ra_ssr/src/matching.rs
@@ -2,17 +2,16 @@
2//! process of matching, placeholder values are recorded. 2//! process of matching, placeholder values are recorded.
3 3
4use crate::{ 4use crate::{
5 parsing::{Placeholder, SsrTemplate}, 5 parsing::{Constraint, NodeKind, Placeholder, SsrTemplate},
6 SsrMatches, SsrPattern, SsrRule, 6 SsrMatches, SsrPattern, SsrRule,
7}; 7};
8use hir::Semantics; 8use hir::Semantics;
9use ra_db::FileRange; 9use ra_db::FileRange;
10use ra_syntax::ast::{AstNode, AstToken}; 10use ra_syntax::ast::{AstNode, AstToken};
11use ra_syntax::{ 11use ra_syntax::{ast, SyntaxElement, SyntaxElementChildren, SyntaxKind, SyntaxNode, SyntaxToken};
12 ast, SyntaxElement, SyntaxElementChildren, SyntaxKind, SyntaxNode, SyntaxToken, TextRange,
13};
14use rustc_hash::FxHashMap; 12use rustc_hash::FxHashMap;
15use std::{cell::Cell, iter::Peekable}; 13use std::{cell::Cell, iter::Peekable};
14use test_utils::mark;
16 15
17// Creates a match error. If we're currently attempting to match some code that we thought we were 16// Creates a match error. If we're currently attempting to match some code that we thought we were
18// going to match, as indicated by the --debug-snippet flag, then populate the reason field. 17// going to match, as indicated by the --debug-snippet flag, then populate the reason field.
@@ -44,8 +43,8 @@ macro_rules! fail_match {
44 43
45/// Information about a match that was found. 44/// Information about a match that was found.
46#[derive(Debug)] 45#[derive(Debug)]
47pub(crate) struct Match { 46pub struct Match {
48 pub(crate) range: TextRange, 47 pub(crate) range: FileRange,
49 pub(crate) matched_node: SyntaxNode, 48 pub(crate) matched_node: SyntaxNode,
50 pub(crate) placeholder_values: FxHashMap<Var, PlaceholderMatch>, 49 pub(crate) placeholder_values: FxHashMap<Var, PlaceholderMatch>,
51 pub(crate) ignored_comments: Vec<ast::Comment>, 50 pub(crate) ignored_comments: Vec<ast::Comment>,
@@ -135,7 +134,7 @@ impl<'db, 'sema> MatchState<'db, 'sema> {
135 match_state.attempt_match_node(&match_inputs, &pattern_tree, code)?; 134 match_state.attempt_match_node(&match_inputs, &pattern_tree, code)?;
136 match_state.validate_range(&sema.original_range(code))?; 135 match_state.validate_range(&sema.original_range(code))?;
137 match_state.match_out = Some(Match { 136 match_state.match_out = Some(Match {
138 range: sema.original_range(code).range, 137 range: sema.original_range(code),
139 matched_node: code.clone(), 138 matched_node: code.clone(),
140 placeholder_values: FxHashMap::default(), 139 placeholder_values: FxHashMap::default(),
141 ignored_comments: Vec::new(), 140 ignored_comments: Vec::new(),
@@ -171,6 +170,9 @@ impl<'db, 'sema> MatchState<'db, 'sema> {
171 if let Some(placeholder) = 170 if let Some(placeholder) =
172 match_inputs.get_placeholder(&SyntaxElement::Node(pattern.clone())) 171 match_inputs.get_placeholder(&SyntaxElement::Node(pattern.clone()))
173 { 172 {
173 for constraint in &placeholder.constraints {
174 self.check_constraint(constraint, code)?;
175 }
174 if self.match_out.is_none() { 176 if self.match_out.is_none() {
175 return Ok(()); 177 return Ok(());
176 } 178 }
@@ -225,7 +227,7 @@ impl<'db, 'sema> MatchState<'db, 'sema> {
225 match self.next_non_trivial(&mut code_it) { 227 match self.next_non_trivial(&mut code_it) {
226 None => { 228 None => {
227 if let Some(p) = pattern_it.next() { 229 if let Some(p) = pattern_it.next() {
228 fail_match!("Part of the pattern was unmached: {:?}", p); 230 fail_match!("Part of the pattern was unmatched: {:?}", p);
229 } 231 }
230 return Ok(()); 232 return Ok(());
231 } 233 }
@@ -294,6 +296,24 @@ impl<'db, 'sema> MatchState<'db, 'sema> {
294 Ok(()) 296 Ok(())
295 } 297 }
296 298
299 fn check_constraint(
300 &self,
301 constraint: &Constraint,
302 code: &SyntaxNode,
303 ) -> Result<(), MatchFailed> {
304 match constraint {
305 Constraint::Kind(kind) => {
306 kind.matches(code)?;
307 }
308 Constraint::Not(sub) => {
309 if self.check_constraint(&*sub, code).is_ok() {
310 fail_match!("Constraint {:?} failed for '{}'", constraint, code.text());
311 }
312 }
313 }
314 Ok(())
315 }
316
297 /// We want to allow the records to match in any order, so we have special matching logic for 317 /// We want to allow the records to match in any order, so we have special matching logic for
298 /// them. 318 /// them.
299 fn attempt_match_record_field_list( 319 fn attempt_match_record_field_list(
@@ -517,6 +537,21 @@ impl SsrPattern {
517 } 537 }
518} 538}
519 539
540impl NodeKind {
541 fn matches(&self, node: &SyntaxNode) -> Result<(), MatchFailed> {
542 let ok = match self {
543 Self::Literal => {
544 mark::hit!(literal_constraint);
545 ast::Literal::can_cast(node.kind())
546 }
547 };
548 if !ok {
549 fail_match!("Code '{}' isn't of kind {:?}", node.text(), self);
550 }
551 Ok(())
552 }
553}
554
520// If `node` contains nothing but an ident then return it, otherwise return None. 555// If `node` contains nothing but an ident then return it, otherwise return None.
521fn only_ident(element: SyntaxElement) -> Option<SyntaxToken> { 556fn only_ident(element: SyntaxElement) -> Option<SyntaxToken> {
522 match element { 557 match element {
diff --git a/crates/ra_ssr/src/parsing.rs b/crates/ra_ssr/src/parsing.rs
index 1ae166d19..5ea125616 100644
--- a/crates/ra_ssr/src/parsing.rs
+++ b/crates/ra_ssr/src/parsing.rs
@@ -6,7 +6,7 @@
6//! e.g. expressions, type references etc. 6//! e.g. expressions, type references etc.
7 7
8use crate::{SsrError, SsrPattern, SsrRule}; 8use crate::{SsrError, SsrPattern, SsrRule};
9use ra_syntax::{ast, AstNode, SmolStr, SyntaxKind}; 9use ra_syntax::{ast, AstNode, SmolStr, SyntaxKind, T};
10use rustc_hash::{FxHashMap, FxHashSet}; 10use rustc_hash::{FxHashMap, FxHashSet};
11use std::str::FromStr; 11use std::str::FromStr;
12 12
@@ -39,6 +39,18 @@ pub(crate) struct Placeholder {
39 pub(crate) ident: SmolStr, 39 pub(crate) ident: SmolStr,
40 /// A unique name used in place of this placeholder when we parse the pattern as Rust code. 40 /// A unique name used in place of this placeholder when we parse the pattern as Rust code.
41 stand_in_name: String, 41 stand_in_name: String,
42 pub(crate) constraints: Vec<Constraint>,
43}
44
45#[derive(Clone, Debug, PartialEq, Eq)]
46pub(crate) enum Constraint {
47 Kind(NodeKind),
48 Not(Box<Constraint>),
49}
50
51#[derive(Clone, Debug, PartialEq, Eq)]
52pub(crate) enum NodeKind {
53 Literal,
42} 54}
43 55
44#[derive(Debug, Clone, PartialEq, Eq)] 56#[derive(Debug, Clone, PartialEq, Eq)]
@@ -55,7 +67,7 @@ impl FromStr for SsrRule {
55 let pattern = it.next().expect("at least empty string").trim(); 67 let pattern = it.next().expect("at least empty string").trim();
56 let template = it 68 let template = it
57 .next() 69 .next()
58 .ok_or_else(|| SsrError("Cannot find delemiter `==>>`".into()))? 70 .ok_or_else(|| SsrError("Cannot find delimiter `==>>`".into()))?
59 .trim() 71 .trim()
60 .to_string(); 72 .to_string();
61 if it.next().is_some() { 73 if it.next().is_some() {
@@ -149,7 +161,7 @@ fn parse_pattern(pattern_str: &str) -> Result<Vec<PatternElement>, SsrError> {
149 let mut placeholder_names = FxHashSet::default(); 161 let mut placeholder_names = FxHashSet::default();
150 let mut tokens = tokenize(pattern_str)?.into_iter(); 162 let mut tokens = tokenize(pattern_str)?.into_iter();
151 while let Some(token) = tokens.next() { 163 while let Some(token) = tokens.next() {
152 if token.kind == SyntaxKind::DOLLAR { 164 if token.kind == T![$] {
153 let placeholder = parse_placeholder(&mut tokens)?; 165 let placeholder = parse_placeholder(&mut tokens)?;
154 if !placeholder_names.insert(placeholder.ident.clone()) { 166 if !placeholder_names.insert(placeholder.ident.clone()) {
155 bail!("Name `{}` repeats more than once", placeholder.ident); 167 bail!("Name `{}` repeats more than once", placeholder.ident);
@@ -177,6 +189,9 @@ fn validate_rule(rule: &SsrRule) -> Result<(), SsrError> {
177 if !defined_placeholders.contains(&placeholder.ident) { 189 if !defined_placeholders.contains(&placeholder.ident) {
178 undefined.push(format!("${}", placeholder.ident)); 190 undefined.push(format!("${}", placeholder.ident));
179 } 191 }
192 if !placeholder.constraints.is_empty() {
193 bail!("Replacement placeholders cannot have constraints");
194 }
180 } 195 }
181 } 196 }
182 if !undefined.is_empty() { 197 if !undefined.is_empty() {
@@ -205,23 +220,90 @@ fn tokenize(source: &str) -> Result<Vec<Token>, SsrError> {
205 220
206fn parse_placeholder(tokens: &mut std::vec::IntoIter<Token>) -> Result<Placeholder, SsrError> { 221fn parse_placeholder(tokens: &mut std::vec::IntoIter<Token>) -> Result<Placeholder, SsrError> {
207 let mut name = None; 222 let mut name = None;
223 let mut constraints = Vec::new();
208 if let Some(token) = tokens.next() { 224 if let Some(token) = tokens.next() {
209 match token.kind { 225 match token.kind {
210 SyntaxKind::IDENT => { 226 SyntaxKind::IDENT => {
211 name = Some(token.text); 227 name = Some(token.text);
212 } 228 }
229 T!['{'] => {
230 let token =
231 tokens.next().ok_or_else(|| SsrError::new("Unexpected end of placeholder"))?;
232 if token.kind == SyntaxKind::IDENT {
233 name = Some(token.text);
234 }
235 loop {
236 let token = tokens
237 .next()
238 .ok_or_else(|| SsrError::new("Placeholder is missing closing brace '}'"))?;
239 match token.kind {
240 T![:] => {
241 constraints.push(parse_constraint(tokens)?);
242 }
243 T!['}'] => break,
244 _ => bail!("Unexpected token while parsing placeholder: '{}'", token.text),
245 }
246 }
247 }
213 _ => { 248 _ => {
214 bail!("Placeholders should be $name"); 249 bail!("Placeholders should either be $name or ${name:constraints}");
215 } 250 }
216 } 251 }
217 } 252 }
218 let name = name.ok_or_else(|| SsrError::new("Placeholder ($) with no name"))?; 253 let name = name.ok_or_else(|| SsrError::new("Placeholder ($) with no name"))?;
219 Ok(Placeholder::new(name)) 254 Ok(Placeholder::new(name, constraints))
255}
256
257fn parse_constraint(tokens: &mut std::vec::IntoIter<Token>) -> Result<Constraint, SsrError> {
258 let constraint_type = tokens
259 .next()
260 .ok_or_else(|| SsrError::new("Found end of placeholder while looking for a constraint"))?
261 .text
262 .to_string();
263 match constraint_type.as_str() {
264 "kind" => {
265 expect_token(tokens, "(")?;
266 let t = tokens.next().ok_or_else(|| {
267 SsrError::new("Unexpected end of constraint while looking for kind")
268 })?;
269 if t.kind != SyntaxKind::IDENT {
270 bail!("Expected ident, found {:?} while parsing kind constraint", t.kind);
271 }
272 expect_token(tokens, ")")?;
273 Ok(Constraint::Kind(NodeKind::from(&t.text)?))
274 }
275 "not" => {
276 expect_token(tokens, "(")?;
277 let sub = parse_constraint(tokens)?;
278 expect_token(tokens, ")")?;
279 Ok(Constraint::Not(Box::new(sub)))
280 }
281 x => bail!("Unsupported constraint type '{}'", x),
282 }
283}
284
285fn expect_token(tokens: &mut std::vec::IntoIter<Token>, expected: &str) -> Result<(), SsrError> {
286 if let Some(t) = tokens.next() {
287 if t.text == expected {
288 return Ok(());
289 }
290 bail!("Expected {} found {}", expected, t.text);
291 }
292 bail!("Expected {} found end of stream");
293}
294
295impl NodeKind {
296 fn from(name: &SmolStr) -> Result<NodeKind, SsrError> {
297 Ok(match name.as_str() {
298 "literal" => NodeKind::Literal,
299 _ => bail!("Unknown node kind '{}'", name),
300 })
301 }
220} 302}
221 303
222impl Placeholder { 304impl Placeholder {
223 fn new(name: SmolStr) -> Self { 305 fn new(name: SmolStr, constraints: Vec<Constraint>) -> Self {
224 Self { stand_in_name: format!("__placeholder_{}", name), ident: name } 306 Self { stand_in_name: format!("__placeholder_{}", name), constraints, ident: name }
225 } 307 }
226} 308}
227 309
@@ -241,31 +323,31 @@ mod tests {
241 PatternElement::Token(Token { kind, text: SmolStr::new(text) }) 323 PatternElement::Token(Token { kind, text: SmolStr::new(text) })
242 } 324 }
243 fn placeholder(name: &str) -> PatternElement { 325 fn placeholder(name: &str) -> PatternElement {
244 PatternElement::Placeholder(Placeholder::new(SmolStr::new(name))) 326 PatternElement::Placeholder(Placeholder::new(SmolStr::new(name), Vec::new()))
245 } 327 }
246 let result: SsrRule = "foo($a, $b) ==>> bar($b, $a)".parse().unwrap(); 328 let result: SsrRule = "foo($a, $b) ==>> bar($b, $a)".parse().unwrap();
247 assert_eq!( 329 assert_eq!(
248 result.pattern.raw.tokens, 330 result.pattern.raw.tokens,
249 vec![ 331 vec![
250 token(SyntaxKind::IDENT, "foo"), 332 token(SyntaxKind::IDENT, "foo"),
251 token(SyntaxKind::L_PAREN, "("), 333 token(T!['('], "("),
252 placeholder("a"), 334 placeholder("a"),
253 token(SyntaxKind::COMMA, ","), 335 token(T![,], ","),
254 token(SyntaxKind::WHITESPACE, " "), 336 token(SyntaxKind::WHITESPACE, " "),
255 placeholder("b"), 337 placeholder("b"),
256 token(SyntaxKind::R_PAREN, ")"), 338 token(T![')'], ")"),
257 ] 339 ]
258 ); 340 );
259 assert_eq!( 341 assert_eq!(
260 result.template.tokens, 342 result.template.tokens,
261 vec![ 343 vec![
262 token(SyntaxKind::IDENT, "bar"), 344 token(SyntaxKind::IDENT, "bar"),
263 token(SyntaxKind::L_PAREN, "("), 345 token(T!['('], "("),
264 placeholder("b"), 346 placeholder("b"),
265 token(SyntaxKind::COMMA, ","), 347 token(T![,], ","),
266 token(SyntaxKind::WHITESPACE, " "), 348 token(SyntaxKind::WHITESPACE, " "),
267 placeholder("a"), 349 placeholder("a"),
268 token(SyntaxKind::R_PAREN, ")"), 350 token(T![')'], ")"),
269 ] 351 ]
270 ); 352 );
271 } 353 }
diff --git a/crates/ra_ssr/src/replacing.rs b/crates/ra_ssr/src/replacing.rs
index 70ce1c185..e43cc5167 100644
--- a/crates/ra_ssr/src/replacing.rs
+++ b/crates/ra_ssr/src/replacing.rs
@@ -21,8 +21,10 @@ fn matches_to_edit_at_offset(
21) -> TextEdit { 21) -> TextEdit {
22 let mut edit_builder = ra_text_edit::TextEditBuilder::default(); 22 let mut edit_builder = ra_text_edit::TextEditBuilder::default();
23 for m in &matches.matches { 23 for m in &matches.matches {
24 edit_builder 24 edit_builder.replace(
25 .replace(m.range.checked_sub(relative_start).unwrap(), render_replace(m, file_src)); 25 m.range.range.checked_sub(relative_start).unwrap(),
26 render_replace(m, file_src),
27 );
26 } 28 }
27 edit_builder.finish() 29 edit_builder.finish()
28} 30}
diff --git a/crates/ra_ssr/src/tests.rs b/crates/ra_ssr/src/tests.rs
index 8be60c293..9568d4432 100644
--- a/crates/ra_ssr/src/tests.rs
+++ b/crates/ra_ssr/src/tests.rs
@@ -1,150 +1,6 @@
1use crate::matching::MatchFailureReason; 1use crate::{MatchFinder, SsrRule};
2use crate::{matching, Match, MatchFinder, SsrMatches, SsrPattern, SsrRule}; 2use ra_db::{FileId, SourceDatabaseExt};
3use matching::record_match_fails_reasons_scope; 3use test_utils::mark;
4use ra_db::{FileId, FileRange, SourceDatabaseExt};
5use ra_syntax::ast::AstNode;
6use ra_syntax::{ast, SyntaxKind, SyntaxNode, TextRange};
7
8struct MatchDebugInfo {
9 node: SyntaxNode,
10 /// Our search pattern parsed as the same kind of syntax node as `node`. e.g. expression, item,
11 /// etc. Will be absent if the pattern can't be parsed as that kind.
12 pattern: Result<SyntaxNode, MatchFailureReason>,
13 matched: Result<Match, MatchFailureReason>,
14}
15
16impl SsrPattern {
17 pub(crate) fn tree_for_kind_with_reason(
18 &self,
19 kind: SyntaxKind,
20 ) -> Result<&SyntaxNode, MatchFailureReason> {
21 record_match_fails_reasons_scope(true, || self.tree_for_kind(kind))
22 .map_err(|e| MatchFailureReason { reason: e.reason.unwrap() })
23 }
24}
25
26impl std::fmt::Debug for MatchDebugInfo {
27 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28 write!(f, "========= PATTERN ==========\n")?;
29 match &self.pattern {
30 Ok(pattern) => {
31 write!(f, "{:#?}", pattern)?;
32 }
33 Err(err) => {
34 write!(f, "{}", err.reason)?;
35 }
36 }
37 write!(
38 f,
39 "\n============ AST ===========\n\
40 {:#?}\n============================",
41 self.node
42 )?;
43 match &self.matched {
44 Ok(_) => write!(f, "Node matched")?,
45 Err(reason) => write!(f, "Node failed to match because: {}", reason.reason)?,
46 }
47 Ok(())
48 }
49}
50
51impl SsrMatches {
52 /// Returns `self` with any nested matches removed and made into top-level matches.
53 pub(crate) fn flattened(self) -> SsrMatches {
54 let mut out = SsrMatches::default();
55 self.flatten_into(&mut out);
56 out
57 }
58
59 fn flatten_into(self, out: &mut SsrMatches) {
60 for mut m in self.matches {
61 for p in m.placeholder_values.values_mut() {
62 std::mem::replace(&mut p.inner_matches, SsrMatches::default()).flatten_into(out);
63 }
64 out.matches.push(m);
65 }
66 }
67}
68
69impl Match {
70 pub(crate) fn matched_text(&self) -> String {
71 self.matched_node.text().to_string()
72 }
73}
74
75impl<'db> MatchFinder<'db> {
76 /// Adds a search pattern. For use if you intend to only call `find_matches_in_file`. If you
77 /// intend to do replacement, use `add_rule` instead.
78 fn add_search_pattern(&mut self, pattern: SsrPattern) {
79 self.add_rule(SsrRule { pattern, template: "()".parse().unwrap() })
80 }
81
82 /// Finds all nodes in `file_id` whose text is exactly equal to `snippet` and attempts to match
83 /// them, while recording reasons why they don't match. This API is useful for command
84 /// line-based debugging where providing a range is difficult.
85 fn debug_where_text_equal(&self, file_id: FileId, snippet: &str) -> Vec<MatchDebugInfo> {
86 let file = self.sema.parse(file_id);
87 let mut res = Vec::new();
88 let file_text = self.sema.db.file_text(file_id);
89 let mut remaining_text = file_text.as_str();
90 let mut base = 0;
91 let len = snippet.len() as u32;
92 while let Some(offset) = remaining_text.find(snippet) {
93 let start = base + offset as u32;
94 let end = start + len;
95 self.output_debug_for_nodes_at_range(
96 file.syntax(),
97 TextRange::new(start.into(), end.into()),
98 &None,
99 &mut res,
100 );
101 remaining_text = &remaining_text[offset + snippet.len()..];
102 base = end;
103 }
104 res
105 }
106
107 fn output_debug_for_nodes_at_range(
108 &self,
109 node: &SyntaxNode,
110 range: TextRange,
111 restrict_range: &Option<FileRange>,
112 out: &mut Vec<MatchDebugInfo>,
113 ) {
114 for node in node.children() {
115 if !node.text_range().contains_range(range) {
116 continue;
117 }
118 if node.text_range() == range {
119 for rule in &self.rules {
120 let pattern =
121 rule.pattern.tree_for_kind_with_reason(node.kind()).map(|p| p.clone());
122 out.push(MatchDebugInfo {
123 matched: matching::get_match(true, rule, &node, restrict_range, &self.sema)
124 .map_err(|e| MatchFailureReason {
125 reason: e.reason.unwrap_or_else(|| {
126 "Match failed, but no reason was given".to_owned()
127 }),
128 }),
129 pattern,
130 node: node.clone(),
131 });
132 }
133 } else if let Some(macro_call) = ast::MacroCall::cast(node.clone()) {
134 if let Some(expanded) = self.sema.expand(&macro_call) {
135 if let Some(tt) = macro_call.token_tree() {
136 self.output_debug_for_nodes_at_range(
137 &expanded,
138 range,
139 &Some(self.sema.original_range(tt.syntax())),
140 out,
141 );
142 }
143 }
144 }
145 }
146 }
147}
148 4
149fn parse_error_text(query: &str) -> String { 5fn parse_error_text(query: &str) -> String {
150 format!("{}", query.parse::<SsrRule>().unwrap_err()) 6 format!("{}", query.parse::<SsrRule>().unwrap_err())
@@ -152,12 +8,12 @@ fn parse_error_text(query: &str) -> String {
152 8
153#[test] 9#[test]
154fn parser_empty_query() { 10fn parser_empty_query() {
155 assert_eq!(parse_error_text(""), "Parse error: Cannot find delemiter `==>>`"); 11 assert_eq!(parse_error_text(""), "Parse error: Cannot find delimiter `==>>`");
156} 12}
157 13
158#[test] 14#[test]
159fn parser_no_delimiter() { 15fn parser_no_delimiter() {
160 assert_eq!(parse_error_text("foo()"), "Parse error: Cannot find delemiter `==>>`"); 16 assert_eq!(parse_error_text("foo()"), "Parse error: Cannot find delimiter `==>>`");
161} 17}
162 18
163#[test] 19#[test]
@@ -227,7 +83,7 @@ fn assert_ssr_transforms(rules: &[&str], input: &str, result: &str) {
227 let mut after = db.file_text(file_id).to_string(); 83 let mut after = db.file_text(file_id).to_string();
228 edits.apply(&mut after); 84 edits.apply(&mut after);
229 // Likewise, we need to make sure that whatever transformations fixture parsing applies, 85 // Likewise, we need to make sure that whatever transformations fixture parsing applies,
230 // also get appplied to our expected result. 86 // also get applied to our expected result.
231 let result = normalize_code(result); 87 let result = normalize_code(result);
232 assert_eq!(after, result); 88 assert_eq!(after, result);
233 } else { 89 } else {
@@ -260,6 +116,19 @@ fn assert_no_match(pattern: &str, code: &str) {
260 assert_matches(pattern, code, &[]); 116 assert_matches(pattern, code, &[]);
261} 117}
262 118
119fn assert_match_failure_reason(pattern: &str, code: &str, snippet: &str, expected_reason: &str) {
120 let (db, file_id) = single_file(code);
121 let mut match_finder = MatchFinder::new(&db);
122 match_finder.add_search_pattern(pattern.parse().unwrap());
123 let mut reasons = Vec::new();
124 for d in match_finder.debug_where_text_equal(file_id, snippet) {
125 if let Some(reason) = d.match_failure_reason() {
126 reasons.push(reason.to_owned());
127 }
128 }
129 assert_eq!(reasons, vec![expected_reason]);
130}
131
263#[test] 132#[test]
264fn ssr_function_to_method() { 133fn ssr_function_to_method() {
265 assert_ssr_transform( 134 assert_ssr_transform(
@@ -434,6 +303,22 @@ fn match_pattern() {
434} 303}
435 304
436#[test] 305#[test]
306fn literal_constraint() {
307 mark::check!(literal_constraint);
308 let code = r#"
309 fn f1() {
310 let x1 = Some(42);
311 let x2 = Some("foo");
312 let x3 = Some(x1);
313 let x4 = Some(40 + 2);
314 let x5 = Some(true);
315 }
316 "#;
317 assert_matches("Some(${a:kind(literal)})", code, &["Some(42)", "Some(\"foo\")", "Some(true)"]);
318 assert_matches("Some(${a:not(kind(literal))})", code, &["Some(x1)", "Some(40 + 2)"]);
319}
320
321#[test]
437fn match_reordered_struct_instantiation() { 322fn match_reordered_struct_instantiation() {
438 assert_matches( 323 assert_matches(
439 "Foo {aa: 1, b: 2, ccc: 3}", 324 "Foo {aa: 1, b: 2, ccc: 3}",
@@ -623,3 +508,30 @@ fn preserves_whitespace_within_macro_expansion() {
623 fn f() {macro1!(4 - 3 - 1 * 2}"#, 508 fn f() {macro1!(4 - 3 - 1 * 2}"#,
624 ) 509 )
625} 510}
511
512#[test]
513fn match_failure_reasons() {
514 let code = r#"
515 macro_rules! foo {
516 ($a:expr) => {
517 1 + $a + 2
518 };
519 }
520 fn f1() {
521 bar(1, 2);
522 foo!(5 + 43.to_string() + 5);
523 }
524 "#;
525 assert_match_failure_reason(
526 "bar($a, 3)",
527 code,
528 "bar(1, 2)",
529 r#"Pattern wanted token '3' (INT_NUMBER), but code had token '2' (INT_NUMBER)"#,
530 );
531 assert_match_failure_reason(
532 "42.to_string()",
533 code,
534 "43.to_string()",
535 r#"Pattern wanted token '42' (INT_NUMBER), but code had token '43' (INT_NUMBER)"#,
536 );
537}
diff --git a/crates/ra_syntax/src/tests.rs b/crates/ra_syntax/src/tests.rs
index 959967b79..7b4232497 100644
--- a/crates/ra_syntax/src/tests.rs
+++ b/crates/ra_syntax/src/tests.rs
@@ -1,9 +1,11 @@
1use std::{ 1use std::{
2 env,
2 fmt::Write, 3 fmt::Write,
4 fs,
3 path::{Component, Path, PathBuf}, 5 path::{Component, Path, PathBuf},
4}; 6};
5 7
6use test_utils::{collect_rust_files, dir_tests, project_dir, read_text}; 8use test_utils::{assert_eq_text, project_dir};
7 9
8use crate::{fuzz, tokenize, SourceFile, SyntaxError, TextRange, TextSize, Token}; 10use crate::{fuzz, tokenize, SourceFile, SyntaxError, TextRange, TextSize, Token};
9 11
@@ -200,3 +202,99 @@ where
200 } 202 }
201 }); 203 });
202} 204}
205
206/// Calls callback `f` with input code and file paths for each `.rs` file in `test_data_dir`
207/// subdirectories defined by `paths`.
208///
209/// If the content of the matching output file differs from the output of `f()`
210/// the test will fail.
211///
212/// If there is no matching output file it will be created and filled with the
213/// output of `f()`, but the test will fail.
214fn dir_tests<F>(test_data_dir: &Path, paths: &[&str], outfile_extension: &str, f: F)
215where
216 F: Fn(&str, &Path) -> String,
217{
218 for (path, input_code) in collect_rust_files(test_data_dir, paths) {
219 let actual = f(&input_code, &path);
220 let path = path.with_extension(outfile_extension);
221 if !path.exists() {
222 println!("\nfile: {}", path.display());
223 println!("No .txt file with expected result, creating...\n");
224 println!("{}\n{}", input_code, actual);
225 fs::write(&path, &actual).unwrap();
226 panic!("No expected result");
227 }
228 let expected = read_text(&path);
229 assert_equal_text(&expected, &actual, &path);
230 }
231}
232
233/// Collects all `.rs` files from `dir` subdirectories defined by `paths`.
234fn collect_rust_files(root_dir: &Path, paths: &[&str]) -> Vec<(PathBuf, String)> {
235 paths
236 .iter()
237 .flat_map(|path| {
238 let path = root_dir.to_owned().join(path);
239 rust_files_in_dir(&path).into_iter()
240 })
241 .map(|path| {
242 let text = read_text(&path);
243 (path, text)
244 })
245 .collect()
246}
247
248/// Collects paths to all `.rs` files from `dir` in a sorted `Vec<PathBuf>`.
249fn rust_files_in_dir(dir: &Path) -> Vec<PathBuf> {
250 let mut acc = Vec::new();
251 for file in fs::read_dir(&dir).unwrap() {
252 let file = file.unwrap();
253 let path = file.path();
254 if path.extension().unwrap_or_default() == "rs" {
255 acc.push(path);
256 }
257 }
258 acc.sort();
259 acc
260}
261
262/// Asserts that `expected` and `actual` strings are equal. If they differ only
263/// in trailing or leading whitespace the test won't fail and
264/// the contents of `actual` will be written to the file located at `path`.
265fn assert_equal_text(expected: &str, actual: &str, path: &Path) {
266 if expected == actual {
267 return;
268 }
269 let dir = project_dir();
270 let pretty_path = path.strip_prefix(&dir).unwrap_or_else(|_| path);
271 if expected.trim() == actual.trim() {
272 println!("whitespace difference, rewriting");
273 println!("file: {}\n", pretty_path.display());
274 fs::write(path, actual).unwrap();
275 return;
276 }
277 if env::var("UPDATE_EXPECT").is_ok() {
278 println!("rewriting {}", pretty_path.display());
279 fs::write(path, actual).unwrap();
280 return;
281 }
282 assert_eq_text!(expected, actual, "file: {}", pretty_path.display());
283}
284
285/// Read file and normalize newlines.
286///
287/// `rustc` seems to always normalize `\r\n` newlines to `\n`:
288///
289/// ```
290/// let s = "
291/// ";
292/// assert_eq!(s.as_bytes(), &[10]);
293/// ```
294///
295/// so this should always be correct.
296fn read_text(path: &Path) -> String {
297 fs::read_to_string(path)
298 .unwrap_or_else(|_| panic!("File at {:?} should be valid", path))
299 .replace("\r\n", "\n")
300}
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index 53621fb44..837b6714d 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -28,6 +28,7 @@ rustc-hash = "1.1.0"
28serde = { version = "1.0.106", features = ["derive"] } 28serde = { version = "1.0.106", features = ["derive"] }
29serde_json = "1.0.48" 29serde_json = "1.0.48"
30threadpool = "1.7.1" 30threadpool = "1.7.1"
31rayon = "1.3.1"
31 32
32stdx = { path = "../stdx" } 33stdx = { path = "../stdx" }
33 34
@@ -45,6 +46,8 @@ ra_toolchain = { path = "../ra_toolchain" }
45 46
46# This should only be used in CLI 47# This should only be used in CLI
47ra_db = { path = "../ra_db" } 48ra_db = { path = "../ra_db" }
49ra_ide_db = { path = "../ra_ide_db" }
50ra_ssr = { path = "../ra_ssr" }
48hir = { path = "../ra_hir", package = "ra_hir" } 51hir = { path = "../ra_hir", package = "ra_hir" }
49hir_def = { path = "../ra_hir_def", package = "ra_hir_def" } 52hir_def = { path = "../ra_hir_def", package = "ra_hir_def" }
50hir_ty = { path = "../ra_hir_ty", package = "ra_hir_ty" } 53hir_ty = { path = "../ra_hir_ty", package = "ra_hir_ty" }
diff --git a/crates/rust-analyzer/src/bin/args.rs b/crates/rust-analyzer/src/bin/args.rs
index 8e3ca9343..8c0f4df8b 100644
--- a/crates/rust-analyzer/src/bin/args.rs
+++ b/crates/rust-analyzer/src/bin/args.rs
@@ -5,6 +5,7 @@
5 5
6use anyhow::{bail, Result}; 6use anyhow::{bail, Result};
7use pico_args::Arguments; 7use pico_args::Arguments;
8use ra_ssr::{SsrPattern, SsrRule};
8use rust_analyzer::cli::{BenchWhat, Position, Verbosity}; 9use rust_analyzer::cli::{BenchWhat, Position, Verbosity};
9 10
10use std::{fmt::Write, path::PathBuf}; 11use std::{fmt::Write, path::PathBuf};
@@ -24,6 +25,7 @@ pub(crate) enum Command {
24 }, 25 },
25 Stats { 26 Stats {
26 randomize: bool, 27 randomize: bool,
28 parallel: bool,
27 memory_usage: bool, 29 memory_usage: bool,
28 only: Option<String>, 30 only: Option<String>,
29 with_deps: bool, 31 with_deps: bool,
@@ -45,6 +47,13 @@ pub(crate) enum Command {
45 /// this would include the parser test files. 47 /// this would include the parser test files.
46 all: bool, 48 all: bool,
47 }, 49 },
50 Ssr {
51 rules: Vec<SsrRule>,
52 },
53 StructuredSearch {
54 debug_snippet: Option<String>,
55 patterns: Vec<SsrPattern>,
56 },
48 ProcMacro, 57 ProcMacro,
49 RunServer, 58 RunServer,
50 Version, 59 Version,
@@ -94,7 +103,7 @@ USAGE:
94 rust-analyzer parse [FLAGS] 103 rust-analyzer parse [FLAGS]
95 104
96FLAGS: 105FLAGS:
97 -h, --help Prints help inforamtion 106 -h, --help Prints help information
98 --no-dump" 107 --no-dump"
99 ); 108 );
100 return Ok(Err(HelpPrinted)); 109 return Ok(Err(HelpPrinted));
@@ -153,10 +162,14 @@ USAGE:
153 rust-analyzer analysis-stats [FLAGS] [OPTIONS] [PATH] 162 rust-analyzer analysis-stats [FLAGS] [OPTIONS] [PATH]
154 163
155FLAGS: 164FLAGS:
165 -o, --only Only analyze items matching this path
156 -h, --help Prints help information 166 -h, --help Prints help information
157 --memory-usage 167 --memory-usage Collect memory usage statistics (requires `--feature jemalloc`)
168 --randomize Randomize order in which crates, modules, and items are processed
169 --parallel Run type inference in parallel
158 --load-output-dirs Load OUT_DIR values by running `cargo check` before analysis 170 --load-output-dirs Load OUT_DIR values by running `cargo check` before analysis
159 --with-proc-macro Use ra-proc-macro-srv for proc-macro expanding 171 --with-proc-macro Use ra-proc-macro-srv for proc-macro expanding
172 --with-deps Also analyze all dependencies
160 -v, --verbose 173 -v, --verbose
161 -q, --quiet 174 -q, --quiet
162 175
@@ -170,6 +183,7 @@ ARGS:
170 } 183 }
171 184
172 let randomize = matches.contains("--randomize"); 185 let randomize = matches.contains("--randomize");
186 let parallel = matches.contains("--parallel");
173 let memory_usage = matches.contains("--memory-usage"); 187 let memory_usage = matches.contains("--memory-usage");
174 let only: Option<String> = matches.opt_value_from_str(["-o", "--only"])?; 188 let only: Option<String> = matches.opt_value_from_str(["-o", "--only"])?;
175 let with_deps: bool = matches.contains("--with-deps"); 189 let with_deps: bool = matches.contains("--with-deps");
@@ -185,6 +199,7 @@ ARGS:
185 199
186 Command::Stats { 200 Command::Stats {
187 randomize, 201 randomize,
202 parallel,
188 memory_usage, 203 memory_usage,
189 only, 204 only,
190 with_deps, 205 with_deps,
@@ -205,7 +220,7 @@ USAGE:
205FLAGS: 220FLAGS:
206 -h, --help Prints help information 221 -h, --help Prints help information
207 --load-output-dirs Load OUT_DIR values by running `cargo check` before analysis 222 --load-output-dirs Load OUT_DIR values by running `cargo check` before analysis
208 --with-proc-macro Use ra-proc-macro-srv for proc-macro expanding 223 --with-proc-macro Use ra-proc-macro-srv for proc-macro expanding
209 -v, --verbose 224 -v, --verbose
210 225
211OPTIONS: 226OPTIONS:
@@ -270,6 +285,61 @@ ARGS:
270 Command::Diagnostics { path, load_output_dirs, with_proc_macro, all } 285 Command::Diagnostics { path, load_output_dirs, with_proc_macro, all }
271 } 286 }
272 "proc-macro" => Command::ProcMacro, 287 "proc-macro" => Command::ProcMacro,
288 "ssr" => {
289 if matches.contains(["-h", "--help"]) {
290 eprintln!(
291 "\
292rust-analyzer ssr
293
294USAGE:
295 rust-analyzer ssr [FLAGS] [RULE...]
296
297EXAMPLE:
298 rust-analyzer ssr '$a.foo($b) ==> bar($a, $b)'
299
300FLAGS:
301 --debug <snippet> Prints debug information for any nodes with source exactly equal to <snippet>
302 -h, --help Prints help information
303
304ARGS:
305 <RULE> A structured search replace rule"
306 );
307 return Ok(Err(HelpPrinted));
308 }
309 let mut rules = Vec::new();
310 while let Some(rule) = matches.free_from_str()? {
311 rules.push(rule);
312 }
313 Command::Ssr { rules }
314 }
315 "search" => {
316 if matches.contains(["-h", "--help"]) {
317 eprintln!(
318 "\
319rust-analyzer search
320
321USAGE:
322 rust-analyzer search [FLAGS] [PATTERN...]
323
324EXAMPLE:
325 rust-analyzer search '$a.foo($b)'
326
327FLAGS:
328 --debug <snippet> Prints debug information for any nodes with source exactly equal to <snippet>
329 -h, --help Prints help information
330
331ARGS:
332 <PATTERN> A structured search pattern"
333 );
334 return Ok(Err(HelpPrinted));
335 }
336 let debug_snippet = matches.opt_value_from_str("--debug")?;
337 let mut patterns = Vec::new();
338 while let Some(rule) = matches.free_from_str()? {
339 patterns.push(rule);
340 }
341 Command::StructuredSearch { patterns, debug_snippet }
342 }
273 _ => { 343 _ => {
274 print_subcommands(); 344 print_subcommands();
275 return Ok(Err(HelpPrinted)); 345 return Ok(Err(HelpPrinted));
@@ -297,6 +367,8 @@ SUBCOMMANDS:
297 diagnostics 367 diagnostics
298 proc-macro 368 proc-macro
299 parse 369 parse
370 search
371 ssr
300 symbols" 372 symbols"
301 ) 373 )
302} 374}
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs
index 45204d1a3..eec76d415 100644
--- a/crates/rust-analyzer/src/bin/main.rs
+++ b/crates/rust-analyzer/src/bin/main.rs
@@ -32,6 +32,7 @@ fn main() -> Result<()> {
32 args::Command::Highlight { rainbow } => cli::highlight(rainbow)?, 32 args::Command::Highlight { rainbow } => cli::highlight(rainbow)?,
33 args::Command::Stats { 33 args::Command::Stats {
34 randomize, 34 randomize,
35 parallel,
35 memory_usage, 36 memory_usage,
36 only, 37 only,
37 with_deps, 38 with_deps,
@@ -45,6 +46,7 @@ fn main() -> Result<()> {
45 only.as_ref().map(String::as_ref), 46 only.as_ref().map(String::as_ref),
46 with_deps, 47 with_deps,
47 randomize, 48 randomize,
49 parallel,
48 load_output_dirs, 50 load_output_dirs,
49 with_proc_macro, 51 with_proc_macro,
50 )?, 52 )?,
@@ -60,6 +62,12 @@ fn main() -> Result<()> {
60 args::Command::Diagnostics { path, load_output_dirs, with_proc_macro, all } => { 62 args::Command::Diagnostics { path, load_output_dirs, with_proc_macro, all } => {
61 cli::diagnostics(path.as_ref(), load_output_dirs, with_proc_macro, all)? 63 cli::diagnostics(path.as_ref(), load_output_dirs, with_proc_macro, all)?
62 } 64 }
65 args::Command::Ssr { rules } => {
66 cli::apply_ssr_rules(rules)?;
67 }
68 args::Command::StructuredSearch { patterns, debug_snippet } => {
69 cli::search_for_patterns(patterns, debug_snippet)?;
70 }
63 args::Command::Version => println!("rust-analyzer {}", env!("REV")), 71 args::Command::Version => println!("rust-analyzer {}", env!("REV")),
64 } 72 }
65 Ok(()) 73 Ok(())
diff --git a/crates/rust-analyzer/src/cli.rs b/crates/rust-analyzer/src/cli.rs
index c5faec83a..6863f100b 100644
--- a/crates/rust-analyzer/src/cli.rs
+++ b/crates/rust-analyzer/src/cli.rs
@@ -5,6 +5,7 @@ mod analysis_stats;
5mod analysis_bench; 5mod analysis_bench;
6mod diagnostics; 6mod diagnostics;
7mod progress_report; 7mod progress_report;
8mod ssr;
8 9
9use std::io::Read; 10use std::io::Read;
10 11
@@ -17,6 +18,7 @@ pub use analysis_bench::{analysis_bench, BenchWhat, Position};
17pub use analysis_stats::analysis_stats; 18pub use analysis_stats::analysis_stats;
18pub use diagnostics::diagnostics; 19pub use diagnostics::diagnostics;
19pub use load_cargo::load_cargo; 20pub use load_cargo::load_cargo;
21pub use ssr::{apply_ssr_rules, search_for_patterns};
20 22
21#[derive(Clone, Copy)] 23#[derive(Clone, Copy)]
22pub enum Verbosity { 24pub enum Verbosity {
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs
index 9d09501cd..14982919d 100644
--- a/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -5,6 +5,7 @@ use std::{path::Path, time::Instant};
5 5
6use itertools::Itertools; 6use itertools::Itertools;
7use rand::{seq::SliceRandom, thread_rng}; 7use rand::{seq::SliceRandom, thread_rng};
8use rayon::prelude::*;
8use rustc_hash::FxHashSet; 9use rustc_hash::FxHashSet;
9 10
10use hir::{ 11use hir::{
@@ -13,12 +14,23 @@ use hir::{
13}; 14};
14use hir_def::FunctionId; 15use hir_def::FunctionId;
15use hir_ty::{Ty, TypeWalk}; 16use hir_ty::{Ty, TypeWalk};
16use ra_db::SourceDatabaseExt; 17use ra_db::{
18 salsa::{self, ParallelDatabase},
19 SourceDatabaseExt,
20};
17use ra_syntax::AstNode; 21use ra_syntax::AstNode;
18use stdx::format_to; 22use stdx::format_to;
19 23
20use crate::cli::{load_cargo::load_cargo, progress_report::ProgressReport, Result, Verbosity}; 24use crate::cli::{load_cargo::load_cargo, progress_report::ProgressReport, Result, Verbosity};
21 25
26/// Need to wrap Snapshot to provide `Clone` impl for `map_with`
27struct Snap<DB>(DB);
28impl<DB: ParallelDatabase> Clone for Snap<salsa::Snapshot<DB>> {
29 fn clone(&self) -> Snap<salsa::Snapshot<DB>> {
30 Snap(self.0.snapshot())
31 }
32}
33
22pub fn analysis_stats( 34pub fn analysis_stats(
23 verbosity: Verbosity, 35 verbosity: Verbosity,
24 memory_usage: bool, 36 memory_usage: bool,
@@ -26,6 +38,7 @@ pub fn analysis_stats(
26 only: Option<&str>, 38 only: Option<&str>,
27 with_deps: bool, 39 with_deps: bool,
28 randomize: bool, 40 randomize: bool,
41 parallel: bool,
29 load_output_dirs: bool, 42 load_output_dirs: bool,
30 with_proc_macro: bool, 43 with_proc_macro: bool,
31) -> Result<()> { 44) -> Result<()> {
@@ -91,12 +104,26 @@ pub fn analysis_stats(
91 funcs.shuffle(&mut thread_rng()); 104 funcs.shuffle(&mut thread_rng());
92 } 105 }
93 106
94 let inference_time = Instant::now();
95 let mut bar = match verbosity { 107 let mut bar = match verbosity {
96 Verbosity::Quiet | Verbosity::Spammy => ProgressReport::hidden(), 108 Verbosity::Quiet | Verbosity::Spammy => ProgressReport::hidden(),
97 _ => ProgressReport::new(funcs.len() as u64), 109 _ => ProgressReport::new(funcs.len() as u64),
98 }; 110 };
99 111
112 if parallel {
113 let inference_time = Instant::now();
114 let snap = Snap(db.snapshot());
115 funcs
116 .par_iter()
117 .map_with(snap, |snap, &f| {
118 let f_id = FunctionId::from(f);
119 snap.0.body(f_id.into());
120 snap.0.infer(f_id.into());
121 })
122 .count();
123 println!("Parallel Inference: {:?}, {}", inference_time.elapsed(), ra_prof::memory_usage());
124 }
125
126 let inference_time = Instant::now();
100 bar.tick(); 127 bar.tick();
101 let mut num_exprs = 0; 128 let mut num_exprs = 0;
102 let mut num_exprs_unknown = 0; 129 let mut num_exprs_unknown = 0;
diff --git a/crates/rust-analyzer/src/cli/ssr.rs b/crates/rust-analyzer/src/cli/ssr.rs
new file mode 100644
index 000000000..4fb829ea5
--- /dev/null
+++ b/crates/rust-analyzer/src/cli/ssr.rs
@@ -0,0 +1,71 @@
1//! Applies structured search replace rules from the command line.
2
3use crate::cli::{load_cargo::load_cargo, Result};
4use ra_ide::SourceFileEdit;
5use ra_ssr::{MatchFinder, SsrPattern, SsrRule};
6
7pub fn apply_ssr_rules(rules: Vec<SsrRule>) -> Result<()> {
8 use ra_db::SourceDatabaseExt;
9 use ra_ide_db::symbol_index::SymbolsDatabase;
10 let (host, vfs) = load_cargo(&std::env::current_dir()?, true, true)?;
11 let db = host.raw_database();
12 let mut match_finder = MatchFinder::new(db);
13 for rule in rules {
14 match_finder.add_rule(rule);
15 }
16 let mut edits = Vec::new();
17 for &root in db.local_roots().iter() {
18 let sr = db.source_root(root);
19 for file_id in sr.iter() {
20 if let Some(edit) = match_finder.edits_for_file(file_id) {
21 edits.push(SourceFileEdit { file_id, edit });
22 }
23 }
24 }
25 for edit in edits {
26 if let Some(path) = vfs.file_path(edit.file_id).as_path() {
27 let mut contents = db.file_text(edit.file_id).to_string();
28 edit.edit.apply(&mut contents);
29 std::fs::write(path, contents)?;
30 }
31 }
32 Ok(())
33}
34
35/// Searches for `patterns`, printing debug information for any nodes whose text exactly matches
36/// `debug_snippet`. This is intended for debugging and probably isn't in it's current form useful
37/// for much else.
38pub fn search_for_patterns(patterns: Vec<SsrPattern>, debug_snippet: Option<String>) -> Result<()> {
39 use ra_db::SourceDatabaseExt;
40 use ra_ide_db::symbol_index::SymbolsDatabase;
41 let (host, vfs) = load_cargo(&std::env::current_dir()?, true, true)?;
42 let db = host.raw_database();
43 let mut match_finder = MatchFinder::new(db);
44 for pattern in patterns {
45 match_finder.add_search_pattern(pattern);
46 }
47 for &root in db.local_roots().iter() {
48 let sr = db.source_root(root);
49 for file_id in sr.iter() {
50 if let Some(debug_snippet) = &debug_snippet {
51 for debug_info in match_finder.debug_where_text_equal(file_id, debug_snippet) {
52 println!("{:#?}", debug_info);
53 }
54 } else {
55 let matches = match_finder.find_matches_in_file(file_id);
56 if !matches.matches.is_empty() {
57 let matches = matches.flattened().matches;
58 if let Some(path) = vfs.file_path(file_id).as_path() {
59 println!("{} matches in '{}'", matches.len(), path.to_string_lossy());
60 }
61 // We could possibly at some point do something more useful than just printing
62 // the matched text. For now though, that's the easiest thing to do.
63 for m in matches {
64 println!("{}", m.matched_text());
65 }
66 }
67 }
68 }
69 }
70 Ok(())
71}
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 6b17ce18b..6c311648a 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -44,7 +44,7 @@ pub struct Config {
44 pub root_path: AbsPathBuf, 44 pub root_path: AbsPathBuf,
45} 45}
46 46
47#[derive(Debug, Clone)] 47#[derive(Debug, Clone, Eq, PartialEq)]
48pub enum LinkedProject { 48pub enum LinkedProject {
49 ProjectManifest(ProjectManifest), 49 ProjectManifest(ProjectManifest),
50 InlineJsonProject(ProjectJson), 50 InlineJsonProject(ProjectJson),
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index b8aa1e5b5..b7b4edf66 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -27,7 +27,7 @@ use crate::{
27 Result, 27 Result,
28}; 28};
29 29
30#[derive(Eq, PartialEq)] 30#[derive(Eq, PartialEq, Copy, Clone)]
31pub(crate) enum Status { 31pub(crate) enum Status {
32 Loading, 32 Loading,
33 Ready, 33 Ready,
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index e35a5e846..3cb532b62 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -23,7 +23,7 @@ use ra_ide::{
23}; 23};
24use ra_prof::profile; 24use ra_prof::profile;
25use ra_project_model::TargetKind; 25use ra_project_model::TargetKind;
26use ra_syntax::{AstNode, SyntaxKind, TextRange, TextSize}; 26use ra_syntax::{algo, ast, AstNode, SyntaxKind, TextRange, TextSize};
27use serde::{Deserialize, Serialize}; 27use serde::{Deserialize, Serialize};
28use serde_json::to_value; 28use serde_json::to_value;
29use stdx::{format_to, split_delim}; 29use stdx::{format_to, split_delim};
@@ -330,11 +330,12 @@ pub(crate) fn handle_workspace_symbol(
330 fn exec_query(snap: &GlobalStateSnapshot, query: Query) -> Result<Vec<SymbolInformation>> { 330 fn exec_query(snap: &GlobalStateSnapshot, query: Query) -> Result<Vec<SymbolInformation>> {
331 let mut res = Vec::new(); 331 let mut res = Vec::new();
332 for nav in snap.analysis.symbol_search(query)? { 332 for nav in snap.analysis.symbol_search(query)? {
333 let container_name = nav.container_name().map(|v| v.to_string());
333 let info = SymbolInformation { 334 let info = SymbolInformation {
334 name: nav.name().to_string(), 335 name: nav.name().to_string(),
335 kind: to_proto::symbol_kind(nav.kind()), 336 kind: to_proto::symbol_kind(nav.kind()),
336 location: to_proto::location(snap, nav.file_range())?, 337 location: to_proto::location_from_nav(snap, nav)?,
337 container_name: nav.container_name().map(|v| v.to_string()), 338 container_name,
338 deprecated: None, 339 deprecated: None,
339 }; 340 };
340 res.push(info); 341 res.push(info);
@@ -407,8 +408,19 @@ pub(crate) fn handle_runnables(
407 let file_id = from_proto::file_id(&snap, &params.text_document.uri)?; 408 let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
408 let line_index = snap.analysis.file_line_index(file_id)?; 409 let line_index = snap.analysis.file_line_index(file_id)?;
409 let offset = params.position.map(|it| from_proto::offset(&line_index, it)); 410 let offset = params.position.map(|it| from_proto::offset(&line_index, it));
410 let mut res = Vec::new();
411 let cargo_spec = CargoTargetSpec::for_file(&snap, file_id)?; 411 let cargo_spec = CargoTargetSpec::for_file(&snap, file_id)?;
412
413 let expect_test = match offset {
414 Some(offset) => {
415 let source_file = snap.analysis.parse(file_id)?;
416 algo::find_node_at_offset::<ast::MacroCall>(source_file.syntax(), offset)
417 .and_then(|it| it.path()?.segment()?.name_ref())
418 .map_or(false, |it| it.text() == "expect" || it.text() == "expect_file")
419 }
420 None => false,
421 };
422
423 let mut res = Vec::new();
412 for runnable in snap.analysis.runnables(file_id)? { 424 for runnable in snap.analysis.runnables(file_id)? {
413 if let Some(offset) = offset { 425 if let Some(offset) = offset {
414 if !runnable.nav.full_range().contains_inclusive(offset) { 426 if !runnable.nav.full_range().contains_inclusive(offset) {
@@ -418,8 +430,12 @@ pub(crate) fn handle_runnables(
418 if should_skip_target(&runnable, cargo_spec.as_ref()) { 430 if should_skip_target(&runnable, cargo_spec.as_ref()) {
419 continue; 431 continue;
420 } 432 }
421 433 let mut runnable = to_proto::runnable(&snap, file_id, runnable)?;
422 res.push(to_proto::runnable(&snap, file_id, runnable)?); 434 if expect_test {
435 runnable.label = format!("{} + expect", runnable.label);
436 runnable.args.expect_test = Some(true);
437 }
438 res.push(runnable);
423 } 439 }
424 440
425 // Add `cargo check` and `cargo test` for the whole package 441 // Add `cargo check` and `cargo test` for the whole package
@@ -438,6 +454,7 @@ pub(crate) fn handle_runnables(
438 spec.package.clone(), 454 spec.package.clone(),
439 ], 455 ],
440 executable_args: Vec::new(), 456 executable_args: Vec::new(),
457 expect_test: None,
441 }, 458 },
442 }) 459 })
443 } 460 }
@@ -451,6 +468,7 @@ pub(crate) fn handle_runnables(
451 workspace_root: None, 468 workspace_root: None,
452 cargo_args: vec!["check".to_string(), "--workspace".to_string()], 469 cargo_args: vec!["check".to_string(), "--workspace".to_string()],
453 executable_args: Vec::new(), 470 executable_args: Vec::new(),
471 expect_test: None,
454 }, 472 },
455 }); 473 });
456 } 474 }
@@ -1027,7 +1045,7 @@ pub(crate) fn handle_call_hierarchy_incoming(
1027 let item = params.item; 1045 let item = params.item;
1028 1046
1029 let doc = TextDocumentIdentifier::new(item.uri); 1047 let doc = TextDocumentIdentifier::new(item.uri);
1030 let frange = from_proto::file_range(&snap, doc, item.range)?; 1048 let frange = from_proto::file_range(&snap, doc, item.selection_range)?;
1031 let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() }; 1049 let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() };
1032 1050
1033 let call_items = match snap.analysis.incoming_calls(fpos)? { 1051 let call_items = match snap.analysis.incoming_calls(fpos)? {
@@ -1062,7 +1080,7 @@ pub(crate) fn handle_call_hierarchy_outgoing(
1062 let item = params.item; 1080 let item = params.item;
1063 1081
1064 let doc = TextDocumentIdentifier::new(item.uri); 1082 let doc = TextDocumentIdentifier::new(item.uri);
1065 let frange = from_proto::file_range(&snap, doc, item.range)?; 1083 let frange = from_proto::file_range(&snap, doc, item.selection_range)?;
1066 let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() }; 1084 let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() };
1067 1085
1068 let call_items = match snap.analysis.outgoing_calls(fpos)? { 1086 let call_items = match snap.analysis.outgoing_calls(fpos)? {
@@ -1196,8 +1214,8 @@ fn show_impl_command_link(
1196 let position = to_proto::position(&line_index, position.offset); 1214 let position = to_proto::position(&line_index, position.offset);
1197 let locations: Vec<_> = nav_data 1215 let locations: Vec<_> = nav_data
1198 .info 1216 .info
1199 .iter() 1217 .into_iter()
1200 .filter_map(|it| to_proto::location(snap, it.file_range()).ok()) 1218 .filter_map(|nav| to_proto::location_from_nav(snap, nav).ok())
1201 .collect(); 1219 .collect();
1202 let title = implementation_title(locations.len()); 1220 let title = implementation_title(locations.len());
1203 let command = show_references_command(title, &uri, position, locations); 1221 let command = show_references_command(title, &uri, position, locations);
diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs
index 1371f6cb4..82207bbb8 100644
--- a/crates/rust-analyzer/src/lsp_ext.rs
+++ b/crates/rust-analyzer/src/lsp_ext.rs
@@ -14,12 +14,12 @@ impl Request for AnalyzerStatus {
14 const METHOD: &'static str = "rust-analyzer/analyzerStatus"; 14 const METHOD: &'static str = "rust-analyzer/analyzerStatus";
15} 15}
16 16
17pub enum CollectGarbage {} 17pub enum ReloadWorkspace {}
18 18
19impl Request for CollectGarbage { 19impl Request for ReloadWorkspace {
20 type Params = (); 20 type Params = ();
21 type Result = (); 21 type Result = ();
22 const METHOD: &'static str = "rust-analyzer/collectGarbage"; 22 const METHOD: &'static str = "rust-analyzer/reloadWorkspace";
23} 23}
24 24
25pub enum SyntaxTree {} 25pub enum SyntaxTree {}
@@ -161,6 +161,8 @@ pub struct CargoRunnable {
161 pub cargo_args: Vec<String>, 161 pub cargo_args: Vec<String>,
162 // stuff after -- 162 // stuff after --
163 pub executable_args: Vec<String>, 163 pub executable_args: Vec<String>,
164 #[serde(skip_serializing_if = "Option::is_none")]
165 pub expect_test: Option<bool>,
164} 166}
165 167
166pub enum InlayHints {} 168pub enum InlayHints {}
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 9fd16ef3b..e03038b25 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -136,7 +136,7 @@ impl GlobalState {
136 log::info!("queued count = {}", queue_count); 136 log::info!("queued count = {}", queue_count);
137 } 137 }
138 138
139 let mut became_ready = false; 139 let prev_status = self.status;
140 match event { 140 match event {
141 Event::Lsp(msg) => match msg { 141 Event::Lsp(msg) => match msg {
142 lsp_server::Message::Request(req) => self.on_request(loop_start, req)?, 142 lsp_server::Message::Request(req) => self.on_request(loop_start, req)?,
@@ -168,22 +168,26 @@ impl GlobalState {
168 } 168 }
169 } 169 }
170 vfs::loader::Message::Progress { n_total, n_done } => { 170 vfs::loader::Message::Progress { n_total, n_done } => {
171 let state = if n_done == 0 { 171 if n_total == 0 {
172 Progress::Begin
173 } else if n_done < n_total {
174 Progress::Report
175 } else {
176 assert_eq!(n_done, n_total);
177 self.status = Status::Ready; 172 self.status = Status::Ready;
178 became_ready = true; 173 } else {
179 Progress::End 174 let state = if n_done == 0 {
180 }; 175 self.status = Status::Loading;
181 self.report_progress( 176 Progress::Begin
182 "roots scanned", 177 } else if n_done < n_total {
183 state, 178 Progress::Report
184 Some(format!("{}/{}", n_done, n_total)), 179 } else {
185 Some(Progress::percentage(n_done, n_total)), 180 assert_eq!(n_done, n_total);
186 ) 181 self.status = Status::Ready;
182 Progress::End
183 };
184 self.report_progress(
185 "roots scanned",
186 state,
187 Some(format!("{}/{}", n_done, n_total)),
188 Some(Progress::percentage(n_done, n_total)),
189 )
190 }
187 } 191 }
188 }, 192 },
189 Event::Flycheck(task) => match task { 193 Event::Flycheck(task) => match task {
@@ -231,13 +235,13 @@ impl GlobalState {
231 } 235 }
232 236
233 let state_changed = self.process_changes(); 237 let state_changed = self.process_changes();
234 if became_ready { 238 if prev_status == Status::Loading && self.status == Status::Ready {
235 if let Some(flycheck) = &self.flycheck { 239 if let Some(flycheck) = &self.flycheck {
236 flycheck.handle.update(); 240 flycheck.handle.update();
237 } 241 }
238 } 242 }
239 243
240 if self.status == Status::Ready && (state_changed || became_ready) { 244 if self.status == Status::Ready && (state_changed || prev_status == Status::Loading) {
241 let subscriptions = self 245 let subscriptions = self
242 .mem_docs 246 .mem_docs
243 .iter() 247 .iter()
@@ -274,7 +278,7 @@ impl GlobalState {
274 self.register_request(&req, request_received); 278 self.register_request(&req, request_received);
275 279
276 RequestDispatcher { req: Some(req), global_state: self } 280 RequestDispatcher { req: Some(req), global_state: self }
277 .on_sync::<lsp_ext::CollectGarbage>(|s, ()| Ok(s.analysis_host.collect_garbage()))? 281 .on_sync::<lsp_ext::ReloadWorkspace>(|s, ()| Ok(s.reload()))?
278 .on_sync::<lsp_ext::JoinLines>(|s, p| handlers::handle_join_lines(s.snapshot(), p))? 282 .on_sync::<lsp_ext::JoinLines>(|s, p| handlers::handle_join_lines(s.snapshot(), p))?
279 .on_sync::<lsp_ext::OnEnter>(|s, p| handlers::handle_on_enter(s.snapshot(), p))? 283 .on_sync::<lsp_ext::OnEnter>(|s, p| handlers::handle_on_enter(s.snapshot(), p))?
280 .on_sync::<lsp_types::request::Shutdown>(|_, ()| Ok(()))? 284 .on_sync::<lsp_types::request::Shutdown>(|_, ()| Ok(()))?
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index ec71f8b29..0c1fd1b8b 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -19,11 +19,14 @@ impl GlobalState {
19 if self.config.lru_capacity != old_config.lru_capacity { 19 if self.config.lru_capacity != old_config.lru_capacity {
20 self.analysis_host.update_lru_capacity(old_config.lru_capacity); 20 self.analysis_host.update_lru_capacity(old_config.lru_capacity);
21 } 21 }
22 if self.config.flycheck != old_config.flycheck { 22 if self.config.linked_projects != old_config.linked_projects {
23 self.reload()
24 } else if self.config.flycheck != old_config.flycheck {
23 self.reload_flycheck(); 25 self.reload_flycheck();
24 } 26 }
25 } 27 }
26 pub(crate) fn reload(&mut self) { 28 pub(crate) fn reload(&mut self) {
29 log::info!("reloading projects: {:?}", self.config.linked_projects);
27 let workspaces = { 30 let workspaces = {
28 if self.config.linked_projects.is_empty() 31 if self.config.linked_projects.is_empty()
29 && self.config.notifications.cargo_toml_not_found 32 && self.config.notifications.cargo_toml_not_found
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index f6cb8e4bb..95dd8e408 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -352,7 +352,7 @@ pub(crate) fn folding_range(
352 let kind = match fold.kind { 352 let kind = match fold.kind {
353 FoldKind::Comment => Some(lsp_types::FoldingRangeKind::Comment), 353 FoldKind::Comment => Some(lsp_types::FoldingRangeKind::Comment),
354 FoldKind::Imports => Some(lsp_types::FoldingRangeKind::Imports), 354 FoldKind::Imports => Some(lsp_types::FoldingRangeKind::Imports),
355 FoldKind::Mods | FoldKind::Block => None, 355 FoldKind::Mods | FoldKind::Block | FoldKind::ArgList => None,
356 }; 356 };
357 357
358 let range = range(line_index, fold.range); 358 let range = range(line_index, fold.range);
@@ -446,6 +446,18 @@ pub(crate) fn location(
446 Ok(loc) 446 Ok(loc)
447} 447}
448 448
449/// Perefer using `location_link`, if the client has the cap.
450pub(crate) fn location_from_nav(
451 snap: &GlobalStateSnapshot,
452 nav: NavigationTarget,
453) -> Result<lsp_types::Location> {
454 let url = url(snap, nav.file_id());
455 let line_index = snap.analysis.file_line_index(nav.file_id())?;
456 let range = range(&line_index, nav.full_range());
457 let loc = lsp_types::Location::new(url, range);
458 Ok(loc)
459}
460
449pub(crate) fn location_link( 461pub(crate) fn location_link(
450 snap: &GlobalStateSnapshot, 462 snap: &GlobalStateSnapshot,
451 src: Option<FileRange>, 463 src: Option<FileRange>,
@@ -666,38 +678,34 @@ pub(crate) fn runnable(
666 workspace_root: workspace_root.map(|it| it.into()), 678 workspace_root: workspace_root.map(|it| it.into()),
667 cargo_args, 679 cargo_args,
668 executable_args, 680 executable_args,
681 expect_test: None,
669 }, 682 },
670 }) 683 })
671} 684}
672 685
673#[cfg(test)] 686#[cfg(test)]
674mod tests { 687mod tests {
675 use test_utils::extract_ranges; 688 use ra_ide::Analysis;
676 689
677 use super::*; 690 use super::*;
678 691
679 #[test] 692 #[test]
680 fn conv_fold_line_folding_only_fixup() { 693 fn conv_fold_line_folding_only_fixup() {
681 let text = r#"<fold>mod a; 694 let text = r#"mod a;
682mod b; 695mod b;
683mod c;</fold> 696mod c;
684 697
685fn main() <fold>{ 698fn main() {
686 if cond <fold>{ 699 if cond {
687 a::do_a(); 700 a::do_a();
688 }</fold> else <fold>{ 701 } else {
689 b::do_b(); 702 b::do_b();
690 }</fold> 703 }
691}</fold>"#; 704}"#;
692 705
693 let (ranges, text) = extract_ranges(text, "fold"); 706 let (analysis, file_id) = Analysis::from_single_file(text.to_string());
694 assert_eq!(ranges.len(), 4); 707 let folds = analysis.folding_ranges(file_id).unwrap();
695 let folds = vec![ 708 assert_eq!(folds.len(), 4);
696 Fold { range: ranges[0], kind: FoldKind::Mods },
697 Fold { range: ranges[1], kind: FoldKind::Block },
698 Fold { range: ranges[2], kind: FoldKind::Block },
699 Fold { range: ranges[3], kind: FoldKind::Block },
700 ];
701 709
702 let line_index = LineIndex::new(&text); 710 let line_index = LineIndex::new(&text);
703 let converted: Vec<lsp_types::FoldingRange> = 711 let converted: Vec<lsp_types::FoldingRange> =
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs
index caf847273..e4aa894ac 100644
--- a/crates/test_utils/src/lib.rs
+++ b/crates/test_utils/src/lib.rs
@@ -11,8 +11,9 @@ pub mod mark;
11mod fixture; 11mod fixture;
12 12
13use std::{ 13use std::{
14 convert::{TryFrom, TryInto},
14 env, fs, 15 env, fs,
15 path::{Path, PathBuf}, 16 path::PathBuf,
16}; 17};
17 18
18use serde_json::Value; 19use serde_json::Value;
@@ -117,8 +118,8 @@ pub fn extract_range_or_offset(text: &str) -> (RangeOrOffset, String) {
117} 118}
118 119
119/// Extracts ranges, marked with `<tag> </tag>` pairs from the `text` 120/// Extracts ranges, marked with `<tag> </tag>` pairs from the `text`
120pub fn extract_ranges(mut text: &str, tag: &str) -> (Vec<TextRange>, String) { 121pub fn extract_tags(mut text: &str, tag: &str) -> (Vec<(TextRange, Option<String>)>, String) {
121 let open = format!("<{}>", tag); 122 let open = format!("<{}", tag);
122 let close = format!("</{}>", tag); 123 let close = format!("</{}>", tag);
123 let mut ranges = Vec::new(); 124 let mut ranges = Vec::new();
124 let mut res = String::new(); 125 let mut res = String::new();
@@ -133,22 +134,35 @@ pub fn extract_ranges(mut text: &str, tag: &str) -> (Vec<TextRange>, String) {
133 res.push_str(&text[..i]); 134 res.push_str(&text[..i]);
134 text = &text[i..]; 135 text = &text[i..];
135 if text.starts_with(&open) { 136 if text.starts_with(&open) {
136 text = &text[open.len()..]; 137 let close_open = text.find('>').unwrap();
138 let attr = text[open.len()..close_open].trim();
139 let attr = if attr.is_empty() { None } else { Some(attr.to_string()) };
140 text = &text[close_open + '>'.len_utf8()..];
137 let from = TextSize::of(&res); 141 let from = TextSize::of(&res);
138 stack.push(from); 142 stack.push((from, attr));
139 } else if text.starts_with(&close) { 143 } else if text.starts_with(&close) {
140 text = &text[close.len()..]; 144 text = &text[close.len()..];
141 let from = stack.pop().unwrap_or_else(|| panic!("unmatched </{}>", tag)); 145 let (from, attr) =
146 stack.pop().unwrap_or_else(|| panic!("unmatched </{}>", tag));
142 let to = TextSize::of(&res); 147 let to = TextSize::of(&res);
143 ranges.push(TextRange::new(from, to)); 148 ranges.push((TextRange::new(from, to), attr));
149 } else {
150 res.push('<');
151 text = &text['<'.len_utf8()..];
144 } 152 }
145 } 153 }
146 } 154 }
147 } 155 }
148 assert!(stack.is_empty(), "unmatched <{}>", tag); 156 assert!(stack.is_empty(), "unmatched <{}>", tag);
149 ranges.sort_by_key(|r| (r.start(), r.end())); 157 ranges.sort_by_key(|r| (r.0.start(), r.0.end()));
150 (ranges, res) 158 (ranges, res)
151} 159}
160#[test]
161fn test_extract_tags() {
162 let (tags, text) = extract_tags(r#"<tag fn>fn <tag>main</tag>() {}</tag>"#, "tag");
163 let actual = tags.into_iter().map(|(range, attr)| (&text[range], attr)).collect::<Vec<_>>();
164 assert_eq!(actual, vec![("fn main() {}", Some("fn".into())), ("main", None),]);
165}
152 166
153/// Inserts `<|>` marker into the `text` at `offset`. 167/// Inserts `<|>` marker into the `text` at `offset`.
154pub fn add_cursor(text: &str, offset: TextSize) -> String { 168pub fn add_cursor(text: &str, offset: TextSize) -> String {
@@ -168,8 +182,9 @@ pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> {
168 for line in lines_with_ends(text) { 182 for line in lines_with_ends(text) {
169 if let Some(idx) = line.find("//^") { 183 if let Some(idx) = line.find("//^") {
170 let offset = prev_line_start.unwrap() + TextSize::of(&line[..idx + "//".len()]); 184 let offset = prev_line_start.unwrap() + TextSize::of(&line[..idx + "//".len()]);
171 let data = line[idx + "//^".len()..].trim().to_string(); 185 for (line_range, text) in extract_line_annotations(&line[idx + "//".len()..]) {
172 res.push((TextRange::at(offset, 1.into()), data)) 186 res.push((line_range + offset, text))
187 }
173 } 188 }
174 prev_line_start = Some(line_start); 189 prev_line_start = Some(line_start);
175 line_start += TextSize::of(line); 190 line_start += TextSize::of(line);
@@ -177,22 +192,37 @@ pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> {
177 res 192 res
178} 193}
179 194
195fn extract_line_annotations(mut line: &str) -> Vec<(TextRange, String)> {
196 let mut res = Vec::new();
197 let mut offset: TextSize = 0.into();
198 while !line.is_empty() {
199 let len = line.chars().take_while(|&it| it == '^').count();
200 assert!(len > 0);
201 let range = TextRange::at(offset, len.try_into().unwrap());
202 let next = line[len..].find('^').map_or(line.len(), |it| it + len);
203 res.push((range, line[len..][..next - len].trim().to_string()));
204 line = &line[next..];
205 offset += TextSize::try_from(next).unwrap();
206 }
207 res
208}
209
180#[test] 210#[test]
181fn test_extract_annotations() { 211fn test_extract_annotations() {
182 let text = stdx::trim_indent( 212 let text = stdx::trim_indent(
183 r#" 213 r#"
184fn main() { 214fn main() {
185 let x = 92; 215 let (x, y) = (9, 2);
186 //^ def 216 //^ def ^ def
187 z + 1 217 zoo + 1
188} //^ i32 218} //^^^ i32
189 "#, 219 "#,
190 ); 220 );
191 let res = extract_annotations(&text) 221 let res = extract_annotations(&text)
192 .into_iter() 222 .into_iter()
193 .map(|(range, ann)| (&text[range], ann)) 223 .map(|(range, ann)| (&text[range], ann))
194 .collect::<Vec<_>>(); 224 .collect::<Vec<_>>();
195 assert_eq!(res, vec![("x", "def".into()), ("z", "i32".into()),]); 225 assert_eq!(res, vec![("x", "def".into()), ("y", "def".into()), ("zoo", "i32".into()),]);
196} 226}
197 227
198// Comparison functionality borrowed from cargo: 228// Comparison functionality borrowed from cargo:
@@ -282,85 +312,6 @@ pub fn find_mismatch<'a>(expected: &'a Value, actual: &'a Value) -> Option<(&'a
282 } 312 }
283} 313}
284 314
285/// Calls callback `f` with input code and file paths for each `.rs` file in `test_data_dir`
286/// subdirectories defined by `paths`.
287///
288/// If the content of the matching output file differs from the output of `f()`
289/// the test will fail.
290///
291/// If there is no matching output file it will be created and filled with the
292/// output of `f()`, but the test will fail.
293pub fn dir_tests<F>(test_data_dir: &Path, paths: &[&str], outfile_extension: &str, f: F)
294where
295 F: Fn(&str, &Path) -> String,
296{
297 for (path, input_code) in collect_rust_files(test_data_dir, paths) {
298 let actual = f(&input_code, &path);
299 let path = path.with_extension(outfile_extension);
300 if !path.exists() {
301 println!("\nfile: {}", path.display());
302 println!("No .txt file with expected result, creating...\n");
303 println!("{}\n{}", input_code, actual);
304 fs::write(&path, &actual).unwrap();
305 panic!("No expected result");
306 }
307 let expected = read_text(&path);
308 assert_equal_text(&expected, &actual, &path);
309 }
310}
311
312/// Collects all `.rs` files from `dir` subdirectories defined by `paths`.
313pub fn collect_rust_files(root_dir: &Path, paths: &[&str]) -> Vec<(PathBuf, String)> {
314 paths
315 .iter()
316 .flat_map(|path| {
317 let path = root_dir.to_owned().join(path);
318 rust_files_in_dir(&path).into_iter()
319 })
320 .map(|path| {
321 let text = read_text(&path);
322 (path, text)
323 })
324 .collect()
325}
326
327/// Collects paths to all `.rs` files from `dir` in a sorted `Vec<PathBuf>`.
328fn rust_files_in_dir(dir: &Path) -> Vec<PathBuf> {
329 let mut acc = Vec::new();
330 for file in fs::read_dir(&dir).unwrap() {
331 let file = file.unwrap();
332 let path = file.path();
333 if path.extension().unwrap_or_default() == "rs" {
334 acc.push(path);
335 }
336 }
337 acc.sort();
338 acc
339}
340
341/// Returns the path to the root directory of `rust-analyzer` project.
342pub fn project_dir() -> PathBuf {
343 let dir = env!("CARGO_MANIFEST_DIR");
344 PathBuf::from(dir).parent().unwrap().parent().unwrap().to_owned()
345}
346
347/// Read file and normalize newlines.
348///
349/// `rustc` seems to always normalize `\r\n` newlines to `\n`:
350///
351/// ```
352/// let s = "
353/// ";
354/// assert_eq!(s.as_bytes(), &[10]);
355/// ```
356///
357/// so this should always be correct.
358pub fn read_text(path: &Path) -> String {
359 fs::read_to_string(path)
360 .unwrap_or_else(|_| panic!("File at {:?} should be valid", path))
361 .replace("\r\n", "\n")
362}
363
364/// Returns `false` if slow tests should not run, otherwise returns `true` and 315/// Returns `false` if slow tests should not run, otherwise returns `true` and
365/// also creates a file at `./target/.slow_tests_cookie` which serves as a flag 316/// also creates a file at `./target/.slow_tests_cookie` which serves as a flag
366/// that slow tests did run. 317/// that slow tests did run.
@@ -375,25 +326,8 @@ pub fn skip_slow_tests() -> bool {
375 should_skip 326 should_skip
376} 327}
377 328
378/// Asserts that `expected` and `actual` strings are equal. If they differ only 329/// Returns the path to the root directory of `rust-analyzer` project.
379/// in trailing or leading whitespace the test won't fail and 330pub fn project_dir() -> PathBuf {
380/// the contents of `actual` will be written to the file located at `path`. 331 let dir = env!("CARGO_MANIFEST_DIR");
381fn assert_equal_text(expected: &str, actual: &str, path: &Path) { 332 PathBuf::from(dir).parent().unwrap().parent().unwrap().to_owned()
382 if expected == actual {
383 return;
384 }
385 let dir = project_dir();
386 let pretty_path = path.strip_prefix(&dir).unwrap_or_else(|_| path);
387 if expected.trim() == actual.trim() {
388 println!("whitespace difference, rewriting");
389 println!("file: {}\n", pretty_path.display());
390 fs::write(path, actual).unwrap();
391 return;
392 }
393 if env::var("UPDATE_EXPECTATIONS").is_ok() {
394 println!("rewriting {}", pretty_path.display());
395 fs::write(path, actual).unwrap();
396 return;
397 }
398 assert_eq_text!(expected, actual, "file: {}", pretty_path.display());
399} 333}
diff --git a/crates/vfs/src/file_set.rs b/crates/vfs/src/file_set.rs
index d0ddeafe7..977ba3010 100644
--- a/crates/vfs/src/file_set.rs
+++ b/crates/vfs/src/file_set.rs
@@ -69,7 +69,7 @@ impl FileSetConfig {
69 Ok(it) => it, 69 Ok(it) => it,
70 Err(it) => it.saturating_sub(1), 70 Err(it) => it.saturating_sub(1),
71 }; 71 };
72 if path.starts_with(&self.roots[idx].0) { 72 if !self.roots.is_empty() && path.starts_with(&self.roots[idx].0) {
73 self.roots[idx].1 73 self.roots[idx].1
74 } else { 74 } else {
75 self.len() - 1 75 self.len() - 1
diff --git a/docs/dev/README.md b/docs/dev/README.md
index 6b6824ded..f87462400 100644
--- a/docs/dev/README.md
+++ b/docs/dev/README.md
@@ -177,6 +177,9 @@ There are many benefits to this:
177* less stuff printed during printf-debugging 177* less stuff printed during printf-debugging
178* less time to run test 178* less time to run test
179 179
180It also makes sense to format snippets more compactly (for example, by placing enum defitions like `enum E { Foo, Bar }` on a single line),
181as long as they are still readable.
182
180## Order of Imports 183## Order of Imports
181 184
182We separate import groups with blank lines 185We separate import groups with blank lines
@@ -358,10 +361,10 @@ There are two kinds of tests:
358The purpose of inline tests is not to achieve full coverage by test cases, but to explain to the reader of the code what each particular `if` and `match` is responsible for. 361The purpose of inline tests is not to achieve full coverage by test cases, but to explain to the reader of the code what each particular `if` and `match` is responsible for.
359If you are tempted to add a large inline test, it might be a good idea to leave only the simplest example in place, and move the test to a manual `parser/ok` test. 362If you are tempted to add a large inline test, it might be a good idea to leave only the simplest example in place, and move the test to a manual `parser/ok` test.
360 363
361To update test data, run with `UPDATE_EXPECTATIONS` variable: 364To update test data, run with `UPDATE_EXPECT` variable:
362 365
363```bash 366```bash
364env UPDATE_EXPECTATIONS=1 cargo qt 367env UPDATE_EXPECT=1 cargo qt
365``` 368```
366 369
367After adding a new inline test you need to run `cargo xtest codegen` and also update the test data as described above. 370After adding a new inline test you need to run `cargo xtest codegen` and also update the test data as described above.
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md
index a0847dad3..c0afb16d3 100644
--- a/docs/dev/lsp-extensions.md
+++ b/docs/dev/lsp-extensions.md
@@ -389,15 +389,15 @@ rust-analyzer supports only one `kind`, `"cargo"`. The `args` for `"cargo"` look
389 389
390Returns internal status message, mostly for debugging purposes. 390Returns internal status message, mostly for debugging purposes.
391 391
392## Collect Garbage 392## Reload Workspace
393 393
394**Method:** `rust-analyzer/collectGarbage` 394**Method:** `rust-analyzer/reloadWorkspace`
395 395
396**Request:** `null` 396**Request:** `null`
397 397
398**Response:** `null` 398**Response:** `null`
399 399
400Frees some caches. For internal use, and is mostly broken at the moment. 400Reloads project information (that is, re-executes `cargo metadata`).
401 401
402## Syntax Tree 402## Syntax Tree
403 403
@@ -504,4 +504,4 @@ Such actions on the client side are appended to a hover bottom as command links:
504 | TITLE _Action1_ | _Action2_ | <- second group 504 | TITLE _Action1_ | _Action2_ | <- second group
505 +-----------------------------+ 505 +-----------------------------+
506 ... 506 ...
507``` \ No newline at end of file 507```
diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json
index 3b4a31682..4f94c2dc5 100644
--- a/editors/code/package-lock.json
+++ b/editors/code/package-lock.json
@@ -5,35 +5,35 @@
5 "requires": true, 5 "requires": true,
6 "dependencies": { 6 "dependencies": {
7 "@babel/code-frame": { 7 "@babel/code-frame": {
8 "version": "7.8.3", 8 "version": "7.10.3",
9 "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", 9 "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.3.tgz",
10 "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", 10 "integrity": "sha512-fDx9eNW0qz0WkUeqL6tXEXzVlPh6Y5aCDEZesl0xBGA8ndRukX91Uk44ZqnkECp01NAZUdCAl+aiQNGi0k88Eg==",
11 "dev": true, 11 "dev": true,
12 "requires": { 12 "requires": {
13 "@babel/highlight": "^7.8.3" 13 "@babel/highlight": "^7.10.3"
14 } 14 }
15 }, 15 },
16 "@babel/helper-validator-identifier": { 16 "@babel/helper-validator-identifier": {
17 "version": "7.9.5", 17 "version": "7.10.3",
18 "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz", 18 "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.3.tgz",
19 "integrity": "sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==", 19 "integrity": "sha512-bU8JvtlYpJSBPuj1VUmKpFGaDZuLxASky3LhaKj3bmpSTY6VWooSM8msk+Z0CZoErFye2tlABF6yDkT3FOPAXw==",
20 "dev": true 20 "dev": true
21 }, 21 },
22 "@babel/highlight": { 22 "@babel/highlight": {
23 "version": "7.9.0", 23 "version": "7.10.3",
24 "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", 24 "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.3.tgz",
25 "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", 25 "integrity": "sha512-Ih9B/u7AtgEnySE2L2F0Xm0GaM729XqqLfHkalTsbjXGyqmf/6M0Cu0WpvqueUlW+xk88BHw9Nkpj49naU+vWw==",
26 "dev": true, 26 "dev": true,
27 "requires": { 27 "requires": {
28 "@babel/helper-validator-identifier": "^7.9.0", 28 "@babel/helper-validator-identifier": "^7.10.3",
29 "chalk": "^2.0.0", 29 "chalk": "^2.0.0",
30 "js-tokens": "^4.0.0" 30 "js-tokens": "^4.0.0"
31 } 31 }
32 }, 32 },
33 "@rollup/plugin-commonjs": { 33 "@rollup/plugin-commonjs": {
34 "version": "12.0.0", 34 "version": "13.0.0",
35 "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-12.0.0.tgz", 35 "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-13.0.0.tgz",
36 "integrity": "sha512-8+mDQt1QUmN+4Y9D3yCG8AJNewuTSLYPJVzKKUZ+lGeQrI+bV12Tc5HCyt2WdlnG6ihIL/DPbKRJlB40DX40mw==", 36 "integrity": "sha512-Anxc3qgkAi7peAyesTqGYidG5GRim9jtg8xhmykNaZkImtvjA7Wsqep08D2mYsqw1IF7rA3lYfciLgzUSgRoqw==",
37 "dev": true, 37 "dev": true,
38 "requires": { 38 "requires": {
39 "@rollup/pluginutils": "^3.0.8", 39 "@rollup/pluginutils": "^3.0.8",
@@ -46,9 +46,9 @@
46 } 46 }
47 }, 47 },
48 "@rollup/plugin-node-resolve": { 48 "@rollup/plugin-node-resolve": {
49 "version": "8.0.0", 49 "version": "8.1.0",
50 "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-8.0.0.tgz", 50 "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-8.1.0.tgz",
51 "integrity": "sha512-5poJCChrkVggXXND/sQ7yNqwjUNT4fP31gpRWCnSNnlXuUXTCMHT33xZrTGxgjm5Rl18MHj7iEzlCT8rYWwQSA==", 51 "integrity": "sha512-ovq7ZM3JJYUUmEjjO+H8tnUdmQmdQudJB7xruX8LFZ1W2q8jXdPUS6SsIYip8ByOApu4RR7729Am9WhCeCMiHA==",
52 "dev": true, 52 "dev": true,
53 "requires": { 53 "requires": {
54 "@rollup/pluginutils": "^3.0.8", 54 "@rollup/pluginutils": "^3.0.8",
@@ -89,19 +89,12 @@
89 "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", 89 "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
90 "dev": true 90 "dev": true
91 }, 91 },
92 "@types/events": {
93 "version": "3.0.0",
94 "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz",
95 "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==",
96 "dev": true
97 },
98 "@types/glob": { 92 "@types/glob": {
99 "version": "7.1.1", 93 "version": "7.1.2",
100 "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", 94 "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.2.tgz",
101 "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", 95 "integrity": "sha512-VgNIkxK+j7Nz5P7jvUZlRvhuPSmsEfS03b0alKcq5V/STUKAa3Plemsn5mrQUO7am6OErJ4rhGEGJbACclrtRA==",
102 "dev": true, 96 "dev": true,
103 "requires": { 97 "requires": {
104 "@types/events": "*",
105 "@types/minimatch": "*", 98 "@types/minimatch": "*",
106 "@types/node": "*" 99 "@types/node": "*"
107 } 100 }
@@ -125,9 +118,9 @@
125 "dev": true 118 "dev": true
126 }, 119 },
127 "@types/node": { 120 "@types/node": {
128 "version": "14.0.5", 121 "version": "12.7.12",
129 "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.5.tgz", 122 "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.12.tgz",
130 "integrity": "sha512-90hiq6/VqtQgX8Sp0EzeIsv3r+ellbGj4URKj5j30tLlZvRUpnAe9YbYnjl3pJM93GyXU0tghHhvXHq+5rnCKA==", 123 "integrity": "sha512-KPYGmfD0/b1eXurQ59fXD1GBzhSQfz6/lKBxkaHX9dKTzjXbK68Zt7yGUxUsCS1jeTy/8aL+d9JEr+S54mpkWQ==",
131 "dev": true 124 "dev": true
132 }, 125 },
133 "@types/node-fetch": { 126 "@types/node-fetch": {
@@ -156,18 +149,46 @@
156 "dev": true 149 "dev": true
157 }, 150 },
158 "@typescript-eslint/eslint-plugin": { 151 "@typescript-eslint/eslint-plugin": {
159 "version": "3.0.0", 152 "version": "3.4.0",
160 "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.0.0.tgz", 153 "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.4.0.tgz",
161 "integrity": "sha512-lcZ0M6jD4cqGccYOERKdMtg+VWpoq3NSnWVxpc/AwAy0zhkUYVioOUZmfNqiNH8/eBNGhCn6HXd6mKIGRgNc1Q==", 154 "integrity": "sha512-wfkpiqaEVhZIuQRmudDszc01jC/YR7gMSxa6ulhggAe/Hs0KVIuo9wzvFiDbG3JD5pRFQoqnf4m7REDsUvBnMQ==",
162 "dev": true, 155 "dev": true,
163 "requires": { 156 "requires": {
164 "@typescript-eslint/experimental-utils": "3.0.0", 157 "@typescript-eslint/experimental-utils": "3.4.0",
158 "debug": "^4.1.1",
165 "functional-red-black-tree": "^1.0.1", 159 "functional-red-black-tree": "^1.0.1",
166 "regexpp": "^3.0.0", 160 "regexpp": "^3.0.0",
167 "semver": "^7.3.2", 161 "semver": "^7.3.2",
168 "tsutils": "^3.17.1" 162 "tsutils": "^3.17.1"
169 }, 163 },
170 "dependencies": { 164 "dependencies": {
165 "@typescript-eslint/experimental-utils": {
166 "version": "3.4.0",
167 "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-3.4.0.tgz",
168 "integrity": "sha512-rHPOjL43lOH1Opte4+dhC0a/+ks+8gOBwxXnyrZ/K4OTAChpSjP76fbI8Cglj7V5GouwVAGaK+xVwzqTyE/TPw==",
169 "dev": true,
170 "requires": {
171 "@types/json-schema": "^7.0.3",
172 "@typescript-eslint/typescript-estree": "3.4.0",
173 "eslint-scope": "^5.0.0",
174 "eslint-utils": "^2.0.0"
175 }
176 },
177 "@typescript-eslint/typescript-estree": {
178 "version": "3.4.0",
179 "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-3.4.0.tgz",
180 "integrity": "sha512-zKwLiybtt4uJb4mkG5q2t6+W7BuYx2IISiDNV+IY68VfoGwErDx/RfVI7SWL4gnZ2t1A1ytQQwZ+YOJbHHJ2rw==",
181 "dev": true,
182 "requires": {
183 "debug": "^4.1.1",
184 "eslint-visitor-keys": "^1.1.0",
185 "glob": "^7.1.6",
186 "is-glob": "^4.0.1",
187 "lodash": "^4.17.15",
188 "semver": "^7.3.2",
189 "tsutils": "^3.17.1"
190 }
191 },
171 "semver": { 192 "semver": {
172 "version": "7.3.2", 193 "version": "7.3.2",
173 "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", 194 "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
@@ -177,33 +198,33 @@
177 } 198 }
178 }, 199 },
179 "@typescript-eslint/experimental-utils": { 200 "@typescript-eslint/experimental-utils": {
180 "version": "3.0.0", 201 "version": "3.4.0",
181 "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-3.0.0.tgz", 202 "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-3.4.0.tgz",
182 "integrity": "sha512-BN0vmr9N79M9s2ctITtChRuP1+Dls0x/wlg0RXW1yQ7WJKPurg6X3Xirv61J2sjPif4F8SLsFMs5Nzte0WYoTQ==", 203 "integrity": "sha512-rHPOjL43lOH1Opte4+dhC0a/+ks+8gOBwxXnyrZ/K4OTAChpSjP76fbI8Cglj7V5GouwVAGaK+xVwzqTyE/TPw==",
183 "dev": true, 204 "dev": true,
184 "requires": { 205 "requires": {
185 "@types/json-schema": "^7.0.3", 206 "@types/json-schema": "^7.0.3",
186 "@typescript-eslint/typescript-estree": "3.0.0", 207 "@typescript-eslint/typescript-estree": "3.4.0",
187 "eslint-scope": "^5.0.0", 208 "eslint-scope": "^5.0.0",
188 "eslint-utils": "^2.0.0" 209 "eslint-utils": "^2.0.0"
189 } 210 }
190 }, 211 },
191 "@typescript-eslint/parser": { 212 "@typescript-eslint/parser": {
192 "version": "3.0.0", 213 "version": "3.4.0",
193 "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-3.0.0.tgz", 214 "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-3.4.0.tgz",
194 "integrity": "sha512-8RRCA9KLxoFNO0mQlrLZA0reGPd/MsobxZS/yPFj+0/XgMdS8+mO8mF3BDj2ZYQj03rkayhSJtF1HAohQ3iylw==", 215 "integrity": "sha512-ZUGI/de44L5x87uX5zM14UYcbn79HSXUR+kzcqU42gH0AgpdB/TjuJy3m4ezI7Q/jk3wTQd755mxSDLhQP79KA==",
195 "dev": true, 216 "dev": true,
196 "requires": { 217 "requires": {
197 "@types/eslint-visitor-keys": "^1.0.0", 218 "@types/eslint-visitor-keys": "^1.0.0",
198 "@typescript-eslint/experimental-utils": "3.0.0", 219 "@typescript-eslint/experimental-utils": "3.4.0",
199 "@typescript-eslint/typescript-estree": "3.0.0", 220 "@typescript-eslint/typescript-estree": "3.4.0",
200 "eslint-visitor-keys": "^1.1.0" 221 "eslint-visitor-keys": "^1.1.0"
201 } 222 }
202 }, 223 },
203 "@typescript-eslint/typescript-estree": { 224 "@typescript-eslint/typescript-estree": {
204 "version": "3.0.0", 225 "version": "3.4.0",
205 "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-3.0.0.tgz", 226 "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-3.4.0.tgz",
206 "integrity": "sha512-nevQvHyNghsfLrrByzVIH4ZG3NROgJ8LZlfh3ddwPPH4CH7W4GAiSx5qu+xHuX5pWsq6q/eqMc1io840ZhAnUg==", 227 "integrity": "sha512-zKwLiybtt4uJb4mkG5q2t6+W7BuYx2IISiDNV+IY68VfoGwErDx/RfVI7SWL4gnZ2t1A1ytQQwZ+YOJbHHJ2rw==",
207 "dev": true, 228 "dev": true,
208 "requires": { 229 "requires": {
209 "debug": "^4.1.1", 230 "debug": "^4.1.1",
@@ -224,9 +245,9 @@
224 } 245 }
225 }, 246 },
226 "acorn": { 247 "acorn": {
227 "version": "7.2.0", 248 "version": "7.3.1",
228 "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.2.0.tgz", 249 "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.3.1.tgz",
229 "integrity": "sha512-apwXVmYVpQ34m/i71vrApRrRKCWQnZZF1+npOD0WV5xZFfwWOmKGQ2RWlfdy9vWITsenisM8M0Qeq8agcFHNiQ==", 250 "integrity": "sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA==",
230 "dev": true 251 "dev": true
231 }, 252 },
232 "acorn-jsx": { 253 "acorn-jsx": {
@@ -262,23 +283,6 @@
262 "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", 283 "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==",
263 "dev": true 284 "dev": true
264 }, 285 },
265 "ansi-escapes": {
266 "version": "4.3.1",
267 "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz",
268 "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==",
269 "dev": true,
270 "requires": {
271 "type-fest": "^0.11.0"
272 },
273 "dependencies": {
274 "type-fest": {
275 "version": "0.11.0",
276 "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz",
277 "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==",
278 "dev": true
279 }
280 }
281 },
282 "ansi-regex": { 286 "ansi-regex": {
283 "version": "5.0.0", 287 "version": "5.0.0",
284 "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", 288 "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
@@ -313,6 +317,18 @@
313 "sprintf-js": "~1.0.2" 317 "sprintf-js": "~1.0.2"
314 } 318 }
315 }, 319 },
320 "array.prototype.map": {
321 "version": "1.0.2",
322 "resolved": "https://registry.npmjs.org/array.prototype.map/-/array.prototype.map-1.0.2.tgz",
323 "integrity": "sha512-Az3OYxgsa1g7xDYp86l0nnN4bcmuEITGe1rbdEBVkrqkzMgDcbdQ2R7r41pNzti+4NMces3H8gMmuioZUilLgw==",
324 "dev": true,
325 "requires": {
326 "define-properties": "^1.1.3",
327 "es-abstract": "^1.17.0-next.1",
328 "es-array-method-boxes-properly": "^1.0.0",
329 "is-string": "^1.0.4"
330 }
331 },
316 "astral-regex": { 332 "astral-regex": {
317 "version": "1.0.0", 333 "version": "1.0.0",
318 "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", 334 "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
@@ -344,9 +360,9 @@
344 "dev": true 360 "dev": true
345 }, 361 },
346 "binary-extensions": { 362 "binary-extensions": {
347 "version": "2.0.0", 363 "version": "2.1.0",
348 "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", 364 "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz",
349 "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", 365 "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==",
350 "dev": true 366 "dev": true
351 }, 367 },
352 "boolbase": { 368 "boolbase": {
@@ -415,12 +431,6 @@
415 "supports-color": "^5.3.0" 431 "supports-color": "^5.3.0"
416 } 432 }
417 }, 433 },
418 "chardet": {
419 "version": "0.7.0",
420 "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
421 "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
422 "dev": true
423 },
424 "cheerio": { 434 "cheerio": {
425 "version": "1.0.0-rc.3", 435 "version": "1.0.0-rc.3",
426 "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.3.tgz", 436 "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.3.tgz",
@@ -436,36 +446,21 @@
436 } 446 }
437 }, 447 },
438 "chokidar": { 448 "chokidar": {
439 "version": "3.3.0", 449 "version": "3.3.1",
440 "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", 450 "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.1.tgz",
441 "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", 451 "integrity": "sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg==",
442 "dev": true, 452 "dev": true,
443 "requires": { 453 "requires": {
444 "anymatch": "~3.1.1", 454 "anymatch": "~3.1.1",
445 "braces": "~3.0.2", 455 "braces": "~3.0.2",
446 "fsevents": "~2.1.1", 456 "fsevents": "~2.1.2",
447 "glob-parent": "~5.1.0", 457 "glob-parent": "~5.1.0",
448 "is-binary-path": "~2.1.0", 458 "is-binary-path": "~2.1.0",
449 "is-glob": "~4.0.1", 459 "is-glob": "~4.0.1",
450 "normalize-path": "~3.0.0", 460 "normalize-path": "~3.0.0",
451 "readdirp": "~3.2.0" 461 "readdirp": "~3.3.0"
452 } 462 }
453 }, 463 },
454 "cli-cursor": {
455 "version": "3.1.0",
456 "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
457 "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
458 "dev": true,
459 "requires": {
460 "restore-cursor": "^3.1.0"
461 }
462 },
463 "cli-width": {
464 "version": "2.2.1",
465 "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz",
466 "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==",
467 "dev": true
468 },
469 "cliui": { 464 "cliui": {
470 "version": "5.0.0", 465 "version": "5.0.0",
471 "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", 466 "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
@@ -483,29 +478,6 @@
483 "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", 478 "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
484 "dev": true 479 "dev": true
485 }, 480 },
486 "emoji-regex": {
487 "version": "7.0.3",
488 "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
489 "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
490 "dev": true
491 },
492 "is-fullwidth-code-point": {
493 "version": "2.0.0",
494 "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
495 "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
496 "dev": true
497 },
498 "string-width": {
499 "version": "3.1.0",
500 "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
501 "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
502 "dev": true,
503 "requires": {
504 "emoji-regex": "^7.0.1",
505 "is-fullwidth-code-point": "^2.0.0",
506 "strip-ansi": "^5.1.0"
507 }
508 },
509 "strip-ansi": { 481 "strip-ansi": {
510 "version": "5.2.0", 482 "version": "5.2.0",
511 "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", 483 "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
@@ -566,9 +538,9 @@
566 "dev": true 538 "dev": true
567 }, 539 },
568 "cross-spawn": { 540 "cross-spawn": {
569 "version": "7.0.2", 541 "version": "7.0.3",
570 "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.2.tgz", 542 "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
571 "integrity": "sha512-PD6G8QG3S4FK/XCGFbEQrDqO2AnMMsy0meR7lerlIOHAAbkuavGU/pOqprrlvfTNjvowivTeBsjebAL0NSoMxw==", 543 "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
572 "dev": true, 544 "dev": true,
573 "requires": { 545 "requires": {
574 "path-key": "^3.1.0", 546 "path-key": "^3.1.0",
@@ -649,9 +621,9 @@
649 "dev": true 621 "dev": true
650 }, 622 },
651 "diff": { 623 "diff": {
652 "version": "3.5.0", 624 "version": "4.0.2",
653 "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", 625 "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
654 "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", 626 "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
655 "dev": true 627 "dev": true
656 }, 628 },
657 "doctrine": { 629 "doctrine": {
@@ -719,11 +691,20 @@
719 } 691 }
720 }, 692 },
721 "emoji-regex": { 693 "emoji-regex": {
722 "version": "8.0.0", 694 "version": "7.0.3",
723 "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 695 "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
724 "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 696 "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
725 "dev": true 697 "dev": true
726 }, 698 },
699 "enquirer": {
700 "version": "2.3.5",
701 "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.5.tgz",
702 "integrity": "sha512-BNT1C08P9XD0vNg3J475yIUG+mVdp9T6towYFHUv897X0KoHBjB1shyrNmhmtHWKP17iSWgo7Gqh7BBuzLZMSA==",
703 "dev": true,
704 "requires": {
705 "ansi-colors": "^3.2.1"
706 }
707 },
727 "entities": { 708 "entities": {
728 "version": "1.1.2", 709 "version": "1.1.2",
729 "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", 710 "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
@@ -731,22 +712,43 @@
731 "dev": true 712 "dev": true
732 }, 713 },
733 "es-abstract": { 714 "es-abstract": {
734 "version": "1.17.5", 715 "version": "1.17.6",
735 "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", 716 "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz",
736 "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", 717 "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==",
737 "dev": true, 718 "dev": true,
738 "requires": { 719 "requires": {
739 "es-to-primitive": "^1.2.1", 720 "es-to-primitive": "^1.2.1",
740 "function-bind": "^1.1.1", 721 "function-bind": "^1.1.1",
741 "has": "^1.0.3", 722 "has": "^1.0.3",
742 "has-symbols": "^1.0.1", 723 "has-symbols": "^1.0.1",
743 "is-callable": "^1.1.5", 724 "is-callable": "^1.2.0",
744 "is-regex": "^1.0.5", 725 "is-regex": "^1.1.0",
745 "object-inspect": "^1.7.0", 726 "object-inspect": "^1.7.0",
746 "object-keys": "^1.1.1", 727 "object-keys": "^1.1.1",
747 "object.assign": "^4.1.0", 728 "object.assign": "^4.1.0",
748 "string.prototype.trimleft": "^2.1.1", 729 "string.prototype.trimend": "^1.0.1",
749 "string.prototype.trimright": "^2.1.1" 730 "string.prototype.trimstart": "^1.0.1"
731 }
732 },
733 "es-array-method-boxes-properly": {
734 "version": "1.0.0",
735 "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz",
736 "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==",
737 "dev": true
738 },
739 "es-get-iterator": {
740 "version": "1.1.0",
741 "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.0.tgz",
742 "integrity": "sha512-UfrmHuWQlNMTs35e1ypnvikg6jCz3SK8v8ImvmDsh36fCVUR1MqoFDiyn0/k52C8NqO3YsO8Oe0azeesNuqSsQ==",
743 "dev": true,
744 "requires": {
745 "es-abstract": "^1.17.4",
746 "has-symbols": "^1.0.1",
747 "is-arguments": "^1.0.4",
748 "is-map": "^2.0.1",
749 "is-set": "^2.0.1",
750 "is-string": "^1.0.5",
751 "isarray": "^2.0.5"
750 } 752 }
751 }, 753 },
752 "es-to-primitive": { 754 "es-to-primitive": {
@@ -782,9 +784,9 @@
782 "dev": true 784 "dev": true
783 }, 785 },
784 "eslint": { 786 "eslint": {
785 "version": "7.1.0", 787 "version": "7.3.1",
786 "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.1.0.tgz", 788 "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.3.1.tgz",
787 "integrity": "sha512-DfS3b8iHMK5z/YLSme8K5cge168I8j8o1uiVmFCgnnjxZQbCGyraF8bMl7Ju4yfBmCuxD7shOF7eqGkcuIHfsA==", 789 "integrity": "sha512-cQC/xj9bhWUcyi/RuMbRtC3I0eW8MH0jhRELSvpKYkWep3C6YZ2OkvcvJVUeO6gcunABmzptbXBuDoXsjHmfTA==",
788 "dev": true, 790 "dev": true,
789 "requires": { 791 "requires": {
790 "@babel/code-frame": "^7.0.0", 792 "@babel/code-frame": "^7.0.0",
@@ -793,10 +795,11 @@
793 "cross-spawn": "^7.0.2", 795 "cross-spawn": "^7.0.2",
794 "debug": "^4.0.1", 796 "debug": "^4.0.1",
795 "doctrine": "^3.0.0", 797 "doctrine": "^3.0.0",
796 "eslint-scope": "^5.0.0", 798 "enquirer": "^2.3.5",
799 "eslint-scope": "^5.1.0",
797 "eslint-utils": "^2.0.0", 800 "eslint-utils": "^2.0.0",
798 "eslint-visitor-keys": "^1.1.0", 801 "eslint-visitor-keys": "^1.2.0",
799 "espree": "^7.0.0", 802 "espree": "^7.1.0",
800 "esquery": "^1.2.0", 803 "esquery": "^1.2.0",
801 "esutils": "^2.0.2", 804 "esutils": "^2.0.2",
802 "file-entry-cache": "^5.0.1", 805 "file-entry-cache": "^5.0.1",
@@ -806,7 +809,6 @@
806 "ignore": "^4.0.6", 809 "ignore": "^4.0.6",
807 "import-fresh": "^3.0.0", 810 "import-fresh": "^3.0.0",
808 "imurmurhash": "^0.1.4", 811 "imurmurhash": "^0.1.4",
809 "inquirer": "^7.0.0",
810 "is-glob": "^4.0.0", 812 "is-glob": "^4.0.0",
811 "js-yaml": "^3.13.1", 813 "js-yaml": "^3.13.1",
812 "json-stable-stringify-without-jsonify": "^1.0.1", 814 "json-stable-stringify-without-jsonify": "^1.0.1",
@@ -836,9 +838,9 @@
836 } 838 }
837 }, 839 },
838 "chalk": { 840 "chalk": {
839 "version": "4.0.0", 841 "version": "4.1.0",
840 "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz", 842 "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
841 "integrity": "sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A==", 843 "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
842 "dev": true, 844 "dev": true,
843 "requires": { 845 "requires": {
844 "ansi-styles": "^4.1.0", 846 "ansi-styles": "^4.1.0",
@@ -860,6 +862,22 @@
860 "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 862 "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
861 "dev": true 863 "dev": true
862 }, 864 },
865 "eslint-scope": {
866 "version": "5.1.0",
867 "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.0.tgz",
868 "integrity": "sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==",
869 "dev": true,
870 "requires": {
871 "esrecurse": "^4.1.0",
872 "estraverse": "^4.1.1"
873 }
874 },
875 "eslint-visitor-keys": {
876 "version": "1.3.0",
877 "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
878 "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
879 "dev": true
880 },
863 "has-flag": { 881 "has-flag": {
864 "version": "4.0.0", 882 "version": "4.0.0",
865 "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 883 "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@@ -909,14 +927,22 @@
909 "dev": true 927 "dev": true
910 }, 928 },
911 "espree": { 929 "espree": {
912 "version": "7.0.0", 930 "version": "7.1.0",
913 "resolved": "https://registry.npmjs.org/espree/-/espree-7.0.0.tgz", 931 "resolved": "https://registry.npmjs.org/espree/-/espree-7.1.0.tgz",
914 "integrity": "sha512-/r2XEx5Mw4pgKdyb7GNLQNsu++asx/dltf/CI8RFi9oGHxmQFgvLbc5Op4U6i8Oaj+kdslhJtVlEZeAqH5qOTw==", 932 "integrity": "sha512-dcorZSyfmm4WTuTnE5Y7MEN1DyoPYy1ZR783QW1FJoenn7RailyWFsq/UL6ZAAA7uXurN9FIpYyUs3OfiIW+Qw==",
915 "dev": true, 933 "dev": true,
916 "requires": { 934 "requires": {
917 "acorn": "^7.1.1", 935 "acorn": "^7.2.0",
918 "acorn-jsx": "^5.2.0", 936 "acorn-jsx": "^5.2.0",
919 "eslint-visitor-keys": "^1.1.0" 937 "eslint-visitor-keys": "^1.2.0"
938 },
939 "dependencies": {
940 "eslint-visitor-keys": {
941 "version": "1.3.0",
942 "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
943 "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
944 "dev": true
945 }
920 } 946 }
921 }, 947 },
922 "esprima": { 948 "esprima": {
@@ -969,21 +995,10 @@
969 "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", 995 "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
970 "dev": true 996 "dev": true
971 }, 997 },
972 "external-editor": {
973 "version": "3.1.0",
974 "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
975 "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
976 "dev": true,
977 "requires": {
978 "chardet": "^0.7.0",
979 "iconv-lite": "^0.4.24",
980 "tmp": "^0.0.33"
981 }
982 },
983 "fast-deep-equal": { 998 "fast-deep-equal": {
984 "version": "3.1.1", 999 "version": "3.1.3",
985 "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", 1000 "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
986 "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==", 1001 "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
987 "dev": true 1002 "dev": true
988 }, 1003 },
989 "fast-json-stable-stringify": { 1004 "fast-json-stable-stringify": {
@@ -1007,15 +1022,6 @@
1007 "pend": "~1.2.0" 1022 "pend": "~1.2.0"
1008 } 1023 }
1009 }, 1024 },
1010 "figures": {
1011 "version": "3.2.0",
1012 "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
1013 "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
1014 "dev": true,
1015 "requires": {
1016 "escape-string-regexp": "^1.0.5"
1017 }
1018 },
1019 "file-entry-cache": { 1025 "file-entry-cache": {
1020 "version": "5.0.1", 1026 "version": "5.0.1",
1021 "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", 1027 "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz",
@@ -1035,12 +1041,13 @@
1035 } 1041 }
1036 }, 1042 },
1037 "find-up": { 1043 "find-up": {
1038 "version": "3.0.0", 1044 "version": "4.1.0",
1039 "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", 1045 "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
1040 "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", 1046 "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
1041 "dev": true, 1047 "dev": true,
1042 "requires": { 1048 "requires": {
1043 "locate-path": "^3.0.0" 1049 "locate-path": "^5.0.0",
1050 "path-exists": "^4.0.0"
1044 } 1051 }
1045 }, 1052 },
1046 "flat": { 1053 "flat": {
@@ -1238,15 +1245,6 @@
1238 } 1245 }
1239 } 1246 }
1240 }, 1247 },
1241 "iconv-lite": {
1242 "version": "0.4.24",
1243 "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
1244 "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
1245 "dev": true,
1246 "requires": {
1247 "safer-buffer": ">= 2.1.2 < 3"
1248 }
1249 },
1250 "ignore": { 1248 "ignore": {
1251 "version": "4.0.6", 1249 "version": "4.0.6",
1252 "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", 1250 "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
@@ -1285,78 +1283,11 @@
1285 "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 1283 "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
1286 "dev": true 1284 "dev": true
1287 }, 1285 },
1288 "inquirer": { 1286 "is-arguments": {
1289 "version": "7.1.0", 1287 "version": "1.0.4",
1290 "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.1.0.tgz", 1288 "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz",
1291 "integrity": "sha512-5fJMWEmikSYu0nv/flMc475MhGbB7TSPd/2IpFV4I4rMklboCH2rQjYY5kKiYGHqUF9gvaambupcJFFG9dvReg==", 1289 "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==",
1292 "dev": true, 1290 "dev": true
1293 "requires": {
1294 "ansi-escapes": "^4.2.1",
1295 "chalk": "^3.0.0",
1296 "cli-cursor": "^3.1.0",
1297 "cli-width": "^2.0.0",
1298 "external-editor": "^3.0.3",
1299 "figures": "^3.0.0",
1300 "lodash": "^4.17.15",
1301 "mute-stream": "0.0.8",
1302 "run-async": "^2.4.0",
1303 "rxjs": "^6.5.3",
1304 "string-width": "^4.1.0",
1305 "strip-ansi": "^6.0.0",
1306 "through": "^2.3.6"
1307 },
1308 "dependencies": {
1309 "ansi-styles": {
1310 "version": "4.2.1",
1311 "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
1312 "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
1313 "dev": true,
1314 "requires": {
1315 "@types/color-name": "^1.1.1",
1316 "color-convert": "^2.0.1"
1317 }
1318 },
1319 "chalk": {
1320 "version": "3.0.0",
1321 "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
1322 "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
1323 "dev": true,
1324 "requires": {
1325 "ansi-styles": "^4.1.0",
1326 "supports-color": "^7.1.0"
1327 }
1328 },
1329 "color-convert": {
1330 "version": "2.0.1",
1331 "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
1332 "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
1333 "dev": true,
1334 "requires": {
1335 "color-name": "~1.1.4"
1336 }
1337 },
1338 "color-name": {
1339 "version": "1.1.4",
1340 "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
1341 "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
1342 "dev": true
1343 },
1344 "has-flag": {
1345 "version": "4.0.0",
1346 "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
1347 "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
1348 "dev": true
1349 },
1350 "supports-color": {
1351 "version": "7.1.0",
1352 "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
1353 "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
1354 "dev": true,
1355 "requires": {
1356 "has-flag": "^4.0.0"
1357 }
1358 }
1359 }
1360 }, 1291 },
1361 "is-binary-path": { 1292 "is-binary-path": {
1362 "version": "2.1.0", 1293 "version": "2.1.0",
@@ -1374,9 +1305,9 @@
1374 "dev": true 1305 "dev": true
1375 }, 1306 },
1376 "is-callable": { 1307 "is-callable": {
1377 "version": "1.1.5", 1308 "version": "1.2.0",
1378 "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", 1309 "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz",
1379 "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", 1310 "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==",
1380 "dev": true 1311 "dev": true
1381 }, 1312 },
1382 "is-date-object": { 1313 "is-date-object": {
@@ -1392,9 +1323,9 @@
1392 "dev": true 1323 "dev": true
1393 }, 1324 },
1394 "is-fullwidth-code-point": { 1325 "is-fullwidth-code-point": {
1395 "version": "3.0.0", 1326 "version": "2.0.0",
1396 "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 1327 "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
1397 "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 1328 "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
1398 "dev": true 1329 "dev": true
1399 }, 1330 },
1400 "is-glob": { 1331 "is-glob": {
@@ -1406,6 +1337,12 @@
1406 "is-extglob": "^2.1.1" 1337 "is-extglob": "^2.1.1"
1407 } 1338 }
1408 }, 1339 },
1340 "is-map": {
1341 "version": "2.0.1",
1342 "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.1.tgz",
1343 "integrity": "sha512-T/S49scO8plUiAOA2DBTBG3JHpn1yiw0kRp6dgiZ0v2/6twi5eiB0rHtHFH9ZIrvlWc6+4O+m4zg5+Z833aXgw==",
1344 "dev": true
1345 },
1409 "is-module": { 1346 "is-module": {
1410 "version": "1.0.0", 1347 "version": "1.0.0",
1411 "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", 1348 "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
@@ -1419,23 +1356,35 @@
1419 "dev": true 1356 "dev": true
1420 }, 1357 },
1421 "is-reference": { 1358 "is-reference": {
1422 "version": "1.1.4", 1359 "version": "1.2.1",
1423 "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.1.4.tgz", 1360 "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz",
1424 "integrity": "sha512-uJA/CDPO3Tao3GTrxYn6AwkM4nUPJiGGYu5+cB8qbC7WGFlrKZbiRo7SFKxUAEpFUfiHofWCXBUNhvYJMh+6zw==", 1361 "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==",
1425 "dev": true, 1362 "dev": true,
1426 "requires": { 1363 "requires": {
1427 "@types/estree": "0.0.39" 1364 "@types/estree": "*"
1428 } 1365 }
1429 }, 1366 },
1430 "is-regex": { 1367 "is-regex": {
1431 "version": "1.0.5", 1368 "version": "1.1.0",
1432 "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", 1369 "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz",
1433 "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", 1370 "integrity": "sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==",
1434 "dev": true, 1371 "dev": true,
1435 "requires": { 1372 "requires": {
1436 "has": "^1.0.3" 1373 "has-symbols": "^1.0.1"
1437 } 1374 }
1438 }, 1375 },
1376 "is-set": {
1377 "version": "2.0.1",
1378 "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.1.tgz",
1379 "integrity": "sha512-eJEzOtVyenDs1TMzSQ3kU3K+E0GUS9sno+F0OBT97xsgcJsF9nXMBtkT9/kut5JEpM7oL7X/0qxR17K3mcwIAA==",
1380 "dev": true
1381 },
1382 "is-string": {
1383 "version": "1.0.5",
1384 "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz",
1385 "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==",
1386 "dev": true
1387 },
1439 "is-symbol": { 1388 "is-symbol": {
1440 "version": "1.0.3", 1389 "version": "1.0.3",
1441 "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", 1390 "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz",
@@ -1445,12 +1394,34 @@
1445 "has-symbols": "^1.0.1" 1394 "has-symbols": "^1.0.1"
1446 } 1395 }
1447 }, 1396 },
1397 "isarray": {
1398 "version": "2.0.5",
1399 "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
1400 "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
1401 "dev": true
1402 },
1448 "isexe": { 1403 "isexe": {
1449 "version": "2.0.0", 1404 "version": "2.0.0",
1450 "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 1405 "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
1451 "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 1406 "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
1452 "dev": true 1407 "dev": true
1453 }, 1408 },
1409 "iterate-iterator": {
1410 "version": "1.0.1",
1411 "resolved": "https://registry.npmjs.org/iterate-iterator/-/iterate-iterator-1.0.1.tgz",
1412 "integrity": "sha512-3Q6tudGN05kbkDQDI4CqjaBf4qf85w6W6GnuZDtUVYwKgtC1q8yxYX7CZed7N+tLzQqS6roujWvszf13T+n9aw==",
1413 "dev": true
1414 },
1415 "iterate-value": {
1416 "version": "1.0.2",
1417 "resolved": "https://registry.npmjs.org/iterate-value/-/iterate-value-1.0.2.tgz",
1418 "integrity": "sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ==",
1419 "dev": true,
1420 "requires": {
1421 "es-get-iterator": "^1.0.2",
1422 "iterate-iterator": "^1.0.1"
1423 }
1424 },
1454 "js-tokens": { 1425 "js-tokens": {
1455 "version": "4.0.0", 1426 "version": "4.0.0",
1456 "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 1427 "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -1505,13 +1476,12 @@
1505 } 1476 }
1506 }, 1477 },
1507 "locate-path": { 1478 "locate-path": {
1508 "version": "3.0.0", 1479 "version": "5.0.0",
1509 "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", 1480 "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
1510 "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", 1481 "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
1511 "dev": true, 1482 "dev": true,
1512 "requires": { 1483 "requires": {
1513 "p-locate": "^3.0.0", 1484 "p-locate": "^4.1.0"
1514 "path-exists": "^3.0.0"
1515 } 1485 }
1516 }, 1486 },
1517 "lodash": { 1487 "lodash": {
@@ -1596,12 +1566,6 @@
1596 "mime-db": "1.44.0" 1566 "mime-db": "1.44.0"
1597 } 1567 }
1598 }, 1568 },
1599 "mimic-fn": {
1600 "version": "2.1.0",
1601 "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
1602 "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
1603 "dev": true
1604 },
1605 "minimatch": { 1569 "minimatch": {
1606 "version": "3.0.4", 1570 "version": "3.0.4",
1607 "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 1571 "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
@@ -1627,37 +1591,44 @@
1627 } 1591 }
1628 }, 1592 },
1629 "mocha": { 1593 "mocha": {
1630 "version": "7.2.0", 1594 "version": "8.0.1",
1631 "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.2.0.tgz", 1595 "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.0.1.tgz",
1632 "integrity": "sha512-O9CIypScywTVpNaRrCAgoUnJgozpIofjKUYmJhiCIJMiuYnLI6otcb1/kpW9/n/tJODHGZ7i8aLQoDVsMtOKQQ==", 1596 "integrity": "sha512-vefaXfdYI8+Yo8nPZQQi0QO2o+5q9UIMX1jZ1XMmK3+4+CQjc7+B0hPdUeglXiTlr8IHMVRo63IhO9Mzt6fxOg==",
1633 "dev": true, 1597 "dev": true,
1634 "requires": { 1598 "requires": {
1635 "ansi-colors": "3.2.3", 1599 "ansi-colors": "4.1.1",
1636 "browser-stdout": "1.3.1", 1600 "browser-stdout": "1.3.1",
1637 "chokidar": "3.3.0", 1601 "chokidar": "3.3.1",
1638 "debug": "3.2.6", 1602 "debug": "3.2.6",
1639 "diff": "3.5.0", 1603 "diff": "4.0.2",
1640 "escape-string-regexp": "1.0.5", 1604 "escape-string-regexp": "1.0.5",
1641 "find-up": "3.0.0", 1605 "find-up": "4.1.0",
1642 "glob": "7.1.3", 1606 "glob": "7.1.6",
1643 "growl": "1.10.5", 1607 "growl": "1.10.5",
1644 "he": "1.2.0", 1608 "he": "1.2.0",
1645 "js-yaml": "3.13.1", 1609 "js-yaml": "3.13.1",
1646 "log-symbols": "3.0.0", 1610 "log-symbols": "3.0.0",
1647 "minimatch": "3.0.4", 1611 "minimatch": "3.0.4",
1648 "mkdirp": "0.5.5", 1612 "ms": "2.1.2",
1649 "ms": "2.1.1",
1650 "node-environment-flags": "1.0.6",
1651 "object.assign": "4.1.0", 1613 "object.assign": "4.1.0",
1652 "strip-json-comments": "2.0.1", 1614 "promise.allsettled": "1.0.2",
1653 "supports-color": "6.0.0", 1615 "serialize-javascript": "3.0.0",
1654 "which": "1.3.1", 1616 "strip-json-comments": "3.0.1",
1617 "supports-color": "7.1.0",
1618 "which": "2.0.2",
1655 "wide-align": "1.1.3", 1619 "wide-align": "1.1.3",
1620 "workerpool": "6.0.0",
1656 "yargs": "13.3.2", 1621 "yargs": "13.3.2",
1657 "yargs-parser": "13.1.2", 1622 "yargs-parser": "13.1.2",
1658 "yargs-unparser": "1.6.0" 1623 "yargs-unparser": "1.6.0"
1659 }, 1624 },
1660 "dependencies": { 1625 "dependencies": {
1626 "ansi-colors": {
1627 "version": "4.1.1",
1628 "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
1629 "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
1630 "dev": true
1631 },
1661 "debug": { 1632 "debug": {
1662 "version": "3.2.6", 1633 "version": "3.2.6",
1663 "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", 1634 "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
@@ -1667,19 +1638,11 @@
1667 "ms": "^2.1.1" 1638 "ms": "^2.1.1"
1668 } 1639 }
1669 }, 1640 },
1670 "glob": { 1641 "has-flag": {
1671 "version": "7.1.3", 1642 "version": "4.0.0",
1672 "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", 1643 "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
1673 "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", 1644 "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
1674 "dev": true, 1645 "dev": true
1675 "requires": {
1676 "fs.realpath": "^1.0.0",
1677 "inflight": "^1.0.4",
1678 "inherits": "2",
1679 "minimatch": "^3.0.4",
1680 "once": "^1.3.0",
1681 "path-is-absolute": "^1.0.0"
1682 }
1683 }, 1646 },
1684 "js-yaml": { 1647 "js-yaml": {
1685 "version": "3.13.1", 1648 "version": "3.13.1",
@@ -1691,34 +1654,19 @@
1691 "esprima": "^4.0.0" 1654 "esprima": "^4.0.0"
1692 } 1655 }
1693 }, 1656 },
1694 "ms": {
1695 "version": "2.1.1",
1696 "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
1697 "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
1698 "dev": true
1699 },
1700 "strip-json-comments": { 1657 "strip-json-comments": {
1701 "version": "2.0.1", 1658 "version": "3.0.1",
1702 "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 1659 "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz",
1703 "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", 1660 "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==",
1704 "dev": true 1661 "dev": true
1705 }, 1662 },
1706 "supports-color": { 1663 "supports-color": {
1707 "version": "6.0.0", 1664 "version": "7.1.0",
1708 "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", 1665 "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
1709 "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", 1666 "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
1710 "dev": true,
1711 "requires": {
1712 "has-flag": "^3.0.0"
1713 }
1714 },
1715 "which": {
1716 "version": "1.3.1",
1717 "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
1718 "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
1719 "dev": true, 1667 "dev": true,
1720 "requires": { 1668 "requires": {
1721 "isexe": "^2.0.0" 1669 "has-flag": "^4.0.0"
1722 } 1670 }
1723 } 1671 }
1724 } 1672 }
@@ -1741,24 +1689,6 @@
1741 "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", 1689 "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
1742 "dev": true 1690 "dev": true
1743 }, 1691 },
1744 "node-environment-flags": {
1745 "version": "1.0.6",
1746 "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz",
1747 "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==",
1748 "dev": true,
1749 "requires": {
1750 "object.getownpropertydescriptors": "^2.0.3",
1751 "semver": "^5.7.0"
1752 },
1753 "dependencies": {
1754 "semver": {
1755 "version": "5.7.1",
1756 "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
1757 "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
1758 "dev": true
1759 }
1760 }
1761 },
1762 "node-fetch": { 1692 "node-fetch": {
1763 "version": "2.6.0", 1693 "version": "2.6.0",
1764 "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", 1694 "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz",
@@ -1780,9 +1710,9 @@
1780 } 1710 }
1781 }, 1711 },
1782 "object-inspect": { 1712 "object-inspect": {
1783 "version": "1.7.0", 1713 "version": "1.8.0",
1784 "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", 1714 "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz",
1785 "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", 1715 "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==",
1786 "dev": true 1716 "dev": true
1787 }, 1717 },
1788 "object-keys": { 1718 "object-keys": {
@@ -1803,16 +1733,6 @@
1803 "object-keys": "^1.0.11" 1733 "object-keys": "^1.0.11"
1804 } 1734 }
1805 }, 1735 },
1806 "object.getownpropertydescriptors": {
1807 "version": "2.1.0",
1808 "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz",
1809 "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==",
1810 "dev": true,
1811 "requires": {
1812 "define-properties": "^1.1.3",
1813 "es-abstract": "^1.17.0-next.1"
1814 }
1815 },
1816 "once": { 1736 "once": {
1817 "version": "1.4.0", 1737 "version": "1.4.0",
1818 "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1738 "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -1822,15 +1742,6 @@
1822 "wrappy": "1" 1742 "wrappy": "1"
1823 } 1743 }
1824 }, 1744 },
1825 "onetime": {
1826 "version": "5.1.0",
1827 "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz",
1828 "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==",
1829 "dev": true,
1830 "requires": {
1831 "mimic-fn": "^2.1.0"
1832 }
1833 },
1834 "optionator": { 1745 "optionator": {
1835 "version": "0.9.1", 1746 "version": "0.9.1",
1836 "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", 1747 "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
@@ -1883,12 +1794,12 @@
1883 } 1794 }
1884 }, 1795 },
1885 "p-locate": { 1796 "p-locate": {
1886 "version": "3.0.0", 1797 "version": "4.1.0",
1887 "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", 1798 "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
1888 "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", 1799 "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
1889 "dev": true, 1800 "dev": true,
1890 "requires": { 1801 "requires": {
1891 "p-limit": "^2.0.0" 1802 "p-limit": "^2.2.0"
1892 } 1803 }
1893 }, 1804 },
1894 "p-try": { 1805 "p-try": {
@@ -1933,9 +1844,9 @@
1933 } 1844 }
1934 }, 1845 },
1935 "path-exists": { 1846 "path-exists": {
1936 "version": "3.0.0", 1847 "version": "4.0.0",
1937 "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", 1848 "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
1938 "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", 1849 "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
1939 "dev": true 1850 "dev": true
1940 }, 1851 },
1941 "path-is-absolute": { 1852 "path-is-absolute": {
@@ -1980,6 +1891,19 @@
1980 "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", 1891 "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
1981 "dev": true 1892 "dev": true
1982 }, 1893 },
1894 "promise.allsettled": {
1895 "version": "1.0.2",
1896 "resolved": "https://registry.npmjs.org/promise.allsettled/-/promise.allsettled-1.0.2.tgz",
1897 "integrity": "sha512-UpcYW5S1RaNKT6pd+s9jp9K9rlQge1UXKskec0j6Mmuq7UJCvlS2J2/s/yuPN8ehftf9HXMxWlKiPbGGUzpoRg==",
1898 "dev": true,
1899 "requires": {
1900 "array.prototype.map": "^1.0.1",
1901 "define-properties": "^1.1.3",
1902 "es-abstract": "^1.17.0-next.1",
1903 "function-bind": "^1.1.1",
1904 "iterate-value": "^1.0.0"
1905 }
1906 },
1983 "pseudomap": { 1907 "pseudomap": {
1984 "version": "1.0.2", 1908 "version": "1.0.2",
1985 "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", 1909 "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
@@ -2013,12 +1937,12 @@
2013 } 1937 }
2014 }, 1938 },
2015 "readdirp": { 1939 "readdirp": {
2016 "version": "3.2.0", 1940 "version": "3.3.0",
2017 "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", 1941 "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.3.0.tgz",
2018 "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", 1942 "integrity": "sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ==",
2019 "dev": true, 1943 "dev": true,
2020 "requires": { 1944 "requires": {
2021 "picomatch": "^2.0.4" 1945 "picomatch": "^2.0.7"
2022 } 1946 }
2023 }, 1947 },
2024 "regexpp": { 1948 "regexpp": {
@@ -2054,16 +1978,6 @@
2054 "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", 1978 "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
2055 "dev": true 1979 "dev": true
2056 }, 1980 },
2057 "restore-cursor": {
2058 "version": "3.1.0",
2059 "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
2060 "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==",
2061 "dev": true,
2062 "requires": {
2063 "onetime": "^5.1.0",
2064 "signal-exit": "^3.0.2"
2065 }
2066 },
2067 "rimraf": { 1981 "rimraf": {
2068 "version": "2.6.3", 1982 "version": "2.6.3",
2069 "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", 1983 "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
@@ -2074,54 +1988,31 @@
2074 } 1988 }
2075 }, 1989 },
2076 "rollup": { 1990 "rollup": {
2077 "version": "2.10.9", 1991 "version": "2.18.1",
2078 "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.10.9.tgz", 1992 "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.18.1.tgz",
2079 "integrity": "sha512-dY/EbjiWC17ZCUSyk14hkxATAMAShkMsD43XmZGWjLrgFj15M3Dw2kEkA9ns64BiLFm9PKN6vTQw8neHwK74eg==", 1993 "integrity": "sha512-w4X77ADA+WTGlapC8Z6yggdJtODw3SBl6R2LSkA7ZW5MtdkgcB7sfaSD1UWyx8diXbMcGIb0eI9gCx/dyqOgNQ==",
2080 "dev": true, 1994 "dev": true,
2081 "requires": { 1995 "requires": {
2082 "fsevents": "~2.1.2" 1996 "fsevents": "~2.1.2"
2083 } 1997 }
2084 }, 1998 },
2085 "run-async": {
2086 "version": "2.4.1",
2087 "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
2088 "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==",
2089 "dev": true
2090 },
2091 "rxjs": {
2092 "version": "6.5.5",
2093 "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.5.tgz",
2094 "integrity": "sha512-WfQI+1gohdf0Dai/Bbmk5L5ItH5tYqm3ki2c5GdWhKjalzjg93N3avFjVStyZZz+A2Em+ZxKH5bNghw9UeylGQ==",
2095 "dev": true,
2096 "requires": {
2097 "tslib": "^1.9.0"
2098 },
2099 "dependencies": {
2100 "tslib": {
2101 "version": "1.13.0",
2102 "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz",
2103 "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==",
2104 "dev": true
2105 }
2106 }
2107 },
2108 "safe-buffer": { 1999 "safe-buffer": {
2109 "version": "5.2.0", 2000 "version": "5.2.0",
2110 "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", 2001 "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
2111 "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", 2002 "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==",
2112 "dev": true 2003 "dev": true
2113 }, 2004 },
2114 "safer-buffer": {
2115 "version": "2.1.2",
2116 "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
2117 "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
2118 "dev": true
2119 },
2120 "semver": { 2005 "semver": {
2121 "version": "6.3.0", 2006 "version": "6.3.0",
2122 "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", 2007 "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
2123 "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" 2008 "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
2124 }, 2009 },
2010 "serialize-javascript": {
2011 "version": "3.0.0",
2012 "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-3.0.0.tgz",
2013 "integrity": "sha512-skZcHYw2vEX4bw90nAr2iTTsz6x2SrHEnfxgKYmZlvJYBEZrvbKtobJWlQ20zczKb3bsHHXXTYt48zBA7ni9cw==",
2014 "dev": true
2015 },
2125 "set-blocking": { 2016 "set-blocking": {
2126 "version": "2.0.0", 2017 "version": "2.0.0",
2127 "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", 2018 "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
@@ -2149,12 +2040,6 @@
2149 "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", 2040 "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=",
2150 "dev": true 2041 "dev": true
2151 }, 2042 },
2152 "signal-exit": {
2153 "version": "3.0.3",
2154 "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
2155 "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==",
2156 "dev": true
2157 },
2158 "slice-ansi": { 2043 "slice-ansi": {
2159 "version": "2.1.0", 2044 "version": "2.1.0",
2160 "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", 2045 "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz",
@@ -2164,14 +2049,6 @@
2164 "ansi-styles": "^3.2.0", 2049 "ansi-styles": "^3.2.0",
2165 "astral-regex": "^1.0.0", 2050 "astral-regex": "^1.0.0",
2166 "is-fullwidth-code-point": "^2.0.0" 2051 "is-fullwidth-code-point": "^2.0.0"
2167 },
2168 "dependencies": {
2169 "is-fullwidth-code-point": {
2170 "version": "2.0.0",
2171 "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
2172 "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
2173 "dev": true
2174 }
2175 } 2052 }
2176 }, 2053 },
2177 "sourcemap-codec": { 2054 "sourcemap-codec": {
@@ -2187,14 +2064,31 @@
2187 "dev": true 2064 "dev": true
2188 }, 2065 },
2189 "string-width": { 2066 "string-width": {
2190 "version": "4.2.0", 2067 "version": "3.1.0",
2191 "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", 2068 "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
2192 "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", 2069 "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
2193 "dev": true, 2070 "dev": true,
2194 "requires": { 2071 "requires": {
2195 "emoji-regex": "^8.0.0", 2072 "emoji-regex": "^7.0.1",
2196 "is-fullwidth-code-point": "^3.0.0", 2073 "is-fullwidth-code-point": "^2.0.0",
2197 "strip-ansi": "^6.0.0" 2074 "strip-ansi": "^5.1.0"
2075 },
2076 "dependencies": {
2077 "ansi-regex": {
2078 "version": "4.1.0",
2079 "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
2080 "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
2081 "dev": true
2082 },
2083 "strip-ansi": {
2084 "version": "5.2.0",
2085 "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
2086 "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
2087 "dev": true,
2088 "requires": {
2089 "ansi-regex": "^4.1.0"
2090 }
2091 }
2198 } 2092 }
2199 }, 2093 },
2200 "string.prototype.trimend": { 2094 "string.prototype.trimend": {
@@ -2207,28 +2101,6 @@
2207 "es-abstract": "^1.17.5" 2101 "es-abstract": "^1.17.5"
2208 } 2102 }
2209 }, 2103 },
2210 "string.prototype.trimleft": {
2211 "version": "2.1.2",
2212 "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz",
2213 "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==",
2214 "dev": true,
2215 "requires": {
2216 "define-properties": "^1.1.3",
2217 "es-abstract": "^1.17.5",
2218 "string.prototype.trimstart": "^1.0.0"
2219 }
2220 },
2221 "string.prototype.trimright": {
2222 "version": "2.1.2",
2223 "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz",
2224 "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==",
2225 "dev": true,
2226 "requires": {
2227 "define-properties": "^1.1.3",
2228 "es-abstract": "^1.17.5",
2229 "string.prototype.trimend": "^1.0.0"
2230 }
2231 },
2232 "string.prototype.trimstart": { 2104 "string.prototype.trimstart": {
2233 "version": "1.0.1", 2105 "version": "1.0.1",
2234 "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", 2106 "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz",
@@ -2282,46 +2154,6 @@
2282 "lodash": "^4.17.14", 2154 "lodash": "^4.17.14",
2283 "slice-ansi": "^2.1.0", 2155 "slice-ansi": "^2.1.0",
2284 "string-width": "^3.0.0" 2156 "string-width": "^3.0.0"
2285 },
2286 "dependencies": {
2287 "ansi-regex": {
2288 "version": "4.1.0",
2289 "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
2290 "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
2291 "dev": true
2292 },
2293 "emoji-regex": {
2294 "version": "7.0.3",
2295 "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
2296 "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
2297 "dev": true
2298 },
2299 "is-fullwidth-code-point": {
2300 "version": "2.0.0",
2301 "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
2302 "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
2303 "dev": true
2304 },
2305 "string-width": {
2306 "version": "3.1.0",
2307 "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
2308 "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
2309 "dev": true,
2310 "requires": {
2311 "emoji-regex": "^7.0.1",
2312 "is-fullwidth-code-point": "^2.0.0",
2313 "strip-ansi": "^5.1.0"
2314 }
2315 },
2316 "strip-ansi": {
2317 "version": "5.2.0",
2318 "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
2319 "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
2320 "dev": true,
2321 "requires": {
2322 "ansi-regex": "^4.1.0"
2323 }
2324 }
2325 } 2157 }
2326 }, 2158 },
2327 "text-table": { 2159 "text-table": {
@@ -2330,21 +2162,6 @@
2330 "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", 2162 "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
2331 "dev": true 2163 "dev": true
2332 }, 2164 },
2333 "through": {
2334 "version": "2.3.8",
2335 "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
2336 "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
2337 "dev": true
2338 },
2339 "tmp": {
2340 "version": "0.0.33",
2341 "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
2342 "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
2343 "dev": true,
2344 "requires": {
2345 "os-tmpdir": "~1.0.2"
2346 }
2347 },
2348 "to-regex-range": { 2165 "to-regex-range": {
2349 "version": "5.0.1", 2166 "version": "5.0.1",
2350 "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 2167 "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@@ -2409,9 +2226,9 @@
2409 } 2226 }
2410 }, 2227 },
2411 "typescript": { 2228 "typescript": {
2412 "version": "3.9.3", 2229 "version": "3.9.5",
2413 "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.3.tgz", 2230 "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.5.tgz",
2414 "integrity": "sha512-D/wqnB2xzNFIcoBG9FG8cXRDjiqSTbG2wd8DMZeQyJlP1vfTkIxH4GKveWaEBYySKIg+USu+E+EDIR47SqnaMQ==", 2231 "integrity": "sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ==",
2415 "dev": true 2232 "dev": true
2416 }, 2233 },
2417 "typescript-formatter": { 2234 "typescript-formatter": {
@@ -2458,9 +2275,9 @@
2458 "dev": true 2275 "dev": true
2459 }, 2276 },
2460 "v8-compile-cache": { 2277 "v8-compile-cache": {
2461 "version": "2.1.0", 2278 "version": "2.1.1",
2462 "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", 2279 "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz",
2463 "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", 2280 "integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==",
2464 "dev": true 2281 "dev": true
2465 }, 2282 },
2466 "vsce": { 2283 "vsce": {
@@ -2537,9 +2354,9 @@
2537 "integrity": "sha512-tZFUSbyjUcrh+qQf13ALX4QDdOfDX0cVaBFgy7ktJ0VwS7AW/yRKgGPSxVqqP9OCMNPdqP57O5q47w2pEwfaUg==" 2354 "integrity": "sha512-tZFUSbyjUcrh+qQf13ALX4QDdOfDX0cVaBFgy7ktJ0VwS7AW/yRKgGPSxVqqP9OCMNPdqP57O5q47w2pEwfaUg=="
2538 }, 2355 },
2539 "vscode-test": { 2356 "vscode-test": {
2540 "version": "1.3.0", 2357 "version": "1.4.0",
2541 "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.3.0.tgz", 2358 "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.4.0.tgz",
2542 "integrity": "sha512-LddukcBiSU2FVTDr3c1D8lwkiOvwlJdDL2hqVbn6gIz+rpTqUCkMZSKYm94Y1v0WXlHSDQBsXyY+tchWQgGVsw==", 2359 "integrity": "sha512-Jt7HNGvSE0+++Tvtq5wc4hiXLIr2OjDShz/gbAfM/mahQpy4rKBnmOK33D+MR67ATWviQhl+vpmU3p/qwSH/Pg==",
2543 "dev": true, 2360 "dev": true,
2544 "requires": { 2361 "requires": {
2545 "http-proxy-agent": "^2.1.0", 2362 "http-proxy-agent": "^2.1.0",
@@ -2577,12 +2394,6 @@
2577 "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", 2394 "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
2578 "dev": true 2395 "dev": true
2579 }, 2396 },
2580 "is-fullwidth-code-point": {
2581 "version": "2.0.0",
2582 "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
2583 "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
2584 "dev": true
2585 },
2586 "string-width": { 2397 "string-width": {
2587 "version": "2.1.1", 2398 "version": "2.1.1",
2588 "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", 2399 "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
@@ -2610,6 +2421,12 @@
2610 "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", 2421 "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
2611 "dev": true 2422 "dev": true
2612 }, 2423 },
2424 "workerpool": {
2425 "version": "6.0.0",
2426 "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.0.0.tgz",
2427 "integrity": "sha512-fU2OcNA/GVAJLLyKUoHkAgIhKb0JoCpSjLC/G2vYKxUjVmQwGbRVeoPJ1a8U4pnVofz4AQV5Y/NEw8oKqxEBtA==",
2428 "dev": true
2429 },
2613 "wrap-ansi": { 2430 "wrap-ansi": {
2614 "version": "5.1.0", 2431 "version": "5.1.0",
2615 "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", 2432 "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
@@ -2627,29 +2444,6 @@
2627 "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", 2444 "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
2628 "dev": true 2445 "dev": true
2629 }, 2446 },
2630 "emoji-regex": {
2631 "version": "7.0.3",
2632 "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
2633 "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
2634 "dev": true
2635 },
2636 "is-fullwidth-code-point": {
2637 "version": "2.0.0",
2638 "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
2639 "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
2640 "dev": true
2641 },
2642 "string-width": {
2643 "version": "3.1.0",
2644 "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
2645 "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
2646 "dev": true,
2647 "requires": {
2648 "emoji-regex": "^7.0.1",
2649 "is-fullwidth-code-point": "^2.0.0",
2650 "strip-ansi": "^5.1.0"
2651 }
2652 },
2653 "strip-ansi": { 2447 "strip-ansi": {
2654 "version": "5.2.0", 2448 "version": "5.2.0",
2655 "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", 2449 "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
@@ -2706,43 +2500,39 @@
2706 "yargs-parser": "^13.1.2" 2500 "yargs-parser": "^13.1.2"
2707 }, 2501 },
2708 "dependencies": { 2502 "dependencies": {
2709 "ansi-regex": { 2503 "find-up": {
2710 "version": "4.1.0", 2504 "version": "3.0.0",
2711 "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", 2505 "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
2712 "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", 2506 "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
2713 "dev": true 2507 "dev": true,
2714 }, 2508 "requires": {
2715 "emoji-regex": { 2509 "locate-path": "^3.0.0"
2716 "version": "7.0.3", 2510 }
2717 "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
2718 "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
2719 "dev": true
2720 },
2721 "is-fullwidth-code-point": {
2722 "version": "2.0.0",
2723 "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
2724 "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
2725 "dev": true
2726 }, 2511 },
2727 "string-width": { 2512 "locate-path": {
2728 "version": "3.1.0", 2513 "version": "3.0.0",
2729 "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", 2514 "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
2730 "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", 2515 "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
2731 "dev": true, 2516 "dev": true,
2732 "requires": { 2517 "requires": {
2733 "emoji-regex": "^7.0.1", 2518 "p-locate": "^3.0.0",
2734 "is-fullwidth-code-point": "^2.0.0", 2519 "path-exists": "^3.0.0"
2735 "strip-ansi": "^5.1.0"
2736 } 2520 }
2737 }, 2521 },
2738 "strip-ansi": { 2522 "p-locate": {
2739 "version": "5.2.0", 2523 "version": "3.0.0",
2740 "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", 2524 "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
2741 "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", 2525 "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
2742 "dev": true, 2526 "dev": true,
2743 "requires": { 2527 "requires": {
2744 "ansi-regex": "^4.1.0" 2528 "p-limit": "^2.0.0"
2745 } 2529 }
2530 },
2531 "path-exists": {
2532 "version": "3.0.0",
2533 "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
2534 "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
2535 "dev": true
2746 } 2536 }
2747 } 2537 }
2748 }, 2538 },
diff --git a/editors/code/package.json b/editors/code/package.json
index f542a490a..af0a5c851 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -39,29 +39,29 @@
39 "vscode-languageclient": "7.0.0-next.1" 39 "vscode-languageclient": "7.0.0-next.1"
40 }, 40 },
41 "devDependencies": { 41 "devDependencies": {
42 "@rollup/plugin-commonjs": "^12.0.0", 42 "@rollup/plugin-commonjs": "^13.0.0",
43 "@rollup/plugin-node-resolve": "^8.0.0", 43 "@rollup/plugin-node-resolve": "^8.1.0",
44 "@types/glob": "^7.1.1", 44 "@types/glob": "^7.1.2",
45 "@types/mocha": "^7.0.2", 45 "@types/mocha": "^7.0.2",
46 "@types/node": "^14.0.5", 46 "@types/node": "~12.7.0",
47 "@types/node-fetch": "^2.5.7", 47 "@types/node-fetch": "^2.5.7",
48 "@types/vscode": "^1.44.1", 48 "@types/vscode": "^1.44.1",
49 "@typescript-eslint/eslint-plugin": "^3.0.0", 49 "@typescript-eslint/eslint-plugin": "^3.4.0",
50 "@typescript-eslint/parser": "^3.0.0", 50 "@typescript-eslint/parser": "^3.4.0",
51 "eslint": "^7.0.0", 51 "eslint": "^7.3.1",
52 "glob": "^7.1.6", 52 "glob": "^7.1.6",
53 "mocha": "^7.1.2", 53 "mocha": "^8.0.1",
54 "rollup": "^2.10.7", 54 "rollup": "^2.18.1",
55 "tslib": "^2.0.0", 55 "tslib": "^2.0.0",
56 "typescript": "^3.9.3", 56 "typescript": "^3.9.5",
57 "typescript-formatter": "^7.2.2", 57 "typescript-formatter": "^7.2.2",
58 "vsce": "^1.75.0", 58 "vsce": "^1.75.0",
59 "vscode-test": "^1.3.0" 59 "vscode-test": "^1.4.0"
60 }, 60 },
61 "activationEvents": [ 61 "activationEvents": [
62 "onLanguage:rust", 62 "onLanguage:rust",
63 "onCommand:rust-analyzer.analyzerStatus", 63 "onCommand:rust-analyzer.analyzerStatus",
64 "onCommand:rust-analyzer.collectGarbage", 64 "onCommand:rust-analyzer.reloadWorkspace",
65 "workspaceContains:**/Cargo.toml" 65 "workspaceContains:**/Cargo.toml"
66 ], 66 ],
67 "main": "./out/src/main", 67 "main": "./out/src/main",
@@ -143,8 +143,8 @@
143 "category": "Rust Analyzer" 143 "category": "Rust Analyzer"
144 }, 144 },
145 { 145 {
146 "command": "rust-analyzer.collectGarbage", 146 "command": "rust-analyzer.reloadWorkspace",
147 "title": "Run garbage collection", 147 "title": "Reload workspace",
148 "category": "Rust Analyzer" 148 "category": "Rust Analyzer"
149 }, 149 },
150 { 150 {
@@ -815,7 +815,7 @@
815 "when": "inRustProject" 815 "when": "inRustProject"
816 }, 816 },
817 { 817 {
818 "command": "rust-analyzer.collectGarbage", 818 "command": "rust-analyzer.reloadWorkspace",
819 "when": "inRustProject" 819 "when": "inRustProject"
820 }, 820 },
821 { 821 {
diff --git a/editors/code/rollup.config.js b/editors/code/rollup.config.js
index 4b4c47f4a..27abf75ac 100644
--- a/editors/code/rollup.config.js
+++ b/editors/code/rollup.config.js
@@ -16,7 +16,6 @@ export default {
16 external: [...nodeBuiltins, 'vscode'], 16 external: [...nodeBuiltins, 'vscode'],
17 output: { 17 output: {
18 file: './out/src/main.js', 18 file: './out/src/main.js',
19 format: 'cjs', 19 format: 'cjs'
20 exports: 'named'
21 } 20 }
22}; 21};
diff --git a/editors/code/rust.tmGrammar.json b/editors/code/rust.tmGrammar.json
index ab87cd39f..0be2583db 100644
--- a/editors/code/rust.tmGrammar.json
+++ b/editors/code/rust.tmGrammar.json
@@ -268,7 +268,7 @@
268 "match": "\\b(log|error|warn|info|debug|trace|log_enabled)!" 268 "match": "\\b(log|error|warn|info|debug|trace|log_enabled)!"
269 }, 269 },
270 { 270 {
271 "comment": "Invokation of a macro", 271 "comment": "Invocation of a macro",
272 "match": "\\b([a-zA-Z_][a-zA-Z0-9_]*\\!)\\s*[({\\[]", 272 "match": "\\b([a-zA-Z_][a-zA-Z0-9_]*\\!)\\s*[({\\[]",
273 "captures": { 273 "captures": {
274 "1": { 274 "1": {
@@ -683,4 +683,4 @@
683 ] 683 ]
684 } 684 }
685 } 685 }
686} \ No newline at end of file 686}
diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts
index 0e78f5101..19a9c2a0d 100644
--- a/editors/code/src/commands.ts
+++ b/editors/code/src/commands.ts
@@ -330,8 +330,8 @@ export function expandMacro(ctx: Ctx): Cmd {
330 }; 330 };
331} 331}
332 332
333export function collectGarbage(ctx: Ctx): Cmd { 333export function reloadWorkspace(ctx: Ctx): Cmd {
334 return async () => ctx.client.sendRequest(ra.collectGarbage, null); 334 return async () => ctx.client.sendRequest(ra.reloadWorkspace, null);
335} 335}
336 336
337export function showReferences(ctx: Ctx): Cmd { 337export function showReferences(ctx: Ctx): Cmd {
diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts
index e16ea799c..981b6f40e 100644
--- a/editors/code/src/lsp_ext.ts
+++ b/editors/code/src/lsp_ext.ts
@@ -6,7 +6,7 @@ import * as lc from "vscode-languageclient";
6 6
7export const analyzerStatus = new lc.RequestType<null, string, void>("rust-analyzer/analyzerStatus"); 7export const analyzerStatus = new lc.RequestType<null, string, void>("rust-analyzer/analyzerStatus");
8 8
9export const collectGarbage = new lc.RequestType<null, null, void>("rust-analyzer/collectGarbage"); 9export const reloadWorkspace = new lc.RequestType<null, null, void>("rust-analyzer/reloadWorkspace");
10 10
11export interface SyntaxTreeParams { 11export interface SyntaxTreeParams {
12 textDocument: lc.TextDocumentIdentifier; 12 textDocument: lc.TextDocumentIdentifier;
@@ -60,6 +60,7 @@ export interface Runnable {
60 workspaceRoot?: string; 60 workspaceRoot?: string;
61 cargoArgs: string[]; 61 cargoArgs: string[];
62 executableArgs: string[]; 62 executableArgs: string[];
63 expectTest?: boolean;
63 }; 64 };
64} 65}
65export const runnables = new lc.RequestType<RunnablesParams, Runnable[], void>("experimental/runnables"); 66export const runnables = new lc.RequestType<RunnablesParams, Runnable[], void>("experimental/runnables");
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index 1ad75a03c..a1521a93b 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -19,6 +19,16 @@ let ctx: Ctx | undefined;
19const RUST_PROJECT_CONTEXT_NAME = "inRustProject"; 19const RUST_PROJECT_CONTEXT_NAME = "inRustProject";
20 20
21export async function activate(context: vscode.ExtensionContext) { 21export async function activate(context: vscode.ExtensionContext) {
22 // For some reason vscode not always shows pop-up error notifications
23 // when an extension fails to activate, so we do it explicitly by ourselves.
24 // FIXME: remove this bit of code once vscode fixes this issue: https://github.com/microsoft/vscode/issues/101242
25 await tryActivate(context).catch(err => {
26 void vscode.window.showErrorMessage(`Cannot activate rust-analyzer: ${err.message}`);
27 throw err;
28 });
29}
30
31async function tryActivate(context: vscode.ExtensionContext) {
22 // Register a "dumb" onEnter command for the case where server fails to 32 // Register a "dumb" onEnter command for the case where server fails to
23 // start. 33 // start.
24 // 34 //
@@ -58,9 +68,7 @@ export async function activate(context: vscode.ExtensionContext) {
58 68
59 const workspaceFolder = vscode.workspace.workspaceFolders?.[0]; 69 const workspaceFolder = vscode.workspace.workspaceFolders?.[0];
60 if (workspaceFolder === undefined) { 70 if (workspaceFolder === undefined) {
61 const err = "Cannot activate rust-analyzer when no folder is opened"; 71 throw new Error("no folder is opened");
62 void vscode.window.showErrorMessage(err);
63 throw new Error(err);
64 } 72 }
65 73
66 // Note: we try to start the server before we activate type hints so that it 74 // Note: we try to start the server before we activate type hints so that it
@@ -88,7 +96,7 @@ export async function activate(context: vscode.ExtensionContext) {
88 }); 96 });
89 97
90 ctx.registerCommand('analyzerStatus', commands.analyzerStatus); 98 ctx.registerCommand('analyzerStatus', commands.analyzerStatus);
91 ctx.registerCommand('collectGarbage', commands.collectGarbage); 99 ctx.registerCommand('reloadWorkspace', commands.reloadWorkspace);
92 ctx.registerCommand('matchingBrace', commands.matchingBrace); 100 ctx.registerCommand('matchingBrace', commands.matchingBrace);
93 ctx.registerCommand('joinLines', commands.joinLines); 101 ctx.registerCommand('joinLines', commands.joinLines);
94 ctx.registerCommand('parentModule', commands.parentModule); 102 ctx.registerCommand('parentModule', commands.parentModule);
diff --git a/editors/code/src/run.ts b/editors/code/src/run.ts
index 766b05112..e1430e31f 100644
--- a/editors/code/src/run.ts
+++ b/editors/code/src/run.ts
@@ -108,12 +108,16 @@ export async function createTask(runnable: ra.Runnable, config: Config): Promise
108 if (runnable.args.executableArgs.length > 0) { 108 if (runnable.args.executableArgs.length > 0) {
109 args.push('--', ...runnable.args.executableArgs); 109 args.push('--', ...runnable.args.executableArgs);
110 } 110 }
111 const env: { [key: string]: string } = { "RUST_BACKTRACE": "short" };
112 if (runnable.args.expectTest) {
113 env["UPDATE_EXPECT"] = "1";
114 }
111 const definition: tasks.CargoTaskDefinition = { 115 const definition: tasks.CargoTaskDefinition = {
112 type: tasks.TASK_TYPE, 116 type: tasks.TASK_TYPE,
113 command: args[0], // run, test, etc... 117 command: args[0], // run, test, etc...
114 args: args.slice(1), 118 args: args.slice(1),
115 cwd: runnable.args.workspaceRoot, 119 cwd: runnable.args.workspaceRoot,
116 env: Object.assign({}, process.env as { [key: string]: string }, { "RUST_BACKTRACE": "short" }), 120 env: Object.assign({}, process.env as { [key: string]: string }, env),
117 }; 121 };
118 122
119 const target = vscode.workspace.workspaceFolders![0]; // safe, see main activate() 123 const target = vscode.workspace.workspaceFolders![0]; // safe, see main activate()