From ac50730dfdb4fea6c6bfb6e09f10fd0733fa3995 Mon Sep 17 00:00:00 2001 From: Stanislav Silin Date: Sat, 4 Feb 2023 17:07:22 +0200 Subject: [PATCH] Fix source generation for type duplicates. --- .../DapperJsonSourceGenerator.cs | 76 ++++++++++--------- ...ypeMappingDuplicatesAsHandled.verified.txt | 3 + src/Dapper.Json.Tests/MainTest.cs | 16 +++- 3 files changed, 60 insertions(+), 35 deletions(-) create mode 100644 src/Dapper.Json.Tests/MainTest.TypeMappingDuplicatesAsHandled.verified.txt diff --git a/src/Dapper.Json.SourceGenerator/DapperJsonSourceGenerator.cs b/src/Dapper.Json.SourceGenerator/DapperJsonSourceGenerator.cs index 1c5738d..bda4ff5 100644 --- a/src/Dapper.Json.SourceGenerator/DapperJsonSourceGenerator.cs +++ b/src/Dapper.Json.SourceGenerator/DapperJsonSourceGenerator.cs @@ -1,4 +1,4 @@ -using System; +using System.Collections.Immutable; using System.Linq; using System.Threading; using DuckInterface; @@ -18,45 +18,33 @@ public void Initialize(IncrementalGeneratorInitializationContext context) var jsons = context.SyntaxProvider .CreateSyntaxProvider(SelectJsonT, Transform); - var combined = jsons.Combine(jsonType); - context.RegisterImplementationSourceOutput(combined, Generate); - } + var combined = jsons.Collect() + .Combine(jsonType); - private ITypeSymbol Transform(GeneratorSyntaxContext context, CancellationToken cancellationToken) - { - switch (context.Node) - { - case GenericNameSyntax: - return context.SemanticModel.GetTypeInfo(context.Node, cancellationToken).Type; - case MemberAccessExpressionSyntax memberAccess: - var symbolInfo = context.SemanticModel.GetSymbolInfo(memberAccess.Name, cancellationToken); - if (symbolInfo.Symbol is IMethodSymbol methodSymbol) - { - return methodSymbol.ReturnType; - } - return null; - default: - return null; - } + context.RegisterImplementationSourceOutput(combined, Generate); } - private void Generate(SourceProductionContext context, (ITypeSymbol Target, INamedTypeSymbol JsonType) input) + private void Generate(SourceProductionContext context, + (ImmutableArray Targets, INamedTypeSymbol JsonType) input) { - var (target, jsonType) = input; - if (target is not INamedTypeSymbol namedTypeSymbol || - !SymbolEqualityComparer.Default.Equals(namedTypeSymbol.ConstructedFrom, jsonType)) + var (targets, jsonType) = input; + var uniqueTargets = targets.Distinct(SymbolEqualityComparer.Default); + foreach (var target in uniqueTargets) { - return; - } + if (target is not INamedTypeSymbol namedTypeSymbol || + !SymbolEqualityComparer.Default.Equals(namedTypeSymbol.ConstructedFrom, jsonType)) + { + return; + } - var type = namedTypeSymbol.TypeArguments.First(); - if (type is ITypeParameterSymbol) - { - return; - } + var type = namedTypeSymbol.TypeArguments.First(); + if (type is ITypeParameterSymbol) + { + return; + } - var safeTypeName = type.ToSafeGlobalName(); - var source = @$"using System; + var safeTypeName = type.ToSafeGlobalName(); + var source = @$"using System; namespace Dapper.Json {{ @@ -70,7 +58,27 @@ public static void Init() }} }} "; - context.AddSource($"Dapper.Json.{safeTypeName}.g.cs", source.ToSourceText()); + context.AddSource($"Dapper.Json.{safeTypeName}.g.cs", source.ToSourceText()); + } + } + + private ITypeSymbol Transform(GeneratorSyntaxContext context, CancellationToken cancellationToken) + { + switch (context.Node) + { + case GenericNameSyntax: + return context.SemanticModel.GetTypeInfo(context.Node, cancellationToken).Type; + case MemberAccessExpressionSyntax memberAccess: + var symbolInfo = context.SemanticModel.GetSymbolInfo(memberAccess.Name, cancellationToken); + if (symbolInfo.Symbol is IMethodSymbol methodSymbol) + { + return methodSymbol.ReturnType; + } + + return null; + default: + return null; + } } private bool SelectJsonT(SyntaxNode syntaxNode, CancellationToken token) diff --git a/src/Dapper.Json.Tests/MainTest.TypeMappingDuplicatesAsHandled.verified.txt b/src/Dapper.Json.Tests/MainTest.TypeMappingDuplicatesAsHandled.verified.txt new file mode 100644 index 0000000..ca8baff --- /dev/null +++ b/src/Dapper.Json.Tests/MainTest.TypeMappingDuplicatesAsHandled.verified.txt @@ -0,0 +1,3 @@ +[ + Role +] \ No newline at end of file diff --git a/src/Dapper.Json.Tests/MainTest.cs b/src/Dapper.Json.Tests/MainTest.cs index ff1184e..66f381d 100644 --- a/src/Dapper.Json.Tests/MainTest.cs +++ b/src/Dapper.Json.Tests/MainTest.cs @@ -66,7 +66,7 @@ public async Task TypeMappingForGenericsAreIgnored() await Verify(handlers); } - + [Fact] public async Task TypeMappingWithAsJsonExtensionIsDetected() { @@ -80,6 +80,20 @@ public async Task TypeMappingWithAsJsonExtensionIsDetected() await Verify(handlers); } + [Fact] + public async Task TypeMappingDuplicatesAsHandled() + { + var newProject = await TestProject.Project.ReplacePartsOfDocumentAsync( + "Program.cs", + ("// place to replace 0", "public class Role { public string Name { get; set;} }"), + ("public Json Emails { get; set; }", "public Json Role { get; set; }"), + ("// place to replace 1", "var role = new Role().AsJson();")); + + var handlers = await Execute(newProject); + + await Verify(handlers); + } + private static async Task Execute(Project project) { var assembly = await project.CompileToRealAssembly();