Skip to content

Commit

Permalink
- optimize result type generator
Browse files Browse the repository at this point in the history
  • Loading branch information
ax0l0tl committed Jul 26, 2024
1 parent 6870a45 commit d6caf88
Show file tree
Hide file tree
Showing 16 changed files with 219 additions and 178 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
<Compile Include="$(MSBuildThisFileDirectory)HashCode.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Result.cs" />
<Compile Include="$(MSBuildThisFileDirectory)RoslynExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)RunCount.cs" />
<Compile Include="$(MSBuildThisFileDirectory)SourceProductionContextExtension.cs" />
<Compile Include="$(MSBuildThisFileDirectory)StringExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)SymbolWrapper.cs" />
</ItemGroup>
</Project>
7 changes: 7 additions & 0 deletions Source/FunicularSwitch.Generators.Common/Result.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@

namespace FunicularSwitch.Generators.Common;

public static class GenerationResult

{
public static GenerationResult<T> Create<T>(T? value, EquatableArray<DiagnosticInfo> diagnostics, bool hasValue)
=> new(value, diagnostics, hasValue);
}

public readonly record struct GenerationResult<T>(T? Value, EquatableArray<DiagnosticInfo> Diagnostics, bool HasValue)
{
public static readonly GenerationResult<T> Empty = new(default, ImmutableArray<DiagnosticInfo>.Empty, false);
Expand Down
5 changes: 2 additions & 3 deletions Source/FunicularSwitch.Generators.Common/RoslynExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public static bool Implements(this INamedTypeSymbol symbol, ITypeSymbol interfac
return parentNamespaces.ToSeparatedString(".");
}

static readonly SymbolDisplayFormat FullTypeWithNamespaceDisplayFormat = new(typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces);
static readonly SymbolDisplayFormat FullTypeWithNamespaceDisplayFormat = SymbolWrapper.FullTypeWithNamespaceDisplayFormat;
static readonly SymbolDisplayFormat FullTypeDisplayFormat = new(typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypes);


Expand Down Expand Up @@ -144,8 +144,7 @@ public static string GetFullTypeName(this SemanticModel semanticModel, SyntaxNod
var typeInfo = semanticModel.GetTypeInfo(typeSyntax);
return typeInfo.Type?.ToDisplayString(
new SymbolDisplayFormat(
typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces,
miscellaneousOptions: SymbolDisplayMiscellaneousOptions.UseSpecialTypes
typeQualificationStyle: SymbolWrapper.FullTypeWithNamespaceDisplayFormat.TypeQualificationStyle
)
) ?? typeSyntax.ToString();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Collections.Concurrent;

namespace FunicularSwitch.Generators;
namespace FunicularSwitch.Generators.Common;

static class RunCount
{
Expand Down
39 changes: 39 additions & 0 deletions Source/FunicularSwitch.Generators.Common/SymbolWrapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using Microsoft.CodeAnalysis;

namespace FunicularSwitch.Generators.Common;

public static class SymbolWrapper
{
internal static readonly SymbolDisplayFormat FullTypeWithNamespaceDisplayFormat = new(typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces);

public static SymbolWrapper<T> Create<T>(T symbol) where T : ISymbol => new(symbol);
}

public class SymbolWrapper<T> : IEquatable<SymbolWrapper<T>> where T : ISymbol
{
public SymbolWrapper(T symbol)
{
Symbol = symbol;
FullNameWithNamespace = symbol.ToDisplayString(SymbolWrapper.FullTypeWithNamespaceDisplayFormat);
}

public string FullNameWithNamespace { get; }
public T Symbol { get; }

public bool Equals(SymbolWrapper<T>? other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return FullNameWithNamespace == other.FullNameWithNamespace;
}

public override bool Equals(object? obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
return Equals((SymbolWrapper<T>)obj);
}

public override int GetHashCode() => FullNameWithNamespace.GetHashCode();
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ string Replace(string code, params string[] additionalNamespaces)

var generateFileHint = $"{unionTypeFullNameWithNamespace}";

//var generatorRuns = RunCount.Increase(unionTypeSchema.UnionTypeBaseType.FullTypeNameWithNamespace());

string Replace(string code, params string[] additionalNamespaces)
{
code = code
Expand All @@ -82,6 +84,8 @@ string Replace(string code, params string[] additionalNamespaces)
.Distinct()
.Select(a => $"using {a};")
.ToSeparatedString("\n"));
//code = $"//Generator runs: {generatorRuns}\r\n" + code;

return code;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
{
context.RegisterPostInitializationOutput(ctx =>
{
const string FunicularSwitchFluentAssertionsNamespace = "FunicularSwitch";

var optionAssertionsText = Templates.GenerateFluentAssertionsForTemplates.OptionAssertions.Replace(Generator.TemplateNamespace, FunicularSwitchFluentAssertionsNamespace);
ctx.AddSource($"{FunicularSwitchFluentAssertionsNamespace}.OptionAssertions.g.cs", optionAssertionsText);
var optionAssertionExtensionsText = Templates.GenerateFluentAssertionsForTemplates.OptionAssertionExtensions.Replace(Generator.TemplateNamespace, FunicularSwitchFluentAssertionsNamespace);
ctx.AddSource($"{FunicularSwitchFluentAssertionsNamespace}.OptionAssertionExtensions.g.cs", optionAssertionExtensionsText);
var generateExtensionsForInternalTypeAttributesText = Templates.GenerateFluentAssertionsForTemplates.GenerateExtensionsForInternalTypesAttribute.Replace(Generator.TemplateNamespace, FunicularSwitchFluentAssertionsNamespace);
ctx.AddSource($"{FunicularSwitchFluentAssertionsNamespace}.GenerateExtensionsForInternalTypesAttribute.g.cs", generateExtensionsForInternalTypeAttributesText);
const string funicularSwitchFluentAssertionsNamespace = "FunicularSwitch";
var optionAssertionsText = Templates.GenerateFluentAssertionsForTemplates.OptionAssertions.Replace(Generator.TemplateNamespace, funicularSwitchFluentAssertionsNamespace);
ctx.AddSource($"{funicularSwitchFluentAssertionsNamespace}.OptionAssertions.g.cs", optionAssertionsText);
var optionAssertionExtensionsText = Templates.GenerateFluentAssertionsForTemplates.OptionAssertionExtensions.Replace(Generator.TemplateNamespace, funicularSwitchFluentAssertionsNamespace);
ctx.AddSource($"{funicularSwitchFluentAssertionsNamespace}.OptionAssertionExtensions.g.cs", optionAssertionExtensionsText);
var generateExtensionsForInternalTypeAttributesText = Templates.GenerateFluentAssertionsForTemplates.GenerateExtensionsForInternalTypesAttribute.Replace(Generator.TemplateNamespace, funicularSwitchFluentAssertionsNamespace);
ctx.AddSource($"{funicularSwitchFluentAssertionsNamespace}.GenerateExtensionsForInternalTypesAttribute.g.cs", generateExtensionsForInternalTypeAttributesText);
});

var refAssemblies = context.CompilationProvider
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

<!--#region adapt versions here-->
<MajorVersion>4</MajorVersion>
<MinorAndPatchVersion>1.0</MinorAndPatchVersion>
<MinorAndPatchVersion>1.1</MinorAndPatchVersion>
<!--#endregion-->

<AssemblyVersion>$(MajorVersion).0.0</AssemblyVersion>
Expand Down
38 changes: 1 addition & 37 deletions Source/FunicularSwitch.Generators/GeneratorHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ static class GeneratorHelper
}
}

Return:
Return:
return hasAttribute ? classDeclarationSyntax : null;
}

Expand All @@ -39,40 +39,4 @@ public static T GetNamedEnumAttributeArgument<T>(this AttributeSyntax attribute,

return (T)Enum.Parse(typeof(T), memberAccess.Name.ToString());
}
}

public class SymbolWrapper
{
internal static readonly SymbolDisplayFormat FullTypeWithNamespaceDisplayFormat = new(typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces);

public static SymbolWrapper<T> Create<T>(T symbol) where T : ISymbol => new(symbol);
}

public class SymbolWrapper<T> : IEquatable<SymbolWrapper<T>> where T : ISymbol
{
public SymbolWrapper(T symbol)
{
Symbol = symbol;
FullNameWithNamespace = symbol.ToDisplayString(SymbolWrapper.FullTypeWithNamespaceDisplayFormat);
}

public string FullNameWithNamespace { get; }
public T Symbol { get; }

public bool Equals(SymbolWrapper<T>? other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return FullNameWithNamespace == other.FullNameWithNamespace;
}

public override bool Equals(object? obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
return Equals((SymbolWrapper<T>)obj);
}

public override int GetHashCode() => FullNameWithNamespace.GetHashCode();
}
38 changes: 21 additions & 17 deletions Source/FunicularSwitch.Generators/ResultType/Generator.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System.Collections.Immutable;
using FunicularSwitch.Generators.Common;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;

namespace FunicularSwitch.Generators.ResultType;

Expand All @@ -11,28 +10,32 @@ static class Generator
const string TemplateResultTypeName = "MyResult";
const string TemplateErrorTypeName = "MyError";

public static IEnumerable<(string filename, string source)> Emit(ResultTypeSchema resultTypeSchema, Action<Diagnostic> reportDiagnostic, CancellationToken cancellationToken)
public static IEnumerable<(string filename, string source)> Emit(
ResultTypeSchema resultTypeSchema,
MergeMethod? mergeErrorMethod,
ExceptionToErrorMethod? exceptionToErrorMethod,
Action<Diagnostic> reportDiagnostic,
CancellationToken cancellationToken)
{
var resultTypeName = resultTypeSchema.ResultType.Identifier.ToString();
var resultTypeNamespace = resultTypeSchema.ResultType.GetContainingNamespace();
var resultTypeName = resultTypeSchema.ResultTypeName.Name;
var resultTypeNamespace = resultTypeSchema.ResultTypeNamespace;
if (resultTypeNamespace == null)
{
reportDiagnostic(Diagnostics.ResultTypeInGlobalNamespace($"Result type {resultTypeName} is placed in global namespace, this is not supported. Please put {resultTypeName} into non empty namespace.", resultTypeSchema.ResultType.GetLocation()));
reportDiagnostic(Diagnostics.ResultTypeInGlobalNamespace($"Result type {resultTypeName} is placed in global namespace, this is not supported. Please put {resultTypeName} into non empty namespace.", resultTypeSchema.ResultTypeLocation?.ToLocation() ?? Location.None));
yield break;
}

var publicModifier = resultTypeSchema.ResultType.Modifiers.FirstOrDefault(t => t.Text == SyntaxFactory.Token(SyntaxKind.PublicKeyword).Text);
var isValueType = resultTypeSchema.ErrorType.IsValueType;
var errorTypeNamespace = resultTypeSchema.ErrorType.GetFullNamespace();
var isValueType = resultTypeSchema.ErrorType.Symbol.IsValueType;
var errorTypeNamespace = resultTypeSchema.ErrorType.Symbol.GetFullNamespace();

string Replace(string code, IReadOnlyCollection<string> additionalNamespaces, string genericTypeParameterNameForHandleExceptions)
{
code = code
.Replace($"namespace {TemplateNamespace}", $"namespace {resultTypeNamespace}")
.Replace(TemplateResultTypeName, resultTypeName)
.Replace(TemplateErrorTypeName, resultTypeSchema.ErrorType.Name);
.Replace(TemplateErrorTypeName, resultTypeSchema.ErrorType.Symbol.Name);

if (publicModifier == default)
if (resultTypeSchema.IsInternal)
code = code
.Replace("public abstract partial", "abstract partial")
.Replace("public static partial", "static partial");
Expand All @@ -41,11 +44,10 @@ string Replace(string code, IReadOnlyCollection<string> additionalNamespaces, st
code = code
.Replace("//additional using directives", additionalNamespaces.Distinct().Select(a => $"using {a};").ToSeparatedString("\n"));

var genericErrorFactoryMethod = resultTypeSchema.ExceptionToErrorMethod;
if (genericErrorFactoryMethod != null)
if (exceptionToErrorMethod != null)
{
code = code.Replace("throw; //createGenericErrorResult",
$"return {resultTypeName}.Error<{genericTypeParameterNameForHandleExceptions}>({genericErrorFactoryMethod.FullMethodName}(e));");
$"return {resultTypeName}.Error<{genericTypeParameterNameForHandleExceptions}>({exceptionToErrorMethod.FullMethodName}(e));");
}

return code;
Expand All @@ -55,23 +57,25 @@ string Replace(string code, IReadOnlyCollection<string> additionalNamespaces, st
if (errorTypeNamespace != resultTypeNamespace && errorTypeNamespace != null)
additionalNamespaces.Add(errorTypeNamespace);

var generateFileHint = $"{resultTypeNamespace}.{resultTypeSchema.ResultType.QualifiedName()}";
var generateFileHint = $"{resultTypeNamespace}.{resultTypeSchema.ResultTypeName}";

var resultTypeImpl = Replace(Templates.ResultTypeTemplates.ResultType, additionalNamespaces, "T1");

//resultTypeImpl = $"//Generator runs: {RunCount.Increase(generateFileHint)}\r\n" + resultTypeImpl;

yield return ($"{generateFileHint}.g.cs", resultTypeImpl);

if (resultTypeSchema.MergeMethod != null)
if (mergeErrorMethod != null)
{
var mergeMethodNamespace = resultTypeSchema.MergeMethod.Match(staticMerge: m => m.Namespace, errorTypeMember: _ => "");
var mergeMethodNamespace = mergeErrorMethod.Match(staticMerge: m => m.Namespace, errorTypeMember: _ => "");
if (!string.IsNullOrEmpty(mergeMethodNamespace) && mergeMethodNamespace != resultTypeNamespace)
additionalNamespaces.Add(mergeMethodNamespace!);

var mergeCode = Replace(
Templates.ResultTypeTemplates.ResultTypeWithMerge
.Replace("//generated aggregate methods", GenerateAggregateMethods(10))
.Replace("//generated aggregate extension methods", GenerateAggregateExtensionMethods(10, isValueType))
.Replace("Merge__MemberOrExtensionMethod", resultTypeSchema.MergeMethod.MethodName),
.Replace("Merge__MemberOrExtensionMethod", mergeErrorMethod.MethodName),
additionalNamespaces,
"T"
);
Expand Down
Loading

0 comments on commit d6caf88

Please sign in to comment.