14
14
pub use self :: Type :: * ;
15
15
pub use self :: Mutability :: * ;
16
16
pub use self :: ItemEnum :: * ;
17
- pub use self :: Attribute :: * ;
18
17
pub use self :: TyParamBound :: * ;
19
18
pub use self :: SelfTy :: * ;
20
19
pub use self :: FunctionRetTy :: * ;
@@ -25,7 +24,6 @@ use syntax::ast;
25
24
use syntax:: attr;
26
25
use syntax:: codemap:: Spanned ;
27
26
use syntax:: ptr:: P ;
28
- use syntax:: print:: pprust as syntax_pprust;
29
27
use syntax:: symbol:: keywords;
30
28
use syntax_pos:: { self , DUMMY_SP , Pos } ;
31
29
@@ -44,6 +42,7 @@ use rustc::hir;
44
42
45
43
use std:: path:: PathBuf ;
46
44
use std:: rc:: Rc ;
45
+ use std:: slice;
47
46
use std:: sync:: Arc ;
48
47
use std:: u32;
49
48
use std:: env:: current_dir;
@@ -227,7 +226,7 @@ impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
227
226
#[ derive( Clone , RustcEncodable , RustcDecodable , Debug ) ]
228
227
pub struct ExternalCrate {
229
228
pub name : String ,
230
- pub attrs : Vec < Attribute > ,
229
+ pub attrs : Attributes ,
231
230
pub primitives : Vec < PrimitiveType > ,
232
231
}
233
232
@@ -258,7 +257,7 @@ pub struct Item {
258
257
pub source : Span ,
259
258
/// Not everything has a name. E.g., impls
260
259
pub name : Option < String > ,
261
- pub attrs : Vec < Attribute > ,
260
+ pub attrs : Attributes ,
262
261
pub inner : ItemEnum ,
263
262
pub visibility : Option < Visibility > ,
264
263
pub def_id : DefId ,
@@ -270,7 +269,7 @@ impl Item {
270
269
/// Finds the `doc` attribute as a NameValue and returns the corresponding
271
270
/// value found.
272
271
pub fn doc_value < ' a > ( & ' a self ) -> Option < & ' a str > {
273
- self . attrs . value ( "doc" )
272
+ self . attrs . doc_value ( )
274
273
}
275
274
pub fn is_crate ( & self ) -> bool {
276
275
match self . inner {
@@ -459,86 +458,104 @@ impl Clean<Item> for doctree::Module {
459
458
}
460
459
}
461
460
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
466
465
}
467
466
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) ;
477
473
}
478
- false
479
- }
480
474
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
+ }
487
482
}
488
483
}
489
484
}
485
+
490
486
None
491
487
}
488
+ }
492
489
490
+ pub trait AttributesExt {
493
491
/// 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
501
501
}
502
- & [ ]
503
502
}
504
503
}
505
504
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
+ }
513
514
}
514
515
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
522
540
}
523
541
}
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
+ }
524
548
}
525
549
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)
536
553
}
537
554
}
538
555
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 )
542
559
}
543
560
}
544
561
@@ -1048,7 +1065,7 @@ impl Clean<Method> for hir::MethodSig {
1048
1065
} ,
1049
1066
output : self . decl . output . clean ( cx) ,
1050
1067
variadic : false ,
1051
- attrs : Vec :: new ( )
1068
+ attrs : Attributes :: default ( )
1052
1069
} ;
1053
1070
Method {
1054
1071
generics : self . generics . clean ( cx) ,
@@ -1076,7 +1093,7 @@ impl Clean<TyMethod> for hir::MethodSig {
1076
1093
} ,
1077
1094
output : self . decl . output . clean ( cx) ,
1078
1095
variadic : false ,
1079
- attrs : Vec :: new ( )
1096
+ attrs : Attributes :: default ( )
1080
1097
} ;
1081
1098
TyMethod {
1082
1099
unsafety : self . unsafety . clone ( ) ,
@@ -1122,7 +1139,7 @@ pub struct FnDecl {
1122
1139
pub inputs : Arguments ,
1123
1140
pub output : FunctionRetTy ,
1124
1141
pub variadic : bool ,
1125
- pub attrs : Vec < Attribute > ,
1142
+ pub attrs : Attributes ,
1126
1143
}
1127
1144
1128
1145
impl FnDecl {
@@ -1148,7 +1165,7 @@ impl Clean<FnDecl> for hir::FnDecl {
1148
1165
} ,
1149
1166
output : self . output . clean ( cx) ,
1150
1167
variadic : self . variadic ,
1151
- attrs : Vec :: new ( )
1168
+ attrs : Attributes :: default ( )
1152
1169
}
1153
1170
}
1154
1171
}
@@ -1163,7 +1180,7 @@ impl<'a, 'tcx> Clean<FnDecl> for (DefId, &'a ty::PolyFnSig<'tcx>) {
1163
1180
} . peekable ( ) ;
1164
1181
FnDecl {
1165
1182
output : Return ( sig. 0 . output . clean ( cx) ) ,
1166
- attrs : Vec :: new ( ) ,
1183
+ attrs : Attributes :: default ( ) ,
1167
1184
variadic : sig. 0 . variadic ,
1168
1185
inputs : Arguments {
1169
1186
values : sig. 0 . inputs . iter ( ) . map ( |t| {
@@ -1616,11 +1633,11 @@ impl PrimitiveType {
1616
1633
}
1617
1634
}
1618
1635
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 ( ) ) {
1624
1641
return ret;
1625
1642
}
1626
1643
}
0 commit comments