Skip to content

Commit 137e3dc

Browse files
committed
Redesign ParseTreeInspection base class
Also adds a base for inspection listeners.
1 parent 9734c7f commit 137e3dc

File tree

47 files changed

+536
-932
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+536
-932
lines changed

Rubberduck.CodeAnalysis/Inspections/Abstract/ParseTreeInspectionBase.cs

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using Antlr4.Runtime;
4+
using Rubberduck.Inspections.Results;
5+
using Rubberduck.Parsing;
6+
using Rubberduck.Parsing.Grammar;
17
using Rubberduck.Parsing.Inspections.Abstract;
28
using Rubberduck.Parsing.VBA;
39
using Rubberduck.Parsing.VBA.Parsing;
10+
using Rubberduck.VBEditor;
11+
using Rubberduck.VBEditor.Extensions;
412

513
namespace Rubberduck.Inspections.Abstract
614
{
@@ -10,6 +18,138 @@ protected ParseTreeInspectionBase(RubberduckParserState state)
1018
: base(state) { }
1119

1220
public abstract IInspectionListener Listener { get; }
21+
protected abstract string ResultDescription(QualifiedContext<ParserRuleContext> context);
22+
23+
protected virtual bool IsResultContext(QualifiedContext<ParserRuleContext> context) => true;
24+
25+
protected override IEnumerable<IInspectionResult> DoGetInspectionResults()
26+
{
27+
return DoGetInspectionResults(Listener.Contexts());
28+
}
29+
30+
private IEnumerable<IInspectionResult> DoGetInspectionResults(QualifiedModuleName module)
31+
{
32+
return DoGetInspectionResults(Listener.Contexts(module));
33+
}
34+
35+
private IEnumerable<IInspectionResult> DoGetInspectionResults(IEnumerable<QualifiedContext<ParserRuleContext>> contexts)
36+
{
37+
var objectionableContexts = contexts
38+
.Where(IsResultContext);
39+
40+
return objectionableContexts
41+
.Select(InspectionResult)
42+
.ToList();
43+
}
44+
45+
protected virtual IInspectionResult InspectionResult(QualifiedContext<ParserRuleContext> context)
46+
{
47+
return new QualifiedContextInspectionResult(
48+
this,
49+
ResultDescription(context),
50+
context,
51+
DisabledQuickFixes(context));
52+
}
53+
54+
protected virtual ICollection<string> DisabledQuickFixes(QualifiedContext<ParserRuleContext> context) => new List<string>();
55+
public virtual CodeKind TargetKindOfCode => CodeKind.CodePaneCode;
56+
}
57+
58+
59+
public abstract class ParseTreeInspectionBase<T> : InspectionBase, IParseTreeInspection
60+
{
61+
protected ParseTreeInspectionBase(RubberduckParserState state)
62+
: base(state)
63+
{}
64+
65+
public abstract IInspectionListener Listener { get; }
66+
protected abstract string ResultDescription(QualifiedContext<ParserRuleContext> context, T properties);
67+
protected abstract (bool isResult, T properties) IsResultContextWithAdditionalProperties(QualifiedContext<ParserRuleContext> context);
68+
69+
protected override IEnumerable<IInspectionResult> DoGetInspectionResults()
70+
{
71+
return DoGetInspectionResults(Listener.Contexts());
72+
}
73+
74+
private IEnumerable<IInspectionResult> DoGetInspectionResults(QualifiedModuleName module)
75+
{
76+
return DoGetInspectionResults(Listener.Contexts(module));
77+
}
78+
79+
private IEnumerable<IInspectionResult> DoGetInspectionResults(IEnumerable<QualifiedContext<ParserRuleContext>> contexts)
80+
{
81+
var objectionableContexts = contexts
82+
.Select(ContextsWithResultProperties)
83+
.Where(result => result.HasValue)
84+
.Select(result => result.Value);
85+
86+
return objectionableContexts
87+
.Select(tpl => InspectionResult(tpl.context, tpl.properties))
88+
.ToList();
89+
}
90+
91+
private (QualifiedContext<ParserRuleContext> context, T properties)? ContextsWithResultProperties(QualifiedContext<ParserRuleContext> context)
92+
{
93+
var (isResult, properties) = IsResultContextWithAdditionalProperties(context);
94+
return isResult
95+
? (context, properties)
96+
: ((QualifiedContext<ParserRuleContext> context, T properties)?) null;
97+
}
98+
99+
protected virtual IInspectionResult InspectionResult(QualifiedContext<ParserRuleContext> context, T properties)
100+
{
101+
return new QualifiedContextInspectionResult<T>(
102+
this,
103+
ResultDescription(context, properties),
104+
context,
105+
properties,
106+
DisabledQuickFixes(context, properties));
107+
}
108+
109+
protected virtual ICollection<string> DisabledQuickFixes(QualifiedContext<ParserRuleContext> context, T properties) => new List<string>();
13110
public virtual CodeKind TargetKindOfCode => CodeKind.CodePaneCode;
14111
}
112+
113+
public class InspectionListenerBase : VBAParserBaseListener, IInspectionListener
114+
{
115+
private readonly IDictionary<QualifiedModuleName, List<QualifiedContext<ParserRuleContext>>> _contexts;
116+
117+
public InspectionListenerBase()
118+
{
119+
_contexts = new Dictionary<QualifiedModuleName, List<QualifiedContext<ParserRuleContext>>>();
120+
}
121+
122+
public QualifiedModuleName CurrentModuleName { get; set; }
123+
124+
public IReadOnlyList<QualifiedContext<ParserRuleContext>> Contexts()
125+
{
126+
return _contexts.AllValues().ToList();
127+
}
128+
129+
public IReadOnlyList<QualifiedContext<ParserRuleContext>> Contexts(QualifiedModuleName module)
130+
{
131+
return _contexts.TryGetValue(module, out var contexts)
132+
? contexts
133+
: new List<QualifiedContext<ParserRuleContext>>();
134+
}
135+
136+
public virtual void ClearContexts()
137+
{
138+
_contexts.Clear();
139+
}
140+
141+
protected void SaveContext(ParserRuleContext context)
142+
{
143+
var module = CurrentModuleName;
144+
var qualifiedContext = new QualifiedContext<ParserRuleContext>(module, context);
145+
if (_contexts.TryGetValue(module, out var contexts))
146+
{
147+
contexts.Add(qualifiedContext);
148+
}
149+
else
150+
{
151+
_contexts.Add(module, new List<QualifiedContext<ParserRuleContext>>{qualifiedContext});
152+
}
153+
}
154+
}
15155
}

