1+ //! A higher level attributes based on TokenTree, with also some shortcuts.
12use std:: { fmt, ops, sync:: Arc } ;
23
34use base_db:: CrateId ;
@@ -65,14 +66,16 @@ impl RawAttrs {
6566 ( None , entries @ Some ( _) ) => Self { entries } ,
6667 ( Some ( entries) , None ) => Self { entries : Some ( entries. clone ( ) ) } ,
6768 ( Some ( a) , Some ( b) ) => {
68- let last_ast_index = a. last ( ) . map_or ( 0 , |it| it. id . ast_index + 1 ) ;
69+ let last_ast_index = a. last ( ) . map_or ( 0 , |it| it. id . ast_index ( ) + 1 ) as u32 ;
6970 Self {
7071 entries : Some (
7172 a. iter ( )
7273 . cloned ( )
7374 . chain ( b. iter ( ) . map ( |it| {
7475 let mut it = it. clone ( ) ;
75- it. id . ast_index += last_ast_index;
76+ it. id . id = it. id . ast_index ( ) as u32 + last_ast_index
77+ | ( it. id . cfg_attr_index ( ) . unwrap_or ( 0 ) as u32 )
78+ << AttrId :: AST_INDEX_BITS ;
7679 it
7780 } ) )
7881 . collect ( ) ,
@@ -83,6 +86,7 @@ impl RawAttrs {
8386 }
8487
8588 /// Processes `cfg_attr`s, returning the resulting semantic `Attrs`.
89+ // FIXME: This should return a different type
8690 pub fn filter ( self , db : & dyn AstDatabase , krate : CrateId ) -> RawAttrs {
8791 let has_cfg_attrs = self
8892 . iter ( )
@@ -106,27 +110,22 @@ impl RawAttrs {
106110 _ => return smallvec ! [ attr. clone( ) ] ,
107111 } ;
108112
109- // Input subtree is: `(cfg, $(attr),+)`
110- // Split it up into a `cfg` subtree and the `attr` subtrees.
111- // FIXME: There should be a common API for this.
112- let mut parts = subtree. token_trees . split ( |tt| {
113- matches ! ( tt, tt:: TokenTree :: Leaf ( tt:: Leaf :: Punct ( Punct { char : ',' , .. } ) ) )
114- } ) ;
115- let cfg = match parts. next ( ) {
113+ let ( cfg, parts) = match parse_cfg_attr_input ( subtree) {
116114 Some ( it) => it,
117- None => return smallvec ! [ ] ,
115+ None => return smallvec ! [ attr . clone ( ) ] ,
118116 } ;
119- let cfg = Subtree { delimiter : subtree. delimiter , token_trees : cfg. to_vec ( ) } ;
120- let cfg = CfgExpr :: parse ( & cfg) ;
121117 let index = attr. id ;
122- let attrs = parts. filter ( |a| !a. is_empty ( ) ) . filter_map ( |attr| {
123- let tree = Subtree { delimiter : None , token_trees : attr. to_vec ( ) } ;
124- // FIXME hygiene
125- let hygiene = Hygiene :: new_unhygienic ( ) ;
126- Attr :: from_tt ( db, & tree, & hygiene, index)
127- } ) ;
118+ let attrs =
119+ parts. enumerate ( ) . take ( 1 << AttrId :: CFG_ATTR_BITS ) . filter_map ( |( idx, attr) | {
120+ let tree = Subtree { delimiter : None , token_trees : attr. to_vec ( ) } ;
121+ // FIXME hygiene
122+ let hygiene = Hygiene :: new_unhygienic ( ) ;
123+ Attr :: from_tt ( db, & tree, & hygiene, index. with_cfg_attr ( idx) )
124+ } ) ;
128125
129126 let cfg_options = & crate_graph[ krate] . cfg_options ;
127+ let cfg = Subtree { delimiter : subtree. delimiter , token_trees : cfg. to_vec ( ) } ;
128+ let cfg = CfgExpr :: parse ( & cfg) ;
130129 if cfg_options. check ( & cfg) == Some ( false ) {
131130 smallvec ! [ ]
132131 } else {
@@ -143,7 +142,32 @@ impl RawAttrs {
143142
144143#[ derive( Debug , Clone , Copy , PartialEq , Eq , Hash ) ]
145144pub struct AttrId {
146- pub ast_index : u32 ,
145+ id : u32 ,
146+ }
147+
148+ // FIXME: This only handles a single level of cfg_attr nesting
149+ // that is `#[cfg_attr(all(), cfg_attr(all(), cfg(any())))]` breaks again
150+ impl AttrId {
151+ const CFG_ATTR_BITS : usize = 7 ;
152+ const AST_INDEX_MASK : usize = 0x00FF_FFFF ;
153+ const AST_INDEX_BITS : usize = Self :: AST_INDEX_MASK . count_ones ( ) as usize ;
154+ const CFG_ATTR_SET_BITS : u32 = 1 << 31 ;
155+
156+ pub fn ast_index ( & self ) -> usize {
157+ self . id as usize & Self :: AST_INDEX_MASK
158+ }
159+
160+ pub fn cfg_attr_index ( & self ) -> Option < usize > {
161+ if self . id & Self :: CFG_ATTR_SET_BITS == 0 {
162+ None
163+ } else {
164+ Some ( self . id as usize >> Self :: AST_INDEX_BITS )
165+ }
166+ }
167+
168+ pub fn with_cfg_attr ( self , idx : usize ) -> AttrId {
169+ AttrId { id : self . id | ( idx as u32 ) << Self :: AST_INDEX_BITS | Self :: CFG_ATTR_SET_BITS }
170+ }
147171}
148172
149173#[ derive( Debug , Clone , PartialEq , Eq ) ]
@@ -272,10 +296,7 @@ pub fn collect_attrs(
272296 Either :: Left ( attr) => attr. kind ( ) . is_outer ( ) ,
273297 Either :: Right ( comment) => comment. is_outer ( ) ,
274298 } ) ;
275- outer_attrs
276- . chain ( inner_attrs)
277- . enumerate ( )
278- . map ( |( id, attr) | ( AttrId { ast_index : id as u32 } , attr) )
299+ outer_attrs. chain ( inner_attrs) . enumerate ( ) . map ( |( id, attr) | ( AttrId { id : id as u32 } , attr) )
279300}
280301
281302fn inner_attributes (
@@ -311,3 +332,15 @@ fn inner_attributes(
311332 } ) ;
312333 Some ( attrs)
313334}
335+
336+ // Input subtree is: `(cfg, $(attr),+)`
337+ // Split it up into a `cfg` subtree and the `attr` subtrees.
338+ pub fn parse_cfg_attr_input (
339+ subtree : & Subtree ,
340+ ) -> Option < ( & [ tt:: TokenTree ] , impl Iterator < Item = & [ tt:: TokenTree ] > ) > {
341+ let mut parts = subtree
342+ . token_trees
343+ . split ( |tt| matches ! ( tt, tt:: TokenTree :: Leaf ( tt:: Leaf :: Punct ( Punct { char : ',' , .. } ) ) ) ) ;
344+ let cfg = parts. next ( ) ?;
345+ Some ( ( cfg, parts. filter ( |it| !it. is_empty ( ) ) ) )
346+ }
0 commit comments