aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir/src/code_model_api.rs2
-rw-r--r--crates/ra_hir/src/nameres.rs90
-rw-r--r--crates/ra_hir/src/nameres/lower.rs22
-rw-r--r--crates/ra_hir/src/nameres/tests.rs48
-rw-r--r--crates/ra_hir/src/resolve.rs5
-rw-r--r--crates/ra_hir/src/ty/snapshots/tests__infer_self.snap10
-rw-r--r--crates/ra_hir/src/ty/tests.rs6
-rw-r--r--crates/ra_ide_api/src/completion/complete_scope.rs14
-rw-r--r--crates/ra_ide_api/src/completion/snapshots/completion_item__extern_prelude.snap22
-rw-r--r--crates/ra_ide_api/src/mock_analysis.rs12
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs27
-rw-r--r--crates/ra_lsp_server/src/project_model/sysroot.rs1
-rw-r--r--crates/ra_mbe/src/lib.rs24
-rw-r--r--crates/ra_mbe/src/mbe_expander.rs8
-rw-r--r--crates/ra_syntax/src/ast/generated.rs10
-rw-r--r--crates/ra_syntax/src/grammar.ron4
-rw-r--r--crates/ra_syntax/src/grammar/items.rs2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0060_extern_crate.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0007_extern_crate.txt4
19 files changed, 247 insertions, 66 deletions
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs
index 92ab0f692..a58bf8f87 100644
--- a/crates/ra_hir/src/code_model_api.rs
+++ b/crates/ra_hir/src/code_model_api.rs
@@ -134,7 +134,7 @@ impl Module {
134 } 134 }
135 135
136 /// Returns the crate this module is part of. 136 /// Returns the crate this module is part of.
137 pub fn krate(&self, _db: &impl HirDatabase) -> Option<Crate> { 137 pub fn krate(&self, _db: &impl PersistentHirDatabase) -> Option<Crate> {
138 Some(self.krate) 138 Some(self.krate)
139 } 139 }
140 140
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index 04cc693b3..681aa9a67 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -34,6 +34,7 @@ use crate::{
34/// module, the set of visible items. 34/// module, the set of visible items.
35#[derive(Default, Debug, PartialEq, Eq)] 35#[derive(Default, Debug, PartialEq, Eq)]
36pub struct ItemMap { 36pub struct ItemMap {
37 pub(crate) extern_prelude: FxHashMap<Name, ModuleDef>,
37 per_module: ArenaMap<ModuleId, ModuleScope>, 38 per_module: ArenaMap<ModuleId, ModuleScope>,
38} 39}
39 40
@@ -204,6 +205,7 @@ where
204 } 205 }
205 206
206 pub(crate) fn resolve(mut self) -> ItemMap { 207 pub(crate) fn resolve(mut self) -> ItemMap {
208 self.populate_extern_prelude();
207 for (&module_id, items) in self.input.iter() { 209 for (&module_id, items) in self.input.iter() {
208 self.populate_module(module_id, Arc::clone(items)); 210 self.populate_module(module_id, Arc::clone(items));
209 } 211 }
@@ -227,29 +229,19 @@ where
227 self.result 229 self.result
228 } 230 }
229 231
232 fn populate_extern_prelude(&mut self) {
233 for dep in self.krate.dependencies(self.db) {
234 log::debug!("crate dep {:?} -> {:?}", dep.name, dep.krate);
235 if let Some(module) = dep.krate.root_module(self.db) {
236 self.result
237 .extern_prelude
238 .insert(dep.name.clone(), module.into());
239 }
240 }
241 }
242
230 fn populate_module(&mut self, module_id: ModuleId, input: Arc<LoweredModule>) { 243 fn populate_module(&mut self, module_id: ModuleId, input: Arc<LoweredModule>) {
231 let mut module_items = ModuleScope::default(); 244 let mut module_items = ModuleScope::default();
232
233 // Populate extern crates prelude
234 {
235 let root_id = module_id.crate_root(&self.module_tree);
236 let file_id = root_id.file_id(&self.module_tree);
237 let crate_graph = self.db.crate_graph();
238 if let Some(crate_id) = crate_graph.crate_id_for_crate_root(file_id.as_original_file())
239 {
240 let krate = Crate { crate_id };
241 for dep in krate.dependencies(self.db) {
242 if let Some(module) = dep.krate.root_module(self.db) {
243 let def = module.into();
244 self.add_module_item(
245 &mut module_items,
246 dep.name.clone(),
247 PerNs::types(def),
248 );
249 }
250 }
251 };
252 }
253 for (import_id, import_data) in input.imports.iter() { 245 for (import_id, import_data) in input.imports.iter() {
254 if let Some(last_segment) = import_data.path.segments.iter().last() { 246 if let Some(last_segment) = import_data.path.segments.iter().last() {
255 if !import_data.is_glob { 247 if !import_data.is_glob {
@@ -327,7 +319,16 @@ where
327 .alias 319 .alias
328 .clone() 320 .clone()
329 .unwrap_or_else(|| last_segment.name.clone()); 321 .unwrap_or_else(|| last_segment.name.clone());
330 log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def,); 322 log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
323
324 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
325 if let Some(root_module) = self.krate.root_module(self.db) {
326 if import.is_extern_crate && module_id == root_module.module_id {
327 if let Some(def) = def.take_types() {
328 self.result.extern_prelude.insert(name.clone(), def);
329 }
330 }
331 }
331 self.update(module_id, |items| { 332 self.update(module_id, |items| {
332 let res = Resolution { 333 let res = Resolution {
333 def, 334 def,
@@ -389,24 +390,53 @@ impl ItemMap {
389 original_module: Module, 390 original_module: Module,
390 path: &Path, 391 path: &Path,
391 ) -> (PerNs<ModuleDef>, ReachedFixedPoint) { 392 ) -> (PerNs<ModuleDef>, ReachedFixedPoint) {
392 let mut curr_per_ns: PerNs<ModuleDef> = PerNs::types(match path.kind { 393 let mut segments = path.segments.iter().enumerate();
393 PathKind::Crate => original_module.crate_root(db).into(), 394 let mut curr_per_ns: PerNs<ModuleDef> = match path.kind {
394 PathKind::Self_ | PathKind::Plain => original_module.into(), 395 PathKind::Crate => PerNs::types(original_module.crate_root(db).into()),
396 PathKind::Self_ => PerNs::types(original_module.into()),
397 PathKind::Plain => {
398 let segment = match segments.next() {
399 Some((_, segment)) => segment,
400 None => return (PerNs::none(), ReachedFixedPoint::Yes),
401 };
402 // Resolve in:
403 // - current module / scope
404 // - extern prelude
405 match self[original_module.module_id].items.get(&segment.name) {
406 Some(res) if !res.def.is_none() => res.def,
407 _ => {
408 if let Some(def) = self.extern_prelude.get(&segment.name) {
409 PerNs::types(*def)
410 } else {
411 return (PerNs::none(), ReachedFixedPoint::No);
412 }
413 }
414 }
415 }
395 PathKind::Super => { 416 PathKind::Super => {
396 if let Some(p) = original_module.parent(db) { 417 if let Some(p) = original_module.parent(db) {
397 p.into() 418 PerNs::types(p.into())
398 } else { 419 } else {
399 log::debug!("super path in root module"); 420 log::debug!("super path in root module");
400 return (PerNs::none(), ReachedFixedPoint::Yes); 421 return (PerNs::none(), ReachedFixedPoint::Yes);
401 } 422 }
402 } 423 }
403 PathKind::Abs => { 424 PathKind::Abs => {
404 // TODO: absolute use is not supported 425 // 2018-style absolute path -- only extern prelude
405 return (PerNs::none(), ReachedFixedPoint::Yes); 426 let segment = match segments.next() {
427 Some((_, segment)) => segment,
428 None => return (PerNs::none(), ReachedFixedPoint::Yes),
429 };
430 if let Some(def) = self.extern_prelude.get(&segment.name) {
431 log::debug!("absolute path {:?} resolved to crate {:?}", path, def);
432 PerNs::types(*def)
433 } else {
434 return (PerNs::none(), ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
435 }
406 } 436 }
407 }); 437 };
408 438
409 for (i, segment) in path.segments.iter().enumerate() { 439 for (i, segment) in segments {
410 let curr = match curr_per_ns.as_ref().take_types() { 440 let curr = match curr_per_ns.as_ref().take_types() {
411 Some(r) => r, 441 Some(r) => r,
412 None => { 442 None => {
diff --git a/crates/ra_hir/src/nameres/lower.rs b/crates/ra_hir/src/nameres/lower.rs
index df87f520f..7e6e48ae0 100644
--- a/crates/ra_hir/src/nameres/lower.rs
+++ b/crates/ra_hir/src/nameres/lower.rs
@@ -8,7 +8,7 @@ use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap};
8use rustc_hash::FxHashMap; 8use rustc_hash::FxHashMap;
9 9
10use crate::{ 10use crate::{
11 SourceItemId, Path, ModuleSource, Name, 11 SourceItemId, Path, PathKind, ModuleSource, Name,
12 HirFileId, MacroCallLoc, AsName, PerNs, Function, 12 HirFileId, MacroCallLoc, AsName, PerNs, Function,
13 ModuleDef, Module, Struct, Enum, Const, Static, Trait, Type, 13 ModuleDef, Module, Struct, Enum, Const, Static, Trait, Type,
14 ids::LocationCtx, PersistentHirDatabase, 14 ids::LocationCtx, PersistentHirDatabase,
@@ -23,6 +23,7 @@ pub(super) struct ImportData {
23 pub(super) path: Path, 23 pub(super) path: Path,
24 pub(super) alias: Option<Name>, 24 pub(super) alias: Option<Name>,
25 pub(super) is_glob: bool, 25 pub(super) is_glob: bool,
26 pub(super) is_extern_crate: bool,
26} 27}
27 28
28/// A set of items and imports declared inside a module, without relation to 29/// A set of items and imports declared inside a module, without relation to
@@ -186,8 +187,22 @@ impl LoweredModule {
186 ast::ModuleItemKind::UseItem(it) => { 187 ast::ModuleItemKind::UseItem(it) => {
187 self.add_use_item(source_map, it); 188 self.add_use_item(source_map, it);
188 } 189 }
189 ast::ModuleItemKind::ExternCrateItem(_) => { 190 ast::ModuleItemKind::ExternCrateItem(it) => {
190 // TODO 191 // Lower `extern crate x` to `use ::x`. This is kind of cheating
192 // and only works if we always interpret absolute paths in the
193 // 2018 style; otherwise `::x` could also refer to a module in
194 // the crate root.
195 if let Some(name_ref) = it.name_ref() {
196 let mut path = Path::from_name_ref(name_ref);
197 path.kind = PathKind::Abs;
198 let alias = it.alias().and_then(|a| a.name()).map(AsName::as_name);
199 self.imports.alloc(ImportData {
200 path,
201 alias,
202 is_glob: false,
203 is_extern_crate: true,
204 });
205 }
191 } 206 }
192 ast::ModuleItemKind::ConstDef(it) => { 207 ast::ModuleItemKind::ConstDef(it) => {
193 if let Some(name) = it.name() { 208 if let Some(name) = it.name() {
@@ -215,6 +230,7 @@ impl LoweredModule {
215 path, 230 path,
216 alias, 231 alias,
217 is_glob: segment.is_none(), 232 is_glob: segment.is_none(),
233 is_extern_crate: false,
218 }); 234 });
219 if let Some(segment) = segment { 235 if let Some(segment) = segment {
220 source_map.insert(import, segment) 236 source_map.insert(import, segment)
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs
index 81c8a4f12..0654dbaa1 100644
--- a/crates/ra_hir/src/nameres/tests.rs
+++ b/crates/ra_hir/src/nameres/tests.rs
@@ -329,7 +329,49 @@ fn item_map_across_crates() {
329 module.module_id, 329 module.module_id,
330 " 330 "
331 Baz: t v 331 Baz: t v
332 test_crate: t 332 ",
333 );
334}
335
336#[test]
337fn extern_crate_rename() {
338 let (mut db, sr) = MockDatabase::with_files(
339 "
340 //- /main.rs
341 extern crate alloc as alloc_crate;
342
343 mod alloc;
344 mod sync;
345
346 //- /sync.rs
347 use alloc_crate::Arc;
348
349 //- /lib.rs
350 struct Arc;
351 ",
352 );
353 let main_id = sr.files[RelativePath::new("/main.rs")];
354 let sync_id = sr.files[RelativePath::new("/sync.rs")];
355 let lib_id = sr.files[RelativePath::new("/lib.rs")];
356
357 let mut crate_graph = CrateGraph::default();
358 let main_crate = crate_graph.add_crate_root(main_id);
359 let lib_crate = crate_graph.add_crate_root(lib_id);
360 crate_graph
361 .add_dep(main_crate, "alloc".into(), lib_crate)
362 .unwrap();
363
364 db.set_crate_graph(Arc::new(crate_graph));
365
366 let module = crate::source_binder::module_from_file_id(&db, sync_id).unwrap();
367 let krate = module.krate(&db).unwrap();
368 let item_map = db.item_map(krate);
369
370 check_module_item_map(
371 &item_map,
372 module.module_id,
373 "
374 Arc: t v
333 ", 375 ",
334 ); 376 );
335} 377}
@@ -361,8 +403,6 @@ fn import_across_source_roots() {
361 403
362 let main_id = sr2.files[RelativePath::new("/main.rs")]; 404 let main_id = sr2.files[RelativePath::new("/main.rs")];
363 405
364 eprintln!("lib = {:?}, main = {:?}", lib_id, main_id);
365
366 let mut crate_graph = CrateGraph::default(); 406 let mut crate_graph = CrateGraph::default();
367 let main_crate = crate_graph.add_crate_root(main_id); 407 let main_crate = crate_graph.add_crate_root(main_id);
368 let lib_crate = crate_graph.add_crate_root(lib_id); 408 let lib_crate = crate_graph.add_crate_root(lib_id);
@@ -381,7 +421,6 @@ fn import_across_source_roots() {
381 module.module_id, 421 module.module_id,
382 " 422 "
383 C: t v 423 C: t v
384 test_crate: t
385 ", 424 ",
386 ); 425 );
387} 426}
@@ -423,7 +462,6 @@ fn reexport_across_crates() {
423 module.module_id, 462 module.module_id,
424 " 463 "
425 Baz: t v 464 Baz: t v
426 test_crate: t
427 ", 465 ",
428 ); 466 );
429} 467}
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs
index 6c87d0df7..5ca7bacb5 100644
--- a/crates/ra_hir/src/resolve.rs
+++ b/crates/ra_hir/src/resolve.rs
@@ -197,7 +197,10 @@ impl Scope {
197 .entries() 197 .entries()
198 .for_each(|(name, res)| { 198 .for_each(|(name, res)| {
199 f(name.clone(), res.def.map(Resolution::Def)); 199 f(name.clone(), res.def.map(Resolution::Def));
200 }) 200 });
201 m.item_map.extern_prelude.iter().for_each(|(name, def)| {
202 f(name.clone(), PerNs::types(Resolution::Def(*def)));
203 });
201 } 204 }
202 Scope::GenericParams(gp) => { 205 Scope::GenericParams(gp) => {
203 for param in &gp.params { 206 for param in &gp.params {
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_self.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_self.snap
index 84c8b1e90..5c927f5c1 100644
--- a/crates/ra_hir/src/ty/snapshots/tests__infer_self.snap
+++ b/crates/ra_hir/src/ty/snapshots/tests__infer_self.snap
@@ -1,8 +1,8 @@
1--- 1---
2created: "2019-01-22T14:45:00.052694700+00:00" 2created: "2019-02-04T19:40:48.826936500+00:00"
3creator: insta@0.4.0 3creator: insta@0.5.3
4expression: "&result" 4expression: "&result"
5source: "crates\\ra_hir\\src\\ty\\tests.rs" 5source: crates/ra_hir/src/ty/tests.rs
6--- 6---
7[34; 38) 'self': &S 7[34; 38) 'self': &S
8[40; 61) '{ ... }': () 8[40; 61) '{ ... }': ()
@@ -10,4 +10,8 @@ source: "crates\\ra_hir\\src\\ty\\tests.rs"
10[75; 79) 'self': &S 10[75; 79) 'self': &S
11[88; 109) '{ ... }': () 11[88; 109) '{ ... }': ()
12[98; 102) 'self': &S 12[98; 102) 'self': &S
13[133; 153) '{ ... }': S
14[143; 147) 'S {}': S
15[177; 200) '{ ... }': S
16[187; 194) 'Self {}': S
13 17
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index cb8d6351d..30da8fc23 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -215,6 +215,12 @@ impl S {
215 fn test2(self: &Self) { 215 fn test2(self: &Self) {
216 self; 216 self;
217 } 217 }
218 fn test3() -> Self {
219 S {}
220 }
221 fn test4() -> Self {
222 Self {}
223 }
218} 224}
219"#, 225"#,
220 ); 226 );
diff --git a/crates/ra_ide_api/src/completion/complete_scope.rs b/crates/ra_ide_api/src/completion/complete_scope.rs
index 44514ab2b..8674b1e66 100644
--- a/crates/ra_ide_api/src/completion/complete_scope.rs
+++ b/crates/ra_ide_api/src/completion/complete_scope.rs
@@ -111,6 +111,20 @@ mod tests {
111 } 111 }
112 112
113 #[test] 113 #[test]
114 fn completes_extern_prelude() {
115 check_reference_completion(
116 "extern_prelude",
117 r"
118 //- /lib.rs
119 use <|>;
120
121 //- /other_crate/lib.rs
122 // nothing here
123 ",
124 );
125 }
126
127 #[test]
114 fn completes_module_items_in_nested_modules() { 128 fn completes_module_items_in_nested_modules() {
115 check_reference_completion( 129 check_reference_completion(
116 "module_items_in_nested_modules", 130 "module_items_in_nested_modules",
diff --git a/crates/ra_ide_api/src/completion/snapshots/completion_item__extern_prelude.snap b/crates/ra_ide_api/src/completion/snapshots/completion_item__extern_prelude.snap
new file mode 100644
index 000000000..d0e3a6188
--- /dev/null
+++ b/crates/ra_ide_api/src/completion/snapshots/completion_item__extern_prelude.snap
@@ -0,0 +1,22 @@
1---
2created: "2019-02-04T21:08:32.615556587+00:00"
3creator: [email protected]
4expression: kind_completions
5source: crates/ra_ide_api/src/completion/completion_item.rs
6---
7[
8 CompletionItem {
9 completion_kind: Reference,
10 label: "other_crate",
11 kind: Some(
12 Module
13 ),
14 detail: None,
15 documentation: None,
16 lookup: None,
17 insert_text: None,
18 insert_text_format: PlainText,
19 source_range: [4; 4),
20 text_edit: None
21 }
22]
diff --git a/crates/ra_ide_api/src/mock_analysis.rs b/crates/ra_ide_api/src/mock_analysis.rs
index 0f2d22ab2..834b30541 100644
--- a/crates/ra_ide_api/src/mock_analysis.rs
+++ b/crates/ra_ide_api/src/mock_analysis.rs
@@ -86,17 +86,25 @@ impl MockAnalysis {
86 let mut change = AnalysisChange::new(); 86 let mut change = AnalysisChange::new();
87 change.add_root(source_root, true); 87 change.add_root(source_root, true);
88 let mut crate_graph = CrateGraph::default(); 88 let mut crate_graph = CrateGraph::default();
89 let mut root_crate = None;
89 for (i, (path, contents)) in self.files.into_iter().enumerate() { 90 for (i, (path, contents)) in self.files.into_iter().enumerate() {
90 assert!(path.starts_with('/')); 91 assert!(path.starts_with('/'));
91 let path = RelativePathBuf::from_path(&path[1..]).unwrap(); 92 let path = RelativePathBuf::from_path(&path[1..]).unwrap();
92 let file_id = FileId(i as u32 + 1); 93 let file_id = FileId(i as u32 + 1);
93 if path == "/lib.rs" || path == "/main.rs" { 94 if path == "/lib.rs" || path == "/main.rs" {
94 crate_graph.add_crate_root(file_id); 95 root_crate = Some(crate_graph.add_crate_root(file_id));
96 } else if path.ends_with("/lib.rs") {
97 let other_crate = crate_graph.add_crate_root(file_id);
98 let crate_name = path.parent().unwrap().file_name().unwrap();
99 if let Some(root_crate) = root_crate {
100 crate_graph
101 .add_dep(root_crate, crate_name.into(), other_crate)
102 .unwrap();
103 }
95 } 104 }
96 change.add_file(source_root, file_id, path, Arc::new(contents)); 105 change.add_file(source_root, file_id, path, Arc::new(contents));
97 } 106 }
98 change.set_crate_graph(crate_graph); 107 change.set_crate_graph(crate_graph);
99 // change.set_file_resolver(Arc::new(file_map));
100 host.apply_change(change); 108 host.apply_change(change);
101 host 109 host
102 } 110 }
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index 9e2cc8ffc..4720a8843 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -599,9 +599,6 @@ pub fn handle_code_action(
599 let title = source_edit.label.clone(); 599 let title = source_edit.label.clone();
600 let edit = source_edit.try_conv_with(&world)?; 600 let edit = source_edit.try_conv_with(&world)?;
601 601
602 // We cannot use the 'editor.action.showReferences' command directly
603 // because that command requires vscode types which we convert in the handler
604 // on the client side.
605 let cmd = Command { 602 let cmd = Command {
606 title, 603 title,
607 command: "rust-analyzer.applySourceChange".to_string(), 604 command: "rust-analyzer.applySourceChange".to_string(),
@@ -713,21 +710,25 @@ pub fn handle_code_lens_resolve(world: ServerWorld, code_lens: CodeLens) -> Resu
713 format!("{} implementations", locations.len()) 710 format!("{} implementations", locations.len())
714 }; 711 };
715 712
713 // We cannot use the 'editor.action.showReferences' command directly
714 // because that command requires vscode types which we convert in the handler
715 // on the client side.
716 let cmd = Command {
717 title,
718 command: "rust-analyzer.showReferences".into(),
719 arguments: Some(vec![
720 to_value(&Ser::new(&lens_params.text_document.uri)).unwrap(),
721 to_value(code_lens.range.start).unwrap(),
722 to_value(locations).unwrap(),
723 ]),
724 };
716 return Ok(CodeLens { 725 return Ok(CodeLens {
717 range: code_lens.range, 726 range: code_lens.range,
718 command: Some(Command { 727 command: Some(cmd),
719 title,
720 command: "rust-analyzer.showReferences".into(),
721 arguments: Some(vec![
722 to_value(&Ser::new(&lens_params.text_document.uri)).unwrap(),
723 to_value(code_lens.range.start).unwrap(),
724 to_value(locations).unwrap(),
725 ]),
726 }),
727 data: None, 728 data: None,
728 }); 729 });
729 } 730 }
730 _ => { 731 None => {
731 return Ok(CodeLens { 732 return Ok(CodeLens {
732 range: code_lens.range, 733 range: code_lens.range,
733 command: Some(Command { 734 command: Some(Command {
diff --git a/crates/ra_lsp_server/src/project_model/sysroot.rs b/crates/ra_lsp_server/src/project_model/sysroot.rs
index 1e0604bf5..fb4685671 100644
--- a/crates/ra_lsp_server/src/project_model/sysroot.rs
+++ b/crates/ra_lsp_server/src/project_model/sysroot.rs
@@ -127,6 +127,7 @@ rustc_tsan
127syntax"; 127syntax";
128 128
129const STD_DEPS: &str = " 129const STD_DEPS: &str = "
130alloc
130alloc_jemalloc 131alloc_jemalloc
131alloc_system 132alloc_system
132core 133core
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs
index 6f719acbf..2c8ad4429 100644
--- a/crates/ra_mbe/src/lib.rs
+++ b/crates/ra_mbe/src/lib.rs
@@ -256,4 +256,28 @@ impl_froms!(TokenTree: Leaf, Subtree);
256 assert_expansion(&rules, "foo! { eggs Baz }", "struct Baz ;"); 256 assert_expansion(&rules, "foo! { eggs Baz }", "struct Baz ;");
257 } 257 }
258 258
259 #[test]
260 fn test_match_group_pattern_by_separator_token() {
261 let rules = create_rules(
262 r#"
263 macro_rules! foo {
264 ($ ($ i:ident),*) => ($ (
265 mod $ i {}
266 )*);
267 ($ ($ i:ident)#*) => ($ (
268 fn $ i() {}
269 )*);
270 ($ i:ident ,# $ j:ident) => (
271 struct $ i;
272 struct $ j;
273 )
274 }
275"#,
276 );
277
278 assert_expansion(&rules, "foo! { foo, bar }", "mod foo {} mod bar {}");
279 assert_expansion(&rules, "foo! { foo# bar }", "fn foo () {} fn bar () {}");
280 assert_expansion(&rules, "foo! { Foo,# Bar }", "struct Foo ; struct Bar ;");
281 }
282
259} 283}
diff --git a/crates/ra_mbe/src/mbe_expander.rs b/crates/ra_mbe/src/mbe_expander.rs
index 212e2ea92..04b5a4035 100644
--- a/crates/ra_mbe/src/mbe_expander.rs
+++ b/crates/ra_mbe/src/mbe_expander.rs
@@ -140,8 +140,12 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Option<Bindings>
140 }) => { 140 }) => {
141 while let Some(nested) = match_lhs(subtree, input) { 141 while let Some(nested) = match_lhs(subtree, input) {
142 res.push_nested(nested)?; 142 res.push_nested(nested)?;
143 if separator.is_some() && !input.is_eof() { 143 if let Some(separator) = *separator {
144 input.eat_punct()?; 144 if !input.is_eof() {
145 if input.eat_punct()?.char != separator {
146 return None;
147 }
148 }
145 } 149 }
146 } 150 }
147 } 151 }
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index 60480c699..a8d60e882 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -970,7 +970,15 @@ impl ToOwned for ExternCrateItem {
970} 970}
971 971
972 972
973impl ExternCrateItem {} 973impl ExternCrateItem {
974 pub fn name_ref(&self) -> Option<&NameRef> {
975 super::child_opt(self)
976 }
977
978 pub fn alias(&self) -> Option<&Alias> {
979 super::child_opt(self)
980 }
981}
974 982
975// FalseKw 983// FalseKw
976#[derive(Debug, PartialEq, Eq, Hash)] 984#[derive(Debug, PartialEq, Eq, Hash)]
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron
index a2ccd7cb9..2ed1fd1b8 100644
--- a/crates/ra_syntax/src/grammar.ron
+++ b/crates/ra_syntax/src/grammar.ron
@@ -601,7 +601,9 @@ Grammar(
601 "UseTreeList": ( 601 "UseTreeList": (
602 collections: [["use_trees", "UseTree"]] 602 collections: [["use_trees", "UseTree"]]
603 ), 603 ),
604 "ExternCrateItem": (), 604 "ExternCrateItem": (
605 options: ["NameRef", "Alias"],
606 ),
605 "ArgList": ( 607 "ArgList": (
606 collections: [ 608 collections: [
607 ["args", "Expr"] 609 ["args", "Expr"]
diff --git a/crates/ra_syntax/src/grammar/items.rs b/crates/ra_syntax/src/grammar/items.rs
index 18039cd3f..84c18a293 100644
--- a/crates/ra_syntax/src/grammar/items.rs
+++ b/crates/ra_syntax/src/grammar/items.rs
@@ -247,7 +247,7 @@ fn extern_crate_item(p: &mut Parser) {
247 p.bump(); 247 p.bump();
248 assert!(p.at(CRATE_KW)); 248 assert!(p.at(CRATE_KW));
249 p.bump(); 249 p.bump();
250 name(p); 250 name_ref(p);
251 opt_alias(p); 251 opt_alias(p);
252 p.expect(SEMI); 252 p.expect(SEMI);
253} 253}
diff --git a/crates/ra_syntax/tests/data/parser/inline/ok/0060_extern_crate.txt b/crates/ra_syntax/tests/data/parser/inline/ok/0060_extern_crate.txt
index 7ffdc7fbd..a7b428787 100644
--- a/crates/ra_syntax/tests/data/parser/inline/ok/0060_extern_crate.txt
+++ b/crates/ra_syntax/tests/data/parser/inline/ok/0060_extern_crate.txt
@@ -4,7 +4,7 @@ SOURCE_FILE@[0; 18)
4 WHITESPACE@[6; 7) 4 WHITESPACE@[6; 7)
5 CRATE_KW@[7; 12) 5 CRATE_KW@[7; 12)
6 WHITESPACE@[12; 13) 6 WHITESPACE@[12; 13)
7 NAME@[13; 16) 7 NAME_REF@[13; 16)
8 IDENT@[13; 16) "foo" 8 IDENT@[13; 16) "foo"
9 SEMI@[16; 17) 9 SEMI@[16; 17)
10 WHITESPACE@[17; 18) 10 WHITESPACE@[17; 18)
diff --git a/crates/ra_syntax/tests/data/parser/ok/0007_extern_crate.txt b/crates/ra_syntax/tests/data/parser/ok/0007_extern_crate.txt
index 5adf3f276..5558d952e 100644
--- a/crates/ra_syntax/tests/data/parser/ok/0007_extern_crate.txt
+++ b/crates/ra_syntax/tests/data/parser/ok/0007_extern_crate.txt
@@ -4,7 +4,7 @@ SOURCE_FILE@[0; 43)
4 WHITESPACE@[6; 7) 4 WHITESPACE@[6; 7)
5 CRATE_KW@[7; 12) 5 CRATE_KW@[7; 12)
6 WHITESPACE@[12; 13) 6 WHITESPACE@[12; 13)
7 NAME@[13; 16) 7 NAME_REF@[13; 16)
8 IDENT@[13; 16) "foo" 8 IDENT@[13; 16) "foo"
9 SEMI@[16; 17) 9 SEMI@[16; 17)
10 WHITESPACE@[17; 18) 10 WHITESPACE@[17; 18)
@@ -13,7 +13,7 @@ SOURCE_FILE@[0; 43)
13 WHITESPACE@[24; 25) 13 WHITESPACE@[24; 25)
14 CRATE_KW@[25; 30) 14 CRATE_KW@[25; 30)
15 WHITESPACE@[30; 31) 15 WHITESPACE@[30; 31)
16 NAME@[31; 34) 16 NAME_REF@[31; 34)
17 IDENT@[31; 34) "foo" 17 IDENT@[31; 34) "foo"
18 WHITESPACE@[34; 35) 18 WHITESPACE@[34; 35)
19 ALIAS@[35; 41) 19 ALIAS@[35; 41)