@@ -174,10 +174,7 @@ memberReturnType is INamedTypeSymbol namedMemberReturnType &&
174174 // Make sure the member returns a compatible type
175175 var iEnumerableOfTheoryDataRowType = TypeSymbolFactory . IEnumerableOfITheoryDataRow ( compilation ) ;
176176 var iAsyncEnumerableOfTheoryDataRowType = TypeSymbolFactory . IAsyncEnumerableOfITheoryDataRow ( compilation ) ;
177- var iEnumerableOfTupleType = TypeSymbolFactory . IEnumerableOfTuple ( compilation ) ;
178- var iAsyncEnumerableOfTupleType = TypeSymbolFactory . IAsyncEnumerableOfTuple ( compilation ) ;
179- var IsValidMemberReturnType =
180- VerifyDataSourceReturnType ( context , compilation , xunitContext , memberReturnType , memberProperties , attributeSyntax , iEnumerableOfTheoryDataRowType , iAsyncEnumerableOfTheoryDataRowType , iEnumerableOfTupleType , iAsyncEnumerableOfTupleType ) ;
177+ var IsValidMemberReturnType = VerifyDataSourceReturnType ( context , compilation , xunitContext , memberReturnType , memberProperties , attributeSyntax ) ;
181178
182179 // Make sure public properties have a public getter
183180 if ( memberSymbol . Kind == SymbolKind . Property && memberSymbol . DeclaredAccessibility == Accessibility . Public )
@@ -314,42 +311,6 @@ public static ImmutableArray<ISymbol> FindMethodSymbols(
314311 return ImmutableArray < ISymbol > . Empty ;
315312 }
316313
317- static ITypeSymbol ? FindTypeArgumentFromIEnumerable (
318- ITypeSymbol ? start ,
319- Compilation compilation )
320- {
321- if ( start is not INamedTypeSymbol namedStart )
322- return null ;
323-
324- var iEnumerableOfT = TypeSymbolFactory . IEnumerableOfT ( compilation ) ;
325- if ( iEnumerableOfT is null )
326- return null ;
327-
328- var current = namedStart ;
329- while ( current != null )
330- {
331- // If this class implements IEnumerable<T>, return T type argument
332- foreach ( var iface in current . AllInterfaces )
333- if ( SymbolEqualityComparer . Default . Equals ( iface . OriginalDefinition , iEnumerableOfT ) )
334- return iface . TypeArguments . FirstOrDefault ( ) ;
335-
336- // Navigate to its Base types to investigate if they implement IEnumerable,
337- // attempt to resolve the base type from the source syntax (handles `: ValidExamples`).
338- var declaredBase = ResolveDeclaredBaseTypeFromSyntax ( current , compilation ) as INamedTypeSymbol ;
339-
340- // Prefer declaredBase when available; otherwise fall back to the BaseType symbol.
341- var next = declaredBase ?? current . BaseType ;
342-
343- // Stop if we reached object
344- if ( next ? . SpecialType == SpecialType . System_Object )
345- break ;
346-
347- current = next ;
348- }
349-
350- return null ;
351- }
352-
353314 public static ( INamedTypeSymbol ? TestClass , ITypeSymbol ? MemberClass ) GetClassTypesForAttribute (
354315 AttributeArgumentListSyntax attributeList ,
355316 SemanticModel semanticModel ,
@@ -490,35 +451,16 @@ static void ReportIncorrectMemberType(
490451
491452 static void ReportIncorrectReturnType (
492453 SyntaxNodeAnalysisContext context ,
493- INamedTypeSymbol iEnumerableOfObjectArrayType ,
494- INamedTypeSymbol ? iAsyncEnumerableOfObjectArrayType ,
495- INamedTypeSymbol ? iEnumerableOfTheoryDataRowType ,
496- INamedTypeSymbol ? iAsyncEnumerableOfTheoryDataRowType ,
497- INamedTypeSymbol ? iEnumerableOfTupleType ,
498- INamedTypeSymbol ? iAsyncEnumerableOfTupleType ,
454+ bool v3 ,
499455 AttributeSyntax attribute ,
500456 ImmutableDictionary < string , string ? > memberProperties ,
501457 ITypeSymbol memberType )
502458 {
503- var validSymbols = "'" + SymbolDisplay . ToDisplayString ( iEnumerableOfObjectArrayType ) + " '";
459+ var validSymbols = "'IEnumerable<object[]> '" ;
504460
505461 // Only want the extra types when we know ITheoryDataRow is valid
506- if ( iAsyncEnumerableOfObjectArrayType is not null &&
507- iEnumerableOfTheoryDataRowType is not null &&
508- iAsyncEnumerableOfTheoryDataRowType is not null &&
509- iEnumerableOfTupleType is not null &&
510- iAsyncEnumerableOfTupleType is not null )
511- #pragma warning disable RS1035 // The suggested fix is not available in this context
512- validSymbols += string . Format (
513- CultureInfo . CurrentCulture ,
514- ", '{0}', '{1}', '{2}', '{3}', or '{4}'" ,
515- SymbolDisplay . ToDisplayString ( iAsyncEnumerableOfObjectArrayType ) ,
516- SymbolDisplay . ToDisplayString ( iEnumerableOfTheoryDataRowType ) ,
517- SymbolDisplay . ToDisplayString ( iAsyncEnumerableOfTheoryDataRowType ) ,
518- SymbolDisplay . ToDisplayString ( iEnumerableOfTupleType ) ,
519- SymbolDisplay . ToDisplayString ( iAsyncEnumerableOfTupleType )
520- ) ;
521- #pragma warning restore RS1035
462+ if ( v3 )
463+ validSymbols += ", 'IAsyncEnumerable<object[]>', 'IEnumerable<ITheoryDataRow>', 'IAsyncEnumerable<ITheoryDataRow>', 'IEnumerable<ITuple>', or 'IAsyncEnumerable<ITuple>'" ;
522464
523465 context . ReportDiagnostic (
524466 Diagnostic . Create (
@@ -1039,60 +981,13 @@ static bool VerifyDataSourceReturnType(
1039981 XunitContext xunitContext ,
1040982 ITypeSymbol memberType ,
1041983 ImmutableDictionary < string , string ? > memberProperties ,
1042- AttributeSyntax attributeSyntax ,
1043- INamedTypeSymbol ? iEnumerableOfTheoryDataRowType ,
1044- INamedTypeSymbol ? iAsyncEnumerableOfTheoryDataRowType ,
1045- INamedTypeSymbol ? iEnumerableOfTupleType ,
1046- INamedTypeSymbol ? iAsyncEnumerableOfTupleType )
984+ AttributeSyntax attributeSyntax )
1047985 {
1048986 var v3 = xunitContext . HasV3References ;
1049- var iEnumerableOfObjectArrayType = TypeSymbolFactory . IEnumerableOfObjectArray ( compilation ) ;
1050- var iAsyncEnumerableOfObjectArrayType = TypeSymbolFactory . IAsyncEnumerableOfObjectArray ( compilation ) ;
1051-
1052- var valid = iEnumerableOfObjectArrayType . IsAssignableFrom ( memberType ) ;
1053-
1054- // Special-case handling for IEnumerable<T> where T is not object[]. If T is any array type, it is assignable to object[] and therefore valid.
1055- var memberEnumerableType = memberType . GetEnumerableType ( ) ;
1056- if ( ! valid && memberEnumerableType is not null )
1057- valid = memberEnumerableType . TypeKind == TypeKind . Array ;
1058-
1059- if ( ! valid && v3 && iAsyncEnumerableOfObjectArrayType is not null )
1060- valid = iAsyncEnumerableOfObjectArrayType . IsAssignableFrom ( memberType ) ;
1061-
1062- if ( ! valid && v3 && iEnumerableOfTheoryDataRowType is not null )
1063- valid = iEnumerableOfTheoryDataRowType . IsAssignableFrom ( memberType ) ;
1064-
1065- if ( ! valid && v3 && iAsyncEnumerableOfTheoryDataRowType is not null )
1066- valid = iAsyncEnumerableOfTheoryDataRowType . IsAssignableFrom ( memberType ) ;
1067-
1068- if ( ! valid && v3 && iEnumerableOfTupleType is not null )
1069- valid = iEnumerableOfTupleType . IsAssignableFrom ( memberType ) ;
1070-
1071- if ( ! valid && v3 && iAsyncEnumerableOfTupleType is not null )
1072- valid = iAsyncEnumerableOfTupleType . IsAssignableFrom ( memberType ) ;
1073-
1074- // If still invalid and the member is a class, check whether it implements IEnumerable<T> and verify that T is an array type.
1075- // This ensures the data can be safely converted to IEnumerable<object[]>.
1076- if ( ! valid && memberType . TypeKind == TypeKind . Class )
1077- {
1078- var resolvedIEnumerableTypeArgument = FindTypeArgumentFromIEnumerable ( memberType , compilation ) ;
1079- if ( resolvedIEnumerableTypeArgument is not null )
1080- valid = ( resolvedIEnumerableTypeArgument . TypeKind == TypeKind . Array ) ;
1081- }
987+ var valid = memberType . IsValidDataSource ( v3 , compilation ) ;
1082988
1083989 if ( ! valid )
1084- ReportIncorrectReturnType (
1085- context ,
1086- iEnumerableOfObjectArrayType ,
1087- iAsyncEnumerableOfObjectArrayType ,
1088- iEnumerableOfTheoryDataRowType ,
1089- iAsyncEnumerableOfTheoryDataRowType ,
1090- iEnumerableOfTupleType ,
1091- iAsyncEnumerableOfTupleType ,
1092- attributeSyntax ,
1093- memberProperties ,
1094- memberType
1095- ) ;
990+ ReportIncorrectReturnType ( context , v3 , attributeSyntax , memberProperties , memberType ) ;
1096991
1097992 return valid ;
1098993 }
0 commit comments