@@ -101,17 +101,13 @@ impl RawAttrs {
101101 hygiene : & Hygiene ,
102102 ) -> Self {
103103 let entries = collect_attrs ( owner)
104- . enumerate ( )
105- . flat_map ( |( i, attr) | {
106- let index = AttrId ( i as u32 ) ;
107- match attr {
108- Either :: Left ( attr) => Attr :: from_src ( db, attr, hygiene, index) ,
109- Either :: Right ( comment) => comment. doc_comment ( ) . map ( |doc| Attr {
110- id : index,
111- input : Some ( AttrInput :: Literal ( SmolStr :: new ( doc) ) ) ,
112- path : Interned :: new ( ModPath :: from ( hir_expand:: name!( doc) ) ) ,
113- } ) ,
114- }
104+ . flat_map ( |( id, attr) | match attr {
105+ Either :: Left ( attr) => Attr :: from_src ( db, attr, hygiene, id) ,
106+ Either :: Right ( comment) => comment. doc_comment ( ) . map ( |doc| Attr {
107+ id,
108+ input : Some ( AttrInput :: Literal ( SmolStr :: new ( doc) ) ) ,
109+ path : Interned :: new ( ModPath :: from ( hir_expand:: name!( doc) ) ) ,
110+ } ) ,
115111 } )
116112 . collect :: < Arc < _ > > ( ) ;
117113
@@ -124,6 +120,7 @@ impl RawAttrs {
124120 }
125121
126122 pub ( crate ) fn merge ( & self , other : Self ) -> Self {
123+ // FIXME: This needs to fixup `AttrId`s
127124 match ( & self . entries , & other. entries ) {
128125 ( None , None ) => Self :: EMPTY ,
129126 ( Some ( entries) , None ) | ( None , Some ( entries) ) => {
@@ -375,39 +372,26 @@ impl AttrsWithOwner {
375372
376373 let def_map = module. def_map ( db) ;
377374 let mod_data = & def_map[ module. local_id ] ;
378- let attrs = match mod_data. declaration_source ( db) {
375+ match mod_data. declaration_source ( db) {
379376 Some ( it) => {
380- let mut attrs: Vec < _ > = collect_attrs ( & it. value as & dyn ast:: AttrsOwner )
381- . map ( |attr| InFile :: new ( it. file_id , attr) )
382- . collect ( ) ;
377+ let mut map = AttrSourceMap :: new ( InFile :: new ( it. file_id , & it. value ) ) ;
383378 if let InFile { file_id, value : ModuleSource :: SourceFile ( file) } =
384379 mod_data. definition_source ( db)
385380 {
386- attrs. extend (
387- collect_attrs ( & file as & dyn ast:: AttrsOwner )
388- . map ( |attr| InFile :: new ( file_id, attr) ) ,
389- )
381+ map. merge ( AttrSourceMap :: new ( InFile :: new ( file_id, & file) ) ) ;
390382 }
391- attrs
383+ return map ;
392384 }
393385 None => {
394386 let InFile { file_id, value } = mod_data. definition_source ( db) ;
395- match & value {
396- ModuleSource :: SourceFile ( file) => {
397- collect_attrs ( file as & dyn ast:: AttrsOwner )
398- }
399- ModuleSource :: Module ( module) => {
400- collect_attrs ( module as & dyn ast:: AttrsOwner )
401- }
402- ModuleSource :: BlockExpr ( block) => {
403- collect_attrs ( block as & dyn ast:: AttrsOwner )
404- }
405- }
406- . map ( |attr| InFile :: new ( file_id, attr) )
407- . collect ( )
387+ let attrs_owner = match & value {
388+ ModuleSource :: SourceFile ( file) => file as & dyn ast:: AttrsOwner ,
389+ ModuleSource :: Module ( module) => module as & dyn ast:: AttrsOwner ,
390+ ModuleSource :: BlockExpr ( block) => block as & dyn ast:: AttrsOwner ,
391+ } ;
392+ return AttrSourceMap :: new ( InFile :: new ( file_id, attrs_owner) ) ;
408393 }
409- } ;
410- return AttrSourceMap { attrs } ;
394+ }
411395 }
412396 AttrDefId :: FieldId ( id) => {
413397 let map = db. fields_attrs_source_map ( id. parent ) ;
@@ -462,11 +446,7 @@ impl AttrsWithOwner {
462446 } ,
463447 } ;
464448
465- AttrSourceMap {
466- attrs : collect_attrs ( & owner. value )
467- . map ( |attr| InFile :: new ( owner. file_id , attr) )
468- . collect ( ) ,
469- }
449+ AttrSourceMap :: new ( owner. as_ref ( ) . map ( |node| node as & dyn AttrsOwner ) )
470450 }
471451
472452 pub fn docs_with_rangemap (
@@ -518,7 +498,7 @@ impl AttrsWithOwner {
518498 if buf. is_empty ( ) {
519499 None
520500 } else {
521- Some ( ( Documentation ( buf) , DocsRangeMap { mapping, source : self . source_map ( db) . attrs } ) )
501+ Some ( ( Documentation ( buf) , DocsRangeMap { mapping, source_map : self . source_map ( db) } ) )
522502 }
523503 }
524504}
@@ -559,27 +539,59 @@ fn inner_attributes(
559539}
560540
561541pub struct AttrSourceMap {
562- attrs : Vec < InFile < Either < ast:: Attr , ast:: Comment > > > ,
542+ attrs : Vec < InFile < ast:: Attr > > ,
543+ doc_comments : Vec < InFile < ast:: Comment > > ,
563544}
564545
565546impl AttrSourceMap {
547+ fn new ( owner : InFile < & dyn ast:: AttrsOwner > ) -> Self {
548+ let mut attrs = Vec :: new ( ) ;
549+ let mut doc_comments = Vec :: new ( ) ;
550+ for ( _, attr) in collect_attrs ( owner. value ) {
551+ match attr {
552+ Either :: Left ( attr) => attrs. push ( owner. with_value ( attr) ) ,
553+ Either :: Right ( comment) => doc_comments. push ( owner. with_value ( comment) ) ,
554+ }
555+ }
556+
557+ Self { attrs, doc_comments }
558+ }
559+
560+ fn merge ( & mut self , other : Self ) {
561+ self . attrs . extend ( other. attrs ) ;
562+ self . doc_comments . extend ( other. doc_comments ) ;
563+ }
564+
566565 /// Maps the lowered `Attr` back to its original syntax node.
567566 ///
568567 /// `attr` must come from the `owner` used for AttrSourceMap
569568 ///
570569 /// Note that the returned syntax node might be a `#[cfg_attr]`, or a doc comment, instead of
571570 /// the attribute represented by `Attr`.
572- pub fn source_of ( & self , attr : & Attr ) -> InFile < & Either < ast:: Attr , ast:: Comment > > {
573- self . attrs
574- . get ( attr. id . 0 as usize )
575- . unwrap_or_else ( || panic ! ( "cannot find `Attr` at index {:?}" , attr. id) )
576- . as_ref ( )
571+ pub fn source_of ( & self , attr : & Attr ) -> InFile < Either < ast:: Attr , ast:: Comment > > {
572+ self . source_of_id ( attr. id )
573+ }
574+
575+ fn source_of_id ( & self , id : AttrId ) -> InFile < Either < ast:: Attr , ast:: Comment > > {
576+ if id. is_doc_comment {
577+ self . doc_comments
578+ . get ( id. ast_index as usize )
579+ . unwrap_or_else ( || panic ! ( "cannot find doc comment at index {:?}" , id) )
580+ . clone ( )
581+ . map ( |attr| Either :: Right ( attr) )
582+ } else {
583+ self . attrs
584+ . get ( id. ast_index as usize )
585+ . unwrap_or_else ( || panic ! ( "cannot find `Attr` at index {:?}" , id) )
586+ . clone ( )
587+ . map ( |attr| Either :: Left ( attr) )
588+ }
577589 }
578590}
579591
580592/// A struct to map text ranges from [`Documentation`] back to TextRanges in the syntax tree.
581593pub struct DocsRangeMap {
582- source : Vec < InFile < Either < ast :: Attr , ast :: Comment > > > ,
594+ source_map : AttrSourceMap ,
583595 // (docstring-line-range, attr_index, attr-string-range)
584596 // a mapping from the text range of a line of the [`Documentation`] to the attribute index and
585597 // the original (untrimmed) syntax doc line
@@ -596,7 +608,7 @@ impl DocsRangeMap {
596608
597609 let relative_range = range - line_docs_range. start ( ) ;
598610
599- let & InFile { file_id, value : ref source } = & self . source [ idx . 0 as usize ] ;
611+ let & InFile { file_id, value : ref source } = & self . source_map . source_of_id ( idx ) ;
600612 match source {
601613 Either :: Left ( _) => None , // FIXME, figure out a nice way to handle doc attributes here
602614 // as well as for whats done in syntax highlight doc injection
@@ -616,7 +628,10 @@ impl DocsRangeMap {
616628}
617629
618630#[ derive( Debug , Clone , Copy , PartialEq , Eq , Hash ) ]
619- pub struct AttrId ( pub u32 ) ;
631+ pub ( crate ) struct AttrId {
632+ is_doc_comment : bool ,
633+ pub ( crate ) ast_index : u32 ,
634+ }
620635
621636#[ derive( Debug , Clone , PartialEq , Eq ) ]
622637pub struct Attr {
@@ -752,22 +767,32 @@ fn attrs_from_item_tree<N: ItemTreeNode>(id: ItemTreeId<N>, db: &dyn DefDatabase
752767
753768fn collect_attrs (
754769 owner : & dyn ast:: AttrsOwner ,
755- ) -> impl Iterator < Item = Either < ast:: Attr , ast:: Comment > > {
770+ ) -> impl Iterator < Item = ( AttrId , Either < ast:: Attr , ast:: Comment > ) > {
756771 let ( inner_attrs, inner_docs) = inner_attributes ( owner. syntax ( ) )
757772 . map_or ( ( None , None ) , |( attrs, docs) | ( Some ( attrs) , Some ( docs) ) ) ;
758773
759774 let outer_attrs = owner. attrs ( ) . filter ( |attr| attr. kind ( ) . is_outer ( ) ) ;
760- let attrs = outer_attrs
761- . chain ( inner_attrs. into_iter ( ) . flatten ( ) )
762- . map ( |attr| ( attr. syntax ( ) . text_range ( ) . start ( ) , Either :: Left ( attr) ) ) ;
775+ let attrs =
776+ outer_attrs. chain ( inner_attrs. into_iter ( ) . flatten ( ) ) . enumerate ( ) . map ( |( idx, attr) | {
777+ (
778+ AttrId { ast_index : idx as u32 , is_doc_comment : false } ,
779+ attr. syntax ( ) . text_range ( ) . start ( ) ,
780+ Either :: Left ( attr) ,
781+ )
782+ } ) ;
763783
764784 let outer_docs =
765785 ast:: CommentIter :: from_syntax_node ( owner. syntax ( ) ) . filter ( ast:: Comment :: is_outer) ;
766- let docs = outer_docs
767- . chain ( inner_docs. into_iter ( ) . flatten ( ) )
768- . map ( |docs_text| ( docs_text. syntax ( ) . text_range ( ) . start ( ) , Either :: Right ( docs_text) ) ) ;
786+ let docs =
787+ outer_docs. chain ( inner_docs. into_iter ( ) . flatten ( ) ) . enumerate ( ) . map ( |( idx, docs_text) | {
788+ (
789+ AttrId { ast_index : idx as u32 , is_doc_comment : true } ,
790+ docs_text. syntax ( ) . text_range ( ) . start ( ) ,
791+ Either :: Right ( docs_text) ,
792+ )
793+ } ) ;
769794 // sort here by syntax node offset because the source can have doc attributes and doc strings be interleaved
770- docs. chain ( attrs) . sorted_by_key ( |& ( offset, _) | offset) . map ( |( _, attr) | attr)
795+ docs. chain ( attrs) . sorted_by_key ( |& ( _ , offset, _) | offset) . map ( |( id , _, attr) | ( id , attr) )
771796}
772797
773798pub ( crate ) fn variants_attrs_source_map (
0 commit comments