Skip to content

Commit e26f553

Browse files
committed
fixes ParameterCanBeByVal false positive with object parameter
1 parent 3b0345c commit e26f553

File tree

2 files changed

+61
-30
lines changed

2 files changed

+61
-30
lines changed

RetailCoder.VBE/Inspections/ParameterCanBeByValInspection.cs

Lines changed: 36 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -23,53 +23,61 @@ public ParameterCanBeByValInspection(RubberduckParserState state)
2323

2424
public override IEnumerable<InspectionResultBase> GetInspectionResults()
2525
{
26-
var declarations = UserDeclarations.ToList();
26+
var declarations = UserDeclarations.ToArray();
2727
var issues = new List<ParameterCanBeByValInspectionResult>();
2828

29-
var interfaceDeclarationMembers = declarations.FindInterfaceMembers().ToList();
30-
var interfaceScopes = declarations.FindInterfaceImplementationMembers().Concat(interfaceDeclarationMembers).Select(s => s.Scope);
29+
var interfaceDeclarationMembers = declarations.FindInterfaceMembers().ToArray();
30+
var interfaceScopes = declarations.FindInterfaceImplementationMembers().Concat(interfaceDeclarationMembers).Select(s => s.Scope).ToArray();
3131

3232
issues.AddRange(GetResults(declarations, interfaceDeclarationMembers));
3333

34-
var eventMembers = declarations.Where(item => !item.IsBuiltIn && item.DeclarationType == DeclarationType.Event).ToList();
35-
var formEventHandlerScopes = State.FindFormEventHandlers().Select(handler => handler.Scope);
36-
var eventHandlerScopes = State.DeclarationFinder.FindEventHandlers().Concat(declarations.FindUserEventHandlers()).Select(e => e.Scope);
34+
var eventMembers = declarations.Where(item => !item.IsBuiltIn && item.DeclarationType == DeclarationType.Event).ToArray();
35+
var formEventHandlerScopes = State.FindFormEventHandlers().Select(handler => handler.Scope).ToArray();
36+
var eventHandlerScopes = State.DeclarationFinder.FindEventHandlers().Concat(declarations.FindUserEventHandlers()).Select(e => e.Scope).ToArray();
3737
var eventScopes = eventMembers.Select(s => s.Scope)
3838
.Concat(formEventHandlerScopes)
39-
.Concat(eventHandlerScopes);
39+
.Concat(eventHandlerScopes)
40+
.ToArray();
4041

4142
issues.AddRange(GetResults(declarations, eventMembers));
4243

4344
var declareScopes = declarations.Where(item =>
4445
item.DeclarationType == DeclarationType.LibraryFunction
4546
|| item.DeclarationType == DeclarationType.LibraryProcedure)
46-
.Select(e => e.Scope);
47+
.Select(e => e.Scope)
48+
.ToArray();
4749

48-
issues.AddRange(declarations.Where(declaration =>
50+
issues.AddRange(declarations.OfType<ParameterDeclaration>()
51+
.Where(declaration => IsIssue(declaration, declarations, declareScopes, eventScopes, interfaceScopes))
52+
.Select(issue => new ParameterCanBeByValInspectionResult(this, State, issue, issue.Context, issue.QualifiedName)));
53+
54+
return issues;
55+
}
56+
57+
private bool IsIssue(ParameterDeclaration declaration, Declaration[] userDeclarations, string[] declareScopes, string[] eventScopes, string[] interfaceScopes)
58+
{
59+
var isIssue =
4960
!declaration.IsArray
61+
&& !declaration.IsParamArray
62+
&& (declaration.IsByRef || declaration.IsImplicitByRef)
5063
&& (declaration.AsTypeDeclaration == null || declaration.AsTypeDeclaration.DeclarationType != DeclarationType.UserDefinedType)
5164
&& !declareScopes.Contains(declaration.ParentScope)
5265
&& !eventScopes.Contains(declaration.ParentScope)
5366
&& !interfaceScopes.Contains(declaration.ParentScope)
54-
&& declaration.DeclarationType == DeclarationType.Parameter
55-
&& ((VBAParser.ArgContext)declaration.Context).BYVAL() == null
56-
&& !IsUsedAsByRefParam(declarations, declaration)
57-
&& !declaration.References.Any(reference => reference.IsAssignment))
58-
.Select(issue => new ParameterCanBeByValInspectionResult(this, State, issue, issue.Context, issue.QualifiedName)));
59-
60-
return issues;
67+
&& !IsUsedAsByRefParam(userDeclarations, declaration)
68+
&& (!declaration.References.Any() || !declaration.References.Any(reference => reference.IsAssignment));
69+
return isIssue;
6170
}
6271

