]>
Commit | Line | Data |
---|---|---|
e1599b0c | 1 | //! Functions dealing with attributes and meta items. |
8faf50e0 | 2 | |
9fa01778 | 3 | use crate::ast; |
74b04a01 | 4 | use crate::ast::{AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute}; |
dfeec247 | 5 | use crate::ast::{Expr, GenericParam, Item, Lit, LitKind, Local, Stmt, StmtKind}; |
60c5eb7d | 6 | use crate::ast::{MacArgs, MacDelimiter, MetaItem, MetaItemKind, NestedMetaItem}; |
f9f354fc | 7 | use crate::ast::{Path, PathSegment}; |
9fa01778 | 8 | use crate::mut_visit::visit_clobber; |
9fa01778 | 9 | use crate::ptr::P; |
dfeec247 | 10 | use crate::token::{self, Token}; |
e74abb32 | 11 | use crate::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint}; |
9fa01778 | 12 | |
74b04a01 XL |
13 | use rustc_data_structures::sync::Lock; |
14 | use rustc_index::bit_set::GrowableBitSet; | |
15 | use rustc_span::edition::{Edition, DEFAULT_EDITION}; | |
dfeec247 | 16 | use rustc_span::source_map::{BytePos, Spanned}; |
f9f354fc | 17 | use rustc_span::symbol::{sym, Ident, Symbol}; |
dfeec247 | 18 | use rustc_span::Span; |
8faf50e0 | 19 | |
dfeec247 | 20 | use log::debug; |
8faf50e0 | 21 | use std::iter; |
9fa01778 | 22 | use std::ops::DerefMut; |
8faf50e0 | 23 | |
f035d41b XL |
24 | // Per-session global variables: this struct is stored in thread-local storage |
25 | // in such a way that it is accessible without any kind of handle to all | |
26 | // threads within the compilation session, but is not accessible outside the | |
27 | // session. | |
28 | pub struct SessionGlobals { | |
74b04a01 XL |
29 | used_attrs: Lock<GrowableBitSet<AttrId>>, |
30 | known_attrs: Lock<GrowableBitSet<AttrId>>, | |
f035d41b | 31 | span_session_globals: rustc_span::SessionGlobals, |
74b04a01 XL |
32 | } |
33 | ||
f035d41b XL |
34 | impl SessionGlobals { |
35 | fn new(edition: Edition) -> SessionGlobals { | |
36 | SessionGlobals { | |
74b04a01 XL |
37 | // We have no idea how many attributes there will be, so just |
38 | // initiate the vectors with 0 bits. We'll grow them as necessary. | |
39 | used_attrs: Lock::new(GrowableBitSet::new_empty()), | |
40 | known_attrs: Lock::new(GrowableBitSet::new_empty()), | |
f035d41b | 41 | span_session_globals: rustc_span::SessionGlobals::new(edition), |
74b04a01 XL |
42 | } |
43 | } | |
44 | } | |
45 | ||
f035d41b XL |
46 | pub fn with_session_globals<R>(edition: Edition, f: impl FnOnce() -> R) -> R { |
47 | let ast_session_globals = SessionGlobals::new(edition); | |
48 | SESSION_GLOBALS.set(&ast_session_globals, || { | |
49 | rustc_span::SESSION_GLOBALS.set(&ast_session_globals.span_session_globals, f) | |
50 | }) | |
74b04a01 XL |
51 | } |
52 | ||
f035d41b XL |
53 | pub fn with_default_session_globals<R>(f: impl FnOnce() -> R) -> R { |
54 | with_session_globals(DEFAULT_EDITION, f) | |
74b04a01 XL |
55 | } |
56 | ||
f035d41b | 57 | scoped_tls::scoped_thread_local!(pub static SESSION_GLOBALS: SessionGlobals); |
74b04a01 | 58 | |
8faf50e0 | 59 | pub fn mark_used(attr: &Attribute) { |
416331ca | 60 | debug!("marking {:?} as used", attr); |
f035d41b XL |
61 | SESSION_GLOBALS.with(|session_globals| { |
62 | session_globals.used_attrs.lock().insert(attr.id); | |
8faf50e0 XL |
63 | }); |
64 | } | |
65 | ||
66 | pub fn is_used(attr: &Attribute) -> bool { | |
f035d41b | 67 | SESSION_GLOBALS.with(|session_globals| session_globals.used_attrs.lock().contains(attr.id)) |
8faf50e0 XL |
68 | } |
69 | ||
70 | pub fn mark_known(attr: &Attribute) { | |
416331ca | 71 | debug!("marking {:?} as known", attr); |
f035d41b XL |
72 | SESSION_GLOBALS.with(|session_globals| { |
73 | session_globals.known_attrs.lock().insert(attr.id); | |
8faf50e0 XL |
74 | }); |
75 | } | |
76 | ||
77 | pub fn is_known(attr: &Attribute) -> bool { | |
f035d41b | 78 | SESSION_GLOBALS.with(|session_globals| session_globals.known_attrs.lock().contains(attr.id)) |
8faf50e0 XL |
79 | } |
80 | ||
8faf50e0 | 81 | pub fn is_known_lint_tool(m_item: Ident) -> bool { |
416331ca | 82 | [sym::clippy, sym::rustc].contains(&m_item.name) |
8faf50e0 XL |
83 | } |
84 | ||
85 | impl NestedMetaItem { | |
e1599b0c | 86 | /// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem`. |
8faf50e0 | 87 | pub fn meta_item(&self) -> Option<&MetaItem> { |
532ac7d7 XL |
88 | match *self { |
89 | NestedMetaItem::MetaItem(ref item) => Some(item), | |
dfeec247 | 90 | _ => None, |
8faf50e0 XL |
91 | } |
92 | } | |
93 | ||
e1599b0c | 94 | /// Returns the `Lit` if `self` is a `NestedMetaItem::Literal`s. |
8faf50e0 | 95 | pub fn literal(&self) -> Option<&Lit> { |
532ac7d7 XL |
96 | match *self { |
97 | NestedMetaItem::Literal(ref lit) => Some(lit), | |
dfeec247 | 98 | _ => None, |
8faf50e0 XL |
99 | } |
100 | } | |
101 | ||
9fa01778 | 102 | /// Returns `true` if this list item is a MetaItem with a name of `name`. |
48663c56 | 103 | pub fn check_name(&self, name: Symbol) -> bool { |
8faf50e0 XL |
104 | self.meta_item().map_or(false, |meta_item| meta_item.check_name(name)) |
105 | } | |
106 | ||
e1599b0c | 107 | /// For a single-segment meta item, returns its name; otherwise, returns `None`. |
9fa01778 XL |
108 | pub fn ident(&self) -> Option<Ident> { |
109 | self.meta_item().and_then(|meta_item| meta_item.ident()) | |
110 | } | |
48663c56 | 111 | pub fn name_or_empty(&self) -> Symbol { |
dc9dc135 | 112 | self.ident().unwrap_or(Ident::invalid()).name |
8faf50e0 XL |
113 | } |
114 | ||
e1599b0c XL |
115 | /// Gets the string value if `self` is a `MetaItem` and the `MetaItem` is a |
116 | /// `MetaItemKind::NameValue` variant containing a string, otherwise `None`. | |
8faf50e0 XL |
117 | pub fn value_str(&self) -> Option<Symbol> { |
118 | self.meta_item().and_then(|meta_item| meta_item.value_str()) | |
119 | } | |
120 | ||
e1599b0c | 121 | /// Returns a name and single literal value tuple of the `MetaItem`. |
f9f354fc | 122 | pub fn name_value_literal(&self) -> Option<(Symbol, &Lit)> { |
dfeec247 XL |
123 | self.meta_item().and_then(|meta_item| { |
124 | meta_item.meta_item_list().and_then(|meta_item_list| { | |
125 | if meta_item_list.len() == 1 { | |
126 | if let Some(ident) = meta_item.ident() { | |
127 | if let Some(lit) = meta_item_list[0].literal() { | |
128 | return Some((ident.name, lit)); | |
8faf50e0 XL |
129 | } |
130 | } | |
dfeec247 XL |
131 | } |
132 | None | |
133 | }) | |
134 | }) | |
8faf50e0 XL |
135 | } |
136 | ||
e1599b0c | 137 | /// Gets a list of inner meta items from a list `MetaItem` type. |
8faf50e0 XL |
138 | pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { |
139 | self.meta_item().and_then(|meta_item| meta_item.meta_item_list()) | |
140 | } | |
141 | ||
e1599b0c | 142 | /// Returns `true` if the variant is `MetaItem`. |
8faf50e0 XL |
143 | pub fn is_meta_item(&self) -> bool { |
144 | self.meta_item().is_some() | |
145 | } | |
146 | ||
e1599b0c | 147 | /// Returns `true` if the variant is `Literal`. |
8faf50e0 XL |
148 | pub fn is_literal(&self) -> bool { |
149 | self.literal().is_some() | |
150 | } | |
151 | ||
e1599b0c | 152 | /// Returns `true` if `self` is a `MetaItem` and the meta item is a word. |
8faf50e0 | 153 | pub fn is_word(&self) -> bool { |
9fa01778 | 154 | self.meta_item().map_or(false, |meta_item| meta_item.is_word()) |
8faf50e0 XL |
155 | } |
156 | ||
e1599b0c | 157 | /// Returns `true` if `self` is a `MetaItem` and the meta item is a `ValueString`. |
8faf50e0 XL |
158 | pub fn is_value_str(&self) -> bool { |
159 | self.value_str().is_some() | |
160 | } | |
161 | ||
e1599b0c | 162 | /// Returns `true` if `self` is a `MetaItem` and the meta item is a list. |
8faf50e0 XL |
163 | pub fn is_meta_item_list(&self) -> bool { |
164 | self.meta_item_list().is_some() | |
165 | } | |
166 | } | |
167 | ||
8faf50e0 | 168 | impl Attribute { |
60c5eb7d XL |
169 | pub fn has_name(&self, name: Symbol) -> bool { |
170 | match self.kind { | |
171 | AttrKind::Normal(ref item) => item.path == name, | |
dfeec247 | 172 | AttrKind::DocComment(_) => false, |
60c5eb7d XL |
173 | } |
174 | } | |
175 | ||
9fa01778 XL |
176 | /// Returns `true` if the attribute's path matches the argument. If it matches, then the |
177 | /// attribute is marked as used. | |
48663c56 | 178 | pub fn check_name(&self, name: Symbol) -> bool { |
60c5eb7d | 179 | let matches = self.has_name(name); |
8faf50e0 XL |
180 | if matches { |
181 | mark_used(self); | |
182 | } | |
183 | matches | |
184 | } | |
185 | ||
e1599b0c | 186 | /// For a single-segment attribute, returns its name; otherwise, returns `None`. |
9fa01778 | 187 | pub fn ident(&self) -> Option<Ident> { |
60c5eb7d XL |
188 | match self.kind { |
189 | AttrKind::Normal(ref item) => { | |
190 | if item.path.segments.len() == 1 { | |
191 | Some(item.path.segments[0].ident) | |
192 | } else { | |
193 | None | |
194 | } | |
195 | } | |
dfeec247 | 196 | AttrKind::DocComment(_) => None, |
9fa01778 XL |
197 | } |
198 | } | |
48663c56 | 199 | pub fn name_or_empty(&self) -> Symbol { |
dc9dc135 | 200 | self.ident().unwrap_or(Ident::invalid()).name |
8faf50e0 XL |
201 | } |
202 | ||
203 | pub fn value_str(&self) -> Option<Symbol> { | |
60c5eb7d | 204 | match self.kind { |
dfeec247 XL |
205 | AttrKind::Normal(ref item) => item.meta(self.span).and_then(|meta| meta.value_str()), |
206 | AttrKind::DocComment(..) => None, | |
60c5eb7d | 207 | } |
8faf50e0 XL |
208 | } |
209 | ||
210 | pub fn meta_item_list(&self) -> Option<Vec<NestedMetaItem>> { | |
60c5eb7d | 211 | match self.kind { |
dfeec247 XL |
212 | AttrKind::Normal(ref item) => match item.meta(self.span) { |
213 | Some(MetaItem { kind: MetaItemKind::List(list), .. }) => Some(list), | |
214 | _ => None, | |
215 | }, | |
60c5eb7d | 216 | AttrKind::DocComment(_) => None, |
8faf50e0 XL |
217 | } |
218 | } | |
219 | ||
220 | pub fn is_word(&self) -> bool { | |
60c5eb7d XL |
221 | if let AttrKind::Normal(item) = &self.kind { |
222 | matches!(item.args, MacArgs::Empty) | |
223 | } else { | |
224 | false | |
225 | } | |
8faf50e0 XL |
226 | } |
227 | ||
8faf50e0 XL |
228 | pub fn is_meta_item_list(&self) -> bool { |
229 | self.meta_item_list().is_some() | |
230 | } | |
231 | ||
e1599b0c | 232 | /// Indicates if the attribute is a `ValueString`. |
8faf50e0 XL |
233 | pub fn is_value_str(&self) -> bool { |
234 | self.value_str().is_some() | |
235 | } | |
8faf50e0 XL |
236 | } |
237 | ||
238 | impl MetaItem { | |
e1599b0c | 239 | /// For a single-segment meta item, returns its name; otherwise, returns `None`. |
9fa01778 | 240 | pub fn ident(&self) -> Option<Ident> { |
dfeec247 | 241 | if self.path.segments.len() == 1 { Some(self.path.segments[0].ident) } else { None } |
9fa01778 | 242 | } |
48663c56 | 243 | pub fn name_or_empty(&self) -> Symbol { |
dc9dc135 | 244 | self.ident().unwrap_or(Ident::invalid()).name |
8faf50e0 XL |
245 | } |
246 | ||
e1599b0c XL |
247 | // Example: |
248 | // #[attribute(name = "value")] | |
249 | // ^^^^^^^^^^^^^^ | |
a1dfa0c6 | 250 | pub fn name_value_literal(&self) -> Option<&Lit> { |
e74abb32 | 251 | match &self.kind { |
a1dfa0c6 XL |
252 | MetaItemKind::NameValue(v) => Some(v), |
253 | _ => None, | |
254 | } | |
255 | } | |
256 | ||
8faf50e0 | 257 | pub fn value_str(&self) -> Option<Symbol> { |
e74abb32 | 258 | match self.kind { |
dfeec247 XL |
259 | MetaItemKind::NameValue(ref v) => match v.kind { |
260 | LitKind::Str(ref s, _) => Some(*s), | |
261 | _ => None, | |
8faf50e0 | 262 | }, |
dfeec247 | 263 | _ => None, |
8faf50e0 XL |
264 | } |
265 | } | |
266 | ||
267 | pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { | |
e74abb32 | 268 | match self.kind { |
8faf50e0 | 269 | MetaItemKind::List(ref l) => Some(&l[..]), |
dfeec247 | 270 | _ => None, |
8faf50e0 XL |
271 | } |
272 | } | |
273 | ||
274 | pub fn is_word(&self) -> bool { | |
e74abb32 | 275 | match self.kind { |
8faf50e0 XL |
276 | MetaItemKind::Word => true, |
277 | _ => false, | |
278 | } | |
279 | } | |
280 | ||
48663c56 | 281 | pub fn check_name(&self, name: Symbol) -> bool { |
532ac7d7 | 282 | self.path == name |
8faf50e0 XL |
283 | } |
284 | ||
285 | pub fn is_value_str(&self) -> bool { | |
286 | self.value_str().is_some() | |
287 | } | |
288 | ||
289 | pub fn is_meta_item_list(&self) -> bool { | |
290 | self.meta_item_list().is_some() | |
291 | } | |
8faf50e0 XL |
292 | } |
293 | ||
e74abb32 | 294 | impl AttrItem { |
74b04a01 XL |
295 | pub fn span(&self) -> Span { |
296 | self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span)) | |
297 | } | |
298 | ||
60c5eb7d | 299 | pub fn meta(&self, span: Span) -> Option<MetaItem> { |
8faf50e0 | 300 | Some(MetaItem { |
532ac7d7 | 301 | path: self.path.clone(), |
60c5eb7d | 302 | kind: MetaItemKind::from_mac_args(&self.args)?, |
e74abb32 | 303 | span, |
8faf50e0 XL |
304 | }) |
305 | } | |
e74abb32 | 306 | } |
8faf50e0 | 307 | |
e74abb32 | 308 | impl Attribute { |
60c5eb7d XL |
309 | pub fn is_doc_comment(&self) -> bool { |
310 | match self.kind { | |
311 | AttrKind::Normal(_) => false, | |
312 | AttrKind::DocComment(_) => true, | |
313 | } | |
8faf50e0 XL |
314 | } |
315 | ||
dfeec247 XL |
316 | pub fn doc_str(&self) -> Option<Symbol> { |
317 | match self.kind { | |
318 | AttrKind::DocComment(symbol) => Some(symbol), | |
319 | AttrKind::Normal(ref item) if item.path == sym::doc => { | |
320 | item.meta(self.span).and_then(|meta| meta.value_str()) | |
321 | } | |
322 | _ => None, | |
323 | } | |
324 | } | |
325 | ||
60c5eb7d XL |
326 | pub fn get_normal_item(&self) -> &AttrItem { |
327 | match self.kind { | |
328 | AttrKind::Normal(ref item) => item, | |
dfeec247 | 329 | AttrKind::DocComment(_) => panic!("unexpected doc comment"), |
60c5eb7d XL |
330 | } |
331 | } | |
332 | ||
333 | pub fn unwrap_normal_item(self) -> AttrItem { | |
334 | match self.kind { | |
335 | AttrKind::Normal(item) => item, | |
dfeec247 | 336 | AttrKind::DocComment(_) => panic!("unexpected doc comment"), |
60c5eb7d XL |
337 | } |
338 | } | |
339 | ||
340 | /// Extracts the MetaItem from inside this Attribute. | |
341 | pub fn meta(&self) -> Option<MetaItem> { | |
342 | match self.kind { | |
343 | AttrKind::Normal(ref item) => item.meta(self.span), | |
dfeec247 | 344 | AttrKind::DocComment(..) => None, |
60c5eb7d | 345 | } |
8faf50e0 | 346 | } |
8faf50e0 XL |
347 | } |
348 | ||
349 | /* Constructors */ | |
350 | ||
e1599b0c XL |
351 | pub fn mk_name_value_item_str(ident: Ident, str: Symbol, str_span: Span) -> MetaItem { |
352 | let lit_kind = LitKind::Str(str, ast::StrStyle::Cooked); | |
353 | mk_name_value_item(ident, lit_kind, str_span) | |
8faf50e0 XL |
354 | } |
355 | ||
416331ca | 356 | pub fn mk_name_value_item(ident: Ident, lit_kind: LitKind, lit_span: Span) -> MetaItem { |
48663c56 | 357 | let lit = Lit::from_lit_kind(lit_kind, lit_span); |
416331ca | 358 | let span = ident.span.to(lit_span); |
e74abb32 | 359 | MetaItem { path: Path::from_ident(ident), span, kind: MetaItemKind::NameValue(lit) } |
8faf50e0 XL |
360 | } |
361 | ||
416331ca | 362 | pub fn mk_list_item(ident: Ident, items: Vec<NestedMetaItem>) -> MetaItem { |
e74abb32 | 363 | MetaItem { path: Path::from_ident(ident), span: ident.span, kind: MetaItemKind::List(items) } |
8faf50e0 XL |
364 | } |
365 | ||
366 | pub fn mk_word_item(ident: Ident) -> MetaItem { | |
e74abb32 | 367 | MetaItem { path: Path::from_ident(ident), span: ident.span, kind: MetaItemKind::Word } |
8faf50e0 XL |
368 | } |
369 | ||
370 | pub fn mk_nested_word_item(ident: Ident) -> NestedMetaItem { | |
532ac7d7 | 371 | NestedMetaItem::MetaItem(mk_word_item(ident)) |
8faf50e0 XL |
372 | } |
373 | ||
416331ca | 374 | crate fn mk_attr_id() -> AttrId { |
ba9703b0 | 375 | use std::sync::atomic::AtomicU32; |
8faf50e0 XL |
376 | use std::sync::atomic::Ordering; |
377 | ||
ba9703b0 | 378 | static NEXT_ATTR_ID: AtomicU32 = AtomicU32::new(0); |
8faf50e0 XL |
379 | |
380 | let id = NEXT_ATTR_ID.fetch_add(1, Ordering::SeqCst); | |
ba9703b0 XL |
381 | assert!(id != u32::MAX); |
382 | AttrId::from_u32(id) | |
8faf50e0 XL |
383 | } |
384 | ||
60c5eb7d XL |
385 | pub fn mk_attr(style: AttrStyle, path: Path, args: MacArgs, span: Span) -> Attribute { |
386 | mk_attr_from_item(style, AttrItem { path, args }, span) | |
387 | } | |
388 | ||
389 | pub fn mk_attr_from_item(style: AttrStyle, item: AttrItem, span: Span) -> Attribute { | |
dfeec247 | 390 | Attribute { kind: AttrKind::Normal(item), id: mk_attr_id(), style, span } |
8faf50e0 XL |
391 | } |
392 | ||
e1599b0c XL |
393 | /// Returns an inner attribute with the given value and span. |
394 | pub fn mk_attr_inner(item: MetaItem) -> Attribute { | |
60c5eb7d | 395 | mk_attr(AttrStyle::Inner, item.path, item.kind.mac_args(item.span), item.span) |
e1599b0c XL |
396 | } |
397 | ||
8faf50e0 | 398 | /// Returns an outer attribute with the given value and span. |
416331ca | 399 | pub fn mk_attr_outer(item: MetaItem) -> Attribute { |
60c5eb7d | 400 | mk_attr(AttrStyle::Outer, item.path, item.kind.mac_args(item.span), item.span) |
8faf50e0 XL |
401 | } |
402 | ||
60c5eb7d | 403 | pub fn mk_doc_comment(style: AttrStyle, comment: Symbol, span: Span) -> Attribute { |
dfeec247 | 404 | Attribute { kind: AttrKind::DocComment(comment), id: mk_attr_id(), style, span } |
8faf50e0 XL |
405 | } |
406 | ||
48663c56 | 407 | pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool { |
dfeec247 | 408 | items.iter().any(|item| item.check_name(name)) |
8faf50e0 XL |
409 | } |
410 | ||
48663c56 | 411 | pub fn contains_name(attrs: &[Attribute], name: Symbol) -> bool { |
dfeec247 | 412 | attrs.iter().any(|item| item.check_name(name)) |
8faf50e0 XL |
413 | } |
414 | ||
416331ca | 415 | pub fn find_by_name(attrs: &[Attribute], name: Symbol) -> Option<&Attribute> { |
8faf50e0 XL |
416 | attrs.iter().find(|attr| attr.check_name(name)) |
417 | } | |
418 | ||
dfeec247 | 419 | pub fn filter_by_name(attrs: &[Attribute], name: Symbol) -> impl Iterator<Item = &Attribute> { |
a1dfa0c6 XL |
420 | attrs.iter().filter(move |attr| attr.check_name(name)) |
421 | } | |
422 | ||
48663c56 | 423 | pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: Symbol) -> Option<Symbol> { |
dfeec247 | 424 | attrs.iter().find(|at| at.check_name(name)).and_then(|at| at.value_str()) |
8faf50e0 XL |
425 | } |
426 | ||
427 | impl MetaItem { | |
e74abb32 | 428 | fn token_trees_and_joints(&self) -> Vec<TreeAndJoint> { |
8faf50e0 XL |
429 | let mut idents = vec![]; |
430 | let mut last_pos = BytePos(0 as u32); | |
532ac7d7 | 431 | for (i, segment) in self.path.segments.iter().enumerate() { |
8faf50e0 XL |
432 | let is_first = i == 0; |
433 | if !is_first { | |
dfeec247 XL |
434 | let mod_sep_span = |
435 | Span::new(last_pos, segment.ident.span.lo(), segment.ident.span.ctxt()); | |
dc9dc135 | 436 | idents.push(TokenTree::token(token::ModSep, mod_sep_span).into()); |
8faf50e0 | 437 | } |
dc9dc135 | 438 | idents.push(TokenTree::Token(Token::from_ast_ident(segment.ident)).into()); |
8faf50e0 XL |
439 | last_pos = segment.ident.span.hi(); |
440 | } | |
e74abb32 XL |
441 | idents.extend(self.kind.token_trees_and_joints(self.span)); |
442 | idents | |
8faf50e0 XL |
443 | } |
444 | ||
445 | fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItem> | |
dfeec247 XL |
446 | where |
447 | I: Iterator<Item = TokenTree>, | |
8faf50e0 XL |
448 | { |
449 | // FIXME: Share code with `parse_path`. | |
74b04a01 | 450 | let path = match tokens.next().map(TokenTree::uninterpolate) { |
ba9703b0 XL |
451 | Some(TokenTree::Token(Token { |
452 | kind: kind @ (token::Ident(..) | token::ModSep), | |
453 | span, | |
454 | })) => 'arm: { | |
dc9dc135 | 455 | let mut segments = if let token::Ident(name, _) = kind { |
dfeec247 XL |
456 | if let Some(TokenTree::Token(Token { kind: token::ModSep, .. })) = tokens.peek() |
457 | { | |
9fa01778 | 458 | tokens.next(); |
dc9dc135 | 459 | vec![PathSegment::from_ident(Ident::new(name, span))] |
9fa01778 | 460 | } else { |
dc9dc135 | 461 | break 'arm Path::from_ident(Ident::new(name, span)); |
8faf50e0 | 462 | } |
8faf50e0 | 463 | } else { |
9fa01778 XL |
464 | vec![PathSegment::path_root(span)] |
465 | }; | |
466 | loop { | |
dfeec247 | 467 | if let Some(TokenTree::Token(Token { kind: token::Ident(name, _), span })) = |
74b04a01 | 468 | tokens.next().map(TokenTree::uninterpolate) |
dfeec247 | 469 | { |
dc9dc135 | 470 | segments.push(PathSegment::from_ident(Ident::new(name, span))); |
9fa01778 XL |
471 | } else { |
472 | return None; | |
473 | } | |
dfeec247 XL |
474 | if let Some(TokenTree::Token(Token { kind: token::ModSep, .. })) = tokens.peek() |
475 | { | |
9fa01778 XL |
476 | tokens.next(); |
477 | } else { | |
478 | break; | |
479 | } | |
8faf50e0 | 480 | } |
9fa01778 XL |
481 | let span = span.with_hi(segments.last().unwrap().ident.span.hi()); |
482 | Path { span, segments } | |
8faf50e0 | 483 | } |
dc9dc135 | 484 | Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. })) => match *nt { |
e74abb32 | 485 | token::Nonterminal::NtMeta(ref item) => return item.meta(item.path.span), |
8faf50e0 XL |
486 | token::Nonterminal::NtPath(ref path) => path.clone(), |
487 | _ => return None, | |
488 | }, | |
489 | _ => return None, | |
490 | }; | |
491 | let list_closing_paren_pos = tokens.peek().map(|tt| tt.span().hi()); | |
e74abb32 XL |
492 | let kind = MetaItemKind::from_tokens(tokens)?; |
493 | let hi = match kind { | |
8faf50e0 | 494 | MetaItemKind::NameValue(ref lit) => lit.span.hi(), |
532ac7d7 XL |
495 | MetaItemKind::List(..) => list_closing_paren_pos.unwrap_or(path.span.hi()), |
496 | _ => path.span.hi(), | |
8faf50e0 | 497 | }; |
532ac7d7 | 498 | let span = path.span.with_hi(hi); |
e74abb32 | 499 | Some(MetaItem { path, kind, span }) |
8faf50e0 XL |
500 | } |
501 | } | |
502 | ||
503 | impl MetaItemKind { | |
60c5eb7d XL |
504 | pub fn mac_args(&self, span: Span) -> MacArgs { |
505 | match self { | |
506 | MetaItemKind::Word => MacArgs::Empty, | |
507 | MetaItemKind::NameValue(lit) => MacArgs::Eq(span, lit.token_tree().into()), | |
508 | MetaItemKind::List(list) => { | |
509 | let mut tts = Vec::new(); | |
510 | for (i, item) in list.iter().enumerate() { | |
511 | if i > 0 { | |
512 | tts.push(TokenTree::token(token::Comma, span).into()); | |
513 | } | |
514 | tts.extend(item.token_trees_and_joints()) | |
515 | } | |
516 | MacArgs::Delimited( | |
dfeec247 XL |
517 | DelimSpan::from_single(span), |
518 | MacDelimiter::Parenthesis, | |
519 | TokenStream::new(tts), | |
60c5eb7d XL |
520 | ) |
521 | } | |
522 | } | |
523 | } | |
524 | ||
525 | fn token_trees_and_joints(&self, span: Span) -> Vec<TreeAndJoint> { | |
8faf50e0 | 526 | match *self { |
e74abb32 | 527 | MetaItemKind::Word => vec![], |
8faf50e0 | 528 | MetaItemKind::NameValue(ref lit) => { |
dfeec247 | 529 | vec![TokenTree::token(token::Eq, span).into(), lit.token_tree().into()] |
8faf50e0 XL |
530 | } |
531 | MetaItemKind::List(ref list) => { | |
532 | let mut tokens = Vec::new(); | |
533 | for (i, item) in list.iter().enumerate() { | |
534 | if i > 0 { | |
dc9dc135 | 535 | tokens.push(TokenTree::token(token::Comma, span).into()); |
8faf50e0 | 536 | } |
e74abb32 | 537 | tokens.extend(item.token_trees_and_joints()) |
8faf50e0 | 538 | } |
e74abb32 XL |
539 | vec![ |
540 | TokenTree::Delimited( | |
541 | DelimSpan::from_single(span), | |
542 | token::Paren, | |
74b04a01 | 543 | TokenStream::new(tokens), |
dfeec247 XL |
544 | ) |
545 | .into(), | |
e74abb32 | 546 | ] |
8faf50e0 XL |
547 | } |
548 | } | |
549 | } | |
550 | ||
60c5eb7d XL |
551 | fn list_from_tokens(tokens: TokenStream) -> Option<MetaItemKind> { |
552 | let mut tokens = tokens.into_trees().peekable(); | |
8faf50e0 XL |
553 | let mut result = Vec::new(); |
554 | while let Some(..) = tokens.peek() { | |
532ac7d7 XL |
555 | let item = NestedMetaItem::from_tokens(&mut tokens)?; |
556 | result.push(item); | |
8faf50e0 | 557 | match tokens.next() { |
dc9dc135 | 558 | None | Some(TokenTree::Token(Token { kind: token::Comma, .. })) => {} |
8faf50e0 XL |
559 | _ => return None, |
560 | } | |
561 | } | |
562 | Some(MetaItemKind::List(result)) | |
563 | } | |
60c5eb7d XL |
564 | |
565 | fn name_value_from_tokens( | |
566 | tokens: &mut impl Iterator<Item = TokenTree>, | |
567 | ) -> Option<MetaItemKind> { | |
568 | match tokens.next() { | |
f035d41b XL |
569 | Some(TokenTree::Delimited(_, token::NoDelim, inner_tokens)) => { |
570 | MetaItemKind::name_value_from_tokens(&mut inner_tokens.trees()) | |
571 | } | |
dfeec247 XL |
572 | Some(TokenTree::Token(token)) => { |
573 | Lit::from_token(&token).ok().map(MetaItemKind::NameValue) | |
574 | } | |
60c5eb7d XL |
575 | _ => None, |
576 | } | |
577 | } | |
578 | ||
579 | fn from_mac_args(args: &MacArgs) -> Option<MetaItemKind> { | |
580 | match args { | |
dfeec247 XL |
581 | MacArgs::Delimited(_, MacDelimiter::Parenthesis, tokens) => { |
582 | MetaItemKind::list_from_tokens(tokens.clone()) | |
583 | } | |
60c5eb7d XL |
584 | MacArgs::Delimited(..) => None, |
585 | MacArgs::Eq(_, tokens) => { | |
586 | assert!(tokens.len() == 1); | |
587 | MetaItemKind::name_value_from_tokens(&mut tokens.trees()) | |
588 | } | |
589 | MacArgs::Empty => Some(MetaItemKind::Word), | |
590 | } | |
591 | } | |
592 | ||
593 | fn from_tokens( | |
594 | tokens: &mut iter::Peekable<impl Iterator<Item = TokenTree>>, | |
595 | ) -> Option<MetaItemKind> { | |
596 | match tokens.peek() { | |
597 | Some(TokenTree::Delimited(_, token::Paren, inner_tokens)) => { | |
598 | let inner_tokens = inner_tokens.clone(); | |
599 | tokens.next(); | |
600 | MetaItemKind::list_from_tokens(inner_tokens) | |
601 | } | |
602 | Some(TokenTree::Delimited(..)) => None, | |
603 | Some(TokenTree::Token(Token { kind: token::Eq, .. })) => { | |
604 | tokens.next(); | |
605 | MetaItemKind::name_value_from_tokens(tokens) | |
606 | } | |
607 | _ => Some(MetaItemKind::Word), | |
608 | } | |
609 | } | |
8faf50e0 XL |
610 | } |
611 | ||
532ac7d7 XL |
612 | impl NestedMetaItem { |
613 | pub fn span(&self) -> Span { | |
8faf50e0 | 614 | match *self { |
532ac7d7 XL |
615 | NestedMetaItem::MetaItem(ref item) => item.span, |
616 | NestedMetaItem::Literal(ref lit) => lit.span, | |
8faf50e0 XL |
617 | } |
618 | } | |
619 | ||
e74abb32 | 620 | fn token_trees_and_joints(&self) -> Vec<TreeAndJoint> { |
8faf50e0 | 621 | match *self { |
e74abb32 XL |
622 | NestedMetaItem::MetaItem(ref item) => item.token_trees_and_joints(), |
623 | NestedMetaItem::Literal(ref lit) => vec![lit.token_tree().into()], | |
8faf50e0 XL |
624 | } |
625 | } | |
626 | ||
532ac7d7 | 627 | fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<NestedMetaItem> |
dfeec247 XL |
628 | where |
629 | I: Iterator<Item = TokenTree>, | |
8faf50e0 | 630 | { |
f035d41b XL |
631 | match tokens.peek() { |
632 | Some(TokenTree::Token(token)) => { | |
633 | if let Ok(lit) = Lit::from_token(token) { | |
634 | tokens.next(); | |
635 | return Some(NestedMetaItem::Literal(lit)); | |
636 | } | |
637 | } | |
638 | Some(TokenTree::Delimited(_, token::NoDelim, inner_tokens)) => { | |
639 | let inner_tokens = inner_tokens.clone(); | |
8faf50e0 | 640 | tokens.next(); |
f035d41b | 641 | return NestedMetaItem::from_tokens(&mut inner_tokens.into_trees().peekable()); |
8faf50e0 | 642 | } |
f035d41b | 643 | _ => {} |
8faf50e0 | 644 | } |
532ac7d7 | 645 | MetaItem::from_tokens(tokens).map(NestedMetaItem::MetaItem) |
8faf50e0 XL |
646 | } |
647 | } | |
648 | ||
8faf50e0 | 649 | pub trait HasAttrs: Sized { |
74b04a01 XL |
650 | fn attrs(&self) -> &[Attribute]; |
651 | fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)); | |
8faf50e0 XL |
652 | } |
653 | ||
654 | impl<T: HasAttrs> HasAttrs for Spanned<T> { | |
74b04a01 | 655 | fn attrs(&self) -> &[Attribute] { |
dfeec247 XL |
656 | self.node.attrs() |
657 | } | |
74b04a01 | 658 | fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) { |
9fa01778 | 659 | self.node.visit_attrs(f); |
8faf50e0 XL |
660 | } |
661 | } | |
662 | ||
663 | impl HasAttrs for Vec<Attribute> { | |
664 | fn attrs(&self) -> &[Attribute] { | |
665 | self | |
666 | } | |
74b04a01 | 667 | fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) { |
8faf50e0 XL |
668 | f(self) |
669 | } | |
670 | } | |
671 | ||
dfeec247 | 672 | impl HasAttrs for AttrVec { |
8faf50e0 XL |
673 | fn attrs(&self) -> &[Attribute] { |
674 | self | |
675 | } | |
74b04a01 | 676 | fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) { |
9fa01778 XL |
677 | visit_clobber(self, |this| { |
678 | let mut vec = this.into(); | |
679 | f(&mut vec); | |
680 | vec.into() | |
681 | }); | |
8faf50e0 XL |
682 | } |
683 | } | |
684 | ||
685 | impl<T: HasAttrs + 'static> HasAttrs for P<T> { | |
686 | fn attrs(&self) -> &[Attribute] { | |
687 | (**self).attrs() | |
688 | } | |
74b04a01 | 689 | fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) { |
9fa01778 | 690 | (**self).visit_attrs(f); |
8faf50e0 XL |
691 | } |
692 | } | |
693 | ||
694 | impl HasAttrs for StmtKind { | |
695 | fn attrs(&self) -> &[Attribute] { | |
696 | match *self { | |
697 | StmtKind::Local(ref local) => local.attrs(), | |
8faf50e0 | 698 | StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => expr.attrs(), |
74b04a01 | 699 | StmtKind::Empty | StmtKind::Item(..) => &[], |
ba9703b0 | 700 | StmtKind::MacCall(ref mac) => { |
8faf50e0 XL |
701 | let (_, _, ref attrs) = **mac; |
702 | attrs.attrs() | |
703 | } | |
704 | } | |
705 | } | |
706 | ||
74b04a01 | 707 | fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) { |
8faf50e0 | 708 | match self { |
9fa01778 | 709 | StmtKind::Local(local) => local.visit_attrs(f), |
74b04a01 XL |
710 | StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.visit_attrs(f), |
711 | StmtKind::Empty | StmtKind::Item(..) => {} | |
ba9703b0 | 712 | StmtKind::MacCall(mac) => { |
9fa01778 XL |
713 | let (_mac, _style, attrs) = mac.deref_mut(); |
714 | attrs.visit_attrs(f); | |
715 | } | |
8faf50e0 XL |
716 | } |
717 | } | |
718 | } | |
719 | ||
720 | impl HasAttrs for Stmt { | |
9fa01778 | 721 | fn attrs(&self) -> &[ast::Attribute] { |
e74abb32 | 722 | self.kind.attrs() |
9fa01778 XL |
723 | } |
724 | ||
74b04a01 | 725 | fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) { |
e74abb32 | 726 | self.kind.visit_attrs(f); |
8faf50e0 XL |
727 | } |
728 | } | |
729 | ||
8faf50e0 XL |
730 | macro_rules! derive_has_attrs { |
731 | ($($ty:path),*) => { $( | |
732 | impl HasAttrs for $ty { | |
733 | fn attrs(&self) -> &[Attribute] { | |
734 | &self.attrs | |
735 | } | |
736 | ||
74b04a01 | 737 | fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) { |
9fa01778 | 738 | self.attrs.visit_attrs(f); |
8faf50e0 XL |
739 | } |
740 | } | |
741 | )* } | |
742 | } | |
743 | ||
744 | derive_has_attrs! { | |
74b04a01 XL |
745 | Item, Expr, Local, ast::AssocItem, ast::ForeignItem, ast::StructField, ast::Arm, |
746 | ast::Field, ast::FieldPat, ast::Variant, ast::Param, GenericParam | |
8faf50e0 | 747 | } |