@@ -85,6 +85,7 @@ impl SearchScope {
85
85
SearchScope { entries }
86
86
}
87
87
88
+ /// Build a search scope spanning the entire crate graph of files.
88
89
fn crate_graph ( db : & RootDatabase ) -> SearchScope {
89
90
let mut entries = FxHashMap :: default ( ) ;
90
91
@@ -98,6 +99,7 @@ impl SearchScope {
98
99
SearchScope { entries }
99
100
}
100
101
102
+ /// Build a search scope spanning all the reverse dependencies of the given crate.
101
103
fn reverse_dependencies ( db : & RootDatabase , of : hir:: Crate ) -> SearchScope {
102
104
let mut entries = FxHashMap :: default ( ) ;
103
105
for rev_dep in of. transitive_reverse_dependencies ( db) {
@@ -109,6 +111,7 @@ impl SearchScope {
109
111
SearchScope { entries }
110
112
}
111
113
114
+ /// Build a search scope spanning the given crate.
112
115
fn krate ( db : & RootDatabase , of : hir:: Crate ) -> SearchScope {
113
116
let root_file = of. root_file ( db) ;
114
117
let source_root_id = db. file_source_root ( root_file) ;
@@ -118,55 +121,55 @@ impl SearchScope {
118
121
}
119
122
}
120
123
121
- fn module ( db : & RootDatabase , module : hir:: Module ) -> SearchScope {
124
+ /// Build a search scope spanning the given module and all its submodules.
125
+ fn module_and_children ( db : & RootDatabase , module : hir:: Module ) -> SearchScope {
122
126
let mut entries = FxHashMap :: default ( ) ;
123
127
124
- let mut to_visit = vec ! [ module] ;
125
- let mut is_first = true ;
128
+ let ( file_id, range) = {
129
+ let InFile { file_id, value } = module. definition_source ( db) ;
130
+ if let Some ( ( file_id, call_source) ) = file_id. original_call_node ( db) {
131
+ ( file_id, Some ( call_source. text_range ( ) ) )
132
+ } else {
133
+ (
134
+ file_id. original_file ( db) ,
135
+ match value {
136
+ ModuleSource :: SourceFile ( _) => None ,
137
+ ModuleSource :: Module ( it) => Some ( it. syntax ( ) . text_range ( ) ) ,
138
+ ModuleSource :: BlockExpr ( it) => Some ( it. syntax ( ) . text_range ( ) ) ,
139
+ } ,
140
+ )
141
+ }
142
+ } ;
143
+ entries. insert ( file_id, range) ;
144
+
145
+ let mut to_visit: Vec < _ > = module. children ( db) . collect ( ) ;
126
146
while let Some ( module) = to_visit. pop ( ) {
127
- let src = module. definition_source ( db) ;
128
- let file_id = src. file_id . original_file ( db) ;
129
- match src. value {
130
- ModuleSource :: Module ( m) => {
131
- if is_first {
132
- let range = Some ( m. syntax ( ) . text_range ( ) ) ;
133
- entries. insert ( file_id, range) ;
134
- } else {
135
- // We have already added the enclosing file to the search scope,
136
- // so do nothing.
137
- }
138
- }
139
- ModuleSource :: BlockExpr ( b) => {
140
- if is_first {
141
- let range = Some ( b. syntax ( ) . text_range ( ) ) ;
142
- entries. insert ( file_id, range) ;
143
- } else {
144
- // We have already added the enclosing file to the search scope,
145
- // so do nothing.
146
- }
147
- }
148
- ModuleSource :: SourceFile ( _) => {
149
- entries. insert ( file_id, None ) ;
150
- }
151
- } ;
152
- is_first = false ;
147
+ if let InFile { file_id, value : ModuleSource :: SourceFile ( _) } =
148
+ module. definition_source ( db)
149
+ {
150
+ entries. insert ( file_id. original_file ( db) , None ) ;
151
+ }
153
152
to_visit. extend ( module. children ( db) ) ;
154
153
}
155
154
SearchScope { entries }
156
155
}
157
156
157
+ /// Build an empty search scope.
158
158
pub fn empty ( ) -> SearchScope {
159
159
SearchScope :: new ( FxHashMap :: default ( ) )
160
160
}
161
161
162
+ /// Build a empty search scope spanning the given file.
162
163
pub fn single_file ( file : FileId ) -> SearchScope {
163
164
SearchScope :: new ( std:: iter:: once ( ( file, None ) ) . collect ( ) )
164
165
}
165
166
167
+ /// Build a empty search scope spanning the text range of the given file.
166
168
pub fn file_range ( range : FileRange ) -> SearchScope {
167
169
SearchScope :: new ( std:: iter:: once ( ( range. file_id , Some ( range. range ) ) ) . collect ( ) )
168
170
}
169
171
172
+ /// Build a empty search scope spanning the given files.
170
173
pub fn files ( files : & [ FileId ] ) -> SearchScope {
171
174
SearchScope :: new ( files. iter ( ) . map ( |f| ( * f, None ) ) . collect ( ) )
172
175
}
@@ -177,29 +180,23 @@ impl SearchScope {
177
180
mem:: swap ( & mut small, & mut large)
178
181
}
179
182
183
+ let intersect_ranges =
184
+ |r1 : Option < TextRange > , r2 : Option < TextRange > | -> Option < Option < TextRange > > {
185
+ match ( r1, r2) {
186
+ ( None , r) | ( r, None ) => Some ( r) ,
187
+ ( Some ( r1) , Some ( r2) ) => r1. intersect ( r2) . map ( Some ) ,
188
+ }
189
+ } ;
180
190
let res = small
181
191
. iter ( )
182
- . filter_map ( |( file_id, r1) | {
183
- let r2 = large. get ( file_id) ?;
184
- let r = intersect_ranges ( * r1, * r2) ?;
185
- Some ( ( * file_id, r) )
192
+ . filter_map ( |( & file_id, & r1) | {
193
+ let & r2 = large. get ( & file_id) ?;
194
+ let r = intersect_ranges ( r1, r2) ?;
195
+ Some ( ( file_id, r) )
186
196
} )
187
197
. collect ( ) ;
188
198
189
- return SearchScope :: new ( res) ;
190
-
191
- fn intersect_ranges (
192
- r1 : Option < TextRange > ,
193
- r2 : Option < TextRange > ,
194
- ) -> Option < Option < TextRange > > {
195
- match ( r1, r2) {
196
- ( None , r) | ( r, None ) => Some ( r) ,
197
- ( Some ( r1) , Some ( r2) ) => {
198
- let r = r1. intersect ( r2) ?;
199
- Some ( Some ( r) )
200
- }
201
- }
202
- }
199
+ SearchScope :: new ( res)
203
200
}
204
201
}
205
202
@@ -282,7 +279,8 @@ impl Definition {
282
279
hir:: MacroKind :: BuiltIn => SearchScope :: crate_graph ( db) ,
283
280
// FIXME: We don't actually see derives in derive attributes as these do not
284
281
// expand to something that references the derive macro in the output.
285
- // We could get around this by emitting dummy `use DeriveMacroPathHere as _;` items maybe?
282
+ // We could get around this by doing pseudo expansions for proc_macro_derive like we
283
+ // do for the derive attribute
286
284
hir:: MacroKind :: Derive | hir:: MacroKind :: Attr | hir:: MacroKind :: ProcMacro => {
287
285
SearchScope :: reverse_dependencies ( db, module. krate ( ) )
288
286
}
@@ -294,7 +292,7 @@ impl Definition {
294
292
return SearchScope :: reverse_dependencies ( db, module. krate ( ) ) ;
295
293
}
296
294
if let Some ( Visibility :: Module ( module) ) = vis {
297
- return SearchScope :: module ( db, module. into ( ) ) ;
295
+ return SearchScope :: module_and_children ( db, module. into ( ) ) ;
298
296
}
299
297
300
298
let range = match module_source {
@@ -341,10 +339,12 @@ impl<'a> FindUsages<'a> {
341
339
self
342
340
}
343
341
342
+ /// Limit the search to a given [`SearchScope`].
344
343
pub fn in_scope ( self , scope : SearchScope ) -> FindUsages < ' a > {
345
344
self . set_scope ( Some ( scope) )
346
345
}
347
346
347
+ /// Limit the search to a given [`SearchScope`].
348
348
pub fn set_scope ( mut self , scope : Option < SearchScope > ) -> FindUsages < ' a > {
349
349
assert ! ( self . scope. is_none( ) ) ;
350
350
self . scope = scope;
@@ -420,6 +420,7 @@ impl<'a> FindUsages<'a> {
420
420
Some ( offset)
421
421
} )
422
422
}
423
+
423
424
fn scope_files < ' a > (
424
425
sema : & ' a Semantics < RootDatabase > ,
425
426
scope : & ' a SearchScope ,
@@ -433,6 +434,12 @@ impl<'a> FindUsages<'a> {
433
434
} )
434
435
}
435
436
437
+ // FIXME: There should be optimization potential here
438
+ // Currently we try to descend everything we find which
439
+ // means we call `Semantics::descend_into_macros` on
440
+ // every textual hit. That function is notoriously
441
+ // expensive even for things that do not get down mapped
442
+ // into macros.
436
443
for ( text, file_id, search_range) in scope_files ( sema, & search_scope) {
437
444
let tree = Lazy :: new ( move || sema. parse ( file_id) . syntax ( ) . clone ( ) ) ;
438
445
@@ -463,7 +470,8 @@ impl<'a> FindUsages<'a> {
463
470
// Search for `super` and `crate` resolving to our module
464
471
match self . def {
465
472
Definition :: Module ( module) => {
466
- let scope = search_scope. intersection ( & SearchScope :: module ( self . sema . db , module) ) ;
473
+ let scope = search_scope
474
+ . intersection ( & SearchScope :: module_and_children ( self . sema . db , module) ) ;
467
475
468
476
let is_crate_root = module. is_crate_root ( self . sema . db ) ;
469
477
0 commit comments