Skip to content

Commit eee24d0

Browse files
committed
Make ParameterCanBeByVal respect that interfaces can have implementation of their own
1 parent 8a9bd3c commit eee24d0

File tree

2 files changed

+287
-9
lines changed

2 files changed

+287
-9
lines changed

Rubberduck.CodeAnalysis/Inspections/Concrete/ParameterCanBeByValInspection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ private IEnumerable<ParameterDeclaration> InterFaceMembersThatCanBeChangedToBePa
9595
continue;
9696
}
9797

98-
var parameterCanBeChangedToBeByVal = interfaceParameters.Select(parameter => parameter.IsByRef).ToList();
98+
var parameterCanBeChangedToBeByVal = interfaceParameters.Select(parameter => CanBeChangedToBePassedByValIndividually(parameter)).ToList();
9999

100100
var implementingMembers = State.DeclarationFinder.FindInterfaceImplementationMembers(memberDeclaration);
101101
foreach (var implementingMember in implementingMembers)

RubberduckTests/Inspections/ParameterCanBeByValInspectionTests.cs

Lines changed: 286 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -589,7 +589,7 @@ Private Sub IClass1_DoSomething(ByVal a As Integer)
589589

590590
[Test]
591591
[Category("Inspections")]
592-
public void ParameterCanBeByVal_InterfaceMember_SingleParamAssignedTo()
592+
public void ParameterCanBeByVal_InterfaceMember_SingleParamAssignedTo_InImplementation()
593593
{
594594
//Input
595595
const string inputCode1 =
@@ -627,7 +627,40 @@ Private Sub IClass1_DoSomething(ByRef a As Integer)
627627

628628
[Test]
629629
[Category("Inspections")]
630-
public void ParameterCanBeByVal_InterfaceMember_SingleParamUsedByRefMethod()
630+
public void ParameterCanBeByVal_InterfaceMember_SingleParamAssignedTo_InInterface()
631+
{
632+
//Input
633+
const string inputCode1 =
634+
@"Public Sub DoSomething(ByRef a As Integer)
635+
a = 42
636+
End Sub";
637+
const string inputCode2 =
638+
@"Implements IClass1
639+
640+
Private Sub IClass1_DoSomething(ByRef a As Integer)
641+
End Sub";
642+
643+
var builder = new MockVbeBuilder();
644+
var project = builder.ProjectBuilder("TestProject1", ProjectProtection.Unprotected)
645+
.AddComponent("IClass1", ComponentType.ClassModule, inputCode1)
646+
.AddComponent("Class1", ComponentType.ClassModule, inputCode2)
647+
.AddComponent("Class2", ComponentType.ClassModule, inputCode2)
648+
.Build();
649+
var vbe = builder.AddProject(project).Build();
650+
651+
using (var state = MockParser.CreateAndParse(vbe.Object))
652+
{
653+
654+
var inspection = new ParameterCanBeByValInspection(state);
655+
var inspectionResults = inspection.GetInspectionResults(CancellationToken.None);
656+
657+
Assert.IsFalse(inspectionResults.Any());
658+
}
659+
}
660+
661+
[Test]
662+
[Category("Inspections")]
663+
public void ParameterCanBeByVal_InterfaceMember_SingleParamUsedByRefMethod_InImplementation()
631664
{
632665
//Input
633666
const string inputCode1 =
@@ -668,7 +701,43 @@ Private Sub IClass1_DoSomething(ByRef a As Integer)
668701

669702
[Test]
670703
[Category("Inspections")]
671-
public void ParameterCanBeByVal_InterfaceMember_SingleParamUsedByRefMethodExplicitlyByVal()
704+
public void ParameterCanBeByVal_InterfaceMember_SingleParamUsedByRefMethod_InInterface()
705+
{
706+
//Input
707+
const string inputCode1 =
708+
@"Public Sub DoSomething(ByRef a As Integer)
709+
DoSomethingElse a
710+
End Sub
711+
712+
Private Sub DoSomethingElse(ByRef bar As Integer)
713+
End Sub";
714+
const string inputCode2 =
715+
@"Implements IClass1
716+
717+
Private Sub IClass1_DoSomething(ByRef a As Integer)
718+
End Sub";
719+
720+
var builder = new MockVbeBuilder();
721+
var project = builder.ProjectBuilder("TestProject1", ProjectProtection.Unprotected)
722+
.AddComponent("IClass1", ComponentType.ClassModule, inputCode1)
723+
.AddComponent("Class1", ComponentType.ClassModule, inputCode2)
724+
.AddComponent("Class2", ComponentType.ClassModule, inputCode2)
725+
.Build();
726+
var vbe = builder.AddProject(project).Build();
727+
728+
using (var state = MockParser.CreateAndParse(vbe.Object))
729+
{
730+
731+
var inspection = new ParameterCanBeByValInspection(state);
732+
var inspectionResults = inspection.GetInspectionResults(CancellationToken.None);
733+
734+
Assert.IsFalse(inspectionResults.Any(result => result.Target.IdentifierName.Equals("a")));
735+
}
736+
}
737+
738+
[Test]
739+
[Category("Inspections")]
740+
public void ParameterCanBeByVal_InterfaceMember_SingleParamUsedByRefMethodExplicitlyByVal_InImplementation()
672741
{
673742
//Input
674743
const string inputCode1 =
@@ -709,7 +778,42 @@ Private Sub IClass1_DoSomething(ByRef a As Integer)
709778

710779
[Test]
711780
[Category("Inspections")]
712-
public void ParameterCanBeByVal_InterfaceMember_SingleParamUsedByRefMethodPartOfExpression()
781+
public void ParameterCanBeByVal_InterfaceMember_SingleParamUsedByRefMethodExplicitlyByVal_InInterface()
782+
{
783+
//Input
784+
const string inputCode1 =
785+
@"Public Sub DoSomething(ByRef a As Integer)
786+
DoSomethingElse (a)
787+
End Sub
788+
789+
Private Sub DoSomethingElse(ByRef bar As Integer)
790+
End Sub";
791+
const string inputCode2 =
792+
@"Implements IClass1
793+
794+
Private Sub IClass1_DoSomething(ByRef a As Integer)
795+
End Sub";
796+
var builder = new MockVbeBuilder();
797+
var project = builder.ProjectBuilder("TestProject1", ProjectProtection.Unprotected)
798+
.AddComponent("IClass1", ComponentType.ClassModule, inputCode1)
799+
.AddComponent("Class1", ComponentType.ClassModule, inputCode2)
800+
.AddComponent("Class2", ComponentType.ClassModule, inputCode2)
801+
.Build();
802+
var vbe = builder.AddProject(project).Build();
803+
804+
using (var state = MockParser.CreateAndParse(vbe.Object))
805+
{
806+
807+
var inspection = new ParameterCanBeByValInspection(state);
808+
var inspectionResults = inspection.GetInspectionResults(CancellationToken.None);
809+
810+
Assert.AreEqual(1, inspectionResults.Count(result => result.Target.IdentifierName.Equals("a")));
811+
}
812+
}
813+
814+
[Test]
815+
[Category("Inspections")]
816+
public void ParameterCanBeByVal_InterfaceMember_SingleParamUsedByRefMethodPartOfExpression_InImplementation()
713817
{
714818
//Input
715819
const string inputCode1 =
@@ -750,7 +854,43 @@ Private Sub IClass1_DoSomething(ByRef a As Integer)
750854

751855
[Test]
752856
[Category("Inspections")]
753-
public void ParameterCanBeByVal_InterfaceMember_SingleParamByRefEvent()
857+
public void ParameterCanBeByVal_InterfaceMember_SingleParamUsedByRefMethodPartOfExpression_InInterface()
858+
{
859+
//Input
860+
const string inputCode1 =
861+
@"Public Sub DoSomething(ByRef a As Integer)
862+
DoSomethingElse a + 42
863+
End Sub
864+
865+
Private Sub DoSomethingElse(ByRef bar As Integer)
866+
End Sub";
867+
const string inputCode2 =
868+
@"Implements IClass1
869+
870+
Private Sub IClass1_DoSomething(ByRef a As Integer)
871+
End Sub";
872+
873+
var builder = new MockVbeBuilder();
874+
var project = builder.ProjectBuilder("TestProject1", ProjectProtection.Unprotected)
875+
.AddComponent("IClass1", ComponentType.ClassModule, inputCode1)
876+
.AddComponent("Class1", ComponentType.ClassModule, inputCode2)
877+
.AddComponent("Class2", ComponentType.ClassModule, inputCode2)
878+
.Build();
879+
var vbe = builder.AddProject(project).Build();
880+
881+
using (var state = MockParser.CreateAndParse(vbe.Object))
882+
{
883+
884+
var inspection = new ParameterCanBeByValInspection(state);
885+
var inspectionResults = inspection.GetInspectionResults(CancellationToken.None);
886+
887+
Assert.AreEqual(1, inspectionResults.Count(result => result.Target.IdentifierName.Equals("a")));
888+
}
889+
}
890+
891+
[Test]
892+
[Category("Inspections")]
893+
public void ParameterCanBeByVal_InterfaceMember_SingleParamByRefEvent_InImplementation()
754894
{
755895
//Input
756896
const string inputCode1 =
@@ -790,7 +930,42 @@ Private Sub IClass1_DoSomething(ByRef a As Integer)
790930

791931
[Test]
792932
[Category("Inspections")]
793-
public void ParameterCanBeByVal_InterfaceMember_SingleParamByRefEventExplicitlyByVal()
933+
public void ParameterCanBeByVal_InterfaceMember_SingleParamByRefEvent_InInterface()
934+
{
935+
//Input
936+
const string inputCode1 =
937+
@"Public Event Bar(ByRef foo As Integer)
938+
939+
Public Sub DoSomething(ByRef a As Integer)
940+
RaiseEvent Bar(a)
941+
End Sub";
942+
const string inputCode2 =
943+
@"Implements IClass1
944+
945+
Private Sub IClass1_DoSomething(ByRef a As Integer)
946+
End Sub";
947+
948+
var builder = new MockVbeBuilder();
949+
var project = builder.ProjectBuilder("TestProject1", ProjectProtection.Unprotected)
950+
.AddComponent("IClass1", ComponentType.ClassModule, inputCode1)
951+
.AddComponent("Class1", ComponentType.ClassModule, inputCode2)
952+
.AddComponent("Class2", ComponentType.ClassModule, inputCode2)
953+
.Build();
954+
var vbe = builder.AddProject(project).Build();
955+
956+
using (var state = MockParser.CreateAndParse(vbe.Object))
957+
{
958+
959+
var inspection = new ParameterCanBeByValInspection(state);
960+
var inspectionResults = inspection.GetInspectionResults(CancellationToken.None);
961+
962+
Assert.IsFalse(inspectionResults.Any(result => result.Target.IdentifierName.Equals("a")));
963+
}
964+
}
965+
966+
[Test]
967+
[Category("Inspections")]
968+
public void ParameterCanBeByVal_InterfaceMember_SingleParamByRefEventExplicitlyByVal_InImplementation()
794969
{
795970
//Input
796971
const string inputCode1 =
@@ -830,7 +1005,42 @@ Private Sub IClass1_DoSomething(ByRef a As Integer)
8301005

8311006
[Test]
8321007
[Category("Inspections")]
833-
public void ParameterCanBeByVal_InterfaceMember_SingleParamByRefEventPartOfExpression()
1008+
public void ParameterCanBeByVal_InterfaceMember_SingleParamByRefEventExplicitlyByVal_InInterface()
1009+
{
1010+
//Input
1011+
const string inputCode1 =
1012+
@"Public Event Bar(ByRef foo As Integer)
1013+
1014+
Public Sub DoSomething(ByRef a As Integer)
1015+
RaiseEvent Bar(ByVal a)
1016+
End Sub";
1017+
const string inputCode2 =
1018+
@"Implements IClass1
1019+
1020+
Private Sub IClass1_DoSomething(ByRef a As Integer)
1021+
End Sub";
1022+
1023+
var builder = new MockVbeBuilder();
1024+
var project = builder.ProjectBuilder("TestProject1", ProjectProtection.Unprotected)
1025+
.AddComponent("IClass1", ComponentType.ClassModule, inputCode1)
1026+
.AddComponent("Class1", ComponentType.ClassModule, inputCode2)
1027+
.AddComponent("Class2", ComponentType.ClassModule, inputCode2)
1028+
.Build();
1029+
var vbe = builder.AddProject(project).Build();
1030+
1031+
using (var state = MockParser.CreateAndParse(vbe.Object))
1032+
{
1033+
1034+
var inspection = new ParameterCanBeByValInspection(state);
1035+
var inspectionResults = inspection.GetInspectionResults(CancellationToken.None);
1036+
1037+
Assert.AreEqual(1, inspectionResults.Count(result => result.Target.IdentifierName.Equals("a")));
1038+
}
1039+
}
1040+
1041+
[Test]
1042+
[Category("Inspections")]
1043+
public void ParameterCanBeByVal_InterfaceMember_SingleParamByRefEventPartOfExpression_InImplementation()
8341044
{
8351045
//Input
8361046
const string inputCode1 =
@@ -870,7 +1080,42 @@ Private Sub IClass1_DoSomething(ByRef a As Integer)
8701080

8711081
[Test]
8721082
[Category("Inspections")]
873-
public void ParameterCanBeByVal_InterfaceMember_MultipleParams_OneCanBeByVal()
1083+
public void ParameterCanBeByVal_InterfaceMember_SingleParamByRefEventPartOfExpression_InInterface()
1084+
{
1085+
//Input
1086+
const string inputCode1 =
1087+
@"Public Event Bar(ByRef foo As Integer)
1088+
1089+
Public Sub DoSomething(ByRef a As Integer)
1090+
RaiseEvent Bar(a + 15)
1091+
End Sub";
1092+
const string inputCode2 =
1093+
@"Implements IClass1
1094+
1095+
Private Sub IClass1_DoSomething(ByRef a As Integer)
1096+
End Sub";
1097+
1098+
var builder = new MockVbeBuilder();
1099+
var project = builder.ProjectBuilder("TestProject1", ProjectProtection.Unprotected)
1100+
.AddComponent("IClass1", ComponentType.ClassModule, inputCode1)
1101+
.AddComponent("Class1", ComponentType.ClassModule, inputCode2)
1102+
.AddComponent("Class2", ComponentType.ClassModule, inputCode2)
1103+
.Build();
1104+
var vbe = builder.AddProject(project).Build();
1105+
1106+
using (var state = MockParser.CreateAndParse(vbe.Object))
1107+
{
1108+
1109+
var inspection = new ParameterCanBeByValInspection(state);
1110+
var inspectionResults = inspection.GetInspectionResults(CancellationToken.None);
1111+
1112+
Assert.AreEqual(1, inspectionResults.Count(result => result.Target.IdentifierName.Equals("a")));
1113+
}
1114+
}
1115+
1116+
[Test]
1117+
[Category("Inspections")]
1118+
public void ParameterCanBeByVal_InterfaceMember_MultipleParams_OneCanBeByVal_InImplementation()
8741119
{
8751120
//Input
8761121
const string inputCode1 =
@@ -906,6 +1151,39 @@ Private Sub IClass1_DoSomething(ByRef a As Integer, ByRef b As Integer)
9061151
}
9071152
}
9081153

1154+
[Test]
1155+
[Category("Inspections")]
1156+
public void ParameterCanBeByVal_InterfaceMember_MultipleParams_OneCanBeByVal_InInterface()
1157+
{
1158+
//Input
1159+
const string inputCode1 =
1160+
@"Public Sub DoSomething(ByRef a As Integer, ByRef b As Integer)
1161+
b = 42
1162+
End Sub";
1163+
const string inputCode2 =
1164+
@"Implements IClass1
1165+
1166+
Private Sub IClass1_DoSomething(ByRef a As Integer, ByRef b As Integer)
1167+
End Sub";
1168+
1169+
var builder = new MockVbeBuilder();
1170+
var project = builder.ProjectBuilder("TestProject1", ProjectProtection.Unprotected)
1171+
.AddComponent("IClass1", ComponentType.ClassModule, inputCode1)
1172+
.AddComponent("Class1", ComponentType.ClassModule, inputCode2)
1173+
.AddComponent("Class2", ComponentType.ClassModule, inputCode2)
1174+
.Build();
1175+
var vbe = builder.AddProject(project).Build();
1176+
1177+
using (var state = MockParser.CreateAndParse(vbe.Object))
1178+
{
1179+
1180+
var inspection = new ParameterCanBeByValInspection(state);
1181+
var inspectionResults = inspection.GetInspectionResults(CancellationToken.None);
1182+
1183+
Assert.AreEqual("a", inspectionResults.Single().Target.IdentifierName);
1184+
}
1185+
}
1186+
9091187
[Test]
9101188
[Category("Inspections")]
9111189
public void ParameterCanBeByVal_EventMember_SingleParam()

0 commit comments

Comments
 (0)