aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_expand/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_expand/src')
-rw-r--r--crates/hir_expand/src/ast_id_map.rs24
-rw-r--r--crates/hir_expand/src/builtin_derive.rs2
-rw-r--r--crates/hir_expand/src/builtin_macro.rs90
-rw-r--r--crates/hir_expand/src/db.rs2
-rw-r--r--crates/hir_expand/src/name.rs12
5 files changed, 64 insertions, 66 deletions
diff --git a/crates/hir_expand/src/ast_id_map.rs b/crates/hir_expand/src/ast_id_map.rs
index 2401b0cc5..16cf29907 100644
--- a/crates/hir_expand/src/ast_id_map.rs
+++ b/crates/hir_expand/src/ast_id_map.rs
@@ -13,7 +13,8 @@ use std::{
13}; 13};
14 14
15use la_arena::{Arena, Idx}; 15use la_arena::{Arena, Idx};
16use syntax::{ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr}; 16use profile::Count;
17use syntax::{ast, match_ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr};
17 18
18/// `AstId` points to an AST node in a specific file. 19/// `AstId` points to an AST node in a specific file.
19pub struct FileAstId<N: AstNode> { 20pub struct FileAstId<N: AstNode> {
@@ -62,22 +63,31 @@ type ErasedFileAstId = Idx<SyntaxNodePtr>;
62#[derive(Debug, PartialEq, Eq, Default)] 63#[derive(Debug, PartialEq, Eq, Default)]
63pub struct AstIdMap { 64pub struct AstIdMap {
64 arena: Arena<SyntaxNodePtr>, 65 arena: Arena<SyntaxNodePtr>,
66 _c: Count<Self>,
65} 67}
66 68
67impl AstIdMap { 69impl AstIdMap {
68 pub(crate) fn from_source(node: &SyntaxNode) -> AstIdMap { 70 pub(crate) fn from_source(node: &SyntaxNode) -> AstIdMap {
69 assert!(node.parent().is_none()); 71 assert!(node.parent().is_none());
70 let mut res = AstIdMap { arena: Arena::default() }; 72 let mut res = AstIdMap::default();
71 // By walking the tree in breadth-first order we make sure that parents 73 // By walking the tree in breadth-first order we make sure that parents
72 // get lower ids then children. That is, adding a new child does not 74 // get lower ids then children. That is, adding a new child does not
73 // change parent's id. This means that, say, adding a new function to a 75 // change parent's id. This means that, say, adding a new function to a
74 // trait does not change ids of top-level items, which helps caching. 76 // trait does not change ids of top-level items, which helps caching.
75 bdfs(node, |it| match ast::Item::cast(it) { 77 bdfs(node, |it| {
76 Some(module_item) => { 78 match_ast! {
77 res.alloc(module_item.syntax()); 79 match it {
78 true 80 ast::Item(module_item) => {
81 res.alloc(module_item.syntax());
82 true
83 },
84 ast::BlockExpr(block) => {
85 res.alloc(block.syntax());
86 true
87 },
88 _ => false,
89 }
79 } 90 }
80 None => false,
81 }); 91 });
82 res 92 res
83 } 93 }
diff --git a/crates/hir_expand/src/builtin_derive.rs b/crates/hir_expand/src/builtin_derive.rs
index eb257579f..b7f1aae8f 100644
--- a/crates/hir_expand/src/builtin_derive.rs
+++ b/crates/hir_expand/src/builtin_derive.rs
@@ -102,7 +102,7 @@ fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, mbe::ExpandError> {
102 debug!("name token not found"); 102 debug!("name token not found");
103 mbe::ExpandError::ConversionError 103 mbe::ExpandError::ConversionError
104 })?; 104 })?;
105 let name_token = tt::Ident { id: name_token_id, text: name.text().clone() }; 105 let name_token = tt::Ident { id: name_token_id, text: name.text().into() };
106 let type_params = params.map_or(0, |type_param_list| type_param_list.type_params().count()); 106 let type_params = params.map_or(0, |type_param_list| type_param_list.type_params().count());
107 Ok(BasicAdtInfo { name: name_token, type_params }) 107 Ok(BasicAdtInfo { name: name_token, type_params })
108} 108}
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs
index 80b60d59f..eb57ea7d6 100644
--- a/crates/hir_expand/src/builtin_macro.rs
+++ b/crates/hir_expand/src/builtin_macro.rs
@@ -6,7 +6,7 @@ use crate::{
6 6
7use base_db::{AnchoredPath, FileId}; 7use base_db::{AnchoredPath, FileId};
8use either::Either; 8use either::Either;
9use mbe::{parse_to_token_tree, ExpandResult}; 9use mbe::{parse_exprs_with_sep, parse_to_token_tree, ExpandResult};
10use parser::FragmentKind; 10use parser::FragmentKind;
11use syntax::ast::{self, AstToken}; 11use syntax::ast::{self, AstToken};
12 12
@@ -182,25 +182,10 @@ fn assert_expand(
182 // ```, 182 // ```,
183 // which is wrong but useful. 183 // which is wrong but useful.
184 184
185 let mut args = Vec::new(); 185 let args = parse_exprs_with_sep(tt, ',');
186 let mut current = Vec::new();
187 for tt in tt.token_trees.iter().cloned() {
188 match tt {
189 tt::TokenTree::Leaf(tt::Leaf::Punct(p)) if p.char == ',' => {
190 args.push(current);
191 current = Vec::new();
192 }
193 _ => {
194 current.push(tt);
195 }
196 }
197 }
198 if !current.is_empty() {
199 args.push(current);
200 }
201 186
202 let arg_tts = args.into_iter().flat_map(|arg| { 187 let arg_tts = args.into_iter().flat_map(|arg| {
203 quote! { &(##arg), } 188 quote! { &(#arg), }
204 }.token_trees).collect::<Vec<_>>(); 189 }.token_trees).collect::<Vec<_>>();
205 190
206 let expanded = quote! { 191 let expanded = quote! {
@@ -238,35 +223,21 @@ fn format_args_expand(
238 // ]) 223 // ])
239 // ```, 224 // ```,
240 // which is still not really correct, but close enough for now 225 // which is still not really correct, but close enough for now
241 let mut args = Vec::new(); 226 let mut args = parse_exprs_with_sep(tt, ',');
242 let mut current = Vec::new(); 227
243 for tt in tt.token_trees.iter().cloned() {
244 match tt {
245 tt::TokenTree::Leaf(tt::Leaf::Punct(p)) if p.char == ',' => {
246 args.push(current);
247 current = Vec::new();
248 }
249 _ => {
250 current.push(tt);
251 }
252 }
253 }
254 if !current.is_empty() {
255 args.push(current);
256 }
257 if args.is_empty() { 228 if args.is_empty() {
258 return ExpandResult::only_err(mbe::ExpandError::NoMatchingRule); 229 return ExpandResult::only_err(mbe::ExpandError::NoMatchingRule);
259 } 230 }
260 for arg in &mut args { 231 for arg in &mut args {
261 // Remove `key =`. 232 // Remove `key =`.
262 if matches!(arg.get(1), Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p))) if p.char == '=' && p.spacing != tt::Spacing::Joint) 233 if matches!(arg.token_trees.get(1), Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p))) if p.char == '=' && p.spacing != tt::Spacing::Joint)
263 { 234 {
264 arg.drain(..2); 235 arg.token_trees.drain(..2);
265 } 236 }
266 } 237 }
267 let _format_string = args.remove(0); 238 let _format_string = args.remove(0);
268 let arg_tts = args.into_iter().flat_map(|arg| { 239 let arg_tts = args.into_iter().flat_map(|arg| {
269 quote! { std::fmt::ArgumentV1::new(&(##arg), std::fmt::Display::fmt), } 240 quote! { std::fmt::ArgumentV1::new(&(#arg), std::fmt::Display::fmt), }
270 }.token_trees).collect::<Vec<_>>(); 241 }.token_trees).collect::<Vec<_>>();
271 let expanded = quote! { 242 let expanded = quote! {
272 std::fmt::Arguments::new_v1(&[], &[##arg_tts]) 243 std::fmt::Arguments::new_v1(&[], &[##arg_tts])
@@ -327,17 +298,14 @@ fn concat_expand(
327 // concat works with string and char literals, so remove any quotes. 298 // concat works with string and char literals, so remove any quotes.
328 // It also works with integer, float and boolean literals, so just use the rest 299 // It also works with integer, float and boolean literals, so just use the rest
329 // as-is. 300 // as-is.
330 301 let component = unquote_str(&it).unwrap_or_else(|| it.text.to_string());
331 text += it 302 text.push_str(&component);
332 .text 303 }
333 .trim_start_matches(|c| match c { 304 // handle boolean literals
334 'r' | '#' | '\'' | '"' => true, 305 tt::TokenTree::Leaf(tt::Leaf::Ident(id))
335 _ => false, 306 if i % 2 == 0 && (id.text == "true" || id.text == "false") =>
336 }) 307 {
337 .trim_end_matches(|c| match c { 308 text.push_str(id.text.as_str());
338 '#' | '\'' | '"' => true,
339 _ => false,
340 });
341 } 309 }
342 tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if i % 2 == 1 && punct.char == ',' => (), 310 tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if i % 2 == 1 && punct.char == ',' => (),
343 _ => { 311 _ => {
@@ -345,7 +313,6 @@ fn concat_expand(
345 } 313 }
346 } 314 }
347 } 315 }
348
349 ExpandResult { value: Some((quote!(#text), FragmentKind::Expr)), err } 316 ExpandResult { value: Some((quote!(#text), FragmentKind::Expr)), err }
350} 317}
351 318
@@ -724,6 +691,25 @@ mod tests {
724 } 691 }
725 692
726 #[test] 693 #[test]
694 fn test_format_args_expand_with_comma_exprs() {
695 let expanded = expand_builtin_macro(
696 r#"
697 #[rustc_builtin_macro]
698 macro_rules! format_args {
699 ($fmt:expr) => ({ /* compiler built-in */ });
700 ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ })
701 }
702 format_args!("{} {:?}", a::<A,B>(), b);
703 "#,
704 );
705
706 assert_eq!(
707 expanded,
708 r#"std::fmt::Arguments::new_v1(&[], &[std::fmt::ArgumentV1::new(&(a::<A,B>()),std::fmt::Display::fmt),std::fmt::ArgumentV1::new(&(b),std::fmt::Display::fmt),])"#
709 );
710 }
711
712 #[test]
727 fn test_include_bytes_expand() { 713 fn test_include_bytes_expand() {
728 let expanded = expand_builtin_macro( 714 let expanded = expand_builtin_macro(
729 r#" 715 r#"
@@ -745,12 +731,10 @@ mod tests {
745 r##" 731 r##"
746 #[rustc_builtin_macro] 732 #[rustc_builtin_macro]
747 macro_rules! concat {} 733 macro_rules! concat {}
748 concat!("foo", 0, r#"bar"#); 734 concat!("foo", "r", 0, r#"bar"#, false);
749 "##, 735 "##,
750 ); 736 );
751 737
752 assert_eq!(expanded, r#""foo0bar""#); 738 assert_eq!(expanded, r#""foor0barfalse""#);
753
754 // FIXME: `true`/`false` literals don't work.
755 } 739 }
756} 740}
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs
index 467516eb7..cb6e23320 100644
--- a/crates/hir_expand/src/db.rs
+++ b/crates/hir_expand/src/db.rs
@@ -173,7 +173,7 @@ fn macro_arg_text(db: &dyn AstDatabase, id: MacroCallId) -> Option<GreenNode> {
173 }; 173 };
174 let loc = db.lookup_intern_macro(id); 174 let loc = db.lookup_intern_macro(id);
175 let arg = loc.kind.arg(db)?; 175 let arg = loc.kind.arg(db)?;
176 Some(arg.green().clone()) 176 Some(arg.green().to_owned())
177} 177}
178 178
179fn macro_arg(db: &dyn AstDatabase, id: MacroCallId) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>> { 179fn macro_arg(db: &dyn AstDatabase, id: MacroCallId) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>> {
diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs
index 95d853b6d..c94fb580a 100644
--- a/crates/hir_expand/src/name.rs
+++ b/crates/hir_expand/src/name.rs
@@ -38,7 +38,7 @@ impl Name {
38 } 38 }
39 39
40 pub fn new_lifetime(lt: &ast::Lifetime) -> Name { 40 pub fn new_lifetime(lt: &ast::Lifetime) -> Name {
41 Self::new_text(lt.text().clone()) 41 Self::new_text(lt.text().into())
42 } 42 }
43 43
44 /// Shortcut to create inline plain text name 44 /// Shortcut to create inline plain text name
@@ -47,12 +47,12 @@ impl Name {
47 } 47 }
48 48
49 /// Resolve a name from the text of token. 49 /// Resolve a name from the text of token.
50 fn resolve(raw_text: &SmolStr) -> Name { 50 fn resolve(raw_text: &str) -> Name {
51 let raw_start = "r#"; 51 let raw_start = "r#";
52 if raw_text.as_str().starts_with(raw_start) { 52 if raw_text.starts_with(raw_start) {
53 Name::new_text(SmolStr::new(&raw_text[raw_start.len()..])) 53 Name::new_text(SmolStr::new(&raw_text[raw_start.len()..]))
54 } else { 54 } else {
55 Name::new_text(raw_text.clone()) 55 Name::new_text(raw_text.into())
56 } 56 }
57 } 57 }
58 58
@@ -186,6 +186,10 @@ pub mod known {
186 Neg, 186 Neg,
187 Not, 187 Not,
188 Index, 188 Index,
189 // Components of known path (function name)
190 filter_map,
191 next,
192 iter_mut,
189 // Builtin macros 193 // Builtin macros
190 file, 194 file,
191 column, 195 column,