Rubberduck.CodeAnalysis/Inspections/Concrete/BooleanAssignedInIfElseInspection.cs

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
1-
using System.Collections.Generic;
2-
using System.Linq;
1+
using System.Linq;
32
using Antlr4.Runtime;
43
using Rubberduck.Inspections.Abstract;
5-
using Rubberduck.Inspections.Results;
64
using Rubberduck.Parsing;
75
using Rubberduck.Parsing.Grammar;
86
using Rubberduck.Parsing.Inspections.Abstract;
97
using Rubberduck.Resources.Inspections;
108
using Rubberduck.Parsing.VBA;
11-
using Rubberduck.VBEditor;
129

1310
namespace Rubberduck.Inspections.Concrete
1411
{
@@ -48,27 +45,21 @@ public BooleanAssignedInIfElseInspection(RubberduckParserState state)
4845
public override IInspectionListener Listener { get; } =
4946
new BooleanAssignedInIfElseListener();
5047

51-
protected override IEnumerable<IInspectionResult> DoGetInspectionResults()
48+
protected override string ResultDescription(QualifiedContext<ParserRuleContext> context)
5249
{
53-
return Listener.Contexts
54-
.Select(result => new QualifiedContextInspectionResult(this,
55-
string.Format(InspectionResults.BooleanAssignedInIfElseInspection,
56-
(((VBAParser.IfStmtContext)result.Context).block().GetDescendent<VBAParser.LetStmtContext>()).lExpression().GetText().Trim()),
57-
result));
50+
var literalText = ((VBAParser.IfStmtContext) context.Context)
51+
.block()
52+
.GetDescendent<VBAParser.LetStmtContext>()
53+
.lExpression()
54+
.GetText()
55+
.Trim();
56+
return string.Format(
57+
InspectionResults.BooleanAssignedInIfElseInspection,
58+
literalText);
5859
}
5960

60-
public class BooleanAssignedInIfElseListener : VBAParserBaseListener, IInspectionListener
61+
public class BooleanAssignedInIfElseListener : InspectionListenerBase
6162
{
62-
private readonly List<QualifiedContext<ParserRuleContext>> _contexts = new List<QualifiedContext<ParserRuleContext>>();
63-
public IReadOnlyList<QualifiedContext<ParserRuleContext>> Contexts => _contexts;
64-
65-
public QualifiedModuleName CurrentModuleName { get; set; }
66-
67-
public void ClearContexts()
68-
{
69-
_contexts.Clear();
70-
}
71-
7263
public override void ExitIfStmt(VBAParser.IfStmtContext context)
7364
{
7465
if (context.elseIfBlock() != null && context.elseIfBlock().Any())
@@ -101,10 +92,10 @@ public override void ExitIfStmt(VBAParser.IfStmtContext context)
10192
return;
10293
}
10394

104-
_contexts.Add(new QualifiedContext<ParserRuleContext>(CurrentModuleName, context));
95+
SaveContext(context);
10596
}
10697

107-
private bool IsSingleBooleanAssignment(VBAParser.BlockContext block)
98+
private static bool IsSingleBooleanAssignment(VBAParser.BlockContext block)
10899
{
109100
if (block.ChildCount != 2)
110101
{

Rubberduck.CodeAnalysis/Inspections/Concrete/DefTypeStatementInspection.cs

Lines changed: 15 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
11
using System.Collections.Generic;
2-
using System.Linq;
32
using Rubberduck.Inspections.Abstract;
43
using Rubberduck.Parsing.VBA;
54
using Rubberduck.Resources.Inspections;
65
using Rubberduck.Parsing.Inspections.Abstract;
76
using Rubberduck.Parsing.Grammar;
87
using Antlr4.Runtime;
98
using Rubberduck.Parsing;
10-
using Rubberduck.VBEditor;
119
using Antlr4.Runtime.Misc;
12-
using Rubberduck.Inspections.Results;
13-
using Rubberduck.Inspections.Inspections.Extensions;
1410

1511
namespace Rubberduck.Inspections.Concrete
1612
{
@@ -40,34 +36,15 @@ public DefTypeStatementInspection(RubberduckParserState state)
4036
}
4137

4238
public override IInspectionListener Listener { get; }
43-
44-
protected override IEnumerable<IInspectionResult> DoGetInspectionResults()
39+
protected override string ResultDescription(QualifiedContext<ParserRuleContext> context)
4540
{
46-
var results = Listener.Contexts
47-
.Select(context => new QualifiedContextInspectionResult(this,
48-
string.Format(InspectionResults.DefTypeStatementInspection,
49-
GetTypeOfDefType(context.Context.start.Text),
50-
context.Context.start.Text),
51-
context));
52-
return results;
53-
}
54-
55-
public class DefTypeStatementInspectionListener : VBAParserBaseListener, IInspectionListener
56-
{
57-
private readonly List<QualifiedContext<ParserRuleContext>> _contexts = new List<QualifiedContext<ParserRuleContext>>();
58-
public IReadOnlyList<QualifiedContext<ParserRuleContext>> Contexts => _contexts;
59-
60-
public QualifiedModuleName CurrentModuleName { get; set; }
41+
var typeName = GetTypeOfDefType(context.Context.start.Text);
42+
var defStmtText = context.Context.start.Text;
6143

62-
public void ClearContexts()
63-
{
64-
_contexts.Clear();
65-
}
66-
67-
public override void ExitDefType([NotNull] VBAParser.DefTypeContext context)
68-
{
69-
_contexts.Add(new QualifiedContext<ParserRuleContext>(CurrentModuleName, context));
70-
}
44+
return string.Format(
45+
InspectionResults.DefTypeStatementInspection,
46+
typeName,
47+
defStmtText);
7148
}
7249

7350
private string GetTypeOfDefType(string defType)
@@ -90,5 +67,13 @@ private string GetTypeOfDefType(string defType)
9067
{ "DefObj", "Object" },
9168
{ "DefVar", "Variant" }
9269
};
70+
71+
public class DefTypeStatementInspectionListener : InspectionListenerBase
72+
{
73+
public override void ExitDefType([NotNull] VBAParser.DefTypeContext context)
74+
{
75+
SaveContext(context);
76+
}
77+
}
9378
}
9479
}

