Skip to content

Commit 0c6cf65

Browse files
committed
Added support for including types which are defined in another assembly in static code generation.
1 parent 1a73db7 commit 0c6cf65

File tree

9 files changed

+121
-56
lines changed

9 files changed

+121
-56
lines changed

YamlDotNet.Analyzers.StaticGenerator/ClassSyntaxReceiver.cs

Lines changed: 69 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -44,69 +44,86 @@ public void OnVisitSyntaxNode(GeneratorSyntaxContext context)
4444
if (attributes.Any(attribute => attribute.AttributeClass?.ToDisplayString() == "YamlDotNet.Serialization.YamlStaticContextAttribute"))
4545
{
4646
YamlStaticContextType = classSymbol;
47+
48+
var types =
49+
attributes.Where(attribute => attribute.AttributeClass?.ToDisplayString() == "YamlDotNet.Serialization.YamlSerializableAttribute"
50+
&& attribute.ConstructorArguments.Any(argument => argument.Type?.ToDisplayString() == "System.Type"))
51+
.Select(attribute => attribute.ConstructorArguments.First().Value)
52+
.ToArray();
53+
54+
foreach (var type in types.OfType<INamedTypeSymbol>())
55+
{
56+
AddSerializableClass(type);
57+
}
4758
}
4859

49-
if (classSymbol.GetAttributes().Any(attribute => attribute.AttributeClass?.ToDisplayString() == "YamlDotNet.Serialization.YamlSerializableAttribute"))
60+
if (classSymbol.GetAttributes().Any(attribute => attribute.AttributeClass?.ToDisplayString() == "YamlDotNet.Serialization.YamlSerializableAttribute"
61+
&& attribute.ConstructorArguments.Length == 0))
5062
{
51-
ClassObject classObject;
52-
var className = SanitizeName(classSymbol.GetFullName());
53-
if (Classes.ContainsKey(className))
63+
AddSerializableClass(classSymbol);
64+
}
65+
}
66+
}
67+
}
68+
69+
private void AddSerializableClass(INamedTypeSymbol classSymbol)
70+
{
71+
ClassObject classObject;
72+
var className = SanitizeName(classSymbol.GetFullName());
73+
if (Classes.ContainsKey(className))
74+
{
75+
classObject = Classes[className];
76+
}
77+
else
78+
{
79+
classObject = new ClassObject(className, classSymbol);
80+
Classes[className] = classObject;
81+
}
82+
while (classSymbol != null)
83+
{
84+
var members = classSymbol.GetMembers();
85+
foreach (var member in members)
86+
{
87+
if (member.IsStatic ||
88+
(member.DeclaredAccessibility != Accessibility.Public &&
89+
member.DeclaredAccessibility != Accessibility.Internal) ||
90+
member.GetAttributes().Any(x => x.AttributeClass!.ToDisplayString() == "YamlDotNet.Serialization.YamlIgnoreAttribute"))
91+
{
92+
continue;
93+
}
94+
95+
if (member is IPropertySymbol propertySymbol)
96+
{
97+
classObject.PropertySymbols.Add(propertySymbol);
98+
CheckForSupportedGeneric(propertySymbol.Type);
99+
}
100+
else if (member is IFieldSymbol fieldSymbol)
101+
{
102+
classObject.FieldSymbols.Add(fieldSymbol);
103+
CheckForSupportedGeneric(fieldSymbol.Type);
104+
}
105+
else if (member is IMethodSymbol methodSymbol)
106+
{
107+
var methodAttributes = methodSymbol.GetAttributes();
108+
if (methodAttributes.Any(x => x.AttributeClass!.ToDisplayString() == "YamlDotNet.Serialization.Callbacks.OnDeserializedAttribute"))
54109
{
55-
classObject = Classes[className];
110+
classObject.OnDeserializedMethods.Add(methodSymbol);
56111
}
57-
else
112+
if (methodAttributes.Any(x => x.AttributeClass!.ToDisplayString() == "YamlDotNet.Serialization.Callbacks.OnDeserializingAttribute"))
58113
{
59-
classObject = new ClassObject(className, classSymbol);
60-
Classes[className] = classObject;
114+
classObject.OnDeserializingMethods.Add(methodSymbol);
61115
}
62-
while (classSymbol != null)
116+
if (methodAttributes.Any(x => x.AttributeClass!.ToDisplayString() == "YamlDotNet.Serialization.Callbacks.OnSerializedAttribute"))
63117
{
64-
var members = classSymbol.GetMembers();
65-
foreach (var member in members)
66-
{
67-
if (member.IsStatic ||
68-
(member.DeclaredAccessibility != Accessibility.Public &&
69-
member.DeclaredAccessibility != Accessibility.Internal) ||
70-
member.GetAttributes().Any(x => x.AttributeClass!.ToDisplayString() == "YamlDotNet.Serialization.YamlIgnoreAttribute"))
71-
{
72-
continue;
73-
}
74-
75-
if (member is IPropertySymbol propertySymbol)
76-
{
77-
classObject.PropertySymbols.Add(propertySymbol);
78-
CheckForSupportedGeneric(propertySymbol.Type);
79-
}
80-
else if (member is IFieldSymbol fieldSymbol)
81-
{
82-
classObject.FieldSymbols.Add(fieldSymbol);
83-
CheckForSupportedGeneric(fieldSymbol.Type);
84-
}
85-
else if (member is IMethodSymbol methodSymbol)
86-
{
87-
var methodAttributes = methodSymbol.GetAttributes();
88-
if (methodAttributes.Any(x => x.AttributeClass!.ToDisplayString() == "YamlDotNet.Serialization.Callbacks.OnDeserializedAttribute"))
89-
{
90-
classObject.OnDeserializedMethods.Add(methodSymbol);
91-
}
92-
if (methodAttributes.Any(x => x.AttributeClass!.ToDisplayString() == "YamlDotNet.Serialization.Callbacks.OnDeserializingAttribute"))
93-
{
94-
classObject.OnDeserializingMethods.Add(methodSymbol);
95-
}
96-
if (methodAttributes.Any(x => x.AttributeClass!.ToDisplayString() == "YamlDotNet.Serialization.Callbacks.OnSerializedAttribute"))
97-
{
98-
classObject.OnSerializedMethods.Add(methodSymbol);
99-
}
100-
if (methodAttributes.Any(x => x.AttributeClass!.ToDisplayString() == "YamlDotNet.Serialization.Callbacks.OnSerializingAttribute"))
101-
{
102-
classObject.OnSerializingMethods.Add(methodSymbol);
103-
}
104-
}
105-
}
106-
classSymbol = classSymbol.BaseType;
118+
classObject.OnSerializedMethods.Add(methodSymbol);
119+
}
120+
if (methodAttributes.Any(x => x.AttributeClass!.ToDisplayString() == "YamlDotNet.Serialization.Callbacks.OnSerializingAttribute"))
121+
{
122+
classObject.OnSerializingMethods.Add(methodSymbol);
107123
}
108124
}
109125
}
126+
classSymbol = classSymbol.BaseType;
110127
}
111128
}
112129

