1
+ using System ;
2
+ using System . Collections . Generic ;
3
+ using System . Diagnostics ;
4
+ using System . Linq ;
5
+ using Rubberduck . Parsing . Grammar ;
6
+ using Rubberduck . Parsing . Rewriter ;
7
+ using Rubberduck . Parsing . Symbols ;
8
+ using Rubberduck . Parsing . VBA ;
9
+ using Rubberduck . VBEditor . ComManagement ;
10
+
11
+ namespace Rubberduck . Refactorings . Rename
12
+ {
13
+ public class RenameCodeDefinedIdentifierRefactoringAction : CodeOnlyRefactoringActionBase < RenameModel >
14
+ {
15
+ private const string AppendUnderscoreFormat = "{0}_" ;
16
+ private const string PrependUnderscoreFormat = "_{0}" ;
17
+
18
+ private readonly IDeclarationFinderProvider _declarationFinderProvider ;
19
+ private readonly IProjectsProvider _projectsProvider ;
20
+ private readonly IDictionary < DeclarationType , Action < RenameModel , IRewriteSession > > _renameActions ;
21
+
22
+ public RenameCodeDefinedIdentifierRefactoringAction (
23
+ IDeclarationFinderProvider declarationFinderProvider ,
24
+ IProjectsProvider projectsProvider ,
25
+ IRewritingManager rewritingManager )
26
+ : base ( rewritingManager )
27
+ {
28
+ _declarationFinderProvider = declarationFinderProvider ;
29
+ _projectsProvider = projectsProvider ;
30
+
31
+ _renameActions = new Dictionary < DeclarationType , Action < RenameModel , IRewriteSession > >
32
+ {
33
+ { DeclarationType . Member , RenameMember } ,
34
+ { DeclarationType . Parameter , RenameParameter } ,
35
+ { DeclarationType . Event , RenameEvent } ,
36
+ { DeclarationType . Variable , RenameVariable }
37
+ } ;
38
+ }
39
+
40
+ public override void Refactor ( RenameModel model , IRewriteSession rewriteSession )
41
+ {
42
+ var actionKeys = _renameActions . Keys . Where ( decType => model . Target . DeclarationType . HasFlag ( decType ) ) . ToList ( ) ;
43
+ if ( actionKeys . Any ( ) )
44
+ {
45
+ Debug . Assert ( actionKeys . Count == 1 , $ "{ actionKeys . Count } Rename Actions have flag '{ model . Target . DeclarationType . ToString ( ) } '") ;
46
+ _renameActions [ actionKeys . FirstOrDefault ( ) ] ( model , rewriteSession ) ;
47
+ }
48
+ else
49
+ {
50
+ RenameStandardElements ( model . Target , model . NewName , rewriteSession ) ;
51
+ }
52
+ }
53
+
54
+ private void RenameMember ( RenameModel model , IRewriteSession rewriteSession )
55
+ {
56
+ if ( model . Target . DeclarationType . HasFlag ( DeclarationType . Property ) )
57
+ {
58
+ var members = _declarationFinderProvider . DeclarationFinder . MatchName ( model . Target . IdentifierName )
59
+ . Where ( item => item . ProjectId == model . Target . ProjectId
60
+ && item . ComponentName == model . Target . ComponentName
61
+ && item . DeclarationType . HasFlag ( DeclarationType . Property ) ) ;
62
+
63
+ foreach ( var member in members )
64
+ {
65
+ RenameStandardElements ( member , model . NewName , rewriteSession ) ;
66
+ }
67
+ }
68
+ else
69
+ {
70
+ RenameStandardElements ( model . Target , model . NewName , rewriteSession ) ;
71
+ }
72
+
73
+ if ( ! model . IsInterfaceMemberRename )
74
+ {
75
+ return ;
76
+ }
77
+
78
+ var implementations = _declarationFinderProvider . DeclarationFinder . FindAllInterfaceImplementingMembers ( )
79
+ . Where ( impl => ReferenceEquals ( model . Target . ParentDeclaration , impl . InterfaceImplemented )
80
+ && impl . InterfaceMemberImplemented . IdentifierName . Equals ( model . Target . IdentifierName ) ) ;
81
+
82
+ RenameDefinedFormatMembers ( model , implementations . ToList ( ) , PrependUnderscoreFormat , rewriteSession ) ;
83
+ }
84
+
85
+ private void RenameParameter ( RenameModel model , IRewriteSession rewriteSession )
86
+ {
87
+ if ( model . Target . ParentDeclaration . DeclarationType . HasFlag ( DeclarationType . Property ) )
88
+ {
89
+ var parameters = _declarationFinderProvider . DeclarationFinder . MatchName ( model . Target . IdentifierName ) . Where ( param =>
90
+ param . ParentDeclaration . DeclarationType . HasFlag ( DeclarationType . Property )
91
+ && param . DeclarationType == DeclarationType . Parameter
92
+ && param . ParentDeclaration . IdentifierName . Equals ( model . Target . ParentDeclaration . IdentifierName )
93
+ && param . ParentDeclaration . ParentScopeDeclaration . Equals ( model . Target . ParentDeclaration . ParentScopeDeclaration ) ) ;
94
+
95
+ foreach ( var param in parameters )
96
+ {
97
+ RenameStandardElements ( param , model . NewName , rewriteSession ) ;
98
+ }
99
+ }
100
+ else
101
+ {
102
+ RenameStandardElements ( model . Target , model . NewName , rewriteSession ) ;
103
+ }
104
+ }
105
+
106
+ private void RenameEvent ( RenameModel model , IRewriteSession rewriteSession )
107
+ {
108
+ RenameStandardElements ( model . Target , model . NewName , rewriteSession ) ;
109
+
110
+ var withEventsDeclarations = _declarationFinderProvider . DeclarationFinder . UserDeclarations ( DeclarationType . Variable )
111
+ . Where ( varDec => varDec . IsWithEvents && varDec . AsTypeName . Equals ( model . Target . ParentDeclaration . IdentifierName ) ) ;
112
+
113
+ var eventHandlers = withEventsDeclarations . SelectMany ( we => _declarationFinderProvider . DeclarationFinder . FindHandlersForWithEventsField ( we ) ) ;
114
+ RenameDefinedFormatMembers ( model , eventHandlers . ToList ( ) , PrependUnderscoreFormat , rewriteSession ) ;
115
+ }
116
+
117
+ private void RenameVariable ( RenameModel model , IRewriteSession rewriteSession )
118
+ {
119
+ if ( ( model . Target . Accessibility == Accessibility . Public ||
120
+ model . Target . Accessibility == Accessibility . Implicit )
121
+ && model . Target . ParentDeclaration is ClassModuleDeclaration classDeclaration
122
+ && classDeclaration . Subtypes . Any ( ) )
123
+ {
124
+ RenameMember ( model , rewriteSession ) ;
125
+ }
126
+ else if ( model . Target . DeclarationType . HasFlag ( DeclarationType . Control ) )
127
+ {
128
+ var component = _projectsProvider . Component ( model . Target . QualifiedName . QualifiedModuleName ) ;
129
+ using ( var controls = component . Controls )
130
+ {
131
+ using ( var control = controls . SingleOrDefault ( item => item . Name == model . Target . IdentifierName ) )
132
+ {
133
+ Debug . Assert ( control != null ,
134
+ $ "input validation fail: unable to locate '{ model . Target . IdentifierName } ' in Controls collection") ;
135
+
136
+ control . Name = model . NewName ;
137
+ }
138
+ }
139
+ RenameReferences ( model . Target , model . NewName , rewriteSession ) ;
140
+ var controlEventHandlers = FindEventHandlersForControl ( model . Target ) ;
141
+ RenameDefinedFormatMembers ( model , controlEventHandlers . ToList ( ) , AppendUnderscoreFormat , rewriteSession ) ;
142
+ }
143
+ else
144
+ {
145
+ RenameStandardElements ( model . Target , model . NewName , rewriteSession ) ;
146
+ if ( model . Target . IsWithEvents )
147
+ {
148
+ var eventHandlers = _declarationFinderProvider . DeclarationFinder . FindHandlersForWithEventsField ( model . Target ) ;
149
+ RenameDefinedFormatMembers ( model , eventHandlers . ToList ( ) , AppendUnderscoreFormat , rewriteSession ) ;
150
+ }
151
+ }
152
+ }
153
+
154
+ private void RenameDefinedFormatMembers ( RenameModel model , IReadOnlyCollection < Declaration > members , string underscoreFormat , IRewriteSession rewriteSession )
155
+ {
156
+ if ( ! members . Any ( ) ) { return ; }
157
+
158
+ var targetFragment = string . Format ( underscoreFormat , model . Target . IdentifierName ) ;
159
+ var replacementFragment = string . Format ( underscoreFormat , model . NewName ) ;
160
+ foreach ( var member in members )
161
+ {
162
+ var newMemberName = member . IdentifierName . Replace ( targetFragment , replacementFragment ) ;
163
+ RenameStandardElements ( member , newMemberName , rewriteSession ) ;
164
+ }
165
+ }
166
+
167
+ private void RenameStandardElements ( Declaration target , string newName , IRewriteSession rewriteSession )
168
+ {
169
+ RenameReferences ( target , newName , rewriteSession ) ;
170
+ RenameDeclaration ( target , newName , rewriteSession ) ;
171
+ }
172
+
173
+ private void RenameReferences ( Declaration target , string newName , IRewriteSession rewriteSession )
174
+ {
175
+ var modules = target . References
176
+ . Where ( reference =>
177
+ reference . Context . GetText ( ) != "Me"
178
+ && ! reference . IsArrayAccess
179
+ && ! reference . IsDefaultMemberAccess )
180
+ . GroupBy ( r => r . QualifiedModuleName ) ;
181
+
182
+ foreach ( var grouping in modules )
183
+ {
184
+ var rewriter = rewriteSession . CheckOutModuleRewriter ( grouping . Key ) ;
185
+ foreach ( var reference in grouping )
186
+ {
187
+ rewriter . Replace ( reference . Context , newName ) ;
188
+ }
189
+ }
190
+ }
191
+
192
+ private void RenameDeclaration ( Declaration target , string newName , IRewriteSession rewriteSession )
193
+ {
194
+ var rewriter = rewriteSession . CheckOutModuleRewriter ( target . QualifiedName . QualifiedModuleName ) ;
195
+
196
+ if ( target . Context is IIdentifierContext context )
197
+ {
198
+ rewriter . Replace ( context . IdentifierTokens , newName ) ;
199
+ }
200
+ }
201
+
202
+ private IEnumerable < Declaration > FindEventHandlersForControl ( Declaration control )
203
+ {
204
+ if ( control != null && control . DeclarationType . HasFlag ( DeclarationType . Control ) )
205
+ {
206
+ return _declarationFinderProvider . DeclarationFinder . FindEventHandlers ( )
207
+ . Where ( ev => ev . Scope . StartsWith ( $ "{ control . ParentScope } .{ control . IdentifierName } _") ) ;
208
+ }
209
+
210
+ return Enumerable . Empty < Declaration > ( ) ;
211
+ }
212
+ }
213
+ }
0 commit comments