Skip to content

Commit 25e534c

Browse files
committed
Adding Step not specified inspection and tests
1 parent 734d986 commit 25e534c

File tree

8 files changed

+299
-0
lines changed

8 files changed

+299
-0
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
using Rubberduck.Inspections.Abstract;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using Rubberduck.Parsing.Inspections.Abstract;
6+
using Rubberduck.Parsing.Inspections.Resources;
7+
using Rubberduck.Parsing.VBA;
8+
using Rubberduck.Parsing.Grammar;
9+
using Antlr4.Runtime.Misc;
10+
using Antlr4.Runtime;
11+
using Rubberduck.Parsing;
12+
using Rubberduck.VBEditor;
13+
using Rubberduck.Inspections.Results;
14+
using static Rubberduck.Parsing.Grammar.VBAParser;
15+
16+
namespace Rubberduck.Inspections.Concrete
17+
{
18+
public sealed class StepIsNotSpecifiedInspection : ParseTreeInspectionBase
19+
{
20+
public StepIsNotSpecifiedInspection(RubberduckParserState state) : base(state, CodeInspectionSeverity.Warning) { }
21+
22+
public override Type Type => typeof(StepIsNotSpecifiedInspection);
23+
24+
public override CodeInspectionType InspectionType => CodeInspectionType.LanguageOpportunities;
25+
26+
public override IEnumerable<IInspectionResult> GetInspectionResults()
27+
{
28+
return Listener.Contexts
29+
.Where(result => !IsIgnoringInspectionResultFor(result.ModuleName, result.Context.Start.Line))
30+
.Select(result => new QualifiedContextInspectionResult(this,
31+
InspectionsUI.StepIsNotSpecifiedInspectionResultFormat,
32+
result));
33+
}
34+
35+
public override IInspectionListener Listener { get; } =
36+
new StepIsNotSpecifiedListener();
37+
}
38+
39+
public class StepIsNotSpecifiedListener : VBAParserBaseListener, IInspectionListener
40+
{
41+
private readonly List<QualifiedContext<ParserRuleContext>> _contexts = new List<QualifiedContext<ParserRuleContext>>();
42+
public IReadOnlyList<QualifiedContext<ParserRuleContext>> Contexts => _contexts;
43+
44+
public QualifiedModuleName CurrentModuleName
45+
{
46+
get;
47+
set;
48+
}
49+
50+
public void ClearContexts()
51+
{
52+
_contexts.Clear();
53+
}
54+
55+
public override void EnterForNextStmt([NotNull] VBAParser.ForNextStmtContext context)
56+
{
57+
StepStmtContext stepStatement = context.stepStmt();
58+
59+
if (stepStatement == null)
60+
{
61+
_contexts.Add(new QualifiedContext<ParserRuleContext>(CurrentModuleName, context));
62+
}
63+
}
64+
}
65+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
using Antlr4.Runtime;
2+
using Antlr4.Runtime.Tree;
3+
using Rubberduck.Inspections.Abstract;
4+
using Rubberduck.Inspections.Concrete;
5+
using Rubberduck.Parsing.Inspections.Abstract;
6+
using Rubberduck.Parsing.Inspections.Resources;
7+
using Rubberduck.Parsing.Rewriter;
8+
using Rubberduck.Parsing.VBA;
9+
using System;
10+
using System.Collections.Generic;
11+
using System.Linq;
12+
using System.Text;
13+
using System.Threading.Tasks;
14+
using static Rubberduck.Parsing.Grammar.VBAParser;
15+
16+
namespace Rubberduck.Inspections.QuickFixes
17+
{
18+
public class AddStepOneQuickFix : QuickFixBase
19+
{
20+
private readonly RubberduckParserState _state;
21+
22+
public AddStepOneQuickFix(RubberduckParserState state)
23+
: base(typeof(StepIsNotSpecifiedInspection))
24+
{
25+
_state = state;
26+
}
27+
28+
public override bool CanFixInProcedure => false;
29+
30+
public override bool CanFixInModule => false;
31+
32+
public override bool CanFixInProject => false;
33+
34+
public override string Description(IInspectionResult result)
35+
{
36+
return InspectionsUI.AddStepOneQuickFix;
37+
}
38+
39+
public override void Fix(IInspectionResult result)
40+
{
41+
IModuleRewriter rewriter = _state.GetRewriter(result.QualifiedSelection.QualifiedName);
42+
ForNextStmtContext context = result.Context as ForNextStmtContext;
43+
44+
int toExpressionEnd = this.GetToExpressionEnd(context);
45+
rewriter.InsertAfter(toExpressionEnd, " Step 1");
46+
}
47+
48+
private int GetToExpressionEnd(ForNextStmtContext context)
49+
{
50+
int toNodeIndex = context.TO().Symbol.TokenIndex;
51+
52+
foreach(ExpressionContext expressionChild in context.expression())
53+
{
54+
if (expressionChild.Stop.TokenIndex > toNodeIndex)
55+
{
56+
return expressionChild.Stop.TokenIndex;
57+
}
58+
}
59+
60+
throw new InvalidOperationException();
61+
}
62+
}
63+
}

Rubberduck.Inspections/Rubberduck.Inspections.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
<Compile Include="Concrete\EmptyForEachBlockInspection.cs" />
6969
<Compile Include="Concrete\EmptyForLoopBlockInspection.cs" />
7070
<Compile Include="Concrete\EmptyWhileWendBlockInspection.cs" />
71+
<Compile Include="Concrete\StepIsNotSpecifiedInspection.cs" />
7172
<Compile Include="Concrete\StepOneIsRedundantInspection.cs" />
7273
<Compile Include="Concrete\StopKeywordInspection.cs" />
7374
<Compile Include="Concrete\LineLabelNotUsedInspection.cs" />
@@ -117,6 +118,7 @@
117118
<Compile Include="Concrete\ProcedureNotUsedInspection.cs" />
118119
<Compile Include="Properties\AssemblyInfo.cs" />
119120
<Compile Include="QuickFixes\AddIdentifierToWhiteListQuickFix.cs" />
121+
<Compile Include="QuickFixes\AddStepOneQuickFix.cs" />
120122
<Compile Include="QuickFixes\ApplicationWorksheetFunctionQuickFix.cs" />
121123
<Compile Include="QuickFixes\AssignedByValParameterMakeLocalCopyQuickFix.cs" />
122124
<Compile Include="QuickFixes\ChangeDimToPrivateQuickFix.cs" />

Rubberduck.Parsing/Inspections/Resources/InspectionsUI.resx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -863,4 +863,10 @@ If the parameter can be null, ignore this inspection result; passing a null valu
863863
<data name="RemoveStepOneQuickFix" xml:space="preserve">
864864
<value>Remove step</value>
865865
</data>
866+
<data name="StepIsNotSpecifiedInspectionResultFormat" xml:space="preserve">
867+
<value>Step not specified</value>
868+
</data>
869+
<data name="AddStepOneQuickFix" xml:space="preserve">
870+
<value>Add step</value>
871+
</data>
866872
</root>

Rubberduck.Parsing/Inspections/Resources/InspectionsUI1.Designer.cs

Lines changed: 18 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
using Microsoft.VisualStudio.TestTools.UnitTesting;
2+
using Rubberduck.Inspections.Concrete;
3+
using RubberduckTests.Mocks;
4+
using System.Linq;
5+
using System.Threading;
6+
7+
namespace RubberduckTests.Inspections
8+
{
9+
[TestClass]
10+
public class StepNotSpecifiedInspectionTests
11+
{
12+
[TestMethod]
13+
[TestCategory("Inspections")]
14+
public void StepNotSpecified_ReturnsResult()
15+
{
16+
string inputCode =
17+
@"Sub Foo()
18+
For value = 0 To 5
19+
Next
20+
End Sub";
21+
22+
this.TestStepNotSpecifiedInspection(inputCode, 1);
23+
}
24+
25+
[TestMethod]
26+
[TestCategory("Inspections")]
27+
public void StepNotSpecified_NestedLoopsAreDetected()
28+
{
29+
string inputCode =
30+
@"Sub Foo()
31+
For value = 0 To 5
32+
For value = 0 To 5
33+
Next
34+
Next
35+
End Sub";
36+
37+
this.TestStepNotSpecifiedInspection(inputCode, 2);
38+
}
39+
40+
private void TestStepNotSpecifiedInspection(string inputCode, int expectedResultCount)
41+
{
42+
var vbe = MockVbeBuilder.BuildFromSingleStandardModule(inputCode, out _);
43+
var state = MockParser.CreateAndParse(vbe.Object);
44+
45+
var inspection = new StepIsNotSpecifiedInspection(state);
46+
var inspector = InspectionsHelper.GetInspector(inspection);
47+
var inspectionResults = inspector.FindIssuesAsync(state, CancellationToken.None).Result;
48+
49+
Assert.AreEqual(expectedResultCount, inspectionResults.Count());
50+
}
51+
}
52+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
using Microsoft.VisualStudio.TestTools.UnitTesting;
2+
using Rubberduck.Inspections.Concrete;
3+
using Rubberduck.Inspections.QuickFixes;
4+
using RubberduckTests.Inspections;
5+
using RubberduckTests.Mocks;
6+
using System.Threading;
7+
8+
namespace RubberduckTests.QuickFixes
9+
{
10+
[TestClass]
11+
public class AddStepOneQuickFixTests
12+
{
13+
[TestMethod]
14+
[TestCategory("QuickFixes")]
15+
public void AddStepOne_QuickFixWorks_Remove()
16+
{
17+
var inputCode =
18+
@"Sub Foo()
19+
For value = 0 To 5
20+
Next
21+
End Sub";
22+
23+
var expectedCode =
24+
@"Sub Foo()
25+
For value = 0 To 5 Step 1
26+
Next
27+
End Sub";
28+
29+
this.TestAddStepOneQuickFix(expectedCode, inputCode);
30+
}
31+
32+
[TestMethod]
33+
[TestCategory("QuickFixes")]
34+
public void AddStepOne_QuickFixWorks_NestedLoops()
35+
{
36+
var inputCode =
37+
@"Sub Foo()
38+
For value = 0 To 5
39+
For value = 0 To 5
40+
Next
41+
Next
42+
End Sub";
43+
44+
var expectedCode =
45+
@"Sub Foo()
46+
For value = 0 To 5 Step 1
47+
For value = 0 To 5 Step 1
48+
Next
49+
Next
50+
End Sub";
51+
52+
this.TestAddStepOneQuickFix(expectedCode, inputCode);
53+
}
54+
55+
[TestMethod]
56+
[TestCategory("QuickFixes")]
57+
public void AddStepOne_QuickFixWorks_ComplexExpression()
58+
{
59+
var inputCode =
60+
@"Sub Foo()
61+
For value = 0 To 1 + 2
62+
Next
63+
End Sub";
64+
65+
var expectedCode =
66+
@"Sub Foo()
67+
For value = 0 To 1 + 2 Step 1
68+
Next
69+
End Sub";
70+
71+
this.TestAddStepOneQuickFix(expectedCode, inputCode);
72+
}
73+
74+
private void TestAddStepOneQuickFix(string expectedCode, string inputCode)
75+
{
76+
var vbe = MockVbeBuilder.BuildFromSingleStandardModule(inputCode, out var component);
77+
var state = MockParser.CreateAndParse(vbe.Object);
78+
79+
var inspection = new StepIsNotSpecifiedInspection(state);
80+
var inspector = InspectionsHelper.GetInspector(inspection);
81+
var inspectionResults = inspector.FindIssuesAsync(state, CancellationToken.None).Result;
82+
83+
foreach (var inspectionResult in inspectionResults)
84+
{
85+
new AddStepOneQuickFix(state).Fix(inspectionResult);
86+
}
87+
88+
Assert.AreEqual(expectedCode, state.GetRewriter(component).GetText());
89+
}
90+
}
91+
}

RubberduckTests/RubberduckTests.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@
117117
<Compile Include="Inspections\ImplicitActiveWorkbookReferenceInspectionTests.cs" />
118118
<Compile Include="Inspections\MemberNotOnInterfaceInspectionTests.cs" />
119119
<Compile Include="Inspections\ShadowedDeclarationInspectionTests.cs" />
120+
<Compile Include="Inspections\StepNotSpecifiedInspectionTests.cs" />
120121
<Compile Include="Inspections\StepOneIsRedundantInspectionTests.cs" />
121122
<Compile Include="Inspections\StopKeywordInspectionTests.cs" />
122123
<Compile Include="Inspections\OptionBaseZeroInspectionTests.cs" />
@@ -125,6 +126,7 @@
125126
<Compile Include="QuickFixes\DeclareAsExplicitVariantQuickFixTests.cs" />
126127
<Compile Include="QuickFixes\PassParameterByReferenceQuickFixTests.cs" />
127128
<Compile Include="QuickFixes\QuickFixProviderTests.cs" />
129+
<Compile Include="QuickFixes\AddStepOneQuickFixTests.cs" />
128130
<Compile Include="QuickFixes\RemoveStepOneQuickFixTests.cs" />
129131
<Compile Include="QuickFixes\RemoveUnassignedIdentifierQuickFixTests.cs" />
130132
<Compile Include="QuickFixes\RemoveUnassignedVariableUsageQuickFix.cs" />

0 commit comments

Comments
 (0)