From da2ebf82fd98e022b30e8a9a13f3dde888a8daf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amaury=20Lev=C3=A9?= Date: Wed, 30 Oct 2024 15:40:01 +0100 Subject: [PATCH] Fix MSTEST0018 FP with IEnumerable (#3978) --- .../DynamicDataShouldBeValidAnalyzer.cs | 32 ++-- .../DynamicDataShouldBeValidAnalyzerTests.cs | 174 +++++++++++++++++- 2 files changed, 188 insertions(+), 18 deletions(-) diff --git a/src/Analyzers/MSTest.Analyzers/DynamicDataShouldBeValidAnalyzer.cs b/src/Analyzers/MSTest.Analyzers/DynamicDataShouldBeValidAnalyzer.cs index 115600daca..c92572ebd9 100644 --- a/src/Analyzers/MSTest.Analyzers/DynamicDataShouldBeValidAnalyzer.cs +++ b/src/Analyzers/MSTest.Analyzers/DynamicDataShouldBeValidAnalyzer.cs @@ -220,23 +220,29 @@ private static void AnalyzeDataSource(SymbolAnalysisContext context, AttributeDa } // Validate member return type. - if (member.GetMemberType() is not INamedTypeSymbol memberType) + ITypeSymbol? memberTypeSymbol = member.GetMemberType(); + if (memberTypeSymbol is INamedTypeSymbol memberNamedType) { - return; - } + if (!SymbolEqualityComparer.Default.Equals(memberNamedType.ConstructedFrom, ienumerableTypeSymbol) + || memberNamedType.TypeArguments.Length != 1) + { + context.ReportDiagnostic(attributeSyntax.CreateDiagnostic(MemberTypeRule, declaringType.Name, memberName)); + return; + } - if (!SymbolEqualityComparer.Default.Equals(memberType.ConstructedFrom, ienumerableTypeSymbol) - || memberType.TypeArguments.Length != 1) - { - context.ReportDiagnostic(attributeSyntax.CreateDiagnostic(MemberTypeRule, declaringType.Name, memberName)); - return; + ITypeSymbol collectionBoundType = memberNamedType.TypeArguments[0]; + if (!collectionBoundType.Inherits(itupleTypeSymbol) + && collectionBoundType is not IArrayTypeSymbol) + { + context.ReportDiagnostic(attributeSyntax.CreateDiagnostic(MemberTypeRule, declaringType.Name, memberName)); + } } - - ITypeSymbol collectionBoundType = memberType.TypeArguments[0]; - if (!collectionBoundType.Inherits(itupleTypeSymbol) - && (collectionBoundType is not IArrayTypeSymbol arrayTypeSymbol || arrayTypeSymbol.ElementType.SpecialType != SpecialType.System_Object)) + else if (memberTypeSymbol is IArrayTypeSymbol arrayType) { - context.ReportDiagnostic(attributeSyntax.CreateDiagnostic(MemberTypeRule, declaringType.Name, memberName)); + if (arrayType.ElementType is not IArrayTypeSymbol) + { + context.ReportDiagnostic(attributeSyntax.CreateDiagnostic(MemberTypeRule, declaringType.Name, memberName)); + } } } diff --git a/test/UnitTests/MSTest.Analyzers.UnitTests/DynamicDataShouldBeValidAnalyzerTests.cs b/test/UnitTests/MSTest.Analyzers.UnitTests/DynamicDataShouldBeValidAnalyzerTests.cs index ec3b1d5491..b15c8c2c9d 100644 --- a/test/UnitTests/MSTest.Analyzers.UnitTests/DynamicDataShouldBeValidAnalyzerTests.cs +++ b/test/UnitTests/MSTest.Analyzers.UnitTests/DynamicDataShouldBeValidAnalyzerTests.cs @@ -164,12 +164,112 @@ public void TestMethod214(int i, string s) { } + [DynamicData("DataJaggedArray")] + [TestMethod] + public void TestMethod301(MyTestClass[] testClasses) + { + } + + [DynamicData("SomeDataJaggedArray", typeof(SomeClass))] + [TestMethod] + public void TestMethod302(MyTestClass[] testClasses) + { + } + + [DynamicData(dynamicDataSourceName: "DataJaggedArray")] + [TestMethod] + public void TestMethod303(MyTestClass[] testClasses) + { + } + + [DynamicData(dynamicDataDeclaringType: typeof(SomeClass), dynamicDataSourceName: "SomeDataJaggedArray")] + [TestMethod] + public void TestMethod304(MyTestClass[] testClasses) + { + } + + [DynamicData("GetDataJaggedArray", DynamicDataSourceType.Method)] + [TestMethod] + public void TestMethod311(MyTestClass[] testClasses) + { + } + + [DynamicData("GetSomeDataJaggedArray", typeof(SomeClass), DynamicDataSourceType.Method)] + [TestMethod] + public void TestMethod312(MyTestClass[] testClasses) + { + } + + [DynamicData(dynamicDataSourceType: DynamicDataSourceType.Method, dynamicDataSourceName: "GetDataJaggedArray")] + [TestMethod] + public void TestMethod313(MyTestClass[] testClasses) + { + } + + [DynamicData(dynamicDataDeclaringType: typeof(SomeClass), dynamicDataSourceType: DynamicDataSourceType.Method, dynamicDataSourceName: "GetSomeDataJaggedArray")] + [TestMethod] + public void TestMethod314(MyTestClass[] testClasses) + { + } + + [DynamicData("DataNonObjectTypeArray")] + [TestMethod] + public void TestMethod401(MyTestClass[] testClasses) + { + } + + [DynamicData("SomeDataNonObjectTypeArray", typeof(SomeClass))] + [TestMethod] + public void TestMethod402(MyTestClass[] testClasses) + { + } + + [DynamicData(dynamicDataSourceName: "DataNonObjectTypeArray")] + [TestMethod] + public void TestMethod403(MyTestClass[] testClasses) + { + } + + [DynamicData(dynamicDataDeclaringType: typeof(SomeClass), dynamicDataSourceName: "SomeDataNonObjectTypeArray")] + [TestMethod] + public void TestMethod404(MyTestClass[] testClasses) + { + } + + [DynamicData("GetDataNonObjectTypeArray", DynamicDataSourceType.Method)] + [TestMethod] + public void TestMethod411(MyTestClass[] testClasses) + { + } + + [DynamicData("GetSomeDataNonObjectTypeArray", typeof(SomeClass), DynamicDataSourceType.Method)] + [TestMethod] + public void TestMethod412(MyTestClass[] testClasses) + { + } + + [DynamicData(dynamicDataSourceType: DynamicDataSourceType.Method, dynamicDataSourceName: "GetDataNonObjectTypeArray")] + [TestMethod] + public void TestMethod413(MyTestClass[] testClasses) + { + } + + [DynamicData(dynamicDataDeclaringType: typeof(SomeClass), dynamicDataSourceType: DynamicDataSourceType.Method, dynamicDataSourceName: "GetSomeDataNonObjectTypeArray")] + [TestMethod] + public void TestMethod414(MyTestClass[] testClasses) + { + } + public static IEnumerable Data => new List(); public static IEnumerable> DataTuple => new List>(); public static IEnumerable<(int, string)> DataValueTuple => new List<(int, string)>(); + public static MyTestClass[][] DataJaggedArray => System.Array.Empty(); + public static IEnumerable DataNonObjectTypeArray => new List(); public static IEnumerable GetData() => new List(); public static IEnumerable> GetDataTuple() => new List>(); public static IEnumerable<(int, string)> GetDataValueTuple() => new List<(int, string)>(); + public static MyTestClass[][] GetDataJaggedArray() => System.Array.Empty(); + public static IEnumerable GetDataNonObjectTypeArray() => new List(); } public class SomeClass @@ -177,9 +277,13 @@ public class SomeClass public static IEnumerable SomeData => new List(); public static IEnumerable> SomeDataTuple => new List>(); public static IEnumerable<(int, string)> SomeDataValueTuple => new List<(int, string)>(); + public static MyTestClass[][] SomeDataJaggedArray => System.Array.Empty(); + public static IEnumerable SomeDataNonObjectTypeArray => new List(); public static IEnumerable GetSomeData() => new List(); public static IEnumerable> GetSomeDataTuple() => new List>(); public static IEnumerable<(int, string)> GetSomeDataValueTuple() => new List<(int, string)>(); + public static MyTestClass[][] GetSomeDataJaggedArray() => System.Array.Empty(); + public static IEnumerable GetSomeDataNonObjectTypeArray() => new List(); } """; @@ -469,36 +573,88 @@ public void TestMethod4(object[] o) [{|#4:DynamicData("GetData", DynamicDataSourceType.Method)|}] [TestMethod] - public void TestMethod11(object[] o) + public void TestMethod5(object[] o) { } [{|#5:DynamicData("GetSomeData", typeof(SomeClass), DynamicDataSourceType.Method)|}] [TestMethod] - public void TestMethod12(object[] o) + public void TestMethod6(object[] o) { } [{|#6:DynamicData(dynamicDataSourceType: DynamicDataSourceType.Method, dynamicDataSourceName: "GetData")|}] [TestMethod] - public void TestMethod13(object[] o) + public void TestMethod7(object[] o) { } [{|#7:DynamicData(dynamicDataDeclaringType: typeof(SomeClass), dynamicDataSourceType: DynamicDataSourceType.Method, dynamicDataSourceName: "GetSomeData")|}] [TestMethod] - public void TestMethod14(object[] o) + public void TestMethod8(object[] o) + { + } + + [{|#8:DynamicData("DataArray")|}] + [TestMethod] + public void TestMethod9(MyTestClass[] o) + { + } + + [{|#9:DynamicData("SomeDataArray", typeof(SomeClass))|}] + [TestMethod] + public void TestMethod10(MyTestClass[] o) + { + } + + [{|#10:DynamicData(dynamicDataSourceName: "DataArray")|}] + [TestMethod] + public void TestMethod11(MyTestClass[] o) + { + } + + [{|#11:DynamicData(dynamicDataDeclaringType: typeof(SomeClass), dynamicDataSourceName: "SomeDataArray")|}] + [TestMethod] + public void TestMethod12(MyTestClass[] o) + { + } + + [{|#12:DynamicData("GetDataArray", DynamicDataSourceType.Method)|}] + [TestMethod] + public void TestMethod13(MyTestClass[] o) + { + } + + [{|#13:DynamicData("GetSomeDataArray", typeof(SomeClass), DynamicDataSourceType.Method)|}] + [TestMethod] + public void TestMethod14(MyTestClass[] o) + { + } + + [{|#14:DynamicData(dynamicDataSourceType: DynamicDataSourceType.Method, dynamicDataSourceName: "GetDataArray")|}] + [TestMethod] + public void TestMethod15(MyTestClass[] o) + { + } + + [{|#15:DynamicData(dynamicDataDeclaringType: typeof(SomeClass), dynamicDataSourceType: DynamicDataSourceType.Method, dynamicDataSourceName: "GetSomeDataArray")|}] + [TestMethod] + public void TestMethod16(MyTestClass[] o) { } public static IEnumerable Data => new List(); + public static MyTestClass[] DataArray => System.Array.Empty(); public static IEnumerable GetData() => new List(); + public static MyTestClass[] GetDataArray() => System.Array.Empty(); } public class SomeClass { public static IEnumerable SomeData => new List(); + public static MyTestClass[] SomeDataArray => System.Array.Empty(); public static IEnumerable GetSomeData() => new List(); + public static MyTestClass[] GetSomeDataArray() => System.Array.Empty(); } """; @@ -511,7 +667,15 @@ await VerifyCS.VerifyAnalyzerAsync( VerifyCS.Diagnostic(DynamicDataShouldBeValidAnalyzer.MemberTypeRule).WithLocation(4).WithArguments("MyTestClass", "GetData"), VerifyCS.Diagnostic(DynamicDataShouldBeValidAnalyzer.MemberTypeRule).WithLocation(5).WithArguments("SomeClass", "GetSomeData"), VerifyCS.Diagnostic(DynamicDataShouldBeValidAnalyzer.MemberTypeRule).WithLocation(6).WithArguments("MyTestClass", "GetData"), - VerifyCS.Diagnostic(DynamicDataShouldBeValidAnalyzer.MemberTypeRule).WithLocation(7).WithArguments("SomeClass", "GetSomeData")); + VerifyCS.Diagnostic(DynamicDataShouldBeValidAnalyzer.MemberTypeRule).WithLocation(7).WithArguments("SomeClass", "GetSomeData"), + VerifyCS.Diagnostic(DynamicDataShouldBeValidAnalyzer.MemberTypeRule).WithLocation(8).WithArguments("MyTestClass", "DataArray"), + VerifyCS.Diagnostic(DynamicDataShouldBeValidAnalyzer.MemberTypeRule).WithLocation(9).WithArguments("SomeClass", "SomeDataArray"), + VerifyCS.Diagnostic(DynamicDataShouldBeValidAnalyzer.MemberTypeRule).WithLocation(10).WithArguments("MyTestClass", "DataArray"), + VerifyCS.Diagnostic(DynamicDataShouldBeValidAnalyzer.MemberTypeRule).WithLocation(11).WithArguments("SomeClass", "SomeDataArray"), + VerifyCS.Diagnostic(DynamicDataShouldBeValidAnalyzer.MemberTypeRule).WithLocation(12).WithArguments("MyTestClass", "GetDataArray"), + VerifyCS.Diagnostic(DynamicDataShouldBeValidAnalyzer.MemberTypeRule).WithLocation(13).WithArguments("SomeClass", "GetSomeDataArray"), + VerifyCS.Diagnostic(DynamicDataShouldBeValidAnalyzer.MemberTypeRule).WithLocation(14).WithArguments("MyTestClass", "GetDataArray"), + VerifyCS.Diagnostic(DynamicDataShouldBeValidAnalyzer.MemberTypeRule).WithLocation(15).WithArguments("SomeClass", "GetSomeDataArray")); } public async Task MemberIsNotStatic_Diagnostic()