diff options
| author | Nicholas Nethercote <nnethercote@mozilla.com> | 2019-10-24 06:33:12 +1100 |
|---|---|---|
| committer | Nicholas Nethercote <nnethercote@mozilla.com> | 2019-11-06 23:05:07 +1100 |
| commit | eea6f23a0ed67fd8c6b8e1b02cda3628fee56b2f (patch) | |
| tree | effdb244138f311440b21c9fd52e4028edb575ea /src/libsyntax/attr | |
| parent | 69bc4aba785e071740d2d46f109623b9951aae5d (diff) | |
| download | rust-eea6f23a0ed67fd8c6b8e1b02cda3628fee56b2f.tar.gz rust-eea6f23a0ed67fd8c6b8e1b02cda3628fee56b2f.zip | |
Make doc comments cheaper with `AttrKind`.
`AttrKind` is a new type with two variants, `Normal` and `DocComment`. It's a
big performance win (over 10% in some cases) because `DocComment` lets doc
comments (which are common) be represented very cheaply.
`Attribute` gets some new helper methods to ease the transition:
- `has_name()`: check if the attribute name matches a single `Symbol`; for
`DocComment` variants it succeeds if the symbol is `sym::doc`.
- `is_doc_comment()`: check if it has a `DocComment` kind.
- `{get,unwrap}_normal_item()`: extract the item from a `Normal` variant;
panic otherwise.
Fixes #60935.
Diffstat (limited to 'src/libsyntax/attr')
| -rw-r--r-- | src/libsyntax/attr/builtin.rs | 8 | ||||
| -rw-r--r-- | src/libsyntax/attr/mod.rs | 110 |
2 files changed, 83 insertions, 35 deletions
diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs index e77d9ef326a..787d69f5e99 100644 --- a/src/libsyntax/attr/builtin.rs +++ b/src/libsyntax/attr/builtin.rs @@ -228,7 +228,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, sym::stable, sym::rustc_promotable, sym::rustc_allow_const_fn_ptr, - ].iter().any(|&s| attr.item.path == s) { + ].iter().any(|&s| attr.has_name(s)) { continue // not a stability level } @@ -236,10 +236,10 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, let meta = attr.meta(); - if attr.item.path == sym::rustc_promotable { + if attr.has_name(sym::rustc_promotable) { promotable = true; } - if attr.item.path == sym::rustc_allow_const_fn_ptr { + if attr.has_name(sym::rustc_allow_const_fn_ptr) { allow_const_fn_ptr = true; } // attributes with data @@ -778,7 +778,7 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec<ReprAttr> { let mut acc = Vec::new(); let diagnostic = &sess.span_diagnostic; - if attr.item.path == sym::repr { + if attr.has_name(sym::repr) { if let Some(items) = attr.meta_item_list() { mark_used(attr); for item in items { diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index 0c46c501be9..c663995eb8f 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -9,7 +9,7 @@ pub use StabilityLevel::*; pub use crate::ast::Attribute; use crate::ast; -use crate::ast::{AttrItem, AttrId, AttrStyle, Name, Ident, Path, PathSegment}; +use crate::ast::{AttrItem, AttrId, AttrKind, AttrStyle, Name, Ident, Path, PathSegment}; use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem}; use crate::ast::{Lit, LitKind, Expr, Item, Local, Stmt, StmtKind, GenericParam}; use crate::mut_visit::visit_clobber; @@ -145,12 +145,17 @@ impl NestedMetaItem { } impl Attribute { + pub fn has_name(&self, name: Symbol) -> bool { + match self.kind { + AttrKind::Normal(ref item) => item.path == name, + AttrKind::DocComment(_) => name == sym::doc, + } + } + /// Returns `true` if the attribute's path matches the argument. If it matches, then the /// attribute is marked as used. - /// - /// To check the attribute name without marking it used, use the `path` field directly. pub fn check_name(&self, name: Symbol) -> bool { - let matches = self.item.path == name; + let matches = self.has_name(name); if matches { mark_used(self); } @@ -159,10 +164,15 @@ impl Attribute { /// For a single-segment attribute, returns its name; otherwise, returns `None`. pub fn ident(&self) -> Option<Ident> { - if self.item.path.segments.len() == 1 { - Some(self.item.path.segments[0].ident) - } else { - None + match self.kind { + AttrKind::Normal(ref item) => { + if item.path.segments.len() == 1 { + Some(item.path.segments[0].ident) + } else { + None + } + } + AttrKind::DocComment(_) => Some(Ident::new(sym::doc, self.span)), } } pub fn name_or_empty(&self) -> Symbol { @@ -170,18 +180,32 @@ impl Attribute { } pub fn value_str(&self) -> Option<Symbol> { - self.meta().and_then(|meta| meta.value_str()) + match self.kind { + AttrKind::Normal(ref item) => { + item.meta(self.span).and_then(|meta| meta.value_str()) + } + AttrKind::DocComment(comment) => Some(comment), + } } pub fn meta_item_list(&self) -> Option<Vec<NestedMetaItem>> { - match self.meta() { - Some(MetaItem { kind: MetaItemKind::List(list), .. }) => Some(list), - _ => None + match self.kind { + AttrKind::Normal(ref item) => { + match item.meta(self.span) { + Some(MetaItem { kind: MetaItemKind::List(list), .. }) => Some(list), + _ => None + } + } + AttrKind::DocComment(_) => None, } } pub fn is_word(&self) -> bool { - self.item.tokens.is_empty() + if let AttrKind::Normal(item) = &self.kind { + item.tokens.is_empty() + } else { + false + } } pub fn is_meta_item_list(&self) -> bool { @@ -275,17 +299,49 @@ impl AttrItem { } impl Attribute { + pub fn is_doc_comment(&self) -> bool { + match self.kind { + AttrKind::Normal(_) => false, + AttrKind::DocComment(_) => true, + } + } + + pub fn get_normal_item(&self) -> &AttrItem { + match self.kind { + AttrKind::Normal(ref item) => item, + AttrKind::DocComment(_) => panic!("unexpected sugared doc"), + } + } + + pub fn unwrap_normal_item(self) -> AttrItem { + match self.kind { + AttrKind::Normal(item) => item, + AttrKind::DocComment(_) => panic!("unexpected sugared doc"), + } + } + /// Extracts the MetaItem from inside this Attribute. pub fn meta(&self) -> Option<MetaItem> { - self.item.meta(self.span) + match self.kind { + AttrKind::Normal(ref item) => item.meta(self.span), + AttrKind::DocComment(comment) => + Some(mk_name_value_item_str(Ident::new(sym::doc, self.span), comment, self.span)), + } } pub fn parse_meta<'a>(&self, sess: &'a ParseSess) -> PResult<'a, MetaItem> { - Ok(MetaItem { - path: self.item.path.clone(), - kind: parse::parse_in_attr(sess, self, |p| p.parse_meta_item_kind())?, - span: self.span, - }) + match self.kind { + AttrKind::Normal(ref item) => { + Ok(MetaItem { + path: item.path.clone(), + kind: parse::parse_in_attr(sess, self, |parser| parser.parse_meta_item_kind())?, + span: self.span, + }) + } + AttrKind::DocComment(comment) => { + Ok(mk_name_value_item_str(Ident::new(sym::doc, self.span), comment, self.span)) + } + } } } @@ -327,10 +383,9 @@ crate fn mk_attr_id() -> AttrId { pub fn mk_attr(style: AttrStyle, path: Path, tokens: TokenStream, span: Span) -> Attribute { Attribute { - item: AttrItem { path, tokens }, + kind: AttrKind::Normal(AttrItem { path, tokens }), id: mk_attr_id(), style, - is_sugared_doc: false, span, } } @@ -345,18 +400,11 @@ pub fn mk_attr_outer(item: MetaItem) -> Attribute { mk_attr(AttrStyle::Outer, item.path, item.kind.tokens(item.span), item.span) } -pub fn mk_sugared_doc_attr(text: Symbol, span: Span) -> Attribute { - let style = doc_comment_style(&text.as_str()); - let lit_kind = LitKind::Str(text, ast::StrStyle::Cooked); - let lit = Lit::from_lit_kind(lit_kind, span); +pub fn mk_doc_comment(comment: Symbol, span: Span) -> Attribute { Attribute { - item: AttrItem { - path: Path::from_ident(Ident::with_dummy_span(sym::doc).with_span_pos(span)), - tokens: MetaItemKind::NameValue(lit).tokens(span), - }, + kind: AttrKind::DocComment(comment), id: mk_attr_id(), - style, - is_sugared_doc: true, + style: doc_comment_style(&comment.as_str()), span, } } |
