diff options
Diffstat (limited to 'crates/hir_expand')
-rw-r--r-- | crates/hir_expand/src/builtin_derive.rs | 4 | ||||
-rw-r--r-- | crates/hir_expand/src/builtin_macro.rs | 40 | ||||
-rw-r--r-- | crates/hir_expand/src/db.rs | 89 | ||||
-rw-r--r-- | crates/hir_expand/src/eager.rs | 7 | ||||
-rw-r--r-- | crates/hir_expand/src/input.rs | 94 | ||||
-rw-r--r-- | crates/hir_expand/src/lib.rs | 89 | ||||
-rw-r--r-- | crates/hir_expand/src/name.rs | 1 | ||||
-rw-r--r-- | crates/hir_expand/src/proc_macro.rs | 102 | ||||
-rw-r--r-- | crates/hir_expand/src/quote.rs | 4 |
9 files changed, 251 insertions, 179 deletions
diff --git a/crates/hir_expand/src/builtin_derive.rs b/crates/hir_expand/src/builtin_derive.rs index 537c03028..b6a6d602f 100644 --- a/crates/hir_expand/src/builtin_derive.rs +++ b/crates/hir_expand/src/builtin_derive.rs | |||
@@ -269,7 +269,7 @@ mod tests { | |||
269 | use expect_test::{expect, Expect}; | 269 | use expect_test::{expect, Expect}; |
270 | use name::AsName; | 270 | use name::AsName; |
271 | 271 | ||
272 | use crate::{test_db::TestDB, AstId, AttrId, MacroCallId, MacroCallKind, MacroCallLoc}; | 272 | use crate::{test_db::TestDB, AstId, MacroCallId, MacroCallKind, MacroCallLoc}; |
273 | 273 | ||
274 | use super::*; | 274 | use super::*; |
275 | 275 | ||
@@ -320,7 +320,7 @@ $0 | |||
320 | kind: MacroCallKind::Derive { | 320 | kind: MacroCallKind::Derive { |
321 | ast_id, | 321 | ast_id, |
322 | derive_name: name.to_string(), | 322 | derive_name: name.to_string(), |
323 | derive_attr: AttrId(0), | 323 | derive_attr_index: 0, |
324 | }, | 324 | }, |
325 | }; | 325 | }; |
326 | 326 | ||
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs index 179de61f9..280c25f11 100644 --- a/crates/hir_expand/src/builtin_macro.rs +++ b/crates/hir_expand/src/builtin_macro.rs | |||
@@ -118,6 +118,7 @@ register_builtin! { | |||
118 | EAGER: | 118 | EAGER: |
119 | (compile_error, CompileError) => compile_error_expand, | 119 | (compile_error, CompileError) => compile_error_expand, |
120 | (concat, Concat) => concat_expand, | 120 | (concat, Concat) => concat_expand, |
121 | (concat_idents, ConcatIdents) => concat_idents_expand, | ||
121 | (include, Include) => include_expand, | 122 | (include, Include) => include_expand, |
122 | (include_bytes, IncludeBytes) => include_bytes_expand, | 123 | (include_bytes, IncludeBytes) => include_bytes_expand, |
123 | (include_str, IncludeStr) => include_str_expand, | 124 | (include_str, IncludeStr) => include_str_expand, |
@@ -373,6 +374,28 @@ fn concat_expand( | |||
373 | ExpandResult { value: Some(ExpandedEager::new(quote!(#text), FragmentKind::Expr)), err } | 374 | ExpandResult { value: Some(ExpandedEager::new(quote!(#text), FragmentKind::Expr)), err } |
374 | } | 375 | } |
375 | 376 | ||
377 | fn concat_idents_expand( | ||
378 | _db: &dyn AstDatabase, | ||
379 | _arg_id: EagerMacroId, | ||
380 | tt: &tt::Subtree, | ||
381 | ) -> ExpandResult<Option<ExpandedEager>> { | ||
382 | let mut err = None; | ||
383 | let mut ident = String::new(); | ||
384 | for (i, t) in tt.token_trees.iter().enumerate() { | ||
385 | match t { | ||
386 | tt::TokenTree::Leaf(tt::Leaf::Ident(id)) => { | ||
387 | ident.push_str(id.text.as_str()); | ||
388 | } | ||
389 | tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if i % 2 == 1 && punct.char == ',' => (), | ||
390 | _ => { | ||
391 | err.get_or_insert(mbe::ExpandError::UnexpectedToken); | ||
392 | } | ||
393 | } | ||
394 | } | ||
395 | let ident = tt::Ident { text: ident.into(), id: tt::TokenId::unspecified() }; | ||
396 | ExpandResult { value: Some(ExpandedEager::new(quote!(#ident), FragmentKind::Expr)), err } | ||
397 | } | ||
398 | |||
376 | fn relative_file( | 399 | fn relative_file( |
377 | db: &dyn AstDatabase, | 400 | db: &dyn AstDatabase, |
378 | call_id: MacroCallId, | 401 | call_id: MacroCallId, |
@@ -578,6 +601,7 @@ mod tests { | |||
578 | krate, | 601 | krate, |
579 | kind: MacroCallKind::FnLike { | 602 | kind: MacroCallKind::FnLike { |
580 | ast_id: AstId::new(file_id.into(), ast_id_map.ast_id(¯o_call)), | 603 | ast_id: AstId::new(file_id.into(), ast_id_map.ast_id(¯o_call)), |
604 | fragment: FragmentKind::Expr, | ||
581 | }, | 605 | }, |
582 | }; | 606 | }; |
583 | 607 | ||
@@ -788,9 +812,21 @@ mod tests { | |||
788 | r##" | 812 | r##" |
789 | #[rustc_builtin_macro] | 813 | #[rustc_builtin_macro] |
790 | macro_rules! concat {} | 814 | macro_rules! concat {} |
791 | concat!("foo", "r", 0, r#"bar"#, false); | 815 | concat!("foo", "r", 0, r#"bar"#, "\n", false); |
816 | "##, | ||
817 | expect![[r#""foor0bar\nfalse""#]], | ||
818 | ); | ||
819 | } | ||
820 | |||
821 | #[test] | ||
822 | fn test_concat_idents_expand() { | ||
823 | check_expansion( | ||
824 | r##" | ||
825 | #[rustc_builtin_macro] | ||
826 | macro_rules! concat_idents {} | ||
827 | concat_idents!(foo, bar); | ||
792 | "##, | 828 | "##, |
793 | expect![[r#""foor0barfalse""#]], | 829 | expect![[r#"foobar"#]], |
794 | ); | 830 | ); |
795 | } | 831 | } |
796 | } | 832 | } |
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs index d61f4b31a..c43d382ad 100644 --- a/crates/hir_expand/src/db.rs +++ b/crates/hir_expand/src/db.rs | |||
@@ -8,15 +8,13 @@ use parser::FragmentKind; | |||
8 | use syntax::{ | 8 | use syntax::{ |
9 | algo::diff, | 9 | algo::diff, |
10 | ast::{self, NameOwner}, | 10 | ast::{self, NameOwner}, |
11 | AstNode, GreenNode, Parse, | 11 | AstNode, GreenNode, Parse, SyntaxNode, SyntaxToken, |
12 | SyntaxKind::*, | ||
13 | SyntaxNode, SyntaxToken, | ||
14 | }; | 12 | }; |
15 | 13 | ||
16 | use crate::{ | 14 | use crate::{ |
17 | ast_id_map::AstIdMap, hygiene::HygieneFrame, BuiltinDeriveExpander, BuiltinFnLikeExpander, | 15 | ast_id_map::AstIdMap, hygiene::HygieneFrame, input::process_macro_input, BuiltinDeriveExpander, |
18 | EagerCallLoc, EagerMacroId, HirFileId, HirFileIdRepr, LazyMacroId, MacroCallId, MacroCallLoc, | 16 | BuiltinFnLikeExpander, EagerCallLoc, EagerMacroId, HirFileId, HirFileIdRepr, LazyMacroId, |
19 | MacroDefId, MacroDefKind, MacroFile, ProcMacroExpander, | 17 | MacroCallId, MacroCallLoc, MacroDefId, MacroDefKind, MacroFile, ProcMacroExpander, |
20 | }; | 18 | }; |
21 | 19 | ||
22 | /// Total limit on the number of tokens produced by any macro invocation. | 20 | /// Total limit on the number of tokens produced by any macro invocation. |
@@ -160,7 +158,7 @@ pub fn expand_hypothetical( | |||
160 | 158 | ||
161 | let hypothetical_expansion = macro_def.expand(db, lazy_id, &tt); | 159 | let hypothetical_expansion = macro_def.expand(db, lazy_id, &tt); |
162 | 160 | ||
163 | let fragment_kind = to_fragment_kind(db, actual_macro_call); | 161 | let fragment_kind = macro_fragment_kind(db, actual_macro_call); |
164 | 162 | ||
165 | let (node, tmap_2) = | 163 | let (node, tmap_2) = |
166 | mbe::token_tree_to_syntax_node(&hypothetical_expansion.value, fragment_kind).ok()?; | 164 | mbe::token_tree_to_syntax_node(&hypothetical_expansion.value, fragment_kind).ok()?; |
@@ -226,7 +224,7 @@ fn parse_macro_expansion( | |||
226 | None => return ExpandResult { value: None, err: result.err }, | 224 | None => return ExpandResult { value: None, err: result.err }, |
227 | }; | 225 | }; |
228 | 226 | ||
229 | let fragment_kind = to_fragment_kind(db, macro_file.macro_call_id); | 227 | let fragment_kind = macro_fragment_kind(db, macro_file.macro_call_id); |
230 | 228 | ||
231 | log::debug!("expanded = {}", tt.as_debug_string()); | 229 | log::debug!("expanded = {}", tt.as_debug_string()); |
232 | log::debug!("kind = {:?}", fragment_kind); | 230 | log::debug!("kind = {:?}", fragment_kind); |
@@ -269,7 +267,16 @@ fn parse_macro_expansion( | |||
269 | 267 | ||
270 | fn macro_arg(db: &dyn AstDatabase, id: MacroCallId) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>> { | 268 | fn macro_arg(db: &dyn AstDatabase, id: MacroCallId) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>> { |
271 | let arg = db.macro_arg_text(id)?; | 269 | let arg = db.macro_arg_text(id)?; |
272 | let (tt, tmap) = mbe::syntax_node_to_token_tree(&SyntaxNode::new_root(arg)); | 270 | let (mut tt, tmap) = mbe::syntax_node_to_token_tree(&SyntaxNode::new_root(arg)); |
271 | |||
272 | if let MacroCallId::LazyMacro(id) = id { | ||
273 | let loc: MacroCallLoc = db.lookup_intern_macro(id); | ||
274 | if loc.def.is_proc_macro() { | ||
275 | // proc macros expect their inputs without parentheses, MBEs expect it with them included | ||
276 | tt.delimiter = None; | ||
277 | } | ||
278 | } | ||
279 | |||
273 | Some(Arc::new((tt, tmap))) | 280 | Some(Arc::new((tt, tmap))) |
274 | } | 281 | } |
275 | 282 | ||
@@ -283,6 +290,7 @@ fn macro_arg_text(db: &dyn AstDatabase, id: MacroCallId) -> Option<GreenNode> { | |||
283 | }; | 290 | }; |
284 | let loc = db.lookup_intern_macro(id); | 291 | let loc = db.lookup_intern_macro(id); |
285 | let arg = loc.kind.arg(db)?; | 292 | let arg = loc.kind.arg(db)?; |
293 | let arg = process_macro_input(db, arg, id); | ||
286 | Some(arg.green().into()) | 294 | Some(arg.green().into()) |
287 | } | 295 | } |
288 | 296 | ||
@@ -427,62 +435,15 @@ fn hygiene_frame(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<HygieneFrame> | |||
427 | Arc::new(HygieneFrame::new(db, file_id)) | 435 | Arc::new(HygieneFrame::new(db, file_id)) |
428 | } | 436 | } |
429 | 437 | ||
430 | /// Given a `MacroCallId`, return what `FragmentKind` it belongs to. | 438 | fn macro_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind { |
431 | /// FIXME: Not completed | 439 | match id { |
432 | fn to_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind { | 440 | MacroCallId::LazyMacro(id) => { |
433 | let lazy_id = match id { | 441 | let loc: MacroCallLoc = db.lookup_intern_macro(id); |
434 | MacroCallId::LazyMacro(id) => id, | 442 | loc.kind.fragment_kind() |
435 | MacroCallId::EagerMacro(id) => { | ||
436 | return db.lookup_intern_eager_expansion(id).fragment; | ||
437 | } | ||
438 | }; | ||
439 | let syn = db.lookup_intern_macro(lazy_id).kind.node(db).value; | ||
440 | |||
441 | let parent = match syn.parent() { | ||
442 | Some(it) => it, | ||
443 | None => return FragmentKind::Statements, | ||
444 | }; | ||
445 | |||
446 | match parent.kind() { | ||
447 | MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items, | ||
448 | MACRO_STMTS => FragmentKind::Statements, | ||
449 | MACRO_PAT => FragmentKind::Pattern, | ||
450 | MACRO_TYPE => FragmentKind::Type, | ||
451 | ITEM_LIST => FragmentKind::Items, | ||
452 | LET_STMT => { | ||
453 | // FIXME: Handle LHS Pattern | ||
454 | FragmentKind::Expr | ||
455 | } | 443 | } |
456 | EXPR_STMT => FragmentKind::Statements, | 444 | MacroCallId::EagerMacro(id) => { |
457 | BLOCK_EXPR => FragmentKind::Statements, | 445 | let loc: EagerCallLoc = db.lookup_intern_eager_expansion(id); |
458 | ARG_LIST => FragmentKind::Expr, | 446 | loc.fragment |
459 | TRY_EXPR => FragmentKind::Expr, | ||
460 | TUPLE_EXPR => FragmentKind::Expr, | ||
461 | PAREN_EXPR => FragmentKind::Expr, | ||
462 | ARRAY_EXPR => FragmentKind::Expr, | ||
463 | FOR_EXPR => FragmentKind::Expr, | ||
464 | PATH_EXPR => FragmentKind::Expr, | ||
465 | CLOSURE_EXPR => FragmentKind::Expr, | ||
466 | CONDITION => FragmentKind::Expr, | ||
467 | BREAK_EXPR => FragmentKind::Expr, | ||
468 | RETURN_EXPR => FragmentKind::Expr, | ||
469 | MATCH_EXPR => FragmentKind::Expr, | ||
470 | MATCH_ARM => FragmentKind::Expr, | ||
471 | MATCH_GUARD => FragmentKind::Expr, | ||
472 | RECORD_EXPR_FIELD => FragmentKind::Expr, | ||
473 | CALL_EXPR => FragmentKind::Expr, | ||
474 | INDEX_EXPR => FragmentKind::Expr, | ||
475 | METHOD_CALL_EXPR => FragmentKind::Expr, | ||
476 | FIELD_EXPR => FragmentKind::Expr, | ||
477 | AWAIT_EXPR => FragmentKind::Expr, | ||
478 | CAST_EXPR => FragmentKind::Expr, | ||
479 | REF_EXPR => FragmentKind::Expr, | ||
480 | PREFIX_EXPR => FragmentKind::Expr, | ||
481 | RANGE_EXPR => FragmentKind::Expr, | ||
482 | BIN_EXPR => FragmentKind::Expr, | ||
483 | _ => { | ||
484 | // Unknown , Just guess it is `Items` | ||
485 | FragmentKind::Items | ||
486 | } | 447 | } |
487 | } | 448 | } |
488 | } | 449 | } |
diff --git a/crates/hir_expand/src/eager.rs b/crates/hir_expand/src/eager.rs index f12132f84..85491fe8b 100644 --- a/crates/hir_expand/src/eager.rs +++ b/crates/hir_expand/src/eager.rs | |||
@@ -175,8 +175,13 @@ fn lazy_expand( | |||
175 | ) -> ExpandResult<Option<InFile<SyntaxNode>>> { | 175 | ) -> ExpandResult<Option<InFile<SyntaxNode>>> { |
176 | let ast_id = db.ast_id_map(macro_call.file_id).ast_id(¯o_call.value); | 176 | let ast_id = db.ast_id_map(macro_call.file_id).ast_id(¯o_call.value); |
177 | 177 | ||
178 | let fragment = crate::to_fragment_kind(¯o_call.value); | ||
178 | let id: MacroCallId = def | 179 | let id: MacroCallId = def |
179 | .as_lazy_macro(db, krate, MacroCallKind::FnLike { ast_id: macro_call.with_value(ast_id) }) | 180 | .as_lazy_macro( |
181 | db, | ||
182 | krate, | ||
183 | MacroCallKind::FnLike { ast_id: macro_call.with_value(ast_id), fragment }, | ||
184 | ) | ||
180 | .into(); | 185 | .into(); |
181 | 186 | ||
182 | let err = db.macro_expand_error(id); | 187 | let err = db.macro_expand_error(id); |
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 | } | ||
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs index 0402640de..88cb16ca4 100644 --- a/crates/hir_expand/src/lib.rs +++ b/crates/hir_expand/src/lib.rs | |||
@@ -14,9 +14,12 @@ pub mod builtin_macro; | |||
14 | pub mod proc_macro; | 14 | pub mod proc_macro; |
15 | pub mod quote; | 15 | pub mod quote; |
16 | pub mod eager; | 16 | pub mod eager; |
17 | mod input; | ||
17 | 18 | ||
18 | use either::Either; | 19 | use either::Either; |
20 | |||
19 | pub use mbe::{ExpandError, ExpandResult}; | 21 | pub use mbe::{ExpandError, ExpandResult}; |
22 | pub use parser::FragmentKind; | ||
20 | 23 | ||
21 | use std::hash::Hash; | 24 | use std::hash::Hash; |
22 | use std::sync::Arc; | 25 | use std::sync::Arc; |
@@ -269,6 +272,10 @@ impl MacroDefId { | |||
269 | }; | 272 | }; |
270 | Either::Left(*id) | 273 | Either::Left(*id) |
271 | } | 274 | } |
275 | |||
276 | pub fn is_proc_macro(&self) -> bool { | ||
277 | matches!(self.kind, MacroDefKind::ProcMacro(..)) | ||
278 | } | ||
272 | } | 279 | } |
273 | 280 | ||
274 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 281 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
@@ -290,13 +297,21 @@ pub struct MacroCallLoc { | |||
290 | 297 | ||
291 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 298 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
292 | pub enum MacroCallKind { | 299 | pub enum MacroCallKind { |
293 | FnLike { ast_id: AstId<ast::MacroCall> }, | 300 | FnLike { |
294 | Derive { ast_id: AstId<ast::Item>, derive_name: String, derive_attr: AttrId }, | 301 | ast_id: AstId<ast::MacroCall>, |
302 | fragment: FragmentKind, | ||
303 | }, | ||
304 | Derive { | ||
305 | ast_id: AstId<ast::Item>, | ||
306 | derive_name: String, | ||
307 | /// Syntactical index of the invoking `#[derive]` attribute. | ||
308 | /// | ||
309 | /// Outer attributes are counted first, then inner attributes. This does not support | ||
310 | /// out-of-line modules, which may have attributes spread across 2 files! | ||
311 | derive_attr_index: u32, | ||
312 | }, | ||
295 | } | 313 | } |
296 | 314 | ||
297 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
298 | pub struct AttrId(pub u32); | ||
299 | |||
300 | impl MacroCallKind { | 315 | impl MacroCallKind { |
301 | fn file_id(&self) -> HirFileId { | 316 | fn file_id(&self) -> HirFileId { |
302 | match self { | 317 | match self { |
@@ -324,6 +339,13 @@ impl MacroCallKind { | |||
324 | MacroCallKind::Derive { ast_id, .. } => Some(ast_id.to_node(db).syntax().clone()), | 339 | MacroCallKind::Derive { ast_id, .. } => Some(ast_id.to_node(db).syntax().clone()), |
325 | } | 340 | } |
326 | } | 341 | } |
342 | |||
343 | fn fragment_kind(&self) -> FragmentKind { | ||
344 | match self { | ||
345 | MacroCallKind::FnLike { fragment, .. } => *fragment, | ||
346 | MacroCallKind::Derive { .. } => FragmentKind::Items, | ||
347 | } | ||
348 | } | ||
327 | } | 349 | } |
328 | 350 | ||
329 | impl MacroCallId { | 351 | impl MacroCallId { |
@@ -357,7 +379,6 @@ pub struct ExpansionInfo { | |||
357 | } | 379 | } |
358 | 380 | ||
359 | pub use mbe::Origin; | 381 | pub use mbe::Origin; |
360 | use parser::FragmentKind; | ||
361 | 382 | ||
362 | impl ExpansionInfo { | 383 | impl ExpansionInfo { |
363 | pub fn call_node(&self) -> Option<InFile<SyntaxNode>> { | 384 | pub fn call_node(&self) -> Option<InFile<SyntaxNode>> { |
@@ -562,3 +583,59 @@ impl<N: AstNode> InFile<N> { | |||
562 | self.with_value(self.value.syntax()) | 583 | self.with_value(self.value.syntax()) |
563 | } | 584 | } |
564 | } | 585 | } |
586 | |||
587 | /// Given a `MacroCallId`, return what `FragmentKind` it belongs to. | ||
588 | /// FIXME: Not completed | ||
589 | pub fn to_fragment_kind(call: &ast::MacroCall) -> FragmentKind { | ||
590 | use syntax::SyntaxKind::*; | ||
591 | |||
592 | let syn = call.syntax(); | ||
593 | |||
594 | let parent = match syn.parent() { | ||
595 | Some(it) => it, | ||
596 | None => return FragmentKind::Statements, | ||
597 | }; | ||
598 | |||
599 | match parent.kind() { | ||
600 | MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items, | ||
601 | MACRO_STMTS => FragmentKind::Statements, | ||
602 | MACRO_PAT => FragmentKind::Pattern, | ||
603 | MACRO_TYPE => FragmentKind::Type, | ||
604 | ITEM_LIST => FragmentKind::Items, | ||
605 | LET_STMT => { | ||
606 | // FIXME: Handle LHS Pattern | ||
607 | FragmentKind::Expr | ||
608 | } | ||
609 | EXPR_STMT => FragmentKind::Statements, | ||
610 | BLOCK_EXPR => FragmentKind::Statements, | ||
611 | ARG_LIST => FragmentKind::Expr, | ||
612 | TRY_EXPR => FragmentKind::Expr, | ||
613 | TUPLE_EXPR => FragmentKind::Expr, | ||
614 | PAREN_EXPR => FragmentKind::Expr, | ||
615 | ARRAY_EXPR => FragmentKind::Expr, | ||
616 | FOR_EXPR => FragmentKind::Expr, | ||
617 | PATH_EXPR => FragmentKind::Expr, | ||
618 | CLOSURE_EXPR => FragmentKind::Expr, | ||
619 | CONDITION => FragmentKind::Expr, | ||
620 | BREAK_EXPR => FragmentKind::Expr, | ||
621 | RETURN_EXPR => FragmentKind::Expr, | ||
622 | MATCH_EXPR => FragmentKind::Expr, | ||
623 | MATCH_ARM => FragmentKind::Expr, | ||
624 | MATCH_GUARD => FragmentKind::Expr, | ||
625 | RECORD_EXPR_FIELD => FragmentKind::Expr, | ||
626 | CALL_EXPR => FragmentKind::Expr, | ||
627 | INDEX_EXPR => FragmentKind::Expr, | ||
628 | METHOD_CALL_EXPR => FragmentKind::Expr, | ||
629 | FIELD_EXPR => FragmentKind::Expr, | ||
630 | AWAIT_EXPR => FragmentKind::Expr, | ||
631 | CAST_EXPR => FragmentKind::Expr, | ||
632 | REF_EXPR => FragmentKind::Expr, | ||
633 | PREFIX_EXPR => FragmentKind::Expr, | ||
634 | RANGE_EXPR => FragmentKind::Expr, | ||
635 | BIN_EXPR => FragmentKind::Expr, | ||
636 | _ => { | ||
637 | // Unknown , Just guess it is `Items` | ||
638 | FragmentKind::Items | ||
639 | } | ||
640 | } | ||
641 | } | ||
diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs index bcfd3e524..5a5dc9afd 100644 --- a/crates/hir_expand/src/name.rs +++ b/crates/hir_expand/src/name.rs | |||
@@ -212,6 +212,7 @@ pub mod known { | |||
212 | std_panic, | 212 | std_panic, |
213 | stringify, | 213 | stringify, |
214 | concat, | 214 | concat, |
215 | concat_idents, | ||
215 | include, | 216 | include, |
216 | include_bytes, | 217 | include_bytes, |
217 | include_str, | 218 | include_str, |
diff --git a/crates/hir_expand/src/proc_macro.rs b/crates/hir_expand/src/proc_macro.rs index 75e950816..d5643393a 100644 --- a/crates/hir_expand/src/proc_macro.rs +++ b/crates/hir_expand/src/proc_macro.rs | |||
@@ -2,7 +2,6 @@ | |||
2 | 2 | ||
3 | use crate::db::AstDatabase; | 3 | use crate::db::AstDatabase; |
4 | use base_db::{CrateId, ProcMacroId}; | 4 | use base_db::{CrateId, ProcMacroId}; |
5 | use tt::buffer::{Cursor, TokenBuffer}; | ||
6 | 5 | ||
7 | #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] | 6 | #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] |
8 | pub struct ProcMacroExpander { | 7 | pub struct ProcMacroExpander { |
@@ -44,9 +43,6 @@ impl ProcMacroExpander { | |||
44 | .clone() | 43 | .clone() |
45 | .ok_or_else(|| err!("No derive macro found."))?; | 44 | .ok_or_else(|| err!("No derive macro found."))?; |
46 | 45 | ||
47 | let tt = remove_derive_attrs(tt) | ||
48 | .ok_or_else(|| err!("Fail to remove derive for custom derive"))?; | ||
49 | |||
50 | // Proc macros have access to the environment variables of the invoking crate. | 46 | // Proc macros have access to the environment variables of the invoking crate. |
51 | let env = &krate_graph[calling_crate].env; | 47 | let env = &krate_graph[calling_crate].env; |
52 | 48 | ||
@@ -56,101 +52,3 @@ impl ProcMacroExpander { | |||
56 | } | 52 | } |
57 | } | 53 | } |
58 | } | 54 | } |
59 | |||
60 | fn eat_punct(cursor: &mut Cursor, c: char) -> bool { | ||
61 | if let Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Punct(punct), _)) = cursor.token_tree() { | ||
62 | if punct.char == c { | ||
63 | *cursor = cursor.bump(); | ||
64 | return true; | ||
65 | } | ||
66 | } | ||
67 | false | ||
68 | } | ||
69 | |||
70 | fn eat_subtree(cursor: &mut Cursor, kind: tt::DelimiterKind) -> bool { | ||
71 | if let Some(tt::buffer::TokenTreeRef::Subtree(subtree, _)) = cursor.token_tree() { | ||
72 | if Some(kind) == subtree.delimiter_kind() { | ||
73 | *cursor = cursor.bump_subtree(); | ||
74 | return true; | ||
75 | } | ||
76 | } | ||
77 | false | ||
78 | } | ||
79 | |||
80 | fn eat_ident(cursor: &mut Cursor, t: &str) -> bool { | ||
81 | if let Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Ident(ident), _)) = cursor.token_tree() { | ||
82 | if t == ident.text.as_str() { | ||
83 | *cursor = cursor.bump(); | ||
84 | return true; | ||
85 | } | ||
86 | } | ||
87 | false | ||
88 | } | ||
89 | |||
90 | fn remove_derive_attrs(tt: &tt::Subtree) -> Option<tt::Subtree> { | ||
91 | let buffer = TokenBuffer::from_tokens(&tt.token_trees); | ||
92 | let mut p = buffer.begin(); | ||
93 | let mut result = tt::Subtree::default(); | ||
94 | |||
95 | while !p.eof() { | ||
96 | let curr = p; | ||
97 | |||
98 | if eat_punct(&mut p, '#') { | ||
99 | eat_punct(&mut p, '!'); | ||
100 | let parent = p; | ||
101 | if eat_subtree(&mut p, tt::DelimiterKind::Bracket) { | ||
102 | if eat_ident(&mut p, "derive") { | ||
103 | p = parent.bump(); | ||
104 | continue; | ||
105 | } | ||
106 | } | ||
107 | } | ||
108 | |||
109 | result.token_trees.push(curr.token_tree()?.cloned()); | ||
110 | p = curr.bump(); | ||
111 | } | ||
112 | |||
113 | Some(result) | ||
114 | } | ||
115 | |||
116 | #[cfg(test)] | ||
117 | mod tests { | ||
118 | use super::*; | ||
119 | use test_utils::assert_eq_text; | ||
120 | |||
121 | #[test] | ||
122 | fn test_remove_derive_attrs() { | ||
123 | let tt = mbe::parse_to_token_tree( | ||
124 | r#" | ||
125 | #[allow(unused)] | ||
126 | #[derive(Copy)] | ||
127 | #[derive(Hello)] | ||
128 | struct A { | ||
129 | bar: u32 | ||
130 | } | ||
131 | "#, | ||
132 | ) | ||
133 | .unwrap() | ||
134 | .0; | ||
135 | let result = format!("{:#?}", remove_derive_attrs(&tt).unwrap()); | ||
136 | |||
137 | assert_eq_text!( | ||
138 | r#" | ||
139 | SUBTREE $ | ||
140 | PUNCH # [alone] 0 | ||
141 | SUBTREE [] 1 | ||
142 | IDENT allow 2 | ||
143 | SUBTREE () 3 | ||
144 | IDENT unused 4 | ||
145 | IDENT struct 15 | ||
146 | IDENT A 16 | ||
147 | SUBTREE {} 17 | ||
148 | IDENT bar 18 | ||
149 | PUNCH : [alone] 19 | ||
150 | IDENT u32 20 | ||
151 | "# | ||
152 | .trim(), | ||
153 | &result | ||
154 | ); | ||
155 | } | ||
156 | } | ||
diff --git a/crates/hir_expand/src/quote.rs b/crates/hir_expand/src/quote.rs index c82487ef0..230a59964 100644 --- a/crates/hir_expand/src/quote.rs +++ b/crates/hir_expand/src/quote.rs | |||
@@ -196,8 +196,8 @@ impl_to_to_tokentrees! { | |||
196 | tt::Literal => self { self }; | 196 | tt::Literal => self { self }; |
197 | tt::Ident => self { self }; | 197 | tt::Ident => self { self }; |
198 | tt::Punct => self { self }; | 198 | tt::Punct => self { self }; |
199 | &str => self { tt::Literal{text: format!("{:?}", self.escape_default().to_string()).into(), id: tt::TokenId::unspecified()}}; | 199 | &str => self { tt::Literal{text: format!("\"{}\"", self.escape_debug()).into(), id: tt::TokenId::unspecified()}}; |
200 | String => self { tt::Literal{text: format!("{:?}", self.escape_default().to_string()).into(), id: tt::TokenId::unspecified()}} | 200 | String => self { tt::Literal{text: format!("\"{}\"", self.escape_debug()).into(), id: tt::TokenId::unspecified()}} |
201 | } | 201 | } |
202 | 202 | ||
203 | #[cfg(test)] | 203 | #[cfg(test)] |