Skip to content

Commit 5c89ec6

Browse files
committed
Cleaned up IParseTreeListeners from within ParseTask and moved them into the Resolving code
Code Cleanup, Fixed temporal coupling between comments and declarations
1 parent 2efe262 commit 5c89ec6

File tree

6 files changed

+164
-203
lines changed

6 files changed

+164
-203
lines changed

Rubberduck.Parsing/IRubberduckParser.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ public interface IRubberduckParser
1010
{
1111
RubberduckParserState State { get; }
1212
void ParseComponent(VBComponent component, TokenStreamRewriter rewriter = null);
13-
Task ParseAsync(VBComponent component, TokenStreamRewriter rewriter = null);
13+
Task ParseAsync(VBComponent component, CancellationToken token, TokenStreamRewriter rewriter = null);
1414
void Cancel(VBComponent component = null);
1515
void Resolve(CancellationToken token);
1616
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using Antlr4.Runtime;
2+
using Antlr4.Runtime.Tree;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
6+
namespace Rubberduck.Parsing.VBA
7+
{
8+
/// <summary>
9+
/// A Class combining an arbitrary number of IParseTreeListener instances into one single instance
10+
/// </summary>
11+
public class CombinedParseTreeListener : IParseTreeListener
12+
{
13+
private List<IParseTreeListener> _listeners;
14+
public CombinedParseTreeListener(IParseTreeListener[] listeners)
15+
{
16+
_listeners = listeners.ToList();
17+
}
18+
19+
public void EnterEveryRule(ParserRuleContext ctx)
20+
{
21+
_listeners.ForEach(l => l.EnterEveryRule(ctx));
22+
}
23+
24+
public void ExitEveryRule(ParserRuleContext ctx)
25+
{
26+
_listeners.ForEach(l => l.ExitEveryRule(ctx));
27+
}
28+
29+
public void VisitErrorNode(IErrorNode node)
30+
{
31+
_listeners.ForEach(l => l.VisitErrorNode(node));
32+
}
33+
34+
public void VisitTerminal(ITerminalNode node)
35+
{
36+
_listeners.ForEach(l => l.VisitTerminal(node));
37+
}
38+
}
39+
}

Rubberduck.Parsing/VBA/ComponentParseTask.cs

Lines changed: 21 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ namespace Rubberduck.Parsing.VBA
2020
{
2121
class ComponentParseTask
2222
{
23-
private readonly IParseTreeListener[] _listeners;
24-
2523
private readonly VBComponent _component;
2624
private readonly QualifiedModuleName _qualifiedName;
2725
private readonly TokenStreamRewriter _rewriter;
@@ -34,14 +32,6 @@ class ComponentParseTask
3432
public ComponentParseTask(VBComponent vbComponent, VBAPreprocessor preprocessor, IAttributeParser attributeParser, TokenStreamRewriter rewriter = null)
3533
{
3634
_component = vbComponent;
37-
_listeners = new IParseTreeListener[]
38-
{
39-
new ObsoleteCallStatementListener(),
40-
new ObsoleteLetStatementListener(),
41-
new EmptyStringLiteralListener(),
42-
new ArgListWithOneByRefParamListener(),
43-
new CommentListener(),
44-
};
4535
_rewriter = rewriter;
4636
_qualifiedName = new QualifiedModuleName(vbComponent);
4737
}
@@ -58,38 +48,32 @@ private void ParseInternal(CancellationToken token)
5848
var code = RewriteAndPreprocess();
5949
token.ThrowIfCancellationRequested();
6050

51+
// temporal coupling... comments must be acquired before we walk the parse tree for declarations
52+
// otherwise none of the annotations get associated to their respective Declaration
53+
var commentListener = new CommentListener();
54+
6155
var stopwatch = Stopwatch.StartNew();
6256
ITokenStream stream;
63-
var tree = ParseInternal(code, _listeners, out stream);
57+
var tree = ParseInternal(code, new IParseTreeListener[]{ commentListener }, out stream);
6458
stopwatch.Stop();
6559
if (tree != null)
6660
{
6761
Debug.Print("IParseTree for component '{0}' acquired in {1}ms (thread {2})", _component.Name, stopwatch.ElapsedMilliseconds, Thread.CurrentThread.ManagedThreadId);
6862
}
6963

64+
var comments = QualifyAndUnionComments(_qualifiedName, commentListener.Comments, commentListener.RemComments);
7065
token.ThrowIfCancellationRequested();
7166

7267
var attributes = _attributeParser.Parse(_component);
73-
CommentListener commentListener = _listeners.OfType<CommentListener>().Single();
74-
var comments = ParseComments(_qualifiedName, commentListener.Comments, commentListener.RemComments);
7568

7669
token.ThrowIfCancellationRequested();
7770

78-
var obsoleteCallsListener = _listeners.OfType<ObsoleteCallStatementListener>().Single();
79-
var obsoleteLetListener = _listeners.OfType<ObsoleteLetStatementListener>().Single();
80-
var emptyStringLiteralListener = _listeners.OfType<EmptyStringLiteralListener>().Single();
81-
var argListsWithOneByRefParamListener = _listeners.OfType<ArgListWithOneByRefParamListener>().Single();
82-
8371
ParseCompleted.Invoke(this, new ParseCompletionArgs
8472
{
85-
Comments = comments,
8673
ParseTree = tree,
8774
Tokens = stream,
8875
Attributes = attributes,
89-
ObsoleteCallContexts = obsoleteCallsListener.Contexts.Select(context => new QualifiedContext(_qualifiedName, context)),
90-
ObsoleteLetContexts = obsoleteLetListener.Contexts.Select(context => new QualifiedContext(_qualifiedName, context)),
91-
EmptyStringLiterals = emptyStringLiteralListener.Contexts.Select(context => new QualifiedContext(_qualifiedName, context)),
92-
ArgListsWithOneByRefParam = argListsWithOneByRefParamListener.Contexts.Select(context => new QualifiedContext(_qualifiedName, context)),
76+
Comments = comments,
9377
});
9478
}
9579
catch (COMException exception)
@@ -132,25 +116,24 @@ private string RewriteAndPreprocess()
132116
return processed;
133117
}
134118

135-
private static IParseTree ParseInternal(string code, IEnumerable<IParseTreeListener> listeners, out ITokenStream outStream)
119+
private static IParseTree ParseInternal(string code, IParseTreeListener[] listeners, out ITokenStream outStream)
136120
{
137121
var stream = new AntlrInputStream(code);
138122
var lexer = new VBALexer(stream);
139123
var tokens = new CommonTokenStream(lexer);
140124
var parser = new VBAParser(tokens);
141125

142126
parser.AddErrorListener(new ExceptionErrorListener());
143-
foreach (var listener in listeners)
127+
foreach (var l in listeners)
144128
{
145-
parser.AddParseListener(listener);
129+
parser.AddParseListener(l);
146130
}
147131

148132
outStream = tokens;
149133
return parser.startRule();
150134
}
151135

152-
153-
private IEnumerable<CommentNode> ParseComments(QualifiedModuleName qualifiedName, IEnumerable<VBAParser.CommentContext> comments, IEnumerable<VBAParser.RemCommentContext> remComments)
136+
private IEnumerable<CommentNode> QualifyAndUnionComments(QualifiedModuleName qualifiedName, IEnumerable<VBAParser.CommentContext> comments, IEnumerable<VBAParser.RemCommentContext> remComments)
154137
{
155138
var commentNodes = comments.Select(comment => new CommentNode(comment.GetComment(), Tokens.CommentMarker, new QualifiedSelection(qualifiedName, comment.GetSelection())));
156139
var remCommentNodes = remComments.Select(comment => new CommentNode(comment.GetComment(), Tokens.Rem, new QualifiedSelection(qualifiedName, comment.GetSelection())));
@@ -167,107 +150,32 @@ public class ParseCompletionArgs
167150
{
168151
public ITokenStream Tokens { get; internal set; }
169152
public IParseTree ParseTree { get; internal set; }
170-
public IEnumerable<CommentNode> Comments { get; internal set; }
171-
public IEnumerable<QualifiedContext> ObsoleteCallContexts { get; internal set; }
172-
public IEnumerable<QualifiedContext> ObsoleteLetContexts { get; internal set; }
173-
public IEnumerable<QualifiedContext> EmptyStringLiterals { get; internal set; }
174-
public IEnumerable<QualifiedContext> ArgListsWithOneByRefParam { get; internal set; }
175-
public IEnumerable<Declaration> Declarations { get; internal set; }
176153
public IDictionary<Tuple<string, DeclarationType>, Attributes> Attributes { get; internal set; }
154+
public IEnumerable<CommentNode> Comments { get; internal set; }
177155
}
178156

179157
public class ParseFailureArgs
180158
{
181159
public Exception Cause { get; internal set; }
182160
}
183-
}
184-
185-
#region Listener classes
186-
class ObsoleteCallStatementListener : VBABaseListener
187-
{
188-
private readonly IList<VBAParser.ExplicitCallStmtContext> _contexts = new List<VBAParser.ExplicitCallStmtContext>();
189-
public IEnumerable<VBAParser.ExplicitCallStmtContext> Contexts { get { return _contexts; } }
190161

191-
public override void ExitExplicitCallStmt(VBAParser.ExplicitCallStmtContext context)
162+
private class CommentListener : VBABaseListener
192163
{
193-
var procedureCall = context.eCS_ProcedureCall();
194-
if (procedureCall != null)
195-
{
196-
if (procedureCall.CALL() != null)
197-
{
198-
_contexts.Add(context);
199-
return;
200-
}
201-
}
164+
private readonly IList<VBAParser.RemCommentContext> _remComments = new List<VBAParser.RemCommentContext>();
165+
public IEnumerable<VBAParser.RemCommentContext> RemComments { get { return _remComments; } }
202166

203-
var memberCall = context.eCS_MemberProcedureCall();
204-
if (memberCall == null) return;
205-
if (memberCall.CALL() == null) return;
206-
_contexts.Add(context);
207-
}
208-
}
167+
private readonly IList<VBAParser.CommentContext> _comments = new List<VBAParser.CommentContext>();
168+
public IEnumerable<VBAParser.CommentContext> Comments { get { return _comments; } }
209169

210-
class ObsoleteLetStatementListener : VBABaseListener
211-
{
212-
private readonly IList<VBAParser.LetStmtContext> _contexts = new List<VBAParser.LetStmtContext>();
213-
public IEnumerable<VBAParser.LetStmtContext> Contexts { get { return _contexts; } }
214-
215-
public override void ExitLetStmt(VBAParser.LetStmtContext context)
216-
{
217-
if (context.LET() != null)
170+
public override void ExitRemComment([NotNull] VBAParser.RemCommentContext context)
218171
{
219-
_contexts.Add(context);
172+
_remComments.Add(context);
220173
}
221-
}
222-
}
223174

224-
class EmptyStringLiteralListener : VBABaseListener
225-
{
226-
private readonly IList<VBAParser.LiteralContext> _contexts = new List<VBAParser.LiteralContext>();
227-
public IEnumerable<VBAParser.LiteralContext> Contexts { get { return _contexts; } }
228-
229-
public override void ExitLiteral(VBAParser.LiteralContext context)
230-
{
231-
var literal = context.STRINGLITERAL();
232-
if (literal != null && literal.GetText() == "\"\"")
233-
{
234-
_contexts.Add(context);
235-
}
236-
}
237-
}
238-
239-
class ArgListWithOneByRefParamListener : VBABaseListener
240-
{
241-
private readonly IList<VBAParser.ArgListContext> _contexts = new List<VBAParser.ArgListContext>();
242-
public IEnumerable<VBAParser.ArgListContext> Contexts { get { return _contexts; } }
243-
244-
public override void ExitArgList(VBAParser.ArgListContext context)
245-
{
246-
if (context.arg() != null && context.arg().Count(a => a.BYREF() != null || (a.BYREF() == null && a.BYVAL() == null)) == 1)
175+
public override void ExitComment([NotNull] VBAParser.CommentContext context)
247176
{
248-
_contexts.Add(context);
177+
_comments.Add(context);
249178
}
250179
}
251180
}
252-
253-
class CommentListener : VBABaseListener
254-
{
255-
private readonly IList<VBAParser.RemCommentContext> _remComments = new List<VBAParser.RemCommentContext>();
256-
public IEnumerable<VBAParser.RemCommentContext> RemComments { get { return _remComments; } }
257-
258-
private readonly IList<VBAParser.CommentContext> _comments = new List<VBAParser.CommentContext>();
259-
public IEnumerable<VBAParser.CommentContext> Comments { get { return _comments; } }
260-
261-
public override void ExitRemComment([NotNull] VBAParser.RemCommentContext context)
262-
{
263-
_remComments.Add(context);
264-
}
265-
266-
public override void ExitComment([NotNull] VBAParser.CommentContext context)
267-
{
268-
_comments.Add(context);
269-
}
270-
}
271-
272-
#endregion
273181
}

