@@ -125,15 +125,25 @@ fn insert(path: &Path, entry: IndexEntry) -> anyhow::Result<()> {
125125 let path = str_from_path ( path) ?;
126126
127127 let index = index. entry ( path. to_string ( ) ) . or_default ( ) ;
128+ index_insert ( index, entry) ;
128129
129- // Retain the first occurrence in the index. In the future we'll track every occurrences and
130- // their scopes but for now we only track the first definition of an object (in a way, its
130+ Ok ( ( ) )
131+ }
132+
133+ fn index_insert ( index : & mut HashMap < String , IndexEntry > , entry : IndexEntry ) {
134+ // We generally retain only the first occurrence in the index. In the
135+ // future we'll track every occurrences and their scopes but for now we
136+ // only track the first definition of an object (in a way, its
131137 // declaration).
132- if !index. contains_key ( & entry. key ) {
138+ if let Some ( existing_entry) = index. get ( & entry. key ) {
139+ // Give priority to non-section entries.
140+ if matches ! ( existing_entry. data, IndexEntryData :: Section { .. } ) {
141+ index. insert ( entry. key . clone ( ) , entry) ;
142+ }
143+ // Else, ignore.
144+ } else {
133145 index. insert ( entry. key . clone ( ) , entry) ;
134146 }
135-
136- Ok ( ( ) )
137147}
138148
139149fn clear ( path : & Path ) -> anyhow:: Result < ( ) > {
@@ -148,6 +158,24 @@ fn clear(path: &Path) -> anyhow::Result<()> {
148158 Ok ( ( ) )
149159}
150160
161+ #[ cfg( test) ]
162+ pub ( crate ) fn indexer_clear ( ) {
163+ let mut index = WORKSPACE_INDEX . lock ( ) . unwrap ( ) ;
164+ index. clear ( ) ;
165+ }
166+
167+ /// RAII guard that clears `WORKSPACE_INDEX` when dropped.
168+ /// Useful for ensuring a clean index state in tests.
169+ #[ cfg( test) ]
170+ pub ( crate ) struct ResetIndexerGuard ;
171+
172+ #[ cfg( test) ]
173+ impl Drop for ResetIndexerGuard {
174+ fn drop ( & mut self ) {
175+ indexer_clear ( ) ;
176+ }
177+ }
178+
151179fn str_from_path ( path : & Path ) -> anyhow:: Result < & str > {
152180 path. to_str ( ) . ok_or ( anyhow ! (
153181 "Couldn't convert path {} to string" ,
@@ -401,7 +429,9 @@ fn index_comment(
401429mod tests {
402430 use std:: path:: PathBuf ;
403431
432+ use assert_matches:: assert_matches;
404433 use insta:: assert_debug_snapshot;
434+ use tower_lsp:: lsp_types;
405435
406436 use super :: * ;
407437 use crate :: lsp:: documents:: Document ;
@@ -532,4 +562,67 @@ class <- R6::R6Class(
532562"#
533563 ) ;
534564 }
565+
566+ #[ test]
567+ fn test_index_insert_priority ( ) {
568+ let mut index = HashMap :: new ( ) ;
569+
570+ let section_entry = IndexEntry {
571+ key : "foo" . to_string ( ) ,
572+ range : Range :: new (
573+ lsp_types:: Position :: new ( 0 , 0 ) ,
574+ lsp_types:: Position :: new ( 0 , 3 ) ,
575+ ) ,
576+ data : IndexEntryData :: Section {
577+ level : 1 ,
578+ title : "foo" . to_string ( ) ,
579+ } ,
580+ } ;
581+
582+ let variable_entry = IndexEntry {
583+ key : "foo" . to_string ( ) ,
584+ range : Range :: new (
585+ lsp_types:: Position :: new ( 1 , 0 ) ,
586+ lsp_types:: Position :: new ( 1 , 3 ) ,
587+ ) ,
588+ data : IndexEntryData :: Variable {
589+ name : "foo" . to_string ( ) ,
590+ } ,
591+ } ;
592+
593+ // The Variable has priority and should replace the Section
594+ index_insert ( & mut index, section_entry. clone ( ) ) ;
595+ index_insert ( & mut index, variable_entry. clone ( ) ) ;
596+ assert_matches ! (
597+ & index. get( "foo" ) . unwrap( ) . data,
598+ IndexEntryData :: Variable { name } => assert_eq!( name, "foo" )
599+ ) ;
600+
601+ // Inserting a Section again with the same key does not override the Variable
602+ index_insert ( & mut index, section_entry. clone ( ) ) ;
603+ assert_matches ! (
604+ & index. get( "foo" ) . unwrap( ) . data,
605+ IndexEntryData :: Variable { name } => assert_eq!( name, "foo" )
606+ ) ;
607+
608+ let function_entry = IndexEntry {
609+ key : "foo" . to_string ( ) ,
610+ range : Range :: new (
611+ lsp_types:: Position :: new ( 2 , 0 ) ,
612+ lsp_types:: Position :: new ( 2 , 3 ) ,
613+ ) ,
614+ data : IndexEntryData :: Function {
615+ name : "foo" . to_string ( ) ,
616+ arguments : vec ! [ "a" . to_string( ) ] ,
617+ } ,
618+ } ;
619+
620+ // Inserting another kind of variable (e.g., Function) with the same key
621+ // does not override it either. The first occurrence is generally retained.
622+ index_insert ( & mut index, function_entry. clone ( ) ) ;
623+ assert_matches ! (
624+ & index. get( "foo" ) . unwrap( ) . data,
625+ IndexEntryData :: Variable { name } => assert_eq!( name, "foo" )
626+ ) ;
627+ }
535628}
0 commit comments