added support for records

This commit is contained in:
daver32
2021-08-15 14:41:36 +02:00
parent ce722408cf
commit 2b1f8af5a3
3 changed files with 75 additions and 10 deletions
@@ -0,0 +1,54 @@
using System.Runtime.CompilerServices;
using FluentAssertions;
using Xunit;
namespace InterfaceGenerator.Tests
{
public class RecordInterfaceGenerationTests
{
private readonly ITestRecord _sut;
public RecordInterfaceGenerationTests()
{
_sut = new TestRecord(420);
}
[Fact]
public void RecordProperty_IsGenerated()
{
var prop = typeof(ITestRecord)
.GetProperty(nameof(TestRecord.RecordProperty));
prop.Should().NotBeNull();
prop.GetMethod.Should().NotBeNull();
prop.SetMethod.Should().NotBeNull();
prop.SetMethod.ReturnParameter.GetRequiredCustomModifiers().Should().Contain(typeof(IsExternalInit));
_sut.RecordProperty.Should().Be(420);
}
[Fact]
public void RecordMethod_IsGenerated()
{
var method = typeof(ITestRecord).GetMethod(
nameof(TestRecord.RecordMethod));
method.Should().NotBeNull();
method.ReturnType.Should().Be(typeof(void));
var parameters = method.GetParameters();
parameters.Should().BeEmpty();
_sut.RecordMethod();
}
}
[GenerateAutoInterface]
internal record TestRecord(int RecordProperty) : ITestRecord
{
public void RecordMethod()
{
}
}
}
+11 -6
View File
@@ -236,7 +236,6 @@ namespace InterfaceGenerator
if (propertySymbol.IsIndexer)
{
writer.Write("{0} this[", propertySymbol.Type);
//writer.WriteJoin(", ", propertySymbol.Parameters, (w, param) => { w.Write("{0} {1}", param.Type, param.Name); });
writer.WriteJoin(", ", propertySymbol.Parameters, WriteMethodParam);
writer.Write("] ");
}
@@ -273,6 +272,12 @@ namespace InterfaceGenerator
{
return;
}
if (methodSymbol.IsImplicitlyDeclared)
{
// omit methods that are auto generated by the compiler (eg. record's methods)
return;
}
WriteMemberDocs(writer, methodSymbol);
@@ -386,14 +391,14 @@ namespace InterfaceGenerator
private static IEnumerable<INamedTypeSymbol> GetImplTypeSymbols(Compilation compilation, SyntaxReceiver receiver)
{
return receiver.CandidateClasses.Select(candidate => GetClassSymbol(compilation, candidate));
return receiver.CandidateTypes.Select(candidate => GetTypeSymbol(compilation, candidate));
}
private static INamedTypeSymbol GetClassSymbol(Compilation compilation, ClassDeclarationSyntax @class)
private static INamedTypeSymbol GetTypeSymbol(Compilation compilation, TypeDeclarationSyntax type)
{
var model = compilation.GetSemanticModel(@class.SyntaxTree);
var classSymbol = ModelExtensions.GetDeclaredSymbol(model, @class)!;
return (INamedTypeSymbol)classSymbol;
var model = compilation.GetSemanticModel(type.SyntaxTree);
var typeSymbol = ModelExtensions.GetDeclaredSymbol(model, type)!;
return (INamedTypeSymbol)typeSymbol;
}
private static Compilation GetCompilation(GeneratorExecutionContext context)
+10 -4
View File
@@ -6,15 +6,21 @@ namespace InterfaceGenerator
{
internal class SyntaxReceiver : ISyntaxReceiver
{
public IList<ClassDeclarationSyntax> CandidateClasses { get; } = new List<ClassDeclarationSyntax>();
public IList<TypeDeclarationSyntax> CandidateTypes { get; } = new List<TypeDeclarationSyntax>();
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
{
if (syntaxNode is ClassDeclarationSyntax classDeclarationSyntax &&
classDeclarationSyntax.AttributeLists.Count > 0)
if (syntaxNode is TypeDeclarationSyntax typeDeclarationSyntax &&
IsClassOrRecord(typeDeclarationSyntax) &&
typeDeclarationSyntax.AttributeLists.Count > 0)
{
CandidateClasses.Add(classDeclarationSyntax);
CandidateTypes.Add(typeDeclarationSyntax);
}
}
private static bool IsClassOrRecord(TypeDeclarationSyntax typeDeclarationSyntax)
{
return typeDeclarationSyntax is ClassDeclarationSyntax || typeDeclarationSyntax is RecordDeclarationSyntax;
}
}
}