@@ -154,18 +154,21 @@ impl RawAttrs {
154
154
return smallvec ! [ attr. clone( ) ] ;
155
155
}
156
156
157
- let subtree = match attr. input . as_deref ( ) {
158
- Some ( AttrInput :: TokenTree ( it , _ ) ) => it,
157
+ let subtree = match attr. token_tree_value ( ) {
158
+ Some ( it ) => it,
159
159
_ => return smallvec ! [ attr. clone( ) ] ,
160
160
} ;
161
161
162
162
// Input subtree is: `(cfg, $(attr),+)`
163
163
// Split it up into a `cfg` subtree and the `attr` subtrees.
164
164
// FIXME: There should be a common API for this.
165
- let mut parts = subtree. token_trees . split (
166
- |tt| matches ! ( tt, tt:: TokenTree :: Leaf ( tt:: Leaf :: Punct ( p) ) if p. char == ',' ) ,
167
- ) ;
168
- let cfg = parts. next ( ) . unwrap ( ) ;
165
+ let mut parts = subtree. token_trees . split ( |tt| {
166
+ matches ! ( tt, tt:: TokenTree :: Leaf ( tt:: Leaf :: Punct ( Punct { char : ',' , .. } ) ) )
167
+ } ) ;
168
+ let cfg = match parts. next ( ) {
169
+ Some ( it) => it,
170
+ None => return smallvec ! [ ] ,
171
+ } ;
169
172
let cfg = Subtree { delimiter : subtree. delimiter , token_trees : cfg. to_vec ( ) } ;
170
173
let cfg = CfgExpr :: parse ( & cfg) ;
171
174
let index = attr. id ;
@@ -259,17 +262,8 @@ impl Attrs {
259
262
}
260
263
261
264
pub fn docs ( & self ) -> Option < Documentation > {
262
- let docs = self . by_key ( "doc" ) . attrs ( ) . flat_map ( |attr| match attr. input . as_deref ( ) ? {
263
- AttrInput :: Literal ( s) => Some ( s) ,
264
- AttrInput :: TokenTree ( ..) => None ,
265
- } ) ;
266
- let indent = docs
267
- . clone ( )
268
- . flat_map ( |s| s. lines ( ) )
269
- . filter ( |line| !line. chars ( ) . all ( |c| c. is_whitespace ( ) ) )
270
- . map ( |line| line. chars ( ) . take_while ( |c| c. is_whitespace ( ) ) . count ( ) )
271
- . min ( )
272
- . unwrap_or ( 0 ) ;
265
+ let docs = self . by_key ( "doc" ) . attrs ( ) . filter_map ( |attr| attr. string_value ( ) ) ;
266
+ let indent = doc_indent ( self ) ;
273
267
let mut buf = String :: new ( ) ;
274
268
for doc in docs {
275
269
// str::lines doesn't yield anything for the empty string
@@ -507,18 +501,9 @@ impl AttrsWithOwner {
507
501
& self ,
508
502
db : & dyn DefDatabase ,
509
503
) -> Option < ( Documentation , DocsRangeMap ) > {
510
- // FIXME: code duplication in `docs` above
511
- let docs = self . by_key ( "doc" ) . attrs ( ) . flat_map ( |attr| match attr. input . as_deref ( ) ? {
512
- AttrInput :: Literal ( s) => Some ( ( s, attr. id ) ) ,
513
- AttrInput :: TokenTree ( ..) => None ,
514
- } ) ;
515
- let indent = docs
516
- . clone ( )
517
- . flat_map ( |( s, _) | s. lines ( ) )
518
- . filter ( |line| !line. chars ( ) . all ( |c| c. is_whitespace ( ) ) )
519
- . map ( |line| line. chars ( ) . take_while ( |c| c. is_whitespace ( ) ) . count ( ) )
520
- . min ( )
521
- . unwrap_or ( 0 ) ;
504
+ let docs =
505
+ self . by_key ( "doc" ) . attrs ( ) . filter_map ( |attr| attr. string_value ( ) . map ( |s| ( s, attr. id ) ) ) ;
506
+ let indent = doc_indent ( self ) ;
522
507
let mut buf = String :: new ( ) ;
523
508
let mut mapping = Vec :: new ( ) ;
524
509
for ( doc, idx) in docs {
@@ -557,6 +542,18 @@ impl AttrsWithOwner {
557
542
}
558
543
}
559
544
545
+ fn doc_indent ( attrs : & Attrs ) -> usize {
546
+ attrs
547
+ . by_key ( "doc" )
548
+ . attrs ( )
549
+ . filter_map ( |attr| attr. string_value ( ) )
550
+ . flat_map ( |s| s. lines ( ) )
551
+ . filter ( |line| !line. chars ( ) . all ( |c| c. is_whitespace ( ) ) )
552
+ . map ( |line| line. chars ( ) . take_while ( |c| c. is_whitespace ( ) ) . count ( ) )
553
+ . min ( )
554
+ . unwrap_or ( 0 )
555
+ }
556
+
560
557
fn inner_attributes (
561
558
syntax : & SyntaxNode ,
562
559
) -> Option < impl Iterator < Item = Either < ast:: Attr , ast:: Comment > > > {
@@ -773,45 +770,58 @@ impl Attr {
773
770
Self :: from_src ( db, ast, hygiene, id)
774
771
}
775
772
773
+ pub fn path ( & self ) -> & ModPath {
774
+ & self . path
775
+ }
776
+ }
777
+
778
+ impl Attr {
779
+ /// #[path = "string"]
780
+ pub fn string_value ( & self ) -> Option < & SmolStr > {
781
+ match self . input . as_deref ( ) ? {
782
+ AttrInput :: Literal ( it) => Some ( it) ,
783
+ _ => None ,
784
+ }
785
+ }
786
+
787
+ /// #[path(ident)]
788
+ pub fn single_ident_value ( & self ) -> Option < & tt:: Ident > {
789
+ match self . input . as_deref ( ) ? {
790
+ AttrInput :: TokenTree ( subtree, _) => match & * subtree. token_trees {
791
+ [ tt:: TokenTree :: Leaf ( tt:: Leaf :: Ident ( ident) ) ] => Some ( ident) ,
792
+ _ => None ,
793
+ } ,
794
+ _ => None ,
795
+ }
796
+ }
797
+
798
+ /// #[path TokenTree]
799
+ pub fn token_tree_value ( & self ) -> Option < & Subtree > {
800
+ match self . input . as_deref ( ) ? {
801
+ AttrInput :: TokenTree ( subtree, _) => Some ( subtree) ,
802
+ _ => None ,
803
+ }
804
+ }
805
+
776
806
/// Parses this attribute as a token tree consisting of comma separated paths.
777
807
pub fn parse_path_comma_token_tree ( & self ) -> Option < impl Iterator < Item = ModPath > + ' _ > {
778
- let args = match self . input . as_deref ( ) {
779
- Some ( AttrInput :: TokenTree ( args, _) ) => args,
780
- _ => return None ,
781
- } ;
808
+ let args = self . token_tree_value ( ) ?;
782
809
783
810
if args. delimiter_kind ( ) != Some ( DelimiterKind :: Parenthesis ) {
784
811
return None ;
785
812
}
786
813
let paths = args
787
814
. token_trees
788
- . iter ( )
789
- . group_by ( |tt| {
790
- matches ! ( tt, tt:: TokenTree :: Leaf ( tt:: Leaf :: Punct ( Punct { char : ',' , .. } ) ) )
791
- } )
792
- . into_iter ( )
793
- . filter ( |( comma, _) | !* comma)
794
- . map ( |( _, tts) | {
795
- let segments = tts. filter_map ( |tt| match tt {
815
+ . split ( |tt| matches ! ( tt, tt:: TokenTree :: Leaf ( tt:: Leaf :: Punct ( Punct { char : ',' , .. } ) ) ) )
816
+ . map ( |tts| {
817
+ let segments = tts. iter ( ) . filter_map ( |tt| match tt {
796
818
tt:: TokenTree :: Leaf ( tt:: Leaf :: Ident ( id) ) => Some ( id. as_name ( ) ) ,
797
819
_ => None ,
798
820
} ) ;
799
821
ModPath :: from_segments ( PathKind :: Plain , segments)
800
- } )
801
- . collect :: < Vec < _ > > ( ) ;
802
-
803
- Some ( paths. into_iter ( ) )
804
- }
805
-
806
- pub fn path ( & self ) -> & ModPath {
807
- & self . path
808
- }
822
+ } ) ;
809
823
810
- pub fn string_value ( & self ) -> Option < & SmolStr > {
811
- match self . input . as_deref ( ) ? {
812
- AttrInput :: Literal ( it) => Some ( it) ,
813
- _ => None ,
814
- }
824
+ Some ( paths)
815
825
}
816
826
}
817
827
@@ -823,17 +833,11 @@ pub struct AttrQuery<'attr> {
823
833
824
834
impl < ' attr > AttrQuery < ' attr > {
825
835
pub fn tt_values ( self ) -> impl Iterator < Item = & ' attr Subtree > {
826
- self . attrs ( ) . filter_map ( |attr| match attr. input . as_deref ( ) ? {
827
- AttrInput :: TokenTree ( it, _) => Some ( it) ,
828
- _ => None ,
829
- } )
836
+ self . attrs ( ) . filter_map ( |attr| attr. token_tree_value ( ) )
830
837
}
831
838
832
839
pub fn string_value ( self ) -> Option < & ' attr SmolStr > {
833
- self . attrs ( ) . find_map ( |attr| match attr. input . as_deref ( ) ? {
834
- AttrInput :: Literal ( it) => Some ( it) ,
835
- _ => None ,
836
- } )
840
+ self . attrs ( ) . find_map ( |attr| attr. string_value ( ) )
837
841
}
838
842
839
843
pub fn exists ( self ) -> bool {
0 commit comments