diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_assists/src/ast_editor.rs | 30 | ||||
-rw-r--r-- | crates/ra_assists/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_assists/src/move_bounds.rs | 135 | ||||
-rw-r--r-- | crates/ra_hir/src/marks.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres.rs | 3 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/collector.rs | 48 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/raw.rs | 13 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/tests/macros.rs | 64 | ||||
-rw-r--r-- | crates/ra_project_model/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/generated.rs | 1 | ||||
-rw-r--r-- | crates/ra_syntax/src/grammar.ron | 1 |
11 files changed, 287 insertions, 13 deletions
diff --git a/crates/ra_assists/src/ast_editor.rs b/crates/ra_assists/src/ast_editor.rs index 048478662..a710edce8 100644 --- a/crates/ra_assists/src/ast_editor.rs +++ b/crates/ra_assists/src/ast_editor.rs | |||
@@ -297,6 +297,11 @@ impl AstBuilder<ast::Path> { | |||
297 | ast_node_from_file_text(text) | 297 | ast_node_from_file_text(text) |
298 | } | 298 | } |
299 | 299 | ||
300 | pub fn from_name(name: ast::Name) -> ast::Path { | ||
301 | let name = name.syntax().to_string(); | ||
302 | Self::from_text(name.as_str()) | ||
303 | } | ||
304 | |||
300 | pub fn from_pieces(enum_name: ast::Name, var_name: ast::Name) -> ast::Path { | 305 | pub fn from_pieces(enum_name: ast::Name, var_name: ast::Name) -> ast::Path { |
301 | Self::from_text(&format!("{}::{}", enum_name.syntax(), var_name.syntax())) | 306 | Self::from_text(&format!("{}::{}", enum_name.syntax(), var_name.syntax())) |
302 | } | 307 | } |
@@ -380,6 +385,31 @@ impl AstBuilder<ast::MatchArmList> { | |||
380 | } | 385 | } |
381 | } | 386 | } |
382 | 387 | ||
388 | impl AstBuilder<ast::WherePred> { | ||
389 | fn from_text(text: &str) -> ast::WherePred { | ||
390 | ast_node_from_file_text(&format!("fn f() where {} {{ }}", text)) | ||
391 | } | ||
392 | |||
393 | pub fn from_pieces( | ||
394 | path: ast::Path, | ||
395 | bounds: impl Iterator<Item = ast::TypeBound>, | ||
396 | ) -> ast::WherePred { | ||
397 | let bounds = bounds.map(|b| b.syntax().to_string()).collect::<Vec<_>>().join(" + "); | ||
398 | Self::from_text(&format!("{}: {}", path.syntax(), bounds)) | ||
399 | } | ||
400 | } | ||
401 | |||
402 | impl AstBuilder<ast::WhereClause> { | ||
403 | fn from_text(text: &str) -> ast::WhereClause { | ||
404 | ast_node_from_file_text(&format!("fn f() where {} {{ }}", text)) | ||
405 | } | ||
406 | |||
407 | pub fn from_predicates(preds: impl Iterator<Item = ast::WherePred>) -> ast::WhereClause { | ||
408 | let preds = preds.map(|p| p.syntax().to_string()).collect::<Vec<_>>().join(", "); | ||
409 | Self::from_text(preds.as_str()) | ||
410 | } | ||
411 | } | ||
412 | |||
383 | fn ast_node_from_file_text<N: AstNode>(text: &str) -> N { | 413 | fn ast_node_from_file_text<N: AstNode>(text: &str) -> N { |
384 | let parse = SourceFile::parse(text); | 414 | let parse = SourceFile::parse(text); |
385 | let res = parse.tree().syntax().descendants().find_map(N::cast).unwrap(); | 415 | let res = parse.tree().syntax().descendants().find_map(N::cast).unwrap(); |
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index 03eec73ad..10ccc345c 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs | |||
@@ -102,6 +102,7 @@ mod remove_dbg; | |||
102 | pub mod auto_import; | 102 | pub mod auto_import; |
103 | mod add_missing_impl_members; | 103 | mod add_missing_impl_members; |
104 | mod move_guard; | 104 | mod move_guard; |
105 | mod move_bounds; | ||
105 | 106 | ||
106 | fn all_assists<DB: HirDatabase>() -> &'static [fn(AssistCtx<DB>) -> Option<Assist>] { | 107 | fn all_assists<DB: HirDatabase>() -> &'static [fn(AssistCtx<DB>) -> Option<Assist>] { |
107 | &[ | 108 | &[ |
@@ -123,6 +124,7 @@ fn all_assists<DB: HirDatabase>() -> &'static [fn(AssistCtx<DB>) -> Option<Assis | |||
123 | inline_local_variable::inline_local_varialbe, | 124 | inline_local_variable::inline_local_varialbe, |
124 | move_guard::move_guard_to_arm_body, | 125 | move_guard::move_guard_to_arm_body, |
125 | move_guard::move_arm_cond_to_match_guard, | 126 | move_guard::move_arm_cond_to_match_guard, |
127 | move_bounds::move_bounds_to_where_clause, | ||
126 | ] | 128 | ] |
127 | } | 129 | } |
128 | 130 | ||
diff --git a/crates/ra_assists/src/move_bounds.rs b/crates/ra_assists/src/move_bounds.rs new file mode 100644 index 000000000..526de1d98 --- /dev/null +++ b/crates/ra_assists/src/move_bounds.rs | |||
@@ -0,0 +1,135 @@ | |||
1 | use hir::db::HirDatabase; | ||
2 | use ra_syntax::{ | ||
3 | ast::{self, AstNode, NameOwner, TypeBoundsOwner}, | ||
4 | SyntaxElement, | ||
5 | SyntaxKind::*, | ||
6 | TextRange, | ||
7 | }; | ||
8 | |||
9 | use crate::{ast_editor::AstBuilder, Assist, AssistCtx, AssistId}; | ||
10 | |||
11 | pub(crate) fn move_bounds_to_where_clause(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | ||
12 | let type_param_list = ctx.node_at_offset::<ast::TypeParamList>()?; | ||
13 | |||
14 | let mut type_params = type_param_list.type_params(); | ||
15 | if type_params.all(|p| p.type_bound_list().is_none()) { | ||
16 | return None; | ||
17 | } | ||
18 | |||
19 | let parent = type_param_list.syntax().parent()?; | ||
20 | if parent.children_with_tokens().find(|it| it.kind() == WHERE_CLAUSE).is_some() { | ||
21 | return None; | ||
22 | } | ||
23 | |||
24 | let anchor: SyntaxElement = match parent.kind() { | ||
25 | FN_DEF => ast::FnDef::cast(parent)?.body()?.syntax().clone().into(), | ||
26 | TRAIT_DEF => ast::TraitDef::cast(parent)?.item_list()?.syntax().clone().into(), | ||
27 | IMPL_BLOCK => ast::ImplBlock::cast(parent)?.item_list()?.syntax().clone().into(), | ||
28 | ENUM_DEF => ast::EnumDef::cast(parent)?.variant_list()?.syntax().clone().into(), | ||
29 | STRUCT_DEF => parent | ||
30 | .children_with_tokens() | ||
31 | .find(|it| it.kind() == RECORD_FIELD_DEF_LIST || it.kind() == SEMI)?, | ||
32 | _ => return None, | ||
33 | }; | ||
34 | |||
35 | ctx.add_action( | ||
36 | AssistId("move_bounds_to_where_clause"), | ||
37 | "move_bounds_to_where_clause", | ||
38 | |edit| { | ||
39 | let type_params = type_param_list.type_params().collect::<Vec<_>>(); | ||
40 | |||
41 | for param in &type_params { | ||
42 | if let Some(bounds) = param.type_bound_list() { | ||
43 | let colon = param | ||
44 | .syntax() | ||
45 | .children_with_tokens() | ||
46 | .find(|it| it.kind() == COLON) | ||
47 | .unwrap(); | ||
48 | let start = colon.text_range().start(); | ||
49 | let end = bounds.syntax().text_range().end(); | ||
50 | edit.delete(TextRange::from_to(start, end)); | ||
51 | } | ||
52 | } | ||
53 | |||
54 | let predicates = type_params.iter().filter_map(build_predicate); | ||
55 | let where_clause = AstBuilder::<ast::WhereClause>::from_predicates(predicates); | ||
56 | |||
57 | let to_insert = match anchor.prev_sibling_or_token() { | ||
58 | Some(ref elem) if elem.kind() == WHITESPACE => { | ||
59 | format!("{} ", where_clause.syntax()) | ||
60 | } | ||
61 | _ => format!(" {}", where_clause.syntax()), | ||
62 | }; | ||
63 | edit.insert(anchor.text_range().start(), to_insert); | ||
64 | edit.target(type_param_list.syntax().text_range()); | ||
65 | }, | ||
66 | ); | ||
67 | |||
68 | ctx.build() | ||
69 | } | ||
70 | |||
71 | fn build_predicate(param: &ast::TypeParam) -> Option<ast::WherePred> { | ||
72 | let path = AstBuilder::<ast::Path>::from_name(param.name()?); | ||
73 | let predicate = | ||
74 | AstBuilder::<ast::WherePred>::from_pieces(path, param.type_bound_list()?.bounds()); | ||
75 | Some(predicate) | ||
76 | } | ||
77 | |||
78 | #[cfg(test)] | ||
79 | mod tests { | ||
80 | use super::*; | ||
81 | |||
82 | use crate::helpers::check_assist; | ||
83 | |||
84 | #[test] | ||
85 | fn move_bounds_to_where_clause_fn() { | ||
86 | check_assist( | ||
87 | move_bounds_to_where_clause, | ||
88 | r#" | ||
89 | fn foo<T: u32, <|>F: FnOnce(T) -> T>() {} | ||
90 | "#, | ||
91 | r#" | ||
92 | fn foo<T, <|>F>() where T: u32, F: FnOnce(T) -> T {} | ||
93 | "#, | ||
94 | ); | ||
95 | } | ||
96 | |||
97 | #[test] | ||
98 | fn move_bounds_to_where_clause_impl() { | ||
99 | check_assist( | ||
100 | move_bounds_to_where_clause, | ||
101 | r#" | ||
102 | impl<U: u32, <|>T> A<U, T> {} | ||
103 | "#, | ||
104 | r#" | ||
105 | impl<U, <|>T> A<U, T> where U: u32 {} | ||
106 | "#, | ||
107 | ); | ||
108 | } | ||
109 | |||
110 | #[test] | ||
111 | fn move_bounds_to_where_clause_struct() { | ||
112 | check_assist( | ||
113 | move_bounds_to_where_clause, | ||
114 | r#" | ||
115 | struct A<<|>T: Iterator<Item = u32>> {} | ||
116 | "#, | ||
117 | r#" | ||
118 | struct A<<|>T> where T: Iterator<Item = u32> {} | ||
119 | "#, | ||
120 | ); | ||
121 | } | ||
122 | |||
123 | #[test] | ||
124 | fn move_bounds_to_where_clause_tuple_struct() { | ||
125 | check_assist( | ||
126 | move_bounds_to_where_clause, | ||
127 | r#" | ||
128 | struct Pair<<|>T: u32>(T, T); | ||
129 | "#, | ||
130 | r#" | ||
131 | struct Pair<<|>T>(T, T) where T: u32; | ||
132 | "#, | ||
133 | ); | ||
134 | } | ||
135 | } | ||
diff --git a/crates/ra_hir/src/marks.rs b/crates/ra_hir/src/marks.rs index 5b15eee90..2e1d35c8c 100644 --- a/crates/ra_hir/src/marks.rs +++ b/crates/ra_hir/src/marks.rs | |||
@@ -11,4 +11,5 @@ test_utils::marks!( | |||
11 | match_ergonomics_ref | 11 | match_ergonomics_ref |
12 | trait_resolution_on_fn_type | 12 | trait_resolution_on_fn_type |
13 | infer_while_let | 13 | infer_while_let |
14 | macro_rules_from_other_crates_are_visible_with_macro_use | ||
14 | ); | 15 | ); |
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index bbdc606cd..f69179bf6 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs | |||
@@ -101,6 +101,8 @@ pub struct CrateDefMap { | |||
101 | /// However, do we want to put it as a global variable? | 101 | /// However, do we want to put it as a global variable? |
102 | poison_macros: FxHashSet<MacroDefId>, | 102 | poison_macros: FxHashSet<MacroDefId>, |
103 | 103 | ||
104 | exported_macros: FxHashMap<Name, MacroDefId>, | ||
105 | |||
104 | diagnostics: Vec<DefDiagnostic>, | 106 | diagnostics: Vec<DefDiagnostic>, |
105 | } | 107 | } |
106 | 108 | ||
@@ -245,6 +247,7 @@ impl CrateDefMap { | |||
245 | root, | 247 | root, |
246 | modules, | 248 | modules, |
247 | poison_macros: FxHashSet::default(), | 249 | poison_macros: FxHashSet::default(), |
250 | exported_macros: FxHashMap::default(), | ||
248 | diagnostics: Vec::new(), | 251 | diagnostics: Vec::new(), |
249 | } | 252 | } |
250 | }; | 253 | }; |
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index 7da2dcdff..5d1c42926 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs | |||
@@ -157,11 +157,42 @@ where | |||
157 | // crate root, even if the parent modules is **not** visible. | 157 | // crate root, even if the parent modules is **not** visible. |
158 | if export { | 158 | if export { |
159 | self.update(self.def_map.root, None, &[(name.clone(), def.clone())]); | 159 | self.update(self.def_map.root, None, &[(name.clone(), def.clone())]); |
160 | |||
161 | // Exported macros are collected in crate level ready for | ||
162 | // glob import with `#[macro_use]`. | ||
163 | self.def_map.exported_macros.insert(name.clone(), macro_id); | ||
160 | } | 164 | } |
161 | self.update(module_id, None, &[(name.clone(), def)]); | 165 | self.update(module_id, None, &[(name.clone(), def)]); |
162 | self.global_macro_scope.insert(name, macro_id); | 166 | self.global_macro_scope.insert(name, macro_id); |
163 | } | 167 | } |
164 | 168 | ||
169 | /// Import macros from `#[macro_use] extern crate`. | ||
170 | /// | ||
171 | /// They are non-scoped, and will only be inserted into mutable `global_macro_scope`. | ||
172 | fn import_macros_from_extern_crate(&mut self, import: &raw::ImportData) { | ||
173 | log::debug!( | ||
174 | "importing macros from extern crate: {:?} ({:?})", | ||
175 | import, | ||
176 | self.def_map.edition, | ||
177 | ); | ||
178 | |||
179 | let res = self.def_map.resolve_name_in_extern_prelude( | ||
180 | &import | ||
181 | .path | ||
182 | .as_ident() | ||
183 | .expect("extern crate should have been desugared to one-element path"), | ||
184 | ); | ||
185 | |||
186 | if let Some(ModuleDef::Module(m)) = res.take_types() { | ||
187 | tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use); | ||
188 | |||
189 | let item_map = self.db.crate_def_map(m.krate); | ||
190 | for (name, ¯o_id) in &item_map.exported_macros { | ||
191 | self.global_macro_scope.insert(name.clone(), macro_id); | ||
192 | } | ||
193 | } | ||
194 | } | ||
195 | |||
165 | fn resolve_imports(&mut self) -> ReachedFixedPoint { | 196 | fn resolve_imports(&mut self) -> ReachedFixedPoint { |
166 | let mut imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); | 197 | let mut imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); |
167 | let mut resolved = Vec::new(); | 198 | let mut resolved = Vec::new(); |
@@ -494,11 +525,17 @@ where | |||
494 | for item in items { | 525 | for item in items { |
495 | match *item { | 526 | match *item { |
496 | raw::RawItem::Module(m) => self.collect_module(&self.raw_items[m]), | 527 | raw::RawItem::Module(m) => self.collect_module(&self.raw_items[m]), |
497 | raw::RawItem::Import(import) => self.def_collector.unresolved_imports.push(( | 528 | raw::RawItem::Import(import_id) => { |
498 | self.module_id, | 529 | let import = self.raw_items[import_id].clone(); |
499 | import, | 530 | // This should be processed eagerly instead of deferred to resolving. |
500 | self.raw_items[import].clone(), | 531 | // Otherwise, since it will only mutate `global_macro_scope` |
501 | )), | 532 | // without `update` names in `mod`s, unresolved macros cannot be expanded. |
533 | if import.is_extern_crate && import.is_macro_use { | ||
534 | self.def_collector.import_macros_from_extern_crate(&import); | ||
535 | } | ||
536 | |||
537 | self.def_collector.unresolved_imports.push((self.module_id, import_id, import)); | ||
538 | } | ||
502 | raw::RawItem::Def(def) => self.define_def(&self.raw_items[def]), | 539 | raw::RawItem::Def(def) => self.define_def(&self.raw_items[def]), |
503 | raw::RawItem::Macro(mac) => self.collect_macro(&self.raw_items[mac]), | 540 | raw::RawItem::Macro(mac) => self.collect_macro(&self.raw_items[mac]), |
504 | } | 541 | } |
@@ -860,6 +897,7 @@ mod tests { | |||
860 | root, | 897 | root, |
861 | modules, | 898 | modules, |
862 | poison_macros: FxHashSet::default(), | 899 | poison_macros: FxHashSet::default(), |
900 | exported_macros: FxHashMap::default(), | ||
863 | diagnostics: Vec::new(), | 901 | diagnostics: Vec::new(), |
864 | } | 902 | } |
865 | }; | 903 | }; |
diff --git a/crates/ra_hir/src/nameres/raw.rs b/crates/ra_hir/src/nameres/raw.rs index 2f973359f..129b047eb 100644 --- a/crates/ra_hir/src/nameres/raw.rs +++ b/crates/ra_hir/src/nameres/raw.rs | |||
@@ -154,6 +154,7 @@ pub struct ImportData { | |||
154 | pub(super) is_glob: bool, | 154 | pub(super) is_glob: bool, |
155 | pub(super) is_prelude: bool, | 155 | pub(super) is_prelude: bool, |
156 | pub(super) is_extern_crate: bool, | 156 | pub(super) is_extern_crate: bool, |
157 | pub(super) is_macro_use: bool, | ||
157 | } | 158 | } |
158 | 159 | ||
159 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 160 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
@@ -293,8 +294,14 @@ impl RawItemsCollector { | |||
293 | let is_prelude = use_item.has_atom_attr("prelude_import"); | 294 | let is_prelude = use_item.has_atom_attr("prelude_import"); |
294 | 295 | ||
295 | Path::expand_use_item(&use_item, |path, use_tree, is_glob, alias| { | 296 | Path::expand_use_item(&use_item, |path, use_tree, is_glob, alias| { |
296 | let import_data = | 297 | let import_data = ImportData { |
297 | ImportData { path, alias, is_glob, is_prelude, is_extern_crate: false }; | 298 | path, |
299 | alias, | ||
300 | is_glob, | ||
301 | is_prelude, | ||
302 | is_extern_crate: false, | ||
303 | is_macro_use: false, | ||
304 | }; | ||
298 | self.push_import(current_module, import_data, Either::A(AstPtr::new(use_tree))); | 305 | self.push_import(current_module, import_data, Either::A(AstPtr::new(use_tree))); |
299 | }) | 306 | }) |
300 | } | 307 | } |
@@ -307,12 +314,14 @@ impl RawItemsCollector { | |||
307 | if let Some(name_ref) = extern_crate.name_ref() { | 314 | if let Some(name_ref) = extern_crate.name_ref() { |
308 | let path = Path::from_name_ref(&name_ref); | 315 | let path = Path::from_name_ref(&name_ref); |
309 | let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name()); | 316 | let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name()); |
317 | let is_macro_use = extern_crate.has_atom_attr("macro_use"); | ||
310 | let import_data = ImportData { | 318 | let import_data = ImportData { |
311 | path, | 319 | path, |
312 | alias, | 320 | alias, |
313 | is_glob: false, | 321 | is_glob: false, |
314 | is_prelude: false, | 322 | is_prelude: false, |
315 | is_extern_crate: true, | 323 | is_extern_crate: true, |
324 | is_macro_use, | ||
316 | }; | 325 | }; |
317 | self.push_import(current_module, import_data, Either::B(AstPtr::new(&extern_crate))); | 326 | self.push_import(current_module, import_data, Either::B(AstPtr::new(&extern_crate))); |
318 | } | 327 | } |
diff --git a/crates/ra_hir/src/nameres/tests/macros.rs b/crates/ra_hir/src/nameres/tests/macros.rs index 631df2cef..ebfefe273 100644 --- a/crates/ra_hir/src/nameres/tests/macros.rs +++ b/crates/ra_hir/src/nameres/tests/macros.rs | |||
@@ -99,14 +99,14 @@ fn macro_rules_from_other_crates_are_visible() { | |||
99 | fn unexpanded_macro_should_expand_by_fixedpoint_loop() { | 99 | fn unexpanded_macro_should_expand_by_fixedpoint_loop() { |
100 | let map = def_map_with_crate_graph( | 100 | let map = def_map_with_crate_graph( |
101 | " | 101 | " |
102 | //- /main.rs | 102 | //- /main.rs |
103 | macro_rules! baz { | 103 | macro_rules! baz { |
104 | () => { | 104 | () => { |
105 | use foo::bar; | 105 | use foo::bar; |
106 | } | 106 | } |
107 | } | 107 | } |
108 | 108 | ||
109 | foo!(); | 109 | foo!(); |
110 | bar!(); | 110 | bar!(); |
111 | baz!(); | 111 | baz!(); |
112 | 112 | ||
@@ -114,7 +114,7 @@ fn unexpanded_macro_should_expand_by_fixedpoint_loop() { | |||
114 | #[macro_export] | 114 | #[macro_export] |
115 | macro_rules! foo { | 115 | macro_rules! foo { |
116 | () => { | 116 | () => { |
117 | struct Foo { field: u32 } | 117 | struct Foo { field: u32 } |
118 | } | 118 | } |
119 | } | 119 | } |
120 | #[macro_export] | 120 | #[macro_export] |
@@ -137,3 +137,57 @@ fn unexpanded_macro_should_expand_by_fixedpoint_loop() { | |||
137 | ⋮foo: m | 137 | ⋮foo: m |
138 | "###); | 138 | "###); |
139 | } | 139 | } |
140 | |||
141 | #[test] | ||
142 | fn macro_rules_from_other_crates_are_visible_with_macro_use() { | ||
143 | covers!(macro_rules_from_other_crates_are_visible_with_macro_use); | ||
144 | let map = def_map_with_crate_graph( | ||
145 | " | ||
146 | //- /main.rs | ||
147 | #[macro_use] | ||
148 | extern crate foo; | ||
149 | |||
150 | structs!(Foo); | ||
151 | structs_priv!(Bar); | ||
152 | structs_not_exported!(MacroNotResolved1); | ||
153 | crate::structs!(MacroNotResolved2); | ||
154 | |||
155 | mod bar; | ||
156 | |||
157 | //- /bar.rs | ||
158 | structs!(Baz); | ||
159 | crate::structs!(MacroNotResolved3); | ||
160 | |||
161 | //- /lib.rs | ||
162 | #[macro_export] | ||
163 | macro_rules! structs { | ||
164 | ($i:ident) => { struct $i; } | ||
165 | } | ||
166 | |||
167 | macro_rules! structs_not_exported { | ||
168 | ($i:ident) => { struct $i; } | ||
169 | } | ||
170 | |||
171 | mod priv_mod { | ||
172 | #[macro_export] | ||
173 | macro_rules! structs_priv { | ||
174 | ($i:ident) => { struct $i; } | ||
175 | } | ||
176 | } | ||
177 | ", | ||
178 | crate_graph! { | ||
179 | "main": ("/main.rs", ["foo"]), | ||
180 | "foo": ("/lib.rs", []), | ||
181 | }, | ||
182 | ); | ||
183 | assert_snapshot!(map, @r###" | ||
184 | ⋮crate | ||
185 | ⋮Bar: t v | ||
186 | ⋮Foo: t v | ||
187 | ⋮bar: t | ||
188 | ⋮foo: t | ||
189 | ⋮ | ||
190 | ⋮crate::bar | ||
191 | ⋮Baz: t v | ||
192 | "###); | ||
193 | } | ||
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index 676dc4941..9b2f534e7 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs | |||
@@ -153,7 +153,7 @@ impl ProjectWorkspace { | |||
153 | if let Some(file_id) = load(krate.root(&sysroot)) { | 153 | if let Some(file_id) = load(krate.root(&sysroot)) { |
154 | sysroot_crates.insert( | 154 | sysroot_crates.insert( |
155 | krate, | 155 | krate, |
156 | crate_graph.add_crate_root(file_id, Edition::Edition2015), | 156 | crate_graph.add_crate_root(file_id, Edition::Edition2018), |
157 | ); | 157 | ); |
158 | } | 158 | } |
159 | } | 159 | } |
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index e2a92ae60..bcf753f78 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs | |||
@@ -934,6 +934,7 @@ impl AstNode for ExternCrateItem { | |||
934 | &self.syntax | 934 | &self.syntax |
935 | } | 935 | } |
936 | } | 936 | } |
937 | impl ast::AttrsOwner for ExternCrateItem {} | ||
937 | impl ExternCrateItem { | 938 | impl ExternCrateItem { |
938 | pub fn name_ref(&self) -> Option<NameRef> { | 939 | pub fn name_ref(&self) -> Option<NameRef> { |
939 | AstChildren::new(&self.syntax).next() | 940 | AstChildren::new(&self.syntax).next() |
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index c14ee0e85..3e6c2d3f3 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron | |||
@@ -669,6 +669,7 @@ Grammar( | |||
669 | collections: [("use_trees", "UseTree")] | 669 | collections: [("use_trees", "UseTree")] |
670 | ), | 670 | ), |
671 | "ExternCrateItem": ( | 671 | "ExternCrateItem": ( |
672 | traits: ["AttrsOwner"], | ||
672 | options: ["NameRef", "Alias"], | 673 | options: ["NameRef", "Alias"], |
673 | ), | 674 | ), |
674 | "ArgList": ( | 675 | "ArgList": ( |