1- use std:: cell:: LazyCell ;
2-
31use hir:: {
4- base_db:: { intern:: Lookup , salsa:: Database , source_db:: SourceDb } ,
2+ base_db:: {
3+ intern:: Lookup ,
4+ salsa:: Database ,
5+ source_db:: { SourceDb , SourceRootDb } ,
6+ source_root:: SourceRootId ,
7+ } ,
58 container:: { ContainerId , InFile } ,
69 semantics:: Semantics ,
710 source_map:: IsSrc ,
811} ;
9- use itertools:: Itertools ;
10- use memchr:: memmem:: Finder ;
1112use nohash_hasher:: IntMap ;
1213use rustc_hash:: FxHashMap ;
13- use smallvec:: SmallVec ;
14- use syntax:: {
15- SyntaxNode , SyntaxTokenWithParent , has_text_range:: HasTextRange , ptr:: SyntaxTokenPtr ,
16- token:: TokenKindExt ,
17- } ;
18- use triomphe:: Arc ;
19- use utils:: {
20- get:: Get ,
21- line_index:: { TextRange , TextSize } ,
22- } ;
14+ use syntax:: { SyntaxTokenWithParent , ptr:: SyntaxTokenPtr } ;
15+ use utils:: { get:: Get , line_index:: TextRange } ;
2316use vfs:: FileId ;
2417
2518use super :: { ReferenceCategory , ReferencesConfig } ;
2619use crate :: {
2720 ScopeVisibility ,
28- db:: root_db:: RootDb ,
29- definitions:: { Definition , DefinitionClass } ,
30- source_targets :: SourceTargetRequestCache ,
21+ db:: { root_db:: RootDb , workspace_symbol_index_db :: source_root_semantic_index_for_root } ,
22+ definitions:: Definition ,
23+ workspace_symbols :: SemanticReference ,
3124} ;
3225
3326/// A search scope is a set of files and ranges within those files that should
@@ -136,6 +129,20 @@ impl SearchScope {
136129 pub ( crate ) fn range_for_file ( & self , file_id : FileId ) -> Option < Option < TextRange > > {
137130 self . 0 . get ( & file_id) . copied ( )
138131 }
132+
133+ pub ( crate ) fn contains ( & self , file_id : FileId , range : TextRange ) -> bool {
134+ self . range_for_file ( file_id) . is_some_and ( |file_range| {
135+ file_range. is_none_or ( |file_range| file_range. intersect ( range) . is_some ( ) )
136+ } )
137+ }
138+
139+ fn source_root_ids ( & self , db : & RootDb ) -> Vec < SourceRootId > {
140+ let mut root_ids =
141+ self . 0 . keys ( ) . map ( |file_id| db. source_root_id ( * file_id) ) . collect :: < Vec < _ > > ( ) ;
142+ root_ids. sort_unstable ( ) ;
143+ root_ids. dedup ( ) ;
144+ root_ids
145+ }
139146}
140147
141148pub ( crate ) struct ReferencesCtx < ' a , ' b > {
@@ -147,19 +154,17 @@ pub(crate) struct ReferencesCtx<'a, 'b> {
147154#[ derive( Debug , Clone , Copy ) ]
148155pub ( crate ) struct ReferenceToken {
149156 ptr : SyntaxTokenPtr ,
157+ range : TextRange ,
150158 category : ReferenceCategory ,
151159}
152160
153161impl ReferenceToken {
154- pub fn new ( token : SyntaxTokenWithParent ) -> Self {
155- Self {
156- ptr : SyntaxTokenPtr :: from_token ( token) ,
157- category : ReferenceCategory :: from_tok ( token) ,
158- }
162+ pub ( crate ) fn from_semantic_reference ( reference : & SemanticReference ) -> Self {
163+ Self { ptr : reference. ptr , range : reference. range , category : reference. category }
159164 }
160165
161166 pub fn range ( & self ) -> TextRange {
162- self . ptr . range ( )
167+ self . range
163168 }
164169
165170 pub fn category ( & self ) -> ReferenceCategory {
@@ -184,142 +189,26 @@ impl<'a, 'b> ReferencesCtx<'a, 'b> {
184189 }
185190
186191 pub ( crate ) fn search ( & self ) -> IntMap < FileId , Vec < ReferenceToken > > {
187- let sema = self . sema ;
188- let db = sema. db ;
192+ let db = self . sema . db ;
189193 let mut res: IntMap < _ , Vec < _ > > = IntMap :: default ( ) ;
190194
191- let Some ( name) = self . def . origins ( ) . into_iter ( ) . find_map ( |def| def. name ( db) ) else {
192- return res;
193- } ;
194- debug_assert ! { {
195- let names = self
196- . def
197- . origins( )
198- . into_iter( )
199- . filter_map( |def| def. name( sema. db) )
200- . collect_vec( ) ;
201- !names. is_empty( ) && names. iter( ) . all( |namei| namei == & name)
202- } } ;
203-
204- let def_ranges: SmallVec < [ _ ; 6 ] > =
205- self . def . origins ( ) . into_iter ( ) . filter_map ( |def| def. name_range ( db) ) . collect ( ) ;
206-
207- let finder = & Finder :: new ( & name) ;
208- let mut source_target_cache = SourceTargetRequestCache :: default ( ) ;
209- for ( text, file_id, range) in self . scope_files ( ) {
195+ for source_root_id in self . scope . source_root_ids ( db) {
210196 self . sema . db . unwind_if_cancelled ( ) ;
197+ let index = source_root_semantic_index_for_root ( db, source_root_id) ;
198+ let Some ( group) = index. references_for_definition ( self . def ) else {
199+ continue ;
200+ } ;
211201
212- let parsed_file = LazyCell :: new ( || sema. parse_file ( file_id) ) ;
213- Self :: match_text ( & text, finder, range)
214- . flat_map ( |offset| {
215- let Some ( root) = ( * parsed_file) . root ( ) else {
216- return Vec :: new ( ) ;
217- } ;
218- Self :: filter_tokens (
219- sema. db ,
220- root,
221- file_id,
222- & def_ranges,
223- offset,
224- & mut source_target_cache,
225- )
226- } )
227- . filter ( |tp| self . classify_and_filter ( sema, file_id. into ( ) , tp) )
228- . for_each ( |token| {
229- res. entry ( file_id)
230- . or_insert_with ( || Vec :: with_capacity ( Self :: FILE_REF_CAPACITY ) )
231- . push ( ReferenceToken :: new ( token) )
232- } ) ;
202+ for reference in group. references . iter ( ) {
203+ if !self . scope . contains ( reference. file_id , reference. range ) {
204+ continue ;
205+ }
206+ res. entry ( reference. file_id )
207+ . or_insert_with ( || Vec :: with_capacity ( Self :: FILE_REF_CAPACITY ) )
208+ . push ( ReferenceToken :: from_semantic_reference ( reference) ) ;
209+ }
233210 }
234211
235212 res
236213 }
237-
238- fn scope_files ( & self ) -> impl Iterator < Item = ( Arc < str > , FileId , TextRange ) > + ' _ {
239- self . scope . 0 . iter ( ) . map ( |( file_id, range) | {
240- let text = self . sema . db . file_text ( * file_id) ;
241- let range = range. unwrap_or_else ( || TextRange :: up_to ( TextSize :: of ( & * text) ) ) ;
242- ( text, * file_id, range)
243- } )
244- }
245-
246- fn match_text < ' c > (
247- text : & ' c str ,
248- finder : & ' c Finder ,
249- search_range : TextRange ,
250- ) -> impl Iterator < Item = TextSize > + ' c {
251- finder. find_iter ( text. as_bytes ( ) ) . filter_map ( move |idx| {
252- let offset = TextSize :: from ( idx as u32 ) ;
253- if !search_range. contains_inclusive ( offset) {
254- return None ;
255- }
256-
257- // If this is not a word boundary, that means this is only part of an ident.
258- if text[ ..idx] . chars ( ) . next_back ( ) . is_some_and ( |ch| ch. is_alphabetic ( ) || ch == '_' )
259- || text[ idx + finder. needle ( ) . len ( ) ..]
260- . chars ( )
261- . next ( )
262- . is_some_and ( |ch| ch. is_alphanumeric ( ) || ch == '_' )
263- {
264- return None ;
265- }
266-
267- Some ( offset)
268- } )
269- }
270-
271- fn filter_tokens < ' tree > (
272- db : & RootDb ,
273- node : SyntaxNode < ' tree > ,
274- file_id : FileId ,
275- names : & [ InFile < TextRange > ] ,
276- offset : TextSize ,
277- source_target_cache : & mut SourceTargetRequestCache ,
278- ) -> Vec < SyntaxTokenWithParent < ' tree > > {
279- let Some ( target) = crate :: source_targets:: source_target_at_offset_with_cache (
280- db,
281- file_id,
282- node,
283- offset,
284- super :: token_precedence,
285- source_target_cache,
286- )
287- . and_then ( |resolution| resolution. resolved ( ) ) else {
288- return Vec :: new ( ) ;
289- } ;
290-
291- target
292- . into_tokens ( )
293- . into_iter ( )
294- . filter ( |tok| tok. kind ( ) . name_like ( ) )
295- . filter ( |tok| {
296- let Some ( tok_range) = tok. text_range ( ) else {
297- return false ;
298- } ;
299-
300- !names. iter ( ) . any ( |InFile { value : range, file_id : name_file_id } | {
301- tok_range == * range && * name_file_id == file_id. into ( )
302- } )
303- } )
304- . collect ( )
305- }
306-
307- fn classify_and_filter < ' tree > (
308- & self ,
309- sema : & Semantics < ' _ , RootDb > ,
310- file_id : hir:: file:: HirFileId ,
311- tp : & SyntaxTokenWithParent < ' tree > ,
312- ) -> bool {
313- let Some ( def) = DefinitionClass :: resolve ( sema, file_id, * tp) else {
314- return false ;
315- } ;
316-
317- match def {
318- DefinitionClass :: Definition ( def) => def == * self . def ,
319- DefinitionClass :: PortConnShorthand { local, port } => {
320- local == * self . def || port == * self . def
321- }
322- DefinitionClass :: Ambiguous ( _) => false ,
323- }
324- }
325214}
0 commit comments