From 2d6f777df02545d542a5c23d37799a7f0eadea3c Mon Sep 17 00:00:00 2001 From: Timothy Makkison Date: Thu, 29 Jan 2026 22:51:44 +0000 Subject: [PATCH] perf: use `string.Create` and remove dead code --- .../CodeGenerators/Writers/AttributeWriter.cs | 55 +----------- .../Helpers/FileNameHelper.cs | 83 ++++--------------- 2 files changed, 19 insertions(+), 119 deletions(-) diff --git a/TUnit.Core.SourceGenerator/CodeGenerators/Writers/AttributeWriter.cs b/TUnit.Core.SourceGenerator/CodeGenerators/Writers/AttributeWriter.cs index fe12ca38aa..99e73e8e65 100644 --- a/TUnit.Core.SourceGenerator/CodeGenerators/Writers/AttributeWriter.cs +++ b/TUnit.Core.SourceGenerator/CodeGenerators/Writers/AttributeWriter.cs @@ -74,57 +74,6 @@ public static void WriteAttribute(ICodeWriter sourceCodeWriter, Compilation comp } } - public static void WriteAttributeMetadata(ICodeWriter sourceCodeWriter, Compilation compilation, - AttributeData attributeData, string targetElement, string? targetMemberName, string? targetTypeName, bool includeClassMetadata = false) - { - sourceCodeWriter.Append("new global::TUnit.Core.AttributeMetadata"); - sourceCodeWriter.Append(" { "); - sourceCodeWriter.Append($"Instance = {GetAttributeObjectInitializer(compilation, attributeData)}, "); - sourceCodeWriter.Append($"TargetElement = global::TUnit.Core.TestAttributeTarget.{targetElement}, "); - - if (targetMemberName != null) - { - sourceCodeWriter.Append($"TargetMemberName = \"{targetMemberName}\", "); - } - - if (targetTypeName != null) - { - sourceCodeWriter.Append($"TargetType = typeof({targetTypeName}), "); - } - - // Add ClassMetadata if requested and not a system attribute - if (includeClassMetadata && attributeData.AttributeClass?.ContainingNamespace?.ToDisplayString()?.StartsWith("System") != true) - { - sourceCodeWriter.Append("ClassMetadata = "); - SourceInformationWriter.GenerateClassInformation(sourceCodeWriter, compilation, attributeData.AttributeClass!); - sourceCodeWriter.Append(", "); - } - - if (attributeData.ConstructorArguments.Length > 0) - { - sourceCodeWriter.Append("ConstructorArguments = new object?[] { "); - - foreach (var typedConstant in attributeData.ConstructorArguments) - { - sourceCodeWriter.Append($"{TypedConstantParser.GetRawTypedConstantValue(typedConstant)}, "); - } - - sourceCodeWriter.Append("}, "); - } - - if (attributeData.NamedArguments.Length > 0) - { - sourceCodeWriter.Append("NamedArguments = new global::System.Collections.Generic.Dictionary() { "); - foreach (var namedArg in attributeData.NamedArguments) - { - sourceCodeWriter.Append($"[\"{namedArg.Key}\"] = {TypedConstantParser.GetRawTypedConstantValue(namedArg.Value)}, "); - } - sourceCodeWriter.Append("}, "); - } - - sourceCodeWriter.Append("}"); - } - public static string GetAttributeObjectInitializer(Compilation compilation, AttributeData attributeData) { @@ -195,8 +144,8 @@ public static void WriteAttributeWithoutSyntax(ICodeWriter sourceCodeWriter, Att var attributeName = attributeData.AttributeClass!.GloballyQualified(); // Skip if any constructor arguments contain compiler-generated types - if (attributeData.ConstructorArguments.Any(arg => - arg is { Kind: TypedConstantKind.Type, Value: ITypeSymbol typeSymbol } && + if (attributeData.ConstructorArguments.Any(arg => + arg is { Kind: TypedConstantKind.Type, Value: ITypeSymbol typeSymbol } && typeSymbol.IsCompilerGeneratedType())) { return; diff --git a/TUnit.Core.SourceGenerator/Helpers/FileNameHelper.cs b/TUnit.Core.SourceGenerator/Helpers/FileNameHelper.cs index ed74f6e194..5bcdfaf7ec 100644 --- a/TUnit.Core.SourceGenerator/Helpers/FileNameHelper.cs +++ b/TUnit.Core.SourceGenerator/Helpers/FileNameHelper.cs @@ -8,57 +8,6 @@ namespace TUnit.Core.SourceGenerator.Helpers; /// internal static class FileNameHelper { - /// - /// Generates a deterministic filename for a test class. - /// Format: {Namespace}_{ClassName}_{GenericArgs}.g.cs - /// - /// The type symbol for the test class - /// A deterministic filename like "MyNamespace_MyClass_T.g.cs" - public static string GetDeterministicFileName(INamedTypeSymbol typeSymbol) - { - var sb = new StringBuilder(); - - // Add namespace - if (!typeSymbol.ContainingNamespace.IsGlobalNamespace) - { - sb.Append(SanitizeForFileName(typeSymbol.ContainingNamespace.ToDisplayString())); - sb.Append('_'); - } - - // Add all containing types (outer classes first, then inner classes) - var containingTypes = new List(); - var currentType = typeSymbol; - while (currentType != null) - { - containingTypes.Add(SanitizeForFileName(currentType.Name)); - currentType = currentType.ContainingType; - } - - // Reverse to get outer-to-inner order - containingTypes.Reverse(); - - // Append containing types from outer to inner - for (int i = 0; i < containingTypes.Count; i++) - { - if (i > 0) sb.Append('_'); - sb.Append(containingTypes[i]); - } - - // Add generic type arguments if any (for the innermost type) - if (typeSymbol.TypeArguments.Length > 0) - { - sb.Append('_'); - for (int i = 0; i < typeSymbol.TypeArguments.Length; i++) - { - if (i > 0) sb.Append('_'); - sb.Append(SanitizeForFileName(typeSymbol.TypeArguments[i].Name)); - } - } - - sb.Append(".g.cs"); - return sb.ToString(); - } - /// /// Generates a deterministic filename for a test method. /// Format: {Namespace}_{ClassName}_{MethodName}__{ParameterTypes}.g.cs @@ -132,24 +81,26 @@ public static string GetDeterministicFileNameForMethod(INamedTypeSymbol typeSymb /// private static string SanitizeForFileName(string input) { - var sb = new StringBuilder(input.Length); - - foreach (var c in input) + return string.Create(input.Length, input, (span, input) => { - // Replace invalid filename characters and special type characters with underscore - if (c == '<' || c == '>' || c == ':' || c == '"' || c == '/' || c == '\\' || - c == '|' || c == '?' || c == '*' || c == '.' || c == ',' || c == ' ' || - c == '(' || c == ')' || c == '[' || c == ']' || c == '{' || c == '}') - { - sb.Append('_'); - } - else + var index = 0; + foreach (var c in input) { - sb.Append(c); + // Replace invalid filename characters and special type characters with underscore + if (c == '<' || c == '>' || c == ':' || c == '"' || c == '/' || c == '\\' || + c == '|' || c == '?' || c == '*' || c == '.' || c == ',' || c == ' ' || + c == '(' || c == ')' || c == '[' || c == ']' || c == '{' || c == '}') + { + span[index] = '_'; + } + else + { + span[index] = c; + } + + index++; } - } - - return sb.ToString(); + }); } }