mirror of https://github.com/icsharpcode/ILSpy.git
25 changed files with 1233 additions and 477 deletions
@ -0,0 +1,154 @@
@@ -0,0 +1,154 @@
|
||||
// Copyright (c) 2022 Siegfried Pammer
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
// software and associated documentation files (the "Software"), to deal in the Software
|
||||
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or
|
||||
// substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#nullable enable |
||||
|
||||
using System; |
||||
using System.Collections.Immutable; |
||||
using System.Reflection.Metadata; |
||||
|
||||
using ICSharpCode.Decompiler.TypeSystem; |
||||
using ICSharpCode.Decompiler.Util; |
||||
|
||||
namespace ICSharpCode.Decompiler.Metadata |
||||
{ |
||||
public class FindTypeDecoder : ISignatureTypeProvider<bool, Unit> |
||||
{ |
||||
readonly PEFile declaringModule; |
||||
readonly MetadataModule? currentModule; |
||||
readonly TypeDefinitionHandle handle; |
||||
readonly string? typeName; |
||||
readonly string? namespaceName; |
||||
readonly PrimitiveTypeCode primitiveType; |
||||
|
||||
/// <summary>
|
||||
/// Constructs a FindTypeDecoder that finds uses of a specific type-definition handle.
|
||||
/// This assumes that the module we are search in is the same as the module containing the type-definiton.
|
||||
/// </summary>
|
||||
internal FindTypeDecoder(TypeDefinitionHandle handle, PEFile declaringModule) |
||||
{ |
||||
this.handle = handle; |
||||
this.declaringModule = declaringModule; |
||||
this.primitiveType = 0; |
||||
this.currentModule = null; |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Constructs a FindTypeDecoder that can be used to find <paramref name="type"/> in signatures from <paramref name="currentModule"/>.
|
||||
/// </summary>
|
||||
public FindTypeDecoder(MetadataModule currentModule, ITypeDefinition type) |
||||
{ |
||||
this.currentModule = currentModule; |
||||
this.declaringModule = type.ParentModule.PEFile ?? throw new InvalidOperationException("Cannot use MetadataModule without PEFile as context."); |
||||
this.handle = (TypeDefinitionHandle)type.MetadataToken; |
||||
this.primitiveType = type.KnownTypeCode == KnownTypeCode.None ? 0 : type.KnownTypeCode.ToPrimitiveTypeCode(); |
||||
this.typeName = type.MetadataName; |
||||
this.namespaceName = type.Namespace; |
||||
} |
||||
|
||||
|
||||
|
||||
public bool GetArrayType(bool elementType, ArrayShape shape) => elementType; |
||||
public bool GetByReferenceType(bool elementType) => elementType; |
||||
public bool GetFunctionPointerType(MethodSignature<bool> signature) |
||||
{ |
||||
return AnyInMethodSignature(signature); |
||||
} |
||||
|
||||
public static bool AnyInMethodSignature(MethodSignature<bool> signature) |
||||
{ |
||||
if (signature.ReturnType) |
||||
return true; |
||||
foreach (bool type in signature.ParameterTypes) |
||||
{ |
||||
if (type) |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
public bool GetGenericInstantiation(bool genericType, ImmutableArray<bool> typeArguments) |
||||
{ |
||||
if (genericType) |
||||
return true; |
||||
foreach (bool ta in typeArguments) |
||||
{ |
||||
if (ta) |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
public bool GetGenericMethodParameter(Unit genericContext, int index) => false; |
||||
public bool GetGenericTypeParameter(Unit genericContext, int index) => false; |
||||
public bool GetModifiedType(bool modifier, bool unmodifiedType, bool isRequired) => unmodifiedType || modifier; |
||||
public bool GetPinnedType(bool elementType) => elementType; |
||||
public bool GetPointerType(bool elementType) => elementType; |
||||
|
||||
public bool GetPrimitiveType(PrimitiveTypeCode typeCode) |
||||
{ |
||||
return typeCode == primitiveType; |
||||
} |
||||
|
||||
public bool GetSZArrayType(bool elementType) => elementType; |
||||
|
||||
public bool GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) |
||||
{ |
||||
return this.handle == handle && reader == declaringModule.Metadata; |
||||
} |
||||
|
||||
public bool GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) |
||||
{ |
||||
if (currentModule == null || typeName == null || namespaceName == null) |
||||
return false; |
||||
|
||||
var tr = reader.GetTypeReference(handle); |
||||
if (!reader.StringComparer.Equals(tr.Name, typeName)) |
||||
return false; |
||||
if (!((tr.Namespace.IsNil && namespaceName.Length == 0) || reader.StringComparer.Equals(tr.Namespace, namespaceName))) |
||||
return false; |
||||
|
||||
var t = currentModule.ResolveType(handle, default); |
||||
var td = t.GetDefinition(); |
||||
if (td == null) |
||||
return false; |
||||
|
||||
return td.MetadataToken == this.handle && td.ParentModule.PEFile == declaringModule; |
||||
} |
||||
|
||||
public bool GetTypeFromSpecification(MetadataReader reader, Unit genericContext, TypeSpecificationHandle handle, byte rawTypeKind) |
||||
{ |
||||
return reader.GetTypeSpecification(handle).DecodeSignature(this, genericContext); |
||||
} |
||||
|
||||
public bool GetTypeFromEntity(MetadataReader reader, EntityHandle handle, Unit genericContext = default, byte rawTypeKind = 0) |
||||
{ |
||||
switch (handle.Kind) |
||||
{ |
||||
case HandleKind.TypeReference: |
||||
return GetTypeFromReference(reader, (TypeReferenceHandle)handle, rawTypeKind); |
||||
case HandleKind.TypeDefinition: |
||||
return GetTypeFromDefinition(reader, (TypeDefinitionHandle)handle, rawTypeKind); |
||||
case HandleKind.TypeSpecification: |
||||
return GetTypeFromSpecification(reader, genericContext, (TypeSpecificationHandle)handle, rawTypeKind); |
||||
default: |
||||
return false; |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,79 @@
@@ -0,0 +1,79 @@
|
||||
// Copyright (c) 2018 Siegfried Pammer
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
// software and associated documentation files (the "Software"), to deal in the Software
|
||||
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or
|
||||
// substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
using System.Reflection.Metadata; |
||||
|
||||
using ICSharpCode.Decompiler.Metadata; |
||||
using ICSharpCode.Decompiler.TypeSystem; |
||||
|
||||
namespace ICSharpCode.ILSpy.Analyzers |
||||
{ |
||||
internal static class AnalyzerHelpers |
||||
{ |
||||
public static bool IsPossibleReferenceTo(EntityHandle member, PEFile module, IMethod analyzedMethod) |
||||
{ |
||||
if (member.IsNil) |
||||
return false; |
||||
MetadataReader metadata = module.Metadata; |
||||
switch (member.Kind) |
||||
{ |
||||
case HandleKind.MethodDefinition: |
||||
return member == analyzedMethod.MetadataToken |
||||
&& module == analyzedMethod.ParentModule.PEFile; |
||||
case HandleKind.MemberReference: |
||||
var mr = metadata.GetMemberReference((MemberReferenceHandle)member); |
||||
if (mr.GetKind() != MemberReferenceKind.Method) |
||||
return false; |
||||
return metadata.StringComparer.Equals(mr.Name, analyzedMethod.Name); |
||||
case HandleKind.MethodSpecification: |
||||
var ms = metadata.GetMethodSpecification((MethodSpecificationHandle)member); |
||||
return IsPossibleReferenceTo(ms.Method, module, analyzedMethod); |
||||
default: |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
public static ISymbol GetParentEntity(DecompilerTypeSystem ts, CustomAttribute customAttribute) |
||||
{ |
||||
var metadata = ts.MainModule.PEFile.Metadata; |
||||
switch (customAttribute.Parent.Kind) |
||||
{ |
||||
case HandleKind.MethodDefinition: |
||||
IMethod parent = (IMethod)ts.MainModule.ResolveEntity(customAttribute.Parent); |
||||
return parent?.AccessorOwner ?? parent; |
||||
case HandleKind.FieldDefinition: |
||||
case HandleKind.PropertyDefinition: |
||||
case HandleKind.EventDefinition: |
||||
case HandleKind.TypeDefinition: |
||||
return ts.MainModule.ResolveEntity(customAttribute.Parent); |
||||
case HandleKind.AssemblyDefinition: |
||||
case HandleKind.ModuleDefinition: |
||||
return ts.MainModule; |
||||
case HandleKind.GenericParameterConstraint: |
||||
var gpc = metadata.GetGenericParameterConstraint((GenericParameterConstraintHandle)customAttribute.Parent); |
||||
var gp = metadata.GetGenericParameter(gpc.Parameter); |
||||
return ts.MainModule.ResolveEntity(gp.Parent); |
||||
case HandleKind.GenericParameter: |
||||
gp = metadata.GetGenericParameter((GenericParameterHandle)customAttribute.Parent); |
||||
return ts.MainModule.ResolveEntity(gp.Parent); |
||||
default: |
||||
return null; |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,158 @@
@@ -0,0 +1,158 @@
|
||||
// Copyright (c) 2022 Siegfried Pammer
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
// software and associated documentation files (the "Software"), to deal in the Software
|
||||
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or
|
||||
// substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#nullable enable |
||||
|
||||
using System; |
||||
using System.Reflection.Metadata; |
||||
|
||||
using ICSharpCode.Decompiler; |
||||
using ICSharpCode.Decompiler.Metadata; |
||||
using ICSharpCode.Decompiler.TypeSystem; |
||||
|
||||
namespace ICSharpCode.ILSpy.Analyzers.Builtin |
||||
{ |
||||
public enum TokenSearchResult : byte |
||||
{ |
||||
NoResult = 0, |
||||
Byte = PrimitiveTypeCode.Byte, |
||||
SByte = PrimitiveTypeCode.SByte, |
||||
Int16 = PrimitiveTypeCode.Int16, |
||||
UInt16 = PrimitiveTypeCode.UInt16, |
||||
Int32 = PrimitiveTypeCode.Int32, |
||||
UInt32 = PrimitiveTypeCode.UInt32, |
||||
Int64 = PrimitiveTypeCode.Int64, |
||||
UInt64 = PrimitiveTypeCode.UInt64, |
||||
IntPtr = PrimitiveTypeCode.IntPtr, |
||||
UIntPtr = PrimitiveTypeCode.UIntPtr, |
||||
|
||||
// lowest PrimitiveTypeCode is 1
|
||||
// highest PrimitiveTypeCode is 28 (0b0001_1100)
|
||||
// TokenSearchResult with a PrimitiveTypeCode set is only used when decoding an enum-type.
|
||||
// It is used for GetUnderlyingEnumType and should be masked out in all other uses.
|
||||
// MSB = Found
|
||||
// 127 = System.Type
|
||||
TypeCodeMask = 0b0111_1111, |
||||
Found = 0b1000_0000, |
||||
SystemType = 127, |
||||
} |
||||
|
||||
class FindTypeInAttributeDecoder : ICustomAttributeTypeProvider<TokenSearchResult> |
||||
{ |
||||
readonly PEFile declaringModule; |
||||
readonly MetadataModule currentModule; |
||||
readonly TypeDefinitionHandle handle; |
||||
readonly PrimitiveTypeCode primitiveType; |
||||
|
||||
/// <summary>
|
||||
/// Constructs a FindTypeInAttributeDecoder that can be used to find <paramref name="type"/> in signatures from <paramref name="currentModule"/>.
|
||||
/// </summary>
|
||||
public FindTypeInAttributeDecoder(MetadataModule currentModule, ITypeDefinition type) |
||||
{ |
||||
this.currentModule = currentModule; |
||||
this.declaringModule = type.ParentModule.PEFile ?? throw new InvalidOperationException("Cannot use MetadataModule without PEFile as context."); |
||||
this.handle = (TypeDefinitionHandle)type.MetadataToken; |
||||
this.primitiveType = type.KnownTypeCode == KnownTypeCode.None ? 0 : type.KnownTypeCode.ToPrimitiveTypeCode(); |
||||
} |
||||
|
||||
public TokenSearchResult GetPrimitiveType(PrimitiveTypeCode typeCode) |
||||
{ |
||||
return typeCode == primitiveType ? TokenSearchResult.Found : 0; |
||||
} |
||||
|
||||
public TokenSearchResult GetSystemType() => TokenSearchResult.SystemType; |
||||
|
||||
public TokenSearchResult GetSZArrayType(TokenSearchResult elementType) => elementType & TokenSearchResult.Found; |
||||
|
||||
public TokenSearchResult GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) |
||||
{ |
||||
TokenSearchResult result = TokenSearchResult.NoResult; |
||||
|
||||
if (handle.IsEnum(reader, out PrimitiveTypeCode underlyingType)) |
||||
{ |
||||
result = (TokenSearchResult)underlyingType; |
||||
} |
||||
else if (((EntityHandle)handle).IsKnownType(reader, KnownTypeCode.Type)) |
||||
{ |
||||
result = TokenSearchResult.SystemType; |
||||
} |
||||
if (this.handle == handle && reader == declaringModule.Metadata) |
||||
{ |
||||
result |= TokenSearchResult.Found; |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
public TokenSearchResult GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) |
||||
{ |
||||
var t = currentModule.ResolveType(handle, default); |
||||
return GetResultFromResolvedType(t); |
||||
} |
||||
|
||||
public TokenSearchResult GetTypeFromSerializedName(string name) |
||||
{ |
||||
if (name == null) |
||||
{ |
||||
return TokenSearchResult.NoResult; |
||||
} |
||||
try |
||||
{ |
||||
IType type = ReflectionHelper.ParseReflectionName(name) |
||||
.Resolve(new SimpleTypeResolveContext(currentModule)); |
||||
return GetResultFromResolvedType(type); |
||||
} |
||||
catch (ReflectionNameParseException) |
||||
{ |
||||
return TokenSearchResult.NoResult; |
||||
} |
||||
} |
||||
|
||||
private TokenSearchResult GetResultFromResolvedType(IType type) |
||||
{ |
||||
var td = type.GetDefinition(); |
||||
if (td == null) |
||||
return TokenSearchResult.NoResult; |
||||
|
||||
TokenSearchResult result = TokenSearchResult.NoResult; |
||||
var underlyingType = td.EnumUnderlyingType?.GetDefinition(); |
||||
if (underlyingType != null) |
||||
{ |
||||
result = (TokenSearchResult)underlyingType.KnownTypeCode.ToPrimitiveTypeCode(); |
||||
} |
||||
else if (td.KnownTypeCode == KnownTypeCode.Type) |
||||
{ |
||||
result = TokenSearchResult.SystemType; |
||||
} |
||||
if (td.MetadataToken == this.handle && td.ParentModule.PEFile == declaringModule) |
||||
{ |
||||
result |= TokenSearchResult.Found; |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
public PrimitiveTypeCode GetUnderlyingEnumType(TokenSearchResult type) |
||||
{ |
||||
TokenSearchResult typeCode = type & TokenSearchResult.TypeCodeMask; |
||||
if (typeCode == 0 || typeCode == TokenSearchResult.SystemType) |
||||
throw new EnumUnderlyingTypeResolveException(); |
||||
return (PrimitiveTypeCode)typeCode; |
||||
} |
||||
|
||||
public bool IsSystemType(TokenSearchResult type) => (type & TokenSearchResult.TypeCodeMask) == TokenSearchResult.SystemType; |
||||
} |
||||
} |
@ -0,0 +1,199 @@
@@ -0,0 +1,199 @@
|
||||
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
// software and associated documentation files (the "Software"), to deal in the Software
|
||||
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or
|
||||
// substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#nullable enable |
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Collections.Immutable; |
||||
using System.Linq; |
||||
using System.Threading.Tasks; |
||||
|
||||
using ICSharpCode.Decompiler.Metadata; |
||||
using ICSharpCode.Decompiler.Util; |
||||
|
||||
namespace ICSharpCode.ILSpy |
||||
{ |
||||
class AssemblyListSnapshot |
||||
{ |
||||
readonly ImmutableArray<LoadedAssembly> assemblies; |
||||
Dictionary<string, PEFile>? asmLookupByFullName; |
||||
Dictionary<string, PEFile>? asmLookupByShortName; |
||||
Dictionary<string, List<(PEFile module, Version version)>>? asmLookupByShortNameGrouped; |
||||
public ImmutableArray<LoadedAssembly> Assemblies => assemblies; |
||||
|
||||
public AssemblyListSnapshot(ImmutableArray<LoadedAssembly> assemblies) |
||||
{ |
||||
this.assemblies = assemblies; |
||||
} |
||||
|
||||
public async Task<PEFile?> TryGetModuleAsync(IAssemblyReference reference, string tfm) |
||||
{ |
||||
bool isWinRT = reference.IsWindowsRuntime; |
||||
if (tfm.StartsWith(".NETFramework,Version=v4.", StringComparison.Ordinal)) |
||||
{ |
||||
tfm = ".NETFramework,Version=v4"; |
||||
} |
||||
string key = tfm + ";" + (isWinRT ? reference.Name : reference.FullName); |
||||
var lookup = LazyInit.VolatileRead(ref isWinRT ? ref asmLookupByShortName : ref asmLookupByFullName); |
||||
if (lookup == null) |
||||
{ |
||||
lookup = await CreateLoadedAssemblyLookupAsync(shortNames: isWinRT).ConfigureAwait(false); |
||||
lookup = LazyInit.GetOrSet(ref isWinRT ? ref asmLookupByShortName : ref asmLookupByFullName, lookup); |
||||
} |
||||
if (lookup.TryGetValue(key, out PEFile module)) |
||||
return module; |
||||
return null; |
||||
} |
||||
|
||||
public async Task<PEFile?> TryGetSimilarModuleAsync(IAssemblyReference reference) |
||||
{ |
||||
var lookup = LazyInit.VolatileRead(ref asmLookupByShortNameGrouped); |
||||
if (lookup == null) |
||||
{ |
||||
lookup = await CreateLoadedAssemblyShortNameGroupLookupAsync().ConfigureAwait(false); |
||||
lookup = LazyInit.GetOrSet(ref asmLookupByShortNameGrouped, lookup); |
||||
} |
||||
|
||||
if (!lookup.TryGetValue(reference.Name, out var candidates)) |
||||
return null; |
||||
return candidates.FirstOrDefault(c => c.version >= reference.Version).module ?? candidates.Last().module; |
||||
} |
||||
|
||||
private async Task<Dictionary<string, PEFile>> CreateLoadedAssemblyLookupAsync(bool shortNames) |
||||
{ |
||||
var result = new Dictionary<string, PEFile>(StringComparer.OrdinalIgnoreCase); |
||||
foreach (LoadedAssembly loaded in assemblies) |
||||
{ |
||||
try |
||||
{ |
||||
var module = await loaded.GetPEFileOrNullAsync().ConfigureAwait(false); |
||||
if (module == null) |
||||
continue; |
||||
var reader = module.Metadata; |
||||
if (reader == null || !reader.IsAssembly) |
||||
continue; |
||||
string tfm = await loaded.GetTargetFrameworkIdAsync().ConfigureAwait(false); |
||||
if (tfm.StartsWith(".NETFramework,Version=v4.", StringComparison.Ordinal)) |
||||
{ |
||||
tfm = ".NETFramework,Version=v4"; |
||||
} |
||||
string key = tfm + ";" |
||||
+ (shortNames ? module.Name : module.FullName); |
||||
if (!result.ContainsKey(key)) |
||||
{ |
||||
result.Add(key, module); |
||||
} |
||||
} |
||||
catch (BadImageFormatException) |
||||
{ |
||||
continue; |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
private async Task<Dictionary<string, List<(PEFile module, Version version)>>> CreateLoadedAssemblyShortNameGroupLookupAsync() |
||||
{ |
||||
var result = new Dictionary<string, List<(PEFile module, Version version)>>(StringComparer.OrdinalIgnoreCase); |
||||
|
||||
foreach (LoadedAssembly loaded in assemblies) |
||||
{ |
||||
try |
||||
{ |
||||
var module = await loaded.GetPEFileOrNullAsync().ConfigureAwait(false); |
||||
var reader = module?.Metadata; |
||||
if (reader == null || !reader.IsAssembly) |
||||
continue; |
||||
var asmDef = reader.GetAssemblyDefinition(); |
||||
var asmDefName = reader.GetString(asmDef.Name); |
||||
|
||||
var line = (module!, version: asmDef.Version); |
||||
|
||||
if (!result.TryGetValue(asmDefName, out var existing)) |
||||
{ |
||||
existing = new List<(PEFile module, Version version)>(); |
||||
result.Add(asmDefName, existing); |
||||
existing.Add(line); |
||||
continue; |
||||
} |
||||
|
||||
int index = existing.BinarySearch(line.version, l => l.version); |
||||
index = index < 0 ? ~index : index + 1; |
||||
existing.Insert(index, line); |
||||
} |
||||
catch (BadImageFormatException) |
||||
{ |
||||
continue; |
||||
} |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
/// <summary>
|
||||
/// Gets all loaded assemblies recursively, including assemblies found in bundles or packages.
|
||||
/// </summary>
|
||||
public async Task<IList<LoadedAssembly>> GetAllAssembliesAsync() |
||||
{ |
||||
var results = new List<LoadedAssembly>(assemblies.Length); |
||||
|
||||
foreach (var asm in assemblies) |
||||
{ |
||||
LoadedAssembly.LoadResult result; |
||||
try |
||||
{ |
||||
result = await asm.GetLoadResultAsync().ConfigureAwait(false); |
||||
} |
||||
catch |
||||
{ |
||||
results.Add(asm); |
||||
continue; |
||||
} |
||||
if (result.Package != null) |
||||
{ |
||||
AddDescendants(result.Package.RootFolder); |
||||
} |
||||
else if (result.PEFile != null) |
||||
{ |
||||
results.Add(asm); |
||||
} |
||||
} |
||||
|
||||
void AddDescendants(PackageFolder folder) |
||||
{ |
||||
foreach (var subFolder in folder.Folders) |
||||
{ |
||||
AddDescendants(subFolder); |
||||
} |
||||
|
||||
foreach (var entry in folder.Entries) |
||||
{ |
||||
if (!entry.Name.EndsWith(".dll", StringComparison.OrdinalIgnoreCase)) |
||||
continue; |
||||
var asm = folder.ResolveFileName(entry.Name); |
||||
if (asm == null) |
||||
continue; |
||||
results.Add(asm); |
||||
} |
||||
} |
||||
|
||||
return results; |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue