Skip to content

Commit cd64320

Browse files
authored
Merge branch 'next' into PortToCastleWindsor
2 parents 9fe4712 + 6759c49 commit cd64320

23 files changed

+747
-57
lines changed
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using Antlr4.Runtime;
5+
using Rubberduck.Inspections.Abstract;
6+
using Rubberduck.Inspections.Results;
7+
using Rubberduck.Parsing;
8+
using Rubberduck.Parsing.Grammar;
9+
using Rubberduck.Parsing.Inspections.Abstract;
10+
using Rubberduck.Parsing.Inspections.Resources;
11+
using Rubberduck.Parsing.Symbols;
12+
using Rubberduck.Parsing.VBA;
13+
using Rubberduck.VBEditor;
14+
15+
namespace Rubberduck.Inspections.Concrete
16+
{
17+
public sealed class BooleanAssignedInIfElseInspection : ParseTreeInspectionBase
18+
{
19+
public BooleanAssignedInIfElseInspection(RubberduckParserState state)
20+
: base(state) { }
21+
22+
public override CodeInspectionType InspectionType => CodeInspectionType.MaintainabilityAndReadabilityIssues;
23+
24+
public override IInspectionListener Listener { get; } =
25+
new BooleanAssignedInIfElseListener();
26+
27+
protected override IEnumerable<IInspectionResult> DoGetInspectionResults()
28+
{
29+
return Listener.Contexts
30+
.Where(result => !IsIgnoringInspectionResultFor(result.ModuleName, result.Context.Start.Line))
31+
.Select(result => new QualifiedContextInspectionResult(this,
32+
string.Format(InspectionsUI.BooleanAssignedInIfElseInspectionResultFormat,
33+
ParserRuleContextHelper.GetDescendent<VBAParser.LetStmtContext>(((VBAParser.IfStmtContext)result.Context).block()).lExpression().GetText().Trim()),
34+
result));
35+
}
36+
37+
public class BooleanAssignedInIfElseListener : VBAParserBaseListener, IInspectionListener
38+
{
39+
private readonly List<QualifiedContext<ParserRuleContext>> _contexts = new List<QualifiedContext<ParserRuleContext>>();
40+
public IReadOnlyList<QualifiedContext<ParserRuleContext>> Contexts => _contexts;
41+
42+
public QualifiedModuleName CurrentModuleName { get; set; }
43+
44+
public void ClearContexts()
45+
{
46+
_contexts.Clear();
47+
}
48+
49+
public override void ExitIfStmt(VBAParser.IfStmtContext context)
50+
{
51+
if (context.elseIfBlock().Any())
52+
{
53+
return;
54+
}
55+
56+
if (!IsSingleBooleanAssignment(context.block()) ||
57+
!IsSingleBooleanAssignment(context.elseBlock().block()))
58+
{
59+
return;
60+
}
61+
62+
// make sure the assignments are the opposite
63+
if (!(ParserRuleContextHelper.GetDescendent<VBAParser.BooleanLiteralIdentifierContext>(context.block()).GetText() == Tokens.True ^
64+
ParserRuleContextHelper.GetDescendent<VBAParser.BooleanLiteralIdentifierContext>(context.elseBlock().block()).GetText() == Tokens.True))
65+
{
66+
return;
67+
}
68+
69+
if (ParserRuleContextHelper.GetDescendent<VBAParser.LetStmtContext>(context.block()).lExpression().GetText().ToLowerInvariant() !=
70+
ParserRuleContextHelper.GetDescendent<VBAParser.LetStmtContext>(context.elseBlock().block()).lExpression().GetText().ToLowerInvariant())
71+
{
72+
return;
73+
}
74+
75+
_contexts.Add(new QualifiedContext<ParserRuleContext>(CurrentModuleName, context));
76+
}
77+
78+
private bool IsSingleBooleanAssignment(VBAParser.BlockContext block)
79+
{
80+
if (block.ChildCount != 2)
81+
{
82+
return false;
83+
}
84+
85+
var mainBlockStmtContext =
86+
ParserRuleContextHelper.GetDescendent<VBAParser.MainBlockStmtContext>(block);
87+
88+
return mainBlockStmtContext.children.FirstOrDefault() is VBAParser.LetStmtContext letStmt &&
89+
letStmt.expression() is VBAParser.LiteralExprContext literal &&
90+
ParserRuleContextHelper.GetDescendent<VBAParser.BooleanLiteralIdentifierContext>(literal) != null;
91+
}
92+
}
93+
}
94+
}

Rubberduck.Inspections/Concrete/EmptyCaseBlockInspection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public EmptyCaseBlockInspection(RubberduckParserState state)
1919
public override IInspectionListener Listener { get; } =
2020
new EmptyCaseBlockListener();
2121

22-
public override CodeInspectionType InspectionType => CodeInspectionType.CodeQualityIssues;
22+
public override CodeInspectionType InspectionType => CodeInspectionType.MaintainabilityAndReadabilityIssues;
2323

2424
protected override IEnumerable<IInspectionResult> DoGetInspectionResults()
2525
{

Rubberduck.Inspections/Concrete/EmptyDoWhileBlockInspection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ internal class EmptyDoWhileBlockInspection : ParseTreeInspectionBase
1616
public EmptyDoWhileBlockInspection(RubberduckParserState state)
1717
: base(state, CodeInspectionSeverity.Suggestion) { }
1818

19-
public override CodeInspectionType InspectionType => CodeInspectionType.CodeQualityIssues;
19+
public override CodeInspectionType InspectionType => CodeInspectionType.MaintainabilityAndReadabilityIssues;
2020

2121
protected override IEnumerable<IInspectionResult> DoGetInspectionResults()
2222
{

Rubberduck.Inspections/Concrete/EmptyElseBlockInspection.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ internal class EmptyElseBlockInspection : ParseTreeInspectionBase
1616
public EmptyElseBlockInspection(RubberduckParserState state)
1717
: base(state, CodeInspectionSeverity.DoNotShow) { }
1818

19-
public override CodeInspectionType InspectionType => CodeInspectionType.CodeQualityIssues;
19+
public override CodeInspectionType InspectionType => CodeInspectionType.MaintainabilityAndReadabilityIssues;
2020

2121
protected override IEnumerable<IInspectionResult> DoGetInspectionResults()
2222
{
@@ -38,4 +38,4 @@ public override void EnterElseBlock([NotNull] VBAParser.ElseBlockContext context
3838
}
3939
}
4040
}
41-
}
41+
}

Rubberduck.Inspections/Concrete/EmptyForEachBlockInspection.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ internal class EmptyForEachBlockInspection : ParseTreeInspectionBase
1616
public EmptyForEachBlockInspection(RubberduckParserState state)
1717
: base(state, CodeInspectionSeverity.DoNotShow) { }
1818

19-
public override CodeInspectionType InspectionType => CodeInspectionType.CodeQualityIssues;
19+
public override CodeInspectionType InspectionType => CodeInspectionType.MaintainabilityAndReadabilityIssues;
2020

2121
protected override IEnumerable<IInspectionResult> DoGetInspectionResults()
2222
{
@@ -38,4 +38,4 @@ public override void EnterForEachStmt([NotNull] VBAParser.ForEachStmtContext con
3838
}
3939
}
4040
}
41-
}
41+
}

Rubberduck.Inspections/Concrete/EmptyForLoopBlockInspection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ internal class EmptyForLoopBlockInspection : ParseTreeInspectionBase
1616
public EmptyForLoopBlockInspection(RubberduckParserState state)
1717
: base(state, CodeInspectionSeverity.DoNotShow) { }
1818

19-
public override CodeInspectionType InspectionType => CodeInspectionType.CodeQualityIssues;
19+
public override CodeInspectionType InspectionType => CodeInspectionType.MaintainabilityAndReadabilityIssues;
2020

