1414pub use self :: Type :: * ;
1515pub use self :: Mutability :: * ;
1616pub use self :: ItemEnum :: * ;
17- pub use self :: Attribute :: * ;
1817pub use self :: TyParamBound :: * ;
1918pub use self :: SelfTy :: * ;
2019pub use self :: FunctionRetTy :: * ;
@@ -25,7 +24,6 @@ use syntax::ast;
2524use syntax:: attr;
2625use syntax:: codemap:: Spanned ;
2726use syntax:: ptr:: P ;
28- use syntax:: print:: pprust as syntax_pprust;
2927use syntax:: symbol:: keywords;
3028use syntax_pos:: { self , DUMMY_SP , Pos } ;
3129
@@ -44,6 +42,7 @@ use rustc::hir;
4442
4543use std:: path:: PathBuf ;
4644use std:: rc:: Rc ;
45+ use std:: slice;
4746use std:: sync:: Arc ;
4847use std:: u32;
4948use 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 ) ]
228227pub 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
11281145impl 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