diff --git a/MetadataProcessor.Core/DumpGenerator/DumpTemplates.cs b/MetadataProcessor.Core/DumpGenerator/DumpTemplates.cs index 1412476b..cbbc4401 100644 --- a/MetadataProcessor.Core/DumpGenerator/DumpTemplates.cs +++ b/MetadataProcessor.Core/DumpGenerator/DumpTemplates.cs @@ -23,6 +23,10 @@ internal partial class DumpTemplates {{#each TypeDefinitions}} TypeDefProps [{{ReferenceId}}]: Flags: {{Flags}} Extends: {{ExtendsType}} Enclosed: {{EnclosedType}} '{{Name}}'{{#newline}} +{{#each GenericParameters}} + GenericParam [{{GenericParamToken}}]: Position: ({{Position}}) '{{Name}}' Owner: {{Owner}} [{{Signature}}]{{#newline}} +{{/each}} + {{#each FieldDefinitions}} FieldDefProps [{{ReferenceId}}]: Attr: {{Attributes}} Flags: {{Flags}} '{{Name}}' [{{Signature}}]{{#newline}} {{/each}} diff --git a/MetadataProcessor.Core/DumpGenerator/GenericParam.cs b/MetadataProcessor.Core/DumpGenerator/GenericParam.cs new file mode 100644 index 00000000..010876ce --- /dev/null +++ b/MetadataProcessor.Core/DumpGenerator/GenericParam.cs @@ -0,0 +1,20 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +namespace nanoFramework.Tools.MetadataProcessor.Core +{ + public class GenericParam + { + public string Position; + + public string GenericParamToken; + + public string Name; + + public string Owner; + + public string Signature; + } +} diff --git a/MetadataProcessor.Core/DumpGenerator/TypeDef.cs b/MetadataProcessor.Core/DumpGenerator/TypeDef.cs index 75aa4ade..51b42990 100644 --- a/MetadataProcessor.Core/DumpGenerator/TypeDef.cs +++ b/MetadataProcessor.Core/DumpGenerator/TypeDef.cs @@ -19,6 +19,7 @@ public class TypeDef public string Name; + public List GenericParameters = new List(); public List FieldDefinitions = new List(); public List MethodDefinitions = new List(); public List InterfaceDefinitions = new List(); diff --git a/MetadataProcessor.Core/Extensions/TypeReferenceExtensions.cs b/MetadataProcessor.Core/Extensions/TypeReferenceExtensions.cs index 120e2495..499115df 100644 --- a/MetadataProcessor.Core/Extensions/TypeReferenceExtensions.cs +++ b/MetadataProcessor.Core/Extensions/TypeReferenceExtensions.cs @@ -97,7 +97,8 @@ public static string TypeSignatureAsString(this TypeReference type) return byrefSig.ToString(); } - if (type.IsGenericParameter) + if (type.IsGenericParameter || + type.IsGenericInstance) { return $"!!{type.Name}"; } diff --git a/MetadataProcessor.Core/MetadataProcessor.Core.csproj b/MetadataProcessor.Core/MetadataProcessor.Core.csproj index 09ff1f37..9f6017a5 100644 --- a/MetadataProcessor.Core/MetadataProcessor.Core.csproj +++ b/MetadataProcessor.Core/MetadataProcessor.Core.csproj @@ -55,6 +55,7 @@ + @@ -92,6 +93,7 @@ + diff --git a/MetadataProcessor.Core/Tables/nanoGenericParamTable.cs b/MetadataProcessor.Core/Tables/nanoGenericParamTable.cs new file mode 100644 index 00000000..d5a16fc6 --- /dev/null +++ b/MetadataProcessor.Core/Tables/nanoGenericParamTable.cs @@ -0,0 +1,88 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +using Mono.Cecil; +using System; +using System.Collections.Generic; + +namespace nanoFramework.Tools.MetadataProcessor +{ + /// + /// Encapsulates logic for storing generic parameters list and writing + /// this collected list into target assembly in .NET nanoFramework format. + /// + public sealed class nanoGenericParamTable : + nanoReferenceTableBase + { + /// + /// Helper class for comparing two instances of objects + /// using property as unique key for comparison. + /// + private sealed class MemberReferenceComparer : IEqualityComparer + { + /// + public bool Equals(GenericParameter x, GenericParameter y) + { + if (x is null) + { + throw new ArgumentNullException(nameof(x)); + } + + if (y is null) + { + throw new ArgumentNullException(nameof(y)); + } + + return x.MetadataToken.ToInt32() == y.MetadataToken.ToInt32(); + } + + /// + public int GetHashCode(GenericParameter obj) + { + return obj.MetadataToken.ToInt32().GetHashCode(); + } + } + + /// + /// Creates new instance of object. + /// + /// List of member references in Mono.Cecil format. + /// + /// Assembly tables context - contains all tables used for building target assembly. + /// + public nanoGenericParamTable( + IEnumerable items, + nanoTablesContext context) + : base(items, new MemberReferenceComparer(), context) + { + } + + /// + /// Gets method reference ID if possible (if method is external and stored in this table). + /// + /// Method reference metadata in Mono.Cecil format. + /// Method reference ID in .NET nanoFramework format. + /// Returns true if reference found, otherwise returns false. + public bool TryGetParameterId( + GenericParameter genericParameter, + out ushort referenceId) + { + return TryGetIdByValue(genericParameter, out referenceId); + } + + /// + protected override void WriteSingleItem( + nanoBinaryWriter writer, + GenericParameter item) + { + if (!_context.MinimizeComplete) + { + return; + } + + // TODO + } + } +} diff --git a/MetadataProcessor.Core/Tables/nanoSignaturesTable.cs b/MetadataProcessor.Core/Tables/nanoSignaturesTable.cs index 1e45a08b..df5b3168 100644 --- a/MetadataProcessor.Core/Tables/nanoSignaturesTable.cs +++ b/MetadataProcessor.Core/Tables/nanoSignaturesTable.cs @@ -665,10 +665,19 @@ private void WriteSubTypeInfo(TypeReference typeDefinition, nanoBinaryWriter wri writer.WriteMetadataToken(((uint)referenceId << 2) | 0x01); } else if (_context.TypeDefinitionTable.TryGetTypeReferenceId( - typeDefinition.Resolve(), out referenceId)) + typeDefinition.Resolve(), + out referenceId)) { writer.WriteMetadataToken((uint)referenceId << 2); } + else if (typeDefinition.Resolve().HasGenericParameters && + _context.GenericParamsTable.TryGetParameterId( + typeDefinition.Resolve().GenericParameters.FirstOrDefault(), + out referenceId)) + { + // TODO + writer.WriteMetadataToken((uint)referenceId << 2); + } else { throw new ArgumentException($"Can't find entry in type reference table for {typeDefinition.FullName}."); diff --git a/MetadataProcessor.Core/Tables/nanoTablesContext.cs b/MetadataProcessor.Core/Tables/nanoTablesContext.cs index fdb64058..960632ce 100644 --- a/MetadataProcessor.Core/Tables/nanoTablesContext.cs +++ b/MetadataProcessor.Core/Tables/nanoTablesContext.cs @@ -115,14 +115,17 @@ public nanoTablesContext( var memberReferences = mainModule.GetMemberReferences() .Where(item => (typeReferencesNames.Contains(item.DeclaringType.FullName) || - item.DeclaringType.GetElementType().IsPrimitive)) + item.DeclaringType.GetElementType().IsPrimitive || + item.ContainsGenericParameter || + item.DeclaringType.IsGenericInstance)) + .ToList(); FieldReferencesTable = new nanoFieldReferenceTable( memberReferences.OfType(), this); MethodReferencesTable = new nanoMethodReferenceTable( memberReferences.OfType(), this); - + // Internal types definitions var types = GetOrderedTypes(mainModule, explicitTypesOrder); @@ -133,7 +136,6 @@ public nanoTablesContext( .SelectMany(item => GetOrderedFields(item.Fields.Where(field => !field.HasConstant))) .ToList(); FieldsTable = new nanoFieldDefinitionTable(fields, this); - var methods = types.SelectMany(item => GetOrderedMethods(item.Methods)).ToList(); MethodDefinitionTable = new nanoMethodDefinitionTable(methods, this); @@ -172,6 +174,24 @@ public nanoTablesContext( ResourceFileTable = new nanoResourceFileTable(this); + // build list of generic parameters belonging to method defs + List methodDefsGenericParameters = new List(); + + foreach (var m in methods) + { + if (m.HasGenericParameters) + { + methodDefsGenericParameters.AddRange(m.GenericParameters); + } + } + + var generics = types + .SelectMany(t => t.GenericParameters) + .Concat(methodDefsGenericParameters) + .ToList(); + + GenericParamsTable = new nanoGenericParamTable(generics, this); + // Pre-allocate strings from some tables AssemblyReferenceTable.AllocateStrings(); TypeReferencesTable.AllocateStrings(); @@ -223,6 +243,8 @@ public ushort GetMethodReferenceId( public nanoFieldReferenceTable FieldReferencesTable { get; private set; } + public nanoGenericParamTable GenericParamsTable { get; private set; } + public nanoMethodReferenceTable MethodReferencesTable { get; private set; } public nanoFieldDefinitionTable FieldsTable { get; private set; } diff --git a/MetadataProcessor.Core/nanoAssemblyBuilder.cs b/MetadataProcessor.Core/nanoAssemblyBuilder.cs index aea8a6dd..61566b2b 100644 --- a/MetadataProcessor.Core/nanoAssemblyBuilder.cs +++ b/MetadataProcessor.Core/nanoAssemblyBuilder.cs @@ -5,6 +5,7 @@ // using Mono.Cecil; +using Mono.Cecil.Cil; using Mono.Collections.Generic; using nanoFramework.Tools.MetadataProcessor.Core.Extensions; using System; @@ -514,6 +515,15 @@ private HashSet BuildDependencyList(MetadataToken token) } } + // generic parameters + foreach (var g in td.GenericParameters) + { + if (!nanoTablesContext.ClassNamesToExclude.Contains(g.DeclaringType.FullName)) + { + set.Add(g.MetadataToken); + } + } + // methods foreach (var m in td.Methods) { @@ -620,6 +630,15 @@ private HashSet BuildDependencyList(MetadataToken token) set.Add(md.ReturnType.MetadataToken); } + // generic parameters + if(md.HasGenericParameters) + { + foreach (var gp in md.GenericParameters) + { + set.Add(gp.MetadataToken); + } + } + // parameters foreach (var p in md.Parameters) { @@ -707,7 +726,9 @@ private HashSet BuildDependencyList(MetadataToken token) i.Operand is FieldReference || i.Operand is TypeDefinition || i.Operand is TypeSpecification || - i.Operand is TypeReference) + i.Operand is TypeReference || + i.Operand is GenericInstanceType || + i.Operand is GenericParameter) { set.Add(((IMetadataTokenProvider)i.Operand).MetadataToken); } @@ -763,6 +784,16 @@ i.Operand is TypeSpecification || } break; + + case TokenType.GenericParam: + case TokenType.AssemblyRef: + case TokenType.String: + // we are good with these, nothing to do here + break; + + default: + Debug.Fail($"Unable to process token {token}."); + break; } return set; @@ -823,6 +854,26 @@ private string TokenToString(MetadataToken token) output.Append(fd.Name); break; + case TokenType.GenericParam: + var gp = _tablesContext.GenericParamsTable.Items.FirstOrDefault(g => g.MetadataToken == token); + + output.Append($"[GenericParam 0x{token.ToUInt32().ToString("X8")}]"); + + if (gp.DeclaringType != null) + { + output.Append(TokenToString(gp.DeclaringType.MetadataToken)); + output.Append("::"); + } + else if(gp.DeclaringMethod != null) + { + output.Append(TokenToString(gp.DeclaringMethod.MetadataToken)); + output.Append("::"); + } + + output.Append(gp.Name); + + break; + case TokenType.Method: var md = _tablesContext.MethodDefinitionTable.Items.FirstOrDefault(i => i.MetadataToken == token); @@ -879,6 +930,17 @@ private string TokenToString(MetadataToken token) typeRef = fr.DeclaringType; typeName = fr.Name; } + else + { + // try now with generic parameters + var gr = _tablesContext.GenericParamsTable.Items.FirstOrDefault(g => g.MetadataToken == token); + + if (gr != null) + { + typeRef = gr.DeclaringType; + typeName = gr.Name; + } + } } Debug.Assert(typeRef != null); @@ -916,6 +978,10 @@ private string TokenToString(MetadataToken token) output.Append($"'{sr}'"); } break; + + default: + Debug.Fail($"Unable to process token {token}."); + break; } // output token ID if empty diff --git a/MetadataProcessor.Core/nanoDumperGenerator.cs b/MetadataProcessor.Core/nanoDumperGenerator.cs index 31c50f9e..3f6b70de 100644 --- a/MetadataProcessor.Core/nanoDumperGenerator.cs +++ b/MetadataProcessor.Core/nanoDumperGenerator.cs @@ -224,6 +224,21 @@ private void DumpTypeDefinitions(DumpAllTable dumpTable) typeDef.EnclosedType = token.ToInt32().ToString("x8"); } + // list generic parameters + foreach (var gp in t.GenericParameters) + { + var genericParam = new GenericParam() + { + Position = gp.Position.ToString(), + GenericParamToken = gp.MetadataToken.ToInt32().ToString("x8"), + Name = gp.FullName, + Owner = gp.Owner.MetadataToken.ToInt32().ToString("x8"), + Signature = gp.DeclaringType.Name + }; + + typeDef.GenericParameters.Add(genericParam); + } + // list type fields foreach (var f in t.Fields) { diff --git a/MetadataProcessor.Core/nanoSkeletonGenerator.cs b/MetadataProcessor.Core/nanoSkeletonGenerator.cs index 1d21c1ad..0e489aad 100644 --- a/MetadataProcessor.Core/nanoSkeletonGenerator.cs +++ b/MetadataProcessor.Core/nanoSkeletonGenerator.cs @@ -4,7 +4,6 @@ // using Mono.Cecil; -using Mono.Cecil.Rocks; using Mustache; using nanoFramework.Tools.MetadataProcessor.Core.Extensions; using System; diff --git a/nanoFramework.Tools.MetadataProcessor.sln b/nanoFramework.Tools.MetadataProcessor.sln index af5531aa..1ba555de 100644 --- a/nanoFramework.Tools.MetadataProcessor.sln +++ b/nanoFramework.Tools.MetadataProcessor.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.28307.902 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30717.126 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MetadataProcessor.Core", "MetadataProcessor.Core\MetadataProcessor.Core.csproj", "{E32F7D15-2499-440C-8026-4D5EE1C5EC3A}" EndProject diff --git a/version.json b/version.json index 78fb9bd7..3388a533 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/AArnott/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", - "version": "2.29", + "version": "2.30", "release": { "branchName" : "release-v{version}", "versionIncrement" : "build",