Skip to content

Struct Members #895

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Apr 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 43 additions & 42 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
@@ -1,44 +1,45 @@
<Project>
<!--
This file tracks all package versions used in Silk.NET, including tests.
For more information what this is see https://github.com/NuGet/Home/wiki/Centrally-managing-NuGet-package-versions
-->
<ItemGroup>
<PackageVersion Include="BenchmarkDotNet" Version="0.12.1" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.0.0-2.final" />
<PackageVersion Include="System.Text.Json" Version="6.0.0-preview.6.21352.12" />
<PackageVersion Include="ClangSharp.PInvokeGenerator" Version="12.0.0-beta2" />
<PackageVersion Include="Microsoft.Build.Locator" Version="1.4.1" />
<PackageVersion Include="Microsoft.Extensions.FileSystemGlobbing" Version="6.0.0-preview.6.21352.12" />
<PackageVersion Include="Microsoft.Build.Framework" Version="16.10.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.0.0-2.final" />
<PackageVersion Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="4.0.0-2.final" />
<PackageVersion Include="System.CommandLine" Version="2.0.0-beta1.21308.1" />
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" />
<PackageVersion Include="NuGet.Protocol" Version="5.8.0" />
<PackageVersion Include="Nuke.Common" Version="6.0.1" />
<PackageVersion Include="Ultz.Bcl.Half" Version="1.0.0" />
<PackageVersion Include="Microsoft.Bcl.HashCode" Version="1.1.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.PublicApiAnalyzers" Version="3.3.1" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="6.0.0" />
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" />
<PackageVersion Include="Microsoft.Extensions.Options" Version="6.0.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="16.8.0" />
<PackageVersion Include="xunit" Version="2.4.1" />
<PackageVersion Include="xunit.runner.visualstudio" Version="2.4.3" />
<PackageVersion Include="Statiq.Core" Version="1.0.0-beta.48" />
<PackageVersion Include="HtmlAgilityPack" Version="1.11.42" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="3.11.0" />
<PackageVersion Include="Statiq.App" Version="1.0.0-beta.48" />
<PackageVersion Include="Statiq.Feeds" Version="1.0.0-beta.48" />
<PackageVersion Include="Statiq.Markdown" Version="1.0.0-beta.48" />
<PackageVersion Include="Statiq.Razor" Version="1.0.0-beta.48" />
<PackageVersion Include="Statiq.Yaml" Version="1.0.0-beta.48" />
<PackageVersion Include="Humanizer.Core" Version="2.14.1" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.1.0" />
<PackageVersion Include="Moq" Version="4.17.2" />
</ItemGroup>
<!--
This file tracks all package versions used in Silk.NET, including tests.
For more information what this is see https://github.com/NuGet/Home/wiki/Centrally-managing-NuGet-package-versions
-->
<ItemGroup>
<PackageVersion Include="BenchmarkDotNet" Version="0.12.1"/>
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.0.0-2.final"/>
<PackageVersion Include="System.Text.Json" Version="6.0.0-preview.6.21352.12"/>
<PackageVersion Include="ClangSharp.PInvokeGenerator" Version="12.0.0-beta2"/>
<PackageVersion Include="Microsoft.Build.Locator" Version="1.4.1"/>
<PackageVersion Include="Microsoft.Extensions.FileSystemGlobbing" Version="6.0.0-preview.6.21352.12"/>
<PackageVersion Include="Microsoft.Build.Framework" Version="16.10.0"/>
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.0.0-2.final"/>
<PackageVersion Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="4.0.0-2.final"/>
<PackageVersion Include="System.CommandLine" Version="2.0.0-beta1.21308.1"/>
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0"/>
<PackageVersion Include="NuGet.Protocol" Version="5.8.0"/>
<PackageVersion Include="Nuke.Common" Version="6.0.1"/>
<PackageVersion Include="Ultz.Bcl.Half" Version="1.0.0"/>
<PackageVersion Include="Microsoft.Bcl.HashCode" Version="1.1.0"/>
<PackageVersion Include="Microsoft.CodeAnalysis.PublicApiAnalyzers" Version="3.3.1"/>
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="6.0.0"/>
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0"/>
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0"/>
<PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0"/>
<PackageVersion Include="Microsoft.Extensions.Options" Version="6.0.0"/>
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="16.8.0"/>
<PackageVersion Include="xunit" Version="2.4.1"/>
<PackageVersion Include="xunit.runner.visualstudio" Version="2.4.3"/>
<PackageVersion Include="Statiq.Core" Version="1.0.0-beta.48"/>
<PackageVersion Include="HtmlAgilityPack" Version="1.11.42"/>
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="3.11.0"/>
<PackageVersion Include="Statiq.App" Version="1.0.0-beta.48"/>
<PackageVersion Include="Statiq.Feeds" Version="1.0.0-beta.48"/>
<PackageVersion Include="Statiq.Markdown" Version="1.0.0-beta.48"/>
<PackageVersion Include="Statiq.Razor" Version="1.0.0-beta.48"/>
<PackageVersion Include="Statiq.Yaml" Version="1.0.0-beta.48"/>
<PackageVersion Include="Humanizer.Core" Version="2.14.1"/>
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.1.0"/>
<PackageVersion Include="Moq" Version="4.17.2"/>
<PackageVersion Include="System.Collections.Immutable" Version="6.0.0"/>
</ItemGroup>
</Project>
27 changes: 24 additions & 3 deletions src/generators/Silk.NET.SilkTouch.Emitter/CSharpEmitter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
Expand Down Expand Up @@ -38,7 +39,7 @@ public CSharpEmitter()
/// </remarks>
public CSharpSyntaxNode Transform(Symbol symbol)
{
var visitor = new Visitor();
var visitor = new Visitor(Whitespace(" "));
visitor.Visit(symbol); // the result is ignored. This allows us to optimize the visitor in some cases.
var syntax = visitor.Syntax;
if (syntax is null)
Expand All @@ -49,10 +50,16 @@ public CSharpSyntaxNode Transform(Symbol symbol)

private class Visitor : Silk.NET.SilkTouch.Symbols.SymbolVisitor
{
private readonly SyntaxTrivia _indentation;
public CSharpSyntaxNode? Syntax => _syntax;
private CSharpSyntaxNode? _syntax = null;
private SyntaxToken? _syntaxToken = null;

public Visitor(SyntaxTrivia indentation) : base()
{
_indentation = indentation;
}

protected override StructSymbol VisitStruct(StructSymbol structSymbol)
{
AssertClearState();
Expand All @@ -62,14 +69,28 @@ protected override StructSymbol VisitStruct(StructSymbol structSymbol)
throw new InvalidOperationException("Field Identifier was not visited correctly");
ClearState();

var members = List<MemberDeclarationSyntax>();
var memberList = new List<MemberDeclarationSyntax>(structSymbol.Members.Length);
foreach (var member in structSymbol.Members)
{
VisitMember(member);
if (_syntax is not MemberDeclarationSyntax memberDeclarationSyntax)
throw new InvalidOperationException("Member was not visited correctly");
ClearState();
memberDeclarationSyntax = memberDeclarationSyntax.WithLeadingTrivia(LineFeed, _indentation);
memberList.Add(memberDeclarationSyntax);
}

var members = List(memberList);

var modifiers = TokenList(Token(SyntaxTriviaList.Empty, SyntaxKind.PublicKeyword, TriviaList(Space)));
_syntax = StructDeclaration
(
List<AttributeListSyntax>(), modifiers, identifierToken, null, null,
List<TypeParameterConstraintClauseSyntax>(), members
)
.WithKeyword(Token(SyntaxTriviaList.Empty, SyntaxKind.StructKeyword, TriviaList(Space)));
.WithKeyword(Token(SyntaxTriviaList.Empty, SyntaxKind.StructKeyword, TriviaList(Space)))
.WithOpenBraceToken(Token(TriviaList(LineFeed), SyntaxKind.OpenBraceToken, SyntaxTriviaList.Empty))
.WithCloseBraceToken(Token(TriviaList(LineFeed), SyntaxKind.CloseBraceToken, SyntaxTriviaList.Empty));
return structSymbol;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,8 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="System.Collections.Immutable" />
</ItemGroup>
</Project>
5 changes: 4 additions & 1 deletion src/generators/Silk.NET.SilkTouch.Symbols/StructSymbol.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Immutable;

namespace Silk.NET.SilkTouch.Symbols;

/// <summary>
/// A <see cref="TypeSymbol"/> representing a <c>struct</c>.
/// </summary>
/// <param name="Identifier">The Identifier of this struct</param>
/// <param name="Members">The Members of this struct</param>
/// <remarks>
/// In this context, a Struct means a type that represents the layout of a continuous block of memory.
/// </remarks>
// /// Each meaningful place in this memory called a field (see <see cref="FieldSymbol"/>) is accessible via this type.
// /// Fields are allowed to overlap.
// /// Additionally it may contain one or multiple <see cref="MethodSymbol"/> that are called with an instance of this type as their first argument.
public sealed record StructSymbol(IdentifierSymbol Identifier) : TypeSymbol(Identifier);
public sealed record StructSymbol(IdentifierSymbol Identifier, ImmutableArray<MemberSymbol> Members) : TypeSymbol(Identifier);
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Immutable;

namespace Silk.NET.SilkTouch.Symbols;

/// <summary>
Expand Down Expand Up @@ -73,7 +75,7 @@ protected virtual TypeSymbol VisitType(TypeSymbol typeSymbol)
/// </remarks>
protected virtual StructSymbol VisitStruct(StructSymbol structSymbol)
{
return new StructSymbol(VisitIdentifier(structSymbol.Identifier));
return new StructSymbol(VisitIdentifier(structSymbol.Identifier), structSymbol.Members.Select(VisitMember).ToImmutableArray());
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Immutable;
using Silk.NET.SilkTouch.Symbols;
using Xunit;

Expand All @@ -13,7 +14,7 @@ public void StructHasStructKeyword()
{
var emitter = CreateEmitter();

var symbol = new FieldSymbol(new StructSymbol(new IdentifierSymbol("int")), new IdentifierSymbol("Test"));
var symbol = new FieldSymbol(new StructSymbol(new IdentifierSymbol("int"), ImmutableArray<MemberSymbol>.Empty), new IdentifierSymbol("Test"));

var syntax = emitter.Transform(symbol);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Immutable;
using Silk.NET.SilkTouch.Symbols;
using Xunit;

namespace Silk.NET.SilkTouch.Emitter.Tests;

public class EmitterStructMemberFieldsTests : EmitterTest
{
[Fact]
public void StructWithSingleFieldIntegration()
{
var node = Transform
(
new StructSymbol
(
new IdentifierSymbol("Test"), (new[]
{
(MemberSymbol) new FieldSymbol
(
new StructSymbol(new IdentifierSymbol("int"), ImmutableArray<MemberSymbol>.Empty),
new IdentifierSymbol("F1")
)
}).ToImmutableArray()
)
);

Assert.Equal
(
@"public struct Test
{
public int F1;
}", node.ToFullString()
);
}
}
13 changes: 8 additions & 5 deletions tests/Silk.NET.SilkTouch.Emitter.Tests/EmitterStructTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Immutable;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Silk.NET.SilkTouch.Symbols;
using Xunit;
Expand All @@ -12,28 +13,28 @@ public sealed class EmitterStructTests : EmitterTest
[Fact]
public void StructIsStructSyntax()
{
var syntax = Transform(new StructSymbol(new IdentifierSymbol("Test")));
var syntax = Transform(new StructSymbol(new IdentifierSymbol("Test"), ImmutableArray<MemberSymbol>.Empty));
Assert.IsType<StructDeclarationSyntax>(syntax);
}

[Fact]
public void StructHasStructKeyword()
{
var syntax = Transform(new StructSymbol(new IdentifierSymbol("Test"))) as StructDeclarationSyntax;
var syntax = Transform(new StructSymbol(new IdentifierSymbol("Test"), ImmutableArray<MemberSymbol>.Empty)) as StructDeclarationSyntax;
Assert.Equal("struct", syntax!.Keyword.Text);
}

[Fact]
public void StructHasCorrectIdentifier()
{
var syntax = Transform(new StructSymbol(new IdentifierSymbol("Test"))) as StructDeclarationSyntax;
var syntax = Transform(new StructSymbol(new IdentifierSymbol("Test"), ImmutableArray<MemberSymbol>.Empty)) as StructDeclarationSyntax;
Assert.Equal("Test", syntax!.Identifier.Text);
}

[Fact]
public void StructIsOnlyPublic()
{
var syntax = Transform(new StructSymbol(new IdentifierSymbol("Test"))) as StructDeclarationSyntax;
var syntax = Transform(new StructSymbol(new IdentifierSymbol("Test"), ImmutableArray<MemberSymbol>.Empty)) as StructDeclarationSyntax;
var @public = Assert.Single(syntax!.Modifiers);
Assert.Equal("public", @public.Text);
}
Expand All @@ -42,6 +43,8 @@ public void StructIsOnlyPublic()
public void IntegrationEmptyStruct()
{
// Note that this test also covers trivia, which is not checked otherwise.
Assert.Equal("public struct Test{}", Transform(new StructSymbol(new IdentifierSymbol("Test"))).ToFullString());
Assert.Equal(@"public struct Test
{
}", Transform(new StructSymbol(new IdentifierSymbol("Test"), ImmutableArray<MemberSymbol>.Empty)).ToFullString());
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Immutable;
using Moq;
using Moq.Protected;
using Xunit;
Expand All @@ -12,7 +13,7 @@ public class FieldTests
[Fact]
public void FieldIsVisitedAsField()
{
var symbol = new FieldSymbol(new StructSymbol(new IdentifierSymbol("")), new IdentifierSymbol(""));
var symbol = new FieldSymbol(new StructSymbol(new IdentifierSymbol(""), ImmutableArray<MemberSymbol>.Empty), new IdentifierSymbol(""));
var visitor = new Mock<SymbolVisitor>
{
CallBase = true
Expand All @@ -27,7 +28,7 @@ public void FieldIsVisitedAsField()
[Fact]
public void FieldIsVisitedAsMember()
{
var symbol = new FieldSymbol(new StructSymbol(new IdentifierSymbol("")), new IdentifierSymbol(""));
var symbol = new FieldSymbol(new StructSymbol(new IdentifierSymbol(""), ImmutableArray<MemberSymbol>.Empty), new IdentifierSymbol(""));
var visitor = new Mock<SymbolVisitor>
{
CallBase = true
Expand All @@ -42,7 +43,7 @@ public void FieldIsVisitedAsMember()
[Fact]
public void FieldTypeIsVisited()
{
var symbol = new FieldSymbol(new StructSymbol(new IdentifierSymbol("")), new IdentifierSymbol(""));
var symbol = new FieldSymbol(new StructSymbol(new IdentifierSymbol(""), ImmutableArray<MemberSymbol>.Empty), new IdentifierSymbol(""));
var visitor = new Mock<SymbolVisitor>
{
CallBase = true
Expand All @@ -57,7 +58,7 @@ public void FieldTypeIsVisited()
[Fact]
public void FieldIdentifierIsVisited()
{
var symbol = new FieldSymbol(new StructSymbol(new IdentifierSymbol("")), new IdentifierSymbol(""));
var symbol = new FieldSymbol(new StructSymbol(new IdentifierSymbol(""), ImmutableArray<MemberSymbol>.Empty), new IdentifierSymbol(""));
var visitor = new Mock<SymbolVisitor>
{
CallBase = true
Expand Down
Loading