/
BooleanAssignedInIfElseInspection.cs
120 lines (104 loc) · 4.61 KB
/
BooleanAssignedInIfElseInspection.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
using System.Collections.Generic;
using System.Linq;
using Antlr4.Runtime;
using Rubberduck.Inspections.Abstract;
using Rubberduck.Inspections.Results;
using Rubberduck.Parsing;
using Rubberduck.Parsing.Grammar;
using Rubberduck.Parsing.Inspections.Abstract;
using Rubberduck.Resources.Inspections;
using Rubberduck.Parsing.VBA;
using Rubberduck.VBEditor;
using Rubberduck.Inspections.Inspections.Extensions;
namespace Rubberduck.Inspections.Concrete
{
/// <summary>
/// Identifies redundant Boolean expressions in conditionals.
/// </summary>
/// <why>
/// A Boolean expression never needs to be compared to a Boolean literal in a conditional expression.
/// </why>
/// <example>
/// <![CDATA[
/// Public Sub DoSomething(ByVal foo As Boolean)
/// If foo = True Then ' foo is known to already be a Boolean value.
/// ' ...
/// End If
/// End Sub
/// ]]>
/// </example>
/// <example>
/// <![CDATA[
/// Public Sub DoSomething(ByVal foo As Boolean)
/// If foo Then
/// ' ...
/// End If
/// End Sub
/// ]]>
/// </example>
public sealed class BooleanAssignedInIfElseInspection : ParseTreeInspectionBase
{
public BooleanAssignedInIfElseInspection(RubberduckParserState state)
: base(state) { }
public override IInspectionListener Listener { get; } =
new BooleanAssignedInIfElseListener();
protected override IEnumerable<IInspectionResult> DoGetInspectionResults()
{
return Listener.Contexts
.Where(result => !result.IsIgnoringInspectionResultFor(State.DeclarationFinder, AnnotationName))
.Select(result => new QualifiedContextInspectionResult(this,
string.Format(InspectionResults.BooleanAssignedInIfElseInspection,
(((VBAParser.IfStmtContext)result.Context).block().GetDescendent<VBAParser.LetStmtContext>()).lExpression().GetText().Trim()),
result));
}
public class BooleanAssignedInIfElseListener : VBAParserBaseListener, IInspectionListener
{
private readonly List<QualifiedContext<ParserRuleContext>> _contexts = new List<QualifiedContext<ParserRuleContext>>();
public IReadOnlyList<QualifiedContext<ParserRuleContext>> Contexts => _contexts;
public QualifiedModuleName CurrentModuleName { get; set; }
public void ClearContexts()
{
_contexts.Clear();
}
public override void ExitIfStmt(VBAParser.IfStmtContext context)
{
if (context.elseIfBlock() != null && context.elseIfBlock().Any())
{
return;
}
if (context.elseBlock() == null)
{
return;
}
if (!IsSingleBooleanAssignment(context.block()) ||
!IsSingleBooleanAssignment(context.elseBlock().block()))
{
return;
}
// make sure the assignments are the opposite
if (!(context.block().GetDescendent<VBAParser.BooleanLiteralIdentifierContext>().GetText() == Tokens.True ^
context.elseBlock().block().GetDescendent<VBAParser.BooleanLiteralIdentifierContext>().GetText() == Tokens.True))
{
return;
}
if (context.block().GetDescendent<VBAParser.LetStmtContext>().lExpression().GetText().ToLowerInvariant() !=
context.elseBlock().block().GetDescendent<VBAParser.LetStmtContext>().lExpression().GetText().ToLowerInvariant())
{
return;
}
_contexts.Add(new QualifiedContext<ParserRuleContext>(CurrentModuleName, context));
}
private bool IsSingleBooleanAssignment(VBAParser.BlockContext block)
{
if (block.ChildCount != 2)
{
return false;
}
var mainBlockStmtContext = block.GetDescendent<VBAParser.MainBlockStmtContext>();
return mainBlockStmtContext.children.FirstOrDefault() is VBAParser.LetStmtContext letStmt &&
letStmt.expression() is VBAParser.LiteralExprContext literal &&
literal.GetDescendent<VBAParser.BooleanLiteralIdentifierContext>() != null;
}
}
}
}