diff options
121 files changed, 3733 insertions, 1269 deletions
diff --git a/Cargo.lock b/Cargo.lock index e3ad50623..efe8dd189 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -11,9 +11,9 @@ dependencies = [ | |||
11 | 11 | ||
12 | [[package]] | 12 | [[package]] |
13 | name = "anyhow" | 13 | name = "anyhow" |
14 | version = "1.0.26" | 14 | version = "1.0.27" |
15 | source = "registry+https://github.com/rust-lang/crates.io-index" | 15 | source = "registry+https://github.com/rust-lang/crates.io-index" |
16 | checksum = "7825f6833612eb2414095684fcf6c635becf3ce97fe48cf6421321e93bfbd53c" | 16 | checksum = "013a6e0a2cbe3d20f9c60b65458f7a7f7a5e636c5d0f45a5a6aee5d4b1f01785" |
17 | 17 | ||
18 | [[package]] | 18 | [[package]] |
19 | name = "anymap" | 19 | name = "anymap" |
@@ -58,9 +58,9 @@ dependencies = [ | |||
58 | 58 | ||
59 | [[package]] | 59 | [[package]] |
60 | name = "backtrace-sys" | 60 | name = "backtrace-sys" |
61 | version = "0.1.33" | 61 | version = "0.1.34" |
62 | source = "registry+https://github.com/rust-lang/crates.io-index" | 62 | source = "registry+https://github.com/rust-lang/crates.io-index" |
63 | checksum = "e17b52e737c40a7d75abca20b29a19a0eb7ba9fc72c5a72dd282a0a3c2c0dc35" | 63 | checksum = "ca797db0057bae1a7aa2eef3283a874695455cecf08a43bfb8507ee0ebc1ed69" |
64 | dependencies = [ | 64 | dependencies = [ |
65 | "cc", | 65 | "cc", |
66 | "libc", | 66 | "libc", |
@@ -80,29 +80,14 @@ checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" | |||
80 | 80 | ||
81 | [[package]] | 81 | [[package]] |
82 | name = "bstr" | 82 | name = "bstr" |
83 | version = "0.2.11" | 83 | version = "0.2.12" |
84 | source = "registry+https://github.com/rust-lang/crates.io-index" | 84 | source = "registry+https://github.com/rust-lang/crates.io-index" |
85 | checksum = "502ae1441a0a5adb8fbd38a5955a6416b9493e92b465de5e4a9bde6a539c2c48" | 85 | checksum = "2889e6d50f394968c8bf4240dc3f2a7eb4680844d27308f798229ac9d4725f41" |
86 | dependencies = [ | 86 | dependencies = [ |
87 | "memchr", | 87 | "memchr", |
88 | ] | 88 | ] |
89 | 89 | ||
90 | [[package]] | 90 | [[package]] |
91 | name = "byteorder" | ||
92 | version = "1.3.4" | ||
93 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
94 | checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" | ||
95 | |||
96 | [[package]] | ||
97 | name = "c2-chacha" | ||
98 | version = "0.2.3" | ||
99 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
100 | checksum = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" | ||
101 | dependencies = [ | ||
102 | "ppv-lite86", | ||
103 | ] | ||
104 | |||
105 | [[package]] | ||
106 | name = "cargo_metadata" | 91 | name = "cargo_metadata" |
107 | version = "0.9.1" | 92 | version = "0.9.1" |
108 | source = "registry+https://github.com/rust-lang/crates.io-index" | 93 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -401,12 +386,9 @@ dependencies = [ | |||
401 | 386 | ||
402 | [[package]] | 387 | [[package]] |
403 | name = "fst" | 388 | name = "fst" |
404 | version = "0.3.5" | 389 | version = "0.4.0" |
405 | source = "registry+https://github.com/rust-lang/crates.io-index" | 390 | source = "registry+https://github.com/rust-lang/crates.io-index" |
406 | checksum = "927fb434ff9f0115b215dc0efd2e4fbdd7448522a92a1aa37c77d6a2f8f1ebd6" | 391 | checksum = "3f7c13470d799474d44e2b9c6a0925807def7af4d120cd4de761433be76f7579" |
407 | dependencies = [ | ||
408 | "byteorder", | ||
409 | ] | ||
410 | 392 | ||
411 | [[package]] | 393 | [[package]] |
412 | name = "fuchsia-zircon" | 394 | name = "fuchsia-zircon" |
@@ -958,6 +940,7 @@ dependencies = [ | |||
958 | name = "ra_hir" | 940 | name = "ra_hir" |
959 | version = "0.1.0" | 941 | version = "0.1.0" |
960 | dependencies = [ | 942 | dependencies = [ |
943 | "arrayvec", | ||
961 | "either", | 944 | "either", |
962 | "itertools", | 945 | "itertools", |
963 | "log", | 946 | "log", |
@@ -1180,11 +1163,11 @@ dependencies = [ | |||
1180 | 1163 | ||
1181 | [[package]] | 1164 | [[package]] |
1182 | name = "rand_chacha" | 1165 | name = "rand_chacha" |
1183 | version = "0.2.1" | 1166 | version = "0.2.2" |
1184 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1167 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1185 | checksum = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" | 1168 | checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" |
1186 | dependencies = [ | 1169 | dependencies = [ |
1187 | "c2-chacha", | 1170 | "ppv-lite86", |
1188 | "rand_core", | 1171 | "rand_core", |
1189 | ] | 1172 | ] |
1190 | 1173 | ||
@@ -1247,9 +1230,9 @@ checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" | |||
1247 | 1230 | ||
1248 | [[package]] | 1231 | [[package]] |
1249 | name = "regex" | 1232 | name = "regex" |
1250 | version = "1.3.4" | 1233 | version = "1.3.5" |
1251 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1234 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1252 | checksum = "322cf97724bea3ee221b78fe25ac9c46114ebb51747ad5babd51a2fc6a8235a8" | 1235 | checksum = "8900ebc1363efa7ea1c399ccc32daed870b4002651e0bed86e72d501ebbe0048" |
1253 | dependencies = [ | 1236 | dependencies = [ |
1254 | "aho-corasick", | 1237 | "aho-corasick", |
1255 | "memchr", | 1238 | "memchr", |
@@ -1259,9 +1242,9 @@ dependencies = [ | |||
1259 | 1242 | ||
1260 | [[package]] | 1243 | [[package]] |
1261 | name = "regex-syntax" | 1244 | name = "regex-syntax" |
1262 | version = "0.6.16" | 1245 | version = "0.6.17" |
1263 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1246 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1264 | checksum = "1132f845907680735a84409c3bebc64d1364a5683ffbce899550cd09d5eaefc1" | 1247 | checksum = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae" |
1265 | 1248 | ||
1266 | [[package]] | 1249 | [[package]] |
1267 | name = "relative-path" | 1250 | name = "relative-path" |
@@ -1359,9 +1342,9 @@ dependencies = [ | |||
1359 | 1342 | ||
1360 | [[package]] | 1343 | [[package]] |
1361 | name = "ryu" | 1344 | name = "ryu" |
1362 | version = "1.0.2" | 1345 | version = "1.0.3" |
1363 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1346 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1364 | checksum = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" | 1347 | checksum = "535622e6be132bccd223f4bb2b8ac8d53cda3c7a6394944d3b2b33fb974f9d76" |
1365 | 1348 | ||
1366 | [[package]] | 1349 | [[package]] |
1367 | name = "salsa" | 1350 | name = "salsa" |
diff --git a/crates/ra_assists/src/ast_transform.rs b/crates/ra_assists/src/ast_transform.rs index 42856f0ca..45558c448 100644 --- a/crates/ra_assists/src/ast_transform.rs +++ b/crates/ra_assists/src/ast_transform.rs | |||
@@ -37,7 +37,6 @@ pub struct SubstituteTypeParams<'a> { | |||
37 | impl<'a> SubstituteTypeParams<'a> { | 37 | impl<'a> SubstituteTypeParams<'a> { |
38 | pub fn for_trait_impl( | 38 | pub fn for_trait_impl( |
39 | source_scope: &'a SemanticsScope<'a, RootDatabase>, | 39 | source_scope: &'a SemanticsScope<'a, RootDatabase>, |
40 | db: &'a RootDatabase, | ||
41 | // FIXME: there's implicit invariant that `trait_` and `source_scope` match... | 40 | // FIXME: there's implicit invariant that `trait_` and `source_scope` match... |
42 | trait_: hir::Trait, | 41 | trait_: hir::Trait, |
43 | impl_def: ast::ImplDef, | 42 | impl_def: ast::ImplDef, |
@@ -45,7 +44,7 @@ impl<'a> SubstituteTypeParams<'a> { | |||
45 | let substs = get_syntactic_substs(impl_def).unwrap_or_default(); | 44 | let substs = get_syntactic_substs(impl_def).unwrap_or_default(); |
46 | let generic_def: hir::GenericDef = trait_.into(); | 45 | let generic_def: hir::GenericDef = trait_.into(); |
47 | let substs_by_param: FxHashMap<_, _> = generic_def | 46 | let substs_by_param: FxHashMap<_, _> = generic_def |
48 | .params(db) | 47 | .params(source_scope.db) |
49 | .into_iter() | 48 | .into_iter() |
50 | // this is a trait impl, so we need to skip the first type parameter -- this is a bit hacky | 49 | // this is a trait impl, so we need to skip the first type parameter -- this is a bit hacky |
51 | .skip(1) | 50 | .skip(1) |
@@ -104,7 +103,6 @@ impl<'a> AstTransform<'a> for SubstituteTypeParams<'a> { | |||
104 | pub struct QualifyPaths<'a> { | 103 | pub struct QualifyPaths<'a> { |
105 | target_scope: &'a SemanticsScope<'a, RootDatabase>, | 104 | target_scope: &'a SemanticsScope<'a, RootDatabase>, |
106 | source_scope: &'a SemanticsScope<'a, RootDatabase>, | 105 | source_scope: &'a SemanticsScope<'a, RootDatabase>, |
107 | db: &'a RootDatabase, | ||
108 | previous: Box<dyn AstTransform<'a> + 'a>, | 106 | previous: Box<dyn AstTransform<'a> + 'a>, |
109 | } | 107 | } |
110 | 108 | ||
@@ -112,9 +110,8 @@ impl<'a> QualifyPaths<'a> { | |||
112 | pub fn new( | 110 | pub fn new( |
113 | target_scope: &'a SemanticsScope<'a, RootDatabase>, | 111 | target_scope: &'a SemanticsScope<'a, RootDatabase>, |
114 | source_scope: &'a SemanticsScope<'a, RootDatabase>, | 112 | source_scope: &'a SemanticsScope<'a, RootDatabase>, |
115 | db: &'a RootDatabase, | ||
116 | ) -> Self { | 113 | ) -> Self { |
117 | Self { target_scope, source_scope, db, previous: Box::new(NullTransformer) } | 114 | Self { target_scope, source_scope, previous: Box::new(NullTransformer) } |
118 | } | 115 | } |
119 | 116 | ||
120 | fn get_substitution_inner( | 117 | fn get_substitution_inner( |
@@ -132,7 +129,7 @@ impl<'a> QualifyPaths<'a> { | |||
132 | let resolution = self.source_scope.resolve_hir_path(&hir_path?)?; | 129 | let resolution = self.source_scope.resolve_hir_path(&hir_path?)?; |
133 | match resolution { | 130 | match resolution { |
134 | PathResolution::Def(def) => { | 131 | PathResolution::Def(def) => { |
135 | let found_path = from.find_use_path(self.db, def)?; | 132 | let found_path = from.find_use_path(self.source_scope.db, def)?; |
136 | let mut path = path_to_ast(found_path); | 133 | let mut path = path_to_ast(found_path); |
137 | 134 | ||
138 | let type_args = p | 135 | let type_args = p |
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 639180d37..e5920b6f6 100644 --- a/crates/ra_assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ra_assists/src/handlers/add_missing_impl_members.rs | |||
@@ -142,8 +142,8 @@ fn add_missing_impl_members_inner( | |||
142 | let n_existing_items = impl_item_list.impl_items().count(); | 142 | let n_existing_items = impl_item_list.impl_items().count(); |
143 | let source_scope = sema.scope_for_def(trait_); | 143 | let source_scope = sema.scope_for_def(trait_); |
144 | let target_scope = sema.scope(impl_item_list.syntax()); | 144 | let target_scope = sema.scope(impl_item_list.syntax()); |
145 | let ast_transform = QualifyPaths::new(&target_scope, &source_scope, sema.db) | 145 | let ast_transform = QualifyPaths::new(&target_scope, &source_scope) |
146 | .or(SubstituteTypeParams::for_trait_impl(&source_scope, sema.db, trait_, impl_node)); | 146 | .or(SubstituteTypeParams::for_trait_impl(&source_scope, trait_, impl_node)); |
147 | let items = missing_items | 147 | let items = missing_items |
148 | .into_iter() | 148 | .into_iter() |
149 | .map(|it| ast_transform::apply(&*ast_transform, it)) | 149 | .map(|it| ast_transform::apply(&*ast_transform, it)) |
diff --git a/crates/ra_assists/src/handlers/fill_match_arms.rs b/crates/ra_assists/src/handlers/fill_match_arms.rs index e5d8c639d..97cf90ae4 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::{db::HirDatabase, Adt, HasSource, Semantics}; | 5 | use hir::{Adt, HasSource, Semantics}; |
6 | use ra_syntax::ast::{self, edit::IndentLevel, make, AstNode, NameOwner}; | 6 | use ra_syntax::ast::{self, edit::IndentLevel, make, AstNode, NameOwner}; |
7 | 7 | ||
8 | use crate::{Assist, AssistCtx, AssistId}; | 8 | use crate::{Assist, AssistCtx, AssistId}; |
@@ -88,11 +88,7 @@ fn resolve_enum_def(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option< | |||
88 | }) | 88 | }) |
89 | } | 89 | } |
90 | 90 | ||
91 | fn build_pat( | 91 | fn build_pat(db: &RootDatabase, module: hir::Module, var: hir::EnumVariant) -> Option<ast::Pat> { |
92 | db: &impl HirDatabase, | ||
93 | module: hir::Module, | ||
94 | var: hir::EnumVariant, | ||
95 | ) -> Option<ast::Pat> { | ||
96 | let path = crate::ast_transform::path_to_ast(module.find_use_path(db, var.into())?); | 92 | let path = crate::ast_transform::path_to_ast(module.find_use_path(db, var.into())?); |
97 | 93 | ||
98 | // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though | 94 | // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though |
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index 50a15f978..62fadcddd 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs | |||
@@ -235,7 +235,7 @@ mod helpers { | |||
235 | (Some(assist), ExpectedResult::Target(target)) => { | 235 | (Some(assist), ExpectedResult::Target(target)) => { |
236 | let action = assist.0[0].action.clone().unwrap(); | 236 | let action = assist.0[0].action.clone().unwrap(); |
237 | let range = action.target.expect("expected target on action"); | 237 | let range = action.target.expect("expected target on action"); |
238 | assert_eq_text!(&before[range.start().to_usize()..range.end().to_usize()], target); | 238 | assert_eq_text!(&before[range], target); |
239 | } | 239 | } |
240 | (Some(_), ExpectedResult::NotApplicable) => panic!("assist should not be applicable!"), | 240 | (Some(_), ExpectedResult::NotApplicable) => panic!("assist should not be applicable!"), |
241 | (None, ExpectedResult::After(_)) | (None, ExpectedResult::Target(_)) => { | 241 | (None, ExpectedResult::After(_)) | (None, ExpectedResult::Target(_)) => { |
diff --git a/crates/ra_cargo_watch/src/conv.rs b/crates/ra_cargo_watch/src/conv.rs index 0246adfb5..c6f8ca329 100644 --- a/crates/ra_cargo_watch/src/conv.rs +++ b/crates/ra_cargo_watch/src/conv.rs | |||
@@ -8,6 +8,7 @@ use lsp_types::{ | |||
8 | Location, NumberOrString, Position, Range, TextEdit, Url, WorkspaceEdit, | 8 | Location, NumberOrString, Position, Range, TextEdit, Url, WorkspaceEdit, |
9 | }; | 9 | }; |
10 | use std::{ | 10 | use std::{ |
11 | collections::HashMap, | ||
11 | fmt::Write, | 12 | fmt::Write, |
12 | path::{Component, Path, PathBuf, Prefix}, | 13 | path::{Component, Path, PathBuf, Prefix}, |
13 | str::FromStr, | 14 | str::FromStr, |
@@ -126,44 +127,34 @@ fn map_rust_child_diagnostic( | |||
126 | rd: &RustDiagnostic, | 127 | rd: &RustDiagnostic, |
127 | workspace_root: &PathBuf, | 128 | workspace_root: &PathBuf, |
128 | ) -> MappedRustChildDiagnostic { | 129 | ) -> MappedRustChildDiagnostic { |
129 | let span: &DiagnosticSpan = match rd.spans.iter().find(|s| s.is_primary) { | 130 | let spans: Vec<&DiagnosticSpan> = rd.spans.iter().filter(|s| s.is_primary).collect(); |
130 | Some(span) => span, | 131 | if spans.is_empty() { |
131 | None => { | 132 | // `rustc` uses these spanless children as a way to print multi-line |
132 | // `rustc` uses these spanless children as a way to print multi-line | 133 | // messages |
133 | // messages | 134 | return MappedRustChildDiagnostic::MessageLine(rd.message.clone()); |
134 | return MappedRustChildDiagnostic::MessageLine(rd.message.clone()); | 135 | } |
136 | |||
137 | let mut edit_map: HashMap<Url, Vec<TextEdit>> = HashMap::new(); | ||
138 | for &span in &spans { | ||
139 | if let Some(suggested_replacement) = &span.suggested_replacement { | ||
140 | let location = map_span_to_location(span, workspace_root); | ||
141 | let edit = TextEdit::new(location.range, suggested_replacement.clone()); | ||
142 | edit_map.entry(location.uri).or_default().push(edit); | ||
135 | } | 143 | } |
136 | }; | 144 | } |
137 | |||
138 | // If we have a primary span use its location, otherwise use the parent | ||
139 | let location = map_span_to_location(&span, workspace_root); | ||
140 | |||
141 | if let Some(suggested_replacement) = &span.suggested_replacement { | ||
142 | // Include our replacement in the title unless it's empty | ||
143 | let title = if !suggested_replacement.is_empty() { | ||
144 | format!("{}: '{}'", rd.message, suggested_replacement) | ||
145 | } else { | ||
146 | rd.message.clone() | ||
147 | }; | ||
148 | |||
149 | let edit = { | ||
150 | let edits = vec![TextEdit::new(location.range, suggested_replacement.clone())]; | ||
151 | let mut edit_map = std::collections::HashMap::new(); | ||
152 | edit_map.insert(location.uri, edits); | ||
153 | WorkspaceEdit::new(edit_map) | ||
154 | }; | ||
155 | 145 | ||
146 | if !edit_map.is_empty() { | ||
156 | MappedRustChildDiagnostic::SuggestedFix(CodeAction { | 147 | MappedRustChildDiagnostic::SuggestedFix(CodeAction { |
157 | title, | 148 | title: rd.message.clone(), |
158 | kind: Some("quickfix".to_string()), | 149 | kind: Some("quickfix".to_string()), |
159 | diagnostics: None, | 150 | diagnostics: None, |
160 | edit: Some(edit), | 151 | edit: Some(WorkspaceEdit::new(edit_map)), |
161 | command: None, | 152 | command: None, |
162 | is_preferred: None, | 153 | is_preferred: None, |
163 | }) | 154 | }) |
164 | } else { | 155 | } else { |
165 | MappedRustChildDiagnostic::Related(DiagnosticRelatedInformation { | 156 | MappedRustChildDiagnostic::Related(DiagnosticRelatedInformation { |
166 | location, | 157 | location: map_span_to_location(spans[0], workspace_root), |
167 | message: rd.message.clone(), | 158 | message: rd.message.clone(), |
168 | }) | 159 | }) |
169 | } | 160 | } |
@@ -189,13 +180,13 @@ pub(crate) struct MappedRustDiagnostic { | |||
189 | pub(crate) fn map_rust_diagnostic_to_lsp( | 180 | pub(crate) fn map_rust_diagnostic_to_lsp( |
190 | rd: &RustDiagnostic, | 181 | rd: &RustDiagnostic, |
191 | workspace_root: &PathBuf, | 182 | workspace_root: &PathBuf, |
192 | ) -> Option<MappedRustDiagnostic> { | 183 | ) -> Vec<MappedRustDiagnostic> { |
193 | let primary_span = rd.spans.iter().find(|s| s.is_primary)?; | 184 | let primary_spans: Vec<&DiagnosticSpan> = rd.spans.iter().filter(|s| s.is_primary).collect(); |
194 | 185 | if primary_spans.is_empty() { | |
195 | let location = map_span_to_location(&primary_span, workspace_root); | 186 | return vec![]; |
187 | } | ||
196 | 188 | ||
197 | let severity = map_level_to_severity(rd.level); | 189 | let severity = map_level_to_severity(rd.level); |
198 | let mut primary_span_label = primary_span.label.as_ref(); | ||
199 | 190 | ||
200 | let mut source = String::from("rustc"); | 191 | let mut source = String::from("rustc"); |
201 | let mut code = rd.code.as_ref().map(|c| c.code.clone()); | 192 | let mut code = rd.code.as_ref().map(|c| c.code.clone()); |
@@ -208,19 +199,10 @@ pub(crate) fn map_rust_diagnostic_to_lsp( | |||
208 | } | 199 | } |
209 | } | 200 | } |
210 | 201 | ||
202 | let mut needs_primary_span_label = true; | ||
211 | let mut related_information = vec![]; | 203 | let mut related_information = vec![]; |
212 | let mut tags = vec![]; | 204 | let mut tags = vec![]; |
213 | 205 | ||
214 | // If error occurs from macro expansion, add related info pointing to | ||
215 | // where the error originated | ||
216 | if !is_from_macro(&primary_span.file_name) && primary_span.expansion.is_some() { | ||
217 | let def_loc = map_span_to_location_naive(&primary_span, workspace_root); | ||
218 | related_information.push(DiagnosticRelatedInformation { | ||
219 | location: def_loc, | ||
220 | message: "Error originated from macro here".to_string(), | ||
221 | }); | ||
222 | } | ||
223 | |||
224 | for secondary_span in rd.spans.iter().filter(|s| !s.is_primary) { | 206 | for secondary_span in rd.spans.iter().filter(|s| !s.is_primary) { |
225 | let related = map_secondary_span_to_related(secondary_span, workspace_root); | 207 | let related = map_secondary_span_to_related(secondary_span, workspace_root); |
226 | if let Some(related) = related { | 208 | if let Some(related) = related { |
@@ -240,15 +222,11 @@ pub(crate) fn map_rust_diagnostic_to_lsp( | |||
240 | 222 | ||
241 | // These secondary messages usually duplicate the content of the | 223 | // These secondary messages usually duplicate the content of the |
242 | // primary span label. | 224 | // primary span label. |
243 | primary_span_label = None; | 225 | needs_primary_span_label = false; |
244 | } | 226 | } |
245 | } | 227 | } |
246 | } | 228 | } |
247 | 229 | ||
248 | if let Some(primary_span_label) = primary_span_label { | ||
249 | write!(&mut message, "\n{}", primary_span_label).unwrap(); | ||
250 | } | ||
251 | |||
252 | if is_unused_or_unnecessary(rd) { | 230 | if is_unused_or_unnecessary(rd) { |
253 | tags.push(DiagnosticTag::Unnecessary); | 231 | tags.push(DiagnosticTag::Unnecessary); |
254 | } | 232 | } |
@@ -257,21 +235,45 @@ pub(crate) fn map_rust_diagnostic_to_lsp( | |||
257 | tags.push(DiagnosticTag::Deprecated); | 235 | tags.push(DiagnosticTag::Deprecated); |
258 | } | 236 | } |
259 | 237 | ||
260 | let diagnostic = Diagnostic { | 238 | primary_spans |
261 | range: location.range, | 239 | .iter() |
262 | severity, | 240 | .map(|primary_span| { |
263 | code: code.map(NumberOrString::String), | 241 | let location = map_span_to_location(&primary_span, workspace_root); |
264 | source: Some(source), | 242 | |
265 | message, | 243 | let mut message = message.clone(); |
266 | related_information: if !related_information.is_empty() { | 244 | if needs_primary_span_label { |
267 | Some(related_information) | 245 | if let Some(primary_span_label) = &primary_span.label { |
268 | } else { | 246 | write!(&mut message, "\n{}", primary_span_label).unwrap(); |
269 | None | 247 | } |
270 | }, | 248 | } |
271 | tags: if !tags.is_empty() { Some(tags) } else { None }, | 249 | |
272 | }; | 250 | // If error occurs from macro expansion, add related info pointing to |
273 | 251 | // where the error originated | |
274 | Some(MappedRustDiagnostic { location, diagnostic, fixes }) | 252 | if !is_from_macro(&primary_span.file_name) && primary_span.expansion.is_some() { |
253 | let def_loc = map_span_to_location_naive(&primary_span, workspace_root); | ||
254 | related_information.push(DiagnosticRelatedInformation { | ||
255 | location: def_loc, | ||
256 | message: "Error originated from macro here".to_string(), | ||
257 | }); | ||
258 | } | ||
259 | |||
260 | let diagnostic = Diagnostic { | ||
261 | range: location.range, | ||
262 | severity, | ||
263 | code: code.clone().map(NumberOrString::String), | ||
264 | source: Some(source.clone()), | ||
265 | message, | ||
266 | related_information: if !related_information.is_empty() { | ||
267 | Some(related_information.clone()) | ||
268 | } else { | ||
269 | None | ||
270 | }, | ||
271 | tags: if !tags.is_empty() { Some(tags.clone()) } else { None }, | ||
272 | }; | ||
273 | |||
274 | MappedRustDiagnostic { location, diagnostic, fixes: fixes.clone() } | ||
275 | }) | ||
276 | .collect() | ||
275 | } | 277 | } |
276 | 278 | ||
277 | /// Returns a `Url` object from a given path, will lowercase drive letters if present. | 279 | /// Returns a `Url` object from a given path, will lowercase drive letters if present. |
diff --git a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_clippy_pass_by_ref.snap b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_clippy_pass_by_ref.snap index 95ca163dc..9e8f4eff4 100644 --- a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_clippy_pass_by_ref.snap +++ b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_clippy_pass_by_ref.snap | |||
@@ -2,98 +2,100 @@ | |||
2 | source: crates/ra_cargo_watch/src/conv/test.rs | 2 | source: crates/ra_cargo_watch/src/conv/test.rs |
3 | expression: diag | 3 | expression: diag |
4 | --- | 4 | --- |
5 | MappedRustDiagnostic { | 5 | [ |
6 | location: Location { | 6 | MappedRustDiagnostic { |
7 | uri: "file:///test/compiler/mir/tagset.rs", | 7 | location: Location { |
8 | range: Range { | 8 | uri: "file:///test/compiler/mir/tagset.rs", |
9 | start: Position { | 9 | range: Range { |
10 | line: 41, | 10 | start: Position { |
11 | character: 23, | 11 | line: 41, |
12 | }, | 12 | character: 23, |
13 | end: Position { | 13 | }, |
14 | line: 41, | 14 | end: Position { |
15 | character: 28, | 15 | line: 41, |
16 | character: 28, | ||
17 | }, | ||
16 | }, | 18 | }, |
17 | }, | 19 | }, |
18 | }, | 20 | diagnostic: Diagnostic { |
19 | diagnostic: Diagnostic { | 21 | range: Range { |
20 | range: Range { | 22 | start: Position { |
21 | start: Position { | 23 | line: 41, |
22 | line: 41, | 24 | character: 23, |
23 | character: 23, | 25 | }, |
24 | }, | 26 | end: Position { |
25 | end: Position { | 27 | line: 41, |
26 | line: 41, | 28 | character: 28, |
27 | character: 28, | 29 | }, |
28 | }, | 30 | }, |
29 | }, | 31 | severity: Some( |
30 | severity: Some( | 32 | Warning, |
31 | Warning, | ||
32 | ), | ||
33 | code: Some( | ||
34 | String( | ||
35 | "trivially_copy_pass_by_ref", | ||
36 | ), | 33 | ), |
37 | ), | 34 | code: Some( |
38 | source: Some( | 35 | String( |
39 | "clippy", | 36 | "trivially_copy_pass_by_ref", |
40 | ), | 37 | ), |
41 | message: "this argument is passed by reference, but would be more efficient if passed by value\n#[warn(clippy::trivially_copy_pass_by_ref)] implied by #[warn(clippy::all)]\nfor further information visit https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref", | 38 | ), |
42 | related_information: Some( | 39 | source: Some( |
43 | [ | 40 | "clippy", |
44 | DiagnosticRelatedInformation { | 41 | ), |
45 | location: Location { | 42 | message: "this argument is passed by reference, but would be more efficient if passed by value\n#[warn(clippy::trivially_copy_pass_by_ref)] implied by #[warn(clippy::all)]\nfor further information visit https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref", |
46 | uri: "file:///test/compiler/lib.rs", | 43 | related_information: Some( |
47 | range: Range { | 44 | [ |
48 | start: Position { | 45 | DiagnosticRelatedInformation { |
49 | line: 0, | 46 | location: Location { |
50 | character: 8, | 47 | uri: "file:///test/compiler/lib.rs", |
51 | }, | 48 | range: Range { |
52 | end: Position { | 49 | start: Position { |
53 | line: 0, | 50 | line: 0, |
54 | character: 19, | 51 | character: 8, |
52 | }, | ||
53 | end: Position { | ||
54 | line: 0, | ||
55 | character: 19, | ||
56 | }, | ||
55 | }, | 57 | }, |
56 | }, | 58 | }, |
59 | message: "lint level defined here", | ||
57 | }, | 60 | }, |
58 | message: "lint level defined here", | 61 | ], |
59 | }, | ||
60 | ], | ||
61 | ), | ||
62 | tags: None, | ||
63 | }, | ||
64 | fixes: [ | ||
65 | CodeAction { | ||
66 | title: "consider passing by value instead: \'self\'", | ||
67 | kind: Some( | ||
68 | "quickfix", | ||
69 | ), | 62 | ), |
70 | diagnostics: None, | 63 | tags: None, |
71 | edit: Some( | 64 | }, |
72 | WorkspaceEdit { | 65 | fixes: [ |
73 | changes: Some( | 66 | CodeAction { |
74 | { | 67 | title: "consider passing by value instead", |
75 | "file:///test/compiler/mir/tagset.rs": [ | 68 | kind: Some( |
76 | TextEdit { | 69 | "quickfix", |
77 | range: Range { | 70 | ), |
78 | start: Position { | 71 | diagnostics: None, |
79 | line: 41, | 72 | edit: Some( |
80 | character: 23, | 73 | WorkspaceEdit { |
81 | }, | 74 | changes: Some( |
82 | end: Position { | 75 | { |
83 | line: 41, | 76 | "file:///test/compiler/mir/tagset.rs": [ |
84 | character: 28, | 77 | TextEdit { |
78 | range: Range { | ||
79 | start: Position { | ||
80 | line: 41, | ||
81 | character: 23, | ||
82 | }, | ||
83 | end: Position { | ||
84 | line: 41, | ||
85 | character: 28, | ||
86 | }, | ||
85 | }, | 87 | }, |
88 | new_text: "self", | ||
86 | }, | 89 | }, |
87 | new_text: "self", | 90 | ], |
88 | }, | 91 | }, |
89 | ], | 92 | ), |
90 | }, | 93 | document_changes: None, |
91 | ), | 94 | }, |
92 | document_changes: None, | 95 | ), |
93 | }, | 96 | command: None, |
94 | ), | 97 | is_preferred: None, |
95 | command: None, | 98 | }, |
96 | is_preferred: None, | 99 | ], |
97 | }, | 100 | }, |
98 | ], | 101 | ] |
99 | } | ||
diff --git a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_handles_macro_location.snap b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_handles_macro_location.snap index 12eb32df4..61ae0c9ae 100644 --- a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_handles_macro_location.snap +++ b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_handles_macro_location.snap | |||
@@ -2,45 +2,47 @@ | |||
2 | source: crates/ra_cargo_watch/src/conv/test.rs | 2 | source: crates/ra_cargo_watch/src/conv/test.rs |
3 | expression: diag | 3 | expression: diag |
4 | --- | 4 | --- |
5 | MappedRustDiagnostic { | 5 | [ |
6 | location: Location { | 6 | MappedRustDiagnostic { |
7 | uri: "file:///test/src/main.rs", | 7 | location: Location { |
8 | range: Range { | 8 | uri: "file:///test/src/main.rs", |
9 | start: Position { | 9 | range: Range { |
10 | line: 1, | 10 | start: Position { |
11 | character: 4, | 11 | line: 1, |
12 | }, | 12 | character: 4, |
13 | end: Position { | 13 | }, |
14 | line: 1, | 14 | end: Position { |
15 | character: 26, | 15 | line: 1, |
16 | character: 26, | ||
17 | }, | ||
16 | }, | 18 | }, |
17 | }, | 19 | }, |
18 | }, | 20 | diagnostic: Diagnostic { |
19 | diagnostic: Diagnostic { | 21 | range: Range { |
20 | range: Range { | 22 | start: Position { |
21 | start: Position { | 23 | line: 1, |
22 | line: 1, | 24 | character: 4, |
23 | character: 4, | 25 | }, |
26 | end: Position { | ||
27 | line: 1, | ||
28 | character: 26, | ||
29 | }, | ||
24 | }, | 30 | }, |
25 | end: Position { | 31 | severity: Some( |
26 | line: 1, | 32 | Error, |
27 | character: 26, | ||
28 | }, | ||
29 | }, | ||
30 | severity: Some( | ||
31 | Error, | ||
32 | ), | ||
33 | code: Some( | ||
34 | String( | ||
35 | "E0277", | ||
36 | ), | 33 | ), |
37 | ), | 34 | code: Some( |
38 | source: Some( | 35 | String( |
39 | "rustc", | 36 | "E0277", |
40 | ), | 37 | ), |
41 | message: "can\'t compare `{integer}` with `&str`\nthe trait `std::cmp::PartialEq<&str>` is not implemented for `{integer}`", | 38 | ), |
42 | related_information: None, | 39 | source: Some( |
43 | tags: None, | 40 | "rustc", |
41 | ), | ||
42 | message: "can\'t compare `{integer}` with `&str`\nthe trait `std::cmp::PartialEq<&str>` is not implemented for `{integer}`", | ||
43 | related_information: None, | ||
44 | tags: None, | ||
45 | }, | ||
46 | fixes: [], | ||
44 | }, | 47 | }, |
45 | fixes: [], | 48 | ] |
46 | } | ||
diff --git a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_macro_compiler_error.snap b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_macro_compiler_error.snap index 7b83a7cd0..641da1a58 100644 --- a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_macro_compiler_error.snap +++ b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_macro_compiler_error.snap | |||
@@ -2,60 +2,62 @@ | |||
2 | source: crates/ra_cargo_watch/src/conv/test.rs | 2 | source: crates/ra_cargo_watch/src/conv/test.rs |
3 | expression: diag | 3 | expression: diag |
4 | --- | 4 | --- |
5 | MappedRustDiagnostic { | 5 | [ |
6 | location: Location { | 6 | MappedRustDiagnostic { |
7 | uri: "file:///test/crates/ra_hir_def/src/data.rs", | 7 | location: Location { |
8 | range: Range { | 8 | uri: "file:///test/crates/ra_hir_def/src/data.rs", |
9 | start: Position { | 9 | range: Range { |
10 | line: 79, | 10 | start: Position { |
11 | character: 15, | 11 | line: 79, |
12 | }, | 12 | character: 15, |
13 | end: Position { | 13 | }, |
14 | line: 79, | 14 | end: Position { |
15 | character: 41, | 15 | line: 79, |
16 | character: 41, | ||
17 | }, | ||
16 | }, | 18 | }, |
17 | }, | 19 | }, |
18 | }, | 20 | diagnostic: Diagnostic { |
19 | diagnostic: Diagnostic { | 21 | range: Range { |
20 | range: Range { | 22 | start: Position { |
21 | start: Position { | 23 | line: 79, |
22 | line: 79, | 24 | character: 15, |
23 | character: 15, | 25 | }, |
24 | }, | 26 | end: Position { |
25 | end: Position { | 27 | line: 79, |
26 | line: 79, | 28 | character: 41, |
27 | character: 41, | 29 | }, |
28 | }, | 30 | }, |
29 | }, | 31 | severity: Some( |
30 | severity: Some( | 32 | Error, |
31 | Error, | 33 | ), |
32 | ), | 34 | code: None, |
33 | code: None, | 35 | source: Some( |
34 | source: Some( | 36 | "rustc", |
35 | "rustc", | 37 | ), |
36 | ), | 38 | message: "Please register your known path in the path module", |
37 | message: "Please register your known path in the path module", | 39 | related_information: Some( |
38 | related_information: Some( | 40 | [ |
39 | [ | 41 | DiagnosticRelatedInformation { |
40 | DiagnosticRelatedInformation { | 42 | location: Location { |
41 | location: Location { | 43 | uri: "file:///test/crates/ra_hir_def/src/path.rs", |
42 | uri: "file:///test/crates/ra_hir_def/src/path.rs", | 44 | range: Range { |
43 | range: Range { | 45 | start: Position { |
44 | start: Position { | 46 | line: 264, |
45 | line: 264, | 47 | character: 8, |
46 | character: 8, | 48 | }, |
47 | }, | 49 | end: Position { |
48 | end: Position { | 50 | line: 264, |
49 | line: 264, | 51 | character: 76, |
50 | character: 76, | 52 | }, |
51 | }, | 53 | }, |
52 | }, | 54 | }, |
55 | message: "Error originated from macro here", | ||
53 | }, | 56 | }, |
54 | message: "Error originated from macro here", | 57 | ], |
55 | }, | 58 | ), |
56 | ], | 59 | tags: None, |
57 | ), | 60 | }, |
58 | tags: None, | 61 | fixes: [], |
59 | }, | 62 | }, |
60 | fixes: [], | 63 | ] |
61 | } | ||
diff --git a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_multi_line_fix.snap b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_multi_line_fix.snap new file mode 100644 index 000000000..0557a2e79 --- /dev/null +++ b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_multi_line_fix.snap | |||
@@ -0,0 +1,114 @@ | |||
1 | --- | ||
2 | source: crates/ra_cargo_watch/src/conv/test.rs | ||
3 | expression: diag | ||
4 | --- | ||
5 | [ | ||
6 | MappedRustDiagnostic { | ||
7 | location: Location { | ||
8 | uri: "file:///test/src/main.rs", | ||
9 | range: Range { | ||
10 | start: Position { | ||
11 | line: 3, | ||
12 | character: 4, | ||
13 | }, | ||
14 | end: Position { | ||
15 | line: 3, | ||
16 | character: 5, | ||
17 | }, | ||
18 | }, | ||
19 | }, | ||
20 | diagnostic: Diagnostic { | ||
21 | range: Range { | ||
22 | start: Position { | ||
23 | line: 3, | ||
24 | character: 4, | ||
25 | }, | ||
26 | end: Position { | ||
27 | line: 3, | ||
28 | character: 5, | ||
29 | }, | ||
30 | }, | ||
31 | severity: Some( | ||
32 | Warning, | ||
33 | ), | ||
34 | code: Some( | ||
35 | String( | ||
36 | "let_and_return", | ||
37 | ), | ||
38 | ), | ||
39 | source: Some( | ||
40 | "clippy", | ||
41 | ), | ||
42 | message: "returning the result of a let binding from a block\n`#[warn(clippy::let_and_return)]` on by default\nfor further information visit https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return", | ||
43 | related_information: Some( | ||
44 | [ | ||
45 | DiagnosticRelatedInformation { | ||
46 | location: Location { | ||
47 | uri: "file:///test/src/main.rs", | ||
48 | range: Range { | ||
49 | start: Position { | ||
50 | line: 2, | ||
51 | character: 4, | ||
52 | }, | ||
53 | end: Position { | ||
54 | line: 2, | ||
55 | character: 30, | ||
56 | }, | ||
57 | }, | ||
58 | }, | ||
59 | message: "unnecessary let binding", | ||
60 | }, | ||
61 | ], | ||
62 | ), | ||
63 | tags: None, | ||
64 | }, | ||
65 | fixes: [ | ||
66 | CodeAction { | ||
67 | title: "return the expression directly", | ||
68 | kind: Some( | ||
69 | "quickfix", | ||
70 | ), | ||
71 | diagnostics: None, | ||
72 | edit: Some( | ||
73 | WorkspaceEdit { | ||
74 | changes: Some( | ||
75 | { | ||
76 | "file:///test/src/main.rs": [ | ||
77 | TextEdit { | ||
78 | range: Range { | ||
79 | start: Position { | ||
80 | line: 2, | ||
81 | character: 4, | ||
82 | }, | ||
83 | end: Position { | ||
84 | line: 2, | ||
85 | character: 30, | ||
86 | }, | ||
87 | }, | ||
88 | new_text: "", | ||
89 | }, | ||
90 | TextEdit { | ||
91 | range: Range { | ||
92 | start: Position { | ||
93 | line: 3, | ||
94 | character: 4, | ||
95 | }, | ||
96 | end: Position { | ||
97 | line: 3, | ||
98 | character: 5, | ||
99 | }, | ||
100 | }, | ||
101 | new_text: "(0..10).collect()", | ||
102 | }, | ||
103 | ], | ||
104 | }, | ||
105 | ), | ||
106 | document_changes: None, | ||
107 | }, | ||
108 | ), | ||
109 | command: None, | ||
110 | is_preferred: None, | ||
111 | }, | ||
112 | ], | ||
113 | }, | ||
114 | ] | ||
diff --git a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_incompatible_type_for_trait.snap b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_incompatible_type_for_trait.snap index 54679c5db..754bc33a4 100644 --- a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_incompatible_type_for_trait.snap +++ b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_incompatible_type_for_trait.snap | |||
@@ -2,45 +2,47 @@ | |||
2 | source: crates/ra_cargo_watch/src/conv/test.rs | 2 | source: crates/ra_cargo_watch/src/conv/test.rs |
3 | expression: diag | 3 | expression: diag |
4 | --- | 4 | --- |
5 | MappedRustDiagnostic { | 5 | [ |
6 | location: Location { | 6 | MappedRustDiagnostic { |
7 | uri: "file:///test/compiler/ty/list_iter.rs", | 7 | location: Location { |
8 | range: Range { | 8 | uri: "file:///test/compiler/ty/list_iter.rs", |
9 | start: Position { | 9 | range: Range { |
10 | line: 51, | 10 | start: Position { |
11 | character: 4, | 11 | line: 51, |
12 | }, | 12 | character: 4, |
13 | end: Position { | 13 | }, |
14 | line: 51, | 14 | end: Position { |
15 | character: 47, | 15 | line: 51, |
16 | character: 47, | ||
17 | }, | ||
16 | }, | 18 | }, |
17 | }, | 19 | }, |
18 | }, | 20 | diagnostic: Diagnostic { |
19 | diagnostic: Diagnostic { | 21 | range: Range { |
20 | range: Range { | 22 | start: Position { |
21 | start: Position { | 23 | line: 51, |
22 | line: 51, | 24 | character: 4, |
23 | character: 4, | 25 | }, |
26 | end: Position { | ||
27 | line: 51, | ||
28 | character: 47, | ||
29 | }, | ||
24 | }, | 30 | }, |
25 | end: Position { | 31 | severity: Some( |
26 | line: 51, | 32 | Error, |
27 | character: 47, | ||
28 | }, | ||
29 | }, | ||
30 | severity: Some( | ||
31 | Error, | ||
32 | ), | ||
33 | code: Some( | ||
34 | String( | ||
35 | "E0053", | ||
36 | ), | 33 | ), |
37 | ), | 34 | code: Some( |
38 | source: Some( | 35 | String( |
39 | "rustc", | 36 | "E0053", |
40 | ), | 37 | ), |
41 | message: "method `next` has an incompatible type for trait\nexpected type `fn(&mut ty::list_iter::ListIterator<\'list, M>) -> std::option::Option<&ty::Ref<M>>`\n found type `fn(&ty::list_iter::ListIterator<\'list, M>) -> std::option::Option<&\'list ty::Ref<M>>`", | 38 | ), |
42 | related_information: None, | 39 | source: Some( |
43 | tags: None, | 40 | "rustc", |
41 | ), | ||
42 | message: "method `next` has an incompatible type for trait\nexpected type `fn(&mut ty::list_iter::ListIterator<\'list, M>) -> std::option::Option<&ty::Ref<M>>`\n found type `fn(&ty::list_iter::ListIterator<\'list, M>) -> std::option::Option<&\'list ty::Ref<M>>`", | ||
43 | related_information: None, | ||
44 | tags: None, | ||
45 | }, | ||
46 | fixes: [], | ||
44 | }, | 47 | }, |
45 | fixes: [], | 48 | ] |
46 | } | ||
diff --git a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_mismatched_type.snap b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_mismatched_type.snap index 57df4ceaf..78b7f7cc8 100644 --- a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_mismatched_type.snap +++ b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_mismatched_type.snap | |||
@@ -2,45 +2,47 @@ | |||
2 | source: crates/ra_cargo_watch/src/conv/test.rs | 2 | source: crates/ra_cargo_watch/src/conv/test.rs |
3 | expression: diag | 3 | expression: diag |
4 | --- | 4 | --- |
5 | MappedRustDiagnostic { | 5 | [ |
6 | location: Location { | 6 | MappedRustDiagnostic { |
7 | uri: "file:///test/runtime/compiler_support.rs", | 7 | location: Location { |
8 | range: Range { | 8 | uri: "file:///test/runtime/compiler_support.rs", |
9 | start: Position { | 9 | range: Range { |
10 | line: 47, | 10 | start: Position { |
11 | character: 64, | 11 | line: 47, |
12 | }, | 12 | character: 64, |
13 | end: Position { | 13 | }, |
14 | line: 47, | 14 | end: Position { |
15 | character: 69, | 15 | line: 47, |
16 | character: 69, | ||
17 | }, | ||
16 | }, | 18 | }, |
17 | }, | 19 | }, |
18 | }, | 20 | diagnostic: Diagnostic { |
19 | diagnostic: Diagnostic { | 21 | range: Range { |
20 | range: Range { | 22 | start: Position { |
21 | start: Position { | 23 | line: 47, |
22 | line: 47, | 24 | character: 64, |
23 | character: 64, | 25 | }, |
26 | end: Position { | ||
27 | line: 47, | ||
28 | character: 69, | ||
29 | }, | ||
24 | }, | 30 | }, |
25 | end: Position { | 31 | severity: Some( |
26 | line: 47, | 32 | Error, |
27 | character: 69, | ||
28 | }, | ||
29 | }, | ||
30 | severity: Some( | ||
31 | Error, | ||
32 | ), | ||
33 | code: Some( | ||
34 | String( | ||
35 | "E0308", | ||
36 | ), | 33 | ), |
37 | ), | 34 | code: Some( |
38 | source: Some( | 35 | String( |
39 | "rustc", | 36 | "E0308", |
40 | ), | 37 | ), |
41 | message: "mismatched types\nexpected usize, found u32", | 38 | ), |
42 | related_information: None, | 39 | source: Some( |
43 | tags: None, | 40 | "rustc", |
41 | ), | ||
42 | message: "mismatched types\nexpected usize, found u32", | ||
43 | related_information: None, | ||
44 | tags: None, | ||
45 | }, | ||
46 | fixes: [], | ||
44 | }, | 47 | }, |
45 | fixes: [], | 48 | ] |
46 | } | ||
diff --git a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_unused_variable.snap b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_unused_variable.snap index 3e1fe736c..5989ed202 100644 --- a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_unused_variable.snap +++ b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_unused_variable.snap | |||
@@ -2,83 +2,85 @@ | |||
2 | source: crates/ra_cargo_watch/src/conv/test.rs | 2 | source: crates/ra_cargo_watch/src/conv/test.rs |
3 | expression: diag | 3 | expression: diag |
4 | --- | 4 | --- |
5 | MappedRustDiagnostic { | 5 | [ |
6 | location: Location { | 6 | MappedRustDiagnostic { |
7 | uri: "file:///test/driver/subcommand/repl.rs", | 7 | location: Location { |
8 | range: Range { | 8 | uri: "file:///test/driver/subcommand/repl.rs", |
9 | start: Position { | 9 | range: Range { |
10 | line: 290, | 10 | start: Position { |
11 | character: 8, | 11 | line: 290, |
12 | }, | 12 | character: 8, |
13 | end: Position { | 13 | }, |
14 | line: 290, | 14 | end: Position { |
15 | character: 11, | 15 | line: 290, |
16 | character: 11, | ||
17 | }, | ||
16 | }, | 18 | }, |
17 | }, | 19 | }, |
18 | }, | 20 | diagnostic: Diagnostic { |
19 | diagnostic: Diagnostic { | 21 | range: Range { |
20 | range: Range { | 22 | start: Position { |
21 | start: Position { | 23 | line: 290, |
22 | line: 290, | 24 | character: 8, |
23 | character: 8, | 25 | }, |
24 | }, | 26 | end: Position { |
25 | end: Position { | 27 | line: 290, |
26 | line: 290, | 28 | character: 11, |
27 | character: 11, | 29 | }, |
28 | }, | 30 | }, |
29 | }, | 31 | severity: Some( |
30 | severity: Some( | 32 | Warning, |
31 | Warning, | ||
32 | ), | ||
33 | code: Some( | ||
34 | String( | ||
35 | "unused_variables", | ||
36 | ), | 33 | ), |
37 | ), | 34 | code: Some( |
38 | source: Some( | 35 | String( |
39 | "rustc", | 36 | "unused_variables", |
40 | ), | 37 | ), |
41 | message: "unused variable: `foo`\n#[warn(unused_variables)] on by default", | ||
42 | related_information: None, | ||
43 | tags: Some( | ||
44 | [ | ||
45 | Unnecessary, | ||
46 | ], | ||
47 | ), | ||
48 | }, | ||
49 | fixes: [ | ||
50 | CodeAction { | ||
51 | title: "consider prefixing with an underscore: \'_foo\'", | ||
52 | kind: Some( | ||
53 | "quickfix", | ||
54 | ), | 38 | ), |
55 | diagnostics: None, | 39 | source: Some( |
56 | edit: Some( | 40 | "rustc", |
57 | WorkspaceEdit { | 41 | ), |
58 | changes: Some( | 42 | message: "unused variable: `foo`\n#[warn(unused_variables)] on by default", |
59 | { | 43 | related_information: None, |
60 | "file:///test/driver/subcommand/repl.rs": [ | 44 | tags: Some( |
61 | TextEdit { | 45 | [ |
62 | range: Range { | 46 | Unnecessary, |
63 | start: Position { | 47 | ], |
64 | line: 290, | ||
65 | character: 8, | ||
66 | }, | ||
67 | end: Position { | ||
68 | line: 290, | ||
69 | character: 11, | ||
70 | }, | ||
71 | }, | ||
72 | new_text: "_foo", | ||
73 | }, | ||
74 | ], | ||
75 | }, | ||
76 | ), | ||
77 | document_changes: None, | ||
78 | }, | ||
79 | ), | 48 | ), |
80 | command: None, | ||
81 | is_preferred: None, | ||
82 | }, | 49 | }, |
83 | ], | 50 | fixes: [ |
84 | } | 51 | CodeAction { |
52 | title: "consider prefixing with an underscore", | ||
53 | kind: Some( | ||
54 | "quickfix", | ||
55 | ), | ||
56 | diagnostics: None, | ||
57 | edit: Some( | ||
58 | WorkspaceEdit { | ||
59 | changes: Some( | ||
60 | { | ||
61 | "file:///test/driver/subcommand/repl.rs": [ | ||
62 | TextEdit { | ||
63 | range: Range { | ||
64 | start: Position { | ||
65 | line: 290, | ||
66 | character: 8, | ||
67 | }, | ||
68 | end: Position { | ||
69 | line: 290, | ||
70 | character: 11, | ||
71 | }, | ||
72 | }, | ||
73 | new_text: "_foo", | ||
74 | }, | ||
75 | ], | ||
76 | }, | ||
77 | ), | ||
78 | document_changes: None, | ||
79 | }, | ||
80 | ), | ||
81 | command: None, | ||
82 | is_preferred: None, | ||
83 | }, | ||
84 | ], | ||
85 | }, | ||
86 | ] | ||
diff --git a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_wrong_number_of_parameters.snap b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_wrong_number_of_parameters.snap index 69301078d..e34b546dc 100644 --- a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_wrong_number_of_parameters.snap +++ b/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_wrong_number_of_parameters.snap | |||
@@ -2,64 +2,66 @@ | |||
2 | source: crates/ra_cargo_watch/src/conv/test.rs | 2 | source: crates/ra_cargo_watch/src/conv/test.rs |
3 | expression: diag | 3 | expression: diag |
4 | --- | 4 | --- |
5 | MappedRustDiagnostic { | 5 | [ |
6 | location: Location { | 6 | MappedRustDiagnostic { |
7 | uri: "file:///test/compiler/ty/select.rs", | 7 | location: Location { |
8 | range: Range { | 8 | uri: "file:///test/compiler/ty/select.rs", |
9 | start: Position { | 9 | range: Range { |
10 | line: 103, | 10 | start: Position { |
11 | character: 17, | 11 | line: 103, |
12 | }, | 12 | character: 17, |
13 | end: Position { | 13 | }, |
14 | line: 103, | 14 | end: Position { |
15 | character: 29, | 15 | line: 103, |
16 | character: 29, | ||
17 | }, | ||
16 | }, | 18 | }, |
17 | }, | 19 | }, |
18 | }, | 20 | diagnostic: Diagnostic { |
19 | diagnostic: Diagnostic { | 21 | range: Range { |
20 | range: Range { | 22 | start: Position { |
21 | start: Position { | 23 | line: 103, |
22 | line: 103, | 24 | character: 17, |
23 | character: 17, | 25 | }, |
24 | }, | 26 | end: Position { |
25 | end: Position { | 27 | line: 103, |
26 | line: 103, | 28 | character: 29, |
27 | character: 29, | 29 | }, |
28 | }, | 30 | }, |
29 | }, | 31 | severity: Some( |
30 | severity: Some( | 32 | Error, |
31 | Error, | ||
32 | ), | ||
33 | code: Some( | ||
34 | String( | ||
35 | "E0061", | ||
36 | ), | 33 | ), |
37 | ), | 34 | code: Some( |
38 | source: Some( | 35 | String( |
39 | "rustc", | 36 | "E0061", |
40 | ), | 37 | ), |
41 | message: "this function takes 2 parameters but 3 parameters were supplied\nexpected 2 parameters", | 38 | ), |
42 | related_information: Some( | 39 | source: Some( |
43 | [ | 40 | "rustc", |
44 | DiagnosticRelatedInformation { | 41 | ), |
45 | location: Location { | 42 | message: "this function takes 2 parameters but 3 parameters were supplied\nexpected 2 parameters", |
46 | uri: "file:///test/compiler/ty/select.rs", | 43 | related_information: Some( |
47 | range: Range { | 44 | [ |
48 | start: Position { | 45 | DiagnosticRelatedInformation { |
49 | line: 218, | 46 | location: Location { |
50 | character: 4, | 47 | uri: "file:///test/compiler/ty/select.rs", |
51 | }, | 48 | range: Range { |
52 | end: Position { | 49 | start: Position { |
53 | line: 230, | 50 | line: 218, |
54 | character: 5, | 51 | character: 4, |
52 | }, | ||
53 | end: Position { | ||
54 | line: 230, | ||
55 | character: 5, | ||
56 | }, | ||
55 | }, | 57 | }, |
56 | }, | 58 | }, |
59 | message: "defined here", | ||
57 | }, | 60 | }, |
58 | message: "defined here", | 61 | ], |
59 | }, | 62 | ), |
60 | ], | 63 | tags: None, |
61 | ), | 64 | }, |
62 | tags: None, | 65 | fixes: [], |
63 | }, | 66 | }, |
64 | fixes: [], | 67 | ] |
65 | } | ||
diff --git a/crates/ra_cargo_watch/src/conv/test.rs b/crates/ra_cargo_watch/src/conv/test.rs index 6b86525b8..4e81455ca 100644 --- a/crates/ra_cargo_watch/src/conv/test.rs +++ b/crates/ra_cargo_watch/src/conv/test.rs | |||
@@ -58,7 +58,7 @@ fn snap_rustc_incompatible_type_for_trait() { | |||
58 | ); | 58 | ); |
59 | 59 | ||
60 | let workspace_root = PathBuf::from("/test/"); | 60 | let workspace_root = PathBuf::from("/test/"); |
61 | let diag = map_rust_diagnostic_to_lsp(&diag, &workspace_root).expect("couldn't map diagnostic"); | 61 | let diag = map_rust_diagnostic_to_lsp(&diag, &workspace_root); |
62 | insta::assert_debug_snapshot!(diag); | 62 | insta::assert_debug_snapshot!(diag); |
63 | } | 63 | } |
64 | 64 | ||
@@ -141,7 +141,7 @@ fn snap_rustc_unused_variable() { | |||
141 | ); | 141 | ); |
142 | 142 | ||
143 | let workspace_root = PathBuf::from("/test/"); | 143 | let workspace_root = PathBuf::from("/test/"); |
144 | let diag = map_rust_diagnostic_to_lsp(&diag, &workspace_root).expect("couldn't map diagnostic"); | 144 | let diag = map_rust_diagnostic_to_lsp(&diag, &workspace_root); |
145 | insta::assert_debug_snapshot!(diag); | 145 | insta::assert_debug_snapshot!(diag); |
146 | } | 146 | } |
147 | 147 | ||
@@ -266,7 +266,7 @@ fn snap_rustc_wrong_number_of_parameters() { | |||
266 | ); | 266 | ); |
267 | 267 | ||
268 | let workspace_root = PathBuf::from("/test/"); | 268 | let workspace_root = PathBuf::from("/test/"); |
269 | let diag = map_rust_diagnostic_to_lsp(&diag, &workspace_root).expect("couldn't map diagnostic"); | 269 | let diag = map_rust_diagnostic_to_lsp(&diag, &workspace_root); |
270 | insta::assert_debug_snapshot!(diag); | 270 | insta::assert_debug_snapshot!(diag); |
271 | } | 271 | } |
272 | 272 | ||
@@ -387,7 +387,7 @@ fn snap_clippy_pass_by_ref() { | |||
387 | ); | 387 | ); |
388 | 388 | ||
389 | let workspace_root = PathBuf::from("/test/"); | 389 | let workspace_root = PathBuf::from("/test/"); |
390 | let diag = map_rust_diagnostic_to_lsp(&diag, &workspace_root).expect("couldn't map diagnostic"); | 390 | let diag = map_rust_diagnostic_to_lsp(&diag, &workspace_root); |
391 | insta::assert_debug_snapshot!(diag); | 391 | insta::assert_debug_snapshot!(diag); |
392 | } | 392 | } |
393 | 393 | ||
@@ -431,7 +431,7 @@ fn snap_rustc_mismatched_type() { | |||
431 | ); | 431 | ); |
432 | 432 | ||
433 | let workspace_root = PathBuf::from("/test/"); | 433 | let workspace_root = PathBuf::from("/test/"); |
434 | let diag = map_rust_diagnostic_to_lsp(&diag, &workspace_root).expect("couldn't map diagnostic"); | 434 | let diag = map_rust_diagnostic_to_lsp(&diag, &workspace_root); |
435 | insta::assert_debug_snapshot!(diag); | 435 | insta::assert_debug_snapshot!(diag); |
436 | } | 436 | } |
437 | 437 | ||
@@ -703,7 +703,7 @@ fn snap_handles_macro_location() { | |||
703 | ); | 703 | ); |
704 | 704 | ||
705 | let workspace_root = PathBuf::from("/test/"); | 705 | let workspace_root = PathBuf::from("/test/"); |
706 | let diag = map_rust_diagnostic_to_lsp(&diag, &workspace_root).expect("couldn't map diagnostic"); | 706 | let diag = map_rust_diagnostic_to_lsp(&diag, &workspace_root); |
707 | insta::assert_debug_snapshot!(diag); | 707 | insta::assert_debug_snapshot!(diag); |
708 | } | 708 | } |
709 | 709 | ||
@@ -933,6 +933,140 @@ fn snap_macro_compiler_error() { | |||
933 | ); | 933 | ); |
934 | 934 | ||
935 | let workspace_root = PathBuf::from("/test/"); | 935 | let workspace_root = PathBuf::from("/test/"); |
936 | let diag = map_rust_diagnostic_to_lsp(&diag, &workspace_root).expect("couldn't map diagnostic"); | 936 | let diag = map_rust_diagnostic_to_lsp(&diag, &workspace_root); |
937 | insta::assert_debug_snapshot!(diag); | ||
938 | } | ||
939 | |||
940 | #[test] | ||
941 | #[cfg(not(windows))] | ||
942 | fn snap_multi_line_fix() { | ||
943 | let diag = parse_diagnostic( | ||
944 | r##"{ | ||
945 | "rendered": "warning: returning the result of a let binding from a block\n --> src/main.rs:4:5\n |\n3 | let a = (0..10).collect();\n | -------------------------- unnecessary let binding\n4 | a\n | ^\n |\n = note: `#[warn(clippy::let_and_return)]` on by default\n = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return\nhelp: return the expression directly\n |\n3 | \n4 | (0..10).collect()\n |\n\n", | ||
946 | "children": [ | ||
947 | { | ||
948 | "children": [], | ||
949 | "code": null, | ||
950 | "level": "note", | ||
951 | "message": "`#[warn(clippy::let_and_return)]` on by default", | ||
952 | "rendered": null, | ||
953 | "spans": [] | ||
954 | }, | ||
955 | { | ||
956 | "children": [], | ||
957 | "code": null, | ||
958 | "level": "help", | ||
959 | "message": "for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return", | ||
960 | "rendered": null, | ||
961 | "spans": [] | ||
962 | }, | ||
963 | { | ||
964 | "children": [], | ||
965 | "code": null, | ||
966 | "level": "help", | ||
967 | "message": "return the expression directly", | ||
968 | "rendered": null, | ||
969 | "spans": [ | ||
970 | { | ||
971 | "byte_end": 55, | ||
972 | "byte_start": 29, | ||
973 | "column_end": 31, | ||
974 | "column_start": 5, | ||
975 | "expansion": null, | ||
976 | "file_name": "src/main.rs", | ||
977 | "is_primary": true, | ||
978 | "label": null, | ||
979 | "line_end": 3, | ||
980 | "line_start": 3, | ||
981 | "suggested_replacement": "", | ||
982 | "suggestion_applicability": "MachineApplicable", | ||
983 | "text": [ | ||
984 | { | ||
985 | "highlight_end": 31, | ||
986 | "highlight_start": 5, | ||
987 | "text": " let a = (0..10).collect();" | ||
988 | } | ||
989 | ] | ||
990 | }, | ||
991 | { | ||
992 | "byte_end": 61, | ||
993 | "byte_start": 60, | ||
994 | "column_end": 6, | ||
995 | "column_start": 5, | ||
996 | "expansion": null, | ||
997 | "file_name": "src/main.rs", | ||
998 | "is_primary": true, | ||
999 | "label": null, | ||
1000 | "line_end": 4, | ||
1001 | "line_start": 4, | ||
1002 | "suggested_replacement": "(0..10).collect()", | ||
1003 | "suggestion_applicability": "MachineApplicable", | ||
1004 | "text": [ | ||
1005 | { | ||
1006 | "highlight_end": 6, | ||
1007 | "highlight_start": 5, | ||
1008 | "text": " a" | ||
1009 | } | ||
1010 | ] | ||
1011 | } | ||
1012 | ] | ||
1013 | } | ||
1014 | ], | ||
1015 | "code": { | ||
1016 | "code": "clippy::let_and_return", | ||
1017 | "explanation": null | ||
1018 | }, | ||
1019 | "level": "warning", | ||
1020 | "message": "returning the result of a let binding from a block", | ||
1021 | "spans": [ | ||
1022 | { | ||
1023 | "byte_end": 55, | ||
1024 | "byte_start": 29, | ||
1025 | "column_end": 31, | ||
1026 | "column_start": 5, | ||
1027 | "expansion": null, | ||
1028 | "file_name": "src/main.rs", | ||
1029 | "is_primary": false, | ||
1030 | "label": "unnecessary let binding", | ||
1031 | "line_end": 3, | ||
1032 | "line_start": 3, | ||
1033 | "suggested_replacement": null, | ||
1034 | "suggestion_applicability": null, | ||
1035 | "text": [ | ||
1036 | { | ||
1037 | "highlight_end": 31, | ||
1038 | "highlight_start": 5, | ||
1039 | "text": " let a = (0..10).collect();" | ||
1040 | } | ||
1041 | ] | ||
1042 | }, | ||
1043 | { | ||
1044 | "byte_end": 61, | ||
1045 | "byte_start": 60, | ||
1046 | "column_end": 6, | ||
1047 | "column_start": 5, | ||
1048 | "expansion": null, | ||
1049 | "file_name": "src/main.rs", | ||
1050 | "is_primary": true, | ||
1051 | "label": null, | ||
1052 | "line_end": 4, | ||
1053 | "line_start": 4, | ||
1054 | "suggested_replacement": null, | ||
1055 | "suggestion_applicability": null, | ||
1056 | "text": [ | ||
1057 | { | ||
1058 | "highlight_end": 6, | ||
1059 | "highlight_start": 5, | ||
1060 | "text": " a" | ||
1061 | } | ||
1062 | ] | ||
1063 | } | ||
1064 | ] | ||
1065 | } | ||
1066 | "##, | ||
1067 | ); | ||
1068 | |||
1069 | let workspace_root = PathBuf::from("/test/"); | ||
1070 | let diag = map_rust_diagnostic_to_lsp(&diag, &workspace_root); | ||
937 | insta::assert_debug_snapshot!(diag); | 1071 | insta::assert_debug_snapshot!(diag); |
938 | } | 1072 | } |
diff --git a/crates/ra_cargo_watch/src/lib.rs b/crates/ra_cargo_watch/src/lib.rs index f07c34549..94b9c03d0 100644 --- a/crates/ra_cargo_watch/src/lib.rs +++ b/crates/ra_cargo_watch/src/lib.rs | |||
@@ -197,23 +197,23 @@ impl CheckWatcherThread { | |||
197 | } | 197 | } |
198 | 198 | ||
199 | CheckEvent::Msg(Message::CompilerMessage(msg)) => { | 199 | CheckEvent::Msg(Message::CompilerMessage(msg)) => { |
200 | let map_result = | 200 | let map_result = map_rust_diagnostic_to_lsp(&msg.message, &self.workspace_root); |
201 | match map_rust_diagnostic_to_lsp(&msg.message, &self.workspace_root) { | 201 | if map_result.is_empty() { |
202 | Some(map_result) => map_result, | 202 | return; |
203 | None => return, | 203 | } |
204 | }; | ||
205 | |||
206 | let MappedRustDiagnostic { location, diagnostic, fixes } = map_result; | ||
207 | let fixes = fixes | ||
208 | .into_iter() | ||
209 | .map(|fix| { | ||
210 | CodeAction { diagnostics: Some(vec![diagnostic.clone()]), ..fix }.into() | ||
211 | }) | ||
212 | .collect(); | ||
213 | 204 | ||
214 | task_send | 205 | for MappedRustDiagnostic { location, diagnostic, fixes } in map_result { |
215 | .send(CheckTask::AddDiagnostic { url: location.uri, diagnostic, fixes }) | 206 | let fixes = fixes |
216 | .unwrap(); | 207 | .into_iter() |
208 | .map(|fix| { | ||
209 | CodeAction { diagnostics: Some(vec![diagnostic.clone()]), ..fix }.into() | ||
210 | }) | ||
211 | .collect(); | ||
212 | |||
213 | task_send | ||
214 | .send(CheckTask::AddDiagnostic { url: location.uri, diagnostic, fixes }) | ||
215 | .unwrap(); | ||
216 | } | ||
217 | } | 217 | } |
218 | 218 | ||
219 | CheckEvent::Msg(Message::BuildScriptExecuted(_msg)) => {} | 219 | CheckEvent::Msg(Message::BuildScriptExecuted(_msg)) => {} |
diff --git a/crates/ra_db/src/fixture.rs b/crates/ra_db/src/fixture.rs index 947d6ad56..3dc86ca2d 100644 --- a/crates/ra_db/src/fixture.rs +++ b/crates/ra_db/src/fixture.rs | |||
@@ -5,7 +5,7 @@ use std::sync::Arc; | |||
5 | 5 | ||
6 | use ra_cfg::CfgOptions; | 6 | use ra_cfg::CfgOptions; |
7 | use rustc_hash::FxHashMap; | 7 | use rustc_hash::FxHashMap; |
8 | use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER}; | 8 | use test_utils::{extract_offset, parse_fixture, parse_single_fixture, CURSOR_MARKER}; |
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | input::CrateName, CrateGraph, CrateId, Edition, Env, FileId, FilePosition, RelativePathBuf, | 11 | input::CrateName, CrateGraph, CrateId, Edition, Env, FileId, FilePosition, RelativePathBuf, |
@@ -45,23 +45,45 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static { | |||
45 | 45 | ||
46 | impl<DB: SourceDatabaseExt + Default + 'static> WithFixture for DB {} | 46 | impl<DB: SourceDatabaseExt + Default + 'static> WithFixture for DB {} |
47 | 47 | ||
48 | fn with_single_file(db: &mut dyn SourceDatabaseExt, text: &str) -> FileId { | 48 | fn with_single_file(db: &mut dyn SourceDatabaseExt, ra_fixture: &str) -> FileId { |
49 | let file_id = FileId(0); | 49 | let file_id = FileId(0); |
50 | let rel_path: RelativePathBuf = "/main.rs".into(); | 50 | let rel_path: RelativePathBuf = "/main.rs".into(); |
51 | 51 | ||
52 | let mut source_root = SourceRoot::new_local(); | 52 | let mut source_root = SourceRoot::new_local(); |
53 | source_root.insert_file(rel_path.clone(), file_id); | 53 | source_root.insert_file(rel_path.clone(), file_id); |
54 | 54 | ||
55 | let mut crate_graph = CrateGraph::default(); | 55 | let fixture = parse_single_fixture(ra_fixture); |
56 | crate_graph.add_crate_root( | 56 | |
57 | file_id, | 57 | let crate_graph = if let Some(entry) = fixture { |
58 | Edition::Edition2018, | 58 | let meta = match parse_meta(&entry.meta) { |
59 | None, | 59 | ParsedMeta::File(it) => it, |
60 | CfgOptions::default(), | 60 | _ => panic!("with_single_file only support file meta"), |
61 | Env::default(), | 61 | }; |
62 | ); | 62 | |
63 | 63 | let mut crate_graph = CrateGraph::default(); | |
64 | db.set_file_text(file_id, Arc::new(text.to_string())); | 64 | crate_graph.add_crate_root( |
65 | file_id, | ||
66 | meta.edition, | ||
67 | meta.krate, | ||
68 | meta.cfg, | ||
69 | meta.env, | ||
70 | Default::default(), | ||
71 | ); | ||
72 | crate_graph | ||
73 | } else { | ||
74 | let mut crate_graph = CrateGraph::default(); | ||
75 | crate_graph.add_crate_root( | ||
76 | file_id, | ||
77 | Edition::Edition2018, | ||
78 | None, | ||
79 | CfgOptions::default(), | ||
80 | Env::default(), | ||
81 | Default::default(), | ||
82 | ); | ||
83 | crate_graph | ||
84 | }; | ||
85 | |||
86 | db.set_file_text(file_id, Arc::new(ra_fixture.to_string())); | ||
65 | db.set_file_relative_path(file_id, rel_path); | 87 | db.set_file_relative_path(file_id, rel_path); |
66 | db.set_file_source_root(file_id, WORKSPACE); | 88 | db.set_file_source_root(file_id, WORKSPACE); |
67 | db.set_source_root(WORKSPACE, Arc::new(source_root)); | 89 | db.set_source_root(WORKSPACE, Arc::new(source_root)); |
@@ -104,7 +126,8 @@ fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosit | |||
104 | meta.edition, | 126 | meta.edition, |
105 | Some(krate.clone()), | 127 | Some(krate.clone()), |
106 | meta.cfg, | 128 | meta.cfg, |
107 | Env::default(), | 129 | meta.env, |
130 | Default::default(), | ||
108 | ); | 131 | ); |
109 | let prev = crates.insert(krate.clone(), crate_id); | 132 | let prev = crates.insert(krate.clone(), crate_id); |
110 | assert!(prev.is_none()); | 133 | assert!(prev.is_none()); |
@@ -141,6 +164,7 @@ fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosit | |||
141 | None, | 164 | None, |
142 | CfgOptions::default(), | 165 | CfgOptions::default(), |
143 | Env::default(), | 166 | Env::default(), |
167 | Default::default(), | ||
144 | ); | 168 | ); |
145 | } else { | 169 | } else { |
146 | for (from, to) in crate_deps { | 170 | for (from, to) in crate_deps { |
@@ -167,9 +191,10 @@ struct FileMeta { | |||
167 | deps: Vec<String>, | 191 | deps: Vec<String>, |
168 | cfg: CfgOptions, | 192 | cfg: CfgOptions, |
169 | edition: Edition, | 193 | edition: Edition, |
194 | env: Env, | ||
170 | } | 195 | } |
171 | 196 | ||
172 | //- /lib.rs crate:foo deps:bar,baz | 197 | //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b env:OUTDIR=path/to,OTHER=foo) |
173 | fn parse_meta(meta: &str) -> ParsedMeta { | 198 | fn parse_meta(meta: &str) -> ParsedMeta { |
174 | let components = meta.split_ascii_whitespace().collect::<Vec<_>>(); | 199 | let components = meta.split_ascii_whitespace().collect::<Vec<_>>(); |
175 | 200 | ||
@@ -186,6 +211,7 @@ fn parse_meta(meta: &str) -> ParsedMeta { | |||
186 | let mut deps = Vec::new(); | 211 | let mut deps = Vec::new(); |
187 | let mut edition = Edition::Edition2018; | 212 | let mut edition = Edition::Edition2018; |
188 | let mut cfg = CfgOptions::default(); | 213 | let mut cfg = CfgOptions::default(); |
214 | let mut env = Env::default(); | ||
189 | for component in components[1..].iter() { | 215 | for component in components[1..].iter() { |
190 | let (key, value) = split1(component, ':').unwrap(); | 216 | let (key, value) = split1(component, ':').unwrap(); |
191 | match key { | 217 | match key { |
@@ -200,11 +226,18 @@ fn parse_meta(meta: &str) -> ParsedMeta { | |||
200 | } | 226 | } |
201 | } | 227 | } |
202 | } | 228 | } |
229 | "env" => { | ||
230 | for key in value.split(',') { | ||
231 | if let Some((k, v)) = split1(key, '=') { | ||
232 | env.set(k.into(), v.into()); | ||
233 | } | ||
234 | } | ||
235 | } | ||
203 | _ => panic!("bad component: {:?}", component), | 236 | _ => panic!("bad component: {:?}", component), |
204 | } | 237 | } |
205 | } | 238 | } |
206 | 239 | ||
207 | ParsedMeta::File(FileMeta { path, krate, deps, edition, cfg }) | 240 | ParsedMeta::File(FileMeta { path, krate, deps, edition, cfg, env }) |
208 | } | 241 | } |
209 | 242 | ||
210 | fn split1(haystack: &str, delim: char) -> Option<(&str, &str)> { | 243 | fn split1(haystack: &str, delim: char) -> Option<(&str, &str)> { |
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs index b77640b2b..06d40db96 100644 --- a/crates/ra_db/src/input.rs +++ b/crates/ra_db/src/input.rs | |||
@@ -113,6 +113,7 @@ pub struct CrateData { | |||
113 | pub display_name: Option<String>, | 113 | pub display_name: Option<String>, |
114 | pub cfg_options: CfgOptions, | 114 | pub cfg_options: CfgOptions, |
115 | pub env: Env, | 115 | pub env: Env, |
116 | pub extern_source: ExternSource, | ||
116 | pub dependencies: Vec<Dependency>, | 117 | pub dependencies: Vec<Dependency>, |
117 | } | 118 | } |
118 | 119 | ||
@@ -122,11 +123,22 @@ pub enum Edition { | |||
122 | Edition2015, | 123 | Edition2015, |
123 | } | 124 | } |
124 | 125 | ||
126 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
127 | pub struct ExternSourceId(pub u32); | ||
128 | |||
125 | #[derive(Default, Debug, Clone, PartialEq, Eq)] | 129 | #[derive(Default, Debug, Clone, PartialEq, Eq)] |
126 | pub struct Env { | 130 | pub struct Env { |
127 | entries: FxHashMap<String, String>, | 131 | entries: FxHashMap<String, String>, |
128 | } | 132 | } |
129 | 133 | ||
134 | // FIXME: Redesign vfs for solve the following limitation ? | ||
135 | // Note: Some env variables (e.g. OUT_DIR) are located outside of the | ||
136 | // crate. We store a map to allow remap it to ExternSourceId | ||
137 | #[derive(Default, Debug, Clone, PartialEq, Eq)] | ||
138 | pub struct ExternSource { | ||
139 | extern_paths: FxHashMap<String, ExternSourceId>, | ||
140 | } | ||
141 | |||
130 | #[derive(Debug, Clone, PartialEq, Eq)] | 142 | #[derive(Debug, Clone, PartialEq, Eq)] |
131 | pub struct Dependency { | 143 | pub struct Dependency { |
132 | pub crate_id: CrateId, | 144 | pub crate_id: CrateId, |
@@ -141,6 +153,7 @@ impl CrateGraph { | |||
141 | display_name: Option<String>, | 153 | display_name: Option<String>, |
142 | cfg_options: CfgOptions, | 154 | cfg_options: CfgOptions, |
143 | env: Env, | 155 | env: Env, |
156 | extern_source: ExternSource, | ||
144 | ) -> CrateId { | 157 | ) -> CrateId { |
145 | let data = CrateData { | 158 | let data = CrateData { |
146 | root_file_id: file_id, | 159 | root_file_id: file_id, |
@@ -148,6 +161,7 @@ impl CrateGraph { | |||
148 | display_name, | 161 | display_name, |
149 | cfg_options, | 162 | cfg_options, |
150 | env, | 163 | env, |
164 | extern_source, | ||
151 | dependencies: Vec::new(), | 165 | dependencies: Vec::new(), |
152 | }; | 166 | }; |
153 | let crate_id = CrateId(self.arena.len() as u32); | 167 | let crate_id = CrateId(self.arena.len() as u32); |
@@ -261,6 +275,37 @@ impl fmt::Display for Edition { | |||
261 | } | 275 | } |
262 | } | 276 | } |
263 | 277 | ||
278 | impl Env { | ||
279 | pub fn set(&mut self, env: &str, value: String) { | ||
280 | self.entries.insert(env.to_owned(), value); | ||
281 | } | ||
282 | |||
283 | pub fn get(&self, env: &str) -> Option<String> { | ||
284 | self.entries.get(env).cloned() | ||
285 | } | ||
286 | } | ||
287 | |||
288 | impl ExternSource { | ||
289 | pub fn extern_path(&self, path: &str) -> Option<(ExternSourceId, RelativePathBuf)> { | ||
290 | self.extern_paths.iter().find_map(|(root_path, id)| { | ||
291 | if path.starts_with(root_path) { | ||
292 | let mut rel_path = &path[root_path.len()..]; | ||
293 | if rel_path.starts_with("/") { | ||
294 | rel_path = &rel_path[1..]; | ||
295 | } | ||
296 | let rel_path = RelativePathBuf::from_path(rel_path).ok()?; | ||
297 | Some((id.clone(), rel_path)) | ||
298 | } else { | ||
299 | None | ||
300 | } | ||
301 | }) | ||
302 | } | ||
303 | |||
304 | pub fn set_extern_path(&mut self, root_path: &str, root: ExternSourceId) { | ||
305 | self.extern_paths.insert(root_path.to_owned(), root); | ||
306 | } | ||
307 | } | ||
308 | |||
264 | #[derive(Debug)] | 309 | #[derive(Debug)] |
265 | pub struct ParseEditionError { | 310 | pub struct ParseEditionError { |
266 | invalid_input: String, | 311 | invalid_input: String, |
@@ -290,6 +335,7 @@ mod tests { | |||
290 | None, | 335 | None, |
291 | CfgOptions::default(), | 336 | CfgOptions::default(), |
292 | Env::default(), | 337 | Env::default(), |
338 | Default::default(), | ||
293 | ); | 339 | ); |
294 | let crate2 = graph.add_crate_root( | 340 | let crate2 = graph.add_crate_root( |
295 | FileId(2u32), | 341 | FileId(2u32), |
@@ -297,6 +343,7 @@ mod tests { | |||
297 | None, | 343 | None, |
298 | CfgOptions::default(), | 344 | CfgOptions::default(), |
299 | Env::default(), | 345 | Env::default(), |
346 | Default::default(), | ||
300 | ); | 347 | ); |
301 | let crate3 = graph.add_crate_root( | 348 | let crate3 = graph.add_crate_root( |
302 | FileId(3u32), | 349 | FileId(3u32), |
@@ -304,6 +351,7 @@ mod tests { | |||
304 | None, | 351 | None, |
305 | CfgOptions::default(), | 352 | CfgOptions::default(), |
306 | Env::default(), | 353 | Env::default(), |
354 | Default::default(), | ||
307 | ); | 355 | ); |
308 | assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok()); | 356 | assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok()); |
309 | assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok()); | 357 | assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok()); |
@@ -319,6 +367,7 @@ mod tests { | |||
319 | None, | 367 | None, |
320 | CfgOptions::default(), | 368 | CfgOptions::default(), |
321 | Env::default(), | 369 | Env::default(), |
370 | Default::default(), | ||
322 | ); | 371 | ); |
323 | let crate2 = graph.add_crate_root( | 372 | let crate2 = graph.add_crate_root( |
324 | FileId(2u32), | 373 | FileId(2u32), |
@@ -326,6 +375,7 @@ mod tests { | |||
326 | None, | 375 | None, |
327 | CfgOptions::default(), | 376 | CfgOptions::default(), |
328 | Env::default(), | 377 | Env::default(), |
378 | Default::default(), | ||
329 | ); | 379 | ); |
330 | let crate3 = graph.add_crate_root( | 380 | let crate3 = graph.add_crate_root( |
331 | FileId(3u32), | 381 | FileId(3u32), |
@@ -333,6 +383,7 @@ mod tests { | |||
333 | None, | 383 | None, |
334 | CfgOptions::default(), | 384 | CfgOptions::default(), |
335 | Env::default(), | 385 | Env::default(), |
386 | Default::default(), | ||
336 | ); | 387 | ); |
337 | assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok()); | 388 | assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok()); |
338 | assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok()); | 389 | assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok()); |
@@ -347,6 +398,7 @@ mod tests { | |||
347 | None, | 398 | None, |
348 | CfgOptions::default(), | 399 | CfgOptions::default(), |
349 | Env::default(), | 400 | Env::default(), |
401 | Default::default(), | ||
350 | ); | 402 | ); |
351 | let crate2 = graph.add_crate_root( | 403 | let crate2 = graph.add_crate_root( |
352 | FileId(2u32), | 404 | FileId(2u32), |
@@ -354,6 +406,7 @@ mod tests { | |||
354 | None, | 406 | None, |
355 | CfgOptions::default(), | 407 | CfgOptions::default(), |
356 | Env::default(), | 408 | Env::default(), |
409 | Default::default(), | ||
357 | ); | 410 | ); |
358 | assert!(graph | 411 | assert!(graph |
359 | .add_dep(crate1, CrateName::normalize_dashes("crate-name-with-dashes"), crate2) | 412 | .add_dep(crate1, CrateName::normalize_dashes("crate-name-with-dashes"), crate2) |
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs index fb002d717..d500d5e85 100644 --- a/crates/ra_db/src/lib.rs +++ b/crates/ra_db/src/lib.rs | |||
@@ -11,7 +11,8 @@ use ra_syntax::{ast, Parse, SourceFile, TextRange, TextUnit}; | |||
11 | pub use crate::{ | 11 | pub use crate::{ |
12 | cancellation::Canceled, | 12 | cancellation::Canceled, |
13 | input::{ | 13 | input::{ |
14 | CrateGraph, CrateId, CrateName, Dependency, Edition, Env, FileId, SourceRoot, SourceRootId, | 14 | CrateGraph, CrateId, CrateName, Dependency, Edition, Env, ExternSource, ExternSourceId, |
15 | FileId, SourceRoot, SourceRootId, | ||
15 | }, | 16 | }, |
16 | }; | 17 | }; |
17 | pub use relative_path::{RelativePath, RelativePathBuf}; | 18 | pub use relative_path::{RelativePath, RelativePathBuf}; |
@@ -87,6 +88,12 @@ pub trait FileLoader { | |||
87 | fn resolve_relative_path(&self, anchor: FileId, relative_path: &RelativePath) | 88 | fn resolve_relative_path(&self, anchor: FileId, relative_path: &RelativePath) |
88 | -> Option<FileId>; | 89 | -> Option<FileId>; |
89 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>>; | 90 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>>; |
91 | |||
92 | fn resolve_extern_path( | ||
93 | &self, | ||
94 | extern_id: ExternSourceId, | ||
95 | relative_path: &RelativePath, | ||
96 | ) -> Option<FileId>; | ||
90 | } | 97 | } |
91 | 98 | ||
92 | /// Database which stores all significant input facts: source code and project | 99 | /// Database which stores all significant input facts: source code and project |
@@ -164,4 +171,13 @@ impl<T: SourceDatabaseExt> FileLoader for FileLoaderDelegate<&'_ T> { | |||
164 | let source_root = self.0.file_source_root(file_id); | 171 | let source_root = self.0.file_source_root(file_id); |
165 | self.0.source_root_crates(source_root) | 172 | self.0.source_root_crates(source_root) |
166 | } | 173 | } |
174 | |||
175 | fn resolve_extern_path( | ||
176 | &self, | ||
177 | extern_id: ExternSourceId, | ||
178 | relative_path: &RelativePath, | ||
179 | ) -> Option<FileId> { | ||
180 | let source_root = self.0.source_root(SourceRootId(extern_id.0)); | ||
181 | source_root.file_by_relative_path(&relative_path) | ||
182 | } | ||
167 | } | 183 | } |
diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml index 266c4cff3..42193b492 100644 --- a/crates/ra_hir/Cargo.toml +++ b/crates/ra_hir/Cargo.toml | |||
@@ -11,6 +11,7 @@ doctest = false | |||
11 | log = "0.4.8" | 11 | log = "0.4.8" |
12 | rustc-hash = "1.1.0" | 12 | rustc-hash = "1.1.0" |
13 | either = "1.5.3" | 13 | either = "1.5.3" |
14 | arrayvec = "0.5.1" | ||
14 | 15 | ||
15 | itertools = "0.8.2" | 16 | itertools = "0.8.2" |
16 | 17 | ||
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 41d4e2ed3..ff041150b 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -1,6 +1,7 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | use std::sync::Arc; | 2 | use std::sync::Arc; |
3 | 3 | ||
4 | use arrayvec::ArrayVec; | ||
4 | use either::Either; | 5 | use either::Either; |
5 | use hir_def::{ | 6 | use hir_def::{ |
6 | adt::StructKind, | 7 | adt::StructKind, |
@@ -226,7 +227,9 @@ impl Module { | |||
226 | Some((name, def)) | 227 | Some((name, def)) |
227 | } | 228 | } |
228 | }) | 229 | }) |
229 | .map(|(name, def)| (name.clone(), def.into())) | 230 | .flat_map(|(name, def)| { |
231 | ScopeDef::all_items(def).into_iter().map(move |item| (name.clone(), item)) | ||
232 | }) | ||
230 | .collect() | 233 | .collect() |
231 | } | 234 | } |
232 | 235 | ||
@@ -308,7 +311,11 @@ impl StructField { | |||
308 | self.parent.variant_data(db).fields()[self.id].name.clone() | 311 | self.parent.variant_data(db).fields()[self.id].name.clone() |
309 | } | 312 | } |
310 | 313 | ||
311 | pub fn ty(&self, db: &impl HirDatabase) -> Type { | 314 | /// Returns the type as in the signature of the struct (i.e., with |
315 | /// placeholder types for type parameters). This is good for showing | ||
316 | /// signature help, but not so good to actually get the type of the field | ||
317 | /// when you actually have a variable of the struct. | ||
318 | pub fn signature_ty(&self, db: &impl HirDatabase) -> Type { | ||
312 | let var_id = self.parent.into(); | 319 | let var_id = self.parent.into(); |
313 | let generic_def_id: GenericDefId = match self.parent { | 320 | let generic_def_id: GenericDefId = match self.parent { |
314 | VariantDef::Struct(it) => it.id.into(), | 321 | VariantDef::Struct(it) => it.id.into(), |
@@ -482,6 +489,10 @@ impl Adt { | |||
482 | let subst = db.generic_defaults(self.into()); | 489 | let subst = db.generic_defaults(self.into()); |
483 | subst.iter().any(|ty| ty == &Ty::Unknown) | 490 | subst.iter().any(|ty| ty == &Ty::Unknown) |
484 | } | 491 | } |
492 | |||
493 | /// Turns this ADT into a type. Any type parameters of the ADT will be | ||
494 | /// turned into unknown types, which is good for e.g. finding the most | ||
495 | /// general set of completions, but will not look very nice when printed. | ||
485 | pub fn ty(self, db: &impl HirDatabase) -> Type { | 496 | pub fn ty(self, db: &impl HirDatabase) -> Type { |
486 | let id = AdtId::from(self); | 497 | let id = AdtId::from(self); |
487 | Type::from_def(db, id.module(db).krate, id) | 498 | Type::from_def(db, id.module(db).krate, id) |
@@ -1028,7 +1039,7 @@ impl Type { | |||
1028 | krate: CrateId, | 1039 | krate: CrateId, |
1029 | def: impl HasResolver + Into<TyDefId> + Into<GenericDefId>, | 1040 | def: impl HasResolver + Into<TyDefId> + Into<GenericDefId>, |
1030 | ) -> Type { | 1041 | ) -> Type { |
1031 | let substs = Substs::type_params(db, def); | 1042 | let substs = Substs::build_for_def(db, def).fill_with_unknown().build(); |
1032 | let ty = db.ty(def.into()).subst(&substs); | 1043 | let ty = db.ty(def.into()).subst(&substs); |
1033 | Type::new(db, krate, def, ty) | 1044 | Type::new(db, krate, def, ty) |
1034 | } | 1045 | } |
@@ -1288,15 +1299,36 @@ pub enum ScopeDef { | |||
1288 | Unknown, | 1299 | Unknown, |
1289 | } | 1300 | } |
1290 | 1301 | ||
1291 | impl From<PerNs> for ScopeDef { | 1302 | impl ScopeDef { |
1292 | fn from(def: PerNs) -> Self { | 1303 | pub fn all_items(def: PerNs) -> ArrayVec<[Self; 3]> { |
1293 | def.take_types() | 1304 | let mut items = ArrayVec::new(); |
1294 | .or_else(|| def.take_values()) | 1305 | |
1295 | .map(|module_def_id| ScopeDef::ModuleDef(module_def_id.into())) | 1306 | match (def.take_types(), def.take_values()) { |
1296 | .or_else(|| { | 1307 | (Some(m1), None) => items.push(ScopeDef::ModuleDef(m1.into())), |
1297 | def.take_macros().map(|macro_def_id| ScopeDef::MacroDef(macro_def_id.into())) | 1308 | (None, Some(m2)) => items.push(ScopeDef::ModuleDef(m2.into())), |
1298 | }) | 1309 | (Some(m1), Some(m2)) => { |
1299 | .unwrap_or(ScopeDef::Unknown) | 1310 | // Some items, like unit structs and enum variants, are |
1311 | // returned as both a type and a value. Here we want | ||
1312 | // to de-duplicate them. | ||
1313 | if m1 != m2 { | ||
1314 | items.push(ScopeDef::ModuleDef(m1.into())); | ||
1315 | items.push(ScopeDef::ModuleDef(m2.into())); | ||
1316 | } else { | ||
1317 | items.push(ScopeDef::ModuleDef(m1.into())); | ||
1318 | } | ||
1319 | } | ||
1320 | (None, None) => {} | ||
1321 | }; | ||
1322 | |||
1323 | if let Some(macro_def_id) = def.take_macros() { | ||
1324 | items.push(ScopeDef::MacroDef(macro_def_id.into())); | ||
1325 | } | ||
1326 | |||
1327 | if items.is_empty() { | ||
1328 | items.push(ScopeDef::Unknown); | ||
1329 | } | ||
1330 | |||
1331 | items | ||
1300 | } | 1332 | } |
1301 | } | 1333 | } |
1302 | 1334 | ||
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index 3782a9984..788bb3eb7 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs | |||
@@ -344,7 +344,13 @@ impl<'a, DB: HirDatabase> SemanticsScope<'a, DB> { | |||
344 | 344 | ||
345 | resolver.process_all_names(self.db, &mut |name, def| { | 345 | resolver.process_all_names(self.db, &mut |name, def| { |
346 | let def = match def { | 346 | let def = match def { |
347 | resolver::ScopeDef::PerNs(it) => it.into(), | 347 | resolver::ScopeDef::PerNs(it) => { |
348 | let items = ScopeDef::all_items(it); | ||
349 | for item in items { | ||
350 | f(name.clone(), item); | ||
351 | } | ||
352 | return; | ||
353 | } | ||
348 | resolver::ScopeDef::ImplSelfType(it) => ScopeDef::ImplSelfType(it.into()), | 354 | resolver::ScopeDef::ImplSelfType(it) => ScopeDef::ImplSelfType(it.into()), |
349 | resolver::ScopeDef::AdtSelfType(it) => ScopeDef::AdtSelfType(it.into()), | 355 | resolver::ScopeDef::AdtSelfType(it) => ScopeDef::AdtSelfType(it.into()), |
350 | resolver::ScopeDef::GenericParam(id) => ScopeDef::GenericParam(TypeParam { id }), | 356 | resolver::ScopeDef::GenericParam(id) => ScopeDef::GenericParam(TypeParam { id }), |
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index 57ba45b45..2bc405a59 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs | |||
@@ -47,13 +47,19 @@ impl Expander { | |||
47 | pub(crate) fn enter_expand<T: ast::AstNode, DB: DefDatabase>( | 47 | pub(crate) fn enter_expand<T: ast::AstNode, DB: DefDatabase>( |
48 | &mut self, | 48 | &mut self, |
49 | db: &DB, | 49 | db: &DB, |
50 | local_scope: Option<&ItemScope>, | ||
50 | macro_call: ast::MacroCall, | 51 | macro_call: ast::MacroCall, |
51 | ) -> Option<(Mark, T)> { | 52 | ) -> Option<(Mark, T)> { |
52 | let macro_call = InFile::new(self.current_file_id, ¯o_call); | 53 | let macro_call = InFile::new(self.current_file_id, ¯o_call); |
53 | 54 | ||
54 | if let Some(call_id) = | 55 | if let Some(call_id) = macro_call.as_call_id(db, |path| { |
55 | macro_call.as_call_id(db, |path| self.resolve_path_as_macro(db, &path)) | 56 | if let Some(local_scope) = local_scope { |
56 | { | 57 | if let Some(def) = path.as_ident().and_then(|n| local_scope.get_legacy_macro(n)) { |
58 | return Some(def); | ||
59 | } | ||
60 | } | ||
61 | self.resolve_path_as_macro(db, &path) | ||
62 | }) { | ||
57 | let file_id = call_id.as_file(); | 63 | let file_id = call_id.as_file(); |
58 | if let Some(node) = db.parse_or_expand(file_id) { | 64 | if let Some(node) = db.parse_or_expand(file_id) { |
59 | if let Some(expr) = T::cast(node) { | 65 | if let Some(expr) = T::cast(node) { |
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index ec1b0c2e7..54b5591d3 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs | |||
@@ -3,7 +3,10 @@ | |||
3 | 3 | ||
4 | use either::Either; | 4 | use either::Either; |
5 | 5 | ||
6 | use hir_expand::name::{name, AsName, Name}; | 6 | use hir_expand::{ |
7 | name::{name, AsName, Name}, | ||
8 | MacroDefId, MacroDefKind, | ||
9 | }; | ||
7 | use ra_arena::Arena; | 10 | use ra_arena::Arena; |
8 | use ra_syntax::{ | 11 | use ra_syntax::{ |
9 | ast::{ | 12 | ast::{ |
@@ -452,19 +455,30 @@ where | |||
452 | None => self.alloc_expr(Expr::Missing, syntax_ptr), | 455 | None => self.alloc_expr(Expr::Missing, syntax_ptr), |
453 | } | 456 | } |
454 | } | 457 | } |
455 | // FIXME expand to statements in statement position | ||
456 | ast::Expr::MacroCall(e) => { | 458 | ast::Expr::MacroCall(e) => { |
457 | let macro_call = self.expander.to_source(AstPtr::new(&e)); | 459 | if let Some(name) = is_macro_rules(&e) { |
458 | match self.expander.enter_expand(self.db, e) { | 460 | let mac = MacroDefId { |
459 | Some((mark, expansion)) => { | 461 | krate: Some(self.expander.module.krate), |
460 | self.source_map | 462 | ast_id: Some(self.expander.ast_id(&e)), |
461 | .expansions | 463 | kind: MacroDefKind::Declarative, |
462 | .insert(macro_call, self.expander.current_file_id); | 464 | }; |
463 | let id = self.collect_expr(expansion); | 465 | self.body.item_scope.define_legacy_macro(name, mac); |
464 | self.expander.exit(self.db, mark); | 466 | |
465 | id | 467 | // FIXME: do we still need to allocate this as missing ? |
468 | self.alloc_expr(Expr::Missing, syntax_ptr) | ||
469 | } else { | ||
470 | let macro_call = self.expander.to_source(AstPtr::new(&e)); | ||
471 | match self.expander.enter_expand(self.db, Some(&self.body.item_scope), e) { | ||
472 | Some((mark, expansion)) => { | ||
473 | self.source_map | ||
474 | .expansions | ||
475 | .insert(macro_call, self.expander.current_file_id); | ||
476 | let id = self.collect_expr(expansion); | ||
477 | self.expander.exit(self.db, mark); | ||
478 | id | ||
479 | } | ||
480 | None => self.alloc_expr(Expr::Missing, syntax_ptr), | ||
466 | } | 481 | } |
467 | None => self.alloc_expr(Expr::Missing, syntax_ptr), | ||
468 | } | 482 | } |
469 | } | 483 | } |
470 | 484 | ||
@@ -686,6 +700,16 @@ where | |||
686 | } | 700 | } |
687 | } | 701 | } |
688 | 702 | ||
703 | fn is_macro_rules(m: &ast::MacroCall) -> Option<Name> { | ||
704 | let name = m.path()?.segment()?.name_ref()?.as_name(); | ||
705 | |||
706 | if name == name![macro_rules] { | ||
707 | Some(m.name()?.as_name()) | ||
708 | } else { | ||
709 | None | ||
710 | } | ||
711 | } | ||
712 | |||
689 | impl From<ast::BinOp> for BinaryOp { | 713 | impl From<ast::BinOp> for BinaryOp { |
690 | fn from(ast_op: ast::BinOp) -> Self { | 714 | fn from(ast_op: ast::BinOp) -> Self { |
691 | match ast_op { | 715 | match ast_op { |
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs index a72eb5369..c0b16b7fa 100644 --- a/crates/ra_hir_def/src/data.rs +++ b/crates/ra_hir_def/src/data.rs | |||
@@ -34,7 +34,8 @@ pub struct FunctionData { | |||
34 | 34 | ||
35 | impl FunctionData { | 35 | impl FunctionData { |
36 | pub(crate) fn fn_data_query(db: &impl DefDatabase, func: FunctionId) -> Arc<FunctionData> { | 36 | pub(crate) fn fn_data_query(db: &impl DefDatabase, func: FunctionId) -> Arc<FunctionData> { |
37 | let src = func.lookup(db).source(db); | 37 | let loc = func.lookup(db); |
38 | let src = loc.source(db); | ||
38 | let name = src.value.name().map(|n| n.as_name()).unwrap_or_else(Name::missing); | 39 | let name = src.value.name().map(|n| n.as_name()).unwrap_or_else(Name::missing); |
39 | let mut params = Vec::new(); | 40 | let mut params = Vec::new(); |
40 | let mut has_self_param = false; | 41 | let mut has_self_param = false; |
@@ -76,7 +77,9 @@ impl FunctionData { | |||
76 | ret_type | 77 | ret_type |
77 | }; | 78 | }; |
78 | 79 | ||
79 | let visibility = RawVisibility::from_ast(db, src.map(|s| s.visibility())); | 80 | let vis_default = RawVisibility::default_for_container(loc.container); |
81 | let visibility = | ||
82 | RawVisibility::from_ast_with_default(db, vis_default, src.map(|s| s.visibility())); | ||
80 | 83 | ||
81 | let sig = FunctionData { name, params, ret_type, has_self_param, visibility }; | 84 | let sig = FunctionData { name, params, ret_type, has_self_param, visibility }; |
82 | Arc::new(sig) | 85 | Arc::new(sig) |
@@ -105,10 +108,13 @@ impl TypeAliasData { | |||
105 | db: &impl DefDatabase, | 108 | db: &impl DefDatabase, |
106 | typ: TypeAliasId, | 109 | typ: TypeAliasId, |
107 | ) -> Arc<TypeAliasData> { | 110 | ) -> Arc<TypeAliasData> { |
108 | let node = typ.lookup(db).source(db); | 111 | let loc = typ.lookup(db); |
112 | let node = loc.source(db); | ||
109 | let name = node.value.name().map_or_else(Name::missing, |n| n.as_name()); | 113 | let name = node.value.name().map_or_else(Name::missing, |n| n.as_name()); |
110 | let type_ref = node.value.type_ref().map(TypeRef::from_ast); | 114 | let type_ref = node.value.type_ref().map(TypeRef::from_ast); |
111 | let visibility = RawVisibility::from_ast(db, node.map(|n| n.visibility())); | 115 | let vis_default = RawVisibility::default_for_container(loc.container); |
116 | let visibility = | ||
117 | RawVisibility::from_ast_with_default(db, vis_default, node.map(|n| n.visibility())); | ||
112 | Arc::new(TypeAliasData { name, type_ref, visibility }) | 118 | Arc::new(TypeAliasData { name, type_ref, visibility }) |
113 | } | 119 | } |
114 | } | 120 | } |
@@ -230,22 +236,26 @@ pub struct ConstData { | |||
230 | 236 | ||
231 | impl ConstData { | 237 | impl ConstData { |
232 | pub(crate) fn const_data_query(db: &impl DefDatabase, konst: ConstId) -> Arc<ConstData> { | 238 | pub(crate) fn const_data_query(db: &impl DefDatabase, konst: ConstId) -> Arc<ConstData> { |
233 | let node = konst.lookup(db).source(db); | 239 | let loc = konst.lookup(db); |
234 | Arc::new(ConstData::new(db, node)) | 240 | let node = loc.source(db); |
241 | let vis_default = RawVisibility::default_for_container(loc.container); | ||
242 | Arc::new(ConstData::new(db, vis_default, node)) | ||
235 | } | 243 | } |
236 | 244 | ||
237 | pub(crate) fn static_data_query(db: &impl DefDatabase, konst: StaticId) -> Arc<ConstData> { | 245 | pub(crate) fn static_data_query(db: &impl DefDatabase, konst: StaticId) -> Arc<ConstData> { |
238 | let node = konst.lookup(db).source(db); | 246 | let node = konst.lookup(db).source(db); |
239 | Arc::new(ConstData::new(db, node)) | 247 | Arc::new(ConstData::new(db, RawVisibility::private(), node)) |
240 | } | 248 | } |
241 | 249 | ||
242 | fn new<N: NameOwner + TypeAscriptionOwner + VisibilityOwner>( | 250 | fn new<N: NameOwner + TypeAscriptionOwner + VisibilityOwner>( |
243 | db: &impl DefDatabase, | 251 | db: &impl DefDatabase, |
252 | vis_default: RawVisibility, | ||
244 | node: InFile<N>, | 253 | node: InFile<N>, |
245 | ) -> ConstData { | 254 | ) -> ConstData { |
246 | let name = node.value.name().map(|n| n.as_name()); | 255 | let name = node.value.name().map(|n| n.as_name()); |
247 | let type_ref = TypeRef::from_ast_opt(node.value.ascribed_type()); | 256 | let type_ref = TypeRef::from_ast_opt(node.value.ascribed_type()); |
248 | let visibility = RawVisibility::from_ast(db, node.map(|n| n.visibility())); | 257 | let visibility = |
258 | RawVisibility::from_ast_with_default(db, vis_default, node.map(|n| n.visibility())); | ||
249 | ConstData { name, type_ref, visibility } | 259 | ConstData { name, type_ref, visibility } |
250 | } | 260 | } |
251 | } | 261 | } |
@@ -280,7 +290,7 @@ fn collect_impl_items_in_macro( | |||
280 | return Vec::new(); | 290 | return Vec::new(); |
281 | } | 291 | } |
282 | 292 | ||
283 | if let Some((mark, items)) = expander.enter_expand(db, m) { | 293 | if let Some((mark, items)) = expander.enter_expand(db, None, m) { |
284 | let items: InFile<ast::MacroItems> = expander.to_source(items); | 294 | let items: InFile<ast::MacroItems> = expander.to_source(items); |
285 | let mut res = collect_impl_items( | 295 | let mut res = collect_impl_items( |
286 | db, | 296 | db, |
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index d0459d9b0..db9838cb5 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs | |||
@@ -102,6 +102,7 @@ struct MacroDirective { | |||
102 | module_id: LocalModuleId, | 102 | module_id: LocalModuleId, |
103 | ast_id: AstIdWithPath<ast::MacroCall>, | 103 | ast_id: AstIdWithPath<ast::MacroCall>, |
104 | legacy: Option<MacroCallId>, | 104 | legacy: Option<MacroCallId>, |
105 | depth: usize, | ||
105 | } | 106 | } |
106 | 107 | ||
107 | #[derive(Clone, Debug, Eq, PartialEq)] | 108 | #[derive(Clone, Debug, Eq, PartialEq)] |
@@ -134,6 +135,7 @@ where | |||
134 | self.def_map.modules[module_id].origin = ModuleOrigin::CrateRoot { definition: file_id }; | 135 | self.def_map.modules[module_id].origin = ModuleOrigin::CrateRoot { definition: file_id }; |
135 | ModCollector { | 136 | ModCollector { |
136 | def_collector: &mut *self, | 137 | def_collector: &mut *self, |
138 | macro_depth: 0, | ||
137 | module_id, | 139 | module_id, |
138 | file_id: file_id.into(), | 140 | file_id: file_id.into(), |
139 | raw_items: &raw_items, | 141 | raw_items: &raw_items, |
@@ -516,7 +518,7 @@ where | |||
516 | macros.retain(|directive| { | 518 | macros.retain(|directive| { |
517 | if let Some(call_id) = directive.legacy { | 519 | if let Some(call_id) = directive.legacy { |
518 | res = ReachedFixedPoint::No; | 520 | res = ReachedFixedPoint::No; |
519 | resolved.push((directive.module_id, call_id)); | 521 | resolved.push((directive.module_id, call_id, directive.depth)); |
520 | return false; | 522 | return false; |
521 | } | 523 | } |
522 | 524 | ||
@@ -530,7 +532,7 @@ where | |||
530 | ); | 532 | ); |
531 | resolved_res.resolved_def.take_macros() | 533 | resolved_res.resolved_def.take_macros() |
532 | }) { | 534 | }) { |
533 | resolved.push((directive.module_id, call_id)); | 535 | resolved.push((directive.module_id, call_id, directive.depth)); |
534 | res = ReachedFixedPoint::No; | 536 | res = ReachedFixedPoint::No; |
535 | return false; | 537 | return false; |
536 | } | 538 | } |
@@ -541,7 +543,7 @@ where | |||
541 | if let Some(call_id) = | 543 | if let Some(call_id) = |
542 | directive.ast_id.as_call_id(self.db, |path| self.resolve_attribute_macro(&path)) | 544 | directive.ast_id.as_call_id(self.db, |path| self.resolve_attribute_macro(&path)) |
543 | { | 545 | { |
544 | resolved.push((directive.module_id, call_id)); | 546 | resolved.push((directive.module_id, call_id, 0)); |
545 | res = ReachedFixedPoint::No; | 547 | res = ReachedFixedPoint::No; |
546 | return false; | 548 | return false; |
547 | } | 549 | } |
@@ -552,8 +554,12 @@ where | |||
552 | self.unexpanded_macros = macros; | 554 | self.unexpanded_macros = macros; |
553 | self.unexpanded_attribute_macros = attribute_macros; | 555 | self.unexpanded_attribute_macros = attribute_macros; |
554 | 556 | ||
555 | for (module_id, macro_call_id) in resolved { | 557 | for (module_id, macro_call_id, depth) in resolved { |
556 | self.collect_macro_expansion(module_id, macro_call_id); | 558 | if depth > 1024 { |
559 | log::debug!("Max macro expansion depth reached"); | ||
560 | continue; | ||
561 | } | ||
562 | self.collect_macro_expansion(module_id, macro_call_id, depth); | ||
557 | } | 563 | } |
558 | 564 | ||
559 | res | 565 | res |
@@ -573,12 +579,18 @@ where | |||
573 | None | 579 | None |
574 | } | 580 | } |
575 | 581 | ||
576 | fn collect_macro_expansion(&mut self, module_id: LocalModuleId, macro_call_id: MacroCallId) { | 582 | fn collect_macro_expansion( |
583 | &mut self, | ||
584 | module_id: LocalModuleId, | ||
585 | macro_call_id: MacroCallId, | ||
586 | depth: usize, | ||
587 | ) { | ||
577 | let file_id: HirFileId = macro_call_id.as_file(); | 588 | let file_id: HirFileId = macro_call_id.as_file(); |
578 | let raw_items = self.db.raw_items(file_id); | 589 | let raw_items = self.db.raw_items(file_id); |
579 | let mod_dir = self.mod_dirs[&module_id].clone(); | 590 | let mod_dir = self.mod_dirs[&module_id].clone(); |
580 | ModCollector { | 591 | ModCollector { |
581 | def_collector: &mut *self, | 592 | def_collector: &mut *self, |
593 | macro_depth: depth, | ||
582 | file_id, | 594 | file_id, |
583 | module_id, | 595 | module_id, |
584 | raw_items: &raw_items, | 596 | raw_items: &raw_items, |
@@ -595,6 +607,7 @@ where | |||
595 | /// Walks a single module, populating defs, imports and macros | 607 | /// Walks a single module, populating defs, imports and macros |
596 | struct ModCollector<'a, D> { | 608 | struct ModCollector<'a, D> { |
597 | def_collector: D, | 609 | def_collector: D, |
610 | macro_depth: usize, | ||
598 | module_id: LocalModuleId, | 611 | module_id: LocalModuleId, |
599 | file_id: HirFileId, | 612 | file_id: HirFileId, |
600 | raw_items: &'a raw::RawItems, | 613 | raw_items: &'a raw::RawItems, |
@@ -684,6 +697,7 @@ where | |||
684 | 697 | ||
685 | ModCollector { | 698 | ModCollector { |
686 | def_collector: &mut *self.def_collector, | 699 | def_collector: &mut *self.def_collector, |
700 | macro_depth: self.macro_depth, | ||
687 | module_id, | 701 | module_id, |
688 | file_id: self.file_id, | 702 | file_id: self.file_id, |
689 | raw_items: self.raw_items, | 703 | raw_items: self.raw_items, |
@@ -713,6 +727,7 @@ where | |||
713 | let raw_items = self.def_collector.db.raw_items(file_id.into()); | 727 | let raw_items = self.def_collector.db.raw_items(file_id.into()); |
714 | ModCollector { | 728 | ModCollector { |
715 | def_collector: &mut *self.def_collector, | 729 | def_collector: &mut *self.def_collector, |
730 | macro_depth: self.macro_depth, | ||
716 | module_id, | 731 | module_id, |
717 | file_id: file_id.into(), | 732 | file_id: file_id.into(), |
718 | raw_items: &raw_items, | 733 | raw_items: &raw_items, |
@@ -887,6 +902,7 @@ where | |||
887 | module_id: self.module_id, | 902 | module_id: self.module_id, |
888 | ast_id, | 903 | ast_id, |
889 | legacy: Some(macro_call_id), | 904 | legacy: Some(macro_call_id), |
905 | depth: self.macro_depth + 1, | ||
890 | }); | 906 | }); |
891 | 907 | ||
892 | return; | 908 | return; |
@@ -902,6 +918,7 @@ where | |||
902 | module_id: self.module_id, | 918 | module_id: self.module_id, |
903 | ast_id, | 919 | ast_id, |
904 | legacy: None, | 920 | legacy: None, |
921 | depth: self.macro_depth + 1, | ||
905 | }); | 922 | }); |
906 | } | 923 | } |
907 | 924 | ||
@@ -971,13 +988,26 @@ mod tests { | |||
971 | } | 988 | } |
972 | 989 | ||
973 | #[test] | 990 | #[test] |
974 | fn test_macro_expand_will_stop() { | 991 | fn test_macro_expand_will_stop_1() { |
992 | do_resolve( | ||
993 | r#" | ||
994 | macro_rules! foo { | ||
995 | ($($ty:ty)*) => { foo!($($ty)*); } | ||
996 | } | ||
997 | foo!(KABOOM); | ||
998 | "#, | ||
999 | ); | ||
1000 | } | ||
1001 | |||
1002 | #[ignore] // this test does succeed, but takes quite a while :/ | ||
1003 | #[test] | ||
1004 | fn test_macro_expand_will_stop_2() { | ||
975 | do_resolve( | 1005 | do_resolve( |
976 | r#" | 1006 | r#" |
977 | macro_rules! foo { | 1007 | macro_rules! foo { |
978 | ($($ty:ty)*) => { foo!($($ty)*, $($ty)*); } | 1008 | ($($ty:ty)*) => { foo!($($ty)* $($ty)*); } |
979 | } | 1009 | } |
980 | foo!(KABOOM); | 1010 | foo!(KABOOM); |
981 | "#, | 1011 | "#, |
982 | ); | 1012 | ); |
983 | } | 1013 | } |
diff --git a/crates/ra_hir_def/src/nameres/tests.rs b/crates/ra_hir_def/src/nameres/tests.rs index dda5ed699..3f33a75b9 100644 --- a/crates/ra_hir_def/src/nameres/tests.rs +++ b/crates/ra_hir_def/src/nameres/tests.rs | |||
@@ -102,6 +102,28 @@ fn crate_def_map_super_super() { | |||
102 | } | 102 | } |
103 | 103 | ||
104 | #[test] | 104 | #[test] |
105 | fn crate_def_map_fn_mod_same_name() { | ||
106 | let map = def_map( | ||
107 | " | ||
108 | //- /lib.rs | ||
109 | mod m { | ||
110 | pub mod z {} | ||
111 | pub fn z() {} | ||
112 | } | ||
113 | ", | ||
114 | ); | ||
115 | assert_snapshot!(map, @r###" | ||
116 | â‹®crate | ||
117 | â‹®m: t | ||
118 | â‹® | ||
119 | â‹®crate::m | ||
120 | â‹®z: t v | ||
121 | â‹® | ||
122 | â‹®crate::m::z | ||
123 | "###) | ||
124 | } | ||
125 | |||
126 | #[test] | ||
105 | fn bogus_paths() { | 127 | fn bogus_paths() { |
106 | covers!(bogus_paths); | 128 | covers!(bogus_paths); |
107 | let map = def_map( | 129 | let map = def_map( |
diff --git a/crates/ra_hir_def/src/resolver.rs b/crates/ra_hir_def/src/resolver.rs index 2734d51a0..123fae72a 100644 --- a/crates/ra_hir_def/src/resolver.rs +++ b/crates/ra_hir_def/src/resolver.rs | |||
@@ -381,6 +381,11 @@ impl Resolver { | |||
381 | db: &impl DefDatabase, | 381 | db: &impl DefDatabase, |
382 | path: &ModPath, | 382 | path: &ModPath, |
383 | ) -> Option<MacroDefId> { | 383 | ) -> Option<MacroDefId> { |
384 | // Search item scope legacy macro first | ||
385 | if let Some(def) = self.resolve_local_macro_def(path) { | ||
386 | return Some(def); | ||
387 | } | ||
388 | |||
384 | let (item_map, module) = self.module_scope()?; | 389 | let (item_map, module) = self.module_scope()?; |
385 | item_map.resolve_path(db, module, &path, BuiltinShadowMode::Other).0.take_macros() | 390 | item_map.resolve_path(db, module, &path, BuiltinShadowMode::Other).0.take_macros() |
386 | } | 391 | } |
@@ -413,6 +418,16 @@ impl Resolver { | |||
413 | }) | 418 | }) |
414 | } | 419 | } |
415 | 420 | ||
421 | fn resolve_local_macro_def(&self, path: &ModPath) -> Option<MacroDefId> { | ||
422 | let name = path.as_ident()?; | ||
423 | self.scopes.iter().rev().find_map(|scope| { | ||
424 | if let Scope::LocalItemsScope(body) = scope { | ||
425 | return body.item_scope.get_legacy_macro(name); | ||
426 | } | ||
427 | None | ||
428 | }) | ||
429 | } | ||
430 | |||
416 | pub fn module(&self) -> Option<ModuleId> { | 431 | pub fn module(&self) -> Option<ModuleId> { |
417 | let (def_map, local_id) = self.module_scope()?; | 432 | let (def_map, local_id) = self.module_scope()?; |
418 | Some(ModuleId { krate: def_map.krate, local_id }) | 433 | Some(ModuleId { krate: def_map.krate, local_id }) |
diff --git a/crates/ra_hir_def/src/test_db.rs b/crates/ra_hir_def/src/test_db.rs index 1568820e9..0756916a8 100644 --- a/crates/ra_hir_def/src/test_db.rs +++ b/crates/ra_hir_def/src/test_db.rs | |||
@@ -6,7 +6,7 @@ use std::{ | |||
6 | }; | 6 | }; |
7 | 7 | ||
8 | use crate::db::DefDatabase; | 8 | use crate::db::DefDatabase; |
9 | use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath}; | 9 | use ra_db::{salsa, CrateId, ExternSourceId, FileId, FileLoader, FileLoaderDelegate, RelativePath}; |
10 | 10 | ||
11 | #[salsa::database( | 11 | #[salsa::database( |
12 | ra_db::SourceDatabaseExtStorage, | 12 | ra_db::SourceDatabaseExtStorage, |
@@ -52,6 +52,14 @@ impl FileLoader for TestDB { | |||
52 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { | 52 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { |
53 | FileLoaderDelegate(self).relevant_crates(file_id) | 53 | FileLoaderDelegate(self).relevant_crates(file_id) |
54 | } | 54 | } |
55 | |||
56 | fn resolve_extern_path( | ||
57 | &self, | ||
58 | extern_id: ExternSourceId, | ||
59 | relative_path: &RelativePath, | ||
60 | ) -> Option<FileId> { | ||
61 | FileLoaderDelegate(self).resolve_extern_path(extern_id, relative_path) | ||
62 | } | ||
55 | } | 63 | } |
56 | 64 | ||
57 | impl TestDB { | 65 | impl TestDB { |
diff --git a/crates/ra_hir_def/src/visibility.rs b/crates/ra_hir_def/src/visibility.rs index d8296da4b..e0c59e905 100644 --- a/crates/ra_hir_def/src/visibility.rs +++ b/crates/ra_hir_def/src/visibility.rs | |||
@@ -6,7 +6,7 @@ use ra_syntax::ast; | |||
6 | use crate::{ | 6 | use crate::{ |
7 | db::DefDatabase, | 7 | db::DefDatabase, |
8 | path::{ModPath, PathKind}, | 8 | path::{ModPath, PathKind}, |
9 | ModuleId, | 9 | AssocContainerId, ModuleId, |
10 | }; | 10 | }; |
11 | 11 | ||
12 | /// Visibility of an item, not yet resolved. | 12 | /// Visibility of an item, not yet resolved. |
@@ -20,11 +20,30 @@ pub enum RawVisibility { | |||
20 | } | 20 | } |
21 | 21 | ||
22 | impl RawVisibility { | 22 | impl RawVisibility { |
23 | const fn private() -> RawVisibility { | 23 | pub(crate) const fn private() -> RawVisibility { |
24 | let path = ModPath { kind: PathKind::Super(0), segments: Vec::new() }; | 24 | let path = ModPath { kind: PathKind::Super(0), segments: Vec::new() }; |
25 | RawVisibility::Module(path) | 25 | RawVisibility::Module(path) |
26 | } | 26 | } |
27 | 27 | ||
28 | pub(crate) fn default_for_container(container_id: AssocContainerId) -> Self { | ||
29 | match container_id { | ||
30 | AssocContainerId::TraitId(_) => RawVisibility::Public, | ||
31 | _ => RawVisibility::private(), | ||
32 | } | ||
33 | } | ||
34 | |||
35 | pub(crate) fn from_ast_with_default( | ||
36 | db: &impl DefDatabase, | ||
37 | default: RawVisibility, | ||
38 | node: InFile<Option<ast::Visibility>>, | ||
39 | ) -> RawVisibility { | ||
40 | Self::from_ast_with_hygiene_and_default( | ||
41 | node.value, | ||
42 | default, | ||
43 | &Hygiene::new(db, node.file_id), | ||
44 | ) | ||
45 | } | ||
46 | |||
28 | pub(crate) fn from_ast( | 47 | pub(crate) fn from_ast( |
29 | db: &impl DefDatabase, | 48 | db: &impl DefDatabase, |
30 | node: InFile<Option<ast::Visibility>>, | 49 | node: InFile<Option<ast::Visibility>>, |
@@ -36,8 +55,16 @@ impl RawVisibility { | |||
36 | node: Option<ast::Visibility>, | 55 | node: Option<ast::Visibility>, |
37 | hygiene: &Hygiene, | 56 | hygiene: &Hygiene, |
38 | ) -> RawVisibility { | 57 | ) -> RawVisibility { |
58 | Self::from_ast_with_hygiene_and_default(node, RawVisibility::private(), hygiene) | ||
59 | } | ||
60 | |||
61 | pub(crate) fn from_ast_with_hygiene_and_default( | ||
62 | node: Option<ast::Visibility>, | ||
63 | default: RawVisibility, | ||
64 | hygiene: &Hygiene, | ||
65 | ) -> RawVisibility { | ||
39 | let node = match node { | 66 | let node = match node { |
40 | None => return RawVisibility::private(), | 67 | None => return default, |
41 | Some(node) => node, | 68 | Some(node) => node, |
42 | }; | 69 | }; |
43 | match node.kind() { | 70 | match node.kind() { |
diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs index 3f60b1cca..f9d3787f6 100644 --- a/crates/ra_hir_expand/src/builtin_macro.rs +++ b/crates/ra_hir_expand/src/builtin_macro.rs | |||
@@ -88,17 +88,18 @@ register_builtin! { | |||
88 | (compile_error, CompileError) => compile_error_expand, | 88 | (compile_error, CompileError) => compile_error_expand, |
89 | (file, File) => file_expand, | 89 | (file, File) => file_expand, |
90 | (line, Line) => line_expand, | 90 | (line, Line) => line_expand, |
91 | (assert, Assert) => assert_expand, | ||
91 | (stringify, Stringify) => stringify_expand, | 92 | (stringify, Stringify) => stringify_expand, |
92 | (format_args, FormatArgs) => format_args_expand, | 93 | (format_args, FormatArgs) => format_args_expand, |
93 | (env, Env) => env_expand, | ||
94 | (option_env, OptionEnv) => option_env_expand, | ||
95 | // format_args_nl only differs in that it adds a newline in the end, | 94 | // format_args_nl only differs in that it adds a newline in the end, |
96 | // so we use the same stub expansion for now | 95 | // so we use the same stub expansion for now |
97 | (format_args_nl, FormatArgsNl) => format_args_expand, | 96 | (format_args_nl, FormatArgsNl) => format_args_expand, |
98 | 97 | ||
99 | EAGER: | 98 | EAGER: |
100 | (concat, Concat) => concat_expand, | 99 | (concat, Concat) => concat_expand, |
101 | (include, Include) => include_expand | 100 | (include, Include) => include_expand, |
101 | (env, Env) => env_expand, | ||
102 | (option_env, OptionEnv) => option_env_expand | ||
102 | } | 103 | } |
103 | 104 | ||
104 | fn line_expand( | 105 | fn line_expand( |
@@ -137,42 +138,56 @@ fn stringify_expand( | |||
137 | Ok(expanded) | 138 | Ok(expanded) |
138 | } | 139 | } |
139 | 140 | ||
140 | fn env_expand( | 141 | fn column_expand( |
141 | _db: &dyn AstDatabase, | 142 | _db: &dyn AstDatabase, |
142 | _id: LazyMacroId, | 143 | _id: LazyMacroId, |
143 | _tt: &tt::Subtree, | 144 | _tt: &tt::Subtree, |
144 | ) -> Result<tt::Subtree, mbe::ExpandError> { | 145 | ) -> Result<tt::Subtree, mbe::ExpandError> { |
145 | // dummy implementation for type-checking purposes | 146 | // dummy implementation for type-checking purposes |
146 | // we cannot use an empty string here, because for | 147 | let col_num = 0; |
147 | // `include!(concat!(env!("OUT_DIR"), "/foo.rs"))` will become | 148 | let expanded = quote! { |
148 | // `include!("foo.rs"), which maybe infinite loop | 149 | #col_num |
149 | let expanded = quote! { "__RA_UNIMPLEMENTATED__" }; | 150 | }; |
150 | 151 | ||
151 | Ok(expanded) | 152 | Ok(expanded) |
152 | } | 153 | } |
153 | 154 | ||
154 | fn option_env_expand( | 155 | fn assert_expand( |
155 | _db: &dyn AstDatabase, | 156 | _db: &dyn AstDatabase, |
156 | _id: LazyMacroId, | 157 | _id: LazyMacroId, |
157 | _tt: &tt::Subtree, | 158 | tt: &tt::Subtree, |
158 | ) -> Result<tt::Subtree, mbe::ExpandError> { | 159 | ) -> Result<tt::Subtree, mbe::ExpandError> { |
159 | // dummy implementation for type-checking purposes | 160 | // A hacky implementation for goto def and hover |
160 | let expanded = quote! { std::option::Option::None::<&str> }; | 161 | // We expand `assert!(cond, arg1, arg2)` to |
162 | // ``` | ||
163 | // {(cond, &(arg1), &(arg2));} | ||
164 | // ```, | ||
165 | // which is wrong but useful. | ||
161 | 166 | ||
162 | Ok(expanded) | 167 | let mut args = Vec::new(); |
163 | } | 168 | let mut current = Vec::new(); |
169 | for tt in tt.token_trees.iter().cloned() { | ||
170 | match tt { | ||
171 | tt::TokenTree::Leaf(tt::Leaf::Punct(p)) if p.char == ',' => { | ||
172 | args.push(current); | ||
173 | current = Vec::new(); | ||
174 | } | ||
175 | _ => { | ||
176 | current.push(tt); | ||
177 | } | ||
178 | } | ||
179 | } | ||
180 | if !current.is_empty() { | ||
181 | args.push(current); | ||
182 | } | ||
183 | |||
184 | let arg_tts = args.into_iter().flat_map(|arg| { | ||
185 | quote! { &(##arg), } | ||
186 | }.token_trees).collect::<Vec<_>>(); | ||
164 | 187 | ||
165 | fn column_expand( | ||
166 | _db: &dyn AstDatabase, | ||
167 | _id: LazyMacroId, | ||
168 | _tt: &tt::Subtree, | ||
169 | ) -> Result<tt::Subtree, mbe::ExpandError> { | ||
170 | // dummy implementation for type-checking purposes | ||
171 | let col_num = 0; | ||
172 | let expanded = quote! { | 188 | let expanded = quote! { |
173 | #col_num | 189 | { { (##arg_tts); } } |
174 | }; | 190 | }; |
175 | |||
176 | Ok(expanded) | 191 | Ok(expanded) |
177 | } | 192 | } |
178 | 193 | ||
@@ -278,30 +293,37 @@ fn concat_expand( | |||
278 | 293 | ||
279 | fn relative_file(db: &dyn AstDatabase, call_id: MacroCallId, path: &str) -> Option<FileId> { | 294 | fn relative_file(db: &dyn AstDatabase, call_id: MacroCallId, path: &str) -> Option<FileId> { |
280 | let call_site = call_id.as_file().original_file(db); | 295 | let call_site = call_id.as_file().original_file(db); |
281 | let path = RelativePath::new(&path); | ||
282 | 296 | ||
283 | let res = db.resolve_relative_path(call_site, &path)?; | 297 | // Handle trivial case |
284 | // Prevent include itself | 298 | if let Some(res) = db.resolve_relative_path(call_site, &RelativePath::new(&path)) { |
285 | if res == call_site { | 299 | // Prevent include itself |
286 | return None; | 300 | return if res == call_site { None } else { Some(res) }; |
287 | } | 301 | } |
288 | Some(res) | 302 | |
303 | // Extern paths ? | ||
304 | let krate = db.relevant_crates(call_site).get(0)?.clone(); | ||
305 | let (extern_source_id, relative_file) = | ||
306 | db.crate_graph()[krate].extern_source.extern_path(path)?; | ||
307 | |||
308 | db.resolve_extern_path(extern_source_id, &relative_file) | ||
289 | } | 309 | } |
290 | 310 | ||
291 | fn include_expand( | 311 | fn parse_string(tt: &tt::Subtree) -> Result<String, mbe::ExpandError> { |
292 | db: &dyn AstDatabase, | 312 | tt.token_trees |
293 | arg_id: EagerMacroId, | ||
294 | tt: &tt::Subtree, | ||
295 | ) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> { | ||
296 | let path = tt | ||
297 | .token_trees | ||
298 | .get(0) | 313 | .get(0) |
299 | .and_then(|tt| match tt { | 314 | .and_then(|tt| match tt { |
300 | tt::TokenTree::Leaf(tt::Leaf::Literal(it)) => unquote_str(&it), | 315 | tt::TokenTree::Leaf(tt::Leaf::Literal(it)) => unquote_str(&it), |
301 | _ => None, | 316 | _ => None, |
302 | }) | 317 | }) |
303 | .ok_or_else(|| mbe::ExpandError::ConversionError)?; | 318 | .ok_or_else(|| mbe::ExpandError::ConversionError) |
319 | } | ||
304 | 320 | ||
321 | fn include_expand( | ||
322 | db: &dyn AstDatabase, | ||
323 | arg_id: EagerMacroId, | ||
324 | tt: &tt::Subtree, | ||
325 | ) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> { | ||
326 | let path = parse_string(tt)?; | ||
305 | let file_id = | 327 | let file_id = |
306 | relative_file(db, arg_id.into(), &path).ok_or_else(|| mbe::ExpandError::ConversionError)?; | 328 | relative_file(db, arg_id.into(), &path).ok_or_else(|| mbe::ExpandError::ConversionError)?; |
307 | 329 | ||
@@ -314,12 +336,58 @@ fn include_expand( | |||
314 | Ok((res, FragmentKind::Items)) | 336 | Ok((res, FragmentKind::Items)) |
315 | } | 337 | } |
316 | 338 | ||
339 | fn get_env_inner(db: &dyn AstDatabase, arg_id: EagerMacroId, key: &str) -> Option<String> { | ||
340 | let call_id: MacroCallId = arg_id.into(); | ||
341 | let original_file = call_id.as_file().original_file(db); | ||
342 | |||
343 | let krate = db.relevant_crates(original_file).get(0)?.clone(); | ||
344 | db.crate_graph()[krate].env.get(key) | ||
345 | } | ||
346 | |||
347 | fn env_expand( | ||
348 | db: &dyn AstDatabase, | ||
349 | arg_id: EagerMacroId, | ||
350 | tt: &tt::Subtree, | ||
351 | ) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> { | ||
352 | let key = parse_string(tt)?; | ||
353 | |||
354 | // FIXME: | ||
355 | // If the environment variable is not defined int rustc, then a compilation error will be emitted. | ||
356 | // We might do the same if we fully support all other stuffs. | ||
357 | // But for now on, we should return some dummy string for better type infer purpose. | ||
358 | // However, we cannot use an empty string here, because for | ||
359 | // `include!(concat!(env!("OUT_DIR"), "/foo.rs"))` will become | ||
360 | // `include!("foo.rs"), which might go to infinite loop | ||
361 | let s = get_env_inner(db, arg_id, &key).unwrap_or("__RA_UNIMPLEMENTATED__".to_string()); | ||
362 | let expanded = quote! { #s }; | ||
363 | |||
364 | Ok((expanded, FragmentKind::Expr)) | ||
365 | } | ||
366 | |||
367 | fn option_env_expand( | ||
368 | db: &dyn AstDatabase, | ||
369 | arg_id: EagerMacroId, | ||
370 | tt: &tt::Subtree, | ||
371 | ) -> Result<(tt::Subtree, FragmentKind), mbe::ExpandError> { | ||
372 | let key = parse_string(tt)?; | ||
373 | let expanded = match get_env_inner(db, arg_id, &key) { | ||
374 | None => quote! { std::option::Option::None::<&str> }, | ||
375 | Some(s) => quote! { std::option::Some(#s) }, | ||
376 | }; | ||
377 | |||
378 | Ok((expanded, FragmentKind::Expr)) | ||
379 | } | ||
380 | |||
317 | #[cfg(test)] | 381 | #[cfg(test)] |
318 | mod tests { | 382 | mod tests { |
319 | use super::*; | 383 | use super::*; |
320 | use crate::{name::AsName, test_db::TestDB, AstNode, MacroCallId, MacroCallKind, MacroCallLoc}; | 384 | use crate::{ |
385 | name::AsName, test_db::TestDB, AstNode, EagerCallLoc, MacroCallId, MacroCallKind, | ||
386 | MacroCallLoc, | ||
387 | }; | ||
321 | use ra_db::{fixture::WithFixture, SourceDatabase}; | 388 | use ra_db::{fixture::WithFixture, SourceDatabase}; |
322 | use ra_syntax::ast::NameOwner; | 389 | use ra_syntax::ast::NameOwner; |
390 | use std::sync::Arc; | ||
323 | 391 | ||
324 | fn expand_builtin_macro(ra_fixture: &str) -> String { | 392 | fn expand_builtin_macro(ra_fixture: &str) -> String { |
325 | let (db, file_id) = TestDB::with_single_file(&ra_fixture); | 393 | let (db, file_id) = TestDB::with_single_file(&ra_fixture); |
@@ -330,27 +398,61 @@ mod tests { | |||
330 | let ast_id_map = db.ast_id_map(file_id.into()); | 398 | let ast_id_map = db.ast_id_map(file_id.into()); |
331 | 399 | ||
332 | let expander = find_by_name(¯o_calls[0].name().unwrap().as_name()).unwrap(); | 400 | let expander = find_by_name(¯o_calls[0].name().unwrap().as_name()).unwrap(); |
333 | let expander = expander.left().unwrap(); | ||
334 | 401 | ||
335 | // the first one should be a macro_rules | 402 | let file_id = match expander { |
336 | let def = MacroDefId { | 403 | Either::Left(expander) => { |
337 | krate: Some(CrateId(0)), | 404 | // the first one should be a macro_rules |
338 | ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_calls[0]))), | 405 | let def = MacroDefId { |
339 | kind: MacroDefKind::BuiltIn(expander), | 406 | krate: Some(CrateId(0)), |
340 | }; | 407 | ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_calls[0]))), |
408 | kind: MacroDefKind::BuiltIn(expander), | ||
409 | }; | ||
341 | 410 | ||
342 | let loc = MacroCallLoc { | 411 | let loc = MacroCallLoc { |
343 | def, | 412 | def, |
344 | kind: MacroCallKind::FnLike(AstId::new( | 413 | kind: MacroCallKind::FnLike(AstId::new( |
345 | file_id.into(), | 414 | file_id.into(), |
346 | ast_id_map.ast_id(¯o_calls[1]), | 415 | ast_id_map.ast_id(¯o_calls[1]), |
347 | )), | 416 | )), |
348 | }; | 417 | }; |
418 | |||
419 | let id: MacroCallId = db.intern_macro(loc).into(); | ||
420 | id.as_file() | ||
421 | } | ||
422 | Either::Right(expander) => { | ||
423 | // the first one should be a macro_rules | ||
424 | let def = MacroDefId { | ||
425 | krate: Some(CrateId(0)), | ||
426 | ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_calls[0]))), | ||
427 | kind: MacroDefKind::BuiltInEager(expander), | ||
428 | }; | ||
349 | 429 | ||
350 | let id: MacroCallId = db.intern_macro(loc).into(); | 430 | let args = macro_calls[1].token_tree().unwrap(); |
351 | let parsed = db.parse_or_expand(id.as_file()).unwrap(); | 431 | let parsed_args = mbe::ast_to_token_tree(&args).unwrap().0; |
432 | |||
433 | let arg_id = db.intern_eager_expansion({ | ||
434 | EagerCallLoc { | ||
435 | def, | ||
436 | fragment: FragmentKind::Expr, | ||
437 | subtree: Arc::new(parsed_args.clone()), | ||
438 | file_id: file_id.into(), | ||
439 | } | ||
440 | }); | ||
441 | |||
442 | let (subtree, fragment) = expander.expand(&db, arg_id, &parsed_args).unwrap(); | ||
443 | let eager = EagerCallLoc { | ||
444 | def, | ||
445 | fragment, | ||
446 | subtree: Arc::new(subtree), | ||
447 | file_id: file_id.into(), | ||
448 | }; | ||
352 | 449 | ||
353 | parsed.text().to_string() | 450 | let id: MacroCallId = db.intern_eager_expansion(eager.into()).into(); |
451 | id.as_file() | ||
452 | } | ||
453 | }; | ||
454 | |||
455 | db.parse_or_expand(file_id).unwrap().to_string() | ||
354 | } | 456 | } |
355 | 457 | ||
356 | #[test] | 458 | #[test] |
@@ -432,6 +534,22 @@ mod tests { | |||
432 | } | 534 | } |
433 | 535 | ||
434 | #[test] | 536 | #[test] |
537 | fn test_assert_expand() { | ||
538 | let expanded = expand_builtin_macro( | ||
539 | r#" | ||
540 | #[rustc_builtin_macro] | ||
541 | macro_rules! assert { | ||
542 | ($cond:expr) => ({ /* compiler built-in */ }); | ||
543 | ($cond:expr, $($args:tt)*) => ({ /* compiler built-in */ }) | ||
544 | } | ||
545 | assert!(true, "{} {:?}", arg1(a, b, c), arg2); | ||
546 | "#, | ||
547 | ); | ||
548 | |||
549 | assert_eq!(expanded, "{{(&(true), &(\"{} {:?}\"), &(arg1(a,b,c)), &(arg2),);}}"); | ||
550 | } | ||
551 | |||
552 | #[test] | ||
435 | fn test_compile_error_expand() { | 553 | fn test_compile_error_expand() { |
436 | let expanded = expand_builtin_macro( | 554 | let expanded = expand_builtin_macro( |
437 | r#" | 555 | r#" |
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index 3fce73e8a..7b72eb7a0 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs | |||
@@ -17,7 +17,7 @@ pub mod eager; | |||
17 | use std::hash::Hash; | 17 | use std::hash::Hash; |
18 | use std::sync::Arc; | 18 | use std::sync::Arc; |
19 | 19 | ||
20 | use ra_db::{salsa, CrateId, FileId}; | 20 | use ra_db::{impl_intern_key, salsa, CrateId, FileId}; |
21 | use ra_syntax::{ | 21 | use ra_syntax::{ |
22 | algo, | 22 | algo, |
23 | ast::{self, AstNode}, | 23 | ast::{self, AstNode}, |
@@ -174,25 +174,11 @@ pub enum MacroCallId { | |||
174 | 174 | ||
175 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 175 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
176 | pub struct LazyMacroId(salsa::InternId); | 176 | pub struct LazyMacroId(salsa::InternId); |
177 | impl salsa::InternKey for LazyMacroId { | 177 | impl_intern_key!(LazyMacroId); |
178 | fn from_intern_id(v: salsa::InternId) -> Self { | ||
179 | LazyMacroId(v) | ||
180 | } | ||
181 | fn as_intern_id(&self) -> salsa::InternId { | ||
182 | self.0 | ||
183 | } | ||
184 | } | ||
185 | 178 | ||
186 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 179 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
187 | pub struct EagerMacroId(salsa::InternId); | 180 | pub struct EagerMacroId(salsa::InternId); |
188 | impl salsa::InternKey for EagerMacroId { | 181 | impl_intern_key!(EagerMacroId); |
189 | fn from_intern_id(v: salsa::InternId) -> Self { | ||
190 | EagerMacroId(v) | ||
191 | } | ||
192 | fn as_intern_id(&self) -> salsa::InternId { | ||
193 | self.0 | ||
194 | } | ||
195 | } | ||
196 | 182 | ||
197 | impl From<LazyMacroId> for MacroCallId { | 183 | impl From<LazyMacroId> for MacroCallId { |
198 | fn from(it: LazyMacroId) -> Self { | 184 | fn from(it: LazyMacroId) -> Self { |
diff --git a/crates/ra_hir_expand/src/name.rs b/crates/ra_hir_expand/src/name.rs index 6d201256f..25cc1e9fc 100644 --- a/crates/ra_hir_expand/src/name.rs +++ b/crates/ra_hir_expand/src/name.rs | |||
@@ -172,6 +172,7 @@ pub mod known { | |||
172 | column, | 172 | column, |
173 | compile_error, | 173 | compile_error, |
174 | line, | 174 | line, |
175 | assert, | ||
175 | stringify, | 176 | stringify, |
176 | concat, | 177 | concat, |
177 | include, | 178 | include, |
diff --git a/crates/ra_hir_expand/src/quote.rs b/crates/ra_hir_expand/src/quote.rs index 57e7eebf9..3fd4233da 100644 --- a/crates/ra_hir_expand/src/quote.rs +++ b/crates/ra_hir_expand/src/quote.rs | |||
@@ -99,6 +99,7 @@ macro_rules! __quote { | |||
99 | ( & ) => {$crate::__quote!(@PUNCT '&')}; | 99 | ( & ) => {$crate::__quote!(@PUNCT '&')}; |
100 | ( , ) => {$crate::__quote!(@PUNCT ',')}; | 100 | ( , ) => {$crate::__quote!(@PUNCT ',')}; |
101 | ( : ) => {$crate::__quote!(@PUNCT ':')}; | 101 | ( : ) => {$crate::__quote!(@PUNCT ':')}; |
102 | ( ; ) => {$crate::__quote!(@PUNCT ';')}; | ||
102 | ( :: ) => {$crate::__quote!(@PUNCT ':', ':')}; | 103 | ( :: ) => {$crate::__quote!(@PUNCT ':', ':')}; |
103 | ( . ) => {$crate::__quote!(@PUNCT '.')}; | 104 | ( . ) => {$crate::__quote!(@PUNCT '.')}; |
104 | ( < ) => {$crate::__quote!(@PUNCT '<')}; | 105 | ( < ) => {$crate::__quote!(@PUNCT '<')}; |
diff --git a/crates/ra_hir_expand/src/test_db.rs b/crates/ra_hir_expand/src/test_db.rs index 918736e2a..c1fb762de 100644 --- a/crates/ra_hir_expand/src/test_db.rs +++ b/crates/ra_hir_expand/src/test_db.rs | |||
@@ -5,7 +5,7 @@ use std::{ | |||
5 | sync::{Arc, Mutex}, | 5 | sync::{Arc, Mutex}, |
6 | }; | 6 | }; |
7 | 7 | ||
8 | use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath}; | 8 | use ra_db::{salsa, CrateId, ExternSourceId, FileId, FileLoader, FileLoaderDelegate, RelativePath}; |
9 | 9 | ||
10 | #[salsa::database( | 10 | #[salsa::database( |
11 | ra_db::SourceDatabaseExtStorage, | 11 | ra_db::SourceDatabaseExtStorage, |
@@ -51,4 +51,11 @@ impl FileLoader for TestDB { | |||
51 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { | 51 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { |
52 | FileLoaderDelegate(self).relevant_crates(file_id) | 52 | FileLoaderDelegate(self).relevant_crates(file_id) |
53 | } | 53 | } |
54 | fn resolve_extern_path( | ||
55 | &self, | ||
56 | anchor: ExternSourceId, | ||
57 | relative_path: &RelativePath, | ||
58 | ) -> Option<FileId> { | ||
59 | FileLoaderDelegate(self).resolve_extern_path(anchor, relative_path) | ||
60 | } | ||
54 | } | 61 | } |
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs <index b7e8855fb..7f5e1469e 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs |