Skip to content

Commit 12c5f8c

Browse files
committed
rustdoc: use libsyntax ast::Attribute instead of "cleaning" them.
1 parent 127a83d commit 12c5f8c

File tree

9 files changed

+266
-262
lines changed

9 files changed

+266
-262
lines changed

src/librustdoc/clean/inline.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,8 @@ fn try_inline_def<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
135135
}
136136

137137
pub fn load_attrs<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
138-
did: DefId) -> Vec<clean::Attribute> {
139-
tcx.get_attrs(did).iter().map(|a| a.clean(cx)).collect()
138+
did: DefId) -> clean::Attributes {
139+
tcx.get_attrs(did).clean(cx)
140140
}
141141

142142
/// Record an external fully qualified name in the external_paths cache.
@@ -377,7 +377,7 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext,
377377
default,
378378
),
379379
source: clean::Span::empty(),
380-
attrs: vec![],
380+
attrs: clean::Attributes::default(),
381381
visibility: None,
382382
stability: tcx.lookup_stability(item.def_id).clean(cx),
383383
deprecation: tcx.lookup_deprecation(item.def_id).clean(cx),
@@ -424,7 +424,7 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext,
424424
name: Some(item.name.clean(cx)),
425425
inner: clean::TypedefItem(typedef, true),
426426
source: clean::Span::empty(),
427-
attrs: vec![],
427+
attrs: clean::Attributes::default(),
428428
visibility: None,
429429
stability: tcx.lookup_stability(item.def_id).clean(cx),
430430
deprecation: tcx.lookup_deprecation(item.def_id).clean(cx),

src/librustdoc/clean/mod.rs

Lines changed: 88 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
pub use self::Type::*;
1515
pub use self::Mutability::*;
1616
pub use self::ItemEnum::*;
17-
pub use self::Attribute::*;
1817
pub use self::TyParamBound::*;
1918
pub use self::SelfTy::*;
2019
pub use self::FunctionRetTy::*;
@@ -25,7 +24,6 @@ use syntax::ast;
2524
use syntax::attr;
2625
use syntax::codemap::Spanned;
2726
use syntax::ptr::P;
28-
use syntax::print::pprust as syntax_pprust;
2927
use syntax::symbol::keywords;
3028
use syntax_pos::{self, DUMMY_SP, Pos};
3129

@@ -44,6 +42,7 @@ use rustc::hir;
4442

4543
use std::path::PathBuf;
4644
use std::rc::Rc;
45+
use std::slice;
4746
use std::sync::Arc;
4847
use std::u32;
4948
use std::env::current_dir;
@@ -227,7 +226,7 @@ impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
227226
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
228227
pub struct ExternalCrate {
229228
pub name: String,
230-
pub attrs: Vec<Attribute>,
229+
pub attrs: Attributes,
231230
pub primitives: Vec<PrimitiveType>,
232231
}
233232

@@ -258,7 +257,7 @@ pub struct Item {
258257
pub source: Span,
259258
/// Not everything has a name. E.g., impls
260259
pub name: Option<String>,
261-
pub attrs: Vec<Attribute>,
260+
pub attrs: Attributes,
262261
pub inner: ItemEnum,
263262
pub visibility: Option<Visibility>,
264263
pub def_id: DefId,
@@ -270,7 +269,7 @@ impl Item {
270269
/// Finds the `doc` attribute as a NameValue and returns the corresponding
271270
/// value found.
272271
pub fn doc_value<'a>(&'a self) -> Option<&'a str> {
273-
self.attrs.value("doc")
272+
self.attrs.doc_value()
274273
}
275274
pub fn is_crate(&self) -> bool {
276275
match self.inner {
@@ -459,86 +458,104 @@ impl Clean<Item> for doctree::Module {
459458
}
460459
}
461460

462-
pub trait Attributes {
463-
fn has_word(&self, &str) -> bool;
464-
fn value<'a>(&'a self, &str) -> Option<&'a str>;
465-
fn list<'a>(&'a self, &str) -> &'a [Attribute];
461+
pub struct ListAttributesIter<'a> {
462+
attrs: slice::Iter<'a, ast::Attribute>,
463+
current_list: slice::Iter<'a, ast::NestedMetaItem>,
464+
name: &'a str
466465
}
467466

