diff options
Diffstat (limited to 'crates/hir_expand/src/input.rs')
-rw-r--r-- | crates/hir_expand/src/input.rs | 94 |
1 files changed, 94 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..112216859 --- /dev/null +++ b/crates/hir_expand/src/input.rs | |||
@@ -0,0 +1,94 @@ | |||
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 | 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_index, .. } => { | ||
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_index as usize).syntax().clone() | ||
30 | } | ||
31 | } | ||
32 | } | ||
33 | |||
34 | /// Removes `#[derive]` attributes from `item`, up to `attr_index`. | ||
35 | fn remove_derives_up_to(item: ast::Item, attr_index: usize) -> ast::Item { | ||
36 | let item = item.clone_for_update(); | ||
37 | for attr in item.attrs().take(attr_index + 1) { | ||
38 | if let Some(name) = | ||
39 | attr.path().and_then(|path| path.as_single_segment()).and_then(|seg| seg.name_ref()) | ||
40 | { | ||
41 | if name.as_name() == name![derive] { | ||
42 | attr.syntax().detach(); | ||
43 | } | ||
44 | } | ||
45 | } | ||
46 | item | ||
47 | } | ||
48 | |||
49 | #[cfg(test)] | ||
50 | mod tests { | ||
51 | use base_db::fixture::WithFixture; | ||
52 | use base_db::SourceDatabase; | ||
53 | use expect_test::{expect, Expect}; | ||
54 | |||
55 | use crate::test_db::TestDB; | ||
56 | |||
57 | use super::*; | ||
58 | |||
59 | fn test_remove_derives_up_to(attr: usize, ra_fixture: &str, expect: Expect) { | ||
60 | let (db, file_id) = TestDB::with_single_file(&ra_fixture); | ||
61 | let parsed = db.parse(file_id); | ||
62 | |||
63 | let mut items: Vec<_> = | ||
64 | parsed.syntax_node().descendants().filter_map(ast::Item::cast).collect(); | ||
65 | assert_eq!(items.len(), 1); | ||
66 | |||
67 | let item = remove_derives_up_to(items.pop().unwrap(), attr); | ||
68 | expect.assert_eq(&item.to_string()); | ||
69 | } | ||
70 | |||
71 | #[test] | ||
72 | fn remove_derive() { | ||
73 | test_remove_derives_up_to( | ||
74 | 2, | ||
75 | r#" | ||
76 | #[allow(unused)] | ||
77 | #[derive(Copy)] | ||
78 | #[derive(Hello)] | ||
79 | #[derive(Clone)] | ||
80 | struct A { | ||
81 | bar: u32 | ||
82 | } | ||
83 | "#, | ||
84 | expect![[r#" | ||
85 | #[allow(unused)] | ||
86 | |||
87 | |||
88 | #[derive(Clone)] | ||
89 | struct A { | ||
90 | bar: u32 | ||
91 | }"#]], | ||
92 | ); | ||
93 | } | ||
94 | } | ||