@@ -3,10 +3,11 @@ use std::{fmt, iter, mem};
3
3
4
4
use base_db:: CrateId ;
5
5
use hir_expand:: { name:: Name , MacroDefId } ;
6
- use intern:: sym;
6
+ use intern:: { sym, Symbol } ;
7
7
use itertools:: Itertools as _;
8
8
use rustc_hash:: FxHashSet ;
9
9
use smallvec:: { smallvec, SmallVec } ;
10
+ use span:: SyntaxContextId ;
10
11
use triomphe:: Arc ;
11
12
12
13
use crate :: {
@@ -342,15 +343,7 @@ impl Resolver {
342
343
}
343
344
344
345
if n_segments <= 1 {
345
- let mut hygiene_info = if !hygiene_id. is_root ( ) {
346
- let ctx = hygiene_id. lookup ( db) ;
347
- ctx. outer_expn . map ( |expansion| {
348
- let expansion = db. lookup_intern_macro_call ( expansion) ;
349
- ( ctx. parent , expansion. def )
350
- } )
351
- } else {
352
- None
353
- } ;
346
+ let mut hygiene_info = hygiene_info ( db, hygiene_id) ;
354
347
for scope in self . scopes ( ) {
355
348
match scope {
356
349
Scope :: ExprScope ( scope) => {
@@ -370,19 +363,7 @@ impl Resolver {
370
363
}
371
364
}
372
365
Scope :: MacroDefScope ( macro_id) => {
373
- if let Some ( ( parent_ctx, label_macro_id) ) = hygiene_info {
374
- if label_macro_id == * * macro_id {
375
- // A macro is allowed to refer to variables from before its declaration.
376
- // Therefore, if we got to the rib of its declaration, give up its hygiene
377
- // and use its parent expansion.
378
- let parent_ctx = db. lookup_intern_syntax_context ( parent_ctx) ;
379
- hygiene_id = HygieneId :: new ( parent_ctx. opaque_and_semitransparent ) ;
380
- hygiene_info = parent_ctx. outer_expn . map ( |expansion| {
381
- let expansion = db. lookup_intern_macro_call ( expansion) ;
382
- ( parent_ctx. parent , expansion. def )
383
- } ) ;
384
- }
385
- }
366
+ handle_macro_def_scope ( db, & mut hygiene_id, & mut hygiene_info, macro_id)
386
367
}
387
368
Scope :: GenericParams { params, def } => {
388
369
if let Some ( id) = params. find_const_by_name ( first_name, * def) {
@@ -728,6 +709,107 @@ impl Resolver {
728
709
} )
729
710
}
730
711
712
+ /// Checks if we rename `renamed` (currently named `current_name`) to `new_name`, will the meaning of this reference
713
+ /// (that contains `current_name` path) change from `renamed` to some another variable (returned as `Some`).
714
+ pub fn rename_will_conflict_with_another_variable (
715
+ & self ,
716
+ db : & dyn DefDatabase ,
717
+ current_name : & Name ,
718
+ current_name_as_path : & ModPath ,
719
+ mut hygiene_id : HygieneId ,
720
+ new_name : & Symbol ,
721
+ to_be_renamed : BindingId ,
722
+ ) -> Option < BindingId > {
723
+ let mut hygiene_info = hygiene_info ( db, hygiene_id) ;
724
+ let mut will_be_resolved_to = None ;
725
+ for scope in self . scopes ( ) {
726
+ match scope {
727
+ Scope :: ExprScope ( scope) => {
728
+ for entry in scope. expr_scopes . entries ( scope. scope_id ) {
729
+ if entry. hygiene ( ) == hygiene_id {
730
+ if entry. binding ( ) == to_be_renamed {
731
+ // This currently resolves to our renamed variable, now `will_be_resolved_to`
732
+ // contains `Some` if the meaning will change or `None` if not.
733
+ return will_be_resolved_to;
734
+ } else if entry. name ( ) . symbol ( ) == new_name {
735
+ will_be_resolved_to = Some ( entry. binding ( ) ) ;
736
+ }
737
+ }
738
+ }
739
+ }
740
+ Scope :: MacroDefScope ( macro_id) => {
741
+ handle_macro_def_scope ( db, & mut hygiene_id, & mut hygiene_info, macro_id)
742
+ }
743
+ Scope :: GenericParams { params, def } => {
744
+ if params. find_const_by_name ( current_name, * def) . is_some ( ) {
745
+ // It does not resolve to our renamed variable.
746
+ return None ;
747
+ }
748
+ }
749
+ Scope :: AdtScope ( _) | Scope :: ImplDefScope ( _) => continue ,
750
+ Scope :: BlockScope ( m) => {
751
+ if m. resolve_path_in_value_ns ( db, current_name_as_path) . is_some ( ) {
752
+ // It does not resolve to our renamed variable.
753
+ return None ;
754
+ }
755
+ }
756
+ }
757
+ }
758
+ // It does not resolve to our renamed variable.
759
+ None
760
+ }
761
+
762
+ /// Checks if we rename `renamed` to `name`, will the meaning of this reference (that contains `name` path) change
763
+ /// from some other variable (returned as `Some`) to `renamed`.
764
+ pub fn rename_will_conflict_with_renamed (
765
+ & self ,
766
+ db : & dyn DefDatabase ,
767
+ name : & Name ,
768
+ name_as_path : & ModPath ,
769
+ mut hygiene_id : HygieneId ,
770
+ to_be_renamed : BindingId ,
771
+ ) -> Option < BindingId > {
772
+ let mut hygiene_info = hygiene_info ( db, hygiene_id) ;
773
+ let mut will_resolve_to_renamed = false ;
774
+ for scope in self . scopes ( ) {
775
+ match scope {
776
+ Scope :: ExprScope ( scope) => {
777
+ for entry in scope. expr_scopes . entries ( scope. scope_id ) {
778
+ if entry. binding ( ) == to_be_renamed {
779
+ will_resolve_to_renamed = true ;
780
+ } else if entry. hygiene ( ) == hygiene_id && entry. name ( ) == name {
781
+ if will_resolve_to_renamed {
782
+ // This will resolve to the renamed variable before it resolves to the original variable.
783
+ return Some ( entry. binding ( ) ) ;
784
+ } else {
785
+ // This will resolve to the original variable.
786
+ return None ;
787
+ }
788
+ }
789
+ }
790
+ }
791
+ Scope :: MacroDefScope ( macro_id) => {
792
+ handle_macro_def_scope ( db, & mut hygiene_id, & mut hygiene_info, macro_id)
793
+ }
794
+ Scope :: GenericParams { params, def } => {
795
+ if params. find_const_by_name ( name, * def) . is_some ( ) {
796
+ // Here and below, it might actually resolve to our renamed variable - in which case it'll
797
+ // hide the generic parameter or some other thing (not a variable). We don't check for that
798
+ // because due to naming conventions, it is rare that variable will shadow a non-variable.
799
+ return None ;
800
+ }
801
+ }
802
+ Scope :: AdtScope ( _) | Scope :: ImplDefScope ( _) => continue ,
803
+ Scope :: BlockScope ( m) => {
804
+ if m. resolve_path_in_value_ns ( db, name_as_path) . is_some ( ) {
805
+ return None ;
806
+ }
807
+ }
808
+ }
809
+ }
810
+ None
811
+ }
812
+
731
813
/// `expr_id` is required to be an expression id that comes after the top level expression scope in the given resolver
732
814
#[ must_use]
733
815
pub fn update_to_inner_scope (
@@ -793,6 +875,44 @@ impl Resolver {
793
875
}
794
876
}
795
877
878
+ #[ inline]
879
+ fn handle_macro_def_scope (
880
+ db : & dyn DefDatabase ,
881
+ hygiene_id : & mut HygieneId ,
882
+ hygiene_info : & mut Option < ( SyntaxContextId , MacroDefId ) > ,
883
+ macro_id : & MacroDefId ,
884
+ ) {
885
+ if let Some ( ( parent_ctx, label_macro_id) ) = hygiene_info {
886
+ if label_macro_id == macro_id {
887
+ // A macro is allowed to refer to variables from before its declaration.
888
+ // Therefore, if we got to the rib of its declaration, give up its hygiene
889
+ // and use its parent expansion.
890
+ let parent_ctx = db. lookup_intern_syntax_context ( * parent_ctx) ;
891
+ * hygiene_id = HygieneId :: new ( parent_ctx. opaque_and_semitransparent ) ;
892
+ * hygiene_info = parent_ctx. outer_expn . map ( |expansion| {
893
+ let expansion = db. lookup_intern_macro_call ( expansion) ;
894
+ ( parent_ctx. parent , expansion. def )
895
+ } ) ;
896
+ }
897
+ }
898
+ }
899
+
900
+ #[ inline]
901
+ fn hygiene_info (
902
+ db : & dyn DefDatabase ,
903
+ hygiene_id : HygieneId ,
904
+ ) -> Option < ( SyntaxContextId , MacroDefId ) > {
905
+ if !hygiene_id. is_root ( ) {
906
+ let ctx = hygiene_id. lookup ( db) ;
907
+ ctx. outer_expn . map ( |expansion| {
908
+ let expansion = db. lookup_intern_macro_call ( expansion) ;
909
+ ( ctx. parent , expansion. def )
910
+ } )
911
+ } else {
912
+ None
913
+ }
914
+ }
915
+
796
916
pub struct UpdateGuard ( usize ) ;
797
917
798
918
impl Resolver {
0 commit comments