2121
protected override IEnumerable<IInspectionResult> DoGetInspectionResults()
2222
{

Rubberduck.Inspections/Concrete/EmptyIfBlockInspection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ internal class EmptyIfBlockInspection : ParseTreeInspectionBase
1818
public EmptyIfBlockInspection(RubberduckParserState state)
1919
: base(state, CodeInspectionSeverity.DoNotShow) { }
2020

21-
public override CodeInspectionType InspectionType => CodeInspectionType.CodeQualityIssues;
21+
public override CodeInspectionType InspectionType => CodeInspectionType.MaintainabilityAndReadabilityIssues;
2222

2323
protected override IEnumerable<IInspectionResult> DoGetInspectionResults()
2424
{

Rubberduck.Inspections/Concrete/EmptyWhileWendBlockInspection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ internal class EmptyWhileWendBlockInspection : ParseTreeInspectionBase
1616
public EmptyWhileWendBlockInspection(RubberduckParserState state)
1717
: base(state, CodeInspectionSeverity.DoNotShow) { }
1818

19-
public override CodeInspectionType InspectionType => CodeInspectionType.CodeQualityIssues;
19+
public override CodeInspectionType InspectionType => CodeInspectionType.MaintainabilityAndReadabilityIssues;
2020

2121
protected override IEnumerable<IInspectionResult> DoGetInspectionResults()
2222
{
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
using Rubberduck.Inspections.Abstract;
2+
using Rubberduck.Inspections.Concrete;
3+
using Rubberduck.Parsing.Grammar;
4+
using Rubberduck.Parsing.Inspections.Abstract;
5+
using Rubberduck.Parsing.Inspections.Resources;
6+
using Rubberduck.Parsing.Symbols;
7+
using Rubberduck.Parsing.VBA;
8+
9+
namespace Rubberduck.Inspections.QuickFixes
10+
{
11+
public sealed class ReplaceIfElseWithConditionalStatementQuickFix : QuickFixBase
12+
{
13+
private readonly RubberduckParserState _state;
14+
15+
public ReplaceIfElseWithConditionalStatementQuickFix(RubberduckParserState state)
16+
: base(typeof(BooleanAssignedInIfElseInspection))
17+
{
18+
_state = state;
19+
}
20+
21+
public override void Fix(IInspectionResult result)
22+
{
23+
var ifContext = (VBAParser.IfStmtContext) result.Context;
24+
var letStmt = ParserRuleContextHelper.GetDescendent<VBAParser.LetStmtContext>(ifContext.block());
25+
26+
var conditional = ifContext.booleanExpression().GetText();
27+
28+
if (letStmt.expression().GetText() == Tokens.False)
29+
{
30+
conditional = $"Not ({conditional})";
31+
}
32+
33+
var rewriter = _state.GetRewriter(result.QualifiedSelection.QualifiedName);
34+
rewriter.Replace(result.Context, $"{letStmt.lExpression().GetText()} = {conditional}");
35+
}
36+
37+
public override string Description(IInspectionResult result)
38+
{
39+
return InspectionsUI.ReplaceIfElseWithConditionalStatementQuickFix;
40+
}
41+
42+
public override bool CanFixInProcedure { get; } = true;
43+
public override bool CanFixInModule { get; } = true;
44+
public override bool CanFixInProject { get; } = true;
45+
}
46+
}

Rubberduck.Inspections/Rubberduck.Inspections.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
<Compile Include="Concrete\EmptyDoWhileBlockInspection.cs" />
6868
<Compile Include="Concrete\EmptyForEachBlockInspection.cs" />
6969
<Compile Include="Concrete\EmptyForLoopBlockInspection.cs" />
70+
<Compile Include="Concrete\BooleanAssignedInIfElseInspection.cs" />
7071
<Compile Include="Concrete\EmptyWhileWendBlockInspection.cs" />
7172
<Compile Include="Concrete\ObsoleteErrorSyntaxInspection.cs" />
7273
<Compile Include="Concrete\StopKeywordInspection.cs" />
@@ -116,6 +117,7 @@
116117
<Compile Include="Concrete\ProcedureCanBeWrittenAsFunctionInspection.cs" />
117118
<Compile Include="Concrete\ProcedureNotUsedInspection.cs" />
118119
<Compile Include="Properties\AssemblyInfo.cs" />
120+
<Compile Include="QuickFixes\ReplaceIfElseWithConditionalStatementQuickFix.cs" />
119121
<Compile Include="QuickFixes\AddIdentifierToWhiteListQuickFix.cs" />
120122
<Compile Include="QuickFixes\ApplicationWorksheetFunctionQuickFix.cs" />
121123
<Compile Include="QuickFixes\AssignedByValParameterMakeLocalCopyQuickFix.cs" />

0 commit comments

Comments
 (0)