Rubberduck.Parsing/VBA/RubberduckParser.cs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ public RubberduckParser(VBE vbe, RubberduckParserState state, IAttributeParser a
3838

3939
private void ReparseRequested(object sender, EventArgs e)
4040
{
41-
Task.Run(() => ParseInternal());
42-
}
41+
Task.Run(() => ParseInternal());
42+
}
4343

4444
private readonly VBE _vbe;
4545
private readonly RubberduckParserState _state;
@@ -129,7 +129,8 @@ private void AddDeclarationsFromProjectReferences(IReadOnlyList<VBProject> proje
129129
var references = projects
130130
.SelectMany(project => project.References.Cast<Reference>())
131131
.DistinctBy(reference => reference.Guid)
132-
.Where(reference => reference.Type == vbext_RefKind.vbext_rk_TypeLib);
132+
.Where(reference => reference.Type == vbext_RefKind.vbext_rk_TypeLib)
133+
.ToList();
133134
foreach (var reference in references)
134135
{
135136
AddDeclarationsFromReference(reference);
@@ -360,6 +361,26 @@ private ParserState WalkParseTree(VBComponent component, IParseTree tree, Declar
360361
return ParserState.Ready;
361362
}
362363

364+
public void Resolve(CancellationToken token)
365+
{
366+
throw new NotImplementedException();
367+
}
368+
369+
public Task ParseAsync(VBComponent component, TokenStreamRewriter rewriter = null)
370+
{
371+
throw new NotImplementedException();
372+
}
373+
374+
public void Cancel(VBComponent component = null)
375+
{
376+
throw new NotImplementedException();
377+
}
378+
379+
public Task ParseAsync(VBComponent component, CancellationToken token, TokenStreamRewriter rewriter = null)
380+
{
381+
throw new NotImplementedException();
382+
}
383+
363384
private class ObsoleteCallStatementListener : VBAParserBaseListener
364385
{
365386
private readonly IList<VBAParser.ExplicitCallStmtContext> _contexts = new List<VBAParser.ExplicitCallStmtContext>();

0 commit comments

Comments
 (0)