468-
impl Attributes for [Attribute] {
469-
/// Returns whether the attribute list contains a specific `Word`
470-
fn has_word(&self, word: &str) -> bool {
471-
for attr in self {
472-
if let Word(ref w) = *attr {
473-
if word == *w {
474-
return true;
475-
}
476-
}
467+
impl<'a> Iterator for ListAttributesIter<'a> {
468+
type Item = &'a ast::NestedMetaItem;
469+
470+
fn next(&mut self) -> Option<Self::Item> {
471+
if let Some(nested) = self.current_list.next() {
472+
return Some(nested);
477473
}
478-
false
479-
}
480474

481-
/// Finds an attribute as NameValue and returns the corresponding value found.
482-
fn value<'a>(&'a self, name: &str) -> Option<&'a str> {
483-
for attr in self {
484-
if let NameValue(ref x, ref v) = *attr {
485-
if name == *x {
486-
return Some(v);
475+
for attr in &mut self.attrs {
476+
if let Some(ref list) = attr.meta_item_list() {
477+
if attr.check_name(self.name) {
478+
self.current_list = list.iter();
479+
if let Some(nested) = self.current_list.next() {
480+
return Some(nested);
481+
}
487482
}
488483
}
489484
}
485+
490486
None
491487
}
488+
}
492489

490+
pub trait AttributesExt {
493491
/// Finds an attribute as List and returns the list of attributes nested inside.
494-
fn list<'a>(&'a self, name: &str) -> &'a [Attribute] {
495-
for attr in self {
496-
if let List(ref x, ref list) = *attr {
497-
if name == *x {
498-
return &list[..];
499-
}
500-
}
492+
fn lists<'a>(&'a self, &'a str) -> ListAttributesIter<'a>;
493+
}
494+
495+
impl AttributesExt for [ast::Attribute] {
496+
fn lists<'a>(&'a self, name: &'a str) -> ListAttributesIter<'a> {
497+
ListAttributesIter {
498+
attrs: self.iter(),
499+
current_list: [].iter(),
500+
name: name
501501
}
502-
&[]
503502
}
504503
}
505504

506-
/// This is a flattened version of the AST's Attribute + MetaItem.
507-
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
508-
pub enum Attribute {
509-
Word(String),
510-
List(String, Vec<Attribute>),
511-
NameValue(String, String),
512-
Literal(String),
505+
pub trait NestedAttributesExt {
506+
/// Returns whether the attribute list contains a specific `Word`
507+
fn has_word(self, &str) -> bool;
508+
}
509+
510+
impl<'a, I: IntoIterator<Item=&'a ast::NestedMetaItem>> NestedAttributesExt for I {
511+
fn has_word(self, word: &str) -> bool {
512+
self.into_iter().any(|attr| attr.is_word() && attr.check_name(word))
513+
}
513514
}
514515

515-
impl Clean<Attribute> for ast::NestedMetaItem {
516-
fn clean(&self, cx: &DocContext) -> Attribute {
517-
if let Some(mi) = self.meta_item() {
518-
mi.clean(cx)
519-
} else { // must be a literal
520-
let lit = self.literal().unwrap();
521-
Literal(syntax_pprust::lit_to_string(lit))
516+
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug, Default)]
517+
pub struct Attributes {
518+
pub doc_strings: Vec<String>,
519+
pub other_attrs: Vec<ast::Attribute>
520+
}
521+
522+
impl Attributes {
523+
pub fn from_ast(attrs: &[ast::Attribute]) -> Attributes {
524+
let mut doc_strings = vec![];
525+
let other_attrs = attrs.iter().filter_map(|attr| {
526+
attr.with_desugared_doc(|attr| {
527+
if let Some(value) = attr.value_str() {
528+
if attr.check_name("doc") {
529+
doc_strings.push(value.to_string());
530+
return None;
531+
}
532+
}
533+
534+
Some(attr.clone())
535+
})
536+
}).collect();
537+
Attributes {
538+
doc_strings: doc_strings,
539+
other_attrs: other_attrs
522540
}
523541
}
542+
543+
/// Finds the `doc` attribute as a NameValue and returns the corresponding
544+
/// value found.
545+
pub fn doc_value<'a>(&'a self) -> Option<&'a str> {
546+
self.doc_strings.first().map(|s| &s[..])
547+
}
524548
}
525549

526-
impl Clean<Attribute> for ast::MetaItem {
527-
fn clean(&self, cx: &DocContext) -> Attribute {
528-
if self.is_word() {
529-
Word(self.name().to_string())
530-
} else if let Some(v) = self.value_str() {
531-
NameValue(self.name().to_string(), v.to_string())
532-
} else { // must be a list
533-
let l = self.meta_item_list().unwrap();
534-
List(self.name().to_string(), l.clean(cx))
535-
}
550+
impl AttributesExt for Attributes {
551+
fn lists<'a>(&'a self, name: &'a str) -> ListAttributesIter<'a> {
552+
self.other_attrs.lists(name)
536553
}
537554
}
538555

539-
impl Clean<Attribute> for ast::Attribute {
540-
fn clean(&self, cx: &DocContext) -> Attribute {
541-
self.with_desugared_doc(|a| a.meta().clean(cx))
556+
impl Clean<Attributes> for [ast::Attribute] {
557+
fn clean(&self, _cx: &DocContext) -> Attributes {
558+
Attributes::from_ast(self)
542559
}
543560
}
544561

@@ -1048,7 +1065,7 @@ impl Clean<Method> for hir::MethodSig {
10481065
},
10491066
output: self.decl.output.clean(cx),
10501067
variadic: false,
1051-
attrs: Vec::new()
1068+
attrs: Attributes::default()
10521069
};
10531070
Method {
10541071
generics: self.generics.clean(cx),
@@ -1076,7 +1093,7 @@ impl Clean<TyMethod> for hir::MethodSig {
10761093
},
10771094
output: self.decl.output.clean(cx),
10781095
variadic: false,
1079-
attrs: Vec::new()
1096+
attrs: Attributes::default()
10801097
};
10811098
TyMethod {
10821099
unsafety: self.unsafety.clone(),
@@ -1122,7 +1139,7 @@ pub struct FnDecl {
11221139
pub inputs: Arguments,
11231140
pub output: FunctionRetTy,
11241141
pub variadic: bool,
1125-
pub attrs: Vec<Attribute>,
1142+
pub attrs: Attributes,
11261143
}
11271144

11281145
impl FnDecl {
@@ -1148,7 +1165,7 @@ impl Clean<FnDecl> for hir::FnDecl {
11481165
},
11491166
output: self.output.clean(cx),
11501167
variadic: self.variadic,
1151-
attrs: Vec::new()
1168+
attrs: Attributes::default()
11521169
}
11531170
}
11541171
}
@@ -1163,7 +1180,7 @@ impl<'a, 'tcx> Clean<FnDecl> for (DefId, &'a ty::PolyFnSig<'tcx>) {
11631180
}.peekable();
11641181
FnDecl {
11651182
output: Return(sig.0.output.clean(cx)),
1166-
attrs: Vec::new(),
1183+
attrs: Attributes::default(),
11671184
variadic: sig.0.variadic,
11681185
inputs: Arguments {
11691186
values: sig.0.inputs.iter().map(|t| {
@@ -1616,11 +1633,11 @@ impl PrimitiveType {
16161633
}
16171634
}
16181635

1619-
fn find(attrs: &[Attribute]) -> Option<PrimitiveType> {
1620-
for attr in attrs.list("doc") {
1621-
if let NameValue(ref k, ref v) = *attr {
1622-
if "primitive" == *k {
1623-
if let ret@Some(..) = PrimitiveType::from_str(v) {
1636+
fn find(attrs: &Attributes) -> Option<PrimitiveType> {
1637+
for attr in attrs.lists("doc") {
1638+
if let Some(v) = attr.value_str() {
1639+
if attr.check_name("primitive") {
1640+
if let ret@Some(..) = PrimitiveType::from_str(&v.as_str()) {
16241641
return ret;
16251642
}
16261643
}

0 commit comments

Comments
 (0)