11use fst;
2- use std:: collections:: { HashMap , HashSet } ;
2+ use std:: collections:: { BTreeMap , HashMap , HashSet } ;
33use std:: iter;
44use std:: path:: { Path , PathBuf } ;
55use std:: time:: SystemTime ;
66
77use crate :: raw:: { CrateId , DefKind } ;
88use crate :: { Id , Span , SymbolQuery } ;
9+ use span:: { Column , Row , ZeroIndexed } ;
910
1011/// This is the main database that contains all the collected symbol information,
1112/// such as definitions, their mapping between spans, hierarchy and so on,
1213/// organized in a per-crate fashion.
13- #[ derive( Debug ) ]
1414pub ( crate ) struct Analysis {
1515 /// Contains lowered data with global inter-crate `Id`s per each crate.
1616 pub per_crate : HashMap < CrateId , PerCrateAnalysis > ,
@@ -31,7 +31,6 @@ pub(crate) struct Analysis {
3131 pub src_url_base : String ,
3232}
3333
34- #[ derive( Debug ) ]
3534pub struct PerCrateAnalysis {
3635 // Map span to id of def (either because it is the span of the def, or of
3736 // the def for the ref).
@@ -49,6 +48,7 @@ pub struct PerCrateAnalysis {
4948 pub ref_spans : HashMap < Id , Vec < Span > > ,
5049 pub globs : HashMap < Span , Glob > ,
5150 pub impls : HashMap < Id , Vec < Span > > ,
51+ pub idents : HashMap < PathBuf , IdentsByLine > ,
5252
5353 pub root_id : Option < Id > ,
5454 pub timestamp : SystemTime ,
@@ -103,6 +103,40 @@ pub struct Def {
103103 // pub sig: Option<Signature>,
104104}
105105
106+ pub type Idents = HashMap < PathBuf , IdentsByLine > ;
107+ pub type IdentsByLine = BTreeMap < Row < ZeroIndexed > , IdentsByColumn > ;
108+ pub type IdentsByColumn = BTreeMap < Column < ZeroIndexed > , IdentBound > ;
109+
110+ /// We store the identifiers for a file in a BTreeMap ordered by starting index.
111+ /// This struct contains the rest of the information we need to create an `Ident`.
112+ ///
113+ /// We're optimising for space, rather than speed (of getting an Ident), because
114+ /// we have to build the whole index for every file (which is a lot for a large
115+ /// project), whereas we only get idents a few at a time and not very often.
116+ #[ derive( new, Clone , Debug ) ]
117+ pub struct IdentBound {
118+ pub column_end : Column < ZeroIndexed > ,
119+ pub id : Id ,
120+ pub kind : IdentKind ,
121+ }
122+
123+ #[ derive( Copy , Clone , Debug , Eq , PartialEq ) ]
124+ pub enum IdentKind {
125+ Def ,
126+ Ref ,
127+ }
128+
129+ /// An identifier (either a reference or definition).
130+ ///
131+ /// This struct represents the syntactic name, use the `id` to look up semantic
132+ /// information.
133+ #[ derive( new, Clone , Debug ) ]
134+ pub struct Ident {
135+ pub span : Span ,
136+ pub id : Id ,
137+ pub kind : IdentKind ,
138+ }
139+
106140#[ derive( Debug , Clone ) ]
107141pub struct Signature {
108142 pub span : Span ,
@@ -139,6 +173,7 @@ impl PerCrateAnalysis {
139173 ref_spans : HashMap :: new ( ) ,
140174 globs : HashMap :: new ( ) ,
141175 impls : HashMap :: new ( ) ,
176+ idents : HashMap :: new ( ) ,
142177 root_id : None ,
143178 timestamp,
144179 path,
@@ -155,6 +190,48 @@ impl PerCrateAnalysis {
155190 None => false ,
156191 }
157192 }
193+
194+ // Returns all identifiers which overlap with `span`. There is no guarantee about
195+ // the ordering of identifiers in the result, but they will probably be roughly
196+ // in order of appearance.
197+ #[ cfg( feature = "idents" ) ]
198+ fn idents ( & self , span : & Span ) -> Vec < Ident > {
199+ self . idents
200+ . get ( & span. file )
201+ . map ( |by_line| {
202+ ( span. range . row_start ..=span. range . row_end )
203+ . flat_map ( |line| {
204+ let vec = by_line
205+ . get ( & line)
206+ . iter ( )
207+ . flat_map ( |by_col| {
208+ by_col. into_iter ( ) . filter_map ( |( col_start, id) | {
209+ if col_start <= & span. range . col_end
210+ && id. column_end >= span. range . col_start
211+ {
212+ Some ( Ident :: new (
213+ Span :: new (
214+ line,
215+ line,
216+ * col_start,
217+ id. column_end ,
218+ span. file . clone ( ) ,
219+ ) ,
220+ id. id ,
221+ id. kind ,
222+ ) )
223+ } else {
224+ None
225+ }
226+ } )
227+ } )
228+ . collect :: < Vec < Ident > > ( ) ;
229+ vec. into_iter ( )
230+ } )
231+ . collect :: < Vec < Ident > > ( )
232+ } )
233+ . unwrap_or_else ( Vec :: new)
234+ }
158235}
159236
160237impl Analysis {
@@ -302,6 +379,19 @@ impl Analysis {
302379 self . for_each_crate ( |c| c. defs_per_file . get ( file) . map ( & f) )
303380 }
304381
382+ #[ cfg( feature = "idents" ) ]
383+ pub fn idents ( & self , span : & Span ) -> Vec < Ident > {
384+ self . for_each_crate ( |c| {
385+ let result = c. idents ( span) ;
386+ if result. is_empty ( ) {
387+ None
388+ } else {
389+ Some ( result)
390+ }
391+ } )
392+ . unwrap_or_else ( Vec :: new)
393+ }
394+
305395 pub fn query_defs ( & self , query : SymbolQuery ) -> Vec < Def > {
306396 let mut crates = Vec :: with_capacity ( self . per_crate . len ( ) ) ;
307397 let stream = query. build_stream ( self . per_crate . values ( ) . map ( |c| {
0 commit comments