]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_expand/src/placeholders.rs
avoid many `&str` to `String` conversions with `MultiSpan::push_span_label`
[rust.git] / compiler / rustc_expand / src / placeholders.rs
1 use crate::expand::{AstFragment, AstFragmentKind};
2
3 use rustc_ast as ast;
4 use rustc_ast::mut_visit::*;
5 use rustc_ast::ptr::P;
6 use rustc_span::source_map::DUMMY_SP;
7 use rustc_span::symbol::Ident;
8
9 use smallvec::{smallvec, SmallVec};
10
11 use rustc_data_structures::fx::FxHashMap;
12
13 pub fn placeholder(
14     kind: AstFragmentKind,
15     id: ast::NodeId,
16     vis: Option<ast::Visibility>,
17 ) -> AstFragment {
18     fn mac_placeholder() -> ast::MacCall {
19         ast::MacCall {
20             path: ast::Path { span: DUMMY_SP, segments: Vec::new(), tokens: None },
21             args: P(ast::MacArgs::Empty),
22             prior_type_ascription: None,
23         }
24     }
25
26     let ident = Ident::empty();
27     let attrs = Vec::new();
28     let vis = vis.unwrap_or(ast::Visibility {
29         span: DUMMY_SP,
30         kind: ast::VisibilityKind::Inherited,
31         tokens: None,
32     });
33     let span = DUMMY_SP;
34     let expr_placeholder = || {
35         P(ast::Expr {
36             id,
37             span,
38             attrs: ast::AttrVec::new(),
39             kind: ast::ExprKind::MacCall(mac_placeholder()),
40             tokens: None,
41         })
42     };
43     let ty =
44         || P(ast::Ty { id, kind: ast::TyKind::MacCall(mac_placeholder()), span, tokens: None });
45     let pat =
46         || P(ast::Pat { id, kind: ast::PatKind::MacCall(mac_placeholder()), span, tokens: None });
47
48     match kind {
49         AstFragmentKind::Crate => AstFragment::Crate(ast::Crate {
50             attrs: Default::default(),
51             items: Default::default(),
52             spans: ast::ModSpans { inner_span: span, ..Default::default() },
53             id,
54             is_placeholder: true,
55         }),
56         AstFragmentKind::Expr => AstFragment::Expr(expr_placeholder()),
57         AstFragmentKind::OptExpr => AstFragment::OptExpr(Some(expr_placeholder())),
58         AstFragmentKind::Items => AstFragment::Items(smallvec![P(ast::Item {
59             id,
60             span,
61             ident,
62             vis,
63             attrs,
64             kind: ast::ItemKind::MacCall(mac_placeholder()),
65             tokens: None,
66         })]),
67         AstFragmentKind::TraitItems => AstFragment::TraitItems(smallvec![P(ast::AssocItem {
68             id,
69             span,
70             ident,
71             vis,
72             attrs,
73             kind: ast::AssocItemKind::MacCall(mac_placeholder()),
74             tokens: None,
75         })]),
76         AstFragmentKind::ImplItems => AstFragment::ImplItems(smallvec![P(ast::AssocItem {
77             id,
78             span,
79             ident,
80             vis,
81             attrs,
82             kind: ast::AssocItemKind::MacCall(mac_placeholder()),
83             tokens: None,
84         })]),
85         AstFragmentKind::ForeignItems => {
86             AstFragment::ForeignItems(smallvec![P(ast::ForeignItem {
87                 id,
88                 span,
89                 ident,
90                 vis,
91                 attrs,
92                 kind: ast::ForeignItemKind::MacCall(mac_placeholder()),
93                 tokens: None,
94             })])
95         }
96         AstFragmentKind::Pat => AstFragment::Pat(P(ast::Pat {
97             id,
98             span,
99             kind: ast::PatKind::MacCall(mac_placeholder()),
100             tokens: None,
101         })),
102         AstFragmentKind::Ty => AstFragment::Ty(P(ast::Ty {
103             id,
104             span,
105             kind: ast::TyKind::MacCall(mac_placeholder()),
106             tokens: None,
107         })),
108         AstFragmentKind::Stmts => AstFragment::Stmts(smallvec![{
109             let mac = P(ast::MacCallStmt {
110                 mac: mac_placeholder(),
111                 style: ast::MacStmtStyle::Braces,
112                 attrs: ast::AttrVec::new(),
113                 tokens: None,
114             });
115             ast::Stmt { id, span, kind: ast::StmtKind::MacCall(mac) }
116         }]),
117         AstFragmentKind::Arms => AstFragment::Arms(smallvec![ast::Arm {
118             attrs: Default::default(),
119             body: expr_placeholder(),
120             guard: None,
121             id,
122             pat: pat(),
123             span,
124             is_placeholder: true,
125         }]),
126         AstFragmentKind::ExprFields => AstFragment::ExprFields(smallvec![ast::ExprField {
127             attrs: Default::default(),
128             expr: expr_placeholder(),
129             id,
130             ident,
131             is_shorthand: false,
132             span,
133             is_placeholder: true,
134         }]),
135         AstFragmentKind::PatFields => AstFragment::PatFields(smallvec![ast::PatField {
136             attrs: Default::default(),
137             id,
138             ident,
139             is_shorthand: false,
140             pat: pat(),
141             span,
142             is_placeholder: true,
143         }]),
144         AstFragmentKind::GenericParams => AstFragment::GenericParams(smallvec![{
145             ast::GenericParam {
146                 attrs: Default::default(),
147                 bounds: Default::default(),
148                 id,
149                 ident,
150                 is_placeholder: true,
151                 kind: ast::GenericParamKind::Lifetime,
152                 colon_span: None,
153             }
154         }]),
155         AstFragmentKind::Params => AstFragment::Params(smallvec![ast::Param {
156             attrs: Default::default(),
157             id,
158             pat: pat(),
159             span,
160             ty: ty(),
161             is_placeholder: true,
162         }]),
163         AstFragmentKind::FieldDefs => AstFragment::FieldDefs(smallvec![ast::FieldDef {
164             attrs: Default::default(),
165             id,
166             ident: None,
167             span,
168             ty: ty(),
169             vis,
170             is_placeholder: true,
171         }]),
172         AstFragmentKind::Variants => AstFragment::Variants(smallvec![ast::Variant {
173             attrs: Default::default(),
174             data: ast::VariantData::Struct(Default::default(), false),
175             disr_expr: None,
176             id,
177             ident,
178             span,
179             vis,
180             is_placeholder: true,
181         }]),
182     }
183 }
184
185 #[derive(Default)]
186 pub struct PlaceholderExpander {
187     expanded_fragments: FxHashMap<ast::NodeId, AstFragment>,
188 }
189
190 impl PlaceholderExpander {
191     pub fn add(&mut self, id: ast::NodeId, mut fragment: AstFragment) {
192         fragment.mut_visit_with(self);
193         self.expanded_fragments.insert(id, fragment);
194     }
195
196     fn remove(&mut self, id: ast::NodeId) -> AstFragment {
197         self.expanded_fragments.remove(&id).unwrap()
198     }
199 }
200
201 impl MutVisitor for PlaceholderExpander {
202     fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> {
203         if arm.is_placeholder {
204             self.remove(arm.id).make_arms()
205         } else {
206             noop_flat_map_arm(arm, self)
207         }
208     }
209
210     fn flat_map_expr_field(&mut self, field: ast::ExprField) -> SmallVec<[ast::ExprField; 1]> {
211         if field.is_placeholder {
212             self.remove(field.id).make_expr_fields()
213         } else {
214             noop_flat_map_expr_field(field, self)
215         }
216     }
217
218     fn flat_map_pat_field(&mut self, fp: ast::PatField) -> SmallVec<[ast::PatField; 1]> {
219         if fp.is_placeholder {
220             self.remove(fp.id).make_pat_fields()
221         } else {
222             noop_flat_map_pat_field(fp, self)
223         }
224     }
225
226     fn flat_map_generic_param(
227         &mut self,
228         param: ast::GenericParam,
229     ) -> SmallVec<[ast::GenericParam; 1]> {
230         if param.is_placeholder {
231             self.remove(param.id).make_generic_params()
232         } else {
233             noop_flat_map_generic_param(param, self)
234         }
235     }
236
237     fn flat_map_param(&mut self, p: ast::Param) -> SmallVec<[ast::Param; 1]> {
238         if p.is_placeholder {
239             self.remove(p.id).make_params()
240         } else {
241             noop_flat_map_param(p, self)
242         }
243     }
244
245     fn flat_map_field_def(&mut self, sf: ast::FieldDef) -> SmallVec<[ast::FieldDef; 1]> {
246         if sf.is_placeholder {
247             self.remove(sf.id).make_field_defs()
248         } else {
249             noop_flat_map_field_def(sf, self)
250         }
251     }
252
253     fn flat_map_variant(&mut self, variant: ast::Variant) -> SmallVec<[ast::Variant; 1]> {
254         if variant.is_placeholder {
255             self.remove(variant.id).make_variants()
256         } else {
257             noop_flat_map_variant(variant, self)
258         }
259     }
260
261     fn flat_map_item(&mut self, item: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
262         match item.kind {
263             ast::ItemKind::MacCall(_) => self.remove(item.id).make_items(),
264             _ => noop_flat_map_item(item, self),
265         }
266     }
267
268     fn flat_map_trait_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
269         match item.kind {
270             ast::AssocItemKind::MacCall(_) => self.remove(item.id).make_trait_items(),
271             _ => noop_flat_map_assoc_item(item, self),
272         }
273     }
274
275     fn flat_map_impl_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
276         match item.kind {
277             ast::AssocItemKind::MacCall(_) => self.remove(item.id).make_impl_items(),
278             _ => noop_flat_map_assoc_item(item, self),
279         }
280     }
281
282     fn flat_map_foreign_item(
283         &mut self,
284         item: P<ast::ForeignItem>,
285     ) -> SmallVec<[P<ast::ForeignItem>; 1]> {
286         match item.kind {
287             ast::ForeignItemKind::MacCall(_) => self.remove(item.id).make_foreign_items(),
288             _ => noop_flat_map_foreign_item(item, self),
289         }
290     }
291
292     fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
293         match expr.kind {
294             ast::ExprKind::MacCall(_) => *expr = self.remove(expr.id).make_expr(),
295             _ => noop_visit_expr(expr, self),
296         }
297     }
298
299     fn filter_map_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
300         match expr.kind {
301             ast::ExprKind::MacCall(_) => self.remove(expr.id).make_opt_expr(),
302             _ => noop_filter_map_expr(expr, self),
303         }
304     }
305
306     fn flat_map_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> {
307         let (style, mut stmts) = match stmt.kind {
308             ast::StmtKind::MacCall(mac) => (mac.style, self.remove(stmt.id).make_stmts()),
309             _ => return noop_flat_map_stmt(stmt, self),
310         };
311
312         if style == ast::MacStmtStyle::Semicolon {
313             // Implement the proposal described in
314             // https://github.com/rust-lang/rust/issues/61733#issuecomment-509626449
315             //
316             // The macro invocation expands to the list of statements. If the
317             // list of statements is empty, then 'parse' the trailing semicolon
318             // on the original invocation as an empty statement. That is:
319             //
320             // `empty();` is parsed as a single `StmtKind::Empty`
321             //
322             // If the list of statements is non-empty, see if the final
323             // statement already has a trailing semicolon.
324             //
325             // If it doesn't have a semicolon, then 'parse' the trailing
326             // semicolon from the invocation as part of the final statement,
327             // using `stmt.add_trailing_semicolon()`
328             //
329             // If it does have a semicolon, then 'parse' the trailing semicolon
330             // from the invocation as a new StmtKind::Empty
331
332             // FIXME: We will need to preserve the original semicolon token and
333             // span as part of #15701
334             let empty_stmt =
335                 ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Empty, span: DUMMY_SP };
336
337             if let Some(stmt) = stmts.pop() {
338                 if stmt.has_trailing_semicolon() {
339                     stmts.push(stmt);
340                     stmts.push(empty_stmt);
341                 } else {
342                     stmts.push(stmt.add_trailing_semicolon());
343                 }
344             } else {
345                 stmts.push(empty_stmt);
346             }
347         }
348
349         stmts
350     }
351
352     fn visit_pat(&mut self, pat: &mut P<ast::Pat>) {
353         match pat.kind {
354             ast::PatKind::MacCall(_) => *pat = self.remove(pat.id).make_pat(),
355             _ => noop_visit_pat(pat, self),
356         }
357     }
358
359     fn visit_ty(&mut self, ty: &mut P<ast::Ty>) {
360         match ty.kind {
361             ast::TyKind::MacCall(_) => *ty = self.remove(ty.id).make_ty(),
362             _ => noop_visit_ty(ty, self),
363         }
364     }
365
366     fn visit_crate(&mut self, krate: &mut ast::Crate) {
367         if krate.is_placeholder {
368             *krate = self.remove(krate.id).make_crate();
369         } else {
370             noop_visit_crate(krate, self)
371         }
372     }
373 }