@@ -14,7 +14,6 @@ use crate::named_entity::{self, AsUnique, DesignEnt, HasEntityId, NamedEntities,
1414use crate :: syntax:: Kind :: * ;
1515use crate :: syntax:: { Kind , Symbols , Token , TokenAccess , Tokenizer , Value } ;
1616use crate :: { AnyEntKind , Design , EntRef , EntityId , HasTokenSpan , Overloaded , Position , Source } ;
17- use itertools:: Itertools ;
1817use std:: collections:: HashSet ;
1918use std:: default:: Default ;
2019use std:: iter:: once;
@@ -350,12 +349,46 @@ impl<'a> Searcher for CompletionSearcher<'a> {
350349 fn search_decl ( & mut self , ctx : & dyn TokenAccess , decl : FoundDeclaration ) -> SearchState {
351350 match decl {
352351 FoundDeclaration :: Architecture ( body) => {
352+ // ensure we are in the concurrent region
353+ if !ctx
354+ . get_span ( body. begin_token , body. get_end_token ( ) )
355+ . contains ( self . cursor )
356+ {
357+ return Finished ( NotFound ) ;
358+ }
359+ // Add architecture declarations to the list of completed names
360+ self . completions . extend (
361+ body. decl
362+ . iter ( )
363+ . filter_map ( |decl| decl. ent_id ( ) )
364+ . map ( |eid| self . root . get_ent ( eid) )
365+ . filter ( |ent| {
366+ matches ! (
367+ ent. kind( ) ,
368+ AnyEntKind :: Object ( _) | AnyEntKind :: ObjectAlias { .. }
369+ )
370+ } )
371+ . map ( CompletionItem :: Simple ) ,
372+ ) ;
373+
353374 let Some ( eid) = body. entity_name . reference . get ( ) else {
354375 return Finished ( NotFound ) ;
355376 } ;
356377 let Some ( ent) = DesignEnt :: from_any ( self . root . get_ent ( eid) ) else {
357378 return Finished ( NotFound ) ;
358379 } ;
380+ // Add ports and generics to the list of completed items
381+ if let Design :: Entity ( _, region) = ent. kind ( ) {
382+ self . completions
383+ . extend ( region. entities . values ( ) . filter_map ( |ent| {
384+ if let NamedEntities :: Single ( ent) = ent {
385+ Some ( CompletionItem :: Simple ( ent) )
386+ } else {
387+ None
388+ }
389+ } ) )
390+ }
391+ // Early-exit for when we are inside a statement.
359392 for statement in & body. statements {
360393 let pos = & statement. statement . pos ;
361394
@@ -368,45 +401,45 @@ impl<'a> Searcher for CompletionSearcher<'a> {
368401 return Finished ( NotFound ) ;
369402 }
370403 }
371- if ctx
372- . get_span ( body. begin_token , body. get_end_token ( ) )
373- . contains ( self . cursor )
374- {
375- self . completions = self
376- . root
404+ self . completions . extend (
405+ self . root
377406 . get_visible_entities_from_entity ( ent)
378- . map ( |eid| {
379- let ent = self . root . get_ent ( eid) ;
380- let architectures = get_architectures_for_entity ( ent, self . root ) ;
381- CompletionItem :: EntityInstantiation (
382- self . root . get_ent ( eid) ,
383- architectures,
384- )
385- } )
386- . collect ( )
387- }
407+ . map ( |eid| entity_to_completion_item ( self . root , eid) ) ,
408+ ) ;
388409 Finished ( Found )
389410 }
390411 _ => NotFinished ,
391412 }
392413 }
393414}
394415
416+ fn entity_to_completion_item ( root : & DesignRoot , eid : EntityId ) -> CompletionItem {
417+ let ent = root. get_ent ( eid) ;
418+ match ent. kind ( ) {
419+ AnyEntKind :: Design ( Design :: Entity ( ..) ) => {
420+ let architectures = get_architectures_for_entity ( ent, root) ;
421+ CompletionItem :: EntityInstantiation ( ent, architectures)
422+ }
423+ _ => CompletionItem :: Simple ( ent) ,
424+ }
425+ }
426+
395427/// Returns a vec populated with all architectures that belong to the given entity
396428fn get_architectures_for_entity < ' a > ( ent : EntRef < ' a > , root : & ' a DesignRoot ) -> Vec < EntRef < ' a > > {
397- if let Some ( design) = DesignEnt :: from_any ( ent) {
398- root. public_symbols ( )
399- . filter ( |sym| match sym. kind ( ) {
400- AnyEntKind :: Design ( Design :: Architecture ( arch_design) ) => {
401- arch_design. id ( ) == design. id ( )
402- }
403- _ => false ,
404- } )
405- . sorted_by_key ( |a| a. decl_pos ( ) )
406- . collect_vec ( )
407- } else {
408- vec ! [ ]
409- }
429+ let Some ( lib_symbol) = ent. library_name ( ) else {
430+ return vec ! [ ] ;
431+ } ;
432+ let Some ( lib) = root. get_lib ( lib_symbol) else {
433+ return vec ! [ ] ;
434+ } ;
435+ let Some ( sym) = ent. designator ( ) . as_identifier ( ) else {
436+ return vec ! [ ] ;
437+ } ;
438+ lib. secondary_units ( sym)
439+ . filter_map ( |locked_unit| locked_unit. unit . get ( ) )
440+ . filter_map ( |read_guard| read_guard. ent_id ( ) )
441+ . map ( |eid| root. get_ent ( eid) )
442+ . collect ( )
410443}
411444
412445impl DesignRoot {
@@ -644,6 +677,20 @@ mod test {
644677 . search_reference ( code. source ( ) , code. s1 ( "dout" ) . start ( ) )
645678 . unwrap ( ) ;
646679
680+ let clk_signal = root
681+ . search_reference (
682+ code. source ( ) ,
683+ code. s1 ( "signal clk, rst: bit;" ) . s1 ( "clk" ) . start ( ) ,
684+ )
685+ . unwrap ( ) ;
686+
687+ let rst_signal = root
688+ . search_reference (
689+ code. source ( ) ,
690+ code. s1 ( "signal clk, rst: bit;" ) . s1 ( "rst" ) . start ( ) ,
691+ )
692+ . unwrap ( ) ;
693+
647694 let cursor = code. s1 ( "port map (" ) . pos ( ) . end ( ) ;
648695 let options = list_completion_options ( & root, code. source ( ) , cursor) ;
649696 assert ! ( options. contains( & CompletionItem :: Formal ( rst) ) ) ;
@@ -655,14 +702,26 @@ mod test {
655702 . pos ( )
656703 . end ( ) ;
657704 let options = list_completion_options ( & root, code. source ( ) , cursor) ;
658- assert_eq ! ( options. len( ) , 0 ) ;
705+ assert_eq_unordered (
706+ & options,
707+ & [
708+ CompletionItem :: Simple ( clk_signal) ,
709+ CompletionItem :: Simple ( rst_signal) ,
710+ ] ,
711+ ) ;
659712 let cursor = code
660713 . s1 ( "port map (
661714 clk => c" )
662715 . pos ( )
663716 . end ( ) ;
664717 let options = list_completion_options ( & root, code. source ( ) , cursor) ;
665- assert_eq ! ( options. len( ) , 0 ) ;
718+ assert_eq_unordered (
719+ & options,
720+ & [
721+ CompletionItem :: Simple ( clk_signal) ,
722+ CompletionItem :: Simple ( rst_signal) ,
723+ ] ,
724+ ) ;
666725 }
667726
668727 #[ test]
@@ -874,9 +933,51 @@ end arch;
874933 . search_reference ( code1. source ( ) , code1. s1 ( "arch2" ) . start ( ) )
875934 . unwrap ( ) ;
876935
877- assert_eq ! (
878- options,
879- vec![ CompletionItem :: EntityInstantiation ( ent, vec![ arch1, arch2] ) ]
936+ match & options[ ..] {
937+ [ CompletionItem :: EntityInstantiation ( got_ent, architectures) ] => {
938+ assert_eq ! ( * got_ent, ent) ;
939+ assert_eq_unordered ( architectures, & [ arch1, arch2] ) ;
940+ }
941+ _ => panic ! ( "Expected entity instantiation" ) ,
942+ }
943+ }
944+
945+ #[ test]
946+ pub fn completes_signals_and_ports ( ) {
947+ let mut builder = LibraryBuilder :: new ( ) ;
948+ let code = builder. code (
949+ "libA" ,
950+ "\
951+ entity my_ent is
952+ port (
953+ foo : in bit
954+ );
955+ end my_ent;
956+
957+ architecture arch of my_ent is
958+ signal bar : natural;
959+ type foobaz is array(natural range <>) of bit;
960+ begin
961+ end arch;
962+ " ,
963+ ) ;
964+
965+ let ( root, diag) = builder. get_analyzed_root ( ) ;
966+ check_no_diagnostics ( & diag) ;
967+ let cursor = code. s1 ( "begin" ) . end ( ) ;
968+ let options = list_completion_options ( & root, code. source ( ) , cursor) ;
969+
970+ let ent1 = root
971+ . search_reference ( code. source ( ) , code. s1 ( "foo" ) . start ( ) )
972+ . unwrap ( ) ;
973+
974+ let ent2 = root
975+ . search_reference ( code. source ( ) , code. s1 ( "bar" ) . start ( ) )
976+ . unwrap ( ) ;
977+
978+ assert_eq_unordered (
979+ & options,
980+ & [ CompletionItem :: Simple ( ent1) , CompletionItem :: Simple ( ent2) ] ,
880981 )
881982 }
882983}
0 commit comments