Skip to content

Commit 80b7f1a

Browse files
authored
Struct Members (#895)
* Add some initial failing tests * Add System.Collections.Immutable to possible packages * Reference System.Collections.Immutable from Symbols * Add Member array to struct * Visit Struct members * Correct symbol visitor tests for member visiting * Fix usages of struct to use immutable array * Add linefeeds to structs * Adjust tests to accept new linefeeds in structs * Visit struct members and add them to resulting tree * Add general indentation to visitor * Indent Struct members * Fix indentation in tests
1 parent 00d0225 commit 80b7f1a

File tree

10 files changed

+178
-60
lines changed

10 files changed

+178
-60
lines changed

Directory.Packages.props

Lines changed: 43 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,45 @@
11
<Project>
2-
<!--
3-
This file tracks all package versions used in Silk.NET, including tests.
4-
For more information what this is see https://github.com/NuGet/Home/wiki/Centrally-managing-NuGet-package-versions
5-
-->
6-
<ItemGroup>
7-
<PackageVersion Include="BenchmarkDotNet" Version="0.12.1" />
8-
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.0.0-2.final" />
9-
<PackageVersion Include="System.Text.Json" Version="6.0.0-preview.6.21352.12" />
10-
<PackageVersion Include="ClangSharp.PInvokeGenerator" Version="12.0.0-beta2" />
11-
<PackageVersion Include="Microsoft.Build.Locator" Version="1.4.1" />
12-
<PackageVersion Include="Microsoft.Extensions.FileSystemGlobbing" Version="6.0.0-preview.6.21352.12" />
13-
<PackageVersion Include="Microsoft.Build.Framework" Version="16.10.0" />
14-
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.0.0-2.final" />
15-
<PackageVersion Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="4.0.0-2.final" />
16-
<PackageVersion Include="System.CommandLine" Version="2.0.0-beta1.21308.1" />
17-
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
18-
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" />
19-
<PackageVersion Include="NuGet.Protocol" Version="5.8.0" />
20-
<PackageVersion Include="Nuke.Common" Version="6.0.1" />
21-
<PackageVersion Include="Ultz.Bcl.Half" Version="1.0.0" />
22-
<PackageVersion Include="Microsoft.Bcl.HashCode" Version="1.1.0" />
23-
<PackageVersion Include="Microsoft.CodeAnalysis.PublicApiAnalyzers" Version="3.3.1" />
24-
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="6.0.0" />
25-
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0" />
26-
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0" />
27-
<PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" />
28-
<PackageVersion Include="Microsoft.Extensions.Options" Version="6.0.0" />
29-
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="16.8.0" />
30-
<PackageVersion Include="xunit" Version="2.4.1" />
31-
<PackageVersion Include="xunit.runner.visualstudio" Version="2.4.3" />
32-
<PackageVersion Include="Statiq.Core" Version="1.0.0-beta.48" />
33-
<PackageVersion Include="HtmlAgilityPack" Version="1.11.42" />
34-
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="3.11.0" />
35-
<PackageVersion Include="Statiq.App" Version="1.0.0-beta.48" />
36-
<PackageVersion Include="Statiq.Feeds" Version="1.0.0-beta.48" />
37-
<PackageVersion Include="Statiq.Markdown" Version="1.0.0-beta.48" />
38-
<PackageVersion Include="Statiq.Razor" Version="1.0.0-beta.48" />
39-
<PackageVersion Include="Statiq.Yaml" Version="1.0.0-beta.48" />
40-
<PackageVersion Include="Humanizer.Core" Version="2.14.1" />
41-
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.1.0" />
42-
<PackageVersion Include="Moq" Version="4.17.2" />
43-
</ItemGroup>
2+
<!--
3+
This file tracks all package versions used in Silk.NET, including tests.
4+
For more information what this is see https://github.com/NuGet/Home/wiki/Centrally-managing-NuGet-package-versions
5+
-->
6+
<ItemGroup>
7+
<PackageVersion Include="BenchmarkDotNet" Version="0.12.1"/>
8+
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.0.0-2.final"/>
9+
<PackageVersion Include="System.Text.Json" Version="6.0.0-preview.6.21352.12"/>
10+
<PackageVersion Include="ClangSharp.PInvokeGenerator" Version="12.0.0-beta2"/>
11+
<PackageVersion Include="Microsoft.Build.Locator" Version="1.4.1"/>
12+
<PackageVersion Include="Microsoft.Extensions.FileSystemGlobbing" Version="6.0.0-preview.6.21352.12"/>
13+
<PackageVersion Include="Microsoft.Build.Framework" Version="16.10.0"/>
14+
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.0.0-2.final"/>
15+
<PackageVersion Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="4.0.0-2.final"/>
16+
<PackageVersion Include="System.CommandLine" Version="2.0.0-beta1.21308.1"/>
17+
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
18+
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0"/>
19+
<PackageVersion Include="NuGet.Protocol" Version="5.8.0"/>
20+
<PackageVersion Include="Nuke.Common" Version="6.0.1"/>
21+
<PackageVersion Include="Ultz.Bcl.Half" Version="1.0.0"/>
22+
<PackageVersion Include="Microsoft.Bcl.HashCode" Version="1.1.0"/>
23+
<PackageVersion Include="Microsoft.CodeAnalysis.PublicApiAnalyzers" Version="3.3.1"/>
24+
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="6.0.0"/>
25+
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0"/>
26+
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0"/>
27+
<PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0"/>
28+
<PackageVersion Include="Microsoft.Extensions.Options" Version="6.0.0"/>
29+
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="16.8.0"/>
30+
<PackageVersion Include="xunit" Version="2.4.1"/>
31+
<PackageVersion Include="xunit.runner.visualstudio" Version="2.4.3"/>
32+
<PackageVersion Include="Statiq.Core" Version="1.0.0-beta.48"/>
33+
<PackageVersion Include="HtmlAgilityPack" Version="1.11.42"/>
34+
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="3.11.0"/>
35+
<PackageVersion Include="Statiq.App" Version="1.0.0-beta.48"/>
36+
<PackageVersion Include="Statiq.Feeds" Version="1.0.0-beta.48"/>
37+
<PackageVersion Include="Statiq.Markdown" Version="1.0.0-beta.48"/>
38+
<PackageVersion Include="Statiq.Razor" Version="1.0.0-beta.48"/>
39+
<PackageVersion Include="Statiq.Yaml" Version="1.0.0-beta.48"/>
40+
<PackageVersion Include="Humanizer.Core" Version="2.14.1"/>
41+
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.1.0"/>
42+
<PackageVersion Include="Moq" Version="4.17.2"/>
43+
<PackageVersion Include="System.Collections.Immutable" Version="6.0.0"/>
44+
</ItemGroup>
4445
</Project>

src/generators/Silk.NET.SilkTouch.Emitter/CSharpEmitter.cs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System;
5+
using System.Collections.Generic;
56
using System.Diagnostics;
67
using Microsoft.CodeAnalysis;
78
using Microsoft.CodeAnalysis.CSharp;
@@ -38,7 +39,7 @@ public CSharpEmitter()
3839
/// </remarks>
3940
public CSharpSyntaxNode Transform(Symbol symbol)
4041
{
41-
var visitor = new Visitor();
42+
var visitor = new Visitor(Whitespace(" "));
4243
visitor.Visit(symbol); // the result is ignored. This allows us to optimize the visitor in some cases.
4344
var syntax = visitor.Syntax;
4445
if (syntax is null)
@@ -49,10 +50,16 @@ public CSharpSyntaxNode Transform(Symbol symbol)
4950

5051
private class Visitor : Silk.NET.SilkTouch.Symbols.SymbolVisitor
5152
{
53+
private readonly SyntaxTrivia _indentation;
5254
public CSharpSyntaxNode? Syntax => _syntax;
5355
private CSharpSyntaxNode? _syntax = null;
5456
private SyntaxToken? _syntaxToken = null;
5557

58+
public Visitor(SyntaxTrivia indentation) : base()
59+
{
60+
_indentation = indentation;
61+
}
62+
5663
protected override StructSymbol VisitStruct(StructSymbol structSymbol)
5764
{
5865
AssertClearState();
@@ -62,14 +69,28 @@ protected override StructSymbol VisitStruct(StructSymbol structSymbol)
6269
throw new InvalidOperationException("Field Identifier was not visited correctly");
6370
ClearState();
6471

65-
var members = List<MemberDeclarationSyntax>();
72+
var memberList = new List<MemberDeclarationSyntax>(structSymbol.Members.Length);
73+
foreach (var member in structSymbol.Members)
74+
{
75+
VisitMember(member);
76+
if (_syntax is not MemberDeclarationSyntax memberDeclarationSyntax)
77+
throw new InvalidOperationException("Member was not visited correctly");
78+
ClearState();
79+
memberDeclarationSyntax = memberDeclarationSyntax.WithLeadingTrivia(LineFeed, _indentation);
80+
memberList.Add(memberDeclarationSyntax);
81+
}
82+
83+
var members = List(memberList);
84+
6685
var modifiers = TokenList(Token(SyntaxTriviaList.Empty, SyntaxKind.PublicKeyword, TriviaList(Space)));
6786
_syntax = StructDeclaration
6887
(
6988
List<AttributeListSyntax>(), modifiers, identifierToken, null, null,
7089
List<TypeParameterConstraintClauseSyntax>(), members
7190
)
72-
.WithKeyword(Token(SyntaxTriviaList.Empty, SyntaxKind.StructKeyword, TriviaList(Space)));
91+
.WithKeyword(Token(SyntaxTriviaList.Empty, SyntaxKind.StructKeyword, TriviaList(Space)))
92+
.WithOpenBraceToken(Token(TriviaList(LineFeed), SyntaxKind.OpenBraceToken, SyntaxTriviaList.Empty))
93+
.WithCloseBraceToken(Token(TriviaList(LineFeed), SyntaxKind.CloseBraceToken, SyntaxTriviaList.Empty));
7394
return structSymbol;
7495
}
7596

src/generators/Silk.NET.SilkTouch.Symbols/Silk.NET.SilkTouch.Symbols.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,8 @@
55
<ImplicitUsings>enable</ImplicitUsings>
66
<Nullable>enable</Nullable>
77
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="System.Collections.Immutable" />
11+
</ItemGroup>
812
</Project>
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Collections.Immutable;
5+
46
namespace Silk.NET.SilkTouch.Symbols;
57

68
/// <summary>
79
/// A <see cref="TypeSymbol"/> representing a <c>struct</c>.
810
/// </summary>
911
/// <param name="Identifier">The Identifier of this struct</param>
12+
/// <param name="Members">The Members of this struct</param>
1013
/// <remarks>
1114
/// In this context, a Struct means a type that represents the layout of a continuous block of memory.
1215
/// </remarks>
1316
// /// Each meaningful place in this memory called a field (see <see cref="FieldSymbol"/>) is accessible via this type.
1417
// /// Fields are allowed to overlap.
1518
// /// Additionally it may contain one or multiple <see cref="MethodSymbol"/> that are called with an instance of this type as their first argument.
16-
public sealed record StructSymbol(IdentifierSymbol Identifier) : TypeSymbol(Identifier);
19+
public sealed record StructSymbol(IdentifierSymbol Identifier, ImmutableArray<MemberSymbol> Members) : TypeSymbol(Identifier);

src/generators/Silk.NET.SilkTouch.Symbols/SymbolVisitor.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Collections.Immutable;
5+
46
namespace Silk.NET.SilkTouch.Symbols;
57

68
/// <summary>
@@ -73,7 +75,7 @@ protected virtual TypeSymbol VisitType(TypeSymbol typeSymbol)
7375
/// </remarks>
7476
protected virtual StructSymbol VisitStruct(StructSymbol structSymbol)
7577
{
76-
return new StructSymbol(VisitIdentifier(structSymbol.Identifier));
78+
return new StructSymbol(VisitIdentifier(structSymbol.Identifier), structSymbol.Members.Select(VisitMember).ToImmutableArray());
7779
}
7880

7981
/// <summary>

tests/Silk.NET.SilkTouch.Emitter.Tests/EmitterFieldTests.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Collections.Immutable;
45
using Silk.NET.SilkTouch.Symbols;
56
using Xunit;
67

@@ -13,7 +14,7 @@ public void StructHasStructKeyword()
1314
{
1415
var emitter = CreateEmitter();
1516

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

1819
var syntax = emitter.Transform(symbol);
1920

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Collections.Immutable;
5+
using Silk.NET.SilkTouch.Symbols;
6+
using Xunit;
7+
8+
namespace Silk.NET.SilkTouch.Emitter.Tests;
9+
10+
public class EmitterStructMemberFieldsTests : EmitterTest
11+
{
12+
[Fact]
13+
public void StructWithSingleFieldIntegration()
14+
{
15+
var node = Transform
16+
(
17+
new StructSymbol
18+
(
19+
new IdentifierSymbol("Test"), (new[]
20+
{
21+
(MemberSymbol) new FieldSymbol
22+
(
23+
new StructSymbol(new IdentifierSymbol("int"), ImmutableArray<MemberSymbol>.Empty),
24+
new IdentifierSymbol("F1")
25+
)
26+
}).ToImmutableArray()
27+
)
28+
);
29+
30+
Assert.Equal
31+
(
32+
@"public struct Test
33+
{
34+
public int F1;
35+
}", node.ToFullString()
36+
);
37+
}
38+
}
Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Collections.Immutable;
45
using Microsoft.CodeAnalysis.CSharp.Syntax;
56
using Silk.NET.SilkTouch.Symbols;
67
using Xunit;
@@ -12,28 +13,28 @@ public sealed class EmitterStructTests : EmitterTest
1213
[Fact]
1314
public void StructIsStructSyntax()
1415
{
15-
var syntax = Transform(new StructSymbol(new IdentifierSymbol("Test")));
16+
var syntax = Transform(new StructSymbol(new IdentifierSymbol("Test"), ImmutableArray<MemberSymbol>.Empty));
1617
Assert.IsType<StructDeclarationSyntax>(syntax);
1718
}
1819

1920
[Fact]
2021
public void StructHasStructKeyword()
2122
{
22-
var syntax = Transform(new StructSymbol(new IdentifierSymbol("Test"))) as StructDeclarationSyntax;
23+
var syntax = Transform(new StructSymbol(new IdentifierSymbol("Test"), ImmutableArray<MemberSymbol>.Empty)) as StructDeclarationSyntax;
2324
Assert.Equal("struct", syntax!.Keyword.Text);
2425
}
2526

2627
[Fact]
2728
public void StructHasCorrectIdentifier()
2829
{
29-
var syntax = Transform(new StructSymbol(new IdentifierSymbol("Test"))) as StructDeclarationSyntax;
30+
var syntax = Transform(new StructSymbol(new IdentifierSymbol("Test"), ImmutableArray<MemberSymbol>.Empty)) as StructDeclarationSyntax;
3031
Assert.Equal("Test", syntax!.Identifier.Text);
3132
}
3233

3334
[Fact]
3435
public void StructIsOnlyPublic()
3536
{
36-
var syntax = Transform(new StructSymbol(new IdentifierSymbol("Test"))) as StructDeclarationSyntax;
37+
var syntax = Transform(new StructSymbol(new IdentifierSymbol("Test"), ImmutableArray<MemberSymbol>.Empty)) as StructDeclarationSyntax;
3738
var @public = Assert.Single(syntax!.Modifiers);
3839
Assert.Equal("public", @public.Text);
3940
}
@@ -42,6 +43,8 @@ public void StructIsOnlyPublic()
4243
public void IntegrationEmptyStruct()
4344
{
4445
// Note that this test also covers trivia, which is not checked otherwise.
45-
Assert.Equal("public struct Test{}", Transform(new StructSymbol(new IdentifierSymbol("Test"))).ToFullString());
46+
Assert.Equal(@"public struct Test
47+
{
48+
}", Transform(new StructSymbol(new IdentifierSymbol("Test"), ImmutableArray<MemberSymbol>.Empty)).ToFullString());
4649
}
4750
}

tests/Silk.NET.SilkTouch.Symbols.Tests/SymbolVisitorTests/FieldTests.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Collections.Immutable;
45
using Moq;
56
using Moq.Protected;
67
using Xunit;
@@ -12,7 +13,7 @@ public class FieldTests
1213
[Fact]
1314
public void FieldIsVisitedAsField()
1415
{
15-
var symbol = new FieldSymbol(new StructSymbol(new IdentifierSymbol("")), new IdentifierSymbol(""));
16+
var symbol = new FieldSymbol(new StructSymbol(new IdentifierSymbol(""), ImmutableArray<MemberSymbol>.Empty), new IdentifierSymbol(""));
1617
var visitor = new Mock<SymbolVisitor>
1718
{
1819
CallBase = true
@@ -27,7 +28,7 @@ public void FieldIsVisitedAsField()
2728
[Fact]
2829
public void FieldIsVisitedAsMember()
2930
{
30-
var symbol = new FieldSymbol(new StructSymbol(new IdentifierSymbol("")), new IdentifierSymbol(""));
31+
var symbol = new FieldSymbol(new StructSymbol(new IdentifierSymbol(""), ImmutableArray<MemberSymbol>.Empty), new IdentifierSymbol(""));
3132
var visitor = new Mock<SymbolVisitor>
3233
{
3334
CallBase = true
@@ -42,7 +43,7 @@ public void FieldIsVisitedAsMember()
4243
[Fact]
4344
public void FieldTypeIsVisited()
4445
{
45-
var symbol = new FieldSymbol(new StructSymbol(new IdentifierSymbol("")), new IdentifierSymbol(""));
46+
var symbol = new FieldSymbol(new StructSymbol(new IdentifierSymbol(""), ImmutableArray<MemberSymbol>.Empty), new IdentifierSymbol(""));
4647
var visitor = new Mock<SymbolVisitor>
4748
{
4849
CallBase = true
@@ -57,7 +58,7 @@ public void FieldTypeIsVisited()
5758
[Fact]
5859
public void FieldIdentifierIsVisited()
5960
{
60-
var symbol = new FieldSymbol(new StructSymbol(new IdentifierSymbol("")), new IdentifierSymbol(""));
61+
var symbol = new FieldSymbol(new StructSymbol(new IdentifierSymbol(""), ImmutableArray<MemberSymbol>.Empty), new IdentifierSymbol(""));
6162
var visitor = new Mock<SymbolVisitor>
6263
{
6364
CallBase = true

0 commit comments

Comments
 (0)