Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions TUnit.Analyzers/TestDataAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -853,8 +853,10 @@ private void CheckDataGenerator(SymbolAnalysisContext context,
if (typedInterface != null)
{
// If the type is a tuple, extract its elements
if (typedInterface.TypeArguments.Length == 1 &&
typedInterface.TypeArguments[0] is INamedTypeSymbol { IsTupleType: true } tupleType)
if (typedInterface.TypeArguments is
[
INamedTypeSymbol { IsTupleType: true } tupleType
])
{
typeArguments = ImmutableArray.CreateRange(tupleType.TupleElements.Select(x => x.Type));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ public static bool CanOptimizeTypedDataSource(AttributeData dataSourceAttribute,
}

// For multiple parameters, check if data source provides a matching tuple
if (dataSourceType is INamedTypeSymbol namedType &&
namedType.IsTupleType &&
if (dataSourceType is INamedTypeSymbol { IsTupleType: true } namedType &&
namedType.TupleElements.Length == testMethod.Parameters.Length)
{
for (int i = 0; i < testMethod.Parameters.Length; i++)
Expand Down Expand Up @@ -71,7 +70,7 @@ public static void GenerateOptimizedDataSourceAccess(
writer.AppendLine("var value = await dataFunc();");
writer.AppendLine($"var args = new object?[] {{ value }};");
}
else if (dataSourceType is INamedTypeSymbol namedType && namedType.IsTupleType)
else if (dataSourceType is INamedTypeSymbol { IsTupleType: true } namedType)
{
// Tuple - decompose without boxing
writer.AppendLine("var tuple = await dataFunc();");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,7 @@ public static void WriteAttributeWithoutSyntax(ICodeWriter sourceCodeWriter, Att

// Skip if any constructor arguments contain compiler-generated types
if (attributeData.ConstructorArguments.Any(arg =>
arg.Kind == TypedConstantKind.Type &&
arg.Value is ITypeSymbol typeSymbol &&
arg is { Kind: TypedConstantKind.Type, Value: ITypeSymbol typeSymbol } &&
typeSymbol.IsCompilerGeneratedType()))
{
return;
Expand Down
2 changes: 1 addition & 1 deletion TUnit.Core.SourceGenerator/Extensions/TypeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ public static string GloballyQualified(this ISymbol typeSymbol)
{
// Handle open generic types where type arguments are type parameters
// This prevents invalid C# like List<T>, Dictionary<TKey, TValue>, T? where type parameters are undefined
if (typeSymbol is INamedTypeSymbol namedTypeSymbol && namedTypeSymbol.IsGenericType)
if (typeSymbol is INamedTypeSymbol { IsGenericType: true } namedTypeSymbol)
{
// Check if this is an unbound generic type or has type parameter arguments
bool hasTypeParameters = namedTypeSymbol.TypeArguments.Any(t => t.TypeKind == TypeKind.TypeParameter);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -245,8 +245,7 @@ private static int GetHookOrder(AttributeData attribute)
{
var hookExecutorAttribute = methodSymbol.GetAttributes()
.FirstOrDefault(a => a.AttributeClass?.Name == "HookExecutorAttribute" ||
(a.AttributeClass?.IsGenericType == true &&
a.AttributeClass?.ConstructedFrom?.Name == "HookExecutorAttribute"));
a.AttributeClass is { IsGenericType: true, ConstructedFrom.Name: "HookExecutorAttribute" });

if (hookExecutorAttribute == null)
{
Expand Down
44 changes: 26 additions & 18 deletions TUnit.Core.SourceGenerator/Generators/TestMetadataGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -728,7 +728,7 @@
if (dataSourceMethod == null)
{
// Still generate the attribute even if method not found - it will fail at runtime with proper error
// Use CodeGenerationHelpers to properly handle any generics on the attribute

Check warning on line 731 in TUnit.Core.SourceGenerator/Generators/TestMetadataGenerator.cs

View workflow job for this annotation

GitHub Actions / modularpipeline (macos-latest)

Possible null reference argument for parameter 'name' in 'ImmutableArray<ISymbol> INamespaceOrTypeSymbol.GetMembers(string name)'.

Check warning on line 731 in TUnit.Core.SourceGenerator/Generators/TestMetadataGenerator.cs

View workflow job for this annotation

GitHub Actions / modularpipeline (macos-latest)

Possible null reference argument for parameter 'name' in 'ImmutableArray<ISymbol> INamespaceOrTypeSymbol.GetMembers(string name)'.

Check warning on line 731 in TUnit.Core.SourceGenerator/Generators/TestMetadataGenerator.cs

View workflow job for this annotation

GitHub Actions / modularpipeline (ubuntu-latest)

Possible null reference argument for parameter 'name' in 'ImmutableArray<ISymbol> INamespaceOrTypeSymbol.GetMembers(string name)'.

Check warning on line 731 in TUnit.Core.SourceGenerator/Generators/TestMetadataGenerator.cs

View workflow job for this annotation

GitHub Actions / modularpipeline (ubuntu-latest)

Possible null reference argument for parameter 'name' in 'ImmutableArray<ISymbol> INamespaceOrTypeSymbol.GetMembers(string name)'.

Check warning on line 731 in TUnit.Core.SourceGenerator/Generators/TestMetadataGenerator.cs

View workflow job for this annotation

GitHub Actions / modularpipeline (ubuntu-latest)

Possible null reference argument for parameter 'name' in 'ImmutableArray<ISymbol> INamespaceOrTypeSymbol.GetMembers(string name)'.

Check warning on line 731 in TUnit.Core.SourceGenerator/Generators/TestMetadataGenerator.cs

View workflow job for this annotation

GitHub Actions / modularpipeline (windows-latest)

Possible null reference argument for parameter 'name' in 'ImmutableArray<ISymbol> INamespaceOrTypeSymbol.GetMembers(string name)'.

Check warning on line 731 in TUnit.Core.SourceGenerator/Generators/TestMetadataGenerator.cs

View workflow job for this annotation

GitHub Actions / modularpipeline (windows-latest)

Possible null reference argument for parameter 'name' in 'ImmutableArray<ISymbol> INamespaceOrTypeSymbol.GetMembers(string name)'.
var generatedCode = CodeGenerationHelpers.GenerateAttributeInstantiation(attr);
writer.AppendLine($"{generatedCode},");
return;
Expand Down Expand Up @@ -979,7 +979,7 @@
private static bool IsAsyncEnumerable(ITypeSymbol type)
{
// Check if the type itself is an IAsyncEnumerable<T>
if (type is INamedTypeSymbol namedType && namedType.IsGenericType &&
if (type is INamedTypeSymbol { IsGenericType: true } namedType &&
namedType.OriginalDefinition.ToDisplayString() == "System.Collections.Generic.IAsyncEnumerable<T>")
{
return true;
Expand Down Expand Up @@ -1560,7 +1560,7 @@
else
{
// Count required parameters (those without default values, excluding CancellationToken and params parameters)
var requiredParamCount = parametersFromArgs.Count(p => !p.HasExplicitDefaultValue && !p.IsOptional && !p.IsParams);
var requiredParamCount = parametersFromArgs.Count(p => !p.HasExplicitDefaultValue && p is { IsOptional: false, IsParams: false });

// Generate runtime logic to handle variable argument counts
writer.AppendLine("switch (args.Length)");
Expand Down Expand Up @@ -1657,7 +1657,7 @@
else
{
// Count required parameters (those without default values, excluding CancellationToken and params parameters)
var requiredParamCount = parametersFromArgs.Count(p => !p.HasExplicitDefaultValue && !p.IsOptional && !p.IsParams);
var requiredParamCount = parametersFromArgs.Count(p => !p.HasExplicitDefaultValue && p is { IsOptional: false, IsParams: false });

// Generate runtime logic to handle variable argument counts
writer.AppendLine("switch (args.Length)");
Expand Down Expand Up @@ -1907,7 +1907,7 @@
// Look for ProceedOnFailure property in named arguments
foreach (var namedArg in attributeData.NamedArguments)
{
if (namedArg.Key == "ProceedOnFailure" && namedArg.Value.Value is bool proceedOnFailure)
if (namedArg is { Key: "ProceedOnFailure", Value.Value: bool proceedOnFailure })
{
return proceedOnFailure;
}
Expand Down Expand Up @@ -2396,7 +2396,7 @@

// For generic classes with non-generic methods, don't include method Arguments here
// They will be processed separately with InferClassTypesFromMethodArguments
if (!(testMethod.IsGenericType && !testMethod.IsGenericMethod))
if (!(testMethod is { IsGenericType: true, IsGenericMethod: false }))
{
allArgumentsAttributes.AddRange(methodArgumentsAttributes);
}
Expand Down Expand Up @@ -2454,7 +2454,7 @@

// Handle generic classes with non-generic methods that have method-level Arguments
// These were skipped in the main loop and need special processing
if (testMethod.IsGenericType && !testMethod.IsGenericMethod && methodArgumentsAttributes.Count > 0)
if (testMethod is { IsGenericType: true, IsGenericMethod: false } && methodArgumentsAttributes.Count > 0)
{
foreach (var methodArgAttr in methodArgumentsAttributes)
{
Expand Down Expand Up @@ -2717,7 +2717,7 @@
}

// Process class-level Arguments attributes for non-generic classes with parameterized constructors
if (!testMethod.IsGenericType && !testMethod.IsGenericMethod)
if (testMethod is { IsGenericType: false, IsGenericMethod: false })
{
var nonGenericClassArguments = testMethod.TypeSymbol.GetAttributes()
.Where(a => a.AttributeClass?.Name == "ArgumentsAttribute")
Expand Down Expand Up @@ -2937,7 +2937,7 @@
continue;

// Check if the method parameter type is a class generic type parameter
if (methodParam.Type is ITypeParameterSymbol typeParam && typeParam.DeclaringMethod == null)
if (methodParam.Type is ITypeParameterSymbol { DeclaringMethod: null } typeParam)
{
// This is a class type parameter
var paramName = typeParam.Name;
Expand Down Expand Up @@ -2997,12 +2997,12 @@

private static bool ContainsClassTypeParameter(ITypeSymbol type, INamedTypeSymbol classSymbol)
{
if (type is ITypeParameterSymbol typeParam && typeParam.DeclaringMethod == null)
if (type is ITypeParameterSymbol { DeclaringMethod: null })
{
return true;
}

if (type is INamedTypeSymbol namedType && namedType.IsGenericType)
if (type is INamedTypeSymbol { IsGenericType: true } namedType)
{
return namedType.TypeArguments.Any(ta => ContainsClassTypeParameter(ta, classSymbol));
}
Expand All @@ -3012,7 +3012,7 @@

private static void MapGenericTypeArguments(ITypeSymbol paramType, ITypeSymbol argType, INamedTypeSymbol classSymbol, Dictionary<string, ITypeSymbol> inferredTypes)
{
if (paramType is ITypeParameterSymbol typeParam && typeParam.DeclaringMethod == null)
if (paramType is ITypeParameterSymbol { DeclaringMethod: null } typeParam)
{
if (!inferredTypes.ContainsKey(typeParam.Name))
{
Expand Down Expand Up @@ -3274,7 +3274,10 @@
}

// Multiple type parameters - check for tuple
if (typeArgs.Length == 1 && typeArgs[0] is INamedTypeSymbol { IsTupleType: true } tupleType)
if (typeArgs is
[
INamedTypeSymbol { IsTupleType: true } tupleType
])
{
if (tupleType.TupleElements.Length == method.TypeParameters.Length)
{
Expand All @@ -3300,7 +3303,10 @@
}

// Multiple type parameters - check for tuple
if (typeArgs.Length == 1 && typeArgs[0] is INamedTypeSymbol { IsTupleType: true } tupleType)
if (typeArgs is
[
INamedTypeSymbol { IsTupleType: true } tupleType
])
{
if (tupleType.TupleElements.Length == classTypeParams.Length)
{
Expand All @@ -3320,7 +3326,10 @@
var totalGenericParams = method.TypeParameters.Length + method.ContainingType.TypeParameters.Length;

// Check if the data source provides types for all parameters
if (typeArgs.Length == 1 && typeArgs[0] is INamedTypeSymbol { IsTupleType: true } tupleType)
if (typeArgs is
[
INamedTypeSymbol { IsTupleType: true } tupleType
])
{
if (tupleType.TupleElements.Length == totalGenericParams)
{
Expand Down Expand Up @@ -3685,7 +3694,7 @@
if (hasParameterizedConstructor)
{
// For classes with constructor parameters, use the specific constructor arguments from the Arguments attribute
if (specificArgumentsAttribute != null && specificArgumentsAttribute.ConstructorArguments.Length > 0 &&
if (specificArgumentsAttribute is { ConstructorArguments.Length: > 0 } &&
specificArgumentsAttribute.ConstructorArguments[0].Kind == TypedConstantKind.Array)
{
var argumentValues = specificArgumentsAttribute.ConstructorArguments[0].Values;
Expand Down Expand Up @@ -3876,7 +3885,7 @@

// For combined generic class + generic method scenarios, also include method-level Arguments
// that provide method parameters (different from the class-level specificArgumentsAttribute)
if (testMethod.IsGenericType && testMethod.IsGenericMethod)
if (testMethod is { IsGenericType: true, IsGenericMethod: true })
{
var additionalMethodDataSources = methodSymbol.GetAttributes()
.Where(a => a.AttributeClass?.Name == "ArgumentsAttribute" && !AreSameAttribute(a, specificArgumentsAttribute))
Expand Down Expand Up @@ -4222,8 +4231,7 @@
// For classes with constructor parameters, check if we have Arguments attribute
var isArgumentsAttribute = classDataSourceAttribute?.AttributeClass?.Name == "ArgumentsAttribute";

if (isArgumentsAttribute && classDataSourceAttribute != null &&
classDataSourceAttribute.ConstructorArguments.Length > 0 &&
if (isArgumentsAttribute && classDataSourceAttribute is { ConstructorArguments.Length: > 0 } &&
classDataSourceAttribute.ConstructorArguments[0].Kind == TypedConstantKind.Array)
{
var argumentValues = classDataSourceAttribute.ConstructorArguments[0].Values;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public override async IAsyncEnumerable<Func<Task<T>>> GetTypedDataRowsAsync(Data
{
// Inject properties into the data source attribute itself if we have context
// This is needed for custom data sources that have their own data source properties
if (dataGeneratorMetadata.TestBuilderContext != null && dataGeneratorMetadata.TestInformation != null)
if (dataGeneratorMetadata is { TestBuilderContext: not null, TestInformation: not null })
{
await PropertyInjectionService.InjectPropertiesIntoObjectAsync(this,
dataGeneratorMetadata.TestBuilderContext.Current.ObjectBag,
Expand Down Expand Up @@ -41,7 +41,7 @@ public abstract class AsyncDataSourceGeneratorAttribute<
public override async IAsyncEnumerable<Func<Task<(T1, T2)>>> GetTypedDataRowsAsync(DataGeneratorMetadata dataGeneratorMetadata)
{
// Inject properties into the data source attribute itself if we have context
if (dataGeneratorMetadata.TestBuilderContext != null && dataGeneratorMetadata.TestInformation != null)
if (dataGeneratorMetadata is { TestBuilderContext: not null, TestInformation: not null })
{
await PropertyInjectionService.InjectPropertiesIntoObjectAsync(this,
dataGeneratorMetadata.TestBuilderContext.Current.ObjectBag,
Expand Down Expand Up @@ -72,7 +72,7 @@ public abstract class AsyncDataSourceGeneratorAttribute<
public override async IAsyncEnumerable<Func<Task<(T1, T2, T3)>>> GetTypedDataRowsAsync(DataGeneratorMetadata dataGeneratorMetadata)
{
// Inject properties into the data source attribute itself if we have context
if (dataGeneratorMetadata.TestBuilderContext != null && dataGeneratorMetadata.TestInformation != null)
if (dataGeneratorMetadata is { TestBuilderContext: not null, TestInformation: not null })
{
await PropertyInjectionService.InjectPropertiesIntoObjectAsync(this,
dataGeneratorMetadata.TestBuilderContext.Current.ObjectBag,
Expand Down Expand Up @@ -105,7 +105,7 @@ public abstract class AsyncDataSourceGeneratorAttribute<
public override async IAsyncEnumerable<Func<Task<(T1, T2, T3, T4)>>> GetTypedDataRowsAsync(DataGeneratorMetadata dataGeneratorMetadata)
{
// Inject properties into the data source attribute itself if we have context
if (dataGeneratorMetadata.TestBuilderContext != null && dataGeneratorMetadata.TestInformation != null)
if (dataGeneratorMetadata is { TestBuilderContext: not null, TestInformation: not null })
{
await PropertyInjectionService.InjectPropertiesIntoObjectAsync(this,
dataGeneratorMetadata.TestBuilderContext.Current.ObjectBag,
Expand Down Expand Up @@ -140,7 +140,7 @@ public abstract class AsyncDataSourceGeneratorAttribute<
public override async IAsyncEnumerable<Func<Task<(T1, T2, T3, T4, T5)>>> GetTypedDataRowsAsync(DataGeneratorMetadata dataGeneratorMetadata)
{
// Inject properties into the data source attribute itself if we have context
if (dataGeneratorMetadata.TestBuilderContext != null && dataGeneratorMetadata.TestInformation != null)
if (dataGeneratorMetadata is { TestBuilderContext: not null, TestInformation: not null })
{
await PropertyInjectionService.InjectPropertiesIntoObjectAsync(this,
dataGeneratorMetadata.TestBuilderContext.Current.ObjectBag,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public abstract class AsyncUntypedDataSourceGeneratorAttribute : Attribute, IAsy

public async IAsyncEnumerable<Func<Task<object?[]?>>> GenerateAsync(DataGeneratorMetadata dataGeneratorMetadata)
{
if (dataGeneratorMetadata.TestBuilderContext != null && dataGeneratorMetadata.TestInformation != null)
if (dataGeneratorMetadata is { TestBuilderContext: not null, TestInformation: not null })
{
await PropertyInjectionService.InjectPropertiesIntoObjectAsync(this, dataGeneratorMetadata.TestBuilderContext.Current.ObjectBag, dataGeneratorMetadata.TestInformation, dataGeneratorMetadata.TestBuilderContext.Current.Events);
}
Expand Down
14 changes: 0 additions & 14 deletions TUnit.Core/Extensions/ClassConstructorExtensions.cs

This file was deleted.

Loading
Loading