Skip to content

Commit c857f06

Browse files
committed
Created ICodeModuleExtensions class. Minimized QuickFixHelper and made it a static class
1 parent 6136377 commit c857f06

File tree

5 files changed

+134
-203
lines changed

5 files changed

+134
-203
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using Antlr4.Runtime;
2+
using Rubberduck.Parsing.Symbols;
3+
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
4+
5+
namespace Rubberduck.Common
6+
{
7+
public static class ICodeModuleExtensions
8+
{
9+
public static void ReplaceToken(this ICodeModule module, IToken token, string replacement)
10+
{
11+
var original = module.GetLines(token.Line, 1);
12+
var result = ReplaceStringAtIndex(original, token.Text, replacement, token.Column);
13+
module.ReplaceLine(token.Line, result);
14+
}
15+
public static void ReplaceIdentifierReferenceName(this ICodeModule module, IdentifierReference identifierReference, string replacement)
16+
{
17+
var original = module.GetLines(identifierReference.Selection.StartLine, 1);
18+
var result = ReplaceStringAtIndex(original, identifierReference.IdentifierName, replacement, identifierReference.Context.Start.Column);
19+
module.ReplaceLine(identifierReference.Selection.StartLine, result);
20+
}
21+
private static string ReplaceStringAtIndex(string original, string toReplace, string replacement, int startIndex)
22+
{
23+
var stopIndex = startIndex + toReplace.Length - 1;
24+
var prefix = original.Substring(0, startIndex);
25+
var suffix = (stopIndex >= original.Length) ? string.Empty : original.Substring(stopIndex + 1);
26+
27+
if(original.Substring(startIndex, stopIndex - startIndex + 1).IndexOf(toReplace) != 0)
28+
{
29+
return original;
30+
}
31+
32+
return prefix + toReplace.Replace(toReplace, replacement) + suffix;
33+
}
34+
}
35+
}

RetailCoder.VBE/Inspections/QuickFixes/AssignedByValParameterMakeLocalCopyQuickFix.cs

Lines changed: 85 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,25 @@
99
using Rubberduck.UI.Refactorings;
1010
using Rubberduck.Common;
1111
using Antlr4.Runtime;
12+
using System.Collections.Generic;
13+
using Antlr4.Runtime.Tree;
1214

1315
namespace Rubberduck.Inspections.QuickFixes
1416
{
1517
public class AssignedByValParameterMakeLocalCopyQuickFix : QuickFixBase
1618
{
1719
private readonly Declaration _target;
1820
private string _localCopyVariableName;
21+
private string[] _variableNamesAccessibleToProcedureContext;
1922
private bool _isQuickFixUnitTest;
20-
private QuickFixHelper _quickFixHelper;
2123

2224
public AssignedByValParameterMakeLocalCopyQuickFix(Declaration target, QualifiedSelection selection)
2325
: base(target.Context, selection, InspectionsUI.AssignedByValParameterQuickFix)
2426
{
2527
_target = target;
2628
_isQuickFixUnitTest = false;
2729
_localCopyVariableName = "x" + _target.IdentifierName.CapitalizeFirstLetter();
28-
_quickFixHelper = new QuickFixHelper(_target, selection);
30+
_variableNamesAccessibleToProcedureContext = GetVariableNamesAccessibleToProcedureContext(_target.Context.Parent.Parent);
2931
}
3032

3133
public override bool CanFixInModule { get { return false; } }
@@ -46,24 +48,24 @@ public void TESTONLY_FixUsingAutoGeneratedName(string suggestedName = "")
4648

4749
public override void Fix()
4850
{
49-
5051
SetLocalCopyVariableName();
5152

52-
if (!ProposedLocalVariableNameIsValid()
53-
|| IsCancelled)
53+
if (!ProposedLocalVariableNameIsValid() || IsCancelled)
5454
{
5555
return;
5656
}
5757

58-
ModifyBlockToUseLocalCopyVariable();
58+
ReplaceAssignedByValParameterReferences();
59+
60+
InsertLocalVariableDeclarationAndAssignment();
5961
}
6062

6163
private void SetLocalCopyVariableName()
6264
{
6365
using (var view = new AssignedByValParameterQuickFixDialog(_target, Selection))
6466
{
6567
view.NewName = _localCopyVariableName;
66-
view.IdentifierNamesAlreadyDeclared = _quickFixHelper.GetIdentifierNamesAccessibleToProcedureContext();
68+
view.IdentifierNamesAlreadyDeclared = _variableNamesAccessibleToProcedureContext;
6769
if (!_isQuickFixUnitTest)
6870
{
6971
view.ShowDialog();
@@ -80,43 +82,101 @@ private bool ProposedLocalVariableNameIsValid()
8082
{
8183
var validator = new VariableNameValidator(_localCopyVariableName);
8284
return validator.IsValidName()
83-
&& !_quickFixHelper.GetIdentifierNamesAccessibleToProcedureContext().Any(name => name.ToUpper().Equals(_localCopyVariableName.ToUpper()));
84-
}
85-
86-
private void ModifyBlockToUseLocalCopyVariable()
87-
{
88-
ReplaceAssignedByValParameterReferences();
89-
90-
InsertLocalVariableDeclarationAndAssignment(GetFirstBlockStartLine());
85+
&& !_variableNamesAccessibleToProcedureContext
86+
.Any(name => name.ToUpper().Equals(_localCopyVariableName.ToUpper()));
9187
}
9288

9389
private void ReplaceAssignedByValParameterReferences()
9490
{
91+
var module = Selection.QualifiedName.Component.CodeModule;
9592
foreach (IdentifierReference identifierReference in _target.References)
9693
{
97-
_quickFixHelper.ReplaceIdentifierReferenceNameInModule(identifierReference, _localCopyVariableName);
94+
module.ReplaceIdentifierReferenceName(identifierReference, _localCopyVariableName);
9895
}
9996
}
100-
private int GetFirstBlockStartLine()
101-
{
102-
var blocks = _quickFixHelper.GetBlockStmtContextsForContext(_target.Context.Parent.Parent);
103-
return blocks.FirstOrDefault().Start.Line;
104-
}
105-
private void InsertLocalVariableDeclarationAndAssignment(int firstBlockLineNumber)
97+
private void InsertLocalVariableDeclarationAndAssignment()
10698
{
107-
string[] newLines = { BuildLocalCopyDeclaration(), BuildLocalCopyAssignment() };
108-
_quickFixHelper.InsertAfterCodeModuleLine(firstBlockLineNumber - 1, newLines);
99+
var blocks = QuickFixHelper.GetBlockStmtContextsForContext(_target.Context.Parent.Parent);
100+
var firstBlockLineNumber = blocks.FirstOrDefault().Start.Line;
101+
102+
var module = Selection.QualifiedName.Component.CodeModule;
103+
module.InsertLines(firstBlockLineNumber++, BuildLocalCopyDeclaration());
104+
module.InsertLines(firstBlockLineNumber, BuildLocalCopyAssignment());
109105
}
110106
private string BuildLocalCopyDeclaration()
111107
{
112108
return Tokens.Dim + " " + _localCopyVariableName + " " + Tokens.As
113109
+ " " + _target.AsTypeName;
114110
}
115-
116111
private string BuildLocalCopyAssignment()
117112
{
118113
return (SymbolList.ValueTypes.Contains(_target.AsTypeName) ? string.Empty : Tokens.Set + " ")
119114
+ _localCopyVariableName + " = " + _target.IdentifierName;
120115
}
116+
private string[] GetVariableNamesAccessibleToProcedureContext(RuleContext ruleContext)
117+
{
118+
var allIdentifiers = new HashSet<string>();
119+
120+
var blocks = QuickFixHelper.GetBlockStmtContextsForContext(ruleContext);
121+
122+
var blockStmtIdentifiers = GetIdentifierNames(blocks);
123+
124+
allIdentifiers.UnionWith(blockStmtIdentifiers);
125+
126+
var args = QuickFixHelper.GetArgContextsForContext(ruleContext);
127+
128+
var potentiallyUnreferencedParameters = GetIdentifierNames(args);
129+
allIdentifiers.UnionWith(potentiallyUnreferencedParameters);
130+
131+
//TODO: add module and global scope variableNames.
132+
133+
return allIdentifiers.ToArray();
134+
}
135+
private HashSet<string> GetIdentifierNames(IReadOnlyList<RuleContext> ruleContexts)
136+
{
137+
var identifiers = new HashSet<string>();
138+
foreach (RuleContext ruleContext in ruleContexts)
139+
{
140+
var identifiersForThisContext = GetIdentifierNames(ruleContext);
141+
identifiers.UnionWith(identifiersForThisContext);
142+
}
143+
return identifiers;
144+
}
145+
private HashSet<string> GetIdentifierNames(RuleContext ruleContext)
146+
{
147+
//Recursively work through the tree to get all IdentifierContexts
148+
var results = new HashSet<string>();
149+
var tokenValues = typeof(Tokens).GetFields().Select(item => item.GetValue(null)).Cast<string>().Select(item => item);
150+
var children = GetChildren(ruleContext);
151+
152+
foreach (IParseTree child in children)
153+
{
154+
if (child is VBAParser.IdentifierContext)
155+
{
156+
var childName = Identifier.GetName((VBAParser.IdentifierContext)child);
157+
if (!tokenValues.Contains(childName))
158+
{
159+
results.Add(childName);
160+
}
161+
}
162+
else
163+
{
164+
if (!(child is TerminalNodeImpl))
165+
{
166+
results.UnionWith(GetIdentifierNames((RuleContext)child));
167+
}
168+
}
169+
}
170+
return results;
171+
}
172+
private static List<IParseTree> GetChildren(RuleContext ruleCtx)
173+
{
174+
var result = new List<IParseTree>();
175+
for (int index = 0; index < ruleCtx.ChildCount; index++)
176+
{
177+
result.Add(ruleCtx.GetChild(index));
178+
}
179+
return result;
180+
}
121181
}
122182
}
Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
using Antlr4.Runtime;
2+
using Rubberduck.Common;
23
using Rubberduck.Inspections.Abstract;
34
using Rubberduck.Inspections.Resources;
45
using Rubberduck.Parsing.Grammar;
56
using Rubberduck.Parsing.Symbols;
67
using Rubberduck.VBEditor;
8+
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
79
using System.Linq;
810

911
namespace Rubberduck.Inspections.QuickFixes
@@ -14,26 +16,22 @@ namespace Rubberduck.Inspections.QuickFixes
1416
public class PassParameterByReferenceQuickFix : QuickFixBase
1517
{
1618
private Declaration _target;
17-
private QuickFixHelper _quickFixHelper;
1819

1920
public PassParameterByReferenceQuickFix(Declaration target, QualifiedSelection selection)
2021
: base(target.Context, selection, InspectionsUI.PassParameterByReferenceQuickFix)
2122
{
2223
_target = target;
23-
_quickFixHelper = new QuickFixHelper(target, selection);
2424
}
2525

2626
public override void Fix()
2727
{
28-
var argCtxt = GetArgContextForIdentifier(Context.Parent.Parent, _target.IdentifierName);
28+
var module = Selection.QualifiedName.Component.CodeModule;
29+
var argContext = QuickFixHelper.GetArgContextsForContext(Context.Parent.Parent)
30+
.SingleOrDefault(parameter => Identifier.GetName(parameter.unrestrictedIdentifier())
31+
.Equals(_target.IdentifierName));
2932

30-
_quickFixHelper.ReplaceTerminalNodeTextInCodeModule(argCtxt.BYVAL(), Tokens.ByRef);
31-
}
32-
private VBAParser.ArgContext GetArgContextForIdentifier(RuleContext context, string identifier)
33-
{
34-
var args = _quickFixHelper.GetArgContextsForContext(context);
35-
return args.SingleOrDefault(parameter =>
36-
Identifier.GetName(parameter.unrestrictedIdentifier()).Equals(identifier));
33+
module.ReplaceToken(argContext.BYVAL().Symbol,Tokens.ByRef);
34+
3735
}
3836
}
3937
}

0 commit comments

Comments
 (0)