Rubberduck.CodeAnalysis/Inspections/Concrete/EmptyBlockInspectionListenerBase.cs

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,22 @@
11
using Antlr4.Runtime;
2-
using Rubberduck.Parsing;
32
using Rubberduck.Parsing.Grammar;
4-
using Rubberduck.Parsing.Inspections.Abstract;
5-
using Rubberduck.VBEditor;
63
using System.Collections.Generic;
74
using System.Diagnostics;
85
using Antlr4.Runtime.Tree;
6+
using Rubberduck.Inspections.Abstract;
97

108
namespace Rubberduck.Inspections.Concrete
119
{
12-
public class EmptyBlockInspectionListenerBase : VBAParserBaseListener, IInspectionListener
10+
public class EmptyBlockInspectionListenerBase : InspectionListenerBase
1311
{
14-
private readonly List<QualifiedContext<ParserRuleContext>> _contexts = new List<QualifiedContext<ParserRuleContext>>();
15-
public IReadOnlyList<QualifiedContext<ParserRuleContext>> Contexts => _contexts;
16-
17-
public QualifiedModuleName CurrentModuleName { get; set; }
18-
19-
public void ClearContexts()
20-
{
21-
_contexts.Clear();
22-
}
23-
2412
public void InspectBlockForExecutableStatements<T>(VBAParser.BlockContext block, T context) where T : ParserRuleContext
2513
{
2614
if (!BlockContainsExecutableStatements(block))
2715
{
28-
AddResult(new QualifiedContext<ParserRuleContext>(CurrentModuleName, context));
16+
SaveContext(context);
2917
}
3018
}
3119

32-
public void AddResult(QualifiedContext<ParserRuleContext> qualifiedContext)
33-
{
34-
_contexts.Add(qualifiedContext);
35-
}
36-
3720
private bool BlockContainsExecutableStatements(VBAParser.BlockContext block)
3821
{
3922
return block?.children != null && ContainsExecutableStatements(block.children);
@@ -82,7 +65,7 @@ public void InspectBlockForExecutableStatements<T>(VBAParser.UnterminatedBlockCo
8265
{
8366
if (!BlockContainsExecutableStatements(block))
8467
{
85-
AddResult(new QualifiedContext<ParserRuleContext>(CurrentModuleName, context));
68+
SaveContext(context);
8669
}
8770
}
8871

Rubberduck.CodeAnalysis/Inspections/Concrete/EmptyCaseBlockInspection.cs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
using Antlr4.Runtime.Misc;
22
using Rubberduck.Inspections.Abstract;
3-
using Rubberduck.Inspections.Results;
43
using Rubberduck.Parsing.Grammar;
54
using Rubberduck.Parsing.Common;
65
using Rubberduck.Parsing.Inspections.Abstract;
76
using Rubberduck.Resources.Inspections;
87
using Rubberduck.Parsing.VBA;
9-
using System.Collections.Generic;
10-
using System.Linq;
8+
using Antlr4.Runtime;
119
using Rubberduck.Resources.Experimentals;
12-
using Rubberduck.Inspections.Inspections.Extensions;
10+
using Rubberduck.Parsing;
1311

1412
namespace Rubberduck.Inspections.Concrete
1513
{
@@ -46,17 +44,15 @@ namespace Rubberduck.Inspections.Concrete
4644
internal class EmptyCaseBlockInspection : ParseTreeInspectionBase
4745
{
4846
public EmptyCaseBlockInspection(RubberduckParserState state)
49-
: base(state) { }
47+
: base(state)
48+
{}
5049

5150
public override IInspectionListener Listener { get; } =
5251
new EmptyCaseBlockListener();
5352

54-
protected override IEnumerable<IInspectionResult> DoGetInspectionResults()
53+
protected override string ResultDescription(QualifiedContext<ParserRuleContext> context)
5554
{
56-
return Listener.Contexts
57-
.Select(result => new QualifiedContextInspectionResult(this,
58-
InspectionResults.EmptyCaseBlockInspection,
59-
result));
55+
return InspectionResults.EmptyCaseBlockInspection;
6056
}
6157

6258
public class EmptyCaseBlockListener : EmptyBlockInspectionListenerBase

0 commit comments

Comments
 (0)