diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_hir/src/code_model/attrs.rs | 25 | ||||
-rw-r--r-- | crates/ra_hir/src/db.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir_def/src/attr.rs | 36 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/collector.rs | 20 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/raw.rs | 18 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/builtin_macro.rs | 27 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/name.rs | 1 | ||||
-rw-r--r-- | crates/ra_ide_api/src/completion/presentation.rs | 9 | ||||
-rw-r--r-- | crates/ra_ide_api/src/expand_macro.rs | 34 |
10 files changed, 123 insertions, 53 deletions
diff --git a/crates/ra_hir/src/code_model/attrs.rs b/crates/ra_hir/src/code_model/attrs.rs index 9e304217c..96da8c88c 100644 --- a/crates/ra_hir/src/code_model/attrs.rs +++ b/crates/ra_hir/src/code_model/attrs.rs | |||
@@ -5,10 +5,9 @@ use crate::{ | |||
5 | Adt, Const, Enum, EnumVariant, FieldSource, Function, HasSource, MacroDef, Module, Static, | 5 | Adt, Const, Enum, EnumVariant, FieldSource, Function, HasSource, MacroDef, Module, Static, |
6 | Struct, StructField, Trait, TypeAlias, Union, | 6 | Struct, StructField, Trait, TypeAlias, Union, |
7 | }; | 7 | }; |
8 | use hir_def::attr::Attr; | 8 | use hir_def::attr::{Attr, Attrs}; |
9 | use hir_expand::hygiene::Hygiene; | 9 | use hir_expand::hygiene::Hygiene; |
10 | use ra_syntax::ast; | 10 | use ra_syntax::ast; |
11 | use std::sync::Arc; | ||
12 | 11 | ||
13 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | 12 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] |
14 | pub enum AttrDef { | 13 | pub enum AttrDef { |
@@ -37,17 +36,17 @@ impl_froms!( | |||
37 | MacroDef | 36 | MacroDef |
38 | ); | 37 | ); |
39 | 38 | ||
40 | pub trait Attrs { | 39 | pub trait HasAttrs { |
41 | fn attrs(&self, db: &impl HirDatabase) -> Option<Arc<[Attr]>>; | 40 | fn attrs(&self, db: &impl HirDatabase) -> Attrs; |
42 | } | 41 | } |
43 | 42 | ||
44 | pub(crate) fn attributes_query( | 43 | pub(crate) fn attributes_query(db: &(impl DefDatabase + AstDatabase), def: AttrDef) -> Attrs { |
45 | db: &(impl DefDatabase + AstDatabase), | ||
46 | def: AttrDef, | ||
47 | ) -> Option<Arc<[Attr]>> { | ||
48 | match def { | 44 | match def { |
49 | AttrDef::Module(it) => { | 45 | AttrDef::Module(it) => { |
50 | let src = it.declaration_source(db)?; | 46 | let src = match it.declaration_source(db) { |
47 | Some(it) => it, | ||
48 | None => return Attrs::default(), | ||
49 | }; | ||
51 | let hygiene = Hygiene::new(db, src.file_id); | 50 | let hygiene = Hygiene::new(db, src.file_id); |
52 | Attr::from_attrs_owner(&src.value, &hygiene) | 51 | Attr::from_attrs_owner(&src.value, &hygiene) |
53 | } | 52 | } |
@@ -57,7 +56,7 @@ pub(crate) fn attributes_query( | |||
57 | let hygiene = Hygiene::new(db, src.file_id); | 56 | let hygiene = Hygiene::new(db, src.file_id); |
58 | Attr::from_attrs_owner(&named, &hygiene) | 57 | Attr::from_attrs_owner(&named, &hygiene) |
59 | } | 58 | } |
60 | FieldSource::Pos(..) => None, | 59 | FieldSource::Pos(..) => Attrs::default(), |
61 | }, | 60 | }, |
62 | AttrDef::Adt(it) => match it { | 61 | AttrDef::Adt(it) => match it { |
63 | Adt::Struct(it) => attrs_from_ast(it, db), | 62 | Adt::Struct(it) => attrs_from_ast(it, db), |
@@ -74,7 +73,7 @@ pub(crate) fn attributes_query( | |||
74 | } | 73 | } |
75 | } | 74 | } |
76 | 75 | ||
77 | fn attrs_from_ast<T, D>(node: T, db: &D) -> Option<Arc<[Attr]>> | 76 | fn attrs_from_ast<T, D>(node: T, db: &D) -> Attrs |
78 | where | 77 | where |
79 | T: HasSource, | 78 | T: HasSource, |
80 | T::Ast: ast::AttrsOwner, | 79 | T::Ast: ast::AttrsOwner, |
@@ -85,8 +84,8 @@ where | |||
85 | Attr::from_attrs_owner(&src.value, &hygiene) | 84 | Attr::from_attrs_owner(&src.value, &hygiene) |
86 | } | 85 | } |
87 | 86 | ||
88 | impl<T: Into<AttrDef> + Copy> Attrs for T { | 87 | impl<T: Into<AttrDef> + Copy> HasAttrs for T { |
89 | fn attrs(&self, db: &impl HirDatabase) -> Option<Arc<[Attr]>> { | 88 | fn attrs(&self, db: &impl HirDatabase) -> Attrs { |
90 | db.attrs((*self).into()) | 89 | db.attrs((*self).into()) |
91 | } | 90 | } |
92 | } | 91 | } |
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index 689874331..1cfcb2fd2 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | use std::sync::Arc; | 3 | use std::sync::Arc; |
4 | 4 | ||
5 | use hir_def::attr::Attr; | 5 | use hir_def::attr::Attrs; |
6 | use ra_db::salsa; | 6 | use ra_db::salsa; |
7 | use ra_syntax::SmolStr; | 7 | use ra_syntax::SmolStr; |
8 | 8 | ||
@@ -57,7 +57,7 @@ pub trait DefDatabase: HirDebugDatabase + DefDatabase2 { | |||
57 | fn documentation(&self, def: crate::DocDef) -> Option<crate::Documentation>; | 57 | fn documentation(&self, def: crate::DocDef) -> Option<crate::Documentation>; |
58 | 58 | ||
59 | #[salsa::invoke(crate::code_model::attrs::attributes_query)] | 59 | #[salsa::invoke(crate::code_model::attrs::attributes_query)] |
60 | fn attrs(&self, def: crate::AttrDef) -> Option<Arc<[Attr]>>; | 60 | fn attrs(&self, def: crate::AttrDef) -> Attrs; |
61 | } | 61 | } |
62 | 62 | ||
63 | #[salsa::query_group(HirDatabaseStorage)] | 63 | #[salsa::query_group(HirDatabaseStorage)] |
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 8e532c36c..8535629ca 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -51,7 +51,7 @@ mod marks; | |||
51 | 51 | ||
52 | pub use crate::{ | 52 | pub use crate::{ |
53 | code_model::{ | 53 | code_model::{ |
54 | attrs::{AttrDef, Attrs}, | 54 | attrs::{AttrDef, HasAttrs}, |
55 | docs::{DocDef, Docs, Documentation}, | 55 | docs::{DocDef, Docs, Documentation}, |
56 | src::{HasBodySource, HasSource}, | 56 | src::{HasBodySource, HasSource}, |
57 | Adt, AssocItem, Const, ConstData, Container, Crate, CrateDependency, DefWithBody, Enum, | 57 | Adt, AssocItem, Const, ConstData, Container, Crate, CrateDependency, DefWithBody, Enum, |
diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs index 0e961ca12..7a9d0fdf4 100644 --- a/crates/ra_hir_def/src/attr.rs +++ b/crates/ra_hir_def/src/attr.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | //! A higher level attributes based on TokenTree, with also some shortcuts. | 1 | //! A higher level attributes based on TokenTree, with also some shortcuts. |
2 | 2 | ||
3 | use std::sync::Arc; | 3 | use std::{ops, sync::Arc}; |
4 | 4 | ||
5 | use hir_expand::hygiene::Hygiene; | 5 | use hir_expand::hygiene::Hygiene; |
6 | use mbe::ast_to_token_tree; | 6 | use mbe::ast_to_token_tree; |
@@ -13,6 +13,28 @@ use tt::Subtree; | |||
13 | 13 | ||
14 | use crate::path::Path; | 14 | use crate::path::Path; |
15 | 15 | ||
16 | #[derive(Default, Debug, Clone, PartialEq, Eq)] | ||
17 | pub struct Attrs { | ||
18 | entries: Option<Arc<[Attr]>>, | ||
19 | } | ||
20 | |||
21 | impl ops::Deref for Attrs { | ||
22 | type Target = [Attr]; | ||
23 | |||
24 | fn deref(&self) -> &[Attr] { | ||
25 | match &self.entries { | ||
26 | Some(it) => &*it, | ||
27 | None => &[], | ||
28 | } | ||
29 | } | ||
30 | } | ||
31 | |||
32 | impl Attrs { | ||
33 | pub fn has_atom(&self, atom: &str) -> bool { | ||
34 | self.iter().any(|it| it.is_simple_atom(atom)) | ||
35 | } | ||
36 | } | ||
37 | |||
16 | #[derive(Debug, Clone, PartialEq, Eq)] | 38 | #[derive(Debug, Clone, PartialEq, Eq)] |
17 | pub struct Attr { | 39 | pub struct Attr { |
18 | pub(crate) path: Path, | 40 | pub(crate) path: Path, |
@@ -43,13 +65,15 @@ impl Attr { | |||
43 | Some(Attr { path, input }) | 65 | Some(Attr { path, input }) |
44 | } | 66 | } |
45 | 67 | ||
46 | pub fn from_attrs_owner(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Option<Arc<[Attr]>> { | 68 | pub fn from_attrs_owner(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Attrs { |
47 | let mut attrs = owner.attrs().peekable(); | 69 | let mut attrs = owner.attrs().peekable(); |
48 | if attrs.peek().is_none() { | 70 | let entries = if attrs.peek().is_none() { |
49 | // Avoid heap allocation | 71 | // Avoid heap allocation |
50 | return None; | 72 | None |
51 | } | 73 | } else { |
52 | Some(attrs.flat_map(|ast| Attr::from_src(ast, hygiene)).collect()) | 74 | Some(attrs.flat_map(|ast| Attr::from_src(ast, hygiene)).collect()) |
75 | }; | ||
76 | Attrs { entries } | ||
53 | } | 77 | } |
54 | 78 | ||
55 | pub fn is_simple_atom(&self, name: &str) -> bool { | 79 | pub fn is_simple_atom(&self, name: &str) -> bool { |
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index aae3dcadf..7902293e8 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs | |||
@@ -12,7 +12,7 @@ use rustc_hash::FxHashMap; | |||
12 | use test_utils::tested_by; | 12 | use test_utils::tested_by; |
13 | 13 | ||
14 | use crate::{ | 14 | use crate::{ |
15 | attr::Attr, | 15 | attr::Attrs, |
16 | db::DefDatabase2, | 16 | db::DefDatabase2, |
17 | nameres::{ | 17 | nameres::{ |
18 | diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint, | 18 | diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint, |
@@ -549,7 +549,7 @@ where | |||
549 | // `#[macro_use] extern crate` is hoisted to imports macros before collecting | 549 | // `#[macro_use] extern crate` is hoisted to imports macros before collecting |
550 | // any other items. | 550 | // any other items. |
551 | for item in items { | 551 | for item in items { |
552 | if self.is_cfg_enabled(item.attrs()) { | 552 | if self.is_cfg_enabled(&item.attrs) { |
553 | if let raw::RawItemKind::Import(import_id) = item.kind { | 553 | if let raw::RawItemKind::Import(import_id) = item.kind { |
554 | let import = self.raw_items[import_id].clone(); | 554 | let import = self.raw_items[import_id].clone(); |
555 | if import.is_extern_crate && import.is_macro_use { | 555 | if import.is_extern_crate && import.is_macro_use { |
@@ -560,10 +560,10 @@ where | |||
560 | } | 560 | } |
561 | 561 | ||
562 | for item in items { | 562 | for item in items { |
563 | if self.is_cfg_enabled(item.attrs()) { | 563 | if self.is_cfg_enabled(&item.attrs) { |
564 | match item.kind { | 564 | match item.kind { |
565 | raw::RawItemKind::Module(m) => { | 565 | raw::RawItemKind::Module(m) => { |
566 | self.collect_module(&self.raw_items[m], item.attrs()) | 566 | self.collect_module(&self.raw_items[m], &item.attrs) |
567 | } | 567 | } |
568 | raw::RawItemKind::Import(import_id) => self | 568 | raw::RawItemKind::Import(import_id) => self |
569 | .def_collector | 569 | .def_collector |
@@ -585,9 +585,9 @@ where | |||
585 | } | 585 | } |
586 | } | 586 | } |
587 | 587 | ||
588 | fn collect_module(&mut self, module: &raw::ModuleData, attrs: &[Attr]) { | 588 | fn collect_module(&mut self, module: &raw::ModuleData, attrs: &Attrs) { |
589 | let path_attr = self.path_attr(attrs); | 589 | let path_attr = self.path_attr(attrs); |
590 | let is_macro_use = self.is_macro_use(attrs); | 590 | let is_macro_use = attrs.has_atom("macro_use"); |
591 | match module { | 591 | match module { |
592 | // inline module, just recurse | 592 | // inline module, just recurse |
593 | raw::ModuleData::Definition { name, items, ast_id } => { | 593 | raw::ModuleData::Definition { name, items, ast_id } => { |
@@ -779,17 +779,13 @@ where | |||
779 | } | 779 | } |
780 | } | 780 | } |
781 | 781 | ||
782 | fn is_cfg_enabled(&self, attrs: &[Attr]) -> bool { | 782 | fn is_cfg_enabled(&self, attrs: &Attrs) -> bool { |
783 | attrs.iter().all(|attr| attr.is_cfg_enabled(&self.def_collector.cfg_options) != Some(false)) | 783 | attrs.iter().all(|attr| attr.is_cfg_enabled(&self.def_collector.cfg_options) != Some(false)) |
784 | } | 784 | } |
785 | 785 | ||
786 | fn path_attr<'a>(&self, attrs: &'a [Attr]) -> Option<&'a SmolStr> { | 786 | fn path_attr<'a>(&self, attrs: &'a Attrs) -> Option<&'a SmolStr> { |
787 | attrs.iter().find_map(|attr| attr.as_path()) | 787 | attrs.iter().find_map(|attr| attr.as_path()) |
788 | } | 788 | } |
789 | |||
790 | fn is_macro_use<'a>(&self, attrs: &'a [Attr]) -> bool { | ||
791 | attrs.iter().any(|attr| attr.is_simple_atom("macro_use")) | ||
792 | } | ||
793 | } | 789 | } |
794 | 790 | ||
795 | fn is_macro_rules(path: &Path) -> bool { | 791 | fn is_macro_rules(path: &Path) -> bool { |
diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs index 7c68fd638..55a9634f8 100644 --- a/crates/ra_hir_def/src/nameres/raw.rs +++ b/crates/ra_hir_def/src/nameres/raw.rs | |||
@@ -16,7 +16,12 @@ use ra_syntax::{ | |||
16 | }; | 16 | }; |
17 | use test_utils::tested_by; | 17 | use test_utils::tested_by; |
18 | 18 | ||
19 | use crate::{attr::Attr, db::DefDatabase2, path::Path, FileAstId, HirFileId, ModuleSource, Source}; | 19 | use crate::{ |
20 | attr::{Attr, Attrs}, | ||
21 | db::DefDatabase2, | ||
22 | path::Path, | ||
23 | FileAstId, HirFileId, ModuleSource, Source, | ||
24 | }; | ||
20 | 25 | ||
21 | /// `RawItems` is a set of top-level items in a file (except for impls). | 26 | /// `RawItems` is a set of top-level items in a file (except for impls). |
22 | /// | 27 | /// |
@@ -129,21 +134,12 @@ impl Index<Impl> for RawItems { | |||
129 | } | 134 | } |
130 | } | 135 | } |
131 | 136 | ||
132 | // Avoid heap allocation on items without attributes. | ||
133 | type Attrs = Option<Arc<[Attr]>>; | ||
134 | |||
135 | #[derive(Debug, PartialEq, Eq, Clone)] | 137 | #[derive(Debug, PartialEq, Eq, Clone)] |
136 | pub(super) struct RawItem { | 138 | pub(super) struct RawItem { |
137 | attrs: Attrs, | 139 | pub(super) attrs: Attrs, |
138 | pub(super) kind: RawItemKind, | 140 | pub(super) kind: RawItemKind, |
139 | } | 141 | } |
140 | 142 | ||
141 | impl RawItem { | ||
142 | pub(super) fn attrs(&self) -> &[Attr] { | ||
143 | self.attrs.as_ref().map_or(&[], |it| &*it) | ||
144 | } | ||
145 | } | ||
146 | |||
147 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | 143 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] |
148 | pub(super) enum RawItemKind { | 144 | pub(super) enum RawItemKind { |
149 | Module(Module), | 145 | Module(Module), |
diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs index 97fb0cb55..9628666d4 100644 --- a/crates/ra_hir_expand/src/builtin_macro.rs +++ b/crates/ra_hir_expand/src/builtin_macro.rs | |||
@@ -11,6 +11,7 @@ use crate::quote; | |||
11 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 11 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
12 | pub enum BuiltinExpander { | 12 | pub enum BuiltinExpander { |
13 | Line, | 13 | Line, |
14 | Stringify, | ||
14 | } | 15 | } |
15 | 16 | ||
16 | impl BuiltinExpander { | 17 | impl BuiltinExpander { |
@@ -22,6 +23,7 @@ impl BuiltinExpander { | |||
22 | ) -> Result<tt::Subtree, mbe::ExpandError> { | 23 | ) -> Result<tt::Subtree, mbe::ExpandError> { |
23 | match self { | 24 | match self { |
24 | BuiltinExpander::Line => line_expand(db, id, tt), | 25 | BuiltinExpander::Line => line_expand(db, id, tt), |
26 | BuiltinExpander::Stringify => stringify_expand(db, id, tt), | ||
25 | } | 27 | } |
26 | } | 28 | } |
27 | } | 29 | } |
@@ -34,6 +36,8 @@ pub fn find_builtin_macro( | |||
34 | // FIXME: Better registering method | 36 | // FIXME: Better registering method |
35 | if ident == &name::LINE_MACRO { | 37 | if ident == &name::LINE_MACRO { |
36 | Some(MacroDefId { krate, ast_id, kind: MacroDefKind::BuiltIn(BuiltinExpander::Line) }) | 38 | Some(MacroDefId { krate, ast_id, kind: MacroDefKind::BuiltIn(BuiltinExpander::Line) }) |
39 | } else if ident == &name::STRINGIFY_MACRO { | ||
40 | Some(MacroDefId { krate, ast_id, kind: MacroDefKind::BuiltIn(BuiltinExpander::Stringify) }) | ||
37 | } else { | 41 | } else { |
38 | None | 42 | None |
39 | } | 43 | } |
@@ -78,3 +82,26 @@ fn line_expand( | |||
78 | 82 | ||
79 | Ok(expanded) | 83 | Ok(expanded) |
80 | } | 84 | } |
85 | |||
86 | fn stringify_expand( | ||
87 | db: &dyn AstDatabase, | ||
88 | id: MacroCallId, | ||
89 | _tt: &tt::Subtree, | ||
90 | ) -> Result<tt::Subtree, mbe::ExpandError> { | ||
91 | let loc = db.lookup_intern_macro(id); | ||
92 | let macro_call = loc.ast_id.to_node(db); | ||
93 | |||
94 | let macro_content = { | ||
95 | let arg = macro_call.token_tree().ok_or_else(|| mbe::ExpandError::UnexpectedToken)?; | ||
96 | let macro_args = arg.syntax().clone(); | ||
97 | let text = macro_args.text(); | ||
98 | let without_parens = TextUnit::of_char('(')..text.len() - TextUnit::of_char(')'); | ||
99 | text.slice(without_parens).to_string() | ||
100 | }; | ||
101 | |||
102 | let expanded = quote! { | ||
103 | #macro_content | ||
104 | }; | ||
105 | |||
106 | Ok(expanded) | ||
107 | } | ||
diff --git a/crates/ra_hir_expand/src/name.rs b/crates/ra_hir_expand/src/name.rs index 1bf17d12b..c3f7e77a5 100644 --- a/crates/ra_hir_expand/src/name.rs +++ b/crates/ra_hir_expand/src/name.rs | |||
@@ -143,3 +143,4 @@ pub const BOX_TYPE: Name = Name::new_inline_ascii(3, b"Box"); | |||
143 | 143 | ||
144 | // Builtin Macros | 144 | // Builtin Macros |
145 | pub const LINE_MACRO: Name = Name::new_inline_ascii(4, b"line"); | 145 | pub const LINE_MACRO: Name = Name::new_inline_ascii(4, b"line"); |
146 | pub const STRINGIFY_MACRO: Name = Name::new_inline_ascii(9, b"stringify"); | ||
diff --git a/crates/ra_ide_api/src/completion/presentation.rs b/crates/ra_ide_api/src/completion/presentation.rs index b20329459..bd464d193 100644 --- a/crates/ra_ide_api/src/completion/presentation.rs +++ b/crates/ra_ide_api/src/completion/presentation.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | //! This modules takes care of rendering various definitions as completion items. | 1 | //! This modules takes care of rendering various definitions as completion items. |
2 | 2 | ||
3 | use hir::{db::HirDatabase, Attrs, Docs, HasSource, HirDisplay, ScopeDef, Ty, TypeWalk}; | 3 | use hir::{db::HirDatabase, Docs, HasAttrs, HasSource, HirDisplay, ScopeDef, Ty, TypeWalk}; |
4 | use join_to_string::join; | 4 | use join_to_string::join; |
5 | use ra_syntax::ast::NameOwner; | 5 | use ra_syntax::ast::NameOwner; |
6 | use test_utils::tested_by; | 6 | use test_utils::tested_by; |
@@ -285,11 +285,8 @@ impl Completions { | |||
285 | } | 285 | } |
286 | } | 286 | } |
287 | 287 | ||
288 | fn is_deprecated(node: impl Attrs, db: &impl HirDatabase) -> bool { | 288 | fn is_deprecated(node: impl HasAttrs, db: &impl HirDatabase) -> bool { |
289 | match node.attrs(db) { | 289 | node.attrs(db).has_atom("deprecated") |
290 | None => false, | ||
291 | Some(attrs) => attrs.iter().any(|x| x.is_simple_atom("deprecated")), | ||
292 | } | ||
293 | } | 290 | } |
294 | 291 | ||
295 | fn has_non_default_type_params(def: hir::GenericDef, db: &db::RootDatabase) -> bool { | 292 | fn has_non_default_type_params(def: hir::GenericDef, db: &db::RootDatabase) -> bool { |
diff --git a/crates/ra_ide_api/src/expand_macro.rs b/crates/ra_ide_api/src/expand_macro.rs index 7dbf33a16..673301b10 100644 --- a/crates/ra_ide_api/src/expand_macro.rs +++ b/crates/ra_ide_api/src/expand_macro.rs | |||
@@ -40,7 +40,7 @@ fn expand_macro_recur( | |||
40 | let analyzer = hir::SourceAnalyzer::new(db, source, None); | 40 | let analyzer = hir::SourceAnalyzer::new(db, source, None); |
41 | let expansion = analyzer.expand(db, macro_call)?; | 41 | let expansion = analyzer.expand(db, macro_call)?; |
42 | let macro_file_id = expansion.file_id(); | 42 | let macro_file_id = expansion.file_id(); |
43 | let expanded: SyntaxNode = db.parse_or_expand(macro_file_id)?; | 43 | let mut expanded: SyntaxNode = db.parse_or_expand(macro_file_id)?; |
44 | 44 | ||
45 | let children = expanded.descendants().filter_map(ast::MacroCall::cast); | 45 | let children = expanded.descendants().filter_map(ast::MacroCall::cast); |
46 | let mut replaces = FxHashMap::default(); | 46 | let mut replaces = FxHashMap::default(); |
@@ -49,7 +49,14 @@ fn expand_macro_recur( | |||
49 | let node = hir::Source::new(macro_file_id, &child); | 49 | let node = hir::Source::new(macro_file_id, &child); |
50 | let new_node = expand_macro_recur(db, source, node)?; | 50 | let new_node = expand_macro_recur(db, source, node)?; |
51 | 51 | ||
52 | replaces.insert(child.syntax().clone().into(), new_node.into()); | 52 | // Replace the whole node if it is root |
53 | // `replace_descendants` will not replace the parent node | ||
54 | // but `SyntaxNode::descendants include itself | ||
55 | if expanded == *child.syntax() { | ||
56 | expanded = new_node; | ||
57 | } else { | ||
58 | replaces.insert(child.syntax().clone().into(), new_node.into()); | ||
59 | } | ||
53 | } | 60 | } |
54 | 61 | ||
55 | Some(replace_descendants(&expanded, &replaces)) | 62 | Some(replace_descendants(&expanded, &replaces)) |
@@ -217,4 +224,27 @@ fn some_thing() -> u32 { | |||
217 | } | 224 | } |
218 | "###); | 225 | "###); |
219 | } | 226 | } |
227 | |||
228 | #[test] | ||
229 | fn macro_expand_match_ast_inside_let_statement() { | ||
230 | let res = check_expand_macro( | ||
231 | r#" | ||
232 | //- /lib.rs | ||
233 | macro_rules! match_ast { | ||
234 | (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) }; | ||
235 | (match ($node:expr) {}) => {{}}; | ||
236 | } | ||
237 | |||
238 | fn main() { | ||
239 | let p = f(|it| { | ||
240 | let res = mat<|>ch_ast! { match c {}}; | ||
241 | Some(res) | ||
242 | })?; | ||
243 | } | ||
244 | "#, | ||
245 | ); | ||
246 | |||
247 | assert_eq!(res.name, "match_ast"); | ||
248 | assert_snapshot!(res.expansion, @r###"{}"###); | ||
249 | } | ||
220 | } | 250 | } |