Skip to content

Commit 8cc941e

Browse files
committed
closes #1754
1 parent a86da60 commit 8cc941e

File tree

2 files changed

+91
-1
lines changed

2 files changed

+91
-1
lines changed

RetailCoder.VBE/Common/CodeModuleExtensions.cs

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Linq;
55
using Antlr4.Runtime;
66
using Rubberduck.Parsing;
7+
using Rubberduck.Parsing.Grammar;
78
using Rubberduck.Parsing.Symbols;
89
using Rubberduck.Parsing.VBA;
910
using Rubberduck.VBEditor;
@@ -162,10 +163,74 @@ private static string RemoveExtraComma(string str, int numParams, int indexRemov
162163

163164
public static void Remove(this ICodeModule module, IdentifierReference target)
164165
{
165-
var parent = target.Context.Parent as ParserRuleContext;
166+
var parent = (ParserRuleContext)target.Context.Parent;
167+
if (target.IsAssignment)
168+
{
169+
// target is LHS of assignment; need to know if there's a procedure call in RHS
170+
var letStmt = parent as VBAParser.LetStmtContext;
171+
var setStmt = parent as VBAParser.SetStmtContext;
172+
173+
string argList;
174+
if (HasProcedureCall(letStmt, out argList) || HasProcedureCall(setStmt, out argList))
175+
{
176+
// need to remove LHS only; RHS expression may have side-effects
177+
var original = parent.GetText();
178+
var replacement = ReplaceStringAtIndex(original, target.IdentifierName + " = ", string.Empty, 0);
179+
if (argList != null)
180+
{
181+
var atIndex = replacement.IndexOf(argList, StringComparison.OrdinalIgnoreCase);
182+
var plainArgs = " " + argList.Substring(1, argList.Length - 2);
183+
replacement = ReplaceStringAtIndex(replacement, argList, plainArgs, atIndex);
184+
}
185+
module.ReplaceLine(parent.Start.Line, replacement);
186+
return;
187+
}
188+
}
189+
166190
module.Remove(parent.GetSelection(), parent);
167191
}
168192

193+
private static bool HasProcedureCall(VBAParser.LetStmtContext context, out string argList)
194+
{
195+
if (context == null)
196+
{
197+
argList = null;
198+
return false;
199+
}
200+
return HasProcedureCall(context.expression(), out argList);
201+
}
202+
203+
private static bool HasProcedureCall(VBAParser.SetStmtContext context, out string argList)
204+
{
205+
if (context == null)
206+
{
207+
argList = null;
208+
return false;
209+
}
210+
return HasProcedureCall(context.expression(), out argList);
211+
}
212+
213+
private static bool HasProcedureCall(VBAParser.ExpressionContext context, out string argList)
214+
{
215+
// bug: what if complex expression has multiple arg lists?
216+
argList = GetArgListString(context.FindChildren<VBAParser.ArgListContext>().FirstOrDefault())
217+
?? GetArgListString(context.FindChildren<VBAParser.ArgumentListContext>().FirstOrDefault());
218+
219+
return !(context is VBAParser.LiteralExprContext
220+
|| context is VBAParser.NewExprContext
221+
|| context is VBAParser.BuiltInTypeExprContext);
222+
}
223+
224+
private static string GetArgListString(VBAParser.ArgListContext context)
225+
{
226+
return context == null ? null : context.GetText();
227+
}
228+
229+
private static string GetArgListString(VBAParser.ArgumentListContext context)
230+
{
231+
return context == null ? null : "(" + context.GetText() + ")";
232+
}
233+
169234
public static void Remove(this ICodeModule module, IEnumerable<IdentifierReference> targets)
170235
{
171236
foreach (var target in targets.OrderByDescending(e => e.Selection))

Rubberduck.Parsing/ParserRuleContextExtensions.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
using System.Collections.Generic;
12
using Antlr4.Runtime;
3+
using Antlr4.Runtime.Tree;
24
using Rubberduck.Parsing.Grammar;
35
using Rubberduck.VBEditor;
46

@@ -36,5 +38,28 @@ private static Selection GetProcedureContextSelection(ParserRuleContext context)
3638
endContext.Start.Line == 0 ? 1 : endContext.Start.Line,
3739
endContext.Start.Column + 1);
3840
}
41+
42+
public static IEnumerable<TContext> FindChildren<TContext>(this ParserRuleContext context) where TContext : ParserRuleContext
43+
{
44+
var walker = new ParseTreeWalker();
45+
var listener = new ChildNodeListener<TContext>();
46+
walker.Walk(listener, context);
47+
return listener.Matches;
48+
}
49+
50+
private class ChildNodeListener<TContext> : VBAParserBaseListener where TContext : ParserRuleContext
51+
{
52+
private readonly HashSet<TContext> _matches = new HashSet<TContext>();
53+
public IEnumerable<TContext> Matches { get { return _matches; } }
54+
55+
public override void EnterEveryRule(ParserRuleContext context)
56+
{
57+
var match = context as TContext;
58+
if (match != null)
59+
{
60+
_matches.Add(match);
61+
}
62+
}
63+
}
3964
}
4065
}

0 commit comments

Comments
 (0)