Skip to content

Commit

Permalink
Fix source generation for type duplicates.
Browse files Browse the repository at this point in the history
  • Loading branch information
byme8 committed Feb 4, 2023
1 parent 793f6a3 commit ac50730
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 35 deletions.
76 changes: 42 additions & 34 deletions src/Dapper.Json.SourceGenerator/DapperJsonSourceGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using DuckInterface;
Expand All @@ -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<ITypeSymbol> 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
{{
Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[
Role
]
16 changes: 15 additions & 1 deletion src/Dapper.Json.Tests/MainTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public async Task TypeMappingForGenericsAreIgnored()

await Verify(handlers);
}

[Fact]
public async Task TypeMappingWithAsJsonExtensionIsDetected()
{
Expand All @@ -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<string[]> Emails { get; set; }", "public Json<Role> Role { get; set; }"),
("// place to replace 1", "var role = new Role().AsJson();"));

var handlers = await Execute(newProject);

await Verify(handlers);
}

private static async Task<string[]> Execute(Project project)
{
var assembly = await project.CompileToRealAssembly();
Expand Down

0 comments on commit ac50730

Please sign in to comment.