@@ -63,6 +63,7 @@ public sealed class ThinktectureRuntimeExtensionsAnalyzer : DiagnosticAnalyzer
6363 DiagnosticsDescriptors . AdHocUnionMustHaveAtLeastTwoMemberTypes ,
6464 DiagnosticsDescriptors . ComparisonAndEqualityOperatorsMismatch ,
6565 DiagnosticsDescriptors . UseSwitchMapWithStaticLambda ,
66+ DiagnosticsDescriptors . TypeParamRefRequiresNotnullConstraint ,
6667 ] ;
6768
6869 /// <inheritdoc />
@@ -604,6 +605,9 @@ private static void ValidateKeyedValueObject(
604605 if ( keyType . TypeKind == TypeKind . Error )
605606 return ;
606607
608+ if ( ReportIfTypeParamRefMissingNotnullConstraint ( context , keyType , type , tdsLocation ) )
609+ return ;
610+
607611 if ( keyType . NullableAnnotation == NullableAnnotation . Annotated || keyType . SpecialType == SpecialType . System_Nullable_T )
608612 {
609613 ReportDiagnostic (
@@ -1091,6 +1095,9 @@ private static void ValidateKeyedSmartEnum(
10911095 if ( keyType . TypeKind == TypeKind . Error )
10921096 return ;
10931097
1098+ if ( ReportIfTypeParamRefMissingNotnullConstraint ( context , keyType , enumType , tdsLocation ) )
1099+ return ;
1100+
10941101 if ( keyType . NullableAnnotation == NullableAnnotation . Annotated || keyType . SpecialType == SpecialType . System_Nullable_T )
10951102 {
10961103 ReportDiagnostic ( context , DiagnosticsDescriptors . SmartEnumKeyShouldNotBeNullable , tdsLocation ) ;
@@ -1386,6 +1393,41 @@ private static void ReportDiagnostic(SymbolAnalysisContext context, DiagnosticDe
13861393 context . ReportDiagnostic ( Diagnostic . Create ( descriptor , location ) ) ;
13871394 }
13881395
1396+ private static bool ReportIfTypeParamRefMissingNotnullConstraint (
1397+ in SymbolAnalysisContext context ,
1398+ ITypeSymbol keyType ,
1399+ INamedTypeSymbol type ,
1400+ Location tdsLocation )
1401+ {
1402+ var maxTypeParamRefIndex = keyType . GetMaxTypeParamRefIndex ( ) ;
1403+
1404+ if ( maxTypeParamRefIndex <= 0 || type . Arity == 0 || maxTypeParamRefIndex > type . Arity )
1405+ return false ;
1406+
1407+ var ( resolved , _) = keyType . ResolveTypeParamRefs ( type . TypeParameters , context . Compilation ) ;
1408+
1409+ if ( resolved is ITypeParameterSymbol { HasNotNullConstraint : false , HasReferenceTypeConstraint : false , HasValueTypeConstraint : false } resolvedTypeParam
1410+ && ! HasNonNullableTypeConstraint ( resolvedTypeParam ) )
1411+ {
1412+ var properties = ImmutableDictionary . Create < string , string ? > ( ) . Add ( "TypeParamName" , resolvedTypeParam . Name ) ;
1413+ ReportDiagnostic ( context , DiagnosticsDescriptors . TypeParamRefRequiresNotnullConstraint , tdsLocation , properties , resolvedTypeParam . Name , type . ToMinimallyQualifiedDisplayString ( ) ) ;
1414+ return true ;
1415+ }
1416+
1417+ return false ;
1418+ }
1419+
1420+ private static bool HasNonNullableTypeConstraint ( ITypeParameterSymbol typeParam )
1421+ {
1422+ foreach ( var constraintType in typeParam . ConstraintTypes )
1423+ {
1424+ if ( constraintType . NullableAnnotation == NullableAnnotation . NotAnnotated )
1425+ return true ;
1426+ }
1427+
1428+ return false ;
1429+ }
1430+
13891431 private static void ReportDiagnostic ( OperationAnalysisContext context , DiagnosticDescriptor descriptor , Location location , string arg0 )
13901432 {
13911433 context . ReportDiagnostic ( Diagnostic . Create ( descriptor , location , arg0 ) ) ;
@@ -1401,6 +1443,11 @@ private static void ReportDiagnostic(in SymbolAnalysisContext context, Diagnosti
14011443 context . ReportDiagnostic ( Diagnostic . Create ( descriptor , location , arg0 , arg1 ) ) ;
14021444 }
14031445
1446+ private static void ReportDiagnostic ( in SymbolAnalysisContext context , DiagnosticDescriptor descriptor , Location location , ImmutableDictionary < string , string ? > properties , string arg0 , string arg1 )
1447+ {
1448+ context . ReportDiagnostic ( Diagnostic . Create ( descriptor , location , properties , arg0 , arg1 ) ) ;
1449+ }
1450+
14041451 private static void ReportDiagnostic ( SymbolAnalysisContext context , DiagnosticDescriptor descriptor , Location location , string arg0 , string arg1 , string arg2 )
14051452 {
14061453 context . ReportDiagnostic ( Diagnostic . Create ( descriptor , location , arg0 , arg1 , arg2 ) ) ;
0 commit comments