1
1
using Rubberduck . Inspections . Abstract ;
2
2
using System . Linq ;
3
- using Rubberduck . Parsing ;
4
3
using Rubberduck . VBEditor ;
5
4
using Rubberduck . Inspections . Resources ;
6
5
using Rubberduck . Parsing . Grammar ;
@@ -18,16 +17,16 @@ public class AssignedByValParameterMakeLocalCopyQuickFix : QuickFixBase
18
17
{
19
18
private readonly Declaration _target ;
20
19
private readonly IAssignedByValParameterQuickFixDialogFactory _dialogFactory ;
20
+ private readonly IEnumerable < string > _forbiddenNames ;
21
21
private string _localCopyVariableName ;
22
- private string [ ] _variableNamesAccessibleToProcedureContext ;
23
22
24
23
public AssignedByValParameterMakeLocalCopyQuickFix ( Declaration target , QualifiedSelection selection , IAssignedByValParameterQuickFixDialogFactory dialogFactory )
25
24
: base ( target . Context , selection , InspectionsUI . AssignedByValParameterMakeLocalCopyQuickFix )
26
25
{
27
26
_target = target ;
28
27
_dialogFactory = dialogFactory ;
29
- _variableNamesAccessibleToProcedureContext = GetVariableNamesAccessibleToProcedureContext ( _target . Context . Parent . Parent ) ;
30
- SetValidLocalCopyVariableNameSuggestion ( ) ;
28
+ _forbiddenNames = GetIdentifierNamesAccessibleToProcedureContext ( target . Context . Parent . Parent ) ;
29
+ _localCopyVariableName = ComputeSuggestedName ( ) ;
31
30
}
32
31
33
32
public override bool CanFixInModule { get { return false ; } }
@@ -49,10 +48,9 @@ public override void Fix()
49
48
50
49
private void RequestLocalCopyVariableName ( )
51
50
{
52
- using ( var view = _dialogFactory . Create ( _target . IdentifierName , _target . DeclarationType . ToString ( ) ) )
51
+ using ( var view = _dialogFactory . Create ( _target . IdentifierName , _target . DeclarationType . ToString ( ) , _forbiddenNames ) )
53
52
{
54
53
view . NewName = _localCopyVariableName ;
55
- view . IdentifierNamesAlreadyDeclared = _variableNamesAccessibleToProcedureContext ;
56
54
view . ShowDialog ( ) ;
57
55
IsCancelled = view . DialogResult == DialogResult . Cancel ;
58
56
if ( ! IsCancelled )
@@ -62,63 +60,65 @@ private void RequestLocalCopyVariableName()
62
60
}
63
61
}
64
62
65
- private void SetValidLocalCopyVariableNameSuggestion ( )
63
+ private string ComputeSuggestedName ( )
66
64
{
67
- _localCopyVariableName = "x" + _target . IdentifierName . CapitalizeFirstLetter ( ) ;
68
- if ( VariableNameIsValid ( _localCopyVariableName ) ) { return ; }
65
+ var newName = "local" + _target . IdentifierName . CapitalizeFirstLetter ( ) ;
66
+ if ( VariableNameIsValid ( newName ) )
67
+ {
68
+ return newName ;
69
+ }
69
70
70
- //If the initial suggestion is not valid, keep pre-pending x's until it is
71
- for ( int attempt = 2 ; attempt < 10 ; attempt ++ )
71
+ for ( var attempt = 2 ; attempt < 10 ; attempt ++ )
72
72
{
73
- _localCopyVariableName = "x" + _localCopyVariableName ;
74
- if ( VariableNameIsValid ( _localCopyVariableName ) )
73
+ var result = newName + attempt ;
74
+ if ( VariableNameIsValid ( result ) )
75
75
{
76
- return ;
76
+ return result ;
77
77
}
78
78
}
79
- //if "xxFoo" to "xxxxxxxxxxFoo" isn't unique, give up and go with the original suggestion.
80
- //The QuickFix will leave the code as-is unless it receives a name that is free of conflicts
81
- _localCopyVariableName = "x" + _target . IdentifierName . CapitalizeFirstLetter ( ) ;
79
+ return newName ;
82
80
}
83
81
84
82
private bool VariableNameIsValid ( string variableName )
85
83
{
86
- var validator = new VariableNameValidator ( variableName ) ;
87
- return validator . IsValidName ( )
88
- && ! _variableNamesAccessibleToProcedureContext
89
- . Any ( name => name . Equals ( variableName , System . StringComparison . InvariantCultureIgnoreCase ) ) ;
84
+ return VariableNameValidator . IsValidName ( variableName )
85
+ && ! _forbiddenNames . Any ( name => name . Equals ( variableName , System . StringComparison . InvariantCultureIgnoreCase ) ) ;
90
86
}
91
87
92
88
private void ReplaceAssignedByValParameterReferences ( )
93
89
{
94
90
var module = Selection . QualifiedName . Component . CodeModule ;
95
- foreach ( IdentifierReference identifierReference in _target . References )
91
+ foreach ( var identifierReference in _target . References )
96
92
{
97
93
module . ReplaceIdentifierReferenceName ( identifierReference , _localCopyVariableName ) ;
98
94
}
99
95
}
100
96
101
97
private void InsertLocalVariableDeclarationAndAssignment ( )
102
98
{
103
- var blocks = QuickFixHelper . GetBlockStmtContextsForContext ( _target . Context . Parent . Parent ) ;
99
+ var block = QuickFixHelper . GetBlockStmtContextsForContext ( _target . Context . Parent . Parent ) . FirstOrDefault ( ) ;
100
+ if ( block == null )
101
+ {
102
+ return ;
103
+ }
104
+
104
105
string [ ] lines = { BuildLocalCopyDeclaration ( ) , BuildLocalCopyAssignment ( ) } ;
105
106
var module = Selection . QualifiedName . Component . CodeModule ;
106
- module . InsertLines ( blocks . FirstOrDefault ( ) . Start . Line , lines ) ;
107
+ module . InsertLines ( block . Start . Line , lines ) ;
107
108
}
108
109
109
110
private string BuildLocalCopyDeclaration ( )
110
111
{
111
- return Tokens . Dim + " " + _localCopyVariableName + " " + Tokens . As
112
- + " " + _target . AsTypeName ;
112
+ return Tokens . Dim + " " + _localCopyVariableName + " " + Tokens . As + " " + _target . AsTypeName ;
113
113
}
114
114
115
115
private string BuildLocalCopyAssignment ( )
116
116
{
117
- return ( SymbolList . ValueTypes . Contains ( _target . AsTypeName ) ? string . Empty : Tokens . Set + " " )
117
+ return ( _target . AsTypeDeclaration is ClassModuleDeclaration ? Tokens . Set + " " : string . Empty )
118
118
+ _localCopyVariableName + " = " + _target . IdentifierName ;
119
119
}
120
120
121
- private string [ ] GetVariableNamesAccessibleToProcedureContext ( RuleContext ruleContext )
121
+ private IEnumerable < string > GetIdentifierNamesAccessibleToProcedureContext ( RuleContext ruleContext )
122
122
{
123
123
var allIdentifiers = new HashSet < string > ( ) ;
124
124
@@ -137,29 +137,31 @@ private string[] GetVariableNamesAccessibleToProcedureContext(RuleContext ruleCo
137
137
return allIdentifiers . ToArray ( ) ;
138
138
}
139
139
140
- private HashSet < string > GetIdentifierNames ( IReadOnlyList < RuleContext > ruleContexts )
140
+ private IEnumerable < string > GetIdentifierNames ( IEnumerable < RuleContext > ruleContexts )
141
141
{
142
142
var identifiers = new HashSet < string > ( ) ;
143
- foreach ( RuleContext ruleContext in ruleContexts )
143
+ foreach ( var identifiersForThisContext in ruleContexts . Select ( GetIdentifierNames ) )
144
144
{
145
- var identifiersForThisContext = GetIdentifierNames ( ruleContext ) ;
146
145
identifiers . UnionWith ( identifiersForThisContext ) ;
147
146
}
148
147
return identifiers ;
149
148
}
150
149
151
- private HashSet < string > GetIdentifierNames ( RuleContext ruleContext )
150
+ private static HashSet < string > GetIdentifierNames ( RuleContext ruleContext )
152
151
{
152
+ // note: this looks like something that's already handled somewhere else...
153
+
153
154
//Recursively work through the tree to get all IdentifierContexts
154
155
var results = new HashSet < string > ( ) ;
155
- var tokenValues = typeof ( Tokens ) . GetFields ( ) . Select ( item => item . GetValue ( null ) ) . Cast < string > ( ) . Select ( item => item ) ;
156
+ var tokenValues = typeof ( Tokens ) . GetFields ( ) . Select ( item => item . GetValue ( null ) ) . Cast < string > ( ) . Select ( item => item ) . ToArray ( ) ;
156
157
var children = GetChildren ( ruleContext ) ;
157
158
158
- foreach ( IParseTree child in children )
159
+ foreach ( var child in children )
159
160
{
160
- if ( child is VBAParser . IdentifierContext )
161
+ var context = child as VBAParser . IdentifierContext ;
162
+ if ( context != null )
161
163
{
162
- var childName = Identifier . GetName ( ( VBAParser . IdentifierContext ) child ) ;
164
+ var childName = Identifier . GetName ( context ) ;
163
165
if ( ! tokenValues . Contains ( childName ) )
164
166
{
165
167
results . Add ( childName ) ;
@@ -176,12 +178,12 @@ private HashSet<string> GetIdentifierNames(RuleContext ruleContext)
176
178
return results ;
177
179
}
178
180
179
- private static List < IParseTree > GetChildren ( RuleContext ruleCtx )
181
+ private static IEnumerable < IParseTree > GetChildren ( IParseTree tree )
180
182
{
181
183
var result = new List < IParseTree > ( ) ;
182
- for ( int index = 0 ; index < ruleCtx . ChildCount ; index ++ )
184
+ for ( var index = 0 ; index < tree . ChildCount ; index ++ )
183
185
{
184
- result . Add ( ruleCtx . GetChild ( index ) ) ;
186
+ result . Add ( tree . GetChild ( index ) ) ;
185
187
}
186
188
return result ;
187
189
}
0 commit comments