diff options
Diffstat (limited to 'crates/hir_expand/src/input.rs')
-rw-r--r-- | crates/hir_expand/src/input.rs | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/crates/hir_expand/src/input.rs b/crates/hir_expand/src/input.rs new file mode 100644 index 000000000..d1f22aba4 --- /dev/null +++ b/crates/hir_expand/src/input.rs | |||
@@ -0,0 +1,95 @@ | |||
1 | //! Macro input conditioning. | ||
2 | |||
3 | use syntax::{ | ||
4 | ast::{self, AttrsOwner}, | ||
5 | AstNode, SyntaxNode, | ||
6 | }; | ||
7 | |||
8 | use crate::{ | ||
9 | db::AstDatabase, | ||
10 | name::{name, AsName}, | ||
11 | AttrId, LazyMacroId, MacroCallKind, MacroCallLoc, | ||
12 | }; | ||
13 | |||
14 | pub(crate) fn process_macro_input( | ||
15 | db: &dyn AstDatabase, | ||
16 | node: SyntaxNode, | ||
17 | id: LazyMacroId, | ||
18 | ) -> SyntaxNode { | ||
19 | let loc: MacroCallLoc = db.lookup_intern_macro(id); | ||
20 | |||
21 | match loc.kind { | ||
22 | MacroCallKind::FnLike { .. } => node, | ||
23 | MacroCallKind::Derive { derive_attr, .. } => { | ||
24 | let item = match ast::Item::cast(node.clone()) { | ||
25 | Some(item) => item, | ||
26 | None => return node, | ||
27 | }; | ||
28 | |||
29 | remove_derives_up_to(item, derive_attr).syntax().clone() | ||
30 | } | ||
31 | } | ||
32 | } | ||
33 | |||
34 | /// Removes `#[derive]` attributes from `item`, up to `attr`. | ||
35 | fn remove_derives_up_to(item: ast::Item, attr: AttrId) -> ast::Item { | ||
36 | let item = item.clone_for_update(); | ||
37 | let idx = attr.0 as usize; | ||
38 | for attr in item.attrs().take(idx + 1) { | ||
39 | if let Some(name) = | ||
40 | attr.path().and_then(|path| path.as_single_segment()).and_then(|seg| seg.name_ref()) | ||
41 | { | ||
42 | if name.as_name() == name![derive] { | ||
43 | attr.syntax().detach(); | ||
44 | } | ||
45 | } | ||
46 | } | ||
47 | item | ||
48 | } | ||
49 | |||
50 | #[cfg(test)] | ||
51 | mod tests { | ||
52 | use base_db::fixture::WithFixture; | ||
53 | use base_db::SourceDatabase; | ||
54 | use expect_test::{expect, Expect}; | ||
55 | |||
56 | use crate::test_db::TestDB; | ||
57 | |||
58 | use super::*; | ||
59 | |||
60 | fn test_remove_derives_up_to(attr: AttrId, ra_fixture: &str, expect: Expect) { | ||
61 | let (db, file_id) = TestDB::with_single_file(&ra_fixture); | ||
62 | let parsed = db.parse(file_id); | ||
63 | |||
64 | let mut items: Vec<_> = | ||
65 | parsed.syntax_node().descendants().filter_map(ast::Item::cast).collect(); | ||
66 | assert_eq!(items.len(), 1); | ||
67 | |||
68 | let item = remove_derives_up_to(items.pop().unwrap(), attr); | ||
69 | expect.assert_eq(&item.to_string()); | ||
70 | } | ||
71 | |||
72 | #[test] | ||
73 | fn remove_derive() { | ||
74 | test_remove_derives_up_to( | ||
75 | AttrId(2), | ||
76 | r#" | ||
77 | #[allow(unused)] | ||
78 | #[derive(Copy)] | ||
79 | #[derive(Hello)] | ||
80 | #[derive(Clone)] | ||
81 | struct A { | ||
82 | bar: u32 | ||
83 | } | ||
84 | "#, | ||
85 | expect![[r#" | ||
86 | #[allow(unused)] | ||
87 | |||
88 | |||
89 | #[derive(Clone)] | ||
90 | struct A { | ||
91 | bar: u32 | ||
92 | }"#]], | ||
93 | ); | ||
94 | } | ||
95 | } | ||