YamlDotNet.Analyzers.StaticGenerator/TypeFactoryGenerator.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
// SOFTWARE.
2121

2222
using System;
23+
using System.Diagnostics;
2324
using System.Text;
2425
using System.Xml;
2526
using Microsoft.CodeAnalysis;
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace YamlDotNet.Core7AoTCompileTest.Model;
2+
3+
public class ExternalModel
4+
{
5+
public string? Text { get; set; }
6+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net70</TargetFramework>
5+
<ImplicitUsings>enable</ImplicitUsings>
6+
<Nullable>enable</Nullable>
7+
</PropertyGroup>
8+
9+
<Import Project="../build/common.props" />
10+
11+
</Project>

YamlDotNet.Core7AoTCompileTest/Program.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,14 @@
2424

2525
using System;
2626
using System.Collections.Generic;
27+
using System.Globalization;
2728
using System.IO;
2829
using YamlDotNet.Core;
30+
using YamlDotNet.Core7AoTCompileTest.Model;
2931
using YamlDotNet.Serialization;
3032
using YamlDotNet.Serialization.Callbacks;
3133

32-
string yaml = $@"MyBool: true
34+
string yaml = string.Create(CultureInfo.InvariantCulture, $@"MyBool: true
3335
hi: 1
3436
MyChar: h
3537
MyDateTime: {DateTime.Now}
@@ -65,7 +67,9 @@
6567
Inherited:
6668
Inherited: hello
6769
NotInherited: world
68-
";
70+
External:
71+
Text: hello
72+
");
6973

7074
var input = new StringReader(yaml);
7175

@@ -91,6 +95,7 @@
9195
Console.WriteLine("MyUInt64: <{0}>", x.MyUInt64);
9296
Console.WriteLine("Inner == null: <{0}>", x.Inner == null);
9397
Console.WriteLine("Inner.Text: <{0}>", x.Inner?.Text);
98+
Console.WriteLine("External.Text: <{0}>", x.External?.Text);
9499
foreach (var inner in x.InnerArray)
95100
{
96101
Console.WriteLine("InnerArray.Text: <{0}>", inner.Text);
@@ -188,6 +193,7 @@ public class PrimitiveTypes
188193
public Dictionary<string, string>? MyDictionary { get; set; }
189194
public List<string>? MyList { get; set; }
190195
public Inherited Inherited { get; set; }
196+
public ExternalModel External { get; set; }
191197
}
192198

193199
public class InheritedBase

YamlDotNet.Core7AoTCompileTest/StaticAoTContext.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@
1919
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2020
// SOFTWARE.
2121

22+
using YamlDotNet.Core7AoTCompileTest.Model;
2223
using YamlDotNet.Serialization;
2324

2425
namespace YamlDotNet.Core7AoTCompileTest
2526
{
2627
// The rest of this partial class gets generated at build time
2728
[YamlStaticContext]
29+
[YamlSerializable(typeof(ExternalModel))]
2830
public partial class StaticContext : YamlDotNet.Serialization.StaticContext
2931
{
3032
}

YamlDotNet.Core7AoTCompileTest/YamlDotNet.Core7AoTCompileTest.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
<ProjectReference Include="..\YamlDotNet.Analyzers.StaticGenerator\YamlDotNet.Analyzers.StaticGenerator.csproj"
2626
OutputItemType="Analyzer"
2727
ReferenceOutputAssembly="false" />
28+
<ProjectReference Include="..\YamlDotNet.Core7AoTCompileTest.Model\YamlDotNet.Core7AoTCompileTest.Model.csproj" />
2829
<ProjectReference Include="..\YamlDotNet\YamlDotNet.csproj" />
2930
</ItemGroup>
3031

YamlDotNet.sln

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YamlDotNet.Core7AoTCompileT
3131
EndProject
3232
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "YamlDotNet.Samples.Fsharp", "YamlDotNet.Samples.Fsharp\YamlDotNet.Samples.Fsharp.fsproj", "{C047392D-6B20-47CD-9FE6-D0FA326FD262}"
3333
EndProject
34+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YamlDotNet.Core7AoTCompileTest.Model", "YamlDotNet.Core7AoTCompileTest.Model\YamlDotNet.Core7AoTCompileTest.Model.csproj", "{BFE15564-7C2C-47DA-8302-9BCB39B6864B}"
35+
EndProject
3436
Global
3537
GlobalSection(SolutionConfigurationPlatforms) = preSolution
3638
Debug|Any CPU = Debug|Any CPU
@@ -69,6 +71,10 @@ Global
6971
{C047392D-6B20-47CD-9FE6-D0FA326FD262}.Debug|Any CPU.Build.0 = Debug|Any CPU
7072
{C047392D-6B20-47CD-9FE6-D0FA326FD262}.Release|Any CPU.ActiveCfg = Release|Any CPU
7173
{C047392D-6B20-47CD-9FE6-D0FA326FD262}.Release|Any CPU.Build.0 = Release|Any CPU
74+
{BFE15564-7C2C-47DA-8302-9BCB39B6864B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
75+
{BFE15564-7C2C-47DA-8302-9BCB39B6864B}.Debug|Any CPU.Build.0 = Debug|Any CPU
76+
{BFE15564-7C2C-47DA-8302-9BCB39B6864B}.Release|Any CPU.ActiveCfg = Release|Any CPU
77+
{BFE15564-7C2C-47DA-8302-9BCB39B6864B}.Release|Any CPU.Build.0 = Release|Any CPU
7278
EndGlobalSection
7379
GlobalSection(SolutionProperties) = preSolution
7480
HideSolutionNode = FALSE

YamlDotNet/Serialization/YamlSerializable.cs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,25 @@
2424
namespace YamlDotNet.Serialization
2525
{
2626
/// <summary>
27-
/// Put this attribute on classes that you want the static analyzer to detect and use.
27+
/// Put this attribute either on serializable types or on the <see cref="StaticContext"/> that you want
28+
/// the static analyzer to detect and use.
2829
/// </summary>
29-
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
30+
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
3031
public sealed class YamlSerializableAttribute : Attribute
3132
{
33+
/// <summary>
34+
/// Use this constructor if the attribute is placed on a serializable class.
35+
/// </summary>
36+
public YamlSerializableAttribute()
37+
{
38+
}
39+
40+
/// <summary>
41+
/// Use this constructor if the attribute is placed on the <see cref="StaticContext"/>.
42+
/// </summary>
43+
/// <param name="serializableType">The type for which to include static code generation.</param>
44+
public YamlSerializableAttribute(Type serializableType)
45+
{
46+
}
3247
}
3348
}

0 commit comments

Comments
 (0)