@@ -77,33 +77,19 @@ impl RawAttrs {
77
77
pub ( crate ) const EMPTY : Self = Self { entries : None } ;
78
78
79
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 }
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
95
fn from_attrs_owner ( db : & dyn DefDatabase , owner : InFile < & dyn AttrsOwner > ) -> Self {
@@ -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 ;
@@ -325,15 +311,36 @@ 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. push ( '\n' ) ;
326
+ } else {
327
+ buf. extend ( Itertools :: intersperse (
328
+ doc. lines ( ) . map ( |line| {
329
+ line. char_indices ( )
330
+ . nth ( indent)
331
+ . map_or ( line, |( offset, _) | & line[ offset..] )
332
+ . trim_end ( )
333
+ } ) ,
334
+ "\n " ,
335
+ ) ) ;
336
+ }
337
+ buf. push ( '\n' ) ;
338
+ }
339
+ buf. pop ( ) ;
340
+ if buf. is_empty ( ) {
334
341
None
335
342
} else {
336
- Some ( Documentation ( docs ) )
343
+ Some ( Documentation ( buf ) )
337
344
}
338
345
}
339
346
}
@@ -407,7 +414,7 @@ pub enum AttrInput {
407
414
}
408
415
409
416
impl Attr {
410
- fn from_src ( ast : ast:: Attr , hygiene : & Hygiene ) -> Option < Attr > {
417
+ fn from_src ( ast : ast:: Attr , hygiene : & Hygiene , index : u32 ) -> Option < Attr > {
411
418
let path = ModPath :: from_src ( ast. path ( ) ?, hygiene) ?;
412
419
let input = if let Some ( lit) = ast. literal ( ) {
413
420
let value = match lit. kind ( ) {
@@ -420,7 +427,7 @@ impl Attr {
420
427
} else {
421
428
None
422
429
} ;
423
- Some ( Attr { index : 0 , path, input } )
430
+ Some ( Attr { index, path, input } )
424
431
}
425
432
426
433
/// Maps this lowered `Attr` back to its original syntax node.
@@ -508,7 +515,7 @@ impl<'a> AttrQuery<'a> {
508
515
self . attrs ( ) . next ( ) . is_some ( )
509
516
}
510
517
511
- pub fn attrs ( self ) -> impl Iterator < Item = & ' a Attr > {
518
+ pub fn attrs ( self ) -> impl Iterator < Item = & ' a Attr > + Clone {
512
519
let key = self . key ;
513
520
self . attrs
514
521
. iter ( )
0 commit comments