1
- using Rubberduck . Parsing . Symbols ;
1
+ using Rubberduck . Parsing ;
2
+ using Rubberduck . Parsing . Grammar ;
3
+ using Rubberduck . Parsing . Symbols ;
2
4
using Rubberduck . Parsing . VBA ;
3
5
using Rubberduck . Refactorings . Common ;
4
6
using Rubberduck . Refactorings . EncapsulateField . Extensions ;
@@ -16,6 +18,7 @@ public interface IEncapsulateFieldConflictFinder
16
18
void AssignNoConflictIdentifiers ( IEncapsulateFieldCandidate candidate ) ;
17
19
void AssignNoConflictIdentifiers ( IObjectStateUDT stateUDT ) ;
18
20
void AssignNoConflictIdentifiers ( IEnumerable < IEncapsulateFieldCandidate > candidates ) ;
21
+ void AssignNoConflictBackingFieldIdentifier ( IEncapsulateFieldCandidate candidate ) ;
19
22
}
20
23
21
24
public class EncapsulateFieldConflictFinder : IEncapsulateFieldConflictFinder
@@ -47,7 +50,8 @@ public EncapsulateFieldConflictFinder(IDeclarationFinderProvider declarationFind
47
50
_fieldCandidates = candidates . ToList ( ) ;
48
51
49
52
_udtMemberCandidates = new List < IUserDefinedTypeMemberCandidate > ( ) ;
50
- _fieldCandidates . ForEach ( c => LoadUDTMembers ( c ) ) ;
53
+
54
+ _fieldCandidates . ForEach ( c => LoadUDTMemberCandidates ( c , _udtMemberCandidates ) ) ;
51
55
52
56
_allCandidates = _fieldCandidates . Concat ( _udtMemberCandidates ) . ToList ( ) ;
53
57
@@ -75,13 +79,23 @@ public EncapsulateFieldConflictFinder(IDeclarationFinderProvider declarationFind
75
79
76
80
var errorMessage = string . Empty ;
77
81
78
- var hasInvalidIdentifierOrHasConflicts =
79
- VBAIdentifierValidator . TryMatchInvalidIdentifierCriteria ( field . PropertyIdentifier , declarationType , out errorMessage , field . Declaration . IsArray )
80
- || IsConflictingIdentifier ( field , field . PropertyIdentifier , out errorMessage )
81
- || IsConflictingIdentifier ( field , field . BackingIdentifier , out errorMessage )
82
- || field is IEncapsulateFieldAsUDTMemberCandidate && ConflictsWithExistingUDTMembers ( SelectedObjectStateUDT ( ) , field . BackingIdentifier , out errorMessage ) ;
82
+ if ( field . Declaration . IsArray )
83
+ {
84
+ if ( field . Declaration . References . Any ( rf => rf . QualifiedModuleName != field . QualifiedModuleName
85
+ && rf . Context . TryGetAncestor < VBAParser . RedimVariableDeclarationContext > ( out _ ) ) )
86
+ {
87
+ errorMessage = string . Format ( RubberduckUI . EncapsulateField_ArrayHasExternalRedimFormat , field . IdentifierName ) ;
88
+ }
89
+ return ( ! string . IsNullOrEmpty ( errorMessage ) , errorMessage ) ;
90
+ }
83
91
84
- return ( string . IsNullOrEmpty ( errorMessage ) , errorMessage ) ;
92
+ var hasConflictFreeValidIdentifiers =
93
+ ! VBAIdentifierValidator . TryMatchInvalidIdentifierCriteria ( field . PropertyIdentifier , declarationType , out errorMessage , field . Declaration . IsArray )
94
+ && ! IsConflictingIdentifier ( field , field . PropertyIdentifier , out errorMessage )
95
+ && ! IsConflictingIdentifier ( field , field . BackingIdentifier , out errorMessage )
96
+ && ! ( field is IEncapsulateFieldAsUDTMemberCandidate && ConflictsWithExistingUDTMembers ( SelectedObjectStateUDT ( ) , field . BackingIdentifier , out errorMessage ) ) ;
97
+
98
+ return ( hasConflictFreeValidIdentifiers , errorMessage ) ;
85
99
}
86
100
87
101
public bool IsConflictingIdentifier ( IEncapsulateFieldCandidate field , string identifierToCompare , out string errorMessage )
@@ -98,39 +112,39 @@ public void AssignNoConflictIdentifiers(IEnumerable<IEncapsulateFieldCandidate>
98
112
{
99
113
foreach ( var candidate in candidates . Where ( c => c . EncapsulateFlag ) )
100
114
{
101
- ResolveFieldConflicts ( candidate ) ;
115
+ ResolveIdentifierConflicts ( candidate ) ;
102
116
}
103
117
}
104
118
105
- private void ResolveFieldConflicts ( IEncapsulateFieldCandidate candidate )
119
+ private void ResolveIdentifierConflicts ( IEncapsulateFieldCandidate candidate )
106
120
{
107
121
AssignNoConflictIdentifiers ( candidate ) ;
108
122
if ( candidate is IUserDefinedTypeCandidate udtCandidate )
109
123
{
110
- ResolveUDTMemberConflicts ( udtCandidate . Members ) ;
124
+ ResolveUDTMemberIdentifierConflicts ( udtCandidate . Members ) ;
111
125
}
112
126
}
113
127
114
- private void ResolveUDTMemberConflicts ( IEnumerable < IUserDefinedTypeMemberCandidate > members )
128
+ private void ResolveUDTMemberIdentifierConflicts ( IEnumerable < IUserDefinedTypeMemberCandidate > members )
115
129
{
116
130
foreach ( var member in members )
117
131
{
118
132
AssignNoConflictIdentifiers ( member ) ;
119
133
if ( member . WrappedCandidate is IUserDefinedTypeCandidate childUDT
120
134
&& childUDT . Declaration . AsTypeDeclaration . HasPrivateAccessibility ( ) )
121
135
{
122
- ResolveFieldConflicts ( childUDT ) ;
136
+ ResolveIdentifierConflicts ( childUDT ) ;
123
137
}
124
138
}
125
139
}
126
140
127
141
public void AssignNoConflictIdentifiers ( IEncapsulateFieldCandidate candidate )
128
142
{
129
- if ( candidate is IEncapsulateFieldAsUDTMemberCandidate )
143
+ if ( candidate is IEncapsulateFieldAsUDTMemberCandidate udtMember )
130
144
{
131
145
AssignIdentifier (
132
- ( ) => ConflictsWithExistingUDTMembers ( SelectedObjectStateUDT ( ) , candidate . PropertyIdentifier , out _ ) ,
133
- ( ) => IncrementPropertyIdentifier ( candidate ) ) ;
146
+ ( ) => ConflictsWithExistingUDTMembers ( SelectedObjectStateUDT ( ) , udtMember . UserDefinedTypeMemberIdentifier , out _ ) ,
147
+ ( ) => udtMember . UserDefinedTypeMemberIdentifier = udtMember . UserDefinedTypeMemberIdentifier . IncrementEncapsulationIdentifier ( ) ) ;
134
148
return ;
135
149
}
136
150
@@ -141,15 +155,16 @@ public void AssignNoConflictIdentifiers(IEncapsulateFieldCandidate candidate)
141
155
public void AssignNoConflictIdentifiers ( IObjectStateUDT stateUDT )
142
156
{
143
157
AssignIdentifier (
144
- ( ) => HasConflictingFieldIdentifier ( stateUDT , stateUDT . FieldIdentifier ) ,
145
- ( ) => stateUDT . FieldIdentifier = stateUDT . FieldIdentifier . IncrementEncapsulationIdentifier ( ) ) ;
158
+ ( ) => _existingUserUDTsAndEnums . Any ( m => m . IdentifierName . IsEquivalentVBAIdentifierTo ( stateUDT . TypeIdentifier ) ) ,
159
+ ( ) => stateUDT . TypeIdentifier = stateUDT . TypeIdentifier . IncrementEncapsulationIdentifier ( ) ) ;
146
160
147
161
AssignIdentifier (
148
- ( ) => _existingUserUDTsAndEnums . Any ( m => m . IdentifierName . IsEquivalentVBAIdentifierTo ( stateUDT . TypeIdentifier ) ) ,
149
- ( ) => stateUDT . TypeIdentifier = stateUDT . TypeIdentifier . IncrementEncapsulationIdentifier ( ) ) ;
162
+ ( ) => HasConflictingFieldIdentifier ( stateUDT , stateUDT . FieldIdentifier ) ,
163
+ ( ) => stateUDT . FieldIdentifier = stateUDT . FieldIdentifier . IncrementEncapsulationIdentifier ( ) ) ;
150
164
}
151
165
152
- private IObjectStateUDT SelectedObjectStateUDT ( ) => _objectStateUDTs . SingleOrDefault ( os => os . IsSelected ) ;
166
+ private IObjectStateUDT SelectedObjectStateUDT ( )
167
+ => _objectStateUDTs . SingleOrDefault ( os => os . IsSelected ) ;
153
168
154
169
private static bool ConflictsWithExistingUDTMembers ( IObjectStateUDT objectStateUDT , string identifier , out string errorMessage )
155
170
{
@@ -161,26 +176,20 @@ private static bool ConflictsWithExistingUDTMembers(IObjectStateUDT objectStateU
161
176
return ! string . IsNullOrEmpty ( errorMessage ) ;
162
177
}
163
178
164
- private void IncrementPropertyIdentifier ( IEncapsulateFieldCandidate candidate )
165
- => candidate . PropertyIdentifier = candidate . PropertyIdentifier . IncrementEncapsulationIdentifier ( ) ;
166
-
167
179
private void AssignNoConflictPropertyIdentifier ( IEncapsulateFieldCandidate candidate )
168
180
{
169
181
AssignIdentifier (
170
182
( ) => IsConflictingIdentifier ( candidate , candidate . PropertyIdentifier , out _ ) ,
171
- ( ) => IncrementPropertyIdentifier ( candidate ) ) ;
183
+ ( ) => candidate . PropertyIdentifier = candidate . PropertyIdentifier . IncrementEncapsulationIdentifier ( ) ) ;
172
184
}
173
185
174
- private void AssignNoConflictBackingFieldIdentifier ( IEncapsulateFieldCandidate candidate )
186
+ public void AssignNoConflictBackingFieldIdentifier ( IEncapsulateFieldCandidate candidate )
175
187
{
176
- //Private UserDefinedTypes are never used directly as a backing field - so never change their identifier.
177
- //The backing fields for an encapsulated Private UDT are its members.
178
- if ( ! ( candidate is UserDefinedTypeMemberCandidate
179
- || candidate is IUserDefinedTypeCandidate udtCandidate && udtCandidate . TypeDeclarationIsPrivate ) )
188
+ if ( candidate . BackingIdentifierMutator != null )
180
189
{
181
190
AssignIdentifier (
182
191
( ) => IsConflictingIdentifier ( candidate , candidate . BackingIdentifier , out _ ) ,
183
- ( ) => candidate . BackingIdentifier = candidate . BackingIdentifier . IncrementEncapsulationIdentifier ( ) ) ;
192
+ ( ) => candidate . BackingIdentifierMutator ( candidate . BackingIdentifier . IncrementEncapsulationIdentifier ( ) ) ) ;
184
193
}
185
194
}
186
195
@@ -200,13 +209,24 @@ private static void AssignIdentifier(Func<bool> hasConflict, Action incrementIde
200
209
201
210
private bool HasConflictIdentifiers ( IEncapsulateFieldCandidate candidate , string identifierToCompare )
202
211
{
203
- if ( _allCandidates . Where ( c => c . TargetID != candidate . TargetID
212
+ return HasInternalPropertyAndBackingFieldConflict ( candidate )
213
+ || HasConflictsWithOtherEncapsulationPropertyIdentifiers ( candidate , identifierToCompare )
214
+ || HasConflictsWithUnmodifiedPropertyAndFieldIdentifiers ( candidate , identifierToCompare )
215
+ || HasConflictWithLocalDeclarationIdentifiers ( candidate , identifierToCompare ) ;
216
+ }
217
+
218
+ private bool HasInternalPropertyAndBackingFieldConflict ( IEncapsulateFieldCandidate candidate )
219
+ => candidate . BackingIdentifierMutator != null
220
+ && candidate . EncapsulateFlag
221
+ && candidate . PropertyIdentifier . IsEquivalentVBAIdentifierTo ( candidate . BackingIdentifier ) ;
222
+
223
+ private bool HasConflictsWithOtherEncapsulationPropertyIdentifiers ( IEncapsulateFieldCandidate candidate , string identifierToCompare )
224
+ => _allCandidates . Where ( c => c . TargetID != candidate . TargetID
204
225
&& c . EncapsulateFlag
205
- && c . PropertyIdentifier . IsEquivalentVBAIdentifierTo ( identifierToCompare ) ) . Any ( ) )
206
- {
207
- return true ;
208
- }
226
+ && c . PropertyIdentifier . IsEquivalentVBAIdentifierTo ( identifierToCompare ) ) . Any ( ) ;
209
227
228
+ private bool HasConflictsWithUnmodifiedPropertyAndFieldIdentifiers ( IEncapsulateFieldCandidate candidate , string identifierToCompare )
229
+ {
210
230
var membersToEvaluate = _members . Where ( d => d != candidate . Declaration ) ;
211
231
212
232
if ( candidate is IEncapsulateFieldAsUDTMemberCandidate )
@@ -219,13 +239,22 @@ private bool HasConflictIdentifiers(IEncapsulateFieldCandidate candidate, string
219
239
var nameConflictCandidates = membersToEvaluate . Where ( member => ! ( member . IsLocalVariable ( ) || member . IsLocalConstant ( )
220
240
|| _declarationTypesThatNeverConflictWithFieldAndPropertyIdentifiers . Contains ( member . DeclarationType ) ) ) ;
221
241
222
- if ( nameConflictCandidates . Any ( m => m . IdentifierName . IsEquivalentVBAIdentifierTo ( identifierToCompare ) ) )
242
+ return nameConflictCandidates . Any ( m => m . IdentifierName . IsEquivalentVBAIdentifierTo ( identifierToCompare ) ) ;
243
+ }
244
+
245
+ private bool HasConflictWithLocalDeclarationIdentifiers ( IEncapsulateFieldCandidate candidate , string identifierToCompare )
246
+ {
247
+ var membersToEvaluate = _members . Where ( d => d != candidate . Declaration ) ;
248
+
249
+ if ( candidate is IEncapsulateFieldAsUDTMemberCandidate )
223
250
{
224
- return true ;
251
+ membersToEvaluate = membersToEvaluate . Except (
252
+ _fieldCandidates . Where ( fc => fc . EncapsulateFlag && fc . Declaration . DeclarationType . HasFlag ( DeclarationType . Variable ) )
253
+ . Select ( f => f . Declaration ) ) ;
225
254
}
226
255
227
- //Only check IdentifierReferences in the declaring module because IdentifierReferences in
228
- //other modules will be module-qualified.
256
+ //Only check IdentifierReferences in the declaring module because encapsulated field
257
+ //references in other modules will be module-qualified.
229
258
var candidateLocalReferences = candidate . Declaration . References . Where ( rf => rf . QualifiedModuleName == candidate . QualifiedModuleName ) ;
230
259
231
260
var localDeclarationConflictCandidates = membersToEvaluate . Where ( localDec => candidateLocalReferences
@@ -251,15 +280,15 @@ private bool HasConflictingFieldIdentifier(IObjectStateUDT candidate, string ide
251
280
. Where ( fc => fc . EncapsulateFlag && fc . Declaration . DeclarationType . HasFlag ( DeclarationType . Variable ) )
252
281
. Select ( fc => fc . Declaration ) ;
253
282
254
- var nameConflictCandidates =
283
+ var nameConflictCandidates =
255
284
_members . Except ( fieldsToRemoveFromConflictCandidates )
256
285
. Where ( member => ! ( member . IsLocalVariable ( ) || member . IsLocalConstant ( )
257
286
|| _declarationTypesThatNeverConflictWithFieldAndPropertyIdentifiers . Contains ( member . DeclarationType ) ) ) ;
258
287
259
288
return nameConflictCandidates . Any ( m => m . IdentifierName . IsEquivalentVBAIdentifierTo ( identifierToCompare ) ) ;
260
289
}
261
290
262
- private void LoadUDTMembers ( IEncapsulateFieldCandidate candidate )
291
+ private void LoadUDTMemberCandidates ( IEncapsulateFieldCandidate candidate , List < IUserDefinedTypeMemberCandidate > udtMemberCandidates )
263
292
{
264
293
if ( ! ( candidate is IUserDefinedTypeCandidate udtCandidate ) )
265
294
{
@@ -268,13 +297,13 @@ private void LoadUDTMembers(IEncapsulateFieldCandidate candidate)
268
297
269
298
foreach ( var member in udtCandidate . Members )
270
299
{
271
- _udtMemberCandidates . Add ( member ) ;
300
+ udtMemberCandidates . Add ( member ) ;
272
301
273
302
if ( member . WrappedCandidate is IUserDefinedTypeCandidate childUDT
274
303
&& childUDT . Declaration . AsTypeDeclaration . HasPrivateAccessibility ( ) )
275
304
{
276
305
//recursive till a non-UserDefinedType member is found
277
- LoadUDTMembers ( childUDT ) ;
306
+ LoadUDTMemberCandidates ( childUDT , udtMemberCandidates ) ;
278
307
}
279
308
}
280
309
}
0 commit comments