63-
private IEnumerable<ParameterCanBeByValInspectionResult> GetResults(List<Declaration> declarations, List<Declaration> declarationMembers)
72+
private IEnumerable<ParameterCanBeByValInspectionResult> GetResults(Declaration[] declarations, Declaration[] declarationMembers)
6473
{
6574
foreach (var declaration in declarationMembers)
6675
{
67-
var declarationParameters =
68-
declarations.Where(d => d.DeclarationType == DeclarationType.Parameter &&
69-
Equals(d.ParentDeclaration, declaration))
70-
.OrderBy(o => o.Selection.StartLine)
71-
.ThenBy(t => t.Selection.StartColumn)
72-
.ToList();
76+
var declarationParameters = declarations.OfType<ParameterDeclaration>()
77+
.Where(d => Equals(d.ParentDeclaration, declaration))
78+
.OrderBy(o => o.Selection.StartLine)
79+
.ThenBy(t => t.Selection.StartColumn)
80+
.ToList();
7381

7482
if (!declarationParameters.Any()) { continue; }
7583
var parametersAreByRef = declarationParameters.Select(s => true).ToList();
@@ -80,12 +88,11 @@ private IEnumerable<ParameterCanBeByValInspectionResult> GetResults(List<Declara
8088

8189
foreach (var member in members)
8290
{
83-
var parameters =
84-
declarations.Where(d => d.DeclarationType == DeclarationType.Parameter &&
85-
Equals(d.ParentDeclaration, member))
86-
.OrderBy(o => o.Selection.StartLine)
87-
.ThenBy(t => t.Selection.StartColumn)
88-
.ToList();
91+
var parameters = declarations.OfType<ParameterDeclaration>()
92+
.Where(d => Equals(d.ParentDeclaration, member))
93+
.OrderBy(o => o.Selection.StartLine)
94+
.ThenBy(t => t.Selection.StartColumn)
95+
.ToList();
8996

9097
for (var i = 0; i < parameters.Count; i++)
9198
{

RubberduckTests/Inspections/ParameterCanBeByValInspectionTests.cs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
using Rubberduck.Inspections.Resources;
88
using Rubberduck.Parsing.VBA;
99
using Rubberduck.VBEditor.Application;
10-
using Rubberduck.VBEditor.Events;
1110
using Rubberduck.VBEditor.SafeComWrappers;
1211
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
1312
using RubberduckTests.Mocks;
@@ -17,6 +16,31 @@ namespace RubberduckTests.Inspections
1716
[TestClass]
1817
public class ParameterCanBeByValInspectionTests
1918
{
19+
[TestMethod]
20+
[TestCategory("Inspections")]
21+
public void ParameterCanBeByVal_NoResultForByValObject()
22+
{
23+
const string inputCode =
24+
@"Sub Foo(ByVal arg1 As Collection)
25+
End Sub";
26+
27+
//Arrange
28+
var builder = new MockVbeBuilder();
29+
IVBComponent component;
30+
var vbe = builder.BuildFromSingleStandardModule(inputCode, out component);
31+
var mockHost = new Mock<IHostApplication>();
32+
mockHost.SetupAllProperties();
33+
var parser = MockParser.Create(vbe.Object, new RubberduckParserState(vbe.Object));
34+
35+
parser.Parse(new CancellationTokenSource());
36+
if (parser.State.Status >= ParserState.Error) { Assert.Inconclusive("Parser Error"); }
37+
38+
var inspection = new ParameterCanBeByValInspection(parser.State);
39+
var inspectionResults = inspection.GetInspectionResults();
40+
41+
Assert.AreEqual(0, inspectionResults.Count());
42+
}
43+
2044
[TestMethod]
2145
[TestCategory("Inspections")]
2246
public void ParameterCanBeByVal_ReturnsResult_PassedByNotSpecified()

0 commit comments

Comments
 (0)