@@ -6,7 +6,9 @@ use hir_expand::{
66 name:: { name, Name } ,
77 MacroDefId ,
88} ;
9+ use indexmap:: IndexMap ;
910use rustc_hash:: FxHashSet ;
11+ use smallvec:: SmallVec ;
1012
1113use crate :: {
1214 body:: scope:: { ExprScopes , ScopeId } ,
@@ -348,10 +350,50 @@ impl Resolver {
348350 item_map. resolve_path ( db, module, path, BuiltinShadowMode :: Other ) . 0 . take_macros ( )
349351 }
350352
351- pub fn process_all_names ( & self , db : & dyn DefDatabase , f : & mut dyn FnMut ( Name , ScopeDef ) ) {
353+ /// Returns a set of names available in the current scope.
354+ ///
355+ /// Note that this is a somewhat fuzzy concept -- internally, the compiler
356+ /// doesn't necessary follow a strict scoping discipline. Rathe, it just
357+ /// tells for each ident what it resolves to.
358+ ///
359+ /// A good example is something like `str::from_utf8`. From scopes point of
360+ /// view, this code is erroneous -- both `str` module and `str` type occupy
361+ /// the same type namespace.
362+ ///
363+ /// We don't try to model that super-correctly -- this functionality is
364+ /// primarily exposed for completions.
365+ ///
366+ /// Note that in Rust one name can be bound to several items:
367+ ///
368+ /// ```
369+ /// macro_rules! t { () => (()) }
370+ /// type t = t!();
371+ /// const t: t = t!()
372+ /// ```
373+ ///
374+ /// That's why we return a multimap.
375+ ///
376+ /// The shadowing is accounted for: in
377+ ///
378+ /// ```
379+ /// let x = 92;
380+ /// {
381+ /// let x = 92;
382+ /// $0
383+ /// }
384+ /// ```
385+ ///
386+ /// there will be only one entry for `x` in the result.
387+ ///
388+ /// The result is ordered *roughly* from the innermost scope to the
389+ /// outermost: when the name is introduced in two namespaces in two scopes,
390+ /// we use the position of the first scope.
391+ pub fn names_in_scope ( & self , db : & dyn DefDatabase ) -> IndexMap < Name , SmallVec < [ ScopeDef ; 1 ] > > {
392+ let mut res = ScopeNames :: default ( ) ;
352393 for scope in self . scopes ( ) {
353- scope. process_names ( db, f ) ;
394+ scope. process_names ( db, & mut res ) ;
354395 }
396+ res. map
355397 }
356398
357399 pub fn traits_in_scope ( & self , db : & dyn DefDatabase ) -> FxHashSet < TraitId > {
@@ -434,8 +476,11 @@ impl Resolver {
434476 }
435477}
436478
479+ #[ derive( Debug , PartialEq , Eq ) ]
437480pub enum ScopeDef {
438- PerNs ( PerNs ) ,
481+ ModuleDef ( ModuleDefId ) ,
482+ MacroDef ( MacroDefId ) ,
483+ Unknown ,
439484 ImplSelfType ( ImplId ) ,
440485 AdtSelfType ( AdtId ) ,
441486 GenericParam ( GenericParamId ) ,
@@ -444,8 +489,7 @@ pub enum ScopeDef {
444489}
445490
446491impl Scope {
447- fn process_names ( & self , db : & dyn DefDatabase , f : & mut dyn FnMut ( Name , ScopeDef ) ) {
448- let mut seen = FxHashSet :: default ( ) ;
492+ fn process_names ( & self , db : & dyn DefDatabase , acc : & mut ScopeNames ) {
449493 match self {
450494 Scope :: ModuleScope ( m) => {
451495 // FIXME: should we provide `self` here?
@@ -456,58 +500,53 @@ impl Scope {
456500 // }),
457501 // );
458502 m. def_map [ m. module_id ] . scope . entries ( ) . for_each ( |( name, def) | {
459- f ( name . clone ( ) , ScopeDef :: PerNs ( def) ) ;
503+ acc . add_per_ns ( name , def) ;
460504 } ) ;
461- m. def_map [ m. module_id ] . scope . legacy_macros ( ) . for_each ( |( name, macro_) | {
462- let scope = PerNs :: macros ( macro_, Visibility :: Public ) ;
463- seen. insert ( ( name. clone ( ) , scope) ) ;
464- f ( name. clone ( ) , ScopeDef :: PerNs ( scope) ) ;
505+ m. def_map [ m. module_id ] . scope . legacy_macros ( ) . for_each ( |( name, mac) | {
506+ acc. add ( name, ScopeDef :: MacroDef ( mac) ) ;
465507 } ) ;
466508 m. def_map . extern_prelude ( ) . for_each ( |( name, & def) | {
467- f ( name . clone ( ) , ScopeDef :: PerNs ( PerNs :: types ( def, Visibility :: Public ) ) ) ;
509+ acc . add ( name , ScopeDef :: ModuleDef ( def) ) ;
468510 } ) ;
469511 BUILTIN_SCOPE . iter ( ) . for_each ( |( name, & def) | {
470- f ( name . clone ( ) , ScopeDef :: PerNs ( def) ) ;
512+ acc . add_per_ns ( name , def) ;
471513 } ) ;
472514 if let Some ( prelude) = m. def_map . prelude ( ) {
473515 let prelude_def_map = prelude. def_map ( db) ;
474- prelude_def_map[ prelude. local_id ] . scope . entries ( ) . for_each ( |( name, def) | {
475- let seen_tuple = ( name. clone ( ) , def) ;
476- if !seen. contains ( & seen_tuple) {
477- f ( seen_tuple. 0 , ScopeDef :: PerNs ( def) ) ;
478- }
479- } ) ;
516+ for ( name, def) in prelude_def_map[ prelude. local_id ] . scope . entries ( ) {
517+ acc. add_per_ns ( name, def)
518+ }
480519 }
481520 }
482521 Scope :: GenericParams { params, def : parent } => {
483522 let parent = * parent;
484523 for ( local_id, param) in params. types . iter ( ) {
485- if let Some ( ref name) = param. name {
524+ if let Some ( name) = & param. name {
486525 let id = TypeParamId { parent, local_id } ;
487- f ( name . clone ( ) , ScopeDef :: GenericParam ( id. into ( ) ) )
526+ acc . add ( name , ScopeDef :: GenericParam ( id. into ( ) ) )
488527 }
489528 }
490529 for ( local_id, param) in params. consts . iter ( ) {
491530 let id = ConstParamId { parent, local_id } ;
492- f ( param. name . clone ( ) , ScopeDef :: GenericParam ( id. into ( ) ) )
531+ acc . add ( & param. name , ScopeDef :: GenericParam ( id. into ( ) ) )
493532 }
494533 for ( local_id, param) in params. lifetimes . iter ( ) {
495534 let id = LifetimeParamId { parent, local_id } ;
496- f ( param. name . clone ( ) , ScopeDef :: GenericParam ( id. into ( ) ) )
535+ acc . add ( & param. name , ScopeDef :: GenericParam ( id. into ( ) ) )
497536 }
498537 }
499538 Scope :: ImplDefScope ( i) => {
500- f ( name ! [ Self ] , ScopeDef :: ImplSelfType ( * i) ) ;
539+ acc . add ( & name ! [ Self ] , ScopeDef :: ImplSelfType ( * i) ) ;
501540 }
502541 Scope :: AdtScope ( i) => {
503- f ( name ! [ Self ] , ScopeDef :: AdtSelfType ( * i) ) ;
542+ acc . add ( & name ! [ Self ] , ScopeDef :: AdtSelfType ( * i) ) ;
504543 }
505544 Scope :: ExprScope ( scope) => {
506545 if let Some ( ( label, name) ) = scope. expr_scopes . label ( scope. scope_id ) {
507- f ( name, ScopeDef :: Label ( label) )
546+ acc . add ( & name, ScopeDef :: Label ( label) )
508547 }
509548 scope. expr_scopes . entries ( scope. scope_id ) . iter ( ) . for_each ( |e| {
510- f ( e. name ( ) . clone ( ) , ScopeDef :: Local ( e. pat ( ) ) ) ;
549+ acc . add_local ( e. name ( ) , e. pat ( ) ) ;
511550 } ) ;
512551 }
513552 }
@@ -651,6 +690,47 @@ fn to_type_ns(per_ns: PerNs) -> Option<TypeNs> {
651690 Some ( res)
652691}
653692
693+ #[ derive( Default ) ]
694+ struct ScopeNames {
695+ map : IndexMap < Name , SmallVec < [ ScopeDef ; 1 ] > > ,
696+ }
697+
698+ impl ScopeNames {
699+ fn add ( & mut self , name : & Name , def : ScopeDef ) {
700+ let set = self . map . entry ( name. clone ( ) ) . or_default ( ) ;
701+ if !set. contains ( & def) {
702+ set. push ( def)
703+ }
704+ }
705+ fn add_per_ns ( & mut self , name : & Name , def : PerNs ) {
706+ if let Some ( ty) = & def. types {
707+ self . add ( name, ScopeDef :: ModuleDef ( ty. 0 ) )
708+ }
709+ if let Some ( val) = & def. values {
710+ self . add ( name, ScopeDef :: ModuleDef ( val. 0 ) )
711+ }
712+ if let Some ( mac) = & def. macros {
713+ self . add ( name, ScopeDef :: MacroDef ( mac. 0 ) )
714+ }
715+ if def. is_none ( ) {
716+ self . add ( name, ScopeDef :: Unknown )
717+ }
718+ }
719+ fn add_local ( & mut self , name : & Name , pat : PatId ) {
720+ let set = self . map . entry ( name. clone ( ) ) . or_default ( ) ;
721+ // XXX: hack, account for local (and only local) shadowing.
722+ //
723+ // This should be somewhat more principled and take namespaces into
724+ // accounts, but, alas, scoping rules are a hoax. `str` type and `str`
725+ // module can be both available in the same scope.
726+ if set. iter ( ) . any ( |it| matches ! ( it, & ScopeDef :: Local ( _) ) ) {
727+ cov_mark:: hit!( shadowing_shows_single_completion) ;
728+ return ;
729+ }
730+ set. push ( ScopeDef :: Local ( pat) )
731+ }
732+ }
733+
654734pub trait HasResolver : Copy {
655735 /// Builds a resolver for type references inside this def.
656736 fn resolver ( self , db : & dyn DefDatabase ) -> Resolver ;
0 commit comments