Skip to content

Commit 40d777a

Browse files
authored
Merge pull request #2039 from Hosch250/reinstateParseTreeInspections
Reinstate parse tree inspections
2 parents 7a9192a + 21b4990 commit 40d777a

10 files changed

+182
-19
lines changed

RetailCoder.VBE/Inspections/InspectionsUI.Designer.cs

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

RetailCoder.VBE/Inspections/InspectionsUI.resx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -559,9 +559,9 @@
559559
<value>An annotation comment is malformed.</value>
560560
</data>
561561
<data name="MalformedAnnotationInspectionName" xml:space="preserve">
562-
<value>Malformed annotation.</value>
562+
<value>Malformed annotation</value>
563563
</data>
564564
<data name="MalformedAnnotationInspectionResultFormat" xml:space="preserve">
565-
<value>The annotation '{0}' is malformed</value>
565+
<value>Malformed '{0}' annotation.</value>
566566
</data>
567567
</root>

RetailCoder.VBE/Inspections/MalformedAnnotationInspection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public MalformedAnnotationInspectionResult(IInspection inspection, QualifiedCont
6868

6969
public override string Description
7070
{
71-
get { return string.Format(Inspection.Description, ((VBAParser.AnnotationContext)Context).annotationName()); }
71+
get { return string.Format(Inspection.Description, ((VBAParser.AnnotationContext)Context).annotationName().GetText()); }
7272
}
7373
}
7474
}

RetailCoder.VBE/Inspections/ParameterCanBeByValInspection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public override IEnumerable<InspectionResultBase> GetInspectionResults()
4949
&& ((VBAParser.ArgContext)declaration.Context).BYVAL() == null
5050
&& !IsUsedAsByRefParam(declarations, declaration)
5151
&& !declaration.References.Any(reference => reference.IsAssignment))
52-
.Select(issue => new ParameterCanBeByValInspectionResult(this, issue, ((dynamic)issue.Context).unrestrictedIdentifier(), issue.QualifiedName));
52+
.Select(issue => new ParameterCanBeByValInspectionResult(this, issue, issue.Context, issue.QualifiedName));
5353

5454
return issues;
5555
}

RetailCoder.VBE/Inspections/ParameterCanBeByValInspectionResult.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,13 @@ public PassParameterByValueQuickFix(ParserRuleContext context, QualifiedSelectio
3636

3737
public override void Fix()
3838
{
39-
var parameter = Context.Parent.GetText();
40-
var newContent = string.Concat(Tokens.ByVal, " ", parameter.Replace(Tokens.ByRef, string.Empty).Trim());
4139
var selection = Selection.Selection;
40+
var selectionLength = ((VBAParser.ArgContext) Context).BYREF() == null ? 0 : 6;
4241

4342
var module = Selection.QualifiedName.Component.CodeModule;
44-
var lines = module.Lines[selection.StartLine, selection.LineCount];
43+
var lines = module.Lines[selection.StartLine, 1];
4544

46-
var result = lines.Replace(parameter, newContent);
45+
var result = lines.Remove(selection.StartColumn - 1, selectionLength).Insert(selection.StartColumn - 1, Tokens.ByVal + ' ');
4746
module.ReplaceLine(selection.StartLine, result);
4847
}
4948
}

RetailCoder.VBE/Inspections/ProcedureShouldBeFunctionInspectionResult.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,12 @@ private void UpdateSignature()
7777

7878
var newArgText = argText.Contains("ByRef ") ? argText.Replace("ByRef ", "ByVal ") : "ByVal " + argText;
7979

80+
var asTypeClause = _argQualifiedContext.Context.asTypeClause() != null
81+
? _argQualifiedContext.Context.asTypeClause().GetText()
82+
: "As Variant";
83+
8084
var newFunctionWithoutReturn = subStmtText.Insert(subStmtText.IndexOf(argListText, StringComparison.Ordinal) + argListText.Length,
81-
" " + _argQualifiedContext.Context.asTypeClause().GetText())
85+
" " + asTypeClause)
8286
.Replace("Sub", "Function")
8387
.Replace(argText, newArgText);
8488

RetailCoder.VBE/Root/RubberduckModule.cs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -218,9 +218,25 @@ private void BindCodeInspectionTypes()
218218
// multibinding for IEnumerable<IInspection> dependency
219219
foreach (var inspection in inspections)
220220
{
221-
var binding = Bind<IInspection>().To(inspection).InSingletonScope();
222-
binding.Intercept().With<TimedCallLoggerInterceptor>();
223-
binding.Intercept().With<EnumerableCounterInterceptor<InspectionResultBase>>();
221+
if (typeof(IParseTreeInspection).IsAssignableFrom(inspection))
222+
{
223+
var binding = Bind<IParseTreeInspection>()
224+
.To(inspection)
225+
.InSingletonScope()
226+
.Named(inspection.FullName);
227+
228+
binding.Intercept().With<TimedCallLoggerInterceptor>();
229+
binding.Intercept().With<EnumerableCounterInterceptor<InspectionResultBase>>();
230+
231+
Bind<IInspection>().ToMethod(
232+
c => c.Kernel.Get<IParseTreeInspection>(inspection.FullName));
233+
}
234+
else
235+
{
236+
var binding = Bind<IInspection>().To(inspection).InSingletonScope();
237+
binding.Intercept().With<TimedCallLoggerInterceptor>();
238+
binding.Intercept().With<EnumerableCounterInterceptor<InspectionResultBase>>();
239+
}
224240
}
225241
}
226242

Rubberduck.Parsing/Symbols/Declaration.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,13 @@ public bool IsEnumeratorMember
308308

309309
public bool IsInspectionDisabled(string inspectionName)
310310
{
311+
if (DeclarationType == DeclarationType.Parameter)
312+
{
313+
return ParentDeclaration.Annotations.Any(annotation =>
314+
annotation.AnnotationType == AnnotationType.Ignore
315+
&& ((IgnoreAnnotation)annotation).IsIgnored(inspectionName));
316+
}
317+
311318
return Annotations.Any(annotation =>
312319
annotation.AnnotationType == AnnotationType.Ignore
313320
&& ((IgnoreAnnotation)annotation).IsIgnored(inspectionName));

RubberduckTests/Inspections/ParameterCanBeByValInspectionTests.cs

Lines changed: 102 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,63 @@ public void ParameterCanByByVal_ReturnsResult_SomeParams()
192192
Assert.AreEqual(1, inspectionResults.Count());
193193
}
194194

195+
[TestMethod]
196+
[TestCategory("Inspections")]
197+
public void GivenArrayParameter_ReturnsNoResult()
198+
{
199+
const string inputCode =
200+
@"Sub Foo(ByRef arg1() As Variant)
201+
End Sub";
202+
203+
//Arrange
204+
var builder = new MockVbeBuilder();
205+
VBComponent component;
206+
var vbe = builder.BuildFromSingleStandardModule(inputCode, out component);
207+
var mockHost = new Mock<IHostApplication>();
208+
mockHost.SetupAllProperties();
209+
var parser = MockParser.Create(vbe.Object, new RubberduckParserState(vbe.Object, new Mock<ISinks>().Object));
210+
211+
parser.Parse(new CancellationTokenSource());
212+
if (parser.State.Status >= ParserState.Error) { Assert.Inconclusive("Parser Error"); }
213+
214+
var inspection = new ParameterCanBeByValInspection(parser.State);
215+
216+
var results = inspection.GetInspectionResults().ToList();
217+
218+
Assert.AreEqual(0, results.Count);
219+
}
220+
221+
[TestMethod]
222+
[TestCategory("Inspections")]
223+
public void ParameterCanByByVal_ReturnsResult_QuickFixWorks_SubNameStartsWithParamName()
224+
{
225+
const string inputCode =
226+
@"Sub foo(f)
227+
End Sub";
228+
229+
const string expectedCode =
230+
@"Sub foo(ByVal f)
231+
End Sub";
232+
233+
//Arrange
234+
var builder = new MockVbeBuilder();
235+
VBComponent component;
236+
var vbe = builder.BuildFromSingleStandardModule(inputCode, out component);
237+
var project = vbe.Object.VBProjects.Item(0);
238+
var module = project.VBComponents.Item(0).CodeModule;
239+
var mockHost = new Mock<IHostApplication>();
240+
mockHost.SetupAllProperties();
241+
var parser = MockParser.Create(vbe.Object, new RubberduckParserState(vbe.Object, new Mock<ISinks>().Object));
242+
243+
parser.Parse(new CancellationTokenSource());
244+
if (parser.State.Status >= ParserState.Error) { Assert.Inconclusive("Parser Error"); }
245+
246+
var inspection = new ParameterCanBeByValInspection(parser.State);
247+
inspection.GetInspectionResults().First().QuickFixes.First().Fix();
248+
249+
Assert.AreEqual(expectedCode, module.Lines());
250+
}
251+
195252
[TestMethod]
196253
[TestCategory("Inspections")]
197254
public void ParameterCanByByVal_ReturnsResult_QuickFixWorks_PassedByUnspecified()
@@ -256,16 +313,24 @@ public void ParameterCanByByVal_ReturnsResult_QuickFixWorks_PassedByRef()
256313

257314
[TestMethod]
258315
[TestCategory("Inspections")]
259-
public void GivenArrayParameter_ReturnsNoResult()
316+
public void ParameterCanByByVal_ReturnsResult_QuickFixWorks_PassedByUnspecified_MultilineParameter()
260317
{
261318
const string inputCode =
262-
@"Sub Foo(ByRef arg1() As Variant)
319+
@"Sub Foo( _
320+
arg1 As String)
321+
End Sub";
322+
323+
const string expectedCode =
324+
@"Sub Foo( _
325+
ByVal arg1 As String)
263326
End Sub";
264327

265328
//Arrange
266329
var builder = new MockVbeBuilder();
267330
VBComponent component;
268331
var vbe = builder.BuildFromSingleStandardModule(inputCode, out component);
332+
var project = vbe.Object.VBProjects.Item(0);
333+
var module = project.VBComponents.Item(0).CodeModule;
269334
var mockHost = new Mock<IHostApplication>();
270335
mockHost.SetupAllProperties();
271336
var parser = MockParser.Create(vbe.Object, new RubberduckParserState(vbe.Object, new Mock<ISinks>().Object));
@@ -274,10 +339,42 @@ public void GivenArrayParameter_ReturnsNoResult()
274339
if (parser.State.Status >= ParserState.Error) { Assert.Inconclusive("Parser Error"); }
275340

276341
var inspection = new ParameterCanBeByValInspection(parser.State);
277-
278-
var results = inspection.GetInspectionResults().ToList();
342+
inspection.GetInspectionResults().First().QuickFixes.First().Fix();
279343

280-
Assert.AreEqual(0, results.Count);
344+
Assert.AreEqual(expectedCode, module.Lines());
345+
}
346+
347+
[TestMethod]
348+
[TestCategory("Inspections")]
349+
public void ParameterCanByByVal_ReturnsResult_QuickFixWorks_PassedByRef_MultilineParameter()
350+
{
351+
const string inputCode =
352+
@"Sub Foo(ByRef _
353+
arg1 As String)
354+
End Sub";
355+
356+
const string expectedCode =
357+
@"Sub Foo(ByVal _
358+
arg1 As String)
359+
End Sub";
360+
361+
//Arrange
362+
var builder = new MockVbeBuilder();
363+
VBComponent component;
364+
var vbe = builder.BuildFromSingleStandardModule(inputCode, out component);
365+
var project = vbe.Object.VBProjects.Item(0);
366+
var module = project.VBComponents.Item(0).CodeModule;
367+
var mockHost = new Mock<IHostApplication>();
368+
mockHost.SetupAllProperties();
369+
var parser = MockParser.Create(vbe.Object, new RubberduckParserState(vbe.Object, new Mock<ISinks>().Object));
370+
371+
parser.Parse(new CancellationTokenSource());
372+
if (parser.State.Status >= ParserState.Error) { Assert.Inconclusive("Parser Error"); }
373+
374+
var inspection = new ParameterCanBeByValInspection(parser.State);
375+
inspection.GetInspectionResults().First().QuickFixes.First().Fix();
376+
377+
Assert.AreEqual(expectedCode, module.Lines());
281378
}
282379

283380
[TestMethod]

RubberduckTests/Inspections/ProcedureShouldBeFunctionInspectionTests.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,46 @@ public void ProcedureShouldBeFunction_QuickFixWorks()
330330
Assert.AreEqual(expectedCode, module.Lines());
331331
}
332332

333+
[TestMethod]
334+
[TestCategory("Inspections")]
335+
public void ProcedureShouldBeFunction_QuickFixWorks_NoAsTypeClauseInParam()
336+
{
337+
const string inputCode =
338+
@"Private Sub Foo(ByRef arg1)
339+
End Sub";
340+
341+
const string expectedCode =
342+
@"Private Function Foo(ByVal arg1) As Variant
343+
Foo = arg1
344+
End Function";
345+
346+
//Arrange
347+
var settings = new Mock<IGeneralConfigService>();
348+
var config = GetTestConfig();
349+
settings.Setup(x => x.LoadConfiguration()).Returns(config);
350+
351+
var builder = new MockVbeBuilder();
352+
VBComponent component;
353+
var vbe = builder.BuildFromSingleStandardModule(inputCode, out component);
354+
var project = vbe.Object.VBProjects.Item(0);
355+
var module = project.VBComponents.Item(0).CodeModule;
356+
var mockHost = new Mock<IHostApplication>();
357+
mockHost.SetupAllProperties();
358+
var parser = MockParser.Create(vbe.Object, new RubberduckParserState(vbe.Object, new Mock<ISinks>().Object));
359+
360+
parser.Parse(new CancellationTokenSource());
361+
if (parser.State.Status >= ParserState.Error) { Assert.Inconclusive("Parser Error"); }
362+
363+
var inspection = new ProcedureCanBeWrittenAsFunctionInspection(parser.State);
364+
var inspector = new Inspector(settings.Object, new IInspection[] { inspection });
365+
366+
var inspectionResults = inspector.FindIssuesAsync(parser.State, CancellationToken.None).Result;
367+
368+
inspectionResults.First().QuickFixes.First().Fix();
369+
370+
Assert.AreEqual(expectedCode, module.Lines());
371+
}
372+
333373
[TestMethod]
334374
[TestCategory("Inspections")]
335375
public void ProcedureShouldBeFunction_QuickFixWorks_DoesNotInterfereWithBody()

0 commit comments

Comments
 (0)