Skip to content

Commit d4a5235

Browse files
committed
Reworked QuickFix to use ArgContext
1 parent a3eb575 commit d4a5235

File tree

1 file changed

+62
-169
lines changed

1 file changed

+62
-169
lines changed
Lines changed: 62 additions & 169 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
using Antlr4.Runtime;
2+
using Antlr4.Runtime.Tree;
23
using Rubberduck.Inspections.Abstract;
34
using Rubberduck.Inspections.Resources;
45
using Rubberduck.Parsing.Grammar;
56
using Rubberduck.Parsing.Symbols;
67
using Rubberduck.VBEditor;
7-
using System;
8-
using System.Collections.Generic;
9-
using System.Text.RegularExpressions;
108
using static Rubberduck.Parsing.Grammar.VBAParser;
119

1210
namespace Rubberduck.Inspections.QuickFixes
@@ -17,208 +15,103 @@ namespace Rubberduck.Inspections.QuickFixes
1715
public class PassParameterByReferenceQuickFix : QuickFixBase
1816
{
1917
private Declaration _target;
20-
private int _byValTokenProcLine;
21-
private int _byValIdentifierNameProcLine;
2218

2319
public PassParameterByReferenceQuickFix(Declaration target, QualifiedSelection selection)
2420
: base(target.Context, selection, InspectionsUI.PassParameterByReferenceQuickFix)
2521
{
2622
_target = target;
27-
_byValTokenProcLine = 0;
28-
_byValIdentifierNameProcLine = 0;
2923
}
3024

3125
public override void Fix()
3226
{
33-
string byValTargetString;
34-
string byValTokenReplacementString;
35-
string replacementString;
27+
var argCtxt = GetArgContextForIdentifier(Context, _target.IdentifierName);
3628

37-
var procLines = RetrieveProcedureLines();
29+
var terminalNodeImpl = GetByValNodeForArgCtx(argCtxt);
3830

39-
SetMemberLineValues(procLines);
31+
var replacementLine = GenerateByRefReplacementLine(terminalNodeImpl);
4032

41-
string moduleLineWithByValToken = procLines[_byValTokenProcLine - 1];
33+
ReplaceModuleLine(terminalNodeImpl.Symbol.Line, replacementLine);
4234

43-
if (_byValTokenProcLine == _byValIdentifierNameProcLine)
44-
{
45-
//The replacement is based on the (e.g. "ByVal identifierName")
46-
byValTargetString = Tokens.ByVal + " " + _target.IdentifierName;
47-
byValTokenReplacementString = BuildByRefParameter(byValTargetString);
48-
replacementString = moduleLineWithByValToken.Replace(byValTargetString, byValTokenReplacementString);
49-
}
50-
else
51-
{
52-
//if the token and identifier are on different lines, then the target
53-
//string consists of the ByVal token and the LineContinuation token.
54-
//(e.g. the replacement is based on "ByVal _". Spaces between tokens can vary)
55-
byValTargetString = GetUniqueTargetStringForByValAtEndOfLine(moduleLineWithByValToken);
56-
byValTokenReplacementString = BuildByRefParameter(byValTargetString);
57-
58-
//avoid updating possible cases of ByVal followed by underscore-prefixed identifiers
59-
var index = moduleLineWithByValToken.LastIndexOf(byValTargetString);
60-
var firstPart = moduleLineWithByValToken.Substring(0, index);
61-
replacementString = firstPart + byValTokenReplacementString;
62-
}
63-
64-
var module = Selection.QualifiedName.Component.CodeModule;
65-
module.ReplaceLine(RetrieveTheProcedureStartLine() + _byValTokenProcLine-1, replacementString);
6635
}
67-
private string[] RetrieveProcedureLines()
36+
private ArgContext GetArgContextForIdentifier(ParserRuleContext context, string identifier)
6837
{
69-
var moduleContent = Context.Start.InputStream.ToString();
70-
string[] newLine = { "\r\n" };
71-
var moduleLines = moduleContent.Split(newLine, StringSplitOptions.None);
72-
var procLines = new List<string>();
73-
var startIndex = RetrieveTheProcedureStartLine();
74-
var endIndex = RetrieveTheProcedureEndLine();
75-
for ( int idx = startIndex - 1; idx < endIndex; idx++)
38+
var procStmtCtx = (ParserRuleContext)context.Parent.Parent;
39+
var procStmtCtxChildren = procStmtCtx.children;
40+
for (int idx = 0; idx < procStmtCtxChildren.Count; idx++)
7641
{
77-
procLines.Add(moduleLines[idx]);
42+
if (procStmtCtxChildren[idx] is SubstmtContext)
43+
{
44+
var procStmtCtxChild = (SubstmtContext)procStmtCtxChildren[idx];
45+
var arg = procStmtCtxChild.children;
46+
for (int idx2 = 0; idx2 < arg.Count; idx2++)
47+
{
48+
if (arg[idx2] is ArgContext)
49+
{
50+
var name = GetIdentifierNameFor((ArgContext)arg[idx2]);
51+
if (name.Equals(identifier))
52+
{
53+
return (ArgContext)arg[idx2];
54+
}
55+
}
56+
}
57+
}
7858
}
79-
return procLines.ToArray();
80-
}
81-
private int RetrieveTheProcedureStartLine()
82-
{
83-
var parserRuleCtxt = (ParserRuleContext)Context.Parent.Parent;
84-
return parserRuleCtxt.Start.Line;
85-
}
86-
private int RetrieveTheProcedureEndLine()
87-
{
88-
var parserRuleCtxt = (ParserRuleContext)Context.Parent.Parent;
89-
return parserRuleCtxt.Stop.Line;
90-
}
91-
private string BuildByRefParameter(string originalParameter)
92-
{
93-
var everythingAfterTheByValToken = originalParameter.Substring(Tokens.ByVal.Length);
94-
return Tokens.ByRef + everythingAfterTheByValToken;
59+
return null;
9560
}
96-
private string GetUniqueTargetStringForByValAtEndOfLine(string procLineWithByValToken)
61+
private string GetIdentifierNameFor(ArgContext argCtxt)
9762
{
98-
System.Diagnostics.Debug.Assert(procLineWithByValToken.Contains(Tokens.LineContinuation));
99-
100-
var positionOfLineContinuation = procLineWithByValToken.LastIndexOf(Tokens.LineContinuation);
101-
var positionOfLastByValToken = procLineWithByValToken.LastIndexOf(Tokens.ByVal);
102-
return procLineWithByValToken.Substring(positionOfLastByValToken, positionOfLineContinuation - positionOfLastByValToken + Tokens.LineContinuation.Length);
63+
var argCtxtChild = argCtxt.children;
64+
var idRef = GetUnRestrictedIdentifierCtx(argCtxt);
65+
return idRef.GetText();
10366
}
104-
private void SetMemberLineValues(string[] procedureLines)
67+
private UnrestrictedIdentifierContext GetUnRestrictedIdentifierCtx(ArgContext argCtxt)
10568
{
106-
107-
string line;
108-
bool byValTokenFound = false;
109-
bool byValIdentifierNameFound = false;
110-
for (int zbIndexByValLine = 0; !byValIdentifierNameFound && zbIndexByValLine < procedureLines.Length; zbIndexByValLine++)
69+
var argCtxtChild = argCtxt.children;
70+
for (int idx = 0; idx < argCtxtChild.Count; idx++)
11171
{
112-
line = procedureLines[zbIndexByValLine];
113-
if (line.Contains(Tokens.ByVal))
72+
if (argCtxtChild[idx] is UnrestrictedIdentifierContext)
11473
{
115-
_byValTokenProcLine = zbIndexByValLine + 1;
116-
byValTokenFound = true;
117-
}
118-
if (byValTokenFound)
119-
{
120-
int lineNum = GetIdentifierLineNumber(_target.IdentifierName);
121-
if(lineNum > 0)
122-
{
123-
_byValIdentifierNameProcLine = lineNum;
124-
byValIdentifierNameFound = true;
125-
}
126-
/*
127-
if (line.Contains(_target.IdentifierName))
128-
{
129-
_byValIdentifierNameProcLine = zbIndexByValLine + 1;
130-
byValIdentifierNameFound = true;
131-
}
132-
*/
74+
return (UnrestrictedIdentifierContext)argCtxtChild[idx];
13375
}
13476
}
135-
136-
System.Diagnostics.Debug.Assert(_byValTokenProcLine > 0);
137-
System.Diagnostics.Debug.Assert(_byValIdentifierNameProcLine > 0);
138-
return;
77+
return null;
13978
}
140-
private int GetIdentifierLineNumber(string identifier)
79+
private TerminalNodeImpl GetByValNodeForArgCtx(ArgContext argCtxt)
14180
{
142-
var names = new List<string>();
143-
var test = (SubStmtContext)Context.Parent.Parent;
144-
var next = test.children;
145-
for (int idx = 0; idx < next.Count; idx++)
81+
var argCtxtChild = argCtxt.children;
82+
for (int idx = 0; idx < argCtxtChild.Count; idx++)
14683
{
147-
if (next[idx] is SubstmtContext)
84+
if (argCtxtChild[idx] is TerminalNodeImpl)
14885
{
149-
var child = (SubstmtContext)next[idx];
150-
var arg = child.children;
151-
for (int idx2 = 0; idx2 < arg.Count; idx2++)
86+
var candidate = (TerminalNodeImpl)argCtxtChild[idx];
87+
if (candidate.Symbol.Text.Equals(Tokens.ByVal))
15288
{
153-
if (arg[idx2] is ArgContext)
154-
{
155-
var asdf = (ArgContext)arg[idx2];
156-
var kids = asdf.children;
157-
for (int idx3 = 0; idx3 < kids.Count; idx3++)
158-
{
159-
var _start = (ParserRuleContext)kids[0];
160-
var _stop = (ParserRuleContext)kids[kids.Count-1];
161-
int startCol = _start.Start.Column;
162-
int stopCol = _start.Stop.Column;
163-
164-
if (kids[idx3] is UnrestrictedIdentifierContext)
165-
{
166-
var idRef = (UnrestrictedIdentifierContext)kids[idx3];
167-
var name = idRef.Start.Text;
168-
if (name.Equals(identifier))
169-
{
170-
int lineNum = idRef.Start.Line;
171-
return lineNum;
172-
}
173-
}
174-
}
175-
}
89+
return candidate;
17690
}
17791
}
17892
}
179-
return -1;
93+
return null;
18094
}
181-
private int GetIdentifierStartIndex(string identifier, out int stopIndex)
95+
private string GenerateByRefReplacementLine(TerminalNodeImpl terminalNodeImpl)
18296
{
183-
var names = new List<string>();
184-
var test = (SubStmtContext)Context.Parent.Parent;
185-
var next = test.children;
186-
for (int idx = 0; idx < next.Count; idx++)
187-
{
188-
if (next[idx] is SubstmtContext)
189-
{
190-
var child = (SubstmtContext)next[idx];
191-
var arg = child.children;
192-
for (int idx2 = 0; idx2 < arg.Count; idx2++)
193-
{
194-
if (arg[idx2] is ArgContext)
195-
{
196-
var asdf = (ArgContext)arg[idx2];
197-
var kids = asdf.children;
198-
for (int idx3 = 0; idx3 < kids.Count; idx3++)
199-
{
200-
var _start = (ParserRuleContext)kids[0];
201-
var _stop = (ParserRuleContext)kids[kids.Count - 1];
202-
stopIndex = _start.Stop.Column;
203-
return _start.Start.Column;
97+
var module = Selection.QualifiedName.Component.CodeModule;
98+
var byValTokenLine = module.GetLines(terminalNodeImpl.Symbol.Line, 1);
20499

205-
if (kids[idx3] is UnrestrictedIdentifierContext)
206-
{
207-
var idRef = (UnrestrictedIdentifierContext)kids[idx3];
208-
var name = idRef.Start.Text;
209-
if (name.Equals(identifier))
210-
{
211-
int lineNum = idRef.Start.Line;
212-
return lineNum;
213-
}
214-
}
215-
}
216-
}
217-
}
218-
}
219-
}
220-
stopIndex = -1;
221-
return -1;
100+
return ReplaceAtIndex(byValTokenLine, Tokens.ByVal, Tokens.ByRef, terminalNodeImpl.Symbol.Column);
101+
}
102+
private string ReplaceAtIndex(string input, string toReplace, string replacement, int index)
103+
{
104+
int stopIndex = index + toReplace.Length;
105+
var prefix = input.Substring(0, index);
106+
var suffix = input.Substring(stopIndex + 1);
107+
var target = input.Substring(index, stopIndex - index + 1);
108+
return prefix + target.Replace(toReplace, replacement) + suffix;
109+
}
110+
private void ReplaceModuleLine(int lineNumber, string replacementLine)
111+
{
112+
var module = Selection.QualifiedName.Component.CodeModule;
113+
module.DeleteLines(lineNumber);
114+
module.InsertLines(lineNumber, replacementLine);
222115
}
223116
}
224117
}

0 commit comments

Comments
 (0)