@@ -9,6 +9,7 @@ use indexmap::IndexMap;
9
9
use itertools:: Itertools ;
10
10
use rustc_hash:: { FxHashSet , FxHasher } ;
11
11
use smallvec:: SmallVec ;
12
+ use stdx:: format_to;
12
13
use triomphe:: Arc ;
13
14
14
15
use crate :: {
@@ -53,13 +54,25 @@ pub struct ImportMap {
53
54
fst : fst:: Map < Vec < u8 > > ,
54
55
}
55
56
56
- #[ derive( Copy , Clone , PartialEq , Eq ) ]
57
+ #[ derive( Copy , Clone , Debug , PartialEq , Eq , Ord , PartialOrd ) ]
57
58
enum IsTraitAssocItem {
58
59
Yes ,
59
60
No ,
60
61
}
61
62
62
63
impl ImportMap {
64
+ pub fn dump ( & self , db : & dyn DefDatabase ) -> String {
65
+ let mut out = String :: new ( ) ;
66
+ for ( k, v) in self . map . iter ( ) {
67
+ format_to ! ( out, "{:?} ({:?}) -> " , k, v. 1 ) ;
68
+ for v in & v. 0 {
69
+ format_to ! ( out, "{}:{:?}, " , v. name. display( db. upcast( ) ) , v. container) ;
70
+ }
71
+ format_to ! ( out, "\n " ) ;
72
+ }
73
+ out
74
+ }
75
+
63
76
pub ( crate ) fn import_map_query ( db : & dyn DefDatabase , krate : CrateId ) -> Arc < Self > {
64
77
let _p = profile:: span ( "import_map_query" ) ;
65
78
@@ -68,26 +81,31 @@ impl ImportMap {
68
81
let mut importables: Vec < _ > = map
69
82
. iter ( )
70
83
// We've only collected items, whose name cannot be tuple field.
71
- . flat_map ( |( & item, ( info, _) ) | {
72
- info. iter ( )
73
- . map ( move |info| ( item, info. name . as_str ( ) . unwrap ( ) . to_ascii_lowercase ( ) ) )
84
+ . flat_map ( |( & item, ( info, is_assoc) ) | {
85
+ info. iter ( ) . map ( move |info| {
86
+ ( item, * is_assoc, info. name . as_str ( ) . unwrap ( ) . to_ascii_lowercase ( ) )
87
+ } )
74
88
} )
75
89
. collect ( ) ;
76
- importables. sort_by ( |( _, lhs_name) , ( _, rhs_name) | lhs_name. cmp ( rhs_name) ) ;
90
+ importables. sort_by ( |( _, l_is_assoc, lhs_name) , ( _, r_is_assoc, rhs_name) | {
91
+ lhs_name. cmp ( rhs_name) . then_with ( || l_is_assoc. cmp ( r_is_assoc) )
92
+ } ) ;
77
93
importables. dedup ( ) ;
78
94
79
95
// Build the FST, taking care not to insert duplicate values.
80
96
let mut builder = fst:: MapBuilder :: memory ( ) ;
81
- let iter =
82
- importables. iter ( ) . enumerate ( ) . dedup_by ( |( _, ( _, lhs) ) , ( _, ( _, rhs) ) | lhs == rhs) ;
83
- for ( start_idx, ( _, name) ) in iter {
97
+ let iter = importables
98
+ . iter ( )
99
+ . enumerate ( )
100
+ . dedup_by ( |( _, ( _, _, lhs) ) , ( _, ( _, _, rhs) ) | lhs == rhs) ;
101
+ for ( start_idx, ( _, _, name) ) in iter {
84
102
let _ = builder. insert ( name, start_idx as u64 ) ;
85
103
}
86
104
87
105
Arc :: new ( ImportMap {
88
106
map,
89
107
fst : builder. into_map ( ) ,
90
- importables : importables. into_iter ( ) . map ( |( item, _) | item) . collect ( ) ,
108
+ importables : importables. into_iter ( ) . map ( |( item, _, _ ) | item) . collect ( ) ,
91
109
} )
92
110
}
93
111
@@ -332,20 +350,20 @@ impl Query {
332
350
}
333
351
334
352
/// Checks whether the import map entry matches the query.
335
- fn import_matches (
336
- & self ,
337
- db : & dyn DefDatabase ,
338
- import : & ImportInfo ,
339
- enforce_lowercase : bool ,
340
- ) -> bool {
353
+ fn import_matches ( & self , import : & ImportInfo , enforce_lowercase : bool ) -> bool {
341
354
let _p = profile:: span ( "import_map::Query::import_matches" ) ;
342
355
343
356
// FIXME: Can we get rid of the alloc here?
344
- let mut input = import. name . display ( db. upcast ( ) ) . to_string ( ) ;
357
+ let input = import. name . to_smol_str ( ) ;
358
+ let mut _s_slot;
345
359
let case_insensitive = enforce_lowercase || !self . case_sensitive ;
346
- if case_insensitive {
347
- input. make_ascii_lowercase ( ) ;
348
- }
360
+ let input = if case_insensitive {
361
+ _s_slot = String :: from ( input) ;
362
+ _s_slot. make_ascii_lowercase ( ) ;
363
+ & * _s_slot
364
+ } else {
365
+ & * input
366
+ } ;
349
367
350
368
let query_string = if case_insensitive { & self . lowercased } else { & self . query } ;
351
369
@@ -355,7 +373,7 @@ impl Query {
355
373
SearchMode :: Fuzzy => {
356
374
let mut input_chars = input. chars ( ) ;
357
375
for query_char in query_string. chars ( ) {
358
- if input_chars. find ( | & it| it == query_char) . is_none ( ) {
376
+ if ! input_chars. any ( | it| it == query_char) {
359
377
return false ;
360
378
}
361
379
}
@@ -376,6 +394,7 @@ pub fn search_dependencies(
376
394
let _p = profile:: span ( "search_dependencies" ) . detail ( || format ! ( "{query:?}" ) ) ;
377
395
378
396
let graph = db. crate_graph ( ) ;
397
+
379
398
let import_maps: Vec < _ > =
380
399
graph[ krate] . dependencies . iter ( ) . map ( |dep| db. import_map ( dep. crate_id ) ) . collect ( ) ;
381
400
@@ -390,22 +409,28 @@ pub fn search_dependencies(
390
409
391
410
let mut res = FxHashSet :: default ( ) ;
392
411
let mut common_importable_data_scratch = vec ! [ ] ;
412
+ // FIXME: Improve this, its rather unreadable and does duplicate amount of work
393
413
while let Some ( ( _, indexed_values) ) = stream. next ( ) {
394
414
for & IndexedValue { index, value } in indexed_values {
395
415
let import_map = & import_maps[ index] ;
396
- let importables @ [ importable, ..] = & import_map. importables [ value as usize ..] else {
416
+ let importables = & import_map. importables [ value as usize ..] ;
417
+
418
+ // Find the first item in this group that has a matching assoc mode and slice the rest away
419
+ let Some ( importable) =
420
+ importables. iter ( ) . position ( |it| query. matches_assoc_mode ( import_map. map [ it] . 1 ) )
421
+ else {
397
422
continue ;
398
423
} ;
399
-
400
- let & ( ref importable_data, is_trait_assoc_item) = & import_map. map [ importable] ;
401
- if !query. matches_assoc_mode ( is_trait_assoc_item) {
424
+ let importables @ [ importable, ..] = & importables[ importable..] else {
402
425
continue ;
403
- }
426
+ } ;
404
427
428
+ // Fetch all the known names of this importable item (to handle import aliases/renames)
405
429
common_importable_data_scratch. extend (
406
- importable_data
430
+ import_map. map [ importable]
431
+ . 0
407
432
. iter ( )
408
- . filter ( |& info| query. import_matches ( db , info, true ) )
433
+ . filter ( |& info| query. import_matches ( info, true ) )
409
434
// Name shared by the importable items in this group.
410
435
. map ( |info| info. name . to_smol_str ( ) ) ,
411
436
) ;
@@ -419,6 +444,7 @@ pub fn search_dependencies(
419
444
common_importable_data_scratch. drain ( ..) . flat_map ( |common_importable_name| {
420
445
// Add the items from this name group. Those are all subsequent items in
421
446
// `importables` whose name match `common_importable_name`.
447
+
422
448
importables
423
449
. iter ( )
424
450
. copied ( )
@@ -434,11 +460,8 @@ pub fn search_dependencies(
434
460
. filter ( move |item| {
435
461
!query. case_sensitive || {
436
462
// we've already checked the common importables name case-insensitively
437
- let & ( ref import_infos, assoc_mode) = & import_map. map [ item] ;
438
- query. matches_assoc_mode ( assoc_mode)
439
- && import_infos
440
- . iter ( )
441
- . any ( |info| query. import_matches ( db, info, false ) )
463
+ let & ( ref import_infos, _) = & import_map. map [ item] ;
464
+ import_infos. iter ( ) . any ( |info| query. import_matches ( info, false ) )
442
465
}
443
466
} )
444
467
} ) ;
0 commit comments