From 19ceee6047a3f083bbf573400ef8596ea66ad2d1 Mon Sep 17 00:00:00 2001 From: Daniel Paoliello Date: Tue, 4 Jun 2024 11:34:15 -0700 Subject: [PATCH] When finding a type def from a type ref, search all assemblies (#1919) --- .../ClangSharpSourceWinmdGenerator.cs | 55 +++++++++---------- sources/MetadataUtils/WinmdUtils.cs | 34 +++++++++--- sources/WinmdUtils/Program.cs | 8 ++- tests/MetadataUtils.Tests/WinmdUtilsTests.cs | 24 ++++++-- 4 files changed, 77 insertions(+), 44 deletions(-) diff --git a/sources/ClangSharpSourceToWinmd/ClangSharpSourceWinmdGenerator.cs b/sources/ClangSharpSourceToWinmd/ClangSharpSourceWinmdGenerator.cs index 5854cc0e..0523a264 100644 --- a/sources/ClangSharpSourceToWinmd/ClangSharpSourceWinmdGenerator.cs +++ b/sources/ClangSharpSourceToWinmd/ClangSharpSourceWinmdGenerator.cs @@ -544,44 +544,43 @@ namespace ClangSharpSourceToWinmd interfaceWalker.Visit(tree.GetRoot()); } - foreach (var r in this.compilation.References) + var allWinmds = this.compilation.References.Where(r => !r.Display.EndsWith("netstandard.dll")).Select(r => MetadataUtils.WinmdUtils.LoadFromFile(r.Display)).ToList(); + + foreach (var winmd in allWinmds) { - if (r.Display.EndsWith("netstandard.dll")) + foreach (var typeInfo in winmd.GetTypes(allWinmds)) { - continue; - } - - using (var winmd = MetadataUtils.WinmdUtils.LoadFromFile(r.Display)) - { - foreach (var typeInfo in winmd.GetTypes()) + if (typeInfo is MetadataUtils.InterfaceInfo interfaceInfo) { - if (typeInfo is MetadataUtils.InterfaceInfo interfaceInfo) - { - this.CacheInterfaceInfo(interfaceInfo); - } - else if (typeInfo is MetadataUtils.StructInfo) - { - var fullName = $"{typeInfo.Namespace}.{typeInfo.Name}"; - var typeSymbol = this.compilation.GetTypeByMetadataName(fullName); + this.CacheInterfaceInfo(interfaceInfo); + } + else if (typeInfo is MetadataUtils.StructInfo) + { + var fullName = $"{typeInfo.Namespace}.{typeInfo.Name}"; + var typeSymbol = this.compilation.GetTypeByMetadataName(fullName); - if (typeSymbol != null) - { - this.nameToSymbols[typeInfo.Name] = typeSymbol; - } - } - else if (typeInfo is MetadataUtils.DelegateTypeInfo) + if (typeSymbol != null) { - var fullName = $"{typeInfo.Namespace}.{typeInfo.Name}"; - var typeSymbol = this.compilation.GetTypeByMetadataName(fullName); + this.nameToSymbols[typeInfo.Name] = typeSymbol; + } + } + else if (typeInfo is MetadataUtils.DelegateTypeInfo) + { + var fullName = $"{typeInfo.Namespace}.{typeInfo.Name}"; + var typeSymbol = this.compilation.GetTypeByMetadataName(fullName); - if (typeSymbol != null) - { - this.nameToSymbols[typeInfo.Name] = typeSymbol; - } + if (typeSymbol != null) + { + this.nameToSymbols[typeInfo.Name] = typeSymbol; } } } } + + foreach (var winmd in allWinmds) + { + winmd.Dispose(); + } } } diff --git a/sources/MetadataUtils/WinmdUtils.cs b/sources/MetadataUtils/WinmdUtils.cs index 5965b305..bb9c192c 100644 --- a/sources/MetadataUtils/WinmdUtils.cs +++ b/sources/MetadataUtils/WinmdUtils.cs @@ -131,7 +131,7 @@ namespace MetadataUtils } } - public IEnumerable GetTypes() + public IEnumerable GetTypes(List allWinmds) { foreach (var typeDefHandle in this.metadataReader.TypeDefinitions) { @@ -185,7 +185,7 @@ namespace MetadataUtils } else if (typeDef.Attributes.HasFlag(TypeAttributes.Interface)) { - var implementedMethodCount = this.InternalGetImplementedMethodCount(typeDef); + var implementedMethodCount = this.InternalGetImplementedMethodCount(typeDef, allWinmds); var methodInfos = this.GetMethodInfos(typeDef.GetMethods()); yield return new InterfaceInfo(ns, name, methodInfos, implementedMethodCount); } @@ -207,7 +207,7 @@ namespace MetadataUtils } } - private int InternalGetImplementedMethodCount(TypeDefinition typeDef) + private int InternalGetImplementedMethodCount(TypeDefinition typeDef, List allWinmds) { int methodCount = typeDef.GetMethods().Count; var interfaceImplHandles = typeDef.GetInterfaceImplementations(); @@ -220,12 +220,7 @@ namespace MetadataUtils { case HandleKind.TypeReference: { - var interfaceTypeRefHandle = this.metadataReader.GetTypeReference((TypeReferenceHandle)interfaceImpl.Interface); - interfaceTypeDef = this.metadataReader.TypeDefinitions - .Select(h => this.metadataReader.GetTypeDefinition(h)) - .First(iterType => - this.metadataReader.GetString(iterType.Name) == this.metadataReader.GetString(interfaceTypeRefHandle.Name) && - this.metadataReader.GetString(iterType.Namespace) == this.metadataReader.GetString(interfaceTypeRefHandle.Namespace)); + interfaceTypeDef = this.GetDefinitionFromReference(this.metadataReader.GetTypeReference((TypeReferenceHandle)interfaceImpl.Interface), allWinmds); break; } @@ -243,6 +238,27 @@ namespace MetadataUtils return methodCount; } + + public TypeDefinition GetDefinitionFromReference(TypeReference typeReference, List allWinmds) + { + var name = this.metadataReader.GetString(typeReference.Name); + var @namespace = this.metadataReader.GetString(typeReference.Namespace); + + foreach (var winmd in allWinmds) + { + foreach (var typeDefinitionHandle in winmd.metadataReader.TypeDefinitions) + { + var typeDefinition = winmd.metadataReader.GetTypeDefinition(typeDefinitionHandle); + if (winmd.metadataReader.GetString(typeDefinition.Name) == name && + winmd.metadataReader.GetString(typeDefinition.Namespace) == @namespace) + { + return typeDefinition; + } + } + } + + throw new InvalidOperationException($"Could not find definition for '{@namespace}.{name}'"); + } } public class TypeInfo diff --git a/sources/WinmdUtils/Program.cs b/sources/WinmdUtils/Program.cs index a15e1e7b..40ad1094 100644 --- a/sources/WinmdUtils/Program.cs +++ b/sources/WinmdUtils/Program.cs @@ -417,13 +417,14 @@ namespace WinmdUtilsProgram public static int ShowPointersToDelegates(FileInfo winmd, string[] allowItem, IConsole console) { + List allWinmds = new List(); HashSet allowTable = new HashSet(allowItem); using WinmdUtils w1 = WinmdUtils.LoadFromFile(winmd.FullName); bool pointersFound = false; - HashSet delegateNames = new HashSet(w1.GetTypes().Where(t => t is DelegateTypeInfo).Select(d => $"{d.Namespace}.{d.Name}")); + HashSet delegateNames = new HashSet(w1.GetTypes(allWinmds).Where(t => t is DelegateTypeInfo).Select(d => $"{d.Namespace}.{d.Name}")); - foreach (var type in w1.GetTypes()) + foreach (var type in w1.GetTypes(allWinmds)) { foreach (var pointerInUse in PointerToOneOfNamesInUse(delegateNames, type)) { @@ -690,10 +691,11 @@ namespace WinmdUtilsProgram public static int ShowEmptyDelegates(FileInfo winmd, string[] allowItem, IConsole console) { + List allWinmds = new List(); HashSet allowTable = new HashSet(allowItem); using WinmdUtils w1 = WinmdUtils.LoadFromFile(winmd.FullName); bool emptyFound = false; - foreach (DelegateTypeInfo type in w1.GetTypes().Where(t => t is DelegateTypeInfo)) + foreach (DelegateTypeInfo type in w1.GetTypes(allWinmds).Where(t => t is DelegateTypeInfo)) { if (!type.Parameters.Any()) { diff --git a/tests/MetadataUtils.Tests/WinmdUtilsTests.cs b/tests/MetadataUtils.Tests/WinmdUtilsTests.cs index ad1a5e2c..3f2e256f 100644 --- a/tests/MetadataUtils.Tests/WinmdUtilsTests.cs +++ b/tests/MetadataUtils.Tests/WinmdUtilsTests.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System.Collections.Generic; +using System.Linq; using System.Reflection; using Xunit; @@ -8,6 +9,7 @@ namespace MetadataUtils.Tests public interface IFoo { void B(); } public interface IBar : IBase { void C(); } public interface IQux : IFoo, IBar { void D(); } + public interface IInheritsFromOther : IRegexConstHelper { } public class WinmdUtilsTests { @@ -18,7 +20,7 @@ namespace MetadataUtils.Tests // Act using var metadata = WinmdUtils.LoadFromFile(Assembly.GetExecutingAssembly().Location); - var typeInfo = metadata.GetTypes().First(t => t.Name == "IQux") as InterfaceInfo; + var typeInfo = metadata.GetTypes(new List { metadata }).First(t => t.Name == "IQux") as InterfaceInfo; // Assert Assert.Equal(4, typeInfo.ImplementedMethodCount); @@ -31,7 +33,7 @@ namespace MetadataUtils.Tests // Act using var metadata = WinmdUtils.LoadFromFile(Assembly.GetExecutingAssembly().Location); - var typeInfo = metadata.GetTypes().First(t => t.Name == "IFoo") as InterfaceInfo; + var typeInfo = metadata.GetTypes(new List { metadata }).First(t => t.Name == "IFoo") as InterfaceInfo; // Assert Assert.Equal(1, typeInfo.ImplementedMethodCount); @@ -44,10 +46,24 @@ namespace MetadataUtils.Tests // Act using var metadata = WinmdUtils.LoadFromFile(Assembly.GetExecutingAssembly().Location); - var typeInfo = metadata.GetTypes().First(t => t.Name == "IBar") as InterfaceInfo; + var typeInfo = metadata.GetTypes(new List { metadata }).First(t => t.Name == "IBar") as InterfaceInfo; // Assert Assert.Equal(2, typeInfo.ImplementedMethodCount); } + + [Fact] + public void GetTypes_InterfaceHeirarchyPresent_InheritFromOtherAssembly() + { + // Arrange + + // Act + using var otherMetadata = WinmdUtils.LoadFromFile(typeof(IRegexConstHelper).Assembly.Location); + using var metadata = WinmdUtils.LoadFromFile(Assembly.GetExecutingAssembly().Location); + var typeInfo = metadata.GetTypes(new List { metadata, otherMetadata }).First(t => t.Name == "IInheritsFromOther") as InterfaceInfo; + + // Assert + Assert.Equal(typeof(IRegexConstHelper).GetMethods().Length, typeInfo.ImplementedMethodCount); + } } }