diff --git a/Authoring/AuthoringSample/AuthoringSample.csproj b/Authoring/AuthoringSample/AuthoringSample.csproj
new file mode 100644
index 000000000..384f9ba86
--- /dev/null
+++ b/Authoring/AuthoringSample/AuthoringSample.csproj
@@ -0,0 +1,18 @@
+
+
+
+ net5.0
+ preview
+ 1.0.0.0
+ true
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Authoring/AuthoringSample/Program.cs b/Authoring/AuthoringSample/Program.cs
new file mode 100644
index 000000000..7b95d3f1b
--- /dev/null
+++ b/Authoring/AuthoringSample/Program.cs
@@ -0,0 +1,209 @@
+using System;
+using System.Reflection;
+using Windows.Foundation.Metadata;
+
+namespace MyTypes
+{
+ public delegate void ExampleDelegate(UInt32 value);
+ public delegate int ExampleDelegateDouble(double newvalue);
+
+ public class ExampleClass
+ {
+ public ExampleClass()
+ {
+ }
+
+ public event ExampleDelegate SampleEvent;
+
+ public ExampleClass(ExampleClass other)
+ {
+ other.MethodA();
+ }
+
+ public ExampleClass(int alpha)
+ {
+ MethodB(alpha, alpha);
+ }
+
+ public void MethodA()
+ {
+ System.Console.WriteLine("Yay!");
+ }
+
+ public int MethodB(int param1, double param2)
+ {
+ return 4;
+ }
+
+ public ExampleClass Get()
+ {
+ return null;
+ }
+
+ private static void HelperMethod(ExampleClass instance)
+ {
+ instance.MethodA();
+ }
+
+ public double ExampleDouble { get; set; }
+ }
+
+ [Version(3)]
+ public interface ITest2
+ {
+ [Version(5)]
+ double GetTest(int test);
+ int GetTest2();
+ double GetSetDouble { get; set; }
+ }
+
+ internal enum PrivateEnum
+ {
+ privatetest,
+ privatetest2
+ }
+
+ public enum TestEnum
+ {
+ test,
+ test2
+ }
+
+ public enum NumericEnum : int
+ {
+ five = -5,
+ six = 6
+ }
+
+ public enum UnsignedEnum : uint
+ {
+ zero,
+ one,
+ two,
+ three
+ }
+
+ public struct MyStruct
+ {
+ public int test, test3;
+ public double test2;
+ }
+
+ public class Test : ITest2
+ {
+ public int GetSetInt { get; set; }
+ public double GetSetDouble { get; set; }
+ public int GetInt { get; }
+
+ public double GetTest(int test)
+ {
+ return test;
+ }
+
+ public int GetTest2()
+ {
+ return 4;
+ }
+ }
+
+ public class ExampleClass2 : ExampleClass
+ {
+ public void Delta()
+ {
+ }
+
+ public int Method()
+ {
+ return 4;
+ }
+
+ public int Method2(int param1, double param2)
+ {
+ return 4;
+ }
+
+ public void Pen()
+ {
+ }
+
+ public int Method3(double p1, double param2, int param3)
+ {
+ return 4;
+ }
+
+ public double Method4(double m4, double m5, int m6, int m7)
+ {
+ return 4;
+ }
+ }
+
+ public class Test3 : Test
+ {
+
+ }
+
+
+ public class Test8 : Windows.Foundation.IWwwFormUrlDecoderEntry
+ {
+ public string Name => throw new NotImplementedException();
+
+ public string Value => throw new NotImplementedException();
+ }
+
+ public class NewTest4 : ITest4
+ {
+ public double GetSetDouble { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
+
+ public event ExampleDelegate TestEvent;
+
+ public double GetTest(int test)
+ {
+ throw new NotImplementedException();
+ }
+
+ public int GetTest2()
+ {
+ throw new NotImplementedException();
+ }
+
+ public int GetTest4()
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ public interface ITest4 : ITest2
+ {
+ int GetTest4();
+
+ public event ExampleDelegate TestEvent;
+ }
+
+ public class TestCustom
+ {
+ public TestCustom(int num)
+ {
+ _num = num;
+ }
+
+ public int GetNum()
+ {
+ return _num;
+ }
+
+ private int _num;
+ }
+
+ internal class SomeMoreCode
+ {
+ public static void Stuff()
+ {
+ const ExampleClass instance1 = null;
+ }
+
+ ExampleClass MyProp2
+ {
+ get { return null; }
+ }
+ }
+}
diff --git a/Authoring/WinRT.SourceGenerator/Generator.cs b/Authoring/WinRT.SourceGenerator/Generator.cs
new file mode 100644
index 000000000..14723a291
--- /dev/null
+++ b/Authoring/WinRT.SourceGenerator/Generator.cs
@@ -0,0 +1,98 @@
+using Microsoft.CodeAnalysis;
+using System;
+using System.IO;
+using System.Reflection.Metadata;
+using System.Reflection.Metadata.Ecma335;
+using System.Reflection.PortableExecutable;
+
+namespace Generator
+{
+ [Generator]
+ public class SourceGenerator : ISourceGenerator
+ {
+ private string GetAssemblyName(SourceGeneratorContext context)
+ {
+ context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.AssemblyName", out var assemblyName);
+ return assemblyName;
+ }
+
+ private string GetAssemblyVersion(SourceGeneratorContext context)
+ {
+ context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.AssemblyVersion", out var assemblyVersion);
+ return assemblyVersion;
+ }
+
+ public static string GetGeneratedFilesDir(SourceGeneratorContext context)
+ {
+ // TODO: determine correct location to write to.
+ string winmdDir = Path.Combine(Directory.GetCurrentDirectory(), "Generated Files");
+ Directory.CreateDirectory(winmdDir);
+ return winmdDir;
+ }
+
+ private string GetWinmdOutputFile(SourceGeneratorContext context)
+ {
+ return Path.Combine(GetGeneratedFilesDir(context), GetAssemblyName(context) + ".winmd");
+ }
+
+ private void GenerateWinMD(MetadataBuilder metadataBuilder, string outputFile)
+ {
+ Logger.Log("Writing " + outputFile);
+ var managedPeBuilder = new ManagedPEBuilder(
+ new PEHeaderBuilder(
+ machine: Machine.I386,
+ imageCharacteristics: Characteristics.ExecutableImage | Characteristics.Dll | Characteristics.Bit32Machine),
+ new MetadataRootBuilder(metadataBuilder, "WindowsRuntime 1.4"),
+ new BlobBuilder(),
+ flags: CorFlags.ILOnly);
+
+ var peBlob = new BlobBuilder();
+ managedPeBuilder.Serialize(peBlob);
+
+ using var fs = new FileStream(outputFile, FileMode.Create, FileAccess.Write);
+ peBlob.WriteContentTo(fs);
+ }
+
+ public void Execute(SourceGeneratorContext context)
+ {
+ Logger.Initialize(context);
+
+ try
+ {
+ string assembly = GetAssemblyName(context);
+ string version = GetAssemblyVersion(context);
+ MetadataBuilder metadataBuilder = new MetadataBuilder();
+
+ var writer = new WinRTTypeWriter(
+ assembly,
+ version,
+ metadataBuilder);
+ foreach (SyntaxTree tree in context.Compilation.SyntaxTrees)
+ {
+ writer.Model = context.Compilation.GetSemanticModel(tree);
+ writer.Visit(tree.GetRoot());
+ }
+ writer.FinalizeGeneration();
+
+ GenerateWinMD(metadataBuilder, GetWinmdOutputFile(context));
+ }
+ catch(Exception e)
+ {
+ Logger.Log(e.ToString());
+ if(e.InnerException != null)
+ {
+ Logger.Log(e.InnerException.ToString());
+ }
+ Logger.Close();
+ throw;
+ }
+
+ Logger.Log("Done");
+ Logger.Close();
+ }
+
+ public void Initialize(InitializationContext context)
+ {
+ }
+ }
+}
diff --git a/Authoring/WinRT.SourceGenerator/Logger.cs b/Authoring/WinRT.SourceGenerator/Logger.cs
new file mode 100644
index 000000000..9dc726af7
--- /dev/null
+++ b/Authoring/WinRT.SourceGenerator/Logger.cs
@@ -0,0 +1,30 @@
+using Microsoft.CodeAnalysis;
+using System.IO;
+
+namespace Generator
+{
+ class Logger
+ {
+ public static void Initialize(SourceGeneratorContext context)
+ {
+ context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.CsWinRTEnableLogging", out var enableLogging);
+ if(enableLogging != null && bool.Parse(enableLogging))
+ {
+ string logFile = Path.Combine(SourceGenerator.GetGeneratedFilesDir(context), "log.txt");
+ fileLogger = File.CreateText(logFile);
+ }
+ }
+
+ public static void Log(string text)
+ {
+ fileLogger?.WriteLine(text);
+ }
+
+ public static void Close()
+ {
+ fileLogger?.Close();
+ }
+
+ private static TextWriter fileLogger;
+ }
+}
diff --git a/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.csproj b/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.csproj
new file mode 100644
index 000000000..e3f170271
--- /dev/null
+++ b/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.csproj
@@ -0,0 +1,13 @@
+
+
+
+ netstandard2.0
+ preview
+
+
+
+
+
+
+
+
diff --git a/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs b/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs
new file mode 100644
index 000000000..7c503db9b
--- /dev/null
+++ b/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs
@@ -0,0 +1,1787 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Reflection.Metadata;
+using System.Reflection.Metadata.Ecma335;
+
+namespace Generator
+{
+ class Parameter
+ {
+ public Symbol Type;
+ public string Name;
+ public ParameterAttributes Attributes;
+
+ public Parameter(Symbol type, string name, ParameterAttributes attributes)
+ {
+ Type = type;
+ Name = name;
+ Attributes = attributes;
+ }
+
+ public Parameter(ITypeSymbol type, string name, ParameterAttributes attributes)
+ :this(new Symbol(type), name, attributes)
+ {
+ }
+
+ public Parameter(EntityHandle type, string name, ParameterAttributes attributes)
+ : this(new Symbol(type), name, attributes)
+ {
+ }
+
+ public Parameter(ParameterSyntax parameter, ParameterAttributes attributes, SemanticModel model)
+ {
+ Type = new Symbol(model.GetDeclaredSymbol(parameter).Type);
+ Name = parameter.Identifier.ValueText;
+ Attributes = attributes;
+ }
+ }
+
+ class Symbol
+ {
+ public ITypeSymbol Type;
+ public EntityHandle Handle;
+
+ public Symbol(ITypeSymbol type)
+ {
+ Type = type;
+ Handle = default;
+ }
+
+ public Symbol(EntityHandle handle)
+ {
+ Type = default;
+ Handle = handle;
+ }
+
+ public bool IsHandle()
+ {
+ return Handle != default;
+ }
+ }
+
+ class TypeDeclaration
+ {
+ public readonly ISymbol Node;
+ public TypeDefinitionHandle Handle;
+ public string DefaultInterface;
+
+ public Dictionary> MethodDefinitions = new Dictionary>();
+ public Dictionary> MethodReferences = new Dictionary>();
+ public Dictionary FieldDefinitions = new Dictionary();
+ public Dictionary PropertyDefinitions = new Dictionary();
+ public Dictionary EventDefinitions = new Dictionary();
+
+ public TypeDeclaration(ISymbol node)
+ {
+ Node = node;
+ }
+
+ public override string ToString()
+ {
+ return Node.ToString();
+ }
+
+ public void AddMethod(ISymbol node, MethodDefinitionHandle handle)
+ {
+ if(!MethodDefinitions.ContainsKey(node))
+ {
+ MethodDefinitions[node] = new List();
+ MethodReferences[node] = new List();
+ }
+
+ MethodDefinitions[node].Add(handle);
+ MethodReferences[node].Add(handle);
+ }
+
+ public void AddMethodReference(ISymbol node, MemberReferenceHandle handle)
+ {
+ if (!MethodReferences.ContainsKey(node))
+ {
+ MethodReferences[node] = new List();
+ }
+
+ MethodReferences[node].Add(handle);
+ }
+
+ public List GetMethodDefinitions()
+ {
+ return MethodDefinitions.Values.SelectMany(list => list).ToList();
+ }
+
+ public List GetMethodReferences()
+ {
+ return MethodReferences.Values.SelectMany(list => list).ToList();
+ }
+
+ public void AddField(ISymbol node, FieldDefinitionHandle handle)
+ {
+ FieldDefinitions[node] = handle;
+ }
+
+ public List GetFieldDefinitions()
+ {
+ return FieldDefinitions.Values.ToList();
+ }
+
+ public void AddProperty(ISymbol node, PropertyDefinitionHandle handle)
+ {
+ PropertyDefinitions[node] = handle;
+ }
+
+ public List GetPropertyDefinitions()
+ {
+ return PropertyDefinitions.Values.ToList();
+ }
+
+ public void AddEvent(ISymbol node, EventDefinitionHandle handle)
+ {
+ EventDefinitions[node] = handle;
+ }
+
+ public List GetEventDefinitions()
+ {
+ return EventDefinitions.Values.ToList();
+ }
+ }
+
+ class WinRTTypeWriter : CSharpSyntaxWalker
+ {
+ public SemanticModel Model;
+
+ private readonly string assembly;
+ private readonly string version;
+
+ private readonly Stack namespaces = new Stack();
+ private readonly Dictionary typeReferenceMapping;
+ private readonly Dictionary assemblyReferenceMapping;
+ private readonly List nodesWithAttributes;
+ private readonly MetadataBuilder metadataBuilder;
+ private bool hasConstructor;
+
+ private readonly Dictionary typeDefinitionMapping;
+ private TypeDeclaration currentTypeDeclaration;
+
+ public WinRTTypeWriter(
+ string assembly,
+ string version,
+ MetadataBuilder metadataBuilder)
+ {
+ this.assembly = assembly;
+ this.version = version;
+ this.metadataBuilder = metadataBuilder;
+ typeReferenceMapping = new Dictionary();
+ assemblyReferenceMapping = new Dictionary();
+ typeDefinitionMapping = new Dictionary();
+ nodesWithAttributes = new List();
+
+ CreteAssembly();
+ }
+
+ private void CreteAssembly()
+ {
+ Logger.Log("Generating assembly " + assembly + " version " + version);
+ metadataBuilder.AddAssembly(
+ metadataBuilder.GetOrAddString(assembly),
+ new Version(version),
+ default,
+ default,
+ AssemblyFlags.WindowsRuntime,
+ AssemblyHashAlgorithm.Sha1);
+
+ var moduleDefinition = metadataBuilder.AddModule(
+ 0,
+ metadataBuilder.GetOrAddString(assembly + ".winmd"),
+ metadataBuilder.GetOrAddGuid(Guid.NewGuid()),
+ default,
+ default);
+ assemblyReferenceMapping[assembly] = moduleDefinition;
+
+ metadataBuilder.AddTypeDefinition(
+ default,
+ default,
+ metadataBuilder.GetOrAddString(""),
+ default,
+ MetadataTokens.FieldDefinitionHandle(1),
+ MetadataTokens.MethodDefinitionHandle(1));
+ }
+
+ private void EncodeSpecialType(SpecialType specialType, SignatureTypeEncoder typeEncoder)
+ {
+ switch (specialType)
+ {
+ case SpecialType.System_Boolean:
+ typeEncoder.Boolean();
+ break;
+ case SpecialType.System_Byte:
+ typeEncoder.Byte();
+ break;
+ case SpecialType.System_Int16:
+ typeEncoder.Int16();
+ break;
+ case SpecialType.System_Int32:
+ typeEncoder.Int32();
+ break;
+ case SpecialType.System_Int64:
+ typeEncoder.Int64();
+ break;
+ case SpecialType.System_UInt16:
+ typeEncoder.UInt16();
+ break;
+ case SpecialType.System_UInt32:
+ typeEncoder.UInt32();
+ break;
+ case SpecialType.System_UInt64:
+ typeEncoder.UInt64();
+ break;
+ case SpecialType.System_Single:
+ typeEncoder.Single();
+ break;
+ case SpecialType.System_Double:
+ typeEncoder.Double();
+ break;
+ case SpecialType.System_Char:
+ typeEncoder.Char();
+ break;
+ case SpecialType.System_String:
+ typeEncoder.String();
+ break;
+ case SpecialType.System_Object:
+ typeEncoder.Object();
+ break;
+ case SpecialType.System_IntPtr:
+ typeEncoder.IntPtr();
+ break;
+ default:
+ Logger.Log("TODO special type: " + specialType);
+ break;
+ }
+
+ // TODO: handle C# interface mappings for special types
+ }
+
+ private BlobHandle GetStrongNameKey(string assembly)
+ {
+ if(assembly == "mscorlib")
+ {
+ byte[] mscorlibStrongName = { 0xb7, 0x7a, 0x5c, 0x56, 0x19, 0x34, 0xe0, 0x89 };
+ return metadataBuilder.GetOrAddBlob(mscorlibStrongName);
+ }
+
+ return default;
+ }
+
+ private EntityHandle GetTypeReference(string @namespace, string name, string assembly)
+ {
+ string fullname = QualifiedName(@namespace, name);
+ if (typeReferenceMapping.ContainsKey(fullname))
+ {
+ return typeReferenceMapping[fullname];
+ }
+
+ if (!assemblyReferenceMapping.ContainsKey(assembly))
+ {
+ EntityHandle assemblyReference = metadataBuilder.AddAssemblyReference(
+ metadataBuilder.GetOrAddString(assembly),
+ new Version(0xff, 0xff, 0xff, 0xff),
+ default,
+ GetStrongNameKey(assembly),
+ AssemblyFlags.ContentTypeMask,
+ default);
+ assemblyReferenceMapping[assembly] = assemblyReference;
+ }
+
+ var typeRef = metadataBuilder.AddTypeReference(
+ assemblyReferenceMapping[assembly],
+ metadataBuilder.GetOrAddString(@namespace),
+ metadataBuilder.GetOrAddString(name));
+ typeReferenceMapping[fullname] = typeRef;
+ return typeRef;
+ }
+
+ private EntityHandle GetTypeReference(ISymbol symbol)
+ {
+ string @namespace = symbol.ContainingNamespace.ToString();
+ string name = symbol.Name;
+
+ string assembly;
+ var winrtTypeAttribute = symbol.GetAttributes().
+ Where(attribute => attribute.AttributeClass.Name == "WindowsRuntimeTypeAttribute");
+ if (winrtTypeAttribute.Any())
+ {
+ assembly = (string) winrtTypeAttribute.First().ConstructorArguments[0].Value;
+ }
+ else
+ {
+ assembly = symbol.ContainingAssembly.Name;
+ }
+
+ return GetTypeReference(@namespace, name, assembly);
+ }
+
+ private void EncodeSymbol(Symbol symbol, SignatureTypeEncoder typeEncoder)
+ {
+ EntityHandle typeReference = symbol.IsHandle() ? symbol.Handle : GetTypeReference(symbol.Type);
+ typeEncoder.Type(typeReference, false);
+ }
+
+ private void EncodeReturnType(Symbol symbol, ReturnTypeEncoder returnTypeEncoder)
+ {
+ if(symbol == null)
+ {
+ returnTypeEncoder.Void();
+ }
+ else if(symbol.IsHandle() || symbol.Type.SpecialType == SpecialType.None)
+ {
+ EncodeSymbol(symbol, returnTypeEncoder.Type());
+ }
+ else if(symbol.Type.SpecialType == SpecialType.System_Void)
+ {
+ returnTypeEncoder.Void();
+ }
+ else
+ {
+ EncodeSpecialType(symbol.Type.SpecialType, returnTypeEncoder.Type());
+ }
+ }
+
+ private void EncodeParameters(Parameter[] parameters, ParametersEncoder parametersEncoder)
+ {
+ foreach (var parameter in parameters)
+ {
+ var parameterType = parameter.Type;
+ var parameterTypeEncoder = parametersEncoder.AddParameter();
+
+ if (!parameterType.IsHandle() && parameterType.Type.SpecialType != SpecialType.None)
+ {
+ EncodeSpecialType(parameterType.Type.SpecialType, parameterTypeEncoder.Type());
+ }
+ else
+ {
+ EncodeSymbol(parameterType, parameterTypeEncoder.Type());
+ }
+ }
+ }
+
+ public MethodDefinitionHandle AddMethodDefinition(
+ string name,
+ Parameter[] parameters,
+ Symbol returnSymbol,
+ bool isStatic,
+ bool isInterfaceParent,
+ bool isSpecialMethod = false,
+ bool isPublic = true,
+ bool isOverridable = false)
+ {
+ var methodSignature = new BlobBuilder();
+ new BlobEncoder(methodSignature)
+ .MethodSignature(
+ SignatureCallingConvention.Default,
+ parameters.Length,
+ !isStatic)
+ .Parameters(
+ parameters.Length,
+ returnType => EncodeReturnType(returnSymbol, returnType),
+ parametersEncoder => EncodeParameters(parameters, parametersEncoder)
+ );
+
+ List parameterHandles = new List();
+ for (int idx = 0; idx < parameters.Length; idx++)
+ {
+ parameterHandles.Add(metadataBuilder.AddParameter(
+ parameters[idx].Attributes,
+ metadataBuilder.GetOrAddString(parameters[idx].Name),
+ idx + 1));
+ }
+
+ var methodAttributes =
+ (isPublic ? MethodAttributes.Public : MethodAttributes.Private) |
+ MethodAttributes.HideBySig;
+
+ var methodImplAttributes = MethodImplAttributes.Managed;
+
+ if (isInterfaceParent)
+ {
+ methodAttributes |= MethodAttributes.Abstract;
+ }
+ else
+ {
+ // TODO check if from overridable interface
+ if (!isOverridable)
+ {
+ methodAttributes |= MethodAttributes.Final;
+ }
+ methodImplAttributes |= MethodImplAttributes.Runtime;
+ }
+
+ if (isSpecialMethod && name == ".ctor")
+ {
+ methodAttributes |= MethodAttributes.RTSpecialName;
+ }
+ else
+ {
+ methodAttributes |=
+ MethodAttributes.Virtual |
+ MethodAttributes.NewSlot;
+ }
+
+ if (isSpecialMethod)
+ {
+ methodAttributes |= MethodAttributes.SpecialName;
+ }
+
+ var methodDefinitionHandle = metadataBuilder.AddMethodDefinition(
+ methodAttributes,
+ methodImplAttributes,
+ metadataBuilder.GetOrAddString(name),
+ metadataBuilder.GetOrAddBlob(methodSignature),
+ -1,
+ parameterHandles.Count == 0 ?
+ MetadataTokens.ParameterHandle(metadataBuilder.GetRowCount(TableIndex.Param) + 1) :
+ parameterHandles[0]);
+ return methodDefinitionHandle;
+ }
+
+ public override void VisitMethodDeclaration(MethodDeclarationSyntax node)
+ {
+ Logger.Log("method: " + node.Identifier.ValueText);
+ if(!IsPublicNode(node))
+ {
+ return;
+ }
+
+ base.VisitMethodDeclaration(node);
+
+ int numParameters = node.ParameterList.Parameters.Count;
+ Parameter[] parameters = new Parameter[numParameters];
+ for(int idx = 0; idx < numParameters; idx++)
+ {
+ parameters[idx] = new Parameter(node.ParameterList.Parameters[idx], ParameterAttributes.In, Model);
+ }
+
+ var methodSymbol = Model.GetDeclaredSymbol(node);
+ var methodDefinitionHandle = AddMethodDefinition(
+ node.Identifier.ValueText,
+ parameters,
+ new Symbol(methodSymbol.ReturnType),
+ !IsStaticNode(node),
+ node.Parent is InterfaceDeclarationSyntax);
+ currentTypeDeclaration.AddMethod(methodSymbol, methodDefinitionHandle);
+ }
+
+ public override void VisitFieldDeclaration(FieldDeclarationSyntax node)
+ {
+ if (!IsPublicNode(node) || node.Parent is not StructDeclarationSyntax)
+ {
+ return;
+ }
+
+ base.VisitFieldDeclaration(node);
+
+ var symbol = Model.GetTypeInfo(node.Declaration.Type).Type;
+ var fieldSignature = new BlobBuilder();
+ var encoder = new BlobEncoder(fieldSignature);
+
+ if (symbol.SpecialType != SpecialType.None)
+ {
+ EncodeSpecialType(symbol.SpecialType, encoder.FieldSignature());
+ }
+ else
+ {
+ EncodeSymbol(new Symbol(symbol), encoder.FieldSignature());
+ }
+
+ foreach (var variable in node.Declaration.Variables)
+ {
+ var fieldSymbol = Model.GetDeclaredSymbol(variable);
+ var fieldDefinitionHandle = metadataBuilder.AddFieldDefinition(
+ FieldAttributes.Public,
+ metadataBuilder.GetOrAddString(variable.Identifier.Text),
+ metadataBuilder.GetOrAddBlob(fieldSignature));
+ currentTypeDeclaration.AddField(fieldSymbol, fieldDefinitionHandle);
+ }
+ }
+
+ public void AddPropertyDeclaration(IPropertySymbol property, bool isInterfaceParent)
+ {
+ Logger.Log("defining property " + property.Name);
+ Logger.Log("parent: " + property.ContainingType.Name);
+
+ var propertySignature = new BlobBuilder();
+ new BlobEncoder(propertySignature)
+ .PropertySignature(true)
+ .Parameters(
+ 0,
+ returnType => EncodeReturnType(new Symbol(property.Type), returnType),
+ parameters => { }
+ );
+
+ var propertyDefinitonHandle = metadataBuilder.AddProperty(
+ PropertyAttributes.None,
+ metadataBuilder.GetOrAddString(property.Name),
+ metadataBuilder.GetOrAddBlob(propertySignature));
+ currentTypeDeclaration.AddProperty(property, propertyDefinitonHandle);
+
+ if (property.SetMethod != null)
+ {
+ var setMethod = AddMethodDefinition(
+ "put_" + property.Name,
+ new Parameter[] { new Parameter(property.Type, "value", ParameterAttributes.In) },
+ null,
+ false,
+ isInterfaceParent,
+ true);
+ currentTypeDeclaration.AddMethod(property, setMethod);
+
+ metadataBuilder.AddMethodSemantics(
+ propertyDefinitonHandle,
+ MethodSemanticsAttributes.Setter,
+ setMethod);
+ }
+
+ var getMethod = AddMethodDefinition(
+ "get_" + property.Name,
+ new Parameter[0],
+ new Symbol(property.Type),
+ false,
+ isInterfaceParent,
+ true);
+ currentTypeDeclaration.AddMethod(property, getMethod);
+
+ metadataBuilder.AddMethodSemantics(
+ propertyDefinitonHandle,
+ MethodSemanticsAttributes.Getter,
+ getMethod);
+ }
+
+ public override void VisitPropertyDeclaration(PropertyDeclarationSyntax node)
+ {
+ base.VisitPropertyDeclaration(node);
+
+ var symbol = Model.GetDeclaredSymbol(node);
+
+ var propertySignature = new BlobBuilder();
+ new BlobEncoder(propertySignature)
+ .PropertySignature(true)
+ .Parameters(
+ 0,
+ returnType => EncodeReturnType(new Symbol(symbol.Type), returnType),
+ parameters => { }
+ );
+
+ var propertyDefinitonHandle = metadataBuilder.AddProperty(
+ PropertyAttributes.None,
+ metadataBuilder.GetOrAddString(node.Identifier.ValueText),
+ metadataBuilder.GetOrAddBlob(propertySignature));
+ currentTypeDeclaration.AddProperty(symbol, propertyDefinitonHandle);
+
+ if (symbol.SetMethod != null)
+ {
+ var setMethod = AddMethodDefinition(
+ "put_" + symbol.Name,
+ new Parameter[] { new Parameter(symbol.Type, "value", ParameterAttributes.In ) },
+ null,
+ false,
+ node.Parent is InterfaceDeclarationSyntax,
+ true);
+ currentTypeDeclaration.AddMethod(symbol, setMethod);
+
+ metadataBuilder.AddMethodSemantics(
+ propertyDefinitonHandle,
+ MethodSemanticsAttributes.Setter,
+ setMethod);
+ }
+
+ var getMethod = AddMethodDefinition(
+ "get_" + symbol.Name,
+ new Parameter[0],
+ new Symbol(symbol.Type),
+ false,
+ node.Parent is InterfaceDeclarationSyntax,
+ true);
+ currentTypeDeclaration.AddMethod(symbol, getMethod);
+
+ metadataBuilder.AddMethodSemantics(
+ propertyDefinitonHandle,
+ MethodSemanticsAttributes.Getter,
+ getMethod);
+ }
+
+ private TypeDefinitionHandle AddTypeDefinition(
+ TypeAttributes typeAttributes,
+ string @namespace,
+ string identifier,
+ EntityHandle baseType)
+ {
+ var fieldDefinitions = currentTypeDeclaration.GetFieldDefinitions();
+ var methodDefinitions = currentTypeDeclaration.GetMethodDefinitions();
+
+ var typeDefinitionHandle = metadataBuilder.AddTypeDefinition(
+ typeAttributes,
+ metadataBuilder.GetOrAddString(@namespace),
+ metadataBuilder.GetOrAddString(identifier),
+ baseType,
+ fieldDefinitions.Count == 0 ?
+ MetadataTokens.FieldDefinitionHandle(metadataBuilder.GetRowCount(TableIndex.Field) + 1) :
+ fieldDefinitions[0],
+ methodDefinitions.Count == 0 ?
+ MetadataTokens.MethodDefinitionHandle(metadataBuilder.GetRowCount(TableIndex.MethodDef) + 1) :
+ methodDefinitions[0]
+ );
+
+ var propertyDefinitions = currentTypeDeclaration.GetPropertyDefinitions();
+ if (propertyDefinitions.Count != 0)
+ {
+ metadataBuilder.AddPropertyMap(
+ typeDefinitionHandle,
+ propertyDefinitions[0]);
+ }
+
+ var eventDefinitions = currentTypeDeclaration.GetEventDefinitions();
+ if (eventDefinitions.Count != 0)
+ {
+ metadataBuilder.AddEventMap(
+ typeDefinitionHandle,
+ eventDefinitions[0]);
+ }
+
+ return typeDefinitionHandle;
+ }
+
+ private void ProcessTypeDeclaration(BaseTypeDeclarationSyntax node, Action visitTypeDeclaration)
+ {
+ if(!IsPublicNode(node))
+ {
+ return;
+ }
+
+ var symbol = Model.GetDeclaredSymbol(node);
+ currentTypeDeclaration = new TypeDeclaration(symbol);
+
+ visitTypeDeclaration();
+
+ TypeAttributes typeAttributes =
+ TypeAttributes.Public |
+ TypeAttributes.WindowsRuntime |
+ TypeAttributes.AutoLayout |
+ TypeAttributes.AnsiClass;
+
+ if (IsSealedNode(node) ||
+ (node is EnumDeclarationSyntax ||
+ node is StructDeclarationSyntax))
+ {
+ typeAttributes |= TypeAttributes.Sealed;
+ }
+
+ EntityHandle baseType = default;
+ if(node is InterfaceDeclarationSyntax)
+ {
+ typeAttributes |=
+ TypeAttributes.Interface |
+ TypeAttributes.Abstract;
+ }
+ else if(node is ClassDeclarationSyntax)
+ {
+ typeAttributes |=
+ TypeAttributes.Class |
+ TypeAttributes.BeforeFieldInit;
+
+ // extens
+ if (node.BaseList != null)
+ {
+ foreach (var type in node.BaseList.Types)
+ {
+ var typeSymbol = Model.GetTypeInfo(type.Type).Type;
+ if(typeSymbol.TypeKind == TypeKind.Class)
+ {
+ baseType = GetTypeReference(typeSymbol);
+ break;
+ }
+ }
+ }
+ else
+ {
+ baseType = GetTypeReference("System", "Object", "mscorlib");
+ }
+ }
+ else if(node is StructDeclarationSyntax)
+ {
+ typeAttributes |= TypeAttributes.SequentialLayout;
+ baseType = GetTypeReference("System", "ValueType", "mscorlib");
+ }
+ else if(node is EnumDeclarationSyntax)
+ {
+ baseType = GetTypeReference("System", "Enum", "mscorlib");
+ }
+
+ var typeDefinitionHandle = AddTypeDefinition(
+ typeAttributes,
+ GetNamespace(),
+ node.Identifier.ValueText,
+ baseType);
+ currentTypeDeclaration.Handle = typeDefinitionHandle;
+
+ if (node.BaseList != null && (node is InterfaceDeclarationSyntax || node is ClassDeclarationSyntax))
+ {
+ foreach (var implementedInterface in symbol.AllInterfaces.
+ OrderBy(implementedInterface => implementedInterface.ToString()))
+ {
+ metadataBuilder.AddInterfaceImplementation(
+ typeDefinitionHandle,
+ GetTypeReference(implementedInterface));
+ }
+ }
+
+ typeDefinitionMapping[QualifiedName(node.Identifier.ValueText)] = currentTypeDeclaration;
+ }
+
+ public override void VisitInterfaceDeclaration(InterfaceDeclarationSyntax node)
+ {
+ ProcessTypeDeclaration(node, () => base.VisitInterfaceDeclaration(node));
+ }
+
+ public override void VisitClassDeclaration(ClassDeclarationSyntax node)
+ {
+ void processClassDeclaration()
+ {
+ hasConstructor = false;
+ base.VisitClassDeclaration(node);
+
+ // implicit constructor if none defined
+ if(!hasConstructor)
+ {
+ var methodDefinitionHandle = AddMethodDefinition(
+ ".ctor",
+ new Parameter[0],
+ null,
+ false,
+ false,
+ true,
+ true,
+ true);
+ var symbol = Model.GetDeclaredSymbol(node);
+ currentTypeDeclaration.AddMethod(symbol, methodDefinitionHandle);
+ }
+ }
+
+ ProcessTypeDeclaration(node, processClassDeclaration);
+
+ if (IsPublicNode(node))
+ {
+ AddSynthesizedInterfaces(currentTypeDeclaration);
+ }
+ }
+
+ public override void VisitStructDeclaration(StructDeclarationSyntax node)
+ {
+ ProcessTypeDeclaration(node, () => base.VisitStructDeclaration(node));
+ }
+
+ private void EncodeTypedConstant(TypedConstant constant, LiteralEncoder encoder)
+ {
+ Logger.Log("typed constant kind: " + constant.Kind);
+ Logger.Log("typed constant type: " + constant.Type);
+ Logger.Log("typed constant value: " + constant.Value);
+
+ switch (constant.Kind)
+ {
+ case TypedConstantKind.Primitive:
+ encoder.Scalar().Constant(constant.Value);
+ break;
+ case TypedConstantKind.Enum:
+ encoder.TaggedScalar(
+ type => type.Enum(constant.Type.ToString()),
+ scalar => scalar.Constant(constant.Value)
+ );
+ break;
+ case TypedConstantKind.Type:
+ encoder.Scalar().SystemType(constant.Type.ToString());
+ break;
+ case TypedConstantKind.Array:
+ {
+ LiteralsEncoder arrayEncoder = encoder.Vector().Count(constant.Values.Length);
+ foreach(var arrayConstant in constant.Values)
+ {
+ EncodeTypedConstant(arrayConstant, arrayEncoder.AddLiteral());
+ }
+ break;
+ }
+ }
+
+ }
+
+ private void EncodeFixedArguments(IList arguments, FixedArgumentsEncoder argumentsEncoder)
+ {
+ foreach(var argument in arguments)
+ {
+ EncodeTypedConstant(argument, argumentsEncoder.AddArgument());
+ }
+ }
+
+ private void EncodeCustomElementType(IFieldSymbol field, CustomAttributeElementTypeEncoder typeEncoder)
+ {
+ switch (field.Type.SpecialType)
+ {
+ case SpecialType.System_Boolean:
+ typeEncoder.Boolean();
+ break;
+ case SpecialType.System_Byte:
+ typeEncoder.Byte();
+ break;
+ case SpecialType.System_Int16:
+ typeEncoder.Int16();
+ break;
+ case SpecialType.System_Int32:
+ typeEncoder.Int32();
+ break;
+ case SpecialType.System_Int64:
+ typeEncoder.Int64();
+ break;
+ case SpecialType.System_UInt16:
+ typeEncoder.UInt16();
+ break;
+ case SpecialType.System_UInt32:
+ typeEncoder.UInt32();
+ break;
+ case SpecialType.System_UInt64:
+ typeEncoder.UInt64();
+ break;
+ case SpecialType.System_Single:
+ typeEncoder.Single();
+ break;
+ case SpecialType.System_Double:
+ typeEncoder.Double();
+ break;
+ case SpecialType.System_Char:
+ typeEncoder.Char();
+ break;
+ case SpecialType.System_String:
+ typeEncoder.String();
+ break;
+ case SpecialType.System_Enum:
+ typeEncoder.Enum(field.Type.ToString());
+ break;
+ case SpecialType.System_SByte:
+ typeEncoder.SByte();
+ break;
+ default:
+ Logger.Log("TODO special type: " + field.Type.SpecialType);
+ break;
+ }
+ }
+
+ private void EncodeNamedArgumentType(INamedTypeSymbol attributeType, string field, NamedArgumentTypeEncoder encoder)
+ {
+ Logger.Log("encoding named type");
+ var fieldMembers = attributeType.GetMembers(field);
+ Logger.Log("# fields: " + fieldMembers.Count());
+ var fieldSymbol = fieldMembers.First() as IFieldSymbol;
+ Logger.Log("found field: " + fieldSymbol);
+
+ if(fieldSymbol.Type.SpecialType == SpecialType.System_Object)
+ {
+ encoder.Object();
+ }
+ else if(fieldSymbol.Type.SpecialType == SpecialType.System_Array)
+ {
+ // TODO array type encoder
+ encoder.SZArray();
+ }
+ else
+ {
+ EncodeCustomElementType(fieldSymbol, encoder.ScalarType());
+ }
+ }
+
+ private void EncodeNamedArguments(INamedTypeSymbol attributeType, IList> namedArguments, CustomAttributeNamedArgumentsEncoder argumentsEncoder)
+ {
+ var encoder = argumentsEncoder.Count(namedArguments.Count);
+ foreach (var argument in namedArguments)
+ {
+ Logger.Log("named argument: " + argument.Key);
+ Logger.Log("value " + argument.Value);
+
+ encoder.AddArgument(
+ true,
+ type => EncodeNamedArgumentType(attributeType, argument.Key, type),
+ name => name.Name(argument.Key),
+ literal => EncodeTypedConstant(argument.Value, literal)
+ );
+ }
+ }
+
+ private void EncodeFixedArguments(IList