@@ -154,18 +154,21 @@ impl RawAttrs {
154154 return smallvec ! [ attr. clone( ) ] ;
155155 }
156156
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,
159159 _ => return smallvec ! [ attr. clone( ) ] ,
160160 } ;
161161
162162 // Input subtree is: `(cfg, $(attr),+)`
163163 // Split it up into a `cfg` subtree and the `attr` subtrees.
164164 // 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+ } ;
169172 let cfg = Subtree { delimiter : subtree. delimiter , token_trees : cfg. to_vec ( ) } ;
170173 let cfg = CfgExpr :: parse ( & cfg) ;
171174 let index = attr. id ;
@@ -259,17 +262,8 @@ impl Attrs {
259262 }
260263
261264 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 ) ;
273267 let mut buf = String :: new ( ) ;
274268 for doc in docs {
275269 // str::lines doesn't yield anything for the empty string
@@ -507,18 +501,9 @@ impl AttrsWithOwner {
507501 & self ,
508502 db : & dyn DefDatabase ,
509503 ) -> 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 ) ;
522507 let mut buf = String :: new ( ) ;
523508 let mut mapping = Vec :: new ( ) ;
524509 for ( doc, idx) in docs {
@@ -557,6 +542,18 @@ impl AttrsWithOwner {
557542 }
558543}
559544
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+
560557fn inner_attributes (
561558 syntax : & SyntaxNode ,
562559) -> Option < impl Iterator < Item = Either < ast:: Attr , ast:: Comment > > > {
@@ -773,45 +770,58 @@ impl Attr {
773770 Self :: from_src ( db, ast, hygiene, id)
774771 }
775772
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+
776806 /// Parses this attribute as a token tree consisting of comma separated paths.
777807 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 ( ) ?;
782809
783810 if args. delimiter_kind ( ) != Some ( DelimiterKind :: Parenthesis ) {
784811 return None ;
785812 }
786813 let paths = args
787814 . 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 {
796818 tt:: TokenTree :: Leaf ( tt:: Leaf :: Ident ( id) ) => Some ( id. as_name ( ) ) ,
797819 _ => None ,
798820 } ) ;
799821 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+ } ) ;
809823
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)
815825 }
816826}
817827
@@ -823,17 +833,11 @@ pub struct AttrQuery<'attr> {
823833
824834impl < ' attr > AttrQuery < ' attr > {
825835 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 ( ) )
830837 }
831838
832839 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 ( ) )
837841 }
838842
839843 pub fn exists ( self ) -> bool {
0 commit comments