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