diff options
72 files changed, 1584 insertions, 704 deletions
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 58c8f083a..29e388e7c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml | |||
@@ -7,14 +7,18 @@ on: | |||
7 | - staging | 7 | - staging |
8 | - trying | 8 | - trying |
9 | 9 | ||
10 | env: | ||
11 | CARGO_INCREMENTAL: 0 | ||
12 | CARGO_NET_RETRY: 10 | ||
13 | CC: deny_c | ||
14 | RUN_SLOW_TESTS: 1 | ||
15 | RUSTFLAGS: -D warnings | ||
16 | RUSTUP_MAX_RETRIES: 10 | ||
17 | |||
10 | jobs: | 18 | jobs: |
11 | rust-audit: | 19 | rust-audit: |
12 | name: Audit Rust vulnerabilities | 20 | name: Audit Rust vulnerabilities |
13 | runs-on: ubuntu-latest | 21 | runs-on: ubuntu-latest |
14 | env: | ||
15 | RUSTUP_MAX_RETRIES: 10 | ||
16 | CARGO_NET_RETRY: 10 | ||
17 | |||
18 | steps: | 22 | steps: |
19 | - name: Install Rust toolchain | 23 | - name: Install Rust toolchain |
20 | uses: actions-rs/toolchain@v1 | 24 | uses: actions-rs/toolchain@v1 |
@@ -46,14 +50,6 @@ jobs: | |||
46 | matrix: | 50 | matrix: |
47 | os: [ubuntu-latest, windows-latest, macos-latest] | 51 | os: [ubuntu-latest, windows-latest, macos-latest] |
48 | 52 | ||
49 | env: | ||
50 | RUSTFLAGS: -D warnings | ||
51 | CC: deny_c | ||
52 | CARGO_INCREMENTAL: 0 | ||
53 | RUN_SLOW_TESTS: 1 | ||
54 | RUSTUP_MAX_RETRIES: 10 | ||
55 | CARGO_NET_RETRY: 10 | ||
56 | |||
57 | steps: | 53 | steps: |
58 | - name: Checkout repository | 54 | - name: Checkout repository |
59 | uses: actions/checkout@v2 | 55 | uses: actions/checkout@v2 |
@@ -111,9 +107,6 @@ jobs: | |||
111 | typescript: | 107 | typescript: |
112 | name: TypeScript | 108 | name: TypeScript |
113 | runs-on: ubuntu-latest | 109 | runs-on: ubuntu-latest |
114 | env: | ||
115 | CXX: g++-4.9 | ||
116 | CC: gcc-4.9 | ||
117 | steps: | 110 | steps: |
118 | - name: Checkout repository | 111 | - name: Checkout repository |
119 | uses: actions/checkout@v2 | 112 | uses: actions/checkout@v2 |
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index c055d113d..fd184e8f1 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml | |||
@@ -8,6 +8,12 @@ on: | |||
8 | - release | 8 | - release |
9 | - nightly | 9 | - nightly |
10 | 10 | ||
11 | env: | ||
12 | CARGO_INCREMENTAL: 0 | ||
13 | CARGO_NET_RETRY: 10 | ||
14 | RUSTFLAGS: -D warnings | ||
15 | RUSTUP_MAX_RETRIES: 10 | ||
16 | |||
11 | jobs: | 17 | jobs: |
12 | dist: | 18 | dist: |
13 | name: dist | 19 | name: dist |
@@ -16,12 +22,6 @@ jobs: | |||
16 | matrix: | 22 | matrix: |
17 | os: [ubuntu-latest, windows-latest, macos-latest] | 23 | os: [ubuntu-latest, windows-latest, macos-latest] |
18 | 24 | ||
19 | env: | ||
20 | RUSTFLAGS: -D warnings | ||
21 | CARGO_INCREMENTAL: 0 | ||
22 | RUSTUP_MAX_RETRIES: 10 | ||
23 | CARGO_NET_RETRY: 10 | ||
24 | |||
25 | steps: | 25 | steps: |
26 | - name: Checkout repository | 26 | - name: Checkout repository |
27 | uses: actions/checkout@v2 | 27 | uses: actions/checkout@v2 |
diff --git a/.github/workflows/rustdoc.yaml b/.github/workflows/rustdoc.yaml index c84ce5d48..cf4bca840 100644 --- a/.github/workflows/rustdoc.yaml +++ b/.github/workflows/rustdoc.yaml | |||
@@ -4,12 +4,15 @@ on: | |||
4 | branches: | 4 | branches: |
5 | - master | 5 | - master |
6 | 6 | ||
7 | env: | ||
8 | CARGO_INCREMENTAL: 0 | ||
9 | CARGO_NET_RETRY: 10 | ||
10 | RUSTFLAGS: -D warnings | ||
11 | RUSTUP_MAX_RETRIES: 10 | ||
12 | |||
7 | jobs: | 13 | jobs: |
8 | rustdoc: | 14 | rustdoc: |
9 | runs-on: ubuntu-latest | 15 | runs-on: ubuntu-latest |
10 | env: | ||
11 | RUSTFLAGS: -D warnings | ||
12 | CARGO_INCREMENTAL: 0 | ||
13 | 16 | ||
14 | steps: | 17 | steps: |
15 | - name: Checkout repository | 18 | - name: Checkout repository |
diff --git a/Cargo.lock b/Cargo.lock index eb5247b69..908319f87 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -170,7 +170,7 @@ dependencies = [ | |||
170 | "chalk-macros", | 170 | "chalk-macros", |
171 | "chalk-rust-ir", | 171 | "chalk-rust-ir", |
172 | "ena", | 172 | "ena", |
173 | "itertools", | 173 | "itertools 0.8.2", |
174 | "petgraph", | 174 | "petgraph", |
175 | "rustc-hash", | 175 | "rustc-hash", |
176 | ] | 176 | ] |
@@ -521,6 +521,15 @@ dependencies = [ | |||
521 | ] | 521 | ] |
522 | 522 | ||
523 | [[package]] | 523 | [[package]] |
524 | name = "itertools" | ||
525 | version = "0.9.0" | ||
526 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
527 | checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" | ||
528 | dependencies = [ | ||
529 | "either", | ||
530 | ] | ||
531 | |||
532 | [[package]] | ||
524 | name = "itoa" | 533 | name = "itoa" |
525 | version = "0.4.5" | 534 | version = "0.4.5" |
526 | source = "registry+https://github.com/rust-lang/crates.io-index" | 535 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -875,8 +884,9 @@ version = "0.1.0" | |||
875 | name = "ra_assists" | 884 | name = "ra_assists" |
876 | version = "0.1.0" | 885 | version = "0.1.0" |
877 | dependencies = [ | 886 | dependencies = [ |
887 | "either", | ||
878 | "format-buf", | 888 | "format-buf", |
879 | "itertools", | 889 | "itertools 0.9.0", |
880 | "join_to_string", | 890 | "join_to_string", |
881 | "ra_db", | 891 | "ra_db", |
882 | "ra_fmt", | 892 | "ra_fmt", |
@@ -928,7 +938,7 @@ dependencies = [ | |||
928 | name = "ra_fmt" | 938 | name = "ra_fmt" |
929 | version = "0.1.0" | 939 | version = "0.1.0" |
930 | dependencies = [ | 940 | dependencies = [ |
931 | "itertools", | 941 | "itertools 0.9.0", |
932 | "ra_syntax", | 942 | "ra_syntax", |
933 | ] | 943 | ] |
934 | 944 | ||
@@ -938,7 +948,7 @@ version = "0.1.0" | |||
938 | dependencies = [ | 948 | dependencies = [ |
939 | "arrayvec", | 949 | "arrayvec", |
940 | "either", | 950 | "either", |
941 | "itertools", | 951 | "itertools 0.9.0", |
942 | "log", | 952 | "log", |
943 | "ra_db", | 953 | "ra_db", |
944 | "ra_hir_def", | 954 | "ra_hir_def", |
@@ -1015,7 +1025,7 @@ dependencies = [ | |||
1015 | "format-buf", | 1025 | "format-buf", |
1016 | "indexmap", | 1026 | "indexmap", |
1017 | "insta", | 1027 | "insta", |
1018 | "itertools", | 1028 | "itertools 0.9.0", |
1019 | "join_to_string", | 1029 | "join_to_string", |
1020 | "log", | 1030 | "log", |
1021 | "ra_assists", | 1031 | "ra_assists", |
@@ -1036,6 +1046,7 @@ dependencies = [ | |||
1036 | name = "ra_ide_db" | 1046 | name = "ra_ide_db" |
1037 | version = "0.1.0" | 1047 | version = "0.1.0" |
1038 | dependencies = [ | 1048 | dependencies = [ |
1049 | "either", | ||
1039 | "fst", | 1050 | "fst", |
1040 | "log", | 1051 | "log", |
1041 | "once_cell", | 1052 | "once_cell", |
@@ -1101,7 +1112,7 @@ name = "ra_syntax" | |||
1101 | version = "0.1.0" | 1112 | version = "0.1.0" |
1102 | dependencies = [ | 1113 | dependencies = [ |
1103 | "arrayvec", | 1114 | "arrayvec", |
1104 | "itertools", | 1115 | "itertools 0.9.0", |
1105 | "once_cell", | 1116 | "once_cell", |
1106 | "ra_parser", | 1117 | "ra_parser", |
1107 | "ra_text_edit", | 1118 | "ra_text_edit", |
@@ -1278,7 +1289,7 @@ dependencies = [ | |||
1278 | "crossbeam-channel", | 1289 | "crossbeam-channel", |
1279 | "env_logger", | 1290 | "env_logger", |
1280 | "globset", | 1291 | "globset", |
1281 | "itertools", | 1292 | "itertools 0.9.0", |
1282 | "jod-thread", | 1293 | "jod-thread", |
1283 | "log", | 1294 | "log", |
1284 | "lsp-server", | 1295 | "lsp-server", |
diff --git a/crates/ra_assists/Cargo.toml b/crates/ra_assists/Cargo.toml index 85adddb5b..a87f4052a 100644 --- a/crates/ra_assists/Cargo.toml +++ b/crates/ra_assists/Cargo.toml | |||
@@ -11,7 +11,8 @@ doctest = false | |||
11 | format-buf = "1.0.0" | 11 | format-buf = "1.0.0" |
12 | join_to_string = "0.1.3" | 12 | join_to_string = "0.1.3" |
13 | rustc-hash = "1.1.0" | 13 | rustc-hash = "1.1.0" |
14 | itertools = "0.8.2" | 14 | itertools = "0.9.0" |
15 | either = "1.5.3" | ||
15 | 16 | ||
16 | ra_syntax = { path = "../ra_syntax" } | 17 | ra_syntax = { path = "../ra_syntax" } |
17 | ra_text_edit = { path = "../ra_text_edit" } | 18 | ra_text_edit = { path = "../ra_text_edit" } |
diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs index 62182cf03..c3e653299 100644 --- a/crates/ra_assists/src/assist_ctx.rs +++ b/crates/ra_assists/src/assist_ctx.rs | |||
@@ -11,6 +11,7 @@ use ra_syntax::{ | |||
11 | use ra_text_edit::TextEditBuilder; | 11 | use ra_text_edit::TextEditBuilder; |
12 | 12 | ||
13 | use crate::{AssistAction, AssistId, AssistLabel, GroupLabel, ResolvedAssist}; | 13 | use crate::{AssistAction, AssistId, AssistLabel, GroupLabel, ResolvedAssist}; |
14 | use algo::SyntaxRewriter; | ||
14 | 15 | ||
15 | #[derive(Clone, Debug)] | 16 | #[derive(Clone, Debug)] |
16 | pub(crate) struct Assist(pub(crate) Vec<AssistInfo>); | 17 | pub(crate) struct Assist(pub(crate) Vec<AssistInfo>); |
@@ -234,6 +235,11 @@ impl ActionBuilder { | |||
234 | pub(crate) fn replace_ast<N: AstNode>(&mut self, old: N, new: N) { | 235 | pub(crate) fn replace_ast<N: AstNode>(&mut self, old: N, new: N) { |
235 | algo::diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit) | 236 | algo::diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit) |
236 | } | 237 | } |
238 | pub(crate) fn rewrite(&mut self, rewriter: SyntaxRewriter) { | ||
239 | let node = rewriter.rewrite_root().unwrap(); | ||
240 | let new = rewriter.rewrite(&node); | ||
241 | algo::diff(&node, &new).into_text_edit(&mut self.edit) | ||
242 | } | ||
237 | 243 | ||
238 | fn build(self) -> AssistAction { | 244 | fn build(self) -> AssistAction { |
239 | AssistAction { | 245 | AssistAction { |
diff --git a/crates/ra_assists/src/ast_transform.rs b/crates/ra_assists/src/ast_transform.rs index 45558c448..52b4c82db 100644 --- a/crates/ra_assists/src/ast_transform.rs +++ b/crates/ra_assists/src/ast_transform.rs | |||
@@ -3,7 +3,10 @@ use rustc_hash::FxHashMap; | |||
3 | 3 | ||
4 | use hir::{PathResolution, SemanticsScope}; | 4 | use hir::{PathResolution, SemanticsScope}; |
5 | use ra_ide_db::RootDatabase; | 5 | use ra_ide_db::RootDatabase; |
6 | use ra_syntax::ast::{self, AstNode}; | 6 | use ra_syntax::{ |
7 | algo::SyntaxRewriter, | ||
8 | ast::{self, AstNode}, | ||
9 | }; | ||
7 | 10 | ||
8 | pub trait AstTransform<'a> { | 11 | pub trait AstTransform<'a> { |
9 | fn get_substitution(&self, node: &ra_syntax::SyntaxNode) -> Option<ra_syntax::SyntaxNode>; | 12 | fn get_substitution(&self, node: &ra_syntax::SyntaxNode) -> Option<ra_syntax::SyntaxNode>; |
@@ -153,15 +156,14 @@ impl<'a> QualifyPaths<'a> { | |||
153 | } | 156 | } |
154 | 157 | ||
155 | pub fn apply<'a, N: AstNode>(transformer: &dyn AstTransform<'a>, node: N) -> N { | 158 | pub fn apply<'a, N: AstNode>(transformer: &dyn AstTransform<'a>, node: N) -> N { |
156 | let syntax = node.syntax(); | 159 | SyntaxRewriter::from_fn(|element| match element { |
157 | let result = ra_syntax::algo::replace_descendants(syntax, |element| match element { | ||
158 | ra_syntax::SyntaxElement::Node(n) => { | 160 | ra_syntax::SyntaxElement::Node(n) => { |
159 | let replacement = transformer.get_substitution(&n)?; | 161 | let replacement = transformer.get_substitution(&n)?; |
160 | Some(replacement.into()) | 162 | Some(replacement.into()) |
161 | } | 163 | } |
162 | _ => None, | 164 | _ => None, |
163 | }); | 165 | }) |
164 | N::cast(result).unwrap() | 166 | .rewrite_ast(&node) |
165 | } | 167 | } |
166 | 168 | ||
167 | impl<'a> AstTransform<'a> for QualifyPaths<'a> { | 169 | impl<'a> AstTransform<'a> for QualifyPaths<'a> { |
diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs index aef6793e8..62dcb3808 100644 --- a/crates/ra_assists/src/doc_tests/generated.rs +++ b/crates/ra_assists/src/doc_tests/generated.rs | |||
@@ -275,8 +275,8 @@ enum Action { Move { distance: u32 }, Stop } | |||
275 | 275 | ||
276 | fn handle(action: Action) { | 276 | fn handle(action: Action) { |
277 | match action { | 277 | match action { |
278 | Action::Move { distance } => (), | 278 | Action::Move { distance } => {} |
279 | Action::Stop => (), | 279 | Action::Stop => {} |
280 | } | 280 | } |
281 | } | 281 | } |
282 | "#####, | 282 | "#####, |
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 e5920b6f6..722f207e2 100644 --- a/crates/ra_assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ra_assists/src/handlers/add_missing_impl_members.rs | |||
@@ -151,7 +151,7 @@ fn add_missing_impl_members_inner( | |||
151 | ast::ImplItem::FnDef(def) => ast::ImplItem::FnDef(add_body(def)), | 151 | ast::ImplItem::FnDef(def) => ast::ImplItem::FnDef(add_body(def)), |
152 | _ => it, | 152 | _ => it, |
153 | }) | 153 | }) |
154 | .map(|it| edit::strip_attrs_and_docs(&it)); | 154 | .map(|it| edit::remove_attrs_and_docs(&it)); |
155 | let new_impl_item_list = impl_item_list.append_items(items); | 155 | let new_impl_item_list = impl_item_list.append_items(items); |
156 | let cursor_position = { | 156 | let cursor_position = { |
157 | let first_new_item = new_impl_item_list.impl_items().nth(n_existing_items).unwrap(); | 157 | let first_new_item = new_impl_item_list.impl_items().nth(n_existing_items).unwrap(); |
diff --git a/crates/ra_assists/src/handlers/auto_import.rs b/crates/ra_assists/src/handlers/auto_import.rs index bb280f633..99682e023 100644 --- a/crates/ra_assists/src/handlers/auto_import.rs +++ b/crates/ra_assists/src/handlers/auto_import.rs | |||
@@ -17,6 +17,7 @@ use crate::{ | |||
17 | utils::insert_use_statement, | 17 | utils::insert_use_statement, |
18 | AssistId, | 18 | AssistId, |
19 | }; | 19 | }; |
20 | use either::Either; | ||
20 | 21 | ||
21 | // Assist: auto_import | 22 | // Assist: auto_import |
22 | // | 23 | // |
@@ -58,6 +59,7 @@ pub(crate) fn auto_import(ctx: AssistCtx) -> Option<Assist> { | |||
58 | group.finish() | 59 | group.finish() |
59 | } | 60 | } |
60 | 61 | ||
62 | #[derive(Debug)] | ||
61 | struct AutoImportAssets { | 63 | struct AutoImportAssets { |
62 | import_candidate: ImportCandidate, | 64 | import_candidate: ImportCandidate, |
63 | module_with_name_to_import: Module, | 65 | module_with_name_to_import: Module, |
@@ -127,14 +129,14 @@ impl AutoImportAssets { | |||
127 | ImportsLocator::new(db) | 129 | ImportsLocator::new(db) |
128 | .find_imports(&self.get_search_query()) | 130 | .find_imports(&self.get_search_query()) |
129 | .into_iter() | 131 | .into_iter() |
130 | .filter_map(|module_def| match &self.import_candidate { | 132 | .filter_map(|candidate| match &self.import_candidate { |
131 | ImportCandidate::TraitAssocItem(assoc_item_type, _) => { | 133 | ImportCandidate::TraitAssocItem(assoc_item_type, _) => { |
132 | let located_assoc_item = match module_def { | 134 | let located_assoc_item = match candidate { |
133 | ModuleDef::Function(located_function) => located_function | 135 | Either::Left(ModuleDef::Function(located_function)) => located_function |
134 | .as_assoc_item(db) | 136 | .as_assoc_item(db) |
135 | .map(|assoc| assoc.container(db)) | 137 | .map(|assoc| assoc.container(db)) |
136 | .and_then(Self::assoc_to_trait), | 138 | .and_then(Self::assoc_to_trait), |
137 | ModuleDef::Const(located_const) => located_const | 139 | Either::Left(ModuleDef::Const(located_const)) => located_const |
138 | .as_assoc_item(db) | 140 | .as_assoc_item(db) |
139 | .map(|assoc| assoc.container(db)) | 141 | .map(|assoc| assoc.container(db)) |
140 | .and_then(Self::assoc_to_trait), | 142 | .and_then(Self::assoc_to_trait), |
@@ -153,10 +155,11 @@ impl AutoImportAssets { | |||
153 | |_, assoc| Self::assoc_to_trait(assoc.container(db)), | 155 | |_, assoc| Self::assoc_to_trait(assoc.container(db)), |
154 | ) | 156 | ) |
155 | .map(ModuleDef::from) | 157 | .map(ModuleDef::from) |
158 | .map(Either::Left) | ||
156 | } | 159 | } |
157 | ImportCandidate::TraitMethod(function_callee, _) => { | 160 | ImportCandidate::TraitMethod(function_callee, _) => { |
158 | let located_assoc_item = | 161 | let located_assoc_item = |
159 | if let ModuleDef::Function(located_function) = module_def { | 162 | if let Either::Left(ModuleDef::Function(located_function)) = candidate { |
160 | located_function | 163 | located_function |
161 | .as_assoc_item(db) | 164 | .as_assoc_item(db) |
162 | .map(|assoc| assoc.container(db)) | 165 | .map(|assoc| assoc.container(db)) |
@@ -179,10 +182,18 @@ impl AutoImportAssets { | |||
179 | }, | 182 | }, |
180 | ) | 183 | ) |
181 | .map(ModuleDef::from) | 184 | .map(ModuleDef::from) |
185 | .map(Either::Left) | ||
186 | } | ||
187 | _ => Some(candidate), | ||
188 | }) | ||
189 | .filter_map(|candidate| match candidate { | ||
190 | Either::Left(module_def) => { | ||
191 | self.module_with_name_to_import.find_use_path(db, module_def) | ||
192 | } | ||
193 | Either::Right(macro_def) => { | ||
194 | self.module_with_name_to_import.find_use_path(db, macro_def) | ||
182 | } | 195 | } |
183 | _ => Some(module_def), | ||
184 | }) | 196 | }) |
185 | .filter_map(|module_def| self.module_with_name_to_import.find_use_path(db, module_def)) | ||
186 | .filter(|use_path| !use_path.segments.is_empty()) | 197 | .filter(|use_path| !use_path.segments.is_empty()) |
187 | .take(20) | 198 | .take(20) |
188 | .collect::<BTreeSet<_>>() | 199 | .collect::<BTreeSet<_>>() |
@@ -440,6 +451,30 @@ mod tests { | |||
440 | } | 451 | } |
441 | 452 | ||
442 | #[test] | 453 | #[test] |
454 | fn macro_import() { | ||
455 | check_assist( | ||
456 | auto_import, | ||
457 | r" | ||
458 | //- /lib.rs crate:crate_with_macro | ||
459 | #[macro_export] | ||
460 | macro_rules! foo { | ||
461 | () => () | ||
462 | } | ||
463 | |||
464 | //- /main.rs crate:main deps:crate_with_macro | ||
465 | fn main() { | ||
466 | foo<|> | ||
467 | }", | ||
468 | r"use crate_with_macro::foo; | ||
469 | |||
470 | fn main() { | ||
471 | foo<|> | ||
472 | } | ||
473 | ", | ||
474 | ); | ||
475 | } | ||
476 | |||
477 | #[test] | ||
443 | fn auto_import_target() { | 478 | fn auto_import_target() { |
444 | check_assist_target( | 479 | check_assist_target( |
445 | auto_import, | 480 | auto_import, |
diff --git a/crates/ra_assists/src/handlers/change_visibility.rs b/crates/ra_assists/src/handlers/change_visibility.rs index 54e0a6c84..cd6d1ee6c 100644 --- a/crates/ra_assists/src/handlers/change_visibility.rs +++ b/crates/ra_assists/src/handlers/change_visibility.rs | |||
@@ -2,13 +2,14 @@ use ra_syntax::{ | |||
2 | ast::{self, NameOwner, VisibilityOwner}, | 2 | ast::{self, NameOwner, VisibilityOwner}, |
3 | AstNode, | 3 | AstNode, |
4 | SyntaxKind::{ | 4 | SyntaxKind::{ |
5 | ATTR, COMMENT, CONST_DEF, ENUM_DEF, FN_DEF, IDENT, MODULE, STRUCT_DEF, TRAIT_DEF, | 5 | ATTR, COMMENT, CONST_DEF, ENUM_DEF, FN_DEF, MODULE, STRUCT_DEF, TRAIT_DEF, VISIBILITY, |
6 | VISIBILITY, WHITESPACE, | 6 | WHITESPACE, |
7 | }, | 7 | }, |
8 | SyntaxNode, TextUnit, T, | 8 | SyntaxNode, TextUnit, T, |
9 | }; | 9 | }; |
10 | 10 | ||
11 | use crate::{Assist, AssistCtx, AssistId}; | 11 | use crate::{Assist, AssistCtx, AssistId}; |
12 | use test_utils::tested_by; | ||
12 | 13 | ||
13 | // Assist: change_visibility | 14 | // Assist: change_visibility |
14 | // | 15 | // |
@@ -47,13 +48,16 @@ fn add_vis(ctx: AssistCtx) -> Option<Assist> { | |||
47 | } | 48 | } |
48 | (vis_offset(&parent), keyword.text_range()) | 49 | (vis_offset(&parent), keyword.text_range()) |
49 | } else { | 50 | } else { |
50 | let ident = ctx.token_at_offset().find(|leaf| leaf.kind() == IDENT)?; | 51 | let field_name: ast::Name = ctx.find_node_at_offset()?; |
51 | let field = ident.parent().ancestors().find_map(ast::RecordFieldDef::cast)?; | 52 | let field = field_name.syntax().ancestors().find_map(ast::RecordFieldDef::cast)?; |
52 | if field.name()?.syntax().text_range() != ident.text_range() && field.visibility().is_some() | 53 | if field.name()? != field_name { |
53 | { | 54 | tested_by!(change_visibility_field_false_positive); |
54 | return None; | 55 | return None; |
55 | } | 56 | } |
56 | (vis_offset(field.syntax()), ident.text_range()) | 57 | if field.visibility().is_some() { |
58 | return None; | ||
59 | } | ||
60 | (vis_offset(field.syntax()), field_name.syntax().text_range()) | ||
57 | }; | 61 | }; |
58 | 62 | ||
59 | ctx.add_assist(AssistId("change_visibility"), "Change visibility to pub(crate)", |edit| { | 63 | ctx.add_assist(AssistId("change_visibility"), "Change visibility to pub(crate)", |edit| { |
@@ -98,8 +102,11 @@ fn change_vis(ctx: AssistCtx, vis: ast::Visibility) -> Option<Assist> { | |||
98 | 102 | ||
99 | #[cfg(test)] | 103 | #[cfg(test)] |
100 | mod tests { | 104 | mod tests { |
105 | use test_utils::covers; | ||
106 | |||
107 | use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target}; | ||
108 | |||
101 | use super::*; | 109 | use super::*; |
102 | use crate::helpers::{check_assist, check_assist_target}; | ||
103 | 110 | ||
104 | #[test] | 111 | #[test] |
105 | fn change_visibility_adds_pub_crate_to_items() { | 112 | fn change_visibility_adds_pub_crate_to_items() { |
@@ -120,8 +127,17 @@ mod tests { | |||
120 | fn change_visibility_works_with_struct_fields() { | 127 | fn change_visibility_works_with_struct_fields() { |
121 | check_assist( | 128 | check_assist( |
122 | change_visibility, | 129 | change_visibility, |
123 | "struct S { <|>field: u32 }", | 130 | r"struct S { <|>field: u32 }", |
124 | "struct S { <|>pub(crate) field: u32 }", | 131 | r"struct S { <|>pub(crate) field: u32 }", |
132 | ) | ||
133 | } | ||
134 | |||
135 | #[test] | ||
136 | fn change_visibility_field_false_positive() { | ||
137 | covers!(change_visibility_field_false_positive); | ||
138 | check_assist_not_applicable( | ||
139 | change_visibility, | ||
140 | r"struct S { field: [(); { let <|>x = ();}] }", | ||
125 | ) | 141 | ) |
126 | } | 142 | } |
127 | 143 | ||
@@ -144,7 +160,7 @@ mod tests { | |||
144 | fn change_visibility_handles_comment_attrs() { | 160 | fn change_visibility_handles_comment_attrs() { |
145 | check_assist( | 161 | check_assist( |
146 | change_visibility, | 162 | change_visibility, |
147 | " | 163 | r" |
148 | /// docs | 164 | /// docs |
149 | 165 | ||
150 | // comments | 166 | // comments |
@@ -152,7 +168,7 @@ mod tests { | |||
152 | #[derive(Debug)] | 168 | #[derive(Debug)] |
153 | <|>struct Foo; | 169 | <|>struct Foo; |
154 | ", | 170 | ", |
155 | " | 171 | r" |
156 | /// docs | 172 | /// docs |
157 | 173 | ||
158 | // comments | 174 | // comments |
diff --git a/crates/ra_assists/src/handlers/fill_match_arms.rs b/crates/ra_assists/src/handlers/fill_match_arms.rs index 7463b2af7..add82e5b1 100644 --- a/crates/ra_assists/src/handlers/fill_match_arms.rs +++ b/crates/ra_assists/src/handlers/fill_match_arms.rs | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | use std::iter; | 3 | use std::iter; |
4 | 4 | ||
5 | use hir::{Adt, HasSource, Semantics}; | 5 | use hir::{Adt, HasSource, ModuleDef, Semantics}; |
6 | use itertools::Itertools; | 6 | use itertools::Itertools; |
7 | use ra_ide_db::RootDatabase; | 7 | use ra_ide_db::RootDatabase; |
8 | 8 | ||
@@ -30,8 +30,8 @@ use ast::{MatchArm, Pat}; | |||
30 | // | 30 | // |
31 | // fn handle(action: Action) { | 31 | // fn handle(action: Action) { |
32 | // match action { | 32 | // match action { |
33 | // Action::Move { distance } => (), | 33 | // Action::Move { distance } => {} |
34 | // Action::Stop => (), | 34 | // Action::Stop => {} |
35 | // } | 35 | // } |
36 | // } | 36 | // } |
37 | // ``` | 37 | // ``` |
@@ -57,7 +57,7 @@ pub(crate) fn fill_match_arms(ctx: AssistCtx) -> Option<Assist> { | |||
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_unit())) | 60 | .map(|pat| make::match_arm(iter::once(pat), make::expr_empty_block())) |
61 | .collect() | 61 | .collect() |
62 | } else if let Some(enum_defs) = resolve_tuple_of_enum_def(&ctx.sema, &expr) { | 62 | } else if let Some(enum_defs) = resolve_tuple_of_enum_def(&ctx.sema, &expr) { |
63 | // Partial fill not currently supported for tuple of enums. | 63 | // Partial fill not currently supported for tuple of enums. |
@@ -86,7 +86,7 @@ pub(crate) fn fill_match_arms(ctx: AssistCtx) -> Option<Assist> { | |||
86 | ast::Pat::from(make::tuple_pat(patterns)) | 86 | ast::Pat::from(make::tuple_pat(patterns)) |
87 | }) | 87 | }) |
88 | .filter(|variant_pat| is_variant_missing(&mut arms, variant_pat)) | 88 | .filter(|variant_pat| is_variant_missing(&mut arms, variant_pat)) |
89 | .map(|pat| make::match_arm(iter::once(pat), make::expr_unit())) | 89 | .map(|pat| make::match_arm(iter::once(pat), make::expr_empty_block())) |
90 | .collect() | 90 | .collect() |
91 | } else { | 91 | } else { |
92 | return None; | 92 | return None; |
@@ -154,7 +154,7 @@ fn resolve_tuple_of_enum_def( | |||
154 | } | 154 | } |
155 | 155 | ||
156 | fn build_pat(db: &RootDatabase, module: hir::Module, var: hir::EnumVariant) -> Option<ast::Pat> { | 156 | fn build_pat(db: &RootDatabase, module: hir::Module, var: hir::EnumVariant) -> Option<ast::Pat> { |
157 | let path = crate::ast_transform::path_to_ast(module.find_use_path(db, var.into())?); | 157 | let path = crate::ast_transform::path_to_ast(module.find_use_path(db, ModuleDef::from(var))?); |
158 | 158 | ||
159 | // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though | 159 | // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though |
160 | let pat: ast::Pat = match var.source(db).value.kind() { | 160 | let pat: ast::Pat = match var.source(db).value.kind() { |
@@ -192,8 +192,8 @@ mod tests { | |||
192 | fn main() { | 192 | fn main() { |
193 | match A::As<|> { | 193 | match A::As<|> { |
194 | A::As, | 194 | A::As, |
195 | A::Bs{x,y:Some(_)} => (), | 195 | A::Bs{x,y:Some(_)} => {} |
196 | A::Cs(_, Some(_)) => (), | 196 | A::Cs(_, Some(_)) => {} |
197 | } | 197 | } |
198 | } | 198 | } |
199 | "#, | 199 | "#, |
@@ -227,8 +227,8 @@ mod tests { | |||
227 | } | 227 | } |
228 | fn main() { | 228 | fn main() { |
229 | match A::As<|> { | 229 | match A::As<|> { |
230 | A::Bs{x,y:Some(_)} => (), | 230 | A::Bs{x,y:Some(_)} => {} |
231 | A::Cs(_, Some(_)) => (), | 231 | A::Cs(_, Some(_)) => {} |
232 | } | 232 | } |
233 | } | 233 | } |
234 | "#, | 234 | "#, |
@@ -240,9 +240,9 @@ mod tests { | |||
240 | } | 240 | } |
241 | fn main() { | 241 | fn main() { |
242 | match <|>A::As { | 242 | match <|>A::As { |
243 | A::Bs{x,y:Some(_)} => (), | 243 | A::Bs{x,y:Some(_)} => {} |
244 | A::Cs(_, Some(_)) => (), | 244 | A::Cs(_, Some(_)) => {} |
245 | A::As => (), | 245 | A::As => {} |
246 | } | 246 | } |
247 | } | 247 | } |
248 | "#, | 248 | "#, |
@@ -261,7 +261,7 @@ mod tests { | |||
261 | } | 261 | } |
262 | fn main() { | 262 | fn main() { |
263 | match A::As<|> { | 263 | match A::As<|> { |
264 | A::Cs(_) | A::Bs => (), | 264 | A::Cs(_) | A::Bs => {} |
265 | } | 265 | } |
266 | } | 266 | } |
267 | "#, | 267 | "#, |
@@ -273,8 +273,8 @@ mod tests { | |||
273 | } | 273 | } |
274 | fn main() { | 274 | fn main() { |
275 | match <|>A::As { | 275 | match <|>A::As { |
276 | A::Cs(_) | A::Bs => (), | 276 | A::Cs(_) | A::Bs => {} |
277 | A::As => (), | 277 | A::As => {} |
278 | } | 278 | } |
279 | } | 279 | } |
280 | "#, | 280 | "#, |
@@ -299,8 +299,8 @@ mod tests { | |||
299 | } | 299 | } |
300 | fn main() { | 300 | fn main() { |
301 | match A::As<|> { | 301 | match A::As<|> { |
302 | A::Bs if 0 < 1 => (), | 302 | A::Bs if 0 < 1 => {} |
303 | A::Ds(_value) => (), | 303 | A::Ds(_value) => { let x = 1; } |
304 | A::Es(B::Xs) => (), | 304 | A::Es(B::Xs) => (), |
305 | } | 305 | } |
306 | } | 306 | } |
@@ -319,11 +319,11 @@ mod tests { | |||
319 | } | 319 | } |
320 | fn main() { | 320 | fn main() { |
321 | match <|>A::As { | 321 | match <|>A::As { |
322 | A::Bs if 0 < 1 => (), | 322 | A::Bs if 0 < 1 => {} |
323 | A::Ds(_value) => (), | 323 | A::Ds(_value) => { let x = 1; } |
324 | A::Es(B::Xs) => (), | 324 | A::Es(B::Xs) => (), |
325 | A::As => (), | 325 | A::As => {} |
326 | A::Cs => (), | 326 | A::Cs => {} |
327 | } | 327 | } |
328 | } | 328 | } |
329 | "#, | 329 | "#, |
@@ -360,11 +360,11 @@ mod tests { | |||
360 | fn main() { | 360 | fn main() { |
361 | let a = A::As; | 361 | let a = A::As; |
362 | match <|>a { | 362 | match <|>a { |
363 | A::As => (), | 363 | A::As => {} |
364 | A::Bs => (), | 364 | A::Bs => {} |
365 | A::Cs(_) => (), | 365 | A::Cs(_) => {} |
366 | A::Ds(_, _) => (), | 366 | A::Ds(_, _) => {} |
367 | A::Es { x, y } => (), | 367 | A::Es { x, y } => {} |
368 | } | 368 | } |
369 | } | 369 | } |
370 | "#, | 370 | "#, |
@@ -405,10 +405,10 @@ mod tests { | |||
405 | let a = A::One; | 405 | let a = A::One; |
406 | let b = B::One; | 406 | let b = B::One; |
407 | match <|>(a, b) { | 407 | match <|>(a, b) { |
408 | (A::One, B::One) => (), | 408 | (A::One, B::One) => {} |
409 | (A::One, B::Two) => (), | 409 | (A::One, B::Two) => {} |
410 | (A::Two, B::One) => (), | 410 | (A::Two, B::One) => {} |
411 | (A::Two, B::Two) => (), | 411 | (A::Two, B::Two) => {} |
412 | } | 412 | } |
413 | } | 413 | } |
414 | "#, | 414 | "#, |
@@ -449,10 +449,10 @@ mod tests { | |||
449 | let a = A::One; | 449 | let a = A::One; |
450 | let b = B::One; | 450 | let b = B::One; |
451 | match <|>(&a, &b) { | 451 | match <|>(&a, &b) { |
452 | (A::One, B::One) => (), | 452 | (A::One, B::One) => {} |
453 | (A::One, B::Two) => (), | 453 | (A::One, B::Two) => {} |
454 | (A::Two, B::One) => (), | 454 | (A::Two, B::One) => {} |
455 | (A::Two, B::Two) => (), | 455 | (A::Two, B::Two) => {} |
456 | } | 456 | } |
457 | } | 457 | } |
458 | "#, | 458 | "#, |
@@ -477,7 +477,7 @@ mod tests { | |||
477 | let a = A::One; | 477 | let a = A::One; |
478 | let b = B::One; | 478 | let b = B::One; |
479 | match (a<|>, b) { | 479 | match (a<|>, b) { |
480 | (A::Two, B::One) => (), | 480 | (A::Two, B::One) => {} |
481 | } | 481 | } |
482 | } | 482 | } |
483 | "#, | 483 | "#, |
@@ -502,10 +502,10 @@ mod tests { | |||
502 | let a = A::One; | 502 | let a = A::One; |
503 | let b = B::One; | 503 | let b = B::One; |
504 | match (a<|>, b) { | 504 | match (a<|>, b) { |
505 | (A::Two, B::One) => (), | 505 | (A::Two, B::One) => {} |
506 | (A::One, B::One) => (), | 506 | (A::One, B::One) => {} |
507 | (A::One, B::Two) => (), | 507 | (A::One, B::Two) => {} |
508 | (A::Two, B::Two) => (), | 508 | (A::Two, B::Two) => {} |
509 | } | 509 | } |
510 | } | 510 | } |
511 | "#, | 511 | "#, |
@@ -555,7 +555,7 @@ mod tests { | |||
555 | 555 | ||
556 | fn foo(a: &A) { | 556 | fn foo(a: &A) { |
557 | match <|>a { | 557 | match <|>a { |
558 | A::As => (), | 558 | A::As => {} |
559 | } | 559 | } |
560 | } | 560 | } |
561 | "#, | 561 | "#, |
@@ -580,7 +580,7 @@ mod tests { | |||
580 | 580 | ||
581 | fn foo(a: &mut A) { | 581 | fn foo(a: &mut A) { |
582 | match <|>a { | 582 | match <|>a { |
583 | A::Es { x, y } => (), | 583 | A::Es { x, y } => {} |
584 | } | 584 | } |
585 | } | 585 | } |
586 | "#, | 586 | "#, |
@@ -611,7 +611,7 @@ mod tests { | |||
611 | 611 | ||
612 | fn main() { | 612 | fn main() { |
613 | match E::X { | 613 | match E::X { |
614 | <|>_ => {}, | 614 | <|>_ => {} |
615 | } | 615 | } |
616 | } | 616 | } |
617 | "#, | 617 | "#, |
@@ -620,8 +620,8 @@ mod tests { | |||
620 | 620 | ||
621 | fn main() { | 621 | fn main() { |
622 | match <|>E::X { | 622 | match <|>E::X { |
623 | E::X => (), | 623 | E::X => {} |
624 | E::Y => (), | 624 | E::Y => {} |
625 | } | 625 | } |
626 | } | 626 | } |
627 | "#, | 627 | "#, |
@@ -648,8 +648,8 @@ mod tests { | |||
648 | 648 | ||
649 | fn main() { | 649 | fn main() { |
650 | match <|>X { | 650 | match <|>X { |
651 | X => (), | 651 | X => {} |
652 | foo::E::Y => (), | 652 | foo::E::Y => {} |
653 | } | 653 | } |
654 | } | 654 | } |
655 | "#, | 655 | "#, |
diff --git a/crates/ra_assists/src/handlers/merge_imports.rs b/crates/ra_assists/src/handlers/merge_imports.rs index 89bc975bd..9c57d1e30 100644 --- a/crates/ra_assists/src/handlers/merge_imports.rs +++ b/crates/ra_assists/src/handlers/merge_imports.rs | |||
@@ -1,9 +1,9 @@ | |||
1 | use std::iter::successors; | 1 | use std::iter::successors; |
2 | 2 | ||
3 | use ra_syntax::{ | 3 | use ra_syntax::{ |
4 | algo::neighbor, | 4 | algo::{neighbor, SyntaxRewriter}, |
5 | ast::{self, edit::AstNodeEdit, make}, | 5 | ast::{self, edit::AstNodeEdit, make}, |
6 | AstNode, AstToken, Direction, InsertPosition, SyntaxElement, TextRange, T, | 6 | AstNode, Direction, InsertPosition, SyntaxElement, T, |
7 | }; | 7 | }; |
8 | 8 | ||
9 | use crate::{Assist, AssistCtx, AssistId}; | 9 | use crate::{Assist, AssistCtx, AssistId}; |
@@ -22,9 +22,10 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
22 | // ``` | 22 | // ``` |
23 | pub(crate) fn merge_imports(ctx: AssistCtx) -> Option<Assist> { | 23 | pub(crate) fn merge_imports(ctx: AssistCtx) -> Option<Assist> { |
24 | let tree: ast::UseTree = ctx.find_node_at_offset()?; | 24 | let tree: ast::UseTree = ctx.find_node_at_offset()?; |
25 | let (new_tree, to_delete) = if let Some(use_item) = | 25 | let mut rewriter = SyntaxRewriter::default(); |
26 | tree.syntax().parent().and_then(ast::UseItem::cast) | 26 | let mut offset = ctx.frange.range.start(); |
27 | { | 27 | |
28 | if let Some(use_item) = tree.syntax().parent().and_then(ast::UseItem::cast) { | ||
28 | let (merged, to_delete) = next_prev() | 29 | let (merged, to_delete) = next_prev() |
29 | .filter_map(|dir| neighbor(&use_item, dir)) | 30 | .filter_map(|dir| neighbor(&use_item, dir)) |
30 | .filter_map(|it| Some((it.clone(), it.use_tree()?))) | 31 | .filter_map(|it| Some((it.clone(), it.use_tree()?))) |
@@ -32,42 +33,28 @@ pub(crate) fn merge_imports(ctx: AssistCtx) -> Option<Assist> { | |||
32 | Some((try_merge_trees(&tree, &use_tree)?, use_item.clone())) | 33 | Some((try_merge_trees(&tree, &use_tree)?, use_item.clone())) |
33 | })?; | 34 | })?; |
34 | 35 | ||
35 | let mut range = to_delete.syntax().text_range(); | 36 | rewriter.replace_ast(&tree, &merged); |
36 | let next_ws = to_delete | 37 | rewriter += to_delete.remove(); |
37 | .syntax() | 38 | |
38 | .next_sibling_or_token() | 39 | if to_delete.syntax().text_range().end() < offset { |
39 | .and_then(|it| it.into_token()) | 40 | offset -= to_delete.syntax().text_range().len(); |
40 | .and_then(ast::Whitespace::cast); | ||
41 | if let Some(ws) = next_ws { | ||
42 | range = range.extend_to(&ws.syntax().text_range()) | ||
43 | } | 41 | } |
44 | (merged, range) | ||
45 | } else { | 42 | } else { |
46 | let (merged, to_delete) = next_prev() | 43 | let (merged, to_delete) = next_prev() |
47 | .filter_map(|dir| neighbor(&tree, dir)) | 44 | .filter_map(|dir| neighbor(&tree, dir)) |
48 | .find_map(|use_tree| Some((try_merge_trees(&tree, &use_tree)?, use_tree.clone())))?; | 45 | .find_map(|use_tree| Some((try_merge_trees(&tree, &use_tree)?, use_tree.clone())))?; |
49 | 46 | ||
50 | let mut range = to_delete.syntax().text_range(); | 47 | rewriter.replace_ast(&tree, &merged); |
51 | if let Some((dir, nb)) = next_prev().find_map(|dir| Some((dir, neighbor(&to_delete, dir)?))) | 48 | rewriter += to_delete.remove(); |
52 | { | 49 | |
53 | let nb_range = nb.syntax().text_range(); | 50 | if to_delete.syntax().text_range().end() < offset { |
54 | if dir == Direction::Prev { | 51 | offset -= to_delete.syntax().text_range().len(); |
55 | range = TextRange::from_to(nb_range.end(), range.end()); | ||
56 | } else { | ||
57 | range = TextRange::from_to(range.start(), nb_range.start()); | ||
58 | } | ||
59 | } | 52 | } |
60 | (merged, range) | ||
61 | }; | 53 | }; |
62 | 54 | ||
63 | let mut offset = ctx.frange.range.start(); | ||
64 | ctx.add_assist(AssistId("merge_imports"), "Merge imports", |edit| { | 55 | ctx.add_assist(AssistId("merge_imports"), "Merge imports", |edit| { |
65 | edit.replace_ast(tree, new_tree); | 56 | edit.rewrite(rewriter); |
66 | edit.delete(to_delete); | 57 | // FIXME: we only need because our diff is imprecise |
67 | |||
68 | if to_delete.end() <= offset { | ||
69 | offset -= to_delete.len(); | ||
70 | } | ||
71 | edit.set_cursor(offset); | 58 | edit.set_cursor(offset); |
72 | }) | 59 | }) |
73 | } | 60 | } |
@@ -156,7 +143,7 @@ use std::fmt::Debug; | |||
156 | use std::fmt<|>::Display; | 143 | use std::fmt<|>::Display; |
157 | ", | 144 | ", |
158 | r" | 145 | r" |
159 | use std::fmt<|>::{Display, Debug}; | 146 | use std::fmt:<|>:{Display, Debug}; |
160 | ", | 147 | ", |
161 | ); | 148 | ); |
162 | } | 149 | } |
@@ -178,7 +165,57 @@ use std::{fmt<|>::{Debug, Display}}; | |||
178 | use std::{fmt::Debug, fmt<|>::Display}; | 165 | use std::{fmt::Debug, fmt<|>::Display}; |
179 | ", | 166 | ", |
180 | r" | 167 | r" |
181 | use std::{fmt<|>::{Display, Debug}}; | 168 | use std::{fmt::<|>{Display, Debug}}; |
169 | ", | ||
170 | ); | ||
171 | } | ||
172 | |||
173 | #[test] | ||
174 | fn removes_just_enough_whitespace() { | ||
175 | check_assist( | ||
176 | merge_imports, | ||
177 | r" | ||
178 | use foo<|>::bar; | ||
179 | use foo::baz; | ||
180 | |||
181 | /// Doc comment | ||
182 | ", | ||
183 | r" | ||
184 | use foo<|>::{bar, baz}; | ||
185 | |||
186 | /// Doc comment | ||
187 | ", | ||
188 | ); | ||
189 | } | ||
190 | |||
191 | #[test] | ||
192 | fn works_with_trailing_comma() { | ||
193 | check_assist( | ||
194 | merge_imports, | ||
195 | r" | ||
196 | use { | ||
197 | foo<|>::bar, | ||
198 | foo::baz, | ||
199 | }; | ||
200 | ", | ||
201 | r" | ||
202 | use { | ||
203 | foo<|>::{bar, baz}, | ||
204 | }; | ||
205 | ", | ||
206 | ); | ||
207 | check_assist( | ||
208 | merge_imports, | ||
209 | r" | ||
210 | use { | ||
211 | foo::baz, | ||
212 | foo<|>::bar, | ||
213 | }; | ||
214 | ", | ||
215 | r" | ||
216 | use { | ||
217 | foo::{bar<|>, baz}, | ||
218 | }; | ||
182 | ", | 219 | ", |
183 | ); | 220 | ); |
184 | } | 221 | } |
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index b8704ea7d..bcc9b3f10 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs | |||
@@ -165,7 +165,6 @@ mod helpers { | |||
165 | 165 | ||
166 | use ra_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt}; | 166 | use ra_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt}; |
167 | use ra_ide_db::{symbol_index::SymbolsDatabase, RootDatabase}; | 167 | use ra_ide_db::{symbol_index::SymbolsDatabase, RootDatabase}; |
168 | use ra_syntax::TextRange; | ||
169 | use test_utils::{add_cursor, assert_eq_text, extract_range_or_offset, RangeOrOffset}; | 168 | use test_utils::{add_cursor, assert_eq_text, extract_range_or_offset, RangeOrOffset}; |
170 | 169 | ||
171 | use crate::{AssistCtx, AssistHandler}; | 170 | use crate::{AssistCtx, AssistHandler}; |
@@ -175,8 +174,7 @@ mod helpers { | |||
175 | let (mut db, file_id) = RootDatabase::with_single_file(text); | 174 | let (mut db, file_id) = RootDatabase::with_single_file(text); |
176 | // FIXME: ideally, this should be done by the above `RootDatabase::with_single_file`, | 175 | // FIXME: ideally, this should be done by the above `RootDatabase::with_single_file`, |
177 | // but it looks like this might need specialization? :( | 176 | // but it looks like this might need specialization? :( |
178 | let local_roots = vec![db.file_source_root(file_id)]; | 177 | db.set_local_roots(Arc::new(vec![db.file_source_root(file_id)])); |
179 | db.set_local_roots(Arc::new(local_roots)); | ||
180 | (db, file_id) | 178 | (db, file_id) |
181 | } | 179 | } |
182 | 180 | ||
@@ -206,11 +204,24 @@ mod helpers { | |||
206 | } | 204 | } |
207 | 205 | ||
208 | fn check(assist: AssistHandler, before: &str, expected: ExpectedResult) { | 206 | fn check(assist: AssistHandler, before: &str, expected: ExpectedResult) { |
209 | let (range_or_offset, before) = extract_range_or_offset(before); | 207 | let (text_without_caret, file_with_caret_id, range_or_offset, db) = |
210 | let range: TextRange = range_or_offset.into(); | 208 | if before.contains("//-") { |
209 | let (mut db, position) = RootDatabase::with_position(before); | ||
210 | db.set_local_roots(Arc::new(vec![db.file_source_root(position.file_id)])); | ||
211 | ( | ||
212 | db.file_text(position.file_id).as_ref().to_owned(), | ||
213 | position.file_id, | ||
214 | RangeOrOffset::Offset(position.offset), | ||
215 | db, | ||
216 | ) | ||
217 | } else { | ||
218 | let (range_or_offset, text_without_caret) = extract_range_or_offset(before); | ||
219 | let (db, file_id) = with_single_file(&text_without_caret); | ||
220 | (text_without_caret, file_id, range_or_offset, db) | ||
221 | }; | ||
222 | |||
223 | let frange = FileRange { file_id: file_with_caret_id, range: range_or_offset.into() }; | ||
211 | 224 | ||
212 | let (db, file_id) = with_single_file(&before); | ||
213 | let frange = FileRange { file_id, range }; | ||
214 | let sema = Semantics::new(&db); | 225 | let sema = Semantics::new(&db); |
215 | let assist_ctx = AssistCtx::new(&sema, frange, true); | 226 | let assist_ctx = AssistCtx::new(&sema, frange, true); |
216 | 227 | ||
@@ -218,7 +229,7 @@ mod helpers { | |||
218 | (Some(assist), ExpectedResult::After(after)) => { | 229 | (Some(assist), ExpectedResult::After(after)) => { |
219 | let action = assist.0[0].action.clone().unwrap(); | 230 | let action = assist.0[0].action.clone().unwrap(); |
220 | 231 | ||
221 | let mut actual = action.edit.apply(&before); | 232 | let mut actual = action.edit.apply(&text_without_caret); |
222 | match action.cursor_position { | 233 | match action.cursor_position { |
223 | None => { | 234 | None => { |
224 | if let RangeOrOffset::Offset(before_cursor_pos) = range_or_offset { | 235 | if let RangeOrOffset::Offset(before_cursor_pos) = range_or_offset { |
@@ -237,7 +248,7 @@ mod helpers { | |||
237 | (Some(assist), ExpectedResult::Target(target)) => { | 248 | (Some(assist), ExpectedResult::Target(target)) => { |
238 | let action = assist.0[0].action.clone().unwrap(); | 249 | let action = assist.0[0].action.clone().unwrap(); |
239 | let range = action.target.expect("expected target on action"); | 250 | let range = action.target.expect("expected target on action"); |
240 | assert_eq_text!(&before[range], target); | 251 | assert_eq_text!(&text_without_caret[range], target); |
241 | } | 252 | } |
242 | (Some(_), ExpectedResult::NotApplicable) => panic!("assist should not be applicable!"), | 253 | (Some(_), ExpectedResult::NotApplicable) => panic!("assist should not be applicable!"), |
243 | (None, ExpectedResult::After(_)) | (None, ExpectedResult::Target(_)) => { | 254 | (None, ExpectedResult::After(_)) | (None, ExpectedResult::Target(_)) => { |
diff --git a/crates/ra_assists/src/marks.rs b/crates/ra_assists/src/marks.rs index 22404ee80..6c2a2b8b6 100644 --- a/crates/ra_assists/src/marks.rs +++ b/crates/ra_assists/src/marks.rs | |||
@@ -7,4 +7,5 @@ test_utils::marks![ | |||
7 | not_applicable_outside_of_bind_pat | 7 | not_applicable_outside_of_bind_pat |
8 | test_not_inline_mut_variable | 8 | test_not_inline_mut_variable |
9 | test_not_applicable_if_variable_unused | 9 | test_not_applicable_if_variable_unused |
10 | change_visibility_field_false_positive | ||
10 | ]; | 11 | ]; |
diff --git a/crates/ra_fmt/Cargo.toml b/crates/ra_fmt/Cargo.toml index ea9befeaf..e9d057afc 100644 --- a/crates/ra_fmt/Cargo.toml +++ b/crates/ra_fmt/Cargo.toml | |||
@@ -9,6 +9,6 @@ publish = false | |||
9 | doctest = false | 9 | doctest = false |
10 | 10 | ||
11 | [dependencies] | 11 | [dependencies] |
12 | itertools = "0.8.2" | 12 | itertools = "0.9.0" |
13 | 13 | ||
14 | ra_syntax = { path = "../ra_syntax" } | 14 | ra_syntax = { path = "../ra_syntax" } |
diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml index 42193b492..ba7b39a19 100644 --- a/crates/ra_hir/Cargo.toml +++ b/crates/ra_hir/Cargo.toml | |||
@@ -13,7 +13,7 @@ rustc-hash = "1.1.0" | |||
13 | either = "1.5.3" | 13 | either = "1.5.3" |
14 | arrayvec = "0.5.1" | 14 | arrayvec = "0.5.1" |
15 | 15 | ||
16 | itertools = "0.8.2" | 16 | itertools = "0.9.0" |
17 | 17 | ||
18 | ra_syntax = { path = "../ra_syntax" } | 18 | ra_syntax = { path = "../ra_syntax" } |
19 | ra_db = { path = "../ra_db" } | 19 | ra_db = { path = "../ra_db" } |
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index e91abf6f5..cd2a8fc62 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -33,7 +33,11 @@ use ra_syntax::{ | |||
33 | }; | 33 | }; |
34 | use rustc_hash::FxHashSet; | 34 | use rustc_hash::FxHashSet; |
35 | 35 | ||
36 | use crate::{db::HirDatabase, has_source::HasSource, CallableDef, HirDisplay, InFile, Name}; | 36 | use crate::{ |
37 | db::{DefDatabase, HirDatabase}, | ||
38 | has_source::HasSource, | ||
39 | CallableDef, HirDisplay, InFile, Name, | ||
40 | }; | ||
37 | 41 | ||
38 | /// hir::Crate describes a single crate. It's the main interface with which | 42 | /// hir::Crate describes a single crate. It's the main interface with which |
39 | /// a crate's dependencies interact. Mostly, it should be just a proxy for the | 43 | /// a crate's dependencies interact. Mostly, it should be just a proxy for the |
@@ -230,6 +234,10 @@ impl Module { | |||
230 | .collect() | 234 | .collect() |
231 | } | 235 | } |
232 | 236 | ||
237 | pub fn visibility_of(self, db: &dyn HirDatabase, def: &ModuleDef) -> Option<Visibility> { | ||
238 | db.crate_def_map(self.id.krate)[self.id.local_id].scope.visibility_of(def.clone().into()) | ||
239 | } | ||
240 | |||
233 | pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { | 241 | pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { |
234 | let _p = profile("Module::diagnostics"); | 242 | let _p = profile("Module::diagnostics"); |
235 | let crate_def_map = db.crate_def_map(self.id.krate); | 243 | let crate_def_map = db.crate_def_map(self.id.krate); |
@@ -274,20 +282,10 @@ impl Module { | |||
274 | /// this module, if possible. | 282 | /// this module, if possible. |
275 | pub fn find_use_path( | 283 | pub fn find_use_path( |
276 | self, | 284 | self, |
277 | db: &dyn HirDatabase, | 285 | db: &dyn DefDatabase, |
278 | item: ModuleDef, | 286 | item: impl Into<ItemInNs>, |
279 | ) -> Option<hir_def::path::ModPath> { | 287 | ) -> Option<hir_def::path::ModPath> { |
280 | // FIXME expose namespace choice | 288 | hir_def::find_path::find_path(db, item.into(), self.into()) |
281 | hir_def::find_path::find_path(db.upcast(), determine_item_namespace(item), self.into()) | ||
282 | } | ||
283 | } | ||
284 | |||
285 | fn determine_item_namespace(module_def: ModuleDef) -> ItemInNs { | ||
286 | match module_def { | ||
287 | ModuleDef::Static(_) | ModuleDef::Const(_) | ModuleDef::Function(_) => { | ||
288 | ItemInNs::Values(module_def.into()) | ||
289 | } | ||
290 | _ => ItemInNs::Types(module_def.into()), | ||
291 | } | 289 | } |
292 | } | 290 | } |
293 | 291 | ||
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index fcba95091..ec931b34f 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -10,15 +10,16 @@ pub use hir_def::db::{ | |||
10 | TraitDataQuery, TypeAliasDataQuery, UnionDataQuery, | 10 | TraitDataQuery, TypeAliasDataQuery, UnionDataQuery, |
11 | }; | 11 | }; |
12 | pub use hir_expand::db::{ | 12 | pub use hir_expand::db::{ |
13 | AstDatabase, AstDatabaseStorage, AstIdMapQuery, InternMacroQuery, MacroArgQuery, MacroDefQuery, | 13 | AstDatabase, AstDatabaseStorage, AstIdMapQuery, InternEagerExpansionQuery, InternMacroQuery, |
14 | MacroExpandQuery, ParseMacroQuery, | 14 | MacroArgQuery, MacroDefQuery, MacroExpandQuery, ParseMacroQuery, |
15 | }; | 15 | }; |
16 | pub use hir_ty::db::{ | 16 | pub 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, ImplsForTraitQuery, | 19 | HirDatabaseStorage, ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, ImplsForTraitQuery, |
20 | ImplsInCrateQuery, InferQueryQuery, InternAssocTyValueQuery, InternChalkImplQuery, | 20 | ImplsInCrateQuery, InferQueryQuery, InternAssocTyValueQuery, InternChalkImplQuery, |
21 | InternTypeCtorQuery, StructDatumQuery, TraitDatumQuery, TraitSolveQuery, TyQuery, ValueTyQuery, | 21 | InternTypeCtorQuery, InternTypeParamIdQuery, StructDatumQuery, TraitDatumQuery, |
22 | TraitSolveQuery, TyQuery, ValueTyQuery, | ||
22 | }; | 23 | }; |
23 | 24 | ||
24 | #[test] | 25 | #[test] |
diff --git a/crates/ra_hir/src/from_id.rs b/crates/ra_hir/src/from_id.rs index c179b13c6..62fb52e72 100644 --- a/crates/ra_hir/src/from_id.rs +++ b/crates/ra_hir/src/from_id.rs | |||
@@ -9,8 +9,8 @@ use hir_def::{ | |||
9 | }; | 9 | }; |
10 | 10 | ||
11 | use crate::{ | 11 | use crate::{ |
12 | Adt, AssocItem, AttrDef, DefWithBody, EnumVariant, GenericDef, Local, ModuleDef, StructField, | 12 | code_model::ItemInNs, Adt, AssocItem, AttrDef, DefWithBody, EnumVariant, GenericDef, Local, |
13 | VariantDef, | 13 | MacroDef, ModuleDef, StructField, VariantDef, |
14 | }; | 14 | }; |
15 | 15 | ||
16 | macro_rules! from_id { | 16 | macro_rules! from_id { |
@@ -228,3 +228,20 @@ impl From<(DefWithBodyId, PatId)> for Local { | |||
228 | Local { parent, pat_id } | 228 | Local { parent, pat_id } |
229 | } | 229 | } |
230 | } | 230 | } |
231 | |||
232 | impl From<MacroDef> for ItemInNs { | ||
233 | fn from(macro_def: MacroDef) -> Self { | ||
234 | ItemInNs::Macros(macro_def.into()) | ||
235 | } | ||
236 | } | ||
237 | |||
238 | impl From<ModuleDef> for ItemInNs { | ||
239 | fn from(module_def: ModuleDef) -> Self { | ||
240 | match module_def { | ||
241 | ModuleDef::Static(_) | ModuleDef::Const(_) | ModuleDef::Function(_) => { | ||
242 | ItemInNs::Values(module_def.into()) | ||
243 | } | ||
244 | _ => ItemInNs::Types(module_def.into()), | ||
245 | } | ||
246 | } | ||
247 | } | ||
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 713d45f48..5af7e5d6d 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -54,7 +54,7 @@ pub use crate::{ | |||
54 | Adt, AsAssocItem, AssocItem, AssocItemContainer, AttrDef, Const, Crate, CrateDependency, | 54 | Adt, AsAssocItem, AssocItem, AssocItemContainer, AttrDef, Const, Crate, CrateDependency, |
55 | DefWithBody, Docs, Enum, EnumVariant, FieldSource, Function, GenericDef, HasAttrs, | 55 | DefWithBody, Docs, Enum, EnumVariant, FieldSource, Function, GenericDef, HasAttrs, |
56 | HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, ScopeDef, Static, Struct, | 56 | HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, ScopeDef, Static, Struct, |
57 | StructField, Trait, Type, TypeAlias, TypeParam, Union, VariantDef, | 57 | StructField, Trait, Type, TypeAlias, TypeParam, Union, VariantDef, Visibility, |
58 | }, | 58 | }, |
59 | has_source::HasSource, | 59 | has_source::HasSource, |
60 | semantics::{original_range, PathResolution, Semantics, SemanticsScope}, | 60 | semantics::{original_range, PathResolution, Semantics, SemanticsScope}, |
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index d982f6ffa..16a5fe968 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs | |||
@@ -173,11 +173,11 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
173 | } | 173 | } |
174 | 174 | ||
175 | pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { | 175 | pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { |
176 | self.analyze(call.syntax()).resolve_method_call(call) | 176 | self.analyze(call.syntax()).resolve_method_call(self.db, call) |
177 | } | 177 | } |
178 | 178 | ||
179 | pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<StructField> { | 179 | pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<StructField> { |
180 | self.analyze(field.syntax()).resolve_field(field) | 180 | self.analyze(field.syntax()).resolve_field(self.db, field) |
181 | } | 181 | } |
182 | 182 | ||
183 | pub fn resolve_record_field( | 183 | pub fn resolve_record_field( |
@@ -188,7 +188,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
188 | } | 188 | } |
189 | 189 | ||
190 | pub fn resolve_record_literal(&self, record_lit: &ast::RecordLit) -> Option<VariantDef> { | 190 | pub fn resolve_record_literal(&self, record_lit: &ast::RecordLit) -> Option<VariantDef> { |
191 | self.analyze(record_lit.syntax()).resolve_record_literal(record_lit) | 191 | self.analyze(record_lit.syntax()).resolve_record_literal(self.db, record_lit) |
192 | } | 192 | } |
193 | 193 | ||
194 | pub fn resolve_record_pattern(&self, record_pat: &ast::RecordPat) -> Option<VariantDef> { | 194 | pub fn resolve_record_pattern(&self, record_pat: &ast::RecordPat) -> Option<VariantDef> { |
diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs index 10c12c910..815ca158c 100644 --- a/crates/ra_hir/src/source_analyzer.rs +++ b/crates/ra_hir/src/source_analyzer.rs | |||
@@ -78,9 +78,15 @@ impl SourceAnalyzer { | |||
78 | } | 78 | } |
79 | } | 79 | } |
80 | 80 | ||
81 | fn expr_id(&self, expr: &ast::Expr) -> Option<ExprId> { | 81 | fn expr_id(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<ExprId> { |
82 | let src = InFile { file_id: self.file_id, value: expr }; | 82 | let src = match expr { |
83 | self.body_source_map.as_ref()?.node_expr(src) | 83 | ast::Expr::MacroCall(call) => { |
84 | self.expand_expr(db, InFile::new(self.file_id, call.clone()))? | ||
85 | } | ||
86 | _ => InFile::new(self.file_id, expr.clone()), | ||
87 | }; | ||
88 | let sm = self.body_source_map.as_ref()?; | ||
89 | sm.node_expr(src.as_ref()) | ||
84 | } | 90 | } |
85 | 91 | ||
86 | fn pat_id(&self, pat: &ast::Pat) -> Option<PatId> { | 92 | fn pat_id(&self, pat: &ast::Pat) -> Option<PatId> { |
@@ -104,14 +110,7 @@ impl SourceAnalyzer { | |||
104 | } | 110 | } |
105 | 111 | ||
106 | pub(crate) fn type_of(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<Type> { | 112 | pub(crate) fn type_of(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<Type> { |
107 | let expr_id = match expr { | 113 | let expr_id = self.expr_id(db, expr)?; |
108 | ast::Expr::MacroCall(call) => { | ||
109 | let expr = self.expand_expr(db, InFile::new(self.file_id, call.clone()))?; | ||
110 | self.body_source_map.as_ref()?.node_expr(expr.as_ref()) | ||
111 | } | ||
112 | _ => self.expr_id(expr), | ||
113 | }?; | ||
114 | |||
115 | let ty = self.infer.as_ref()?[expr_id].clone(); | 114 | let ty = self.infer.as_ref()?[expr_id].clone(); |
116 | Type::new_with_resolver(db, &self.resolver, ty) | 115 | Type::new_with_resolver(db, &self.resolver, ty) |
117 | } | 116 | } |
@@ -122,13 +121,21 @@ impl SourceAnalyzer { | |||
122 | Type::new_with_resolver(db, &self.resolver, ty) | 121 | Type::new_with_resolver(db, &self.resolver, ty) |
123 | } | 122 | } |
124 | 123 | ||
125 | pub(crate) fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { | 124 | pub(crate) fn resolve_method_call( |
126 | let expr_id = self.expr_id(&call.clone().into())?; | 125 | &self, |
126 | db: &dyn HirDatabase, | ||
127 | call: &ast::MethodCallExpr, | ||
128 | ) -> Option<Function> { | ||
129 | let expr_id = self.expr_id(db, &call.clone().into())?; | ||
127 | self.infer.as_ref()?.method_resolution(expr_id).map(Function::from) | 130 | self.infer.as_ref()?.method_resolution(expr_id).map(Function::from) |
128 | } | 131 | } |
129 | 132 | ||
130 | pub(crate) fn resolve_field(&self, field: &ast::FieldExpr) -> Option<crate::StructField> { | 133 | pub(crate) fn resolve_field( |
131 | let expr_id = self.expr_id(&field.clone().into())?; | 134 | &self, |
135 | db: &dyn HirDatabase, | ||
136 | field: &ast::FieldExpr, | ||
137 | ) -> Option<crate::StructField> { | ||
138 | let expr_id = self.expr_id(db, &field.clone().into())?; | ||
132 | self.infer.as_ref()?.field_resolution(expr_id).map(|it| it.into()) | 139 | self.infer.as_ref()?.field_resolution(expr_id).map(|it| it.into()) |
133 | } | 140 | } |
134 | 141 | ||
@@ -138,7 +145,7 @@ impl SourceAnalyzer { | |||
138 | field: &ast::RecordField, | 145 | field: &ast::RecordField, |
139 | ) -> Option<(crate::StructField, Option<Local>)> { | 146 | ) -> Option<(crate::StructField, Option<Local>)> { |
140 | let (expr_id, local) = match field.expr() { | 147 | let (expr_id, local) = match field.expr() { |
141 | Some(it) => (self.expr_id(&it)?, None), | 148 | Some(it) => (self.expr_id(db, &it)?, None), |
142 | None => { | 149 | None => { |
143 | let src = InFile { file_id: self.file_id, value: field }; | 150 | let src = InFile { file_id: self.file_id, value: field }; |
144 | let expr_id = self.body_source_map.as_ref()?.field_init_shorthand_expr(src)?; | 151 | let expr_id = self.body_source_map.as_ref()?.field_init_shorthand_expr(src)?; |
@@ -159,9 +166,10 @@ impl SourceAnalyzer { | |||
159 | 166 | ||
160 | pub(crate) fn resolve_record_literal( | 167 | pub(crate) fn resolve_record_literal( |
161 | &self, | 168 | &self, |
169 | db: &dyn HirDatabase, | ||
162 | record_lit: &ast::RecordLit, | 170 | record_lit: &ast::RecordLit, |
163 | ) -> Option<crate::VariantDef> { | 171 | ) -> Option<crate::VariantDef> { |
164 | let expr_id = self.expr_id(&record_lit.clone().into())?; | 172 | let expr_id = self.expr_id(db, &record_lit.clone().into())?; |
165 | self.infer.as_ref()?.variant_resolution_for_expr(expr_id).map(|it| it.into()) | 173 | self.infer.as_ref()?.variant_resolution_for_expr(expr_id).map(|it| it.into()) |
166 | } | 174 | } |
167 | 175 | ||
@@ -207,7 +215,7 @@ impl SourceAnalyzer { | |||
207 | path: &ast::Path, | 215 | path: &ast::Path, |
208 | ) -> Option<PathResolution> { | 216 | ) -> Option<PathResolution> { |
209 | if let Some(path_expr) = path.syntax().parent().and_then(ast::PathExpr::cast) { | 217 | if let Some(path_expr) = path.syntax().parent().and_then(ast::PathExpr::cast) { |
210 | let expr_id = self.expr_id(&path_expr.into())?; | 218 | let expr_id = self.expr_id(db, &path_expr.into())?; |
211 | if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_expr(expr_id) { | 219 | if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_expr(expr_id) { |
212 | return Some(PathResolution::AssocItem(assoc.into())); | 220 | return Some(PathResolution::AssocItem(assoc.into())); |
213 | } | 221 | } |
diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs index 7f8c1ea21..5dc7395f5 100644 --- a/crates/ra_hir_def/src/db.rs +++ b/crates/ra_hir_def/src/db.rs | |||
@@ -48,6 +48,7 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> { | |||
48 | fn raw_items(&self, file_id: HirFileId) -> Arc<RawItems>; | 48 | fn raw_items(&self, file_id: HirFileId) -> Arc<RawItems>; |
49 | 49 | ||
50 | #[salsa::invoke(crate_def_map_wait)] | 50 | #[salsa::invoke(crate_def_map_wait)] |
51 | #[salsa::transparent] | ||
51 | fn crate_def_map(&self, krate: CrateId) -> Arc<CrateDefMap>; | 52 | fn crate_def_map(&self, krate: CrateId) -> Arc<CrateDefMap>; |
52 | 53 | ||
53 | #[salsa::invoke(CrateDefMap::crate_def_map_query)] | 54 | #[salsa::invoke(CrateDefMap::crate_def_map_query)] |
@@ -109,12 +110,6 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> { | |||
109 | fn documentation(&self, def: AttrDefId) -> Option<Documentation>; | 110 | fn documentation(&self, def: AttrDefId) -> Option<Documentation>; |
110 | } | 111 | } |
111 | 112 | ||
112 | // impl<T: DefDatabase> Upcast<dyn AstDatabase> for T { | ||
113 | // fn upcast(&self) -> &dyn AstDatabase { | ||
114 | // &*self | ||
115 | // } | ||
116 | // } | ||
117 | |||
118 | fn crate_def_map_wait(db: &impl DefDatabase, krate: CrateId) -> Arc<CrateDefMap> { | 113 | fn crate_def_map_wait(db: &impl DefDatabase, krate: CrateId) -> Arc<CrateDefMap> { |
119 | let _p = profile("crate_def_map:wait"); | 114 | let _p = profile("crate_def_map:wait"); |
120 | db.crate_def_map_query(krate) | 115 | db.crate_def_map_query(krate) |
diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs index 5e943b780..259b9ff03 100644 --- a/crates/ra_hir_def/src/item_scope.rs +++ b/crates/ra_hir_def/src/item_scope.rs | |||
@@ -68,6 +68,12 @@ impl ItemScope { | |||
68 | self.impls.iter().copied() | 68 | self.impls.iter().copied() |
69 | } | 69 | } |
70 | 70 | ||
71 | pub fn visibility_of(&self, def: ModuleDefId) -> Option<Visibility> { | ||
72 | self.name_of(ItemInNs::Types(def)) | ||
73 | .or_else(|| self.name_of(ItemInNs::Values(def))) | ||
74 | .map(|(_, v)| v) | ||
75 | } | ||
76 | |||
71 | /// Iterate over all module scoped macros | 77 | /// Iterate over all module scoped macros |
72 | pub(crate) fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a { | 78 | pub(crate) fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a { |
73 | self.visible.iter().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_))) | 79 | self.visible.iter().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_))) |
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index 516dd773e..bd32ac20a 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs | |||
@@ -475,6 +475,12 @@ impl AsMacroCall for AstIdWithPath<ast::ModuleItem> { | |||
475 | resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, | 475 | resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, |
476 | ) -> Option<MacroCallId> { | 476 | ) -> Option<MacroCallId> { |
477 | let def = resolver(self.path.clone())?; | 477 | let def = resolver(self.path.clone())?; |
478 | Some(def.as_lazy_macro(db.upcast(), MacroCallKind::Attr(self.ast_id)).into()) | 478 | Some( |
479 | def.as_lazy_macro( | ||
480 | db.upcast(), | ||
481 | MacroCallKind::Attr(self.ast_id, self.path.segments.last()?.to_string()), | ||
482 | ) | ||
483 | .into(), | ||
484 | ) | ||
479 | } | 485 | } |
480 | } | 486 | } |
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index 5b292c250..9c125f32f 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs | |||
@@ -7,6 +7,7 @@ use hir_expand::{ | |||
7 | builtin_derive::find_builtin_derive, | 7 | builtin_derive::find_builtin_derive, |
8 | builtin_macro::find_builtin_macro, | 8 | builtin_macro::find_builtin_macro, |
9 | name::{name, AsName, Name}, | 9 | name::{name, AsName, Name}, |
10 | proc_macro::ProcMacroExpander, | ||
10 | HirFileId, MacroCallId, MacroDefId, MacroDefKind, | 11 | HirFileId, MacroCallId, MacroDefId, MacroDefKind, |
11 | }; | 12 | }; |
12 | use ra_cfg::CfgOptions; | 13 | use ra_cfg::CfgOptions; |
@@ -64,6 +65,9 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: CrateDefMap) -> Cr | |||
64 | unexpanded_attribute_macros: Vec::new(), | 65 | unexpanded_attribute_macros: Vec::new(), |
65 | mod_dirs: FxHashMap::default(), | 66 | mod_dirs: FxHashMap::default(), |
66 | cfg_options, | 67 | cfg_options, |
68 | |||
69 | // FIXME: pass proc-macro from crate-graph | ||
70 | proc_macros: Default::default(), | ||
67 | }; | 71 | }; |
68 | collector.collect(); | 72 | collector.collect(); |
69 | collector.finish() | 73 | collector.finish() |
@@ -122,6 +126,7 @@ struct DefCollector<'a> { | |||
122 | unexpanded_attribute_macros: Vec<DeriveDirective>, | 126 | unexpanded_attribute_macros: Vec<DeriveDirective>, |
123 | mod_dirs: FxHashMap<LocalModuleId, ModDir>, | 127 | mod_dirs: FxHashMap<LocalModuleId, ModDir>, |
124 | cfg_options: &'a CfgOptions, | 128 | cfg_options: &'a CfgOptions, |
129 | proc_macros: Vec<(Name, ProcMacroExpander)>, | ||
125 | } | 130 | } |
126 | 131 | ||
127 | impl DefCollector<'_> { | 132 | impl DefCollector<'_> { |
@@ -177,6 +182,24 @@ impl DefCollector<'_> { | |||
177 | for directive in unresolved_imports { | 182 | for directive in unresolved_imports { |
178 | self.record_resolved_import(&directive) | 183 | self.record_resolved_import(&directive) |
179 | } | 184 | } |
185 | |||
186 | // Record proc-macros | ||
187 | self.collect_proc_macro(); | ||
188 | } | ||
189 | |||
190 | fn collect_proc_macro(&mut self) { | ||
191 | let proc_macros = std::mem::take(&mut self.proc_macros); | ||
192 | for (name, expander) in proc_macros { | ||
193 | let krate = self.def_map.krate; | ||
194 | |||
195 | let macro_id = MacroDefId { | ||
196 | ast_id: None, | ||
197 | krate: Some(krate), | ||
198 | kind: MacroDefKind::CustomDerive(expander), | ||
199 | }; | ||
200 | |||
201 | self.define_proc_macro(name.clone(), macro_id); | ||
202 | } | ||
180 | } | 203 | } |
181 | 204 | ||
182 | /// Define a macro with `macro_rules`. | 205 | /// Define a macro with `macro_rules`. |
@@ -238,6 +261,18 @@ impl DefCollector<'_> { | |||
238 | self.def_map.modules[module_id].scope.define_legacy_macro(name, mac); | 261 | self.def_map.modules[module_id].scope.define_legacy_macro(name, mac); |
239 | } | 262 | } |
240 | 263 | ||
264 | /// Define a proc macro | ||
265 | /// | ||
266 | /// A proc macro is similar to normal macro scope, but it would not visiable in legacy textual scoped. | ||
267 | /// And unconditionally exported. | ||
268 | fn define_proc_macro(&mut self, name: Name, macro_: MacroDefId) { | ||
269 | self.update( | ||
270 | self.def_map.root, | ||
271 | &[(name, PerNs::macros(macro_, Visibility::Public))], | ||
272 | Visibility::Public, | ||
273 | ); | ||
274 | } | ||
275 | |||
241 | /// Import macros from `#[macro_use] extern crate`. | 276 | /// Import macros from `#[macro_use] extern crate`. |
242 | fn import_macros_from_extern_crate( | 277 | fn import_macros_from_extern_crate( |
243 | &mut self, | 278 | &mut self, |
@@ -537,8 +572,9 @@ impl DefCollector<'_> { | |||
537 | true | 572 | true |
538 | }); | 573 | }); |
539 | attribute_macros.retain(|directive| { | 574 | attribute_macros.retain(|directive| { |
540 | if let Some(call_id) = | 575 | if let Some(call_id) = directive |
541 | directive.ast_id.as_call_id(self.db, |path| self.resolve_attribute_macro(&path)) | 576 | .ast_id |
577 | .as_call_id(self.db, |path| self.resolve_attribute_macro(&directive, &path)) | ||
542 | { | 578 | { |
543 | resolved.push((directive.module_id, call_id, 0)); | 579 | resolved.push((directive.module_id, call_id, 0)); |
544 | res = ReachedFixedPoint::No; | 580 | res = ReachedFixedPoint::No; |
@@ -562,9 +598,11 @@ impl DefCollector<'_> { | |||
562 | res | 598 | res |
563 | } | 599 | } |
564 | 600 | ||
565 | fn resolve_attribute_macro(&self, path: &ModPath) -> Option<MacroDefId> { | 601 | fn resolve_attribute_macro( |
566 | // FIXME this is currently super hacky, just enough to support the | 602 | &self, |
567 | // built-in derives | 603 | directive: &DeriveDirective, |
604 | path: &ModPath, | ||
605 | ) -> Option<MacroDefId> { | ||
568 | if let Some(name) = path.as_ident() { | 606 | if let Some(name) = path.as_ident() { |
569 | // FIXME this should actually be handled with the normal name | 607 | // FIXME this should actually be handled with the normal name |
570 | // resolution; the std lib defines built-in stubs for the derives, | 608 | // resolution; the std lib defines built-in stubs for the derives, |
@@ -573,7 +611,15 @@ impl DefCollector<'_> { | |||
573 | return Some(def_id); | 611 | return Some(def_id); |
574 | } | 612 | } |
575 | } | 613 | } |
576 | None | 614 | let resolved_res = self.def_map.resolve_path_fp_with_macro( |
615 | self.db, | ||
616 | ResolveMode::Other, | ||
617 | directive.module_id, | ||
618 | &path, | ||
619 | BuiltinShadowMode::Module, | ||
620 | ); | ||
621 | |||
622 | resolved_res.resolved_def.take_macros() | ||
577 | } | 623 | } |
578 | 624 | ||
579 | fn collect_macro_expansion( | 625 | fn collect_macro_expansion( |
@@ -776,7 +822,6 @@ impl ModCollector<'_, '_> { | |||
776 | // FIXME: check attrs to see if this is an attribute macro invocation; | 822 | // FIXME: check attrs to see if this is an attribute macro invocation; |
777 | // in which case we don't add the invocation, just a single attribute | 823 | // in which case we don't add the invocation, just a single attribute |
778 | // macro invocation | 824 | // macro invocation |
779 | |||
780 | self.collect_derives(attrs, def); | 825 | self.collect_derives(attrs, def); |
781 | 826 | ||
782 | let name = def.name.clone(); | 827 | let name = def.name.clone(); |
@@ -955,6 +1000,7 @@ mod tests { | |||
955 | unexpanded_attribute_macros: Vec::new(), | 1000 | unexpanded_attribute_macros: Vec::new(), |
956 | mod_dirs: FxHashMap::default(), | 1001 | mod_dirs: FxHashMap::default(), |
957 | cfg_options: &CfgOptions::default(), | 1002 | cfg_options: &CfgOptions::default(), |
1003 | proc_macros: Default::default(), | ||
958 | }; | 1004 | }; |
959 | collector.collect(); | 1005 | collector.collect(); |
960 | collector.def_map | 1006 | collector.def_map |
diff --git a/crates/ra_hir_expand/src/builtin_derive.rs b/crates/ra_hir_expand/src/builtin_derive.rs index a5b50a832..79aea5806 100644 --- a/crates/ra_hir_expand/src/builtin_derive.rs +++ b/crates/ra_hir_expand/src/builtin_derive.rs | |||
@@ -229,9 +229,12 @@ fn partial_ord_expand( | |||
229 | mod tests { | 229 | mod tests { |
230 | use super::*; | 230 | use super::*; |
231 | use crate::{test_db::TestDB, AstId, MacroCallId, MacroCallKind, MacroCallLoc}; | 231 | use crate::{test_db::TestDB, AstId, MacroCallId, MacroCallKind, MacroCallLoc}; |
232 | use name::{known, Name}; | ||
232 | use ra_db::{fixture::WithFixture, SourceDatabase}; | 233 | use ra_db::{fixture::WithFixture, SourceDatabase}; |
233 | 234 | ||
234 | fn expand_builtin_derive(s: &str, expander: BuiltinDeriveExpander) -> String { | 235 | fn expand_builtin_derive(s: &str, name: Name) -> String { |
236 | let def = find_builtin_derive(&name).unwrap(); | ||
237 | |||
235 | let (db, file_id) = TestDB::with_single_file(&s); | 238 | let (db, file_id) = TestDB::with_single_file(&s); |
236 | let parsed = db.parse(file_id); | 239 | let parsed = db.parse(file_id); |
237 | let items: Vec<_> = | 240 | let items: Vec<_> = |
@@ -239,14 +242,9 @@ mod tests { | |||
239 | 242 | ||
240 | let ast_id_map = db.ast_id_map(file_id.into()); | 243 | let ast_id_map = db.ast_id_map(file_id.into()); |
241 | 244 | ||
242 | // the first one should be a macro_rules | 245 | let attr_id = AstId::new(file_id.into(), ast_id_map.ast_id(&items[0])); |
243 | let def = | ||
244 | MacroDefId { krate: None, ast_id: None, kind: MacroDefKind::BuiltInDerive(expander) }; | ||
245 | 246 | ||
246 | let loc = MacroCallLoc { | 247 | let loc = MacroCallLoc { def, kind: MacroCallKind::Attr(attr_id, name.to_string()) }; |
247 | def, | ||
248 | kind: MacroCallKind::Attr(AstId::new(file_id.into(), ast_id_map.ast_id(&items[0]))), | ||
249 | }; | ||
250 | 248 | ||
251 | let id: MacroCallId = db.intern_macro(loc).into(); | 249 | let id: MacroCallId = db.intern_macro(loc).into(); |
252 | let parsed = db.parse_or_expand(id.as_file()).unwrap(); | 250 | let parsed = db.parse_or_expand(id.as_file()).unwrap(); |
@@ -263,7 +261,7 @@ mod tests { | |||
263 | #[derive(Copy)] | 261 | #[derive(Copy)] |
264 | struct Foo; | 262 | struct Foo; |
265 | "#, | 263 | "#, |
266 | BuiltinDeriveExpander::Copy, | 264 | known::Copy, |
267 | ); | 265 | ); |
268 | 266 | ||
269 | assert_eq!(expanded, "impl< >std::marker::CopyforFoo< >{}"); | 267 | assert_eq!(expanded, "impl< >std::marker::CopyforFoo< >{}"); |
@@ -276,7 +274,7 @@ mod tests { | |||
276 | #[derive(Copy)] | 274 | #[derive(Copy)] |
277 | struct Foo<A, B>; | 275 | struct Foo<A, B>; |
278 | "#, | 276 | "#, |
279 | BuiltinDeriveExpander::Copy, | 277 | known::Copy, |
280 | ); | 278 | ); |
281 | 279 | ||
282 | assert_eq!( | 280 | assert_eq!( |
@@ -292,7 +290,7 @@ mod tests { | |||
292 | #[derive(Copy)] | 290 | #[derive(Copy)] |
293 | struct Foo<A, B, 'a, 'b>; | 291 | struct Foo<A, B, 'a, 'b>; |
294 | "#, | 292 | "#, |
295 | BuiltinDeriveExpander::Copy, | 293 | known::Copy, |
296 | ); | 294 | ); |
297 | 295 | ||
298 | // We currently just ignore lifetimes | 296 | // We currently just ignore lifetimes |
@@ -310,7 +308,7 @@ mod tests { | |||
310 | #[derive(Clone)] | 308 | #[derive(Clone)] |
311 | struct Foo<A, B>; | 309 | struct Foo<A, B>; |
312 | "#, | 310 | "#, |
313 | BuiltinDeriveExpander::Clone, | 311 | known::Clone, |
314 | ); | 312 | ); |
315 | 313 | ||
316 | assert_eq!( | 314 | assert_eq!( |
diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs index 5a696542f..047452306 100644 --- a/crates/ra_hir_expand/src/db.rs +++ b/crates/ra_hir_expand/src/db.rs | |||
@@ -11,7 +11,7 @@ use ra_syntax::{algo::diff, AstNode, Parse, SyntaxKind::*, SyntaxNode}; | |||
11 | use crate::{ | 11 | use crate::{ |
12 | ast_id_map::AstIdMap, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallLoc, EagerMacroId, | 12 | ast_id_map::AstIdMap, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallLoc, EagerMacroId, |
13 | HirFileId, HirFileIdRepr, LazyMacroId, MacroCallId, MacroCallLoc, MacroDefId, MacroDefKind, | 13 | HirFileId, HirFileIdRepr, LazyMacroId, MacroCallId, MacroCallLoc, MacroDefId, MacroDefKind, |
14 | MacroFile, | 14 | MacroFile, ProcMacroExpander, |
15 | }; | 15 | }; |
16 | 16 | ||
17 | #[derive(Debug, Clone, Eq, PartialEq)] | 17 | #[derive(Debug, Clone, Eq, PartialEq)] |
@@ -19,6 +19,7 @@ pub enum TokenExpander { | |||
19 | MacroRules(mbe::MacroRules), | 19 | MacroRules(mbe::MacroRules), |
20 | Builtin(BuiltinFnLikeExpander), | 20 | Builtin(BuiltinFnLikeExpander), |
21 | BuiltinDerive(BuiltinDeriveExpander), | 21 | BuiltinDerive(BuiltinDeriveExpander), |
22 | ProcMacro(ProcMacroExpander), | ||
22 | } | 23 | } |
23 | 24 | ||
24 | impl TokenExpander { | 25 | impl TokenExpander { |
@@ -33,6 +34,7 @@ impl TokenExpander { | |||
33 | // FIXME switch these to ExpandResult as well | 34 | // FIXME switch these to ExpandResult as well |
34 | TokenExpander::Builtin(it) => it.expand(db, id, tt).into(), | 35 | TokenExpander::Builtin(it) => it.expand(db, id, tt).into(), |
35 | TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt).into(), | 36 | TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt).into(), |
37 | TokenExpander::ProcMacro(it) => it.expand(db, id, tt).into(), | ||
36 | } | 38 | } |
37 | } | 39 | } |
38 | 40 | ||
@@ -41,6 +43,7 @@ impl TokenExpander { | |||
41 | TokenExpander::MacroRules(it) => it.map_id_down(id), | 43 | TokenExpander::MacroRules(it) => it.map_id_down(id), |
42 | TokenExpander::Builtin(..) => id, | 44 | TokenExpander::Builtin(..) => id, |
43 | TokenExpander::BuiltinDerive(..) => id, | 45 | TokenExpander::BuiltinDerive(..) => id, |
46 | TokenExpander::ProcMacro(..) => id, | ||
44 | } | 47 | } |
45 | } | 48 | } |
46 | 49 | ||
@@ -49,6 +52,7 @@ impl TokenExpander { | |||
49 | TokenExpander::MacroRules(it) => it.map_id_up(id), | 52 | TokenExpander::MacroRules(it) => it.map_id_up(id), |
50 | TokenExpander::Builtin(..) => (id, mbe::Origin::Call), | 53 | TokenExpander::Builtin(..) => (id, mbe::Origin::Call), |
51 | TokenExpander::BuiltinDerive(..) => (id, mbe::Origin::Call), | 54 | TokenExpander::BuiltinDerive(..) => (id, mbe::Origin::Call), |
55 | TokenExpander::ProcMacro(..) => (id, mbe::Origin::Call), | ||
52 | } | 56 | } |
53 | } | 57 | } |
54 | } | 58 | } |
@@ -130,7 +134,10 @@ pub(crate) fn macro_def( | |||
130 | MacroDefKind::BuiltInDerive(expander) => { | 134 | MacroDefKind::BuiltInDerive(expander) => { |
131 | Some(Arc::new((TokenExpander::BuiltinDerive(expander), mbe::TokenMap::default()))) | 135 | Some(Arc::new((TokenExpander::BuiltinDerive(expander), mbe::TokenMap::default()))) |
132 | } | 136 | } |
133 | MacroDefKind::BuiltInEager(_expander) => None, | 137 | MacroDefKind::BuiltInEager(_) => None, |
138 | MacroDefKind::CustomDerive(expander) => { | ||
139 | Some(Arc::new((TokenExpander::ProcMacro(expander), mbe::TokenMap::default()))) | ||
140 | } | ||
134 | } | 141 | } |
135 | } | 142 | } |
136 | 143 | ||
diff --git a/crates/ra_hir_expand/src/eager.rs b/crates/ra_hir_expand/src/eager.rs index 4cbce4df5..932f47c30 100644 --- a/crates/ra_hir_expand/src/eager.rs +++ b/crates/ra_hir_expand/src/eager.rs | |||
@@ -26,8 +26,8 @@ use crate::{ | |||
26 | }; | 26 | }; |
27 | 27 | ||
28 | use ra_parser::FragmentKind; | 28 | use ra_parser::FragmentKind; |
29 | use ra_syntax::{algo::replace_descendants, SyntaxElement, SyntaxNode}; | 29 | use ra_syntax::{algo::SyntaxRewriter, SyntaxNode}; |
30 | use std::{collections::HashMap, sync::Arc}; | 30 | use std::sync::Arc; |
31 | 31 | ||
32 | pub fn expand_eager_macro( | 32 | pub fn expand_eager_macro( |
33 | db: &dyn AstDatabase, | 33 | db: &dyn AstDatabase, |
@@ -95,10 +95,10 @@ fn eager_macro_recur( | |||
95 | curr: InFile<SyntaxNode>, | 95 | curr: InFile<SyntaxNode>, |
96 | macro_resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>, | 96 | macro_resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>, |
97 | ) -> Option<SyntaxNode> { | 97 | ) -> Option<SyntaxNode> { |
98 | let mut original = curr.value.clone(); | 98 | let original = curr.value.clone(); |
99 | 99 | ||
100 | let children = curr.value.descendants().filter_map(ast::MacroCall::cast); | 100 | let children = curr.value.descendants().filter_map(ast::MacroCall::cast); |
101 | let mut replaces: HashMap<SyntaxElement, SyntaxElement> = HashMap::default(); | 101 | let mut rewriter = SyntaxRewriter::default(); |
102 | 102 | ||
103 | // Collect replacement | 103 | // Collect replacement |
104 | for child in children { | 104 | for child in children { |
@@ -112,19 +112,17 @@ fn eager_macro_recur( | |||
112 | } | 112 | } |
113 | MacroDefKind::Declarative | 113 | MacroDefKind::Declarative |
114 | | MacroDefKind::BuiltIn(_) | 114 | | MacroDefKind::BuiltIn(_) |
115 | | MacroDefKind::BuiltInDerive(_) => { | 115 | | MacroDefKind::BuiltInDerive(_) |
116 | | MacroDefKind::CustomDerive(_) => { | ||
116 | let expanded = lazy_expand(db, &def, curr.with_value(child.clone()))?; | 117 | let expanded = lazy_expand(db, &def, curr.with_value(child.clone()))?; |
117 | // replace macro inside | 118 | // replace macro inside |
118 | eager_macro_recur(db, expanded, macro_resolver)? | 119 | eager_macro_recur(db, expanded, macro_resolver)? |
119 | } | 120 | } |
120 | }; | 121 | }; |
121 | 122 | ||
122 | replaces.insert(child.syntax().clone().into(), insert.into()); | 123 | rewriter.replace(child.syntax(), &insert); |
123 | } | 124 | } |
124 | 125 | ||
125 | if !replaces.is_empty() { | 126 | let res = rewriter.rewrite(&original); |
126 | original = replace_descendants(&original, |n| replaces.get(n).cloned()); | 127 | Some(res) |
127 | } | ||
128 | |||
129 | Some(original) | ||
130 | } | 128 | } |
diff --git a/crates/ra_hir_expand/src/hygiene.rs b/crates/ra_hir_expand/src/hygiene.rs index dfbac494f..0b41d0e95 100644 --- a/crates/ra_hir_expand/src/hygiene.rs +++ b/crates/ra_hir_expand/src/hygiene.rs | |||
@@ -30,6 +30,7 @@ impl Hygiene { | |||
30 | MacroDefKind::BuiltIn(_) => None, | 30 | MacroDefKind::BuiltIn(_) => None, |
31 | MacroDefKind::BuiltInDerive(_) => None, | 31 | MacroDefKind::BuiltInDerive(_) => None, |
32 | MacroDefKind::BuiltInEager(_) => None, | 32 | MacroDefKind::BuiltInEager(_) => None, |
33 | MacroDefKind::CustomDerive(_) => None, | ||
33 | } | 34 | } |
34 | } | 35 | } |
35 | MacroCallId::EagerMacro(_id) => None, | 36 | MacroCallId::EagerMacro(_id) => None, |
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index 6b59ea4c9..86299459f 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs | |||
@@ -11,6 +11,7 @@ pub mod hygiene; | |||
11 | pub mod diagnostics; | 11 | pub mod diagnostics; |
12 | pub mod builtin_derive; | 12 | pub mod builtin_derive; |
13 | pub mod builtin_macro; | 13 | pub mod builtin_macro; |
14 | pub mod proc_macro; | ||
14 | pub mod quote; | 15 | pub mod quote; |
15 | pub mod eager; | 16 | pub mod eager; |
16 | 17 | ||
@@ -27,6 +28,7 @@ use ra_syntax::{ | |||
27 | use crate::ast_id_map::FileAstId; | 28 | use crate::ast_id_map::FileAstId; |
28 | use crate::builtin_derive::BuiltinDeriveExpander; | 29 | use crate::builtin_derive::BuiltinDeriveExpander; |
29 | use crate::builtin_macro::{BuiltinFnLikeExpander, EagerExpander}; | 30 | use crate::builtin_macro::{BuiltinFnLikeExpander, EagerExpander}; |
31 | use crate::proc_macro::ProcMacroExpander; | ||
30 | 32 | ||
31 | #[cfg(test)] | 33 | #[cfg(test)] |
32 | mod test_db; | 34 | mod test_db; |
@@ -217,6 +219,7 @@ pub enum MacroDefKind { | |||
217 | // FIXME: maybe just Builtin and rename BuiltinFnLikeExpander to BuiltinExpander | 219 | // FIXME: maybe just Builtin and rename BuiltinFnLikeExpander to BuiltinExpander |
218 | BuiltInDerive(BuiltinDeriveExpander), | 220 | BuiltInDerive(BuiltinDeriveExpander), |
219 | BuiltInEager(EagerExpander), | 221 | BuiltInEager(EagerExpander), |
222 | CustomDerive(ProcMacroExpander), | ||
220 | } | 223 | } |
221 | 224 | ||
222 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 225 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
@@ -228,21 +231,23 @@ pub struct MacroCallLoc { | |||
228 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 231 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
229 | pub enum MacroCallKind { | 232 | pub enum MacroCallKind { |
230 | FnLike(AstId<ast::MacroCall>), | 233 | FnLike(AstId<ast::MacroCall>), |
231 | Attr(AstId<ast::ModuleItem>), | 234 | Attr(AstId<ast::ModuleItem>, String), |
232 | } | 235 | } |
233 | 236 | ||
234 | impl MacroCallKind { | 237 | impl MacroCallKind { |
235 | pub fn file_id(&self) -> HirFileId { | 238 | pub fn file_id(&self) -> HirFileId { |
236 | match self { | 239 | match self { |
237 | MacroCallKind::FnLike(ast_id) => ast_id.file_id, | 240 | MacroCallKind::FnLike(ast_id) => ast_id.file_id, |
238 | MacroCallKind::Attr(ast_id) => ast_id.file_id, | 241 | MacroCallKind::Attr(ast_id, _) => ast_id.file_id, |
239 | } | 242 | } |
240 | } | 243 | } |
241 | 244 | ||
242 | pub fn node(&self, db: &dyn db::AstDatabase) -> InFile<SyntaxNode> { | 245 | pub fn node(&self, db: &dyn db::AstDatabase) -> InFile<SyntaxNode> { |
243 | match self { | 246 | match self { |
244 | MacroCallKind::FnLike(ast_id) => ast_id.with_value(ast_id.to_node(db).syntax().clone()), | 247 | MacroCallKind::FnLike(ast_id) => ast_id.with_value(ast_id.to_node(db).syntax().clone()), |
245 | MacroCallKind::Attr(ast_id) => ast_id.with_value(ast_id.to_node(db).syntax().clone()), | 248 | MacroCallKind::Attr(ast_id, _) => { |
249 | ast_id.with_value(ast_id.to_node(db).syntax().clone()) | ||
250 | } | ||
246 | } | 251 | } |
247 | } | 252 | } |
248 | 253 | ||
@@ -251,7 +256,7 @@ impl MacroCallKind { | |||
251 | MacroCallKind::FnLike(ast_id) => { | 256 | MacroCallKind::FnLike(ast_id) => { |
252 | Some(ast_id.to_node(db).token_tree()?.syntax().clone()) | 257 | Some(ast_id.to_node(db).token_tree()?.syntax().clone()) |
253 | } | 258 | } |
254 | MacroCallKind::Attr(ast_id) => Some(ast_id.to_node(db).syntax().clone()), | 259 | MacroCallKind::Attr(ast_id, _) => Some(ast_id.to_node(db).syntax().clone()), |
255 | } | 260 | } |
256 | } | 261 | } |
257 | } | 262 | } |
diff --git a/crates/ra_hir_expand/src/proc_macro.rs b/crates/ra_hir_expand/src/proc_macro.rs new file mode 100644 index 000000000..a8dee2052 --- /dev/null +++ b/crates/ra_hir_expand/src/proc_macro.rs | |||
@@ -0,0 +1,33 @@ | |||
1 | //! Proc Macro Expander stub | ||
2 | |||
3 | use crate::{db::AstDatabase, LazyMacroId, MacroCallKind, MacroCallLoc}; | ||
4 | use ra_db::CrateId; | ||
5 | |||
6 | #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] | ||
7 | pub struct ProcMacroExpander { | ||
8 | krate: CrateId, | ||
9 | } | ||
10 | |||
11 | impl ProcMacroExpander { | ||
12 | pub fn new(krate: CrateId) -> ProcMacroExpander { | ||
13 | ProcMacroExpander { krate } | ||
14 | } | ||
15 | |||
16 | pub fn expand( | ||
17 | &self, | ||
18 | db: &dyn AstDatabase, | ||
19 | id: LazyMacroId, | ||
20 | _tt: &tt::Subtree, | ||
21 | ) -> Result<tt::Subtree, mbe::ExpandError> { | ||
22 | let loc: MacroCallLoc = db.lookup_intern_macro(id); | ||
23 | let name = match loc.kind { | ||
24 | MacroCallKind::FnLike(_) => return Err(mbe::ExpandError::ConversionError), | ||
25 | MacroCallKind::Attr(_, name) => name, | ||
26 | }; | ||
27 | |||
28 | log::debug!("Proc-macro-expanding name = {}", name); | ||
29 | |||
30 | // Return nothing for now | ||
31 | return Ok(tt::Subtree::default()); | ||
32 | } | ||
33 | } | ||
diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs index 11fc2ac3d..1462b053f 100644 --- a/crates/ra_hir_ty/src/db.rs +++ b/crates/ra_hir_ty/src/db.rs | |||
@@ -22,6 +22,7 @@ use hir_expand::name::Name; | |||
22 | #[salsa::requires(salsa::Database)] | 22 | #[salsa::requires(salsa::Database)] |
23 | pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { | 23 | pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { |
24 | #[salsa::invoke(infer_wait)] | 24 | #[salsa::invoke(infer_wait)] |
25 | #[salsa::transparent] | ||
25 | fn infer(&self, def: DefWithBodyId) -> Arc<InferenceResult>; | 26 | fn infer(&self, def: DefWithBodyId) -> Arc<InferenceResult>; |
26 | 27 | ||
27 | #[salsa::invoke(crate::infer::infer_query)] | 28 | #[salsa::invoke(crate::infer::infer_query)] |
diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs index 2e309a379..eb97288f1 100644 --- a/crates/ra_hir_ty/src/tests/macros.rs +++ b/crates/ra_hir_ty/src/tests/macros.rs | |||
@@ -639,3 +639,22 @@ mod clone { | |||
639 | ); | 639 | ); |
640 | assert_eq!("(Wrapper<S>, {unknown})", type_at_pos(&db, pos)); | 640 | assert_eq!("(Wrapper<S>, {unknown})", type_at_pos(&db, pos)); |
641 | } | 641 | } |
642 | |||
643 | #[test] | ||
644 | fn infer_custom_derive_simple() { | ||
645 | // FIXME: this test current now do nothing | ||
646 | let (db, pos) = TestDB::with_position( | ||
647 | r#" | ||
648 | //- /main.rs crate:main | ||
649 | use foo::Foo; | ||
650 | |||
651 | #[derive(Foo)] | ||
652 | struct S{} | ||
653 | |||
654 | fn test() { | ||
655 | S{}<|>; | ||
656 | } | ||
657 | "#, | ||
658 | ); | ||
659 | assert_eq!("S", type_at_pos(&db, pos)); | ||
660 | } | ||
diff --git a/crates/ra_ide/Cargo.toml b/crates/ra_ide/Cargo.toml index 7235c944c..36eec0e60 100644 --- a/crates/ra_ide/Cargo.toml +++ b/crates/ra_ide/Cargo.toml | |||
@@ -14,7 +14,7 @@ wasm = [] | |||
14 | either = "1.5.3" | 14 | either = "1.5.3" |
15 | format-buf = "1.0.0" | 15 | format-buf = "1.0.0" |
16 | indexmap = "1.3.2" | 16 | indexmap = "1.3.2" |
17 | itertools = "0.8.2" | 17 | itertools = "0.9.0" |
18 | join_to_string = "0.1.3" | 18 | join_to_string = "0.1.3" |
19 | log = "0.4.8" | 19 | log = "0.4.8" |
20 | rustc-hash = "1.1.0" | 20 | rustc-hash = "1.1.0" |
diff --git a/crates/ra_ide/src/completion/complete_postfix.rs b/crates/ra_ide/src/completion/complete_postfix.rs index 0ba382165..0a00054b2 100644 --- a/crates/ra_ide/src/completion/complete_postfix.rs +++ b/crates/ra_ide/src/completion/complete_postfix.rs | |||
@@ -1,6 +1,9 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use ra_syntax::{ast::AstNode, TextRange, TextUnit}; | 3 | use ra_syntax::{ |
4 | ast::{self, AstNode}, | ||
5 | TextRange, TextUnit, | ||
6 | }; | ||
4 | use ra_text_edit::TextEdit; | 7 | use ra_text_edit::TextEdit; |
5 | 8 | ||
6 | use crate::{ | 9 | use crate::{ |
@@ -21,13 +24,8 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
21 | None => return, | 24 | None => return, |
22 | }; | 25 | }; |
23 | 26 | ||
24 | let receiver_text = if ctx.dot_receiver_is_ambiguous_float_literal { | 27 | let receiver_text = |
25 | let text = dot_receiver.syntax().text(); | 28 | get_receiver_text(dot_receiver, ctx.dot_receiver_is_ambiguous_float_literal); |
26 | let without_dot = ..text.len() - TextUnit::of_char('.'); | ||
27 | text.slice(without_dot).to_string() | ||
28 | } else { | ||
29 | dot_receiver.syntax().text().to_string() | ||
30 | }; | ||
31 | 29 | ||
32 | let receiver_ty = match ctx.sema.type_of_expr(&dot_receiver) { | 30 | let receiver_ty = match ctx.sema.type_of_expr(&dot_receiver) { |
33 | Some(it) => it, | 31 | Some(it) => it, |
@@ -35,10 +33,17 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
35 | }; | 33 | }; |
36 | 34 | ||
37 | if receiver_ty.is_bool() || receiver_ty.is_unknown() { | 35 | if receiver_ty.is_bool() || receiver_ty.is_unknown() { |
38 | postfix_snippet(ctx, "if", "if expr {}", &format!("if {} {{$0}}", receiver_text)) | ||
39 | .add_to(acc); | ||
40 | postfix_snippet( | 36 | postfix_snippet( |
41 | ctx, | 37 | ctx, |
38 | &dot_receiver, | ||
39 | "if", | ||
40 | "if expr {}", | ||
41 | &format!("if {} {{$0}}", receiver_text), | ||
42 | ) | ||
43 | .add_to(acc); | ||
44 | postfix_snippet( | ||
45 | ctx, | ||
46 | &dot_receiver, | ||
42 | "while", | 47 | "while", |
43 | "while expr {}", | 48 | "while expr {}", |
44 | &format!("while {} {{\n$0\n}}", receiver_text), | 49 | &format!("while {} {{\n$0\n}}", receiver_text), |
@@ -46,28 +51,70 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
46 | .add_to(acc); | 51 | .add_to(acc); |
47 | } | 52 | } |
48 | 53 | ||
49 | postfix_snippet(ctx, "not", "!expr", &format!("!{}", receiver_text)).add_to(acc); | 54 | // !&&&42 is a compiler error, ergo process it before considering the references |
55 | postfix_snippet(ctx, &dot_receiver, "not", "!expr", &format!("!{}", receiver_text)).add_to(acc); | ||
50 | 56 | ||
51 | postfix_snippet(ctx, "ref", "&expr", &format!("&{}", receiver_text)).add_to(acc); | 57 | postfix_snippet(ctx, &dot_receiver, "ref", "&expr", &format!("&{}", receiver_text)).add_to(acc); |
52 | postfix_snippet(ctx, "refm", "&mut expr", &format!("&mut {}", receiver_text)).add_to(acc); | 58 | postfix_snippet(ctx, &dot_receiver, "refm", "&mut expr", &format!("&mut {}", receiver_text)) |
59 | .add_to(acc); | ||
60 | |||
61 | // The rest of the postfix completions create an expression that moves an argument, | ||
62 | // so it's better to consider references now to avoid breaking the compilation | ||
63 | let dot_receiver = include_references(dot_receiver); | ||
64 | let receiver_text = | ||
65 | get_receiver_text(&dot_receiver, ctx.dot_receiver_is_ambiguous_float_literal); | ||
53 | 66 | ||
54 | postfix_snippet( | 67 | postfix_snippet( |
55 | ctx, | 68 | ctx, |
69 | &dot_receiver, | ||
56 | "match", | 70 | "match", |
57 | "match expr {}", | 71 | "match expr {}", |
58 | &format!("match {} {{\n ${{1:_}} => {{$0\\}},\n}}", receiver_text), | 72 | &format!("match {} {{\n ${{1:_}} => {{$0\\}},\n}}", receiver_text), |
59 | ) | 73 | ) |
60 | .add_to(acc); | 74 | .add_to(acc); |
61 | 75 | ||
62 | postfix_snippet(ctx, "dbg", "dbg!(expr)", &format!("dbg!({})", receiver_text)).add_to(acc); | 76 | postfix_snippet( |
77 | ctx, | ||
78 | &dot_receiver, | ||
79 | "box", | ||
80 | "Box::new(expr)", | ||
81 | &format!("Box::new({})", receiver_text), | ||
82 | ) | ||
83 | .add_to(acc); | ||
63 | 84 | ||
64 | postfix_snippet(ctx, "box", "Box::new(expr)", &format!("Box::new({})", receiver_text)) | 85 | postfix_snippet(ctx, &dot_receiver, "dbg", "dbg!(expr)", &format!("dbg!({})", receiver_text)) |
65 | .add_to(acc); | 86 | .add_to(acc); |
66 | } | 87 | } |
67 | 88 | ||
68 | fn postfix_snippet(ctx: &CompletionContext, label: &str, detail: &str, snippet: &str) -> Builder { | 89 | fn get_receiver_text(receiver: &ast::Expr, receiver_is_ambiguous_float_literal: bool) -> String { |
90 | if receiver_is_ambiguous_float_literal { | ||
91 | let text = receiver.syntax().text(); | ||
92 | let without_dot = ..text.len() - TextUnit::of_char('.'); | ||
93 | text.slice(without_dot).to_string() | ||
94 | } else { | ||
95 | receiver.to_string() | ||
96 | } | ||
97 | } | ||
98 | |||
99 | fn include_references(initial_element: &ast::Expr) -> ast::Expr { | ||
100 | let mut resulting_element = initial_element.clone(); | ||
101 | while let Some(parent_ref_element) = | ||
102 | resulting_element.syntax().parent().and_then(ast::RefExpr::cast) | ||
103 | { | ||
104 | resulting_element = ast::Expr::from(parent_ref_element); | ||
105 | } | ||
106 | resulting_element | ||
107 | } | ||
108 | |||
109 | fn postfix_snippet( | ||
110 | ctx: &CompletionContext, | ||
111 | receiver: &ast::Expr, | ||
112 | label: &str, | ||
113 | detail: &str, | ||
114 | snippet: &str, | ||
115 | ) -> Builder { | ||
69 | let edit = { | 116 | let edit = { |
70 | let receiver_syntax = ctx.dot_receiver.as_ref().expect("no receiver available").syntax(); | 117 | let receiver_syntax = receiver.syntax(); |
71 | let receiver_range = ctx.sema.original_range(receiver_syntax).range; | 118 | let receiver_range = ctx.sema.original_range(receiver_syntax).range; |
72 | let delete_range = TextRange::from_to(receiver_range.start(), ctx.source_range().end()); | 119 | let delete_range = TextRange::from_to(receiver_range.start(), ctx.source_range().end()); |
73 | TextEdit::replace(delete_range, snippet.to_string()) | 120 | TextEdit::replace(delete_range, snippet.to_string()) |
@@ -340,4 +387,63 @@ mod tests { | |||
340 | "### | 387 | "### |
341 | ); | 388 | ); |
342 | } | 389 | } |
390 | |||
391 | #[test] | ||
392 | fn postfix_completion_for_references() { | ||
393 | assert_debug_snapshot!( | ||
394 | do_postfix_completion( | ||
395 | r#" | ||
396 | fn main() { | ||
397 | &&&&42.<|> | ||
398 | } | ||
399 | "#, | ||
400 | ), | ||
401 | @r###" | ||
402 | [ | ||
403 | CompletionItem { | ||
404 | label: "box", | ||
405 | source_range: [56; 56), | ||
406 | delete: [49; 56), | ||
407 | insert: "Box::new(&&&&42)", | ||
408 | detail: "Box::new(expr)", | ||
409 | }, | ||
410 | CompletionItem { | ||
411 | label: "dbg", | ||
412 | source_range: [56; 56), | ||
413 | delete: [49; 56), | ||
414 | insert: "dbg!(&&&&42)", | ||
415 | detail: "dbg!(expr)", | ||
416 | }, | ||
417 | CompletionItem { | ||
418 | label: "match", | ||
419 | source_range: [56; 56), | ||
420 | delete: [49; 56), | ||
421 | insert: "match &&&&42 {\n ${1:_} => {$0\\},\n}", | ||
422 | detail: "match expr {}", | ||
423 | }, | ||
424 | CompletionItem { | ||
425 | label: "not", | ||
426 | source_range: [56; 56), | ||
427 | delete: [53; 56), | ||
428 | insert: "!42", | ||
429 | detail: "!expr", | ||
430 | }, | ||
431 | CompletionItem { | ||
432 | label: "ref", | ||
433 | source_range: [56; 56), | ||
434 | delete: [53; 56), | ||
435 | insert: "&42", | ||
436 | detail: "&expr", | ||
437 | }, | ||
438 | CompletionItem { | ||
439 | label: "refm", | ||
440 | source_range: [56; 56), | ||
441 | delete: [53; 56), | ||
442 | insert: "&mut 42", | ||
443 | detail: "&mut expr", | ||
444 | }, | ||
445 | ] | ||
446 | "### | ||
447 | ); | ||
448 | } | ||
343 | } | 449 | } |
diff --git a/crates/ra_ide/src/completion/complete_record_literal.rs b/crates/ra_ide/src/completion/complete_record_literal.rs index 83ed1d52c..e4e764f58 100644 --- a/crates/ra_ide/src/completion/complete_record_literal.rs +++ b/crates/ra_ide/src/completion/complete_record_literal.rs | |||
@@ -1,6 +1,7 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use crate::completion::{CompletionContext, Completions}; | 3 | use crate::completion::{CompletionContext, Completions}; |
4 | use ra_syntax::SmolStr; | ||
4 | 5 | ||
5 | /// Complete fields in fields literals. | 6 | /// Complete fields in fields literals. |
6 | pub(super) fn complete_record_literal(acc: &mut Completions, ctx: &CompletionContext) { | 7 | pub(super) fn complete_record_literal(acc: &mut Completions, ctx: &CompletionContext) { |
@@ -11,8 +12,24 @@ pub(super) fn complete_record_literal(acc: &mut Completions, ctx: &CompletionCon | |||
11 | _ => return, | 12 | _ => return, |
12 | }; | 13 | }; |
13 | 14 | ||
15 | let already_present_names: Vec<SmolStr> = ctx | ||
16 | .record_lit_syntax | ||
17 | .as_ref() | ||
18 | .and_then(|record_literal| record_literal.record_field_list()) | ||
19 | .map(|field_list| field_list.fields()) | ||
20 | .map(|fields| { | ||
21 | fields | ||
22 | .into_iter() | ||
23 | .filter_map(|field| field.name_ref()) | ||
24 | .map(|name_ref| name_ref.text().clone()) | ||
25 | .collect() | ||
26 | }) | ||
27 | .unwrap_or_default(); | ||
28 | |||
14 | for (field, field_ty) in ty.variant_fields(ctx.db, variant) { | 29 | for (field, field_ty) in ty.variant_fields(ctx.db, variant) { |
15 | acc.add_field(ctx, field, &field_ty); | 30 | if !already_present_names.contains(&SmolStr::from(field.name(ctx.db).to_string())) { |
31 | acc.add_field(ctx, field, &field_ty); | ||
32 | } | ||
16 | } | 33 | } |
17 | } | 34 | } |
18 | 35 | ||
@@ -178,4 +195,47 @@ mod tests { | |||
178 | ] | 195 | ] |
179 | "###); | 196 | "###); |
180 | } | 197 | } |
198 | |||
199 | #[test] | ||
200 | fn only_missing_fields_are_completed() { | ||
201 | let completions = complete( | ||
202 | r" | ||
203 | struct S { | ||
204 | foo1: u32, | ||
205 | foo2: u32, | ||
206 | bar: u32, | ||
207 | baz: u32, | ||
208 | } | ||
209 | |||
210 | fn main() { | ||
211 | let foo1 = 1; | ||
212 | let s = S { | ||
213 | foo1, | ||
214 | foo2: 5, | ||
215 | <|> | ||
216 | } | ||
217 | } | ||
218 | ", | ||
219 | ); | ||
220 | assert_debug_snapshot!(completions, @r###" | ||
221 | [ | ||
222 | CompletionItem { | ||
223 | label: "bar", | ||
224 | source_range: [302; 302), | ||
225 | delete: [302; 302), | ||
226 | insert: "bar", | ||
227 | kind: Field, | ||
228 | detail: "u32", | ||
229 | }, | ||
230 | CompletionItem { | ||
231 | label: "baz", | ||
232 | source_range: [302; 302), | ||
233 | delete: [302; 302), | ||
234 | insert: "baz", | ||
235 | kind: Field, | ||
236 | detail: "u32", | ||
237 | }, | ||
238 | ] | ||
239 | "###); | ||
240 | } | ||
181 | } | 241 | } |
diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index 7fefa2c7a..ded1ff3bc 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs | |||
@@ -193,7 +193,7 @@ fn add_const_impl( | |||
193 | } | 193 | } |
194 | 194 | ||
195 | fn make_const_compl_syntax(const_: &ast::ConstDef) -> String { | 195 | fn make_const_compl_syntax(const_: &ast::ConstDef) -> String { |
196 | let const_ = edit::strip_attrs_and_docs(const_); | 196 | let const_ = edit::remove_attrs_and_docs(const_); |
197 | 197 | ||
198 | let const_start = const_.syntax().text_range().start(); | 198 | let const_start = const_.syntax().text_range().start(); |
199 | let const_end = const_.syntax().text_range().end(); | 199 | let const_end = const_.syntax().text_range().end(); |
diff --git a/crates/ra_ide/src/expand_macro.rs b/crates/ra_ide/src/expand_macro.rs index e58526f31..f536ba3e7 100644 --- a/crates/ra_ide/src/expand_macro.rs +++ b/crates/ra_ide/src/expand_macro.rs | |||
@@ -3,10 +3,9 @@ | |||
3 | use hir::Semantics; | 3 | use hir::Semantics; |
4 | use ra_ide_db::RootDatabase; | 4 | use ra_ide_db::RootDatabase; |
5 | use ra_syntax::{ | 5 | use ra_syntax::{ |
6 | algo::{find_node_at_offset, replace_descendants}, | 6 | algo::{find_node_at_offset, SyntaxRewriter}, |
7 | ast, AstNode, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, WalkEvent, T, | 7 | ast, AstNode, NodeOrToken, SyntaxKind, SyntaxNode, WalkEvent, T, |
8 | }; | 8 | }; |
9 | use rustc_hash::FxHashMap; | ||
10 | 9 | ||
11 | use crate::FilePosition; | 10 | use crate::FilePosition; |
12 | 11 | ||
@@ -37,7 +36,7 @@ fn expand_macro_recur( | |||
37 | let mut expanded = sema.expand(macro_call)?; | 36 | let mut expanded = sema.expand(macro_call)?; |
38 | 37 | ||
39 | let children = expanded.descendants().filter_map(ast::MacroCall::cast); | 38 | let children = expanded.descendants().filter_map(ast::MacroCall::cast); |
40 | let mut replaces: FxHashMap<SyntaxElement, SyntaxElement> = FxHashMap::default(); | 39 | let mut rewriter = SyntaxRewriter::default(); |
41 | 40 | ||
42 | for child in children.into_iter() { | 41 | for child in children.into_iter() { |
43 | if let Some(new_node) = expand_macro_recur(sema, &child) { | 42 | if let Some(new_node) = expand_macro_recur(sema, &child) { |
@@ -47,12 +46,13 @@ fn expand_macro_recur( | |||
47 | if expanded == *child.syntax() { | 46 | if expanded == *child.syntax() { |
48 | expanded = new_node; | 47 | expanded = new_node; |
49 | } else { | 48 | } else { |
50 | replaces.insert(child.syntax().clone().into(), new_node.into()); | 49 | rewriter.replace(child.syntax(), &new_node) |
51 | } | 50 | } |
52 | } | 51 | } |
53 | } | 52 | } |
54 | 53 | ||
55 | Some(replace_descendants(&expanded, |n| replaces.get(n).cloned())) | 54 | let res = rewriter.rewrite(&expanded); |
55 | Some(res) | ||
56 | } | 56 | } |
57 | 57 | ||
58 | // FIXME: It would also be cool to share logic here and in the mbe tests, | 58 | // FIXME: It would also be cool to share logic here and in the mbe tests, |
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs index 502fcb0cf..8aed94d16 100644 --- a/crates/ra_ide/src/goto_definition.rs +++ b/crates/ra_ide/src/goto_definition.rs | |||
@@ -104,6 +104,9 @@ mod tests { | |||
104 | let (analysis, pos) = analysis_and_position(ra_fixture); | 104 | let (analysis, pos) = analysis_and_position(ra_fixture); |
105 | 105 | ||
106 | let mut navs = analysis.goto_definition(pos).unwrap().unwrap().info; | 106 | let mut navs = analysis.goto_definition(pos).unwrap().unwrap().info; |
107 | if navs.len() == 0 { | ||
108 | panic!("unresolved reference") | ||
109 | } | ||
107 | assert_eq!(navs.len(), 1); | 110 | assert_eq!(navs.len(), 1); |
108 | 111 | ||
109 | let nav = navs.pop().unwrap(); | 112 | let nav = navs.pop().unwrap(); |
@@ -359,7 +362,7 @@ mod tests { | |||
359 | fn goto_def_for_fields() { | 362 | fn goto_def_for_fields() { |
360 | covers!(ra_ide_db::goto_def_for_fields); | 363 | covers!(ra_ide_db::goto_def_for_fields); |
361 | check_goto( | 364 | check_goto( |
362 | " | 365 | r" |
363 | //- /lib.rs | 366 | //- /lib.rs |
364 | struct Foo { | 367 | struct Foo { |
365 | spam: u32, | 368 | spam: u32, |
@@ -378,7 +381,7 @@ mod tests { | |||
378 | fn goto_def_for_record_fields() { | 381 | fn goto_def_for_record_fields() { |
379 | covers!(ra_ide_db::goto_def_for_record_fields); | 382 | covers!(ra_ide_db::goto_def_for_record_fields); |
380 | check_goto( | 383 | check_goto( |
381 | " | 384 | r" |
382 | //- /lib.rs | 385 | //- /lib.rs |
383 | struct Foo { | 386 | struct Foo { |
384 | spam: u32, | 387 | spam: u32, |
@@ -396,6 +399,23 @@ mod tests { | |||
396 | } | 399 | } |
397 | 400 | ||
398 | #[test] | 401 | #[test] |
402 | fn goto_def_for_record_fields_macros() { | ||
403 | check_goto( | ||
404 | r" | ||
405 | //- /lib.rs | ||
406 | macro_rules! m { () => { 92 };} | ||
407 | struct Foo { spam: u32 } | ||
408 | |||
409 | fn bar() -> Foo { | ||
410 | Foo { spam<|>: m!() } | ||
411 | } | ||
412 | ", | ||
413 | "spam RECORD_FIELD_DEF FileId(1) [45; 54) [45; 49)", | ||
414 | "spam: u32|spam", | ||
415 | ); | ||
416 | } | ||
417 | |||
418 | #[test] | ||
399 | fn goto_for_tuple_fields() { | 419 | fn goto_for_tuple_fields() { |
400 | check_goto( | 420 | check_goto( |
401 | " | 421 | " |
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs index ecd615cf4..f4f0751c0 100644 --- a/crates/ra_ide/src/inlay_hints.rs +++ b/crates/ra_ide/src/inlay_hints.rs | |||
@@ -5,7 +5,7 @@ use ra_ide_db::RootDatabase; | |||
5 | use ra_prof::profile; | 5 | use ra_prof::profile; |
6 | use ra_syntax::{ | 6 | use ra_syntax::{ |
7 | ast::{self, ArgListOwner, AstNode, TypeAscriptionOwner}, | 7 | ast::{self, ArgListOwner, AstNode, TypeAscriptionOwner}, |
8 | match_ast, SmolStr, TextRange, | 8 | match_ast, Direction, NodeOrToken, SmolStr, SyntaxKind, TextRange, |
9 | }; | 9 | }; |
10 | 10 | ||
11 | use crate::{FileId, FunctionSignature}; | 11 | use crate::{FileId, FunctionSignature}; |
@@ -14,12 +14,13 @@ use crate::{FileId, FunctionSignature}; | |||
14 | pub struct InlayHintsOptions { | 14 | pub struct InlayHintsOptions { |
15 | pub type_hints: bool, | 15 | pub type_hints: bool, |
16 | pub parameter_hints: bool, | 16 | pub parameter_hints: bool, |
17 | pub chaining_hints: bool, | ||
17 | pub max_length: Option<usize>, | 18 | pub max_length: Option<usize>, |
18 | } | 19 | } |
19 | 20 | ||
20 | impl Default for InlayHintsOptions { | 21 | impl Default for InlayHintsOptions { |
21 | fn default() -> Self { | 22 | fn default() -> Self { |
22 | Self { type_hints: true, parameter_hints: true, max_length: None } | 23 | Self { type_hints: true, parameter_hints: true, chaining_hints: true, max_length: None } |
23 | } | 24 | } |
24 | } | 25 | } |
25 | 26 | ||
@@ -27,6 +28,7 @@ impl Default for InlayHintsOptions { | |||
27 | pub enum InlayKind { | 28 | pub enum InlayKind { |
28 | TypeHint, | 29 | TypeHint, |
29 | ParameterHint, | 30 | ParameterHint, |
31 | ChainingHint, | ||
30 | } | 32 | } |
31 | 33 | ||
32 | #[derive(Debug)] | 34 | #[derive(Debug)] |
@@ -47,6 +49,10 @@ pub(crate) fn inlay_hints( | |||
47 | 49 | ||
48 | let mut res = Vec::new(); | 50 | let mut res = Vec::new(); |
49 | for node in file.syntax().descendants() { | 51 | for node in file.syntax().descendants() { |
52 | if let Some(expr) = ast::Expr::cast(node.clone()) { | ||
53 | get_chaining_hints(&mut res, &sema, options, expr); | ||
54 | } | ||
55 | |||
50 | match_ast! { | 56 | match_ast! { |
51 | match node { | 57 | match node { |
52 | ast::CallExpr(it) => { get_param_name_hints(&mut res, &sema, options, ast::Expr::from(it)); }, | 58 | ast::CallExpr(it) => { get_param_name_hints(&mut res, &sema, options, ast::Expr::from(it)); }, |
@@ -59,6 +65,46 @@ pub(crate) fn inlay_hints( | |||
59 | res | 65 | res |
60 | } | 66 | } |
61 | 67 | ||
68 | fn get_chaining_hints( | ||
69 | acc: &mut Vec<InlayHint>, | ||
70 | sema: &Semantics<RootDatabase>, | ||
71 | options: &InlayHintsOptions, | ||
72 | expr: ast::Expr, | ||
73 | ) -> Option<()> { | ||
74 | if !options.chaining_hints { | ||
75 | return None; | ||
76 | } | ||
77 | |||
78 | let ty = sema.type_of_expr(&expr)?; | ||
79 | if ty.is_unknown() { | ||
80 | return None; | ||
81 | } | ||
82 | |||
83 | let mut tokens = expr | ||
84 | .syntax() | ||
85 | .siblings_with_tokens(Direction::Next) | ||
86 | .filter_map(NodeOrToken::into_token) | ||
87 | .filter(|t| match t.kind() { | ||
88 | SyntaxKind::WHITESPACE if !t.text().contains('\n') => false, | ||
89 | SyntaxKind::COMMENT => false, | ||
90 | _ => true, | ||
91 | }); | ||
92 | |||
93 | // Chaining can be defined as an expression whose next sibling tokens are newline and dot | ||
94 | // Ignoring extra whitespace and comments | ||
95 | let next = tokens.next()?.kind(); | ||
96 | let next_next = tokens.next()?.kind(); | ||
97 | if next == SyntaxKind::WHITESPACE && next_next == SyntaxKind::DOT { | ||
98 | let label = ty.display_truncated(sema.db, options.max_length).to_string(); | ||
99 | acc.push(InlayHint { | ||
100 | range: expr.syntax().text_range(), | ||
101 | kind: InlayKind::ChainingHint, | ||
102 | label: label.into(), | ||
103 | }); | ||
104 | } | ||
105 | Some(()) | ||
106 | } | ||
107 | |||
62 | fn get_param_name_hints( | 108 | fn get_param_name_hints( |
63 | acc: &mut Vec<InlayHint>, | 109 | acc: &mut Vec<InlayHint>, |
64 | sema: &Semantics<RootDatabase>, | 110 | sema: &Semantics<RootDatabase>, |
@@ -238,7 +284,7 @@ mod tests { | |||
238 | let _x = foo(4, 4); | 284 | let _x = foo(4, 4); |
239 | }"#, | 285 | }"#, |
240 | ); | 286 | ); |
241 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ parameter_hints: true, type_hints: false, max_length: None}).unwrap(), @r###" | 287 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ parameter_hints: true, type_hints: false, chaining_hints: false, max_length: None}).unwrap(), @r###" |
242 | [ | 288 | [ |
243 | InlayHint { | 289 | InlayHint { |
244 | range: [106; 107), | 290 | range: [106; 107), |
@@ -262,7 +308,7 @@ mod tests { | |||
262 | let _x = foo(4, 4); | 308 | let _x = foo(4, 4); |
263 | }"#, | 309 | }"#, |
264 | ); | 310 | ); |
265 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ type_hints: false, parameter_hints: false, max_length: None}).unwrap(), @r###"[]"###); | 311 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ type_hints: false, parameter_hints: false, chaining_hints: false, max_length: None}).unwrap(), @r###"[]"###); |
266 | } | 312 | } |
267 | 313 | ||
268 | #[test] | 314 | #[test] |
@@ -274,7 +320,7 @@ mod tests { | |||
274 | let _x = foo(4, 4); | 320 | let _x = foo(4, 4); |
275 | }"#, | 321 | }"#, |
276 | ); | 322 | ); |
277 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ type_hints: true, parameter_hints: false, max_length: None}).unwrap(), @r###" | 323 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ type_hints: true, parameter_hints: false, chaining_hints: false, max_length: None}).unwrap(), @r###" |
278 | [ | 324 | [ |
279 | InlayHint { | 325 | InlayHint { |
280 | range: [97; 99), | 326 | range: [97; 99), |
@@ -1052,4 +1098,124 @@ fn main() { | |||
1052 | "### | 1098 | "### |
1053 | ); | 1099 | ); |
1054 | } | 1100 | } |
1101 | |||
1102 | #[test] | ||
1103 | fn chaining_hints_ignore_comments() { | ||
1104 | let (analysis, file_id) = single_file( | ||
1105 | r#" | ||
1106 | struct A(B); | ||
1107 | impl A { fn into_b(self) -> B { self.0 } } | ||
1108 | struct B(C); | ||
1109 | impl B { fn into_c(self) -> C { self.0 } } | ||
1110 | struct C; | ||
1111 | |||
1112 | fn main() { | ||
1113 | let c = A(B(C)) | ||
1114 | .into_b() // This is a comment | ||
1115 | .into_c(); | ||
1116 | }"#, | ||
1117 | ); | ||
1118 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###" | ||
1119 | [ | ||
1120 | InlayHint { | ||
1121 | range: [232; 269), | ||
1122 | kind: ChainingHint, | ||
1123 | label: "B", | ||
1124 | }, | ||
1125 | InlayHint { | ||
1126 | range: [232; 239), | ||
1127 | kind: ChainingHint, | ||
1128 | label: "A", | ||
1129 | }, | ||
1130 | ]"###); | ||
1131 | } | ||
1132 | |||
1133 | #[test] | ||
1134 | fn chaining_hints_without_newlines() { | ||
1135 | let (analysis, file_id) = single_file( | ||
1136 | r#" | ||
1137 | struct A(B); | ||
1138 | impl A { fn into_b(self) -> B { self.0 } } | ||
1139 | struct B(C); | ||
1140 | impl B { fn into_c(self) -> C { self.0 } } | ||
1141 | struct C; | ||
1142 | |||
1143 | fn main() { | ||
1144 | let c = A(B(C)).into_b().into_c(); | ||
1145 | }"#, | ||
1146 | ); | ||
1147 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###"[]"###); | ||
1148 | } | ||
1149 | |||
1150 | #[test] | ||
1151 | fn struct_access_chaining_hints() { | ||
1152 | let (analysis, file_id) = single_file( | ||
1153 | r#" | ||
1154 | struct A { pub b: B } | ||
1155 | struct B { pub c: C } | ||
1156 | struct C(pub bool); | ||
1157 | |||
1158 | fn main() { | ||
1159 | let x = A { b: B { c: C(true) } } | ||
1160 | .b | ||
1161 | .c | ||
1162 | .0; | ||
1163 | }"#, | ||
1164 | ); | ||
1165 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###" | ||
1166 | [ | ||
1167 | InlayHint { | ||
1168 | range: [150; 221), | ||
1169 | kind: ChainingHint, | ||
1170 | label: "C", | ||
1171 | }, | ||
1172 | InlayHint { | ||
1173 | range: [150; 198), | ||
1174 | kind: ChainingHint, | ||
1175 | label: "B", | ||
1176 | }, | ||
1177 | InlayHint { | ||
1178 | range: [150; 175), | ||
1179 | kind: ChainingHint, | ||
1180 | label: "A", | ||
1181 | }, | ||
1182 | ]"###); | ||
1183 | } | ||
1184 | |||
1185 | #[test] | ||
1186 | fn generic_chaining_hints() { | ||
1187 | let (analysis, file_id) = single_file( | ||
1188 | r#" | ||
1189 | struct A<T>(T); | ||
1190 | struct B<T>(T); | ||
1191 | struct C<T>(T); | ||
1192 | struct X<T,R>(T, R); | ||
1193 | |||
1194 | impl<T> A<T> { | ||
1195 | fn new(t: T) -> Self { A(t) } | ||
1196 | fn into_b(self) -> B<T> { B(self.0) } | ||
1197 | } | ||
1198 | impl<T> B<T> { | ||
1199 | fn into_c(self) -> C<T> { C(self.0) } | ||
1200 | } | ||
1201 | fn main() { | ||
1202 | let c = A::new(X(42, true)) | ||
1203 | .into_b() | ||
1204 | .into_c(); | ||
1205 | }"#, | ||
1206 | ); | ||
1207 | assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###" | ||
1208 | [ | ||
1209 | InlayHint { | ||
1210 | range: [403; 452), | ||
1211 | kind: ChainingHint, | ||
1212 | label: "B<X<i32, bool>>", | ||
1213 | }, | ||
1214 | InlayHint { | ||
1215 | range: [403; 422), | ||
1216 | kind: ChainingHint, | ||
1217 | label: "A<X<i32, bool>>", | ||
1218 | }, | ||
1219 | ]"###); | ||
1220 | } | ||
1055 | } | 1221 | } |
diff --git a/crates/ra_ide_db/Cargo.toml b/crates/ra_ide_db/Cargo.toml index de4f5bce0..c3921bd40 100644 --- a/crates/ra_ide_db/Cargo.toml +++ b/crates/ra_ide_db/Cargo.toml | |||
@@ -17,6 +17,7 @@ fst = { version = "0.4", default-features = false } | |||
17 | rustc-hash = "1.1.0" | 17 | rustc-hash = "1.1.0" |
18 | superslice = "1.0.0" | 18 | superslice = "1.0.0" |
19 | once_cell = "1.3.1" | 19 | once_cell = "1.3.1" |
20 | either = "1.5.3" | ||
20 | 21 | ||
21 | ra_syntax = { path = "../ra_syntax" } | 22 | ra_syntax = { path = "../ra_syntax" } |
22 | ra_text_edit = { path = "../ra_text_edit" } | 23 | ra_text_edit = { path = "../ra_text_edit" } |
diff --git a/crates/ra_ide_db/src/change.rs b/crates/ra_ide_db/src/change.rs index 628cf6416..8446ef88e 100644 --- a/crates/ra_ide_db/src/change.rs +++ b/crates/ra_ide_db/src/change.rs | |||
@@ -311,6 +311,7 @@ impl RootDatabase { | |||
311 | hir::db::MacroDefQuery | 311 | hir::db::MacroDefQuery |
312 | hir::db::ParseMacroQuery | 312 | hir::db::ParseMacroQuery |
313 | hir::db::MacroExpandQuery | 313 | hir::db::MacroExpandQuery |
314 | hir::db::InternEagerExpansionQuery | ||
314 | 315 | ||
315 | // DefDatabase | 316 | // DefDatabase |
316 | hir::db::RawItemsQuery | 317 | hir::db::RawItemsQuery |
@@ -359,14 +360,21 @@ impl RootDatabase { | |||
359 | hir::db::ImplsInCrateQuery | 360 | hir::db::ImplsInCrateQuery |
360 | hir::db::ImplsForTraitQuery | 361 | hir::db::ImplsForTraitQuery |
361 | hir::db::InternTypeCtorQuery | 362 | hir::db::InternTypeCtorQuery |
363 | hir::db::InternTypeParamIdQuery | ||
362 | hir::db::InternChalkImplQuery | 364 | hir::db::InternChalkImplQuery |
363 | hir::db::InternAssocTyValueQuery | 365 | hir::db::InternAssocTyValueQuery |
364 | hir::db::AssociatedTyDataQuery | 366 | hir::db::AssociatedTyDataQuery |
365 | hir::db::AssociatedTyValueQuery | ||
366 | hir::db::TraitSolveQuery | ||
367 | hir::db::TraitDatumQuery | 367 | hir::db::TraitDatumQuery |
368 | hir::db::StructDatumQuery | 368 | hir::db::StructDatumQuery |
369 | hir::db::ImplDatumQuery | 369 | hir::db::ImplDatumQuery |
370 | hir::db::AssociatedTyValueQuery | ||
371 | hir::db::TraitSolveQuery | ||
372 | |||
373 | // SymbolsDatabase | ||
374 | crate::symbol_index::FileSymbolsQuery | ||
375 | |||
376 | // LineIndexDatabase | ||
377 | crate::LineIndexQuery | ||
370 | ]; | 378 | ]; |
371 | acc.sort_by_key(|it| std::cmp::Reverse(it.1)); | 379 | acc.sort_by_key(|it| std::cmp::Reverse(it.1)); |
372 | acc | 380 | acc |
diff --git a/crates/ra_ide_db/src/defs.rs b/crates/ra_ide_db/src/defs.rs index 97961bb6d..e9934844e 100644 --- a/crates/ra_ide_db/src/defs.rs +++ b/crates/ra_ide_db/src/defs.rs | |||
@@ -6,12 +6,12 @@ | |||
6 | // FIXME: this badly needs rename/rewrite (matklad, 2020-02-06). | 6 | // FIXME: this badly needs rename/rewrite (matklad, 2020-02-06). |
7 | 7 | ||
8 | use hir::{ | 8 | use hir::{ |
9 | Adt, FieldSource, HasSource, ImplDef, Local, MacroDef, Module, ModuleDef, Name, PathResolution, | 9 | HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, Name, PathResolution, Semantics, |
10 | Semantics, StructField, TypeParam, | 10 | StructField, TypeParam, Visibility, |
11 | }; | 11 | }; |
12 | use ra_prof::profile; | 12 | use ra_prof::profile; |
13 | use ra_syntax::{ | 13 | use ra_syntax::{ |
14 | ast::{self, AstNode, VisibilityOwner}, | 14 | ast::{self, AstNode}, |
15 | match_ast, | 15 | match_ast, |
16 | }; | 16 | }; |
17 | use test_utils::tested_by; | 17 | use test_utils::tested_by; |
@@ -41,28 +41,13 @@ impl Definition { | |||
41 | } | 41 | } |
42 | } | 42 | } |
43 | 43 | ||
44 | pub fn visibility(&self, db: &RootDatabase) -> Option<ast::Visibility> { | 44 | pub fn visibility(&self, db: &RootDatabase) -> Option<Visibility> { |
45 | let module = self.module(db); | ||
46 | |||
45 | match self { | 47 | match self { |
46 | Definition::Macro(_) => None, | 48 | Definition::Macro(_) => None, |
47 | Definition::StructField(sf) => match sf.source(db).value { | 49 | Definition::StructField(sf) => Some(sf.visibility(db)), |
48 | FieldSource::Named(it) => it.visibility(), | 50 | Definition::ModuleDef(def) => module?.visibility_of(db, def), |
49 | FieldSource::Pos(it) => it.visibility(), | ||
50 | }, | ||
51 | Definition::ModuleDef(def) => match def { | ||
52 | ModuleDef::Module(it) => it.declaration_source(db)?.value.visibility(), | ||
53 | ModuleDef::Function(it) => it.source(db).value.visibility(), | ||
54 | ModuleDef::Adt(adt) => match adt { | ||
55 | Adt::Struct(it) => it.source(db).value.visibility(), | ||
56 | Adt::Union(it) => it.source(db).value.visibility(), | ||
57 | Adt::Enum(it) => it.source(db).value.visibility(), | ||
58 | }, | ||
59 | ModuleDef::Const(it) => it.source(db).value.visibility(), | ||
60 | ModuleDef::Static(it) => it.source(db).value.visibility(), | ||
61 | ModuleDef::Trait(it) => it.source(db).value.visibility(), | ||
62 | ModuleDef::TypeAlias(it) => it.source(db).value.visibility(), | ||
63 | ModuleDef::EnumVariant(_) => None, | ||
64 | ModuleDef::BuiltinType(_) => None, | ||
65 | }, | ||
66 | Definition::SelfType(_) => None, | 51 | Definition::SelfType(_) => None, |
67 | Definition::Local(_) => None, | 52 | Definition::Local(_) => None, |
68 | Definition::TypeParam(_) => None, | 53 | Definition::TypeParam(_) => None, |
diff --git a/crates/ra_ide_db/src/imports_locator.rs b/crates/ra_ide_db/src/imports_locator.rs index c96351982..bf0d8db60 100644 --- a/crates/ra_ide_db/src/imports_locator.rs +++ b/crates/ra_ide_db/src/imports_locator.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | //! This module contains an import search funcionality that is provided to the ra_assists module. | 1 | //! This module contains an import search funcionality that is provided to the ra_assists module. |
2 | //! Later, this should be moved away to a separate crate that is accessible from the ra_assists module. | 2 | //! Later, this should be moved away to a separate crate that is accessible from the ra_assists module. |
3 | 3 | ||
4 | use hir::{ModuleDef, Semantics}; | 4 | use hir::{MacroDef, ModuleDef, Semantics}; |
5 | use ra_prof::profile; | 5 | use ra_prof::profile; |
6 | use ra_syntax::{ast, AstNode, SyntaxKind::NAME}; | 6 | use ra_syntax::{ast, AstNode, SyntaxKind::NAME}; |
7 | 7 | ||
@@ -10,6 +10,7 @@ use crate::{ | |||
10 | symbol_index::{self, FileSymbol, Query}, | 10 | symbol_index::{self, FileSymbol, Query}, |
11 | RootDatabase, | 11 | RootDatabase, |
12 | }; | 12 | }; |
13 | use either::Either; | ||
13 | 14 | ||
14 | pub struct ImportsLocator<'a> { | 15 | pub struct ImportsLocator<'a> { |
15 | sema: Semantics<'a, RootDatabase>, | 16 | sema: Semantics<'a, RootDatabase>, |
@@ -20,7 +21,7 @@ impl<'a> ImportsLocator<'a> { | |||
20 | Self { sema: Semantics::new(db) } | 21 | Self { sema: Semantics::new(db) } |
21 | } | 22 | } |
22 | 23 | ||
23 | pub fn find_imports(&mut self, name_to_import: &str) -> Vec<ModuleDef> { | 24 | pub fn find_imports(&mut self, name_to_import: &str) -> Vec<Either<ModuleDef, MacroDef>> { |
24 | let _p = profile("search_for_imports"); | 25 | let _p = profile("search_for_imports"); |
25 | let db = self.sema.db; | 26 | let db = self.sema.db; |
26 | 27 | ||
@@ -43,7 +44,8 @@ impl<'a> ImportsLocator<'a> { | |||
43 | .chain(lib_results.into_iter()) | 44 | .chain(lib_results.into_iter()) |
44 | .filter_map(|import_candidate| self.get_name_definition(&import_candidate)) | 45 | .filter_map(|import_candidate| self.get_name_definition(&import_candidate)) |
45 | .filter_map(|name_definition_to_import| match name_definition_to_import { | 46 | .filter_map(|name_definition_to_import| match name_definition_to_import { |
46 | Definition::ModuleDef(module_def) => Some(module_def), | 47 | Definition::ModuleDef(module_def) => Some(Either::Left(module_def)), |
48 | Definition::Macro(macro_def) => Some(Either::Right(macro_def)), | ||
47 | _ => None, | 49 | _ => None, |
48 | }) | 50 | }) |
49 | .collect() | 51 | .collect() |
diff --git a/crates/ra_ide_db/src/search.rs b/crates/ra_ide_db/src/search.rs index 117454695..05a0eed30 100644 --- a/crates/ra_ide_db/src/search.rs +++ b/crates/ra_ide_db/src/search.rs | |||
@@ -6,7 +6,7 @@ | |||
6 | 6 | ||
7 | use std::mem; | 7 | use std::mem; |
8 | 8 | ||
9 | use hir::{DefWithBody, HasSource, ModuleSource, Semantics}; | 9 | use hir::{DefWithBody, HasSource, Module, ModuleSource, Semantics, Visibility}; |
10 | use once_cell::unsync::Lazy; | 10 | use once_cell::unsync::Lazy; |
11 | use ra_db::{FileId, FileRange, SourceDatabaseExt}; | 11 | use ra_db::{FileId, FileRange, SourceDatabaseExt}; |
12 | use ra_prof::profile; | 12 | use ra_prof::profile; |
@@ -123,51 +123,47 @@ impl Definition { | |||
123 | return SearchScope::new(res); | 123 | return SearchScope::new(res); |
124 | } | 124 | } |
125 | 125 | ||
126 | let vis = self.visibility(db).as_ref().map(|v| v.syntax().to_string()).unwrap_or_default(); | 126 | let vis = self.visibility(db); |
127 | 127 | ||
128 | if vis.as_str() == "pub(super)" { | 128 | // FIXME: |
129 | if let Some(parent_module) = module.parent(db) { | 129 | // The following logic are wrong that it does not search |
130 | let mut res = FxHashMap::default(); | 130 | // for submodules within other files recursively. |
131 | let parent_src = parent_module.definition_source(db); | ||
132 | let file_id = parent_src.file_id.original_file(db); | ||
133 | 131 | ||
134 | match parent_src.value { | 132 | if let Some(Visibility::Module(module)) = vis.and_then(|it| it.into()) { |
135 | ModuleSource::Module(m) => { | 133 | let module: Module = module.into(); |
136 | let range = Some(m.syntax().text_range()); | 134 | let mut res = FxHashMap::default(); |
137 | res.insert(file_id, range); | 135 | let src = module.definition_source(db); |
138 | } | 136 | let file_id = src.file_id.original_file(db); |
139 | ModuleSource::SourceFile(_) => { | 137 | |
140 | res.insert(file_id, None); | 138 | match src.value { |
141 | res.extend(parent_module.children(db).map(|m| { | 139 | ModuleSource::Module(m) => { |
142 | let src = m.definition_source(db); | 140 | let range = Some(m.syntax().text_range()); |
143 | (src.file_id.original_file(db), None) | 141 | res.insert(file_id, range); |
144 | })); | 142 | } |
145 | } | 143 | ModuleSource::SourceFile(_) => { |
144 | res.insert(file_id, None); | ||
145 | res.extend(module.children(db).map(|m| { | ||
146 | let src = m.definition_source(db); | ||
147 | (src.file_id.original_file(db), None) | ||
148 | })); | ||
146 | } | 149 | } |
147 | return SearchScope::new(res); | ||
148 | } | 150 | } |
151 | return SearchScope::new(res); | ||
149 | } | 152 | } |
150 | 153 | ||
151 | if vis.as_str() != "" { | 154 | if let Some(Visibility::Public) = vis { |
152 | let source_root_id = db.file_source_root(file_id); | 155 | let source_root_id = db.file_source_root(file_id); |
153 | let source_root = db.source_root(source_root_id); | 156 | let source_root = db.source_root(source_root_id); |
154 | let mut res = source_root.walk().map(|id| (id, None)).collect::<FxHashMap<_, _>>(); | 157 | let mut res = source_root.walk().map(|id| (id, None)).collect::<FxHashMap<_, _>>(); |
155 | 158 | ||
156 | // FIXME: add "pub(in path)" | 159 | let krate = module.krate(); |
157 | 160 | for rev_dep in krate.reverse_dependencies(db) { | |
158 | if vis.as_str() == "pub(crate)" { | 161 | let root_file = rev_dep.root_file(db); |
159 | return SearchScope::new(res); | 162 | let source_root_id = db.file_source_root(root_file); |
160 | } | 163 | let source_root = db.source_root(source_root_id); |
161 | if vis.as_str() == "pub" { | 164 | res.extend(source_root.walk().map(|id| (id, None))); |
162 | let krate = module.krate(); | ||
163 | for rev_dep in krate.reverse_dependencies(db) { | ||
164 | let root_file = rev_dep.root_file(db); | ||
165 | let source_root_id = db.file_source_root(root_file); | ||
166 | let source_root = db.source_root(source_root_id); | ||
167 | res.extend(source_root.walk().map(|id| (id, None))); | ||
168 | } | ||
169 | return SearchScope::new(res); | ||
170 | } | 165 | } |
166 | return SearchScope::new(res); | ||
171 | } | 167 | } |
172 | 168 | ||
173 | let mut res = FxHashMap::default(); | 169 | let mut res = FxHashMap::default(); |
diff --git a/crates/ra_mbe/src/syntax_bridge.rs b/crates/ra_mbe/src/syntax_bridge.rs index fcb73fbc7..8e8ae2b29 100644 --- a/crates/ra_mbe/src/syntax_bridge.rs +++ b/crates/ra_mbe/src/syntax_bridge.rs | |||
@@ -3,12 +3,11 @@ | |||
3 | use ra_parser::{FragmentKind, ParseError, TreeSink}; | 3 | use ra_parser::{FragmentKind, ParseError, TreeSink}; |
4 | use ra_syntax::{ | 4 | use ra_syntax::{ |
5 | ast::{self, make::tokens::doc_comment}, | 5 | ast::{self, make::tokens::doc_comment}, |
6 | tokenize, AstToken, NodeOrToken, Parse, SmolStr, SyntaxKind, | 6 | tokenize, AstToken, Parse, SmolStr, SyntaxKind, |
7 | SyntaxKind::*, | 7 | SyntaxKind::*, |
8 | SyntaxNode, SyntaxTreeBuilder, TextRange, TextUnit, Token, T, | 8 | SyntaxNode, SyntaxToken, SyntaxTreeBuilder, TextRange, TextUnit, Token as RawToken, T, |
9 | }; | 9 | }; |
10 | use rustc_hash::FxHashMap; | 10 | use rustc_hash::FxHashMap; |
11 | use std::iter::successors; | ||
12 | use tt::buffer::{Cursor, TokenBuffer}; | 11 | use tt::buffer::{Cursor, TokenBuffer}; |
13 | 12 | ||
14 | use crate::subtree_source::SubtreeTokenSource; | 13 | use crate::subtree_source::SubtreeTokenSource; |
@@ -34,7 +33,7 @@ impl TokenTextRange { | |||
34 | } | 33 | } |
35 | 34 | ||
36 | /// Maps `tt::TokenId` to the relative range of the original token. | 35 | /// Maps `tt::TokenId` to the relative range of the original token. |
37 | #[derive(Debug, PartialEq, Eq, Default)] | 36 | #[derive(Debug, PartialEq, Eq, Clone, Default)] |
38 | pub struct TokenMap { | 37 | pub struct TokenMap { |
39 | /// Maps `tt::TokenId` to the *relative* source range. | 38 | /// Maps `tt::TokenId` to the *relative* source range. |
40 | entries: Vec<(tt::TokenId, TokenTextRange)>, | 39 | entries: Vec<(tt::TokenId, TokenTextRange)>, |
@@ -50,10 +49,8 @@ pub fn ast_to_token_tree(ast: &impl ast::AstNode) -> Option<(tt::Subtree, TokenM | |||
50 | /// will consume). | 49 | /// will consume). |
51 | pub fn syntax_node_to_token_tree(node: &SyntaxNode) -> Option<(tt::Subtree, TokenMap)> { | 50 | pub fn syntax_node_to_token_tree(node: &SyntaxNode) -> Option<(tt::Subtree, TokenMap)> { |
52 | let global_offset = node.text_range().start(); | 51 | let global_offset = node.text_range().start(); |
53 | let mut c = Convertor { | 52 | let mut c = Convertor::new(node, global_offset); |
54 | id_alloc: { TokenIdAlloc { map: TokenMap::default(), global_offset, next_id: 0 } }, | 53 | let subtree = c.go()?; |
55 | }; | ||
56 | let subtree = c.go(node)?; | ||
57 | Some((subtree, c.id_alloc.map)) | 54 | Some((subtree, c.id_alloc.map)) |
58 | } | 55 | } |
59 | 56 | ||
@@ -152,6 +149,10 @@ impl TokenMap { | |||
152 | } | 149 | } |
153 | } | 150 | } |
154 | } | 151 | } |
152 | |||
153 | fn remove_delim(&mut self, token_id: tt::TokenId) { | ||
154 | self.entries.retain(|(tid, _)| *tid != token_id); | ||
155 | } | ||
155 | } | 156 | } |
156 | 157 | ||
157 | /// Returns the textual content of a doc comment block as a quoted string | 158 | /// Returns the textual content of a doc comment block as a quoted string |
@@ -237,25 +238,26 @@ impl TokenIdAlloc { | |||
237 | token_id | 238 | token_id |
238 | } | 239 | } |
239 | 240 | ||
240 | fn delim(&mut self, open_abs_range: TextRange, close_abs_range: TextRange) -> tt::TokenId { | ||
241 | let open_relative_range = open_abs_range - self.global_offset; | ||
242 | let close_relative_range = close_abs_range - self.global_offset; | ||
243 | let token_id = tt::TokenId(self.next_id); | ||
244 | self.next_id += 1; | ||
245 | |||
246 | self.map.insert_delim(token_id, open_relative_range, close_relative_range); | ||
247 | token_id | ||
248 | } | ||
249 | |||
250 | fn open_delim(&mut self, open_abs_range: TextRange) -> tt::TokenId { | 241 | fn open_delim(&mut self, open_abs_range: TextRange) -> tt::TokenId { |
251 | let token_id = tt::TokenId(self.next_id); | 242 | let token_id = tt::TokenId(self.next_id); |
252 | self.next_id += 1; | 243 | self.next_id += 1; |
253 | self.map.insert_delim(token_id, open_abs_range, open_abs_range); | 244 | self.map.insert_delim( |
245 | token_id, | ||
246 | open_abs_range - self.global_offset, | ||
247 | open_abs_range - self.global_offset, | ||
248 | ); | ||
254 | token_id | 249 | token_id |
255 | } | 250 | } |
256 | 251 | ||
257 | fn close_delim(&mut self, id: tt::TokenId, close_abs_range: TextRange) { | 252 | fn close_delim(&mut self, id: tt::TokenId, close_abs_range: Option<TextRange>) { |
258 | self.map.update_close_delim(id, close_abs_range); | 253 | match close_abs_range { |
254 | None => { | ||
255 | self.map.remove_delim(id); | ||
256 | } | ||
257 | Some(close) => { | ||
258 | self.map.update_close_delim(id, close - self.global_offset); | ||
259 | } | ||
260 | } | ||
259 | } | 261 | } |
260 | } | 262 | } |
261 | 263 | ||
@@ -264,10 +266,20 @@ struct RawConvertor<'a> { | |||
264 | text: &'a str, | 266 | text: &'a str, |
265 | offset: TextUnit, | 267 | offset: TextUnit, |
266 | id_alloc: TokenIdAlloc, | 268 | id_alloc: TokenIdAlloc, |
267 | inner: std::slice::Iter<'a, Token>, | 269 | inner: std::slice::Iter<'a, RawToken>, |
268 | } | 270 | } |
269 | 271 | ||
270 | impl RawConvertor<'_> { | 272 | trait SrcToken { |
273 | fn kind(&self) -> SyntaxKind; | ||
274 | |||
275 | fn to_char(&self) -> Option<char>; | ||
276 | |||
277 | fn to_text(&self) -> SmolStr; | ||
278 | } | ||
279 | |||
280 | trait TokenConvertor { | ||
281 | type Token: SrcToken; | ||
282 | |||
271 | fn go(&mut self) -> Option<tt::Subtree> { | 283 | fn go(&mut self) -> Option<tt::Subtree> { |
272 | let mut subtree = tt::Subtree::default(); | 284 | let mut subtree = tt::Subtree::default(); |
273 | subtree.delimiter = None; | 285 | subtree.delimiter = None; |
@@ -285,33 +297,22 @@ impl RawConvertor<'_> { | |||
285 | Some(subtree) | 297 | Some(subtree) |
286 | } | 298 | } |
287 | 299 | ||
288 | fn bump(&mut self) -> Option<(Token, TextRange)> { | ||
289 | let token = self.inner.next()?; | ||
290 | let range = TextRange::offset_len(self.offset, token.len); | ||
291 | self.offset += token.len; | ||
292 | Some((*token, range)) | ||
293 | } | ||
294 | |||
295 | fn peek(&self) -> Option<Token> { | ||
296 | self.inner.as_slice().get(0).cloned() | ||
297 | } | ||
298 | |||
299 | fn collect_leaf(&mut self, result: &mut Vec<tt::TokenTree>) { | 300 | fn collect_leaf(&mut self, result: &mut Vec<tt::TokenTree>) { |
300 | let (token, range) = match self.bump() { | 301 | let (token, range) = match self.bump() { |
301 | None => return, | 302 | None => return, |
302 | Some(it) => it, | 303 | Some(it) => it, |
303 | }; | 304 | }; |
304 | 305 | ||
305 | let k: SyntaxKind = token.kind; | 306 | let k: SyntaxKind = token.kind(); |
306 | if k == COMMENT { | 307 | if k == COMMENT { |
307 | let node = doc_comment(&self.text[range]); | 308 | if let Some(tokens) = self.convert_doc_comment(&token) { |
308 | if let Some(tokens) = convert_doc_comment(&node) { | ||
309 | result.extend(tokens); | 309 | result.extend(tokens); |
310 | } | 310 | } |
311 | return; | 311 | return; |
312 | } | 312 | } |
313 | 313 | ||
314 | result.push(if k.is_punct() { | 314 | result.push(if k.is_punct() { |
315 | assert_eq!(range.len().to_usize(), 1); | ||
315 | let delim = match k { | 316 | let delim = match k { |
316 | T!['('] => Some((tt::DelimiterKind::Parenthesis, T![')'])), | 317 | T!['('] => Some((tt::DelimiterKind::Parenthesis, T![')'])), |
317 | T!['{'] => Some((tt::DelimiterKind::Brace, T!['}'])), | 318 | T!['{'] => Some((tt::DelimiterKind::Brace, T!['}'])), |
@@ -321,40 +322,51 @@ impl RawConvertor<'_> { | |||
321 | 322 | ||
322 | if let Some((kind, closed)) = delim { | 323 | if let Some((kind, closed)) = delim { |
323 | let mut subtree = tt::Subtree::default(); | 324 | let mut subtree = tt::Subtree::default(); |
324 | let id = self.id_alloc.open_delim(range); | 325 | let id = self.id_alloc().open_delim(range); |
325 | subtree.delimiter = Some(tt::Delimiter { kind, id }); | 326 | subtree.delimiter = Some(tt::Delimiter { kind, id }); |
326 | 327 | ||
327 | while self.peek().map(|it| it.kind != closed).unwrap_or(false) { | 328 | while self.peek().map(|it| it.kind() != closed).unwrap_or(false) { |
328 | self.collect_leaf(&mut subtree.token_trees); | 329 | self.collect_leaf(&mut subtree.token_trees); |
329 | } | 330 | } |
330 | let last_range = match self.bump() { | 331 | let last_range = match self.bump() { |
331 | None => return, | 332 | None => { |
333 | // For error resilience, we insert an char punct for the opening delim here | ||
334 | self.id_alloc().close_delim(id, None); | ||
335 | let leaf: tt::Leaf = tt::Punct { | ||
336 | id: self.id_alloc().alloc(range), | ||
337 | char: token.to_char().unwrap(), | ||
338 | spacing: tt::Spacing::Alone, | ||
339 | } | ||
340 | .into(); | ||
341 | result.push(leaf.into()); | ||
342 | result.extend(subtree.token_trees); | ||
343 | return; | ||
344 | } | ||
332 | Some(it) => it.1, | 345 | Some(it) => it.1, |
333 | }; | 346 | }; |
334 | self.id_alloc.close_delim(id, last_range); | 347 | self.id_alloc().close_delim(id, Some(last_range)); |
335 | subtree.into() | 348 | subtree.into() |
336 | } else { | 349 | } else { |
337 | let spacing = match self.peek() { | 350 | let spacing = match self.peek() { |
338 | Some(next) | 351 | Some(next) |
339 | if next.kind.is_trivia() | 352 | if next.kind().is_trivia() |
340 | || next.kind == T!['['] | 353 | || next.kind() == T!['['] |
341 | || next.kind == T!['{'] | 354 | || next.kind() == T!['{'] |
342 | || next.kind == T!['('] => | 355 | || next.kind() == T!['('] => |
343 | { | 356 | { |
344 | tt::Spacing::Alone | 357 | tt::Spacing::Alone |
345 | } | 358 | } |
346 | Some(next) if next.kind.is_punct() => tt::Spacing::Joint, | 359 | Some(next) if next.kind().is_punct() => tt::Spacing::Joint, |
347 | _ => tt::Spacing::Alone, | 360 | _ => tt::Spacing::Alone, |
348 | }; | 361 | }; |
349 | let char = | 362 | let char = token.to_char().expect("Token from lexer must be single char"); |
350 | self.text[range].chars().next().expect("Token from lexer must be single char"); | ||
351 | 363 | ||
352 | tt::Leaf::from(tt::Punct { char, spacing, id: self.id_alloc.alloc(range) }).into() | 364 | tt::Leaf::from(tt::Punct { char, spacing, id: self.id_alloc().alloc(range) }).into() |
353 | } | 365 | } |
354 | } else { | 366 | } else { |
355 | macro_rules! make_leaf { | 367 | macro_rules! make_leaf { |
356 | ($i:ident) => { | 368 | ($i:ident) => { |
357 | tt::$i { id: self.id_alloc.alloc(range), text: self.text[range].into() }.into() | 369 | tt::$i { id: self.id_alloc().alloc(range), text: token.to_text() }.into() |
358 | }; | 370 | }; |
359 | } | 371 | } |
360 | let leaf: tt::Leaf = match k { | 372 | let leaf: tt::Leaf = match k { |
@@ -368,133 +380,168 @@ impl RawConvertor<'_> { | |||
368 | leaf.into() | 380 | leaf.into() |
369 | }); | 381 | }); |
370 | } | 382 | } |
383 | |||
384 | fn convert_doc_comment(&self, token: &Self::Token) -> Option<Vec<tt::TokenTree>>; | ||
385 | |||
386 | fn bump(&mut self) -> Option<(Self::Token, TextRange)>; | ||
387 | |||
388 | fn peek(&self) -> Option<Self::Token>; | ||
389 | |||
390 | fn id_alloc(&mut self) -> &mut TokenIdAlloc; | ||
391 | } | ||
392 | |||
393 | impl<'a> SrcToken for (RawToken, &'a str) { | ||
394 | fn kind(&self) -> SyntaxKind { | ||
395 | self.0.kind | ||
396 | } | ||
397 | |||
398 | fn to_char(&self) -> Option<char> { | ||
399 | self.1.chars().next() | ||
400 | } | ||
401 | |||
402 | fn to_text(&self) -> SmolStr { | ||
403 | self.1.into() | ||
404 | } | ||
405 | } | ||
406 | |||
407 | impl RawConvertor<'_> {} | ||
408 | |||
409 | impl<'a> TokenConvertor for RawConvertor<'a> { | ||
410 | type Token = (RawToken, &'a str); | ||
411 | |||
412 | fn convert_doc_comment(&self, token: &Self::Token) -> Option<Vec<tt::TokenTree>> { | ||
413 | convert_doc_comment(&doc_comment(token.1)) | ||
414 | } | ||
415 | |||
416 | fn bump(&mut self) -> Option<(Self::Token, TextRange)> { | ||
417 | let token = self.inner.next()?; | ||
418 | let range = TextRange::offset_len(self.offset, token.len); | ||
419 | self.offset += token.len; | ||
420 | |||
421 | Some(((*token, &self.text[range]), range)) | ||
422 | } | ||
423 | |||
424 | fn peek(&self) -> Option<Self::Token> { | ||
425 | let token = self.inner.as_slice().get(0).cloned(); | ||
426 | |||
427 | token.map(|it| { | ||
428 | let range = TextRange::offset_len(self.offset, it.len); | ||
429 | (it, &self.text[range]) | ||
430 | }) | ||
431 | } | ||
432 | |||
433 | fn id_alloc(&mut self) -> &mut TokenIdAlloc { | ||
434 | &mut self.id_alloc | ||
435 | } | ||
371 | } |