11
11
using Antlr4 . Runtime ;
12
12
using System . Collections . Generic ;
13
13
using Antlr4 . Runtime . Tree ;
14
+ using Rubberduck . Parsing . VBA ;
14
15
15
16
namespace Rubberduck . Inspections . QuickFixes
16
17
{
17
18
public class AssignedByValParameterMakeLocalCopyQuickFix : QuickFixBase
18
19
{
19
20
private readonly Declaration _target ;
20
21
private readonly IAssignedByValParameterQuickFixDialogFactory _dialogFactory ;
22
+ private readonly RubberduckParserState _parserState ;
21
23
private string _localCopyVariableName ;
22
24
private string [ ] _variableNamesAccessibleToProcedureContext ;
23
25
24
- public AssignedByValParameterMakeLocalCopyQuickFix ( Declaration target , QualifiedSelection selection , IAssignedByValParameterQuickFixDialogFactory dialogFactory )
26
+ public AssignedByValParameterMakeLocalCopyQuickFix ( Declaration target , QualifiedSelection selection , RubberduckParserState parserState , IAssignedByValParameterQuickFixDialogFactory dialogFactory )
25
27
: base ( target . Context , selection , InspectionsUI . AssignedByValParameterMakeLocalCopyQuickFix )
26
28
{
27
29
_target = target ;
28
30
_dialogFactory = dialogFactory ;
29
- _variableNamesAccessibleToProcedureContext = GetVariableNamesAccessibleToProcedureContext ( _target . Context . Parent . Parent ) ;
31
+ _parserState = parserState ;
32
+ _variableNamesAccessibleToProcedureContext = GetUserDefinedNamesAccessibleToProcedureContext ( _target . Context . Parent . Parent ) ;
30
33
SetValidLocalCopyVariableNameSuggestion ( ) ;
31
34
}
32
35
@@ -100,7 +103,7 @@ private void ReplaceAssignedByValParameterReferences()
100
103
101
104
private void InsertLocalVariableDeclarationAndAssignment ( )
102
105
{
103
- var blocks = QuickFixHelper . GetBlockStmtContextsForContext ( _target . Context . Parent . Parent ) ;
106
+ var blocks = QuickFixHelper . GetBlockStmtContexts ( _target . Context . Parent . Parent ) ;
104
107
string [ ] lines = { BuildLocalCopyDeclaration ( ) , BuildLocalCopyAssignment ( ) } ;
105
108
var module = Selection . QualifiedName . Component . CodeModule ;
106
109
module . InsertLines ( blocks . FirstOrDefault ( ) . Start . Line , lines ) ;
@@ -118,58 +121,93 @@ private string BuildLocalCopyAssignment()
118
121
+ _localCopyVariableName + " = " + _target . IdentifierName ;
119
122
}
120
123
121
- private string [ ] GetVariableNamesAccessibleToProcedureContext ( RuleContext ruleContext )
124
+ private string [ ] GetUserDefinedNamesAccessibleToProcedureContext ( RuleContext ruleContext )
122
125
{
123
126
var allIdentifiers = new HashSet < string > ( ) ;
124
127
125
- var blocks = QuickFixHelper . GetBlockStmtContextsForContext ( ruleContext ) ;
128
+ //Locally declared variable names
129
+ var blocks = QuickFixHelper . GetBlockStmtContexts ( ruleContext ) ;
130
+
131
+ var blockStmtIdentifierContexts = GetIdentifierContexts ( blocks ) ;
132
+ var blockStmtIdentifiers = GetVariableNamesFromRuleContexts ( blockStmtIdentifierContexts . ToArray ( ) ) ;
126
133
127
- var blockStmtIdentifiers = GetIdentifierNames ( blocks ) ;
128
134
allIdentifiers . UnionWith ( blockStmtIdentifiers ) ;
129
135
130
- var args = QuickFixHelper . GetArgContextsForContext ( ruleContext ) ;
136
+ //The parameters of the procedure that are unreferenced in the procedure body
137
+ var args = QuickFixHelper . GetArgContexts ( ruleContext ) ;
138
+
139
+ var potentiallyUnreferencedIdentifierContexts = GetIdentifierContexts ( args ) ;
140
+ var potentiallyUnreferencedParameters = GetVariableNamesFromRuleContexts ( potentiallyUnreferencedIdentifierContexts . ToArray ( ) ) ;
131
141
132
- var potentiallyUnreferencedParameters = GetIdentifierNames ( args ) ;
133
142
allIdentifiers . UnionWith ( potentiallyUnreferencedParameters ) ;
134
143
135
- //TODO: add module and global scope variableNames to the list.
144
+ //All declarations within the same module, but outside of all procedures (e.g., member variables, procedure names)
145
+ var sameModuleDeclarations = _parserState . AllUserDeclarations
146
+ . Where ( item => item . ComponentName == _target . ComponentName
147
+ && ! IsProceduralContext ( item . ParentDeclaration . Context ) )
148
+ . ToList ( ) ;
149
+
150
+ allIdentifiers . UnionWith ( sameModuleDeclarations . Select ( d => d . IdentifierName ) ) ;
151
+
152
+ //Public declarations anywhere within the project other than Public members and
153
+ //procedures of Class modules
154
+ var allPublicDeclarations = _parserState . AllUserDeclarations
155
+ . Where ( item => ( item . Accessibility == Accessibility . Public
156
+ || ( ( item . Accessibility == Accessibility . Implicit )
157
+ && item . ParentScopeDeclaration is ProceduralModuleDeclaration ) )
158
+ && ! ( item . ParentScopeDeclaration is ClassModuleDeclaration ) )
159
+ . ToList ( ) ;
160
+
161
+ allIdentifiers . UnionWith ( allPublicDeclarations . Select ( d => d . IdentifierName ) ) ;
136
162
137
163
return allIdentifiers . ToArray ( ) ;
138
164
}
139
165
140
- private HashSet < string > GetIdentifierNames ( IReadOnlyList < RuleContext > ruleContexts )
166
+ private HashSet < string > GetVariableNamesFromRuleContexts ( RuleContext [ ] ruleContexts )
167
+ {
168
+ var tokenValues = typeof ( Tokens ) . GetFields ( ) . Select ( item => item . GetValue ( null ) ) . Cast < string > ( ) . Select ( item => item ) ;
169
+ var results = new HashSet < string > ( ) ;
170
+
171
+ foreach ( var ruleContext in ruleContexts )
172
+ {
173
+ var name = Identifier . GetName ( ( VBAParser . IdentifierContext ) ruleContext ) ;
174
+ if ( ! tokenValues . Contains ( name ) )
175
+ {
176
+ results . Add ( name ) ;
177
+ }
178
+ }
179
+ return results ;
180
+ }
181
+
182
+ private HashSet < RuleContext > GetIdentifierContexts ( IReadOnlyList < RuleContext > ruleContexts )
141
183
{
142
- var identifiers = new HashSet < string > ( ) ;
184
+ var identifiers = new HashSet < RuleContext > ( ) ;
143
185
foreach ( RuleContext ruleContext in ruleContexts )
144
186
{
145
- var identifiersForThisContext = GetIdentifierNames ( ruleContext ) ;
187
+ var identifiersForThisContext = GetIdentifierContexts ( ruleContext ) ;
146
188
identifiers . UnionWith ( identifiersForThisContext ) ;
147
189
}
148
190
return identifiers ;
149
191
}
150
192
151
- private HashSet < string > GetIdentifierNames ( RuleContext ruleContext )
193
+ private HashSet < RuleContext > GetIdentifierContexts ( RuleContext ruleContext )
152
194
{
153
195
//Recursively work through the tree to get all IdentifierContexts
154
- var results = new HashSet < string > ( ) ;
155
- var tokenValues = typeof ( Tokens ) . GetFields ( ) . Select ( item => item . GetValue ( null ) ) . Cast < string > ( ) . Select ( item => item ) ;
196
+ var results = new HashSet < RuleContext > ( ) ;
156
197
var children = GetChildren ( ruleContext ) ;
157
198
158
199
foreach ( IParseTree child in children )
159
200
{
160
201
if ( child is VBAParser . IdentifierContext )
161
202
{
162
203
var childName = Identifier . GetName ( ( VBAParser . IdentifierContext ) child ) ;
163
- if ( ! tokenValues . Contains ( childName ) )
164
- {
165
- results . Add ( childName ) ;
166
- }
204
+ results . Add ( ( RuleContext ) child ) ;
167
205
}
168
206
else
169
207
{
170
208
if ( ! ( child is TerminalNodeImpl ) )
171
209
{
172
- results . UnionWith ( GetIdentifierNames ( ( RuleContext ) child ) ) ;
210
+ results . UnionWith ( GetIdentifierContexts ( ( RuleContext ) child ) ) ;
173
211
}
174
212
}
175
213
}
@@ -185,5 +223,29 @@ private static List<IParseTree> GetChildren(RuleContext ruleCtx)
185
223
}
186
224
return result ;
187
225
}
226
+ private bool IsProceduralContext ( RuleContext context )
227
+ {
228
+ if ( context is VBAParser . SubStmtContext )
229
+ {
230
+ return true ;
231
+ }
232
+ else if ( context is VBAParser . FunctionStmtContext )
233
+ {
234
+ return true ;
235
+ }
236
+ else if ( context is VBAParser . PropertyLetStmtContext )
237
+ {
238
+ return true ;
239
+ }
240
+ else if ( context is VBAParser . PropertyGetStmtContext )
241
+ {
242
+ return true ;
243
+ }
244
+ else if ( context is VBAParser . PropertySetStmtContext )
245
+ {
246
+ return true ;
247
+ }
248
+ return false ;
249
+ }
188
250
}
189
251
}
0 commit comments