@@ -76,37 +76,23 @@ impl ops::Deref for Attrs {
76
76
impl RawAttrs {
77
77
pub ( crate ) const EMPTY : Self = Self { entries : None } ;
78
78
79
- pub ( crate ) fn new ( owner : & dyn AttrsOwner , hygiene : & Hygiene ) -> Self {
80
- let attrs: Vec < _ > = collect_attrs ( owner) . collect ( ) ;
81
- let entries = if attrs. is_empty ( ) {
82
- // Avoid heap allocation
83
- None
84
- } else {
85
- Some (
86
- attrs
87
- . into_iter ( )
88
- . enumerate ( )
89
- . flat_map ( |( i, attr) | match attr {
90
- Either :: Left ( attr) => Attr :: from_src ( attr, hygiene) . map ( |attr| ( i, attr) ) ,
91
- Either :: Right ( comment) => comment. doc_comment ( ) . map ( |doc| {
92
- (
93
- i,
94
- Attr {
95
- index : 0 ,
96
- input : Some ( AttrInput :: Literal ( SmolStr :: new ( doc) ) ) ,
97
- path : ModPath :: from ( hir_expand:: name!( doc) ) ,
98
- } ,
99
- )
100
- } ) ,
101
- } )
102
- . map ( |( i, attr) | Attr { index : i as u32 , ..attr } )
103
- . collect ( ) ,
104
- )
105
- } ;
106
- Self { entries }
79
+ pub ( crate ) fn new ( owner : & dyn ast:: AttrsOwner , hygiene : & Hygiene ) -> Self {
80
+ let entries = collect_attrs ( owner)
81
+ . enumerate ( )
82
+ . flat_map ( |( i, attr) | match attr {
83
+ Either :: Left ( attr) => Attr :: from_src ( attr, hygiene, i as u32 ) ,
84
+ Either :: Right ( comment) => comment. doc_comment ( ) . map ( |doc| Attr {
85
+ index : i as u32 ,
86
+ input : Some ( AttrInput :: Literal ( SmolStr :: new ( doc) ) ) ,
87
+ path : ModPath :: from ( hir_expand:: name!( doc) ) ,
88
+ } ) ,
89
+ } )
90
+ . collect :: < Arc < _ > > ( ) ;
91
+
92
+ Self { entries : if entries. is_empty ( ) { None } else { Some ( entries) } }
107
93
}
108
94
109
- fn from_attrs_owner ( db : & dyn DefDatabase , owner : InFile < & dyn AttrsOwner > ) -> Self {
95
+ fn from_attrs_owner ( db : & dyn DefDatabase , owner : InFile < & dyn ast :: AttrsOwner > ) -> Self {
110
96
let hygiene = Hygiene :: new ( db. upcast ( ) , owner. file_id ) ;
111
97
Self :: new ( owner. value , & hygiene)
112
98
}
@@ -162,7 +148,7 @@ impl RawAttrs {
162
148
let attr = ast:: Attr :: parse ( & format ! ( "#[{}]" , tree) ) . ok ( ) ?;
163
149
// FIXME hygiene
164
150
let hygiene = Hygiene :: new_unhygienic ( ) ;
165
- Attr :: from_src ( attr, & hygiene) . map ( |attr| Attr { index , ..attr } )
151
+ Attr :: from_src ( attr, & hygiene, index )
166
152
} ) ;
167
153
168
154
let cfg_options = & crate_graph[ krate] . cfg_options ;
@@ -192,7 +178,7 @@ impl Attrs {
192
178
Some ( it) => {
193
179
let raw_attrs = RawAttrs :: from_attrs_owner (
194
180
db,
195
- it. as_ref ( ) . map ( |it| it as & dyn AttrsOwner ) ,
181
+ it. as_ref ( ) . map ( |it| it as & dyn ast :: AttrsOwner ) ,
196
182
) ;
197
183
match mod_data. definition_source ( db) {
198
184
InFile { file_id, value : ModuleSource :: SourceFile ( file) } => raw_attrs
@@ -203,9 +189,9 @@ impl Attrs {
203
189
None => RawAttrs :: from_attrs_owner (
204
190
db,
205
191
mod_data. definition_source ( db) . as_ref ( ) . map ( |src| match src {
206
- ModuleSource :: SourceFile ( file) => file as & dyn AttrsOwner ,
207
- ModuleSource :: Module ( module) => module as & dyn AttrsOwner ,
208
- ModuleSource :: BlockExpr ( block) => block as & dyn AttrsOwner ,
192
+ ModuleSource :: SourceFile ( file) => file as & dyn ast :: AttrsOwner ,
193
+ ModuleSource :: Module ( module) => module as & dyn ast :: AttrsOwner ,
194
+ ModuleSource :: BlockExpr ( block) => block as & dyn ast :: AttrsOwner ,
209
195
} ) ,
210
196
) ,
211
197
}
@@ -263,7 +249,7 @@ impl Attrs {
263
249
let mut res = ArenaMap :: default ( ) ;
264
250
265
251
for ( id, var) in src. value . iter ( ) {
266
- let attrs = RawAttrs :: from_attrs_owner ( db, src. with_value ( var as & dyn AttrsOwner ) )
252
+ let attrs = RawAttrs :: from_attrs_owner ( db, src. with_value ( var as & dyn ast :: AttrsOwner ) )
267
253
. filter ( db, krate) ;
268
254
269
255
res. insert ( id, attrs)
@@ -297,7 +283,7 @@ impl Attrs {
297
283
/// Constructs a map that maps the lowered `Attr`s in this `Attrs` back to its original syntax nodes.
298
284
///
299
285
/// `owner` must be the original owner of the attributes.
300
- pub fn source_map ( & self , owner : & dyn AttrsOwner ) -> AttrSourceMap {
286
+ pub fn source_map ( & self , owner : & dyn ast :: AttrsOwner ) -> AttrSourceMap {
301
287
AttrSourceMap { attrs : collect_attrs ( owner) . collect ( ) }
302
288
}
303
289
@@ -325,15 +311,34 @@ impl Attrs {
325
311
AttrInput :: Literal ( s) => Some ( s) ,
326
312
AttrInput :: TokenTree ( _) => None ,
327
313
} ) ;
328
- // FIXME: Replace `Itertools::intersperse` with `Iterator::intersperse[_with]` until the
329
- // libstd api gets stabilized (https://github.com/rust-lang/rust/issues/79524).
330
- let docs = Itertools :: intersperse ( docs, & SmolStr :: new_inline ( "\n " ) )
331
- . map ( |it| it. as_str ( ) )
332
- . collect :: < String > ( ) ;
333
- if docs. is_empty ( ) {
314
+ let indent = docs
315
+ . clone ( )
316
+ . flat_map ( |s| s. lines ( ) )
317
+ . filter ( |line| !line. chars ( ) . all ( |c| c. is_whitespace ( ) ) )
318
+ . map ( |line| line. chars ( ) . take_while ( |c| c. is_whitespace ( ) ) . count ( ) )
319
+ . min ( )
320
+ . unwrap_or ( 0 ) ;
321
+ let mut buf = String :: new ( ) ;
322
+ for doc in docs {
323
+ // str::lines doesn't yield anything for the empty string
324
+ if !doc. is_empty ( ) {
325
+ buf. extend ( Itertools :: intersperse (
326
+ doc. lines ( ) . map ( |line| {
327
+ line. char_indices ( )
328
+ . nth ( indent)
329
+ . map_or ( line, |( offset, _) | & line[ offset..] )
330
+ . trim_end ( )
331
+ } ) ,
332
+ "\n " ,
333
+ ) ) ;
334
+ }
335
+ buf. push ( '\n' ) ;
336
+ }
337
+ buf. pop ( ) ;
338
+ if buf. is_empty ( ) {
334
339
None
335
340
} else {
336
- Some ( Documentation ( docs ) )
341
+ Some ( Documentation ( buf ) )
337
342
}
338
343
}
339
344
}
@@ -407,7 +412,7 @@ pub enum AttrInput {
407
412
}
408
413
409
414
impl Attr {
410
- fn from_src ( ast : ast:: Attr , hygiene : & Hygiene ) -> Option < Attr > {
415
+ fn from_src ( ast : ast:: Attr , hygiene : & Hygiene , index : u32 ) -> Option < Attr > {
411
416
let path = ModPath :: from_src ( ast. path ( ) ?, hygiene) ?;
412
417
let input = if let Some ( lit) = ast. literal ( ) {
413
418
let value = match lit. kind ( ) {
@@ -420,7 +425,7 @@ impl Attr {
420
425
} else {
421
426
None
422
427
} ;
423
- Some ( Attr { index : 0 , path, input } )
428
+ Some ( Attr { index, path, input } )
424
429
}
425
430
426
431
/// Maps this lowered `Attr` back to its original syntax node.
@@ -429,7 +434,7 @@ impl Attr {
429
434
///
430
435
/// Note that the returned syntax node might be a `#[cfg_attr]`, or a doc comment, instead of
431
436
/// the attribute represented by `Attr`.
432
- pub fn to_src ( & self , owner : & dyn AttrsOwner ) -> Either < ast:: Attr , ast:: Comment > {
437
+ pub fn to_src ( & self , owner : & dyn ast :: AttrsOwner ) -> Either < ast:: Attr , ast:: Comment > {
433
438
collect_attrs ( owner) . nth ( self . index as usize ) . unwrap_or_else ( || {
434
439
panic ! ( "cannot find `Attr` at index {} in {}" , self . index, owner. syntax( ) )
435
440
} )
@@ -508,7 +513,7 @@ impl<'a> AttrQuery<'a> {
508
513
self . attrs ( ) . next ( ) . is_some ( )
509
514
}
510
515
511
- pub fn attrs ( self ) -> impl Iterator < Item = & ' a Attr > {
516
+ pub fn attrs ( self ) -> impl Iterator < Item = & ' a Attr > + Clone {
512
517
let key = self . key ;
513
518
self . attrs
514
519
. iter ( )
@@ -521,7 +526,7 @@ where
521
526
N : ast:: AttrsOwner ,
522
527
{
523
528
let src = InFile :: new ( src. file_id , src. to_node ( db. upcast ( ) ) ) ;
524
- RawAttrs :: from_attrs_owner ( db, src. as_ref ( ) . map ( |it| it as & dyn AttrsOwner ) )
529
+ RawAttrs :: from_attrs_owner ( db, src. as_ref ( ) . map ( |it| it as & dyn ast :: AttrsOwner ) )
525
530
}
526
531
527
532
fn attrs_from_item_tree < N : ItemTreeNode > ( id : ItemTreeId < N > , db : & dyn DefDatabase ) -> RawAttrs {
@@ -530,7 +535,9 @@ fn attrs_from_item_tree<N: ItemTreeNode>(id: ItemTreeId<N>, db: &dyn DefDatabase
530
535
tree. raw_attrs ( mod_item. into ( ) ) . clone ( )
531
536
}
532
537
533
- fn collect_attrs ( owner : & dyn AttrsOwner ) -> impl Iterator < Item = Either < ast:: Attr , ast:: Comment > > {
538
+ fn collect_attrs (
539
+ owner : & dyn ast:: AttrsOwner ,
540
+ ) -> impl Iterator < Item = Either < ast:: Attr , ast:: Comment > > {
534
541
let ( inner_attrs, inner_docs) = inner_attributes ( owner. syntax ( ) )
535
542
. map_or ( ( None , None ) , |( attrs, docs) | ( ( Some ( attrs) , Some ( docs) ) ) ) ;
536
543
0 commit comments