diff --git a/Directory.Build.props b/Directory.Build.props
index 13a85bb60..128e21272 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -7,7 +7,7 @@
https://github.com/Washi1337/AsmResolver
git
10
- 5.0.0-beta.2
+ 5.0.0
diff --git a/src/AsmResolver.DotNet.Dynamic/DynamicCilOperandResolver.cs b/src/AsmResolver.DotNet.Dynamic/DynamicCilOperandResolver.cs
index 3efbe83d1..8f4b202f4 100644
--- a/src/AsmResolver.DotNet.Dynamic/DynamicCilOperandResolver.cs
+++ b/src/AsmResolver.DotNet.Dynamic/DynamicCilOperandResolver.cs
@@ -96,7 +96,8 @@ public DynamicCilOperandResolver(SerializedModuleDefinition contextModule, CilMe
case TableIndex.StandAloneSig:
var reader = new BinaryStreamReader((byte[])_tokens[(int)token.Rid]!);
- return CallingConventionSignature.FromReader(new BlobReadContext(_readerContext), ref reader);
+ var blobReadContext = new BlobReaderContext(_readerContext);
+ return CallingConventionSignature.FromReader(ref blobReadContext, ref reader);
}
return token;
diff --git a/src/AsmResolver.DotNet.Dynamic/DynamicMethodHelper.cs b/src/AsmResolver.DotNet.Dynamic/DynamicMethodHelper.cs
index 3563096b6..27e3d27c3 100644
--- a/src/AsmResolver.DotNet.Dynamic/DynamicMethodHelper.cs
+++ b/src/AsmResolver.DotNet.Dynamic/DynamicMethodHelper.cs
@@ -19,8 +19,8 @@ public static void ReadLocalVariables(CilMethodBody methodBody, MethodDefinition
throw new ArgumentException("Method body should reference a serialized module.");
var reader = new BinaryStreamReader(localSig);
- var context = new BlobReadContext(module.ReaderContext, DynamicTypeSignatureResolver.Instance);
- if (CallingConventionSignature.FromReader(context, ref reader)
+ var context = new BlobReaderContext(module.ReaderContext, DynamicTypeSignatureResolver.Instance);
+ if (CallingConventionSignature.FromReader(ref context, ref reader)
is not LocalVariablesSignature localsSignature)
{
throw new ArgumentException("Invalid local variables signature.");
diff --git a/src/AsmResolver.DotNet.Dynamic/DynamicTypeSignatureReader.cs b/src/AsmResolver.DotNet.Dynamic/DynamicTypeSignatureReader.cs
index 969ef3f0a..876ae9f4c 100644
--- a/src/AsmResolver.DotNet.Dynamic/DynamicTypeSignatureReader.cs
+++ b/src/AsmResolver.DotNet.Dynamic/DynamicTypeSignatureReader.cs
@@ -41,7 +41,7 @@ static DynamicTypeSignatureResolver()
public static bool IsSupported => GetTypeFromHandleUnsafeMethod is not null;
///
- public override TypeSignature ResolveRuntimeType(in BlobReadContext context, nint address)
+ public override TypeSignature ResolveRuntimeType(ref BlobReaderContext context, nint address)
{
if (!IsSupported)
throw new PlatformNotSupportedException("The current platform does not support the translation of raw type handles to System.Type instances.");
diff --git a/src/AsmResolver.DotNet/AsmResolver.DotNet.csproj b/src/AsmResolver.DotNet/AsmResolver.DotNet.csproj
index edf05784b..344e5b44a 100644
--- a/src/AsmResolver.DotNet/AsmResolver.DotNet.csproj
+++ b/src/AsmResolver.DotNet/AsmResolver.DotNet.csproj
@@ -28,7 +28,7 @@
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
diff --git a/src/AsmResolver.DotNet/AssemblyDefinition.cs b/src/AsmResolver.DotNet/AssemblyDefinition.cs
index fabe500a6..e379cf590 100644
--- a/src/AsmResolver.DotNet/AssemblyDefinition.cs
+++ b/src/AsmResolver.DotNet/AssemblyDefinition.cs
@@ -106,7 +106,7 @@ protected AssemblyDefinition(MetadataToken token)
///
/// The name of the assembly.
/// The version of the assembly.
- public AssemblyDefinition(string? name, Version version)
+ public AssemblyDefinition(Utf8String? name, Version version)
: this(new MetadataToken(TableIndex.Assembly, 0))
{
Name = name;
@@ -290,11 +290,9 @@ public void Write(string filePath, IPEImageBuilder imageBuilder, IPEFileBuilder
for (int i = 0; i < Modules.Count; i++)
{
var module = Modules[i];
- string modulePath;
- if (module == ManifestModule)
- modulePath = filePath;
- else
- modulePath = Path.Combine(directory, module.Name ?? $"module{i}.bin");
+ string modulePath = module == ManifestModule
+ ? filePath
+ : Path.Combine(directory, module.Name?.Value ?? $"module{i}.bin");
module.Write(modulePath, imageBuilder, fileBuilder);
}
diff --git a/src/AsmResolver.DotNet/AssemblyReference.cs b/src/AsmResolver.DotNet/AssemblyReference.cs
index f699d00fc..d4432896c 100644
--- a/src/AsmResolver.DotNet/AssemblyReference.cs
+++ b/src/AsmResolver.DotNet/AssemblyReference.cs
@@ -1,4 +1,5 @@
using System;
+using System.Threading;
using AsmResolver.Collections;
using AsmResolver.PE.DotNet.Metadata.Tables;
using AsmResolver.PE.DotNet.Metadata.Tables.Rows;
@@ -34,7 +35,7 @@ protected AssemblyReference(MetadataToken token)
///
/// The name of the assembly.
/// The version of the assembly.
- public AssemblyReference(string? name, Version version)
+ public AssemblyReference(Utf8String? name, Version version)
: this(new MetadataToken(TableIndex.AssemblyRef, 0))
{
Name = name;
@@ -50,7 +51,7 @@ public AssemblyReference(string? name, Version version)
/// unhashed public key used to verify the authenticity of the assembly.
/// Indicates the public key or token (depending on ),
/// used to verify the authenticity of the assembly.
- public AssemblyReference(string? name, Version version, bool publicKey, byte[]? publicKeyOrToken)
+ public AssemblyReference(Utf8String? name, Version version, bool publicKey, byte[]? publicKeyOrToken)
: this(new MetadataToken(TableIndex.AssemblyRef, 0))
{
Name = name;
@@ -128,9 +129,14 @@ public byte[]? HashValue
if (!HasPublicKey)
return PublicKeyOrToken;
- _publicKeyToken ??= PublicKeyOrToken != null
- ? ComputePublicKeyToken(PublicKeyOrToken, Resolve()?.HashAlgorithm ?? AssemblyHashAlgorithm.Sha1)
- : null;
+ if (_publicKeyToken is null && PublicKeyOrToken is not null)
+ {
+ lock (_publicKeyOrToken)
+ {
+ if (_publicKeyToken is null && PublicKeyOrToken is not null)
+ _publicKeyToken = ComputePublicKeyToken(PublicKeyOrToken, AssemblyHashAlgorithm.Sha1);
+ }
+ }
return _publicKeyToken;
}
diff --git a/src/AsmResolver.DotNet/Builder/Metadata/Strings/StringsStreamBlob.cs b/src/AsmResolver.DotNet/Builder/Metadata/Strings/StringsStreamBlob.cs
index f048ba4c8..9dcc1f167 100644
--- a/src/AsmResolver.DotNet/Builder/Metadata/Strings/StringsStreamBlob.cs
+++ b/src/AsmResolver.DotNet/Builder/Metadata/Strings/StringsStreamBlob.cs
@@ -6,7 +6,7 @@ namespace AsmResolver.DotNet.Builder.Metadata.Strings
{
public StringsStreamBlob(Utf8String blob, bool isFixed)
{
- Blob = blob.GetBytesUnsafe();
+ Blob = blob;
Flags = isFixed
? StringsStreamBlobFlags.ZeroTerminated | StringsStreamBlobFlags.Fixed
: StringsStreamBlobFlags.ZeroTerminated;
diff --git a/src/AsmResolver.DotNet/Builder/Metadata/Tables/SortedMetadataTableBuffer.cs b/src/AsmResolver.DotNet/Builder/Metadata/Tables/SortedMetadataTableBuffer.cs
index 7f33b1694..9928a14f1 100644
--- a/src/AsmResolver.DotNet/Builder/Metadata/Tables/SortedMetadataTableBuffer.cs
+++ b/src/AsmResolver.DotNet/Builder/Metadata/Tables/SortedMetadataTableBuffer.cs
@@ -15,7 +15,14 @@ public class SortedMetadataTableBuffer : ISortedMetadataTableBuffer<
where TKey : notnull
where TRow : struct, IMetadataRow
{
- private readonly List<(TKey Key, TRow Row)> _entries = new();
+ ///
+ /// The entries that this table will contain.
+ /// - Key: The original key to be able to assign metadata tokens easily after sorting.
+ /// - Row: The metadata row that was constructed for this key.
+ /// - InputIndex: An index to ensure a stable sort.
+ ///
+ private readonly List<(TKey Key, TRow Row, int InputIndex)> _entries = new();
+
private readonly Dictionary _newTokens = new();
private readonly MetadataTable _table;
private readonly EntryComparer _comparer;
@@ -48,7 +55,7 @@ public SortedMetadataTableBuffer(MetadataTable table, int primaryColumn, i
///
public void Add(TKey originalKey, in TRow row)
{
- _entries.Add((originalKey, row));
+ _entries.Add((originalKey, row, _entries.Count));
}
///
@@ -61,7 +68,7 @@ public void Sort()
for (uint rid = 1; rid <= _entries.Count; rid++)
{
- var (member, _) = _entries[(int) (rid - 1)];
+ var member = _entries[(int) (rid - 1)].Key;
_newTokens[member] = new MetadataToken(_table.TableIndex, rid);
}
}
@@ -73,6 +80,7 @@ public void Sort()
public void FlushToTable()
{
Sort();
+
_table.Clear();
foreach (var row in _entries)
_table.Add(row.Row);
@@ -85,7 +93,7 @@ public void Clear()
_table.Clear();
}
- private sealed class EntryComparer : IComparer<(TKey Key, TRow Row)>
+ private sealed class EntryComparer : IComparer<(TKey Key, TRow Row, int InputIndex)>
{
private readonly int _primaryColumn;
private readonly int _secondaryColumn;
@@ -96,11 +104,13 @@ public EntryComparer(int primaryColumn, int secondaryColumn)
_secondaryColumn = secondaryColumn;
}
- public int Compare((TKey Key, TRow Row) x, (TKey Key, TRow Row) y)
+ public int Compare((TKey Key, TRow Row, int InputIndex) x, (TKey Key, TRow Row, int InputIndex) y)
{
int result = x.Row[_primaryColumn].CompareTo(y.Row[_primaryColumn]);
if (result == 0)
result = x.Row[_secondaryColumn].CompareTo(y.Row[_secondaryColumn]);
+ if (result == 0)
+ result = x.InputIndex.CompareTo(y.InputIndex);
return result;
}
}
diff --git a/src/AsmResolver.DotNet/DefaultMetadataResolver.cs b/src/AsmResolver.DotNet/DefaultMetadataResolver.cs
index fcfc69b8b..0d625ed02 100644
--- a/src/AsmResolver.DotNet/DefaultMetadataResolver.cs
+++ b/src/AsmResolver.DotNet/DefaultMetadataResolver.cs
@@ -81,12 +81,12 @@ public IAssemblyResolver AssemblyResolver
return null;
var resolvedType = LookupInCache(exportedType);
- if (resolvedType != null)
+ if (resolvedType is not null)
return resolvedType;
var resolution = new TypeResolution(AssemblyResolver);
resolvedType = resolution.ResolveExportedType(exportedType);
- if (resolvedType != null)
+ if (resolvedType is not null)
_typeCache[exportedType] = resolvedType;
return resolvedType;
@@ -137,6 +137,10 @@ public IAssemblyResolver AssemblyResolver
if (declaringType is null)
return null;
+ var name = field is MemberReference member
+ ? member.Name
+ : (Utf8String?) field.Name;
+
for (int i = 0; i < declaringType.Fields.Count; i++)
{
var candidate = declaringType.Fields[i];
@@ -171,7 +175,7 @@ public TypeResolution(IAssemblyResolver resolver)
{
case TableIndex.AssemblyRef:
var assemblyDefScope = _assemblyResolver.Resolve((AssemblyReference) scope);
- return assemblyDefScope != null
+ return assemblyDefScope is not null
? FindTypeInAssembly(assemblyDefScope, reference.Namespace, reference.Name)
: null;
@@ -180,7 +184,7 @@ public TypeResolution(IAssemblyResolver resolver)
case TableIndex.TypeRef:
var typeDefScope = ResolveTypeReference((TypeReference) scope);
- return typeDefScope != null
+ return typeDefScope is not null
? FindTypeInType(typeDefScope, reference.Name)
: null;
@@ -200,20 +204,20 @@ public TypeResolution(IAssemblyResolver resolver)
{
case TableIndex.AssemblyRef:
var assembly = _assemblyResolver.Resolve((AssemblyReference) implementation);
- return assembly is {}
+ return assembly is not null
? FindTypeInAssembly(assembly, exportedType.Namespace, exportedType.Name)
: null;
case TableIndex.File when !string.IsNullOrEmpty(implementation.Name):
var module = FindModuleInAssembly(exportedType.Module!.Assembly!, implementation.Name!);
- return module is {}
+ return module is not null
? FindTypeInModule(module, exportedType.Namespace, exportedType.Name)
: null;
case TableIndex.ExportedType:
var exportedDeclaringType = (ExportedType) implementation;
var declaringType = ResolveExportedType(exportedDeclaringType);
- return declaringType is {}
+ return declaringType is not null
? FindTypeInType(declaringType, exportedType.Name)
: null;
@@ -222,39 +226,39 @@ public TypeResolution(IAssemblyResolver resolver)
}
}
- private TypeDefinition? FindTypeInAssembly(AssemblyDefinition assembly, string? ns, string name)
+ private TypeDefinition? FindTypeInAssembly(AssemblyDefinition assembly, Utf8String? ns, Utf8String name)
{
for (int i = 0; i < assembly.Modules.Count; i++)
{
var module = assembly.Modules[i];
var type = FindTypeInModule(module, ns, name);
- if (type != null)
+ if (type is not null)
return type;
}
return null;
}
- private TypeDefinition? FindTypeInModule(ModuleDefinition module, string? ns, string name)
+ private TypeDefinition? FindTypeInModule(ModuleDefinition module, Utf8String? ns, Utf8String name)
{
for (int i = 0; i < module.ExportedTypes.Count; i++)
{
var exportedType = module.ExportedTypes[i];
- if (exportedType.IsTypeOf(ns, name))
+ if (exportedType.IsTypeOfUtf8(ns, name))
return ResolveExportedType(exportedType);
}
for (int i = 0; i < module.TopLevelTypes.Count; i++)
{
var type = module.TopLevelTypes[i];
- if (type.IsTypeOf(ns, name))
+ if (type.IsTypeOfUtf8(ns, name))
return type;
}
return null;
}
- private static TypeDefinition? FindTypeInType(TypeDefinition enclosingType, string name)
+ private static TypeDefinition? FindTypeInType(TypeDefinition enclosingType, Utf8String name)
{
for (int i = 0; i < enclosingType.NestedTypes.Count; i++)
{
@@ -266,7 +270,7 @@ public TypeResolution(IAssemblyResolver resolver)
return null;
}
- private static ModuleDefinition? FindModuleInAssembly(AssemblyDefinition assembly, string name)
+ private static ModuleDefinition? FindModuleInAssembly(AssemblyDefinition assembly, Utf8String name)
{
for (int i = 0; i < assembly.Modules.Count; i++)
{
diff --git a/src/AsmResolver.DotNet/EventDefinition.cs b/src/AsmResolver.DotNet/EventDefinition.cs
index d21d1036b..cc36a78d7 100644
--- a/src/AsmResolver.DotNet/EventDefinition.cs
+++ b/src/AsmResolver.DotNet/EventDefinition.cs
@@ -42,7 +42,7 @@ protected EventDefinition(MetadataToken token)
/// The name of the property.
/// The attributes.
/// The delegate type of the event.
- public EventDefinition(string? name, EventAttributes attributes, ITypeDefOrRef? eventType)
+ public EventDefinition(Utf8String? name, EventAttributes attributes, ITypeDefOrRef? eventType)
: this(new MetadataToken(TableIndex.Event,0))
{
Name = name;
@@ -94,7 +94,7 @@ public Utf8String? Name
string? INameProvider.Name => Name;
///
- public string FullName => FullNameGenerator.GetEventFullName(Name, DeclaringType, EventType);
+ public string FullName => MemberNameGenerator.GetEventFullName(this);
///
/// Gets or sets the delegate type of the event.
diff --git a/src/AsmResolver.DotNet/ExportedType.cs b/src/AsmResolver.DotNet/ExportedType.cs
index 323bc800e..c6253d0ba 100644
--- a/src/AsmResolver.DotNet/ExportedType.cs
+++ b/src/AsmResolver.DotNet/ExportedType.cs
@@ -94,7 +94,7 @@ public Utf8String? Namespace
string? ITypeDescriptor.Namespace => Namespace;
///
- public string FullName => this.GetTypeFullName();
+ public string FullName => MemberNameGenerator.GetTypeFullName(this);
///
public ModuleDefinition? Module
diff --git a/src/AsmResolver.DotNet/FieldDefinition.cs b/src/AsmResolver.DotNet/FieldDefinition.cs
index 39b7e5c3e..0d464fb01 100644
--- a/src/AsmResolver.DotNet/FieldDefinition.cs
+++ b/src/AsmResolver.DotNet/FieldDefinition.cs
@@ -57,7 +57,7 @@ protected FieldDefinition(MetadataToken token)
/// The name of the field.
/// The attributes.
/// The signature of the field.
- public FieldDefinition(string? name, FieldAttributes attributes, FieldSignature? signature)
+ public FieldDefinition(Utf8String? name, FieldAttributes attributes, FieldSignature? signature)
: this(new MetadataToken(TableIndex.Field, 0))
{
Name = name;
@@ -71,7 +71,7 @@ public FieldDefinition(string? name, FieldAttributes attributes, FieldSignature?
/// The name of the field.
/// The attributes.
/// The type of values the field contains.
- public FieldDefinition(string? name, FieldAttributes attributes, TypeSignature? fieldType)
+ public FieldDefinition(Utf8String name, FieldAttributes attributes, TypeSignature? fieldType)
: this(new MetadataToken(TableIndex.Field, 0))
{
Name = name;
@@ -105,7 +105,7 @@ public FieldSignature? Signature
}
///
- public string FullName => FullNameGenerator.GetFieldFullName(Name, DeclaringType, Signature);
+ public string FullName => MemberNameGenerator.GetFieldFullName(this);
///
/// Gets or sets the attributes associated to the field.
diff --git a/src/AsmResolver.DotNet/FileReference.cs b/src/AsmResolver.DotNet/FileReference.cs
index 8f6078e0e..48401e611 100644
--- a/src/AsmResolver.DotNet/FileReference.cs
+++ b/src/AsmResolver.DotNet/FileReference.cs
@@ -35,7 +35,7 @@ protected FileReference(MetadataToken token)
///
/// The name of the file.
/// The attributes associated to the reference.
- public FileReference(string? name, FileAttributes attributes)
+ public FileReference(Utf8String? name, FileAttributes attributes)
: this(new MetadataToken(TableIndex.File, 0))
{
Name = name;
diff --git a/src/AsmResolver.DotNet/FullNameGenerator.cs b/src/AsmResolver.DotNet/FullNameGenerator.cs
deleted file mode 100644
index fe2409c38..000000000
--- a/src/AsmResolver.DotNet/FullNameGenerator.cs
+++ /dev/null
@@ -1,148 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using AsmResolver.DotNet.Signatures;
-using AsmResolver.DotNet.Signatures.Types;
-
-namespace AsmResolver.DotNet
-{
- ///
- /// Provides methods for constructing the full name of a member in a .NET module.
- ///
- public static class FullNameGenerator
- {
- ///
- /// Computes the full name of a field definition, including its declaring type's full name, as well as its
- /// field type.
- ///
- /// The name of the field.
- /// The declaring type of the field, if available.
- /// The signature of the field.
- /// The full name
- public static string GetFieldFullName(string? name, ITypeDescriptor? declaringType, FieldSignature? signature)
- {
- string fieldTypeString = signature?.FieldType.FullName ?? TypeSignature.NullTypeToString;
-
- return declaringType is null
- ? $"{fieldTypeString} {name}"
- : $"{fieldTypeString} {declaringType}::{name}";
- }
-
- ///
- /// Computes the full name of a method definition, including its declaring type's full name, as well as its
- /// return type and parameters.
- ///
- /// The name of the method.
- /// The declaring type of the method if available.
- /// The signature of the method.
- /// The full name
- public static string GetMethodFullName(string? name, ITypeDescriptor? declaringType, MethodSignature? signature)
- {
- if (signature?.GenericParameterCount > 0)
- {
- return GetMethodFullName(name, declaringType, signature,
- Enumerable.Repeat("?", signature.GenericParameterCount));
- }
-
- string returnTypeString = signature?.ReturnType.FullName ?? TypeSignature.NullTypeToString;
- string parameterTypesString = GetParameterTypesString(signature);
-
- return declaringType is null
- ? $"{returnTypeString} {name}({parameterTypesString})"
- : $"{returnTypeString} {declaringType}::{name}({parameterTypesString})";
- }
-
- ///
- /// Computes the full name of a method specification, including its declaring type's full name, as well as its
- /// return type, parameters and any type arguments.
- ///
- /// The name of the method.
- /// The declaring type of the method if available.
- /// The signature of the method.
- /// The type arguments.
- /// The full name
- public static string GetMethodFullName(
- string? name,
- ITypeDescriptor? declaringType,
- MethodSignature? signature,
- IEnumerable typeArguments)
- {
- string returnTypeString = signature?.ReturnType.FullName ?? TypeSignature.NullTypeToString;
- string parameterTypesString = GetParameterTypesString(signature);
-
- string[] argumentNames = typeArguments.ToArray();
- string typeArgumentsString = argumentNames.Length>0
- ? $"<{string.Join(", ", argumentNames)}>"
- : string.Empty;
-
- return declaringType is null
- ? $"{returnTypeString} {name}{typeArgumentsString}({parameterTypesString})"
- : $"{returnTypeString} {declaringType}::{name}{typeArgumentsString}({parameterTypesString})";
- }
-
- ///
- /// Computes the full name of a property definition, including its declaring type's full name, as well as its
- /// return type and parameters.
- ///
- /// The name of the property.
- /// The declaring type of the property if available.
- /// The signature of the property.
- /// The full name
- public static string GetPropertyFullName(string? name, ITypeDescriptor? declaringType, PropertySignature? signature)
- {
- string propertyTypeString = signature?.ReturnType.FullName ?? TypeSignature.NullTypeToString;
- string parameterTypesString = signature?.ParameterTypes.Count > 0
- ? $"[{GetParameterTypesString(signature)}]"
- : string.Empty;
-
- return declaringType is null
- ? $"{propertyTypeString} {name}{parameterTypesString}"
- : $"{propertyTypeString} {declaringType}::{name}{parameterTypesString}";
- }
-
- ///
- /// Computes the full name of a event definition, including its declaring type's full name, as well as its
- /// event type.
- ///
- /// The name of the field.
- /// The declaring type of the field, if available.
- /// The type of the event.
- /// The full name
- public static string GetEventFullName(string? name, ITypeDescriptor? declaringType, ITypeDefOrRef? eventType)
- {
- return declaringType is null
- ? $"{eventType} {name}"
- : $"{eventType} {declaringType}::{name}";
- }
-
- private static string GetParameterTypesString(MethodSignatureBase? signature)
- {
- if (signature is null)
- return string.Empty;
-
- string parametersString = string.Join(", ", signature.ParameterTypes);
- string sentinelSuffix = signature.IsSentinel
- ? ", ..."
- : string.Empty;
-
- return $"{parametersString}{sentinelSuffix}";
- }
-
- ///
- /// Computes the full name of a type descriptor, including its namespace and/or declaring types.
- ///
- /// The type to obtain the full name for.
- /// The full name.
- public static string GetTypeFullName(this ITypeDescriptor type)
- {
- string name = type.Name ?? MetadataMember.NullName;
-
- if (type.DeclaringType is not null)
- return $"{type.DeclaringType.FullName}+{name}";
-
- return !string.IsNullOrEmpty(type.Namespace)
- ? $"{type.Namespace}.{name}"
- : name;
- }
-
- }
-}
diff --git a/src/AsmResolver.DotNet/GenericParameter.cs b/src/AsmResolver.DotNet/GenericParameter.cs
index cb4d1390a..a4021ca53 100644
--- a/src/AsmResolver.DotNet/GenericParameter.cs
+++ b/src/AsmResolver.DotNet/GenericParameter.cs
@@ -36,7 +36,7 @@ protected GenericParameter(MetadataToken token)
/// Creates a new generic parameter.
///
/// The name of the parameter.
- public GenericParameter(string? name)
+ public GenericParameter(Utf8String? name)
: this(new MetadataToken(TableIndex.GenericParam, 0))
{
Name = name;
@@ -47,7 +47,7 @@ public GenericParameter(string? name)
///
/// The name of the parameter.
/// Additional attributes to assign to the parameter.
- public GenericParameter(string? name, GenericParameterAttributes attributes)
+ public GenericParameter(Utf8String? name, GenericParameterAttributes attributes)
: this(new MetadataToken(TableIndex.GenericParam, 0))
{
Name = name;
diff --git a/src/AsmResolver.DotNet/IFieldDescriptor.cs b/src/AsmResolver.DotNet/IFieldDescriptor.cs
index 18143ac19..233b45d02 100644
--- a/src/AsmResolver.DotNet/IFieldDescriptor.cs
+++ b/src/AsmResolver.DotNet/IFieldDescriptor.cs
@@ -7,6 +7,14 @@ namespace AsmResolver.DotNet
///
public interface IFieldDescriptor : IMemberDescriptor, IMetadataMember
{
+ ///
+ /// Gets the name of the field.
+ ///
+ new Utf8String? Name
+ {
+ get;
+ }
+
///
/// Gets the signature of the field.
///
diff --git a/src/AsmResolver.DotNet/IMethodDescriptor.cs b/src/AsmResolver.DotNet/IMethodDescriptor.cs
index 4f695c8f9..80b4485d0 100644
--- a/src/AsmResolver.DotNet/IMethodDescriptor.cs
+++ b/src/AsmResolver.DotNet/IMethodDescriptor.cs
@@ -7,6 +7,14 @@ namespace AsmResolver.DotNet
///
public interface IMethodDescriptor : IMemberDescriptor, IMetadataMember
{
+ ///
+ /// Gets the name of the method.
+ ///
+ new Utf8String? Name
+ {
+ get;
+ }
+
///
/// Gets the signature of the method.
///
diff --git a/src/AsmResolver.DotNet/ImplementationMap.cs b/src/AsmResolver.DotNet/ImplementationMap.cs
index 2c9a9877f..b846d8f42 100644
--- a/src/AsmResolver.DotNet/ImplementationMap.cs
+++ b/src/AsmResolver.DotNet/ImplementationMap.cs
@@ -31,7 +31,7 @@ protected ImplementationMap(MetadataToken token)
/// The scope that declares the imported member.
/// The name of the imported member.
/// The attributes associated to the implementation mapping.
- public ImplementationMap(ModuleReference? scope, string? name, ImplementationMapAttributes attributes)
+ public ImplementationMap(ModuleReference? scope, Utf8String? name, ImplementationMapAttributes attributes)
: this(new MetadataToken(TableIndex.ImplMap, 0))
{
Scope = scope;
diff --git a/src/AsmResolver.DotNet/ManifestResource.cs b/src/AsmResolver.DotNet/ManifestResource.cs
index a0b07fbde..4034e9142 100644
--- a/src/AsmResolver.DotNet/ManifestResource.cs
+++ b/src/AsmResolver.DotNet/ManifestResource.cs
@@ -42,7 +42,7 @@ protected ManifestResource(MetadataToken token)
/// The attributes of the resource.
/// The location of the resource data.
/// The offset within the file referenced by where the data starts.
- public ManifestResource(string? name, ManifestResourceAttributes attributes, IImplementation? implementation, uint offset)
+ public ManifestResource(Utf8String? name, ManifestResourceAttributes attributes, IImplementation? implementation, uint offset)
: this(new MetadataToken(TableIndex.ManifestResource, 0))
{
Name = name;
@@ -57,7 +57,7 @@ public ManifestResource(string? name, ManifestResourceAttributes attributes, IIm
/// The name of the repository.
/// The attributes of the resource.
/// The embedded resource data.
- public ManifestResource(string? name, ManifestResourceAttributes attributes, ISegment? data)
+ public ManifestResource(Utf8String? name, ManifestResourceAttributes attributes, ISegment? data)
: this(new MetadataToken(TableIndex.ManifestResource, 0))
{
Name = name;
diff --git a/src/AsmResolver.DotNet/MemberNameGenerator.cs b/src/AsmResolver.DotNet/MemberNameGenerator.cs
new file mode 100644
index 000000000..79170b52a
--- /dev/null
+++ b/src/AsmResolver.DotNet/MemberNameGenerator.cs
@@ -0,0 +1,456 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using AsmResolver.DotNet.Signatures;
+using AsmResolver.DotNet.Signatures.Types;
+
+namespace AsmResolver.DotNet
+{
+ ///
+ /// Provides methods for constructing the full name of a member in a .NET module.
+ ///
+ public sealed class MemberNameGenerator : ITypeSignatureVisitor
+ {
+ [ThreadStatic]
+ private static StringBuilder? _builder;
+
+ private MemberNameGenerator()
+ {
+ }
+
+ ///
+ /// Gets the singleton instance for the member name generator.
+ ///
+ private static MemberNameGenerator Instance
+ {
+ get;
+ } = new();
+
+ private static StringBuilder GetBuilder()
+ {
+ _builder ??= new StringBuilder();
+ _builder.Clear();
+ return _builder;
+ }
+
+ ///
+ /// Computes the full name of a type descriptor, including its namespace and/or declaring types.
+ ///
+ /// The type to obtain the full name for.
+ /// The full name.
+ public static string GetTypeFullName(ITypeDescriptor type)
+ {
+ var state = GetBuilder();
+ return AppendTypeFullName(state, type).ToString();
+ }
+
+ ///
+ /// Computes the full name of a field definition, including its declaring type's full name, as well as its
+ /// field type.
+ ///
+ /// The field
+ /// The full name
+ public static string GetFieldFullName(IFieldDescriptor descriptor)
+ {
+ var state = GetBuilder();
+
+ AppendTypeFullName(state, descriptor.Signature?.FieldType);
+ state.Append(' ');
+ AppendMemberDeclaringType(state, descriptor.DeclaringType);
+
+ return state.Append(descriptor.Name ?? MetadataMember.NullName).ToString();
+ }
+
+ ///
+ /// Computes the full name of a method reference, including its declaring type's full name, as well as its
+ /// return type and parameters.
+ ///
+ /// The reference
+ /// The full name
+ public static string GetMethodFullName(MemberReference reference)
+ {
+ var state = GetBuilder();
+
+ var signature = reference.Signature as MethodSignature;
+
+ AppendTypeFullName(state, signature?.ReturnType);
+ state.Append(' ');
+ AppendMemberDeclaringType(state, reference.DeclaringType);
+ state.Append(reference.Name ?? MetadataMember.NullName);
+
+ AppendTypeArgumentPlaceholders(state, signature);
+
+ state.Append('(');
+ AppendSignatureParameterTypes(state, signature);
+ state.Append(')');
+
+ return state.ToString();
+ }
+
+ ///
+ /// Computes the full name of a method definition, including its declaring type's full name, as well as its
+ /// return type, parameters and any type arguments.
+ ///
+ /// The definition
+ /// The full name
+ public static string GetMethodFullName(MethodDefinition definition)
+ {
+ var state = GetBuilder();
+
+ var signature = definition.Signature;
+
+ AppendTypeFullName(state, signature?.ReturnType);
+ state.Append(' ');
+ AppendMemberDeclaringType(state, definition.DeclaringType);
+ state.Append(definition.Name ?? MetadataMember.NullName);
+
+ AppendTypeParameters(state, definition.GenericParameters);
+
+ state.Append('(');
+ AppendSignatureParameterTypes(state, signature);
+ state.Append(')');
+
+ return state.ToString();
+ }
+
+ ///
+ /// Computes the full name of a method specification, including its declaring type's full name, as well as its
+ /// return type, parameters and any type arguments.
+ ///
+ /// The specification
+ /// The full name
+ public static string GetMethodFullName(MethodSpecification specification)
+ {
+ var state = GetBuilder();
+
+ var signature = specification.Method?.Signature;
+
+ AppendTypeFullName(state, signature?.ReturnType);
+ state.Append(' ');
+ AppendMemberDeclaringType(state, specification.DeclaringType);
+ state.Append(specification.Name);
+
+ AppendTypeParameters(state, specification.Signature?.TypeArguments ?? Array.Empty());
+
+ state.Append('(');
+ AppendSignatureParameterTypes(state, signature);
+ state.Append(')');
+
+ return state.ToString();
+ }
+
+ ///
+ /// Computes the full name of a property definition, including its declaring type's full name, as well as its
+ /// return type and parameters.
+ ///
+ /// The property
+ /// The full name
+ public static string GetPropertyFullName(PropertyDefinition definition)
+ {
+ var state = GetBuilder();
+
+ var signature = definition.Signature;
+
+ AppendTypeFullName(state, signature?.ReturnType);
+ state.Append(' ');
+ AppendMemberDeclaringType(state, definition.DeclaringType);
+ state.Append(definition.Name ?? MetadataMember.NullName);
+
+ if (signature?.ParameterTypes.Count > 0)
+ {
+ state.Append('[');
+ AppendSignatureParameterTypes(state, signature);
+ state.Append(']');
+ }
+
+ return state.ToString();
+ }
+
+ ///
+ /// Computes the full name of a event definition, including its declaring type's full name, as well as its
+ /// event type.
+ ///
+ /// The event
+ /// The full name
+ public static string GetEventFullName(EventDefinition definition)
+ {
+ var state = GetBuilder();
+
+ AppendTypeFullName(state, definition.EventType);
+ state.Append(' ');
+ AppendMemberDeclaringType(state, definition.DeclaringType);
+ state.Append(definition.Name);
+
+ return state.ToString();
+ }
+
+ private static StringBuilder AppendMemberDeclaringType(StringBuilder state, ITypeDescriptor? declaringType)
+ {
+ if (declaringType is not null)
+ {
+ AppendTypeFullName(state, declaringType);
+ state.Append("::");
+ }
+
+ return state;
+ }
+
+ private static StringBuilder AppendSignatureParameterTypes(StringBuilder state, MethodSignatureBase? signature)
+ {
+ if (signature is null)
+ return state;
+
+ for (int i = 0; i < signature.ParameterTypes.Count; i++)
+ {
+ signature.ParameterTypes[i].AcceptVisitor(Instance, state);
+ if (i < signature.ParameterTypes.Count - 1)
+ state.Append(", ");
+ }
+
+ if (signature.IsSentinel)
+ state.Append("...");
+
+ return state;
+ }
+
+ private static StringBuilder AppendTypeParameters(StringBuilder state, IList typeArguments)
+ {
+ if (typeArguments.Count > 0)
+ {
+ state.Append('<');
+ AppendCommaSeparatedCollection(state, typeArguments, static (s, t) => s.Append(t.Name));
+ state.Append('>');
+ }
+
+ return state;
+ }
+
+ private static StringBuilder AppendTypeParameters(StringBuilder state, IList typeArguments)
+ {
+ if (typeArguments.Count > 0)
+ {
+ state.Append('<');
+ AppendCommaSeparatedCollection(state, typeArguments, static (s, t) => t.AcceptVisitor(Instance, s));
+ state.Append('>');
+ }
+
+ return state;
+ }
+
+ private static StringBuilder AppendTypeFullName(StringBuilder state, ITypeDescriptor? type)
+ {
+ switch (type)
+ {
+ case TypeSignature signature:
+ return signature.AcceptVisitor(Instance, state);
+
+ case ITypeDefOrRef reference:
+ return AppendTypeFullName(state, reference);
+
+ case null:
+ return state.Append(TypeSignature.NullTypeToString);
+
+ default:
+ throw new ArgumentOutOfRangeException(nameof(type));
+ }
+ }
+
+ private static StringBuilder AppendTypeFullName(StringBuilder state, ITypeDefOrRef? type)
+ {
+ if (type is null)
+ return state.Append(TypeSignature.NullTypeToString);
+
+ if (type is TypeSpecification specification)
+ return AppendTypeFullName(state, specification.Signature);
+
+ if (type.DeclaringType is { } declaringType)
+ {
+ AppendTypeFullName(state, declaringType);
+ state.Append('+');
+ }
+ else if (!string.IsNullOrEmpty(type.Namespace))
+ {
+ state.Append(type.Namespace);
+ state.Append('.');
+ }
+
+ return state.Append(type.Name ?? MetadataMember.NullName);
+ }
+
+ private static StringBuilder AppendTypeArgumentPlaceholders(StringBuilder state, MethodSignature? signature)
+ {
+ if (signature?.GenericParameterCount > 0)
+ {
+ state.Append('<');
+
+ for (int i = 0; i < signature.GenericParameterCount; i++)
+ {
+ state.Append('?');
+ if (i < signature.GenericParameterCount - 1)
+ state.Append(", ");
+ }
+
+ state.Append('>');
+ }
+
+ return state;
+ }
+
+ private static StringBuilder AppendMethodSignature(StringBuilder state, MethodSignature signature)
+ {
+ if (signature.HasThis)
+ state.Append("instance ");
+
+ signature.ReturnType.AcceptVisitor(Instance, state);
+
+ state.Append(" *");
+
+ AppendTypeArgumentPlaceholders(state, signature);
+
+ state.Append('(');
+ AppendSignatureParameterTypes(state, signature);
+ return state.Append(')');
+ }
+
+ private static StringBuilder AppendCommaSeparatedCollection(
+ StringBuilder state,
+ IList collection,
+ Action action)
+ {
+ for (int i = 0; i < collection.Count; i++)
+ {
+ action(state, collection[i]);
+ if (i < collection.Count - 1)
+ state.Append(", ");
+ }
+
+ return state;
+ }
+
+ ///
+ StringBuilder ITypeSignatureVisitor.VisitArrayType(ArrayTypeSignature signature, StringBuilder state)
+ {
+ signature.BaseType.AcceptVisitor(this, state);
+
+ state.Append('[');
+
+ AppendCommaSeparatedCollection(state, signature.Dimensions, static (s, d) =>
+ {
+ if (d.LowerBound.HasValue)
+ {
+ if (d.Size.HasValue)
+ {
+ AppendDimensionBound(s, d.LowerBound.Value, d.Size.Value);
+ }
+ else
+ {
+ s.Append(d.LowerBound.Value)
+ .Append("...");
+ }
+ }
+
+ if (d.Size.HasValue)
+ AppendDimensionBound(s, 0, d.Size.Value);
+
+ static void AppendDimensionBound(StringBuilder state, int low, int size)
+ {
+ state.Append(low)
+ .Append("...")
+ .Append(low + size - 1);
+ }
+ });
+
+ return state.Append(']');
+ }
+
+ ///
+ StringBuilder ITypeSignatureVisitor.VisitBoxedType(BoxedTypeSignature signature, StringBuilder state)
+ {
+ return signature.BaseType.AcceptVisitor(this, state);
+ }
+
+ ///
+ StringBuilder ITypeSignatureVisitor.VisitByReferenceType(ByReferenceTypeSignature signature, StringBuilder state)
+ {
+ return signature.BaseType
+ .AcceptVisitor(this, state)
+ .Append('&');
+ }
+
+ ///
+ StringBuilder ITypeSignatureVisitor.VisitCorLibType(CorLibTypeSignature signature, StringBuilder state)
+ {
+ return state.Append("System.").Append(signature.Name);
+ }
+
+ ///
+ StringBuilder ITypeSignatureVisitor.VisitCustomModifierType(CustomModifierTypeSignature signature, StringBuilder state)
+ {
+ signature.BaseType.AcceptVisitor(this, state);
+ state.Append(signature.IsRequired ? " modreq(" : " modopt(");
+ AppendTypeFullName(state, signature.ModifierType);
+ return state.Append(')');
+ }
+
+ ///
+ StringBuilder ITypeSignatureVisitor.VisitGenericInstanceType(GenericInstanceTypeSignature signature, StringBuilder state)
+ {
+ AppendTypeFullName(state, signature.GenericType);
+ return AppendTypeParameters(state, signature.TypeArguments);
+ }
+
+ ///
+ StringBuilder ITypeSignatureVisitor.VisitGenericParameter(GenericParameterSignature signature, StringBuilder state)
+ {
+ state.Append(signature.ParameterType switch
+ {
+ GenericParameterType.Type => "!",
+ GenericParameterType.Method => "!!",
+ _ => throw new ArgumentOutOfRangeException()
+ });
+
+ return state.Append(signature.Index);
+ }
+
+ ///
+ StringBuilder ITypeSignatureVisitor.VisitPinnedType(PinnedTypeSignature signature, StringBuilder state)
+ {
+ return signature.BaseType.AcceptVisitor(this, state);
+ }
+
+ ///
+ StringBuilder ITypeSignatureVisitor.VisitPointerType(PointerTypeSignature signature, StringBuilder state)
+ {
+ return signature.BaseType
+ .AcceptVisitor(this, state)
+ .Append('*');
+ }
+
+ ///
+ StringBuilder ITypeSignatureVisitor.VisitSentinelType(SentinelTypeSignature signature, StringBuilder state)
+ {
+ return state.Append("<<>>");
+ }
+
+ ///
+ StringBuilder ITypeSignatureVisitor.VisitSzArrayType(SzArrayTypeSignature signature, StringBuilder state)
+ {
+ return signature.BaseType
+ .AcceptVisitor(this, state)
+ .Append("[]");
+ }
+
+ ///
+ StringBuilder ITypeSignatureVisitor.VisitTypeDefOrRef(TypeDefOrRefSignature signature, StringBuilder state)
+ {
+ return AppendTypeFullName(state, signature.Type);
+ }
+
+ ///
+ StringBuilder ITypeSignatureVisitor.VisitFunctionPointerType(FunctionPointerTypeSignature signature, StringBuilder state)
+ {
+ state.Append("method ");
+ return AppendMethodSignature(state, signature.Signature);
+ }
+ }
+}
diff --git a/src/AsmResolver.DotNet/MemberReference.cs b/src/AsmResolver.DotNet/MemberReference.cs
index 69a274884..276ebb1a7 100644
--- a/src/AsmResolver.DotNet/MemberReference.cs
+++ b/src/AsmResolver.DotNet/MemberReference.cs
@@ -37,7 +37,7 @@ protected MemberReference(MetadataToken token)
/// The name of the referenced member.
/// The signature of the referenced member. This dictates whether the
/// referenced member is a field or a method.
- public MemberReference(IMemberRefParent? parent, string? name, MemberSignature? signature)
+ public MemberReference(IMemberRefParent? parent, Utf8String? name, MemberSignature? signature)
: this(new MetadataToken(TableIndex.MemberRef, 0))
{
Parent = parent;
@@ -103,9 +103,10 @@ public string FullName
get
{
if (IsField)
- return FullNameGenerator.GetFieldFullName(Name, DeclaringType, (FieldSignature) Signature);
+ return MemberNameGenerator.GetFieldFullName(this);
if (IsMethod)
- return FullNameGenerator.GetMethodFullName(Name, DeclaringType, (MethodSignature) Signature);
+ return MemberNameGenerator.GetMethodFullName(this);
+
return Name ?? NullName;
}
}
diff --git a/src/AsmResolver.DotNet/MethodDefinition.cs b/src/AsmResolver.DotNet/MethodDefinition.cs
index a65658523..2e40249fc 100644
--- a/src/AsmResolver.DotNet/MethodDefinition.cs
+++ b/src/AsmResolver.DotNet/MethodDefinition.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
-using System.Linq;
using System.Threading;
using AsmResolver.Collections;
using AsmResolver.DotNet.Code;
@@ -68,7 +67,7 @@ protected MethodDefinition(MetadataToken token)
/// is set, the bit should be unset in
/// and vice versa.
///
- public MethodDefinition(string? name, MethodAttributes attributes, MethodSignature? signature)
+ public MethodDefinition(Utf8String? name, MethodAttributes attributes, MethodSignature? signature)
: this(new MetadataToken(TableIndex.Method, 0))
{
Name = name;
@@ -101,13 +100,7 @@ public MethodSignature? Signature
}
///
- public string FullName => FullNameGenerator.GetMethodFullName(
- Name,
- DeclaringType,
- Signature,
- GenericParameters.Count > 0
- ? GenericParameters.Select(x => x.Name?.Value ?? NullName)
- : Enumerable.Empty());
+ public string FullName => MemberNameGenerator.GetMethodFullName(this);
///
/// Gets or sets the attributes associated to the method.
diff --git a/src/AsmResolver.DotNet/MethodSpecification.cs b/src/AsmResolver.DotNet/MethodSpecification.cs
index 31ca1226e..e9b9a3210 100644
--- a/src/AsmResolver.DotNet/MethodSpecification.cs
+++ b/src/AsmResolver.DotNet/MethodSpecification.cs
@@ -1,9 +1,7 @@
using System.Collections.Generic;
-using System.Linq;
using System.Threading;
using AsmResolver.Collections;
using AsmResolver.DotNet.Signatures;
-using AsmResolver.DotNet.Signatures.Types;
using AsmResolver.PE.DotNet.Metadata.Tables;
namespace AsmResolver.DotNet
@@ -69,11 +67,7 @@ public GenericInstanceMethodSignature? Signature
string? INameProvider.Name => Name;
///
- public string FullName => FullNameGenerator.GetMethodFullName(
- Name,
- DeclaringType,
- Method?.Signature,
- Signature?.TypeArguments.Select(x => x.FullName) ?? Enumerable.Empty());
+ public string FullName => MemberNameGenerator.GetMethodFullName(this);
///
public ModuleDefinition? Module => Method?.Module;
diff --git a/src/AsmResolver.DotNet/ModuleDefinition.cs b/src/AsmResolver.DotNet/ModuleDefinition.cs
index c463b7e2a..13a5c9669 100644
--- a/src/AsmResolver.DotNet/ModuleDefinition.cs
+++ b/src/AsmResolver.DotNet/ModuleDefinition.cs
@@ -283,7 +283,19 @@ protected ModuleDefinition(MetadataToken token)
/// Defines a new .NET module that references mscorlib version 4.0.0.0.
///
/// The name of the module.
+ ///
+ /// This constructor co-exists with the Utf8String overload for backwards compatibility.
+ ///
public ModuleDefinition(string? name)
+ : this((Utf8String?) name)
+ {
+ }
+
+ ///
+ /// Defines a new .NET module that references mscorlib version 4.0.0.0.
+ ///
+ /// The name of the module.
+ public ModuleDefinition(Utf8String? name)
: this(new MetadataToken(TableIndex.Module, 0))
{
Name = name;
diff --git a/src/AsmResolver.DotNet/ModuleReference.cs b/src/AsmResolver.DotNet/ModuleReference.cs
index 1c4cef6d4..87f8a52e2 100644
--- a/src/AsmResolver.DotNet/ModuleReference.cs
+++ b/src/AsmResolver.DotNet/ModuleReference.cs
@@ -32,7 +32,7 @@ protected ModuleReference(MetadataToken token)
/// Creates a new reference to an external module.
///
/// The file name of the module.
- public ModuleReference(string? name)
+ public ModuleReference(Utf8String? name)
: this(new MetadataToken(TableIndex.ModuleRef, 0))
{
Name = name;
diff --git a/src/AsmResolver.DotNet/ParameterDefinition.cs b/src/AsmResolver.DotNet/ParameterDefinition.cs
index 33331e50a..81e815ea9 100644
--- a/src/AsmResolver.DotNet/ParameterDefinition.cs
+++ b/src/AsmResolver.DotNet/ParameterDefinition.cs
@@ -45,7 +45,7 @@ protected ParameterDefinition(MetadataToken token)
/// Creates a new parameter definition using the provided name.
///
/// The name of the new parameter.
- public ParameterDefinition(string? name)
+ public ParameterDefinition(Utf8String? name)
: this(new MetadataToken(TableIndex.Param, 0))
{
Name = name;
@@ -57,7 +57,7 @@ public ParameterDefinition(string? name)
/// The sequence number of the new parameter.
/// The name of the new parameter.
/// The attributes to assign to the parameter.
- public ParameterDefinition(ushort sequence, string? name, ParameterAttributes attributes)
+ public ParameterDefinition(ushort sequence, Utf8String? name, ParameterAttributes attributes)
: this(new MetadataToken(TableIndex.Param, 0))
{
Sequence = sequence;
diff --git a/src/AsmResolver.DotNet/PropertyDefinition.cs b/src/AsmResolver.DotNet/PropertyDefinition.cs
index 325bacd11..ac35369ab 100644
--- a/src/AsmResolver.DotNet/PropertyDefinition.cs
+++ b/src/AsmResolver.DotNet/PropertyDefinition.cs
@@ -46,7 +46,7 @@ protected PropertyDefinition(MetadataToken token)
/// The name of the property.
/// The attributes.
/// The signature of the property.
- public PropertyDefinition(string? name, PropertyAttributes attributes, PropertySignature? signature)
+ public PropertyDefinition(Utf8String? name, PropertyAttributes attributes, PropertySignature? signature)
: this(new MetadataToken(TableIndex.Property,0))
{
Name = name;
@@ -109,7 +109,7 @@ public Utf8String? Name
string? INameProvider.Name => Name;
///
- public string FullName => FullNameGenerator.GetPropertyFullName(Name, DeclaringType, Signature);
+ public string FullName => MemberNameGenerator.GetPropertyFullName(this);
///
/// Gets or sets the signature of the property. This includes the property type, as well as any parameters the
diff --git a/src/AsmResolver.DotNet/Serialized/SerializedCustomAttribute.cs b/src/AsmResolver.DotNet/Serialized/SerializedCustomAttribute.cs
index 9809a0516..6b334c1b4 100644
--- a/src/AsmResolver.DotNet/Serialized/SerializedCustomAttribute.cs
+++ b/src/AsmResolver.DotNet/Serialized/SerializedCustomAttribute.cs
@@ -64,7 +64,7 @@ public SerializedCustomAttribute(ModuleReaderContext context, MetadataToken toke
$"Invalid signature blob index in custom attribute {MetadataToken}.");
}
- return CustomAttributeSignature.FromReader(new BlobReadContext(_context), Constructor, reader);
+ return CustomAttributeSignature.FromReader(new BlobReaderContext(_context), Constructor, reader);
}
}
}
diff --git a/src/AsmResolver.DotNet/Serialized/SerializedFieldDefinition.cs b/src/AsmResolver.DotNet/Serialized/SerializedFieldDefinition.cs
index 083dd51e9..768f687fd 100644
--- a/src/AsmResolver.DotNet/Serialized/SerializedFieldDefinition.cs
+++ b/src/AsmResolver.DotNet/Serialized/SerializedFieldDefinition.cs
@@ -47,7 +47,8 @@ public SerializedFieldDefinition(ModuleReaderContext context, MetadataToken toke
$"Invalid signature blob index in field {MetadataToken.ToString()}.");
}
- return FieldSignature.FromReader(new BlobReadContext(_context), ref reader);
+ var context = new BlobReaderContext(_context);
+ return FieldSignature.FromReader(ref context, ref reader);
}
///
diff --git a/src/AsmResolver.DotNet/Serialized/SerializedMemberReference.cs b/src/AsmResolver.DotNet/Serialized/SerializedMemberReference.cs
index 1a867ef11..e1250020c 100644
--- a/src/AsmResolver.DotNet/Serialized/SerializedMemberReference.cs
+++ b/src/AsmResolver.DotNet/Serialized/SerializedMemberReference.cs
@@ -60,7 +60,8 @@ public SerializedMemberReference(
$"Invalid signature blob index in member reference {MetadataToken.ToString()}.");
}
- return CallingConventionSignature.FromReader(new BlobReadContext(_context), ref reader, true);
+ var context = new BlobReaderContext(_context);
+ return CallingConventionSignature.FromReader(ref context, ref reader, true);
}
///
diff --git a/src/AsmResolver.DotNet/Serialized/SerializedMethodDefinition.cs b/src/AsmResolver.DotNet/Serialized/SerializedMethodDefinition.cs
index 0d09b8e0a..42675f8ab 100644
--- a/src/AsmResolver.DotNet/Serialized/SerializedMethodDefinition.cs
+++ b/src/AsmResolver.DotNet/Serialized/SerializedMethodDefinition.cs
@@ -52,7 +52,8 @@ public SerializedMethodDefinition(ModuleReaderContext context, MetadataToken tok
$"Invalid signature blob index in method {MetadataToken.ToString()}.");
}
- return MethodSignature.FromReader(new BlobReadContext(_context), ref reader);
+ var context = new BlobReaderContext(_context);
+ return MethodSignature.FromReader(ref context, ref reader);
}
///
diff --git a/src/AsmResolver.DotNet/Serialized/SerializedMethodSpecification.cs b/src/AsmResolver.DotNet/Serialized/SerializedMethodSpecification.cs
index 929366651..7878db964 100644
--- a/src/AsmResolver.DotNet/Serialized/SerializedMethodSpecification.cs
+++ b/src/AsmResolver.DotNet/Serialized/SerializedMethodSpecification.cs
@@ -52,7 +52,8 @@ public SerializedMethodSpecification(ModuleReaderContext context, MetadataToken
$"Invalid instantiation blob index in method specification {MetadataToken.ToString()}.");
}
- return GenericInstanceMethodSignature.FromReader(new BlobReadContext(_context), ref reader);
+ var context = new BlobReaderContext(_context);
+ return GenericInstanceMethodSignature.FromReader(ref context, ref reader);
}
///
diff --git a/src/AsmResolver.DotNet/Serialized/SerializedPropertyDefinition.cs b/src/AsmResolver.DotNet/Serialized/SerializedPropertyDefinition.cs
index d2dd3ae74..1d235e66a 100644
--- a/src/AsmResolver.DotNet/Serialized/SerializedPropertyDefinition.cs
+++ b/src/AsmResolver.DotNet/Serialized/SerializedPropertyDefinition.cs
@@ -48,7 +48,8 @@ public SerializedPropertyDefinition(ModuleReaderContext context, MetadataToken t
$"Invalid signature blob index in property {MetadataToken.ToString()}.");
}
- return PropertySignature.FromReader(new BlobReadContext(_context), ref reader);
+ var context = new BlobReaderContext(_context);
+ return PropertySignature.FromReader(ref context, ref reader);
}
///
diff --git a/src/AsmResolver.DotNet/Serialized/SerializedSecurityDeclaration.cs b/src/AsmResolver.DotNet/Serialized/SerializedSecurityDeclaration.cs
index c39273a75..a6dd50fd9 100644
--- a/src/AsmResolver.DotNet/Serialized/SerializedSecurityDeclaration.cs
+++ b/src/AsmResolver.DotNet/Serialized/SerializedSecurityDeclaration.cs
@@ -56,7 +56,7 @@ public SerializedSecurityDeclaration(
$"Invalid permission set blob index in security declaration {MetadataToken.ToString()}.");
}
- return PermissionSetSignature.FromReader(new BlobReadContext(_context), ref reader);
+ return PermissionSetSignature.FromReader(new BlobReaderContext(_context), ref reader);
}
}
}
diff --git a/src/AsmResolver.DotNet/Serialized/SerializedStandAloneSignature.cs b/src/AsmResolver.DotNet/Serialized/SerializedStandAloneSignature.cs
index 49ab50915..65e82da76 100644
--- a/src/AsmResolver.DotNet/Serialized/SerializedStandAloneSignature.cs
+++ b/src/AsmResolver.DotNet/Serialized/SerializedStandAloneSignature.cs
@@ -43,7 +43,8 @@ public SerializedStandAloneSignature(
$"Invalid signature blob index in stand-alone signature {MetadataToken.ToString()}.");
}
- return CallingConventionSignature.FromReader(new BlobReadContext(_context), ref reader);
+ var context = new BlobReaderContext(_context);
+ return CallingConventionSignature.FromReader(ref context, ref reader);
}
///
diff --git a/src/AsmResolver.DotNet/Serialized/SerializedTypeSpecification.cs b/src/AsmResolver.DotNet/Serialized/SerializedTypeSpecification.cs
index 47f29d5ac..4f05ed1ba 100644
--- a/src/AsmResolver.DotNet/Serialized/SerializedTypeSpecification.cs
+++ b/src/AsmResolver.DotNet/Serialized/SerializedTypeSpecification.cs
@@ -41,9 +41,9 @@ public SerializedTypeSpecification(ModuleReaderContext context, MetadataToken to
$"Invalid blob signature for type specification {MetadataToken.ToString()}");
}
- var context = new BlobReadContext(_context);
- context.TraversedTokens.Add(MetadataToken);
- return TypeSignature.FromReader(context, ref reader);
+ var context = new BlobReaderContext(_context);
+ context.StepInToken(MetadataToken);
+ return TypeSignature.FromReader(ref context, ref reader);
}
///
diff --git a/src/AsmResolver.DotNet/Signatures/BlobReadContext.cs b/src/AsmResolver.DotNet/Signatures/BlobReadContext.cs
deleted file mode 100644
index 1af93d92d..000000000
--- a/src/AsmResolver.DotNet/Signatures/BlobReadContext.cs
+++ /dev/null
@@ -1,71 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using AsmResolver.DotNet.Serialized;
-using AsmResolver.DotNet.Signatures.Types;
-using AsmResolver.PE.DotNet.Metadata.Tables;
-
-namespace AsmResolver.DotNet.Signatures
-{
- ///
- /// Provides a context in which a metadata blob parser exists in. This includes the original module reader context
- /// as well as a mechanism to protect against infinite recursion.
- ///
- public readonly struct BlobReadContext
- {
- ///
- /// Creates a new instance of the structure.
- ///
- /// The original read context.
- public BlobReadContext(ModuleReaderContext readerContext)
- : this(readerContext, PhysicalTypeSignatureResolver.Instance, Enumerable.Empty())
- {
- }
-
- ///
- /// Creates a new instance of the structure.
- ///
- /// The original read context.
- /// The object responsible for resolving raw type metadata tokens and addresses.
- public BlobReadContext(ModuleReaderContext readerContext, ITypeSignatureResolver resolver)
- : this(readerContext, resolver, Enumerable.Empty())
- {
- }
-
- ///
- /// Creates a new instance of the structure.
- ///
- /// The original read context.
- /// The object responsible for resolving raw type metadata tokens and addresses.
- /// A collection of traversed metadata tokens.
- public BlobReadContext(ModuleReaderContext readerContext, ITypeSignatureResolver resolver, IEnumerable traversedTokens)
- {
- ReaderContext = readerContext;
- TypeSignatureResolver = resolver;
- TraversedTokens = new HashSet(traversedTokens);
- }
-
- ///
- /// Gets the module reader context.
- ///
- public ModuleReaderContext ReaderContext
- {
- get;
- }
-
- ///
- /// Gets the object responsible for resolving raw type metadata tokens and addresses.
- ///
- public ITypeSignatureResolver TypeSignatureResolver
- {
- get;
- }
-
- ///
- /// Gets a collection of metadata tokens that were traversed during the parsing of metadata.
- ///
- public ISet TraversedTokens
- {
- get;
- }
- }
-}
diff --git a/src/AsmResolver.DotNet/Signatures/BlobReaderContext.cs b/src/AsmResolver.DotNet/Signatures/BlobReaderContext.cs
new file mode 100644
index 000000000..b9395871a
--- /dev/null
+++ b/src/AsmResolver.DotNet/Signatures/BlobReaderContext.cs
@@ -0,0 +1,86 @@
+using System;
+using System.Collections.Generic;
+using AsmResolver.DotNet.Serialized;
+using AsmResolver.DotNet.Signatures.Types;
+using AsmResolver.PE.DotNet.Metadata.Tables;
+
+namespace AsmResolver.DotNet.Signatures
+{
+ ///
+ /// Provides a context in which a metadata blob parser exists in. This includes the original module reader context
+ /// as well as a mechanism to protect against infinite recursion.
+ ///
+ public struct BlobReaderContext
+ {
+ private Stack? _traversedTokens;
+
+ ///
+ /// Creates a new instance of the structure.
+ ///
+ /// The original read context.
+ public BlobReaderContext(ModuleReaderContext readerContext)
+ : this(readerContext, PhysicalTypeSignatureResolver.Instance)
+ {
+ }
+
+ ///
+ /// Creates a new instance of the structure.
+ ///
+ /// The original read context.
+ /// The object responsible for resolving raw type metadata tokens and addresses.
+ public BlobReaderContext(ModuleReaderContext readerContext, ITypeSignatureResolver resolver)
+ {
+ ReaderContext = readerContext;
+ TypeSignatureResolver = resolver;
+ _traversedTokens = null;
+ }
+
+ ///
+ /// Gets the module reader context.
+ ///
+ public ModuleReaderContext ReaderContext
+ {
+ get;
+ }
+
+ ///
+ /// Gets the object responsible for resolving raw type metadata tokens and addresses.
+ ///
+ public ITypeSignatureResolver TypeSignatureResolver
+ {
+ get;
+ }
+
+ ///
+ /// Records a step in the blob reading process where a metadata token into the tables stream is about to
+ /// be traversed.
+ ///
+ /// The token to traverse
+ ///
+ /// true if this token was recorded, false if the token was already traversed before.
+ ///
+ public bool StepInToken(MetadataToken token)
+ {
+ if (_traversedTokens is null)
+ _traversedTokens = new Stack();
+ else if (_traversedTokens.Contains(token))
+ return false;
+
+ _traversedTokens.Push(token);
+ return true;
+ }
+
+ ///
+ /// Records a step in the blob reading process where the last recorded metadata token into the tables stream
+ /// was traversed and processed completely.
+ ///
+ /// Occurs when there was no token traversed.
+ public void StepOutToken()
+ {
+ if (_traversedTokens is null)
+ throw new InvalidOperationException();
+
+ _traversedTokens.Pop();
+ }
+ }
+}
diff --git a/src/AsmResolver.DotNet/Signatures/CallingConventionSignature.cs b/src/AsmResolver.DotNet/Signatures/CallingConventionSignature.cs
index 12d04b0e2..e58903d30 100644
--- a/src/AsmResolver.DotNet/Signatures/CallingConventionSignature.cs
+++ b/src/AsmResolver.DotNet/Signatures/CallingConventionSignature.cs
@@ -20,11 +20,11 @@ public abstract class CallingConventionSignature : ExtendableBlobSignature, IImp
/// put into the property.
/// The read signature.
public static CallingConventionSignature? FromReader(
- in BlobReadContext context,
+ ref BlobReaderContext context,
ref BinaryStreamReader reader,
bool readToEnd = true)
{
- var signature = ReadSignature(context, ref reader);
+ var signature = ReadSignature(ref context, ref reader);
if (readToEnd)
{
byte[] extraData = reader.ReadToEnd();
@@ -35,7 +35,7 @@ public abstract class CallingConventionSignature : ExtendableBlobSignature, IImp
return signature;
}
- private static CallingConventionSignature? ReadSignature(in BlobReadContext context, ref BinaryStreamReader reader)
+ private static CallingConventionSignature? ReadSignature(ref BlobReaderContext context, ref BinaryStreamReader reader)
{
byte flag = reader.ReadByte();
reader.Offset--;
@@ -50,19 +50,19 @@ public abstract class CallingConventionSignature : ExtendableBlobSignature, IImp
case CallingConventionAttributes.ThisCall:
case CallingConventionAttributes.VarArg:
case CallingConventionAttributes.Unmanaged:
- return MethodSignature.FromReader(context, ref reader);
+ return MethodSignature.FromReader(ref context, ref reader);
case CallingConventionAttributes.Property:
- return PropertySignature.FromReader(context, ref reader);
+ return PropertySignature.FromReader(ref context, ref reader);
case CallingConventionAttributes.Local:
- return LocalVariablesSignature.FromReader(context, ref reader);
+ return LocalVariablesSignature.FromReader(ref context, ref reader);
case CallingConventionAttributes.GenericInstance:
- return GenericInstanceMethodSignature.FromReader(context, ref reader);
+ return GenericInstanceMethodSignature.FromReader(ref context, ref reader);
case CallingConventionAttributes.Field:
- return FieldSignature.FromReader(context, ref reader);
+ return FieldSignature.FromReader(ref context, ref reader);
}
throw new NotSupportedException($"Invalid or unsupported calling convention signature header {flag:X2}.");
diff --git a/src/AsmResolver.DotNet/Signatures/CustomAttributeArgument.cs b/src/AsmResolver.DotNet/Signatures/CustomAttributeArgument.cs
index 58823dd1b..8683f8925 100644
--- a/src/AsmResolver.DotNet/Signatures/CustomAttributeArgument.cs
+++ b/src/AsmResolver.DotNet/Signatures/CustomAttributeArgument.cs
@@ -19,7 +19,7 @@ public class CustomAttributeArgument
/// The type of the argument to read.
/// The input stream.
/// The argument.
- public static CustomAttributeArgument FromReader(in BlobReadContext context, TypeSignature argumentType,
+ public static CustomAttributeArgument FromReader(in BlobReaderContext context, TypeSignature argumentType,
ref BinaryStreamReader reader)
{
var elementReader = CustomAttributeArgumentReader.Create();
diff --git a/src/AsmResolver.DotNet/Signatures/CustomAttributeArgumentReader.cs b/src/AsmResolver.DotNet/Signatures/CustomAttributeArgumentReader.cs
index 246f8a27f..4ace31c1d 100644
--- a/src/AsmResolver.DotNet/Signatures/CustomAttributeArgumentReader.cs
+++ b/src/AsmResolver.DotNet/Signatures/CustomAttributeArgumentReader.cs
@@ -30,7 +30,7 @@ public bool IsNullArray
private set;
}
- public void ReadValue(in BlobReadContext context, ref BinaryStreamReader reader, TypeSignature valueType)
+ public void ReadValue(in BlobReaderContext context, ref BinaryStreamReader reader, TypeSignature valueType)
{
var module = context.ReaderContext.ParentModule;
diff --git a/src/AsmResolver.DotNet/Signatures/CustomAttributeNamedArgument.cs b/src/AsmResolver.DotNet/Signatures/CustomAttributeNamedArgument.cs
index 770af083e..6d4e08f62 100644
--- a/src/AsmResolver.DotNet/Signatures/CustomAttributeNamedArgument.cs
+++ b/src/AsmResolver.DotNet/Signatures/CustomAttributeNamedArgument.cs
@@ -69,7 +69,7 @@ public CustomAttributeArgument Argument
/// The blob reader context.
/// The input stream.
/// The argument.
- public static CustomAttributeNamedArgument FromReader(in BlobReadContext context, ref BinaryStreamReader reader)
+ public static CustomAttributeNamedArgument FromReader(in BlobReaderContext context, ref BinaryStreamReader reader)
{
var memberType = (CustomAttributeArgumentMemberType) reader.ReadByte();
var argumentType = TypeSignature.ReadFieldOrPropType(context, ref reader);
diff --git a/src/AsmResolver.DotNet/Signatures/CustomAttributeSignature.cs b/src/AsmResolver.DotNet/Signatures/CustomAttributeSignature.cs
index 8e645704a..1a399f616 100644
--- a/src/AsmResolver.DotNet/Signatures/CustomAttributeSignature.cs
+++ b/src/AsmResolver.DotNet/Signatures/CustomAttributeSignature.cs
@@ -86,7 +86,7 @@ public IList NamedArguments
/// The signature.
/// Occurs when the input stream does not point to a valid signature.
public static CustomAttributeSignature FromReader(
- in BlobReadContext context,
+ in BlobReaderContext context,
ICustomAttributeType ctor,
in BinaryStreamReader reader)
{
diff --git a/src/AsmResolver.DotNet/Signatures/FieldSignature.cs b/src/AsmResolver.DotNet/Signatures/FieldSignature.cs
index f1d69e005..971839ab8 100644
--- a/src/AsmResolver.DotNet/Signatures/FieldSignature.cs
+++ b/src/AsmResolver.DotNet/Signatures/FieldSignature.cs
@@ -37,11 +37,11 @@ public static FieldSignature CreateInstance(TypeSignature fieldType)
/// The blob reader context.
/// The blob input stream.
/// The field signature.
- public static FieldSignature FromReader(in BlobReadContext context, ref BinaryStreamReader reader)
+ public static FieldSignature FromReader(ref BlobReaderContext context, ref BinaryStreamReader reader)
{
return new(
(CallingConventionAttributes) reader.ReadByte(),
- TypeSignature.FromReader(context, ref reader));
+ TypeSignature.FromReader(ref context, ref reader));
}
///
diff --git a/src/AsmResolver.DotNet/Signatures/GenericInstanceMethodSignature.cs b/src/AsmResolver.DotNet/Signatures/GenericInstanceMethodSignature.cs
index 33848a34d..9e12333c8 100644
--- a/src/AsmResolver.DotNet/Signatures/GenericInstanceMethodSignature.cs
+++ b/src/AsmResolver.DotNet/Signatures/GenericInstanceMethodSignature.cs
@@ -11,7 +11,7 @@ namespace AsmResolver.DotNet.Signatures
public class GenericInstanceMethodSignature : CallingConventionSignature, IGenericArgumentsProvider
{
internal static GenericInstanceMethodSignature? FromReader(
- in BlobReadContext context,
+ ref BlobReaderContext context,
ref BinaryStreamReader reader)
{
if (!reader.CanRead(sizeof(byte)))
@@ -30,7 +30,7 @@ public class GenericInstanceMethodSignature : CallingConventionSignature, IGener
var result = new GenericInstanceMethodSignature(attributes, (int) count);
for (int i = 0; i < count; i++)
- result.TypeArguments.Add(TypeSignature.FromReader(context, ref reader));
+ result.TypeArguments.Add(TypeSignature.FromReader(ref context, ref reader));
return result;
}
diff --git a/src/AsmResolver.DotNet/Signatures/LocalVariablesSignature.cs b/src/AsmResolver.DotNet/Signatures/LocalVariablesSignature.cs
index 068dfc4a9..5f0e56597 100644
--- a/src/AsmResolver.DotNet/Signatures/LocalVariablesSignature.cs
+++ b/src/AsmResolver.DotNet/Signatures/LocalVariablesSignature.cs
@@ -16,7 +16,7 @@ public class LocalVariablesSignature : CallingConventionSignature
/// The blob reader context.
/// The input stream.
/// The signature.
- public static LocalVariablesSignature FromReader(in BlobReadContext context, ref BinaryStreamReader reader)
+ public static LocalVariablesSignature FromReader(ref BlobReaderContext context, ref BinaryStreamReader reader)
{
var result = new LocalVariablesSignature();
result.Attributes = (CallingConventionAttributes) reader.ReadByte();
@@ -28,7 +28,7 @@ public static LocalVariablesSignature FromReader(in BlobReadContext context, ref
}
for (int i = 0; i < count; i++)
- result.VariableTypes.Add(TypeSignature.FromReader(context, ref reader));
+ result.VariableTypes.Add(TypeSignature.FromReader(ref context, ref reader));
return result;
}
diff --git a/src/AsmResolver.DotNet/Signatures/Marshal/LPArrayMarshalDescriptor.cs b/src/AsmResolver.DotNet/Signatures/Marshal/LPArrayMarshalDescriptor.cs
index 7346b3616..b57d2ed18 100644
--- a/src/AsmResolver.DotNet/Signatures/Marshal/LPArrayMarshalDescriptor.cs
+++ b/src/AsmResolver.DotNet/Signatures/Marshal/LPArrayMarshalDescriptor.cs
@@ -17,7 +17,11 @@ public class LPArrayMarshalDescriptor : MarshalDescriptor
///
public static LPArrayMarshalDescriptor FromReader(ref BinaryStreamReader reader)
{
- var descriptor = new LPArrayMarshalDescriptor((NativeType) reader.ReadByte());
+ var descriptor = new LPArrayMarshalDescriptor();
+
+ if (!reader.CanRead(sizeof(byte)))
+ return descriptor;
+ descriptor.ArrayElementType = (NativeType) reader.ReadByte();
if (!reader.TryReadCompressedUInt32(out uint value))
return descriptor;
@@ -34,11 +38,18 @@ public static LPArrayMarshalDescriptor FromReader(ref BinaryStreamReader reader)
return descriptor;
}
+ ///
+ /// Creates a new empty instance of the class.
+ ///
+ public LPArrayMarshalDescriptor()
+ {
+ }
+
///
/// Creates a new instance of the class.
///
/// The type of elements stored in the array.
- public LPArrayMarshalDescriptor(NativeType arrayElementType)
+ public LPArrayMarshalDescriptor(NativeType? arrayElementType)
{
ArrayElementType = arrayElementType;
}
@@ -49,7 +60,7 @@ public LPArrayMarshalDescriptor(NativeType arrayElementType)
///
/// Gets the type of elements stored in the array.
///
- public NativeType ArrayElementType
+ public NativeType? ArrayElementType
{
get;
set;
@@ -86,20 +97,22 @@ public LPArrayFlags? Flags
protected override void WriteContents(in BlobSerializationContext context)
{
var writer = context.Writer;
-
writer.WriteByte((byte) NativeType);
+
+ if (!ArrayElementType.HasValue)
+ return;
writer.WriteByte((byte) ArrayElementType);
- if (ParameterIndex.HasValue)
- {
- writer.WriteCompressedUInt32((uint) ParameterIndex.Value);
- if (NumberOfElements.HasValue)
- {
- writer.WriteCompressedUInt32((uint) NumberOfElements.Value);
- if (Flags.HasValue)
- writer.WriteCompressedUInt32((uint) Flags.Value);
- }
- }
+ if (!ParameterIndex.HasValue)
+ return;
+ writer.WriteCompressedUInt32((uint) ParameterIndex.Value);
+
+ if (!NumberOfElements.HasValue)
+ return;
+ writer.WriteCompressedUInt32((uint) NumberOfElements.Value);
+
+ if (Flags.HasValue)
+ writer.WriteCompressedUInt32((uint) Flags.Value);
}
}
}
diff --git a/src/AsmResolver.DotNet/Signatures/MethodSignature.cs b/src/AsmResolver.DotNet/Signatures/MethodSignature.cs
index 3600c6e32..0651a80fb 100644
--- a/src/AsmResolver.DotNet/Signatures/MethodSignature.cs
+++ b/src/AsmResolver.DotNet/Signatures/MethodSignature.cs
@@ -18,7 +18,7 @@ public class MethodSignature : MethodSignatureBase
/// The blob reader context.
/// The blob input stream.
/// The method signature.
- public static MethodSignature FromReader(in BlobReadContext context, ref BinaryStreamReader reader)
+ public static MethodSignature FromReader(ref BlobReaderContext context, ref BinaryStreamReader reader)
{
var result = new MethodSignature(
(CallingConventionAttributes) reader.ReadByte(),
@@ -37,7 +37,7 @@ public static MethodSignature FromReader(in BlobReadContext context, ref BinaryS
result.GenericParameterCount = (int) genericParameterCount;
}
- result.ReadParametersAndReturnType(context, ref reader);
+ result.ReadParametersAndReturnType(ref context, ref reader);
return result;
}
diff --git a/src/AsmResolver.DotNet/Signatures/MethodSignatureBase.cs b/src/AsmResolver.DotNet/Signatures/MethodSignatureBase.cs
index 191bc2710..4da04a96b 100644
--- a/src/AsmResolver.DotNet/Signatures/MethodSignatureBase.cs
+++ b/src/AsmResolver.DotNet/Signatures/MethodSignatureBase.cs
@@ -106,7 +106,7 @@ public override bool IsImportedInModule(ModuleDefinition module)
///
/// The blob reader context.
/// The input stream.
- protected void ReadParametersAndReturnType(in BlobReadContext context, ref BinaryStreamReader reader)
+ protected void ReadParametersAndReturnType(ref BlobReaderContext context, ref BinaryStreamReader reader)
{
// Parameter count.
if (!reader.TryReadCompressedUInt32(out uint parameterCount))
@@ -116,14 +116,14 @@ protected void ReadParametersAndReturnType(in BlobReadContext context, ref Binar
}
// Return type.
- ReturnType = TypeSignature.FromReader(context, ref reader);
+ ReturnType = TypeSignature.FromReader(ref context, ref reader);
// Parameter types.
_parameterTypes.Capacity = (int) parameterCount;
bool sentinel = false;
for (int i = 0; i < parameterCount; i++)
{
- var parameterType = TypeSignature.FromReader(context, ref reader);
+ var parameterType = TypeSignature.FromReader(ref context, ref reader);
if (parameterType.ElementType == ElementType.Sentinel)
{
diff --git a/src/AsmResolver.DotNet/Signatures/PropertySignature.cs b/src/AsmResolver.DotNet/Signatures/PropertySignature.cs
index 15b01e0d1..7da4f39c3 100644
--- a/src/AsmResolver.DotNet/Signatures/PropertySignature.cs
+++ b/src/AsmResolver.DotNet/Signatures/PropertySignature.cs
@@ -17,7 +17,7 @@ public class PropertySignature : MethodSignatureBase
/// The blob reader context.
/// The blob input stream.
/// The property signature.
- public static PropertySignature? FromReader(in BlobReadContext context, ref BinaryStreamReader reader)
+ public static PropertySignature? FromReader(ref BlobReaderContext context, ref BinaryStreamReader reader)
{
var attributes = (CallingConventionAttributes) reader.ReadByte();
if ((attributes & CallingConventionAttributes.Property) == 0)
@@ -31,7 +31,7 @@ public class PropertySignature : MethodSignatureBase
context.ReaderContext.ParentModule.CorLibTypeFactory.Object,
Enumerable.Empty());
- result.ReadParametersAndReturnType(context, ref reader);
+ result.ReadParametersAndReturnType(ref context, ref reader);
return result;
}
diff --git a/src/AsmResolver.DotNet/Signatures/Security/PermissionSetSignature.cs b/src/AsmResolver.DotNet/Signatures/Security/PermissionSetSignature.cs
index 347365357..9ccbcfb75 100644
--- a/src/AsmResolver.DotNet/Signatures/Security/PermissionSetSignature.cs
+++ b/src/AsmResolver.DotNet/Signatures/Security/PermissionSetSignature.cs
@@ -14,7 +14,7 @@ public class PermissionSetSignature : ExtendableBlobSignature
/// The blob reader context.
/// The input blob stream.
/// The permission set.
- public static PermissionSetSignature FromReader(in BlobReadContext context, ref BinaryStreamReader reader)
+ public static PermissionSetSignature FromReader(in BlobReaderContext context, ref BinaryStreamReader reader)
{
var result = new PermissionSetSignature();
if (reader.ReadByte() != '.')
diff --git a/src/AsmResolver.DotNet/Signatures/Security/SecurityAttribute.cs b/src/AsmResolver.DotNet/Signatures/Security/SecurityAttribute.cs
index 92ea1cef5..abb55b287 100644
--- a/src/AsmResolver.DotNet/Signatures/Security/SecurityAttribute.cs
+++ b/src/AsmResolver.DotNet/Signatures/Security/SecurityAttribute.cs
@@ -17,7 +17,7 @@ public class SecurityAttribute
/// The blob reader context.
/// The input blob stream.
/// The security attribute.
- public static SecurityAttribute FromReader(in BlobReadContext context, ref BinaryStreamReader reader)
+ public static SecurityAttribute FromReader(in BlobReaderContext context, ref BinaryStreamReader reader)
{
string? typeName = reader.ReadSerString();
var type = string.IsNullOrEmpty(typeName)
diff --git a/src/AsmResolver.DotNet/Signatures/SerializedCustomAttributeSignature.cs b/src/AsmResolver.DotNet/Signatures/SerializedCustomAttributeSignature.cs
index 3a841170a..a7e6e6028 100644
--- a/src/AsmResolver.DotNet/Signatures/SerializedCustomAttributeSignature.cs
+++ b/src/AsmResolver.DotNet/Signatures/SerializedCustomAttributeSignature.cs
@@ -10,7 +10,7 @@ namespace AsmResolver.DotNet.Signatures
///
public class SerializedCustomAttributeSignature : CustomAttributeSignature
{
- private readonly BlobReadContext _context;
+ private readonly BlobReaderContext _context;
private readonly TypeSignature[] _fixedArgTypes;
private readonly BinaryStreamReader _reader;
@@ -21,7 +21,7 @@ public class SerializedCustomAttributeSignature : CustomAttributeSignature
/// The types of all fixed arguments.
/// The input blob reader.
public SerializedCustomAttributeSignature(
- in BlobReadContext context,
+ in BlobReaderContext context,
IEnumerable fixedArgTypes,
in BinaryStreamReader reader)
{
diff --git a/src/AsmResolver.DotNet/Signatures/Types/ArrayTypeSignature.cs b/src/AsmResolver.DotNet/Signatures/Types/ArrayTypeSignature.cs
index 081ec88e2..682ec1f4e 100644
--- a/src/AsmResolver.DotNet/Signatures/Types/ArrayTypeSignature.cs
+++ b/src/AsmResolver.DotNet/Signatures/Types/ArrayTypeSignature.cs
@@ -69,9 +69,9 @@ public IList Dimensions
get;
}
- internal new static ArrayTypeSignature FromReader(in BlobReadContext context, ref BinaryStreamReader reader)
+ internal new static ArrayTypeSignature FromReader(ref BlobReaderContext context, ref BinaryStreamReader reader)
{
- var signature = new ArrayTypeSignature(TypeSignature.FromReader(context, ref reader));
+ var signature = new ArrayTypeSignature(TypeSignature.FromReader(ref context, ref reader));
// Rank
if (!reader.TryReadCompressedUInt32(out uint rank))
diff --git a/src/AsmResolver.DotNet/Signatures/Types/GenericInstanceTypeSignature.cs b/src/AsmResolver.DotNet/Signatures/Types/GenericInstanceTypeSignature.cs
index 33d588a03..990652f5f 100644
--- a/src/AsmResolver.DotNet/Signatures/Types/GenericInstanceTypeSignature.cs
+++ b/src/AsmResolver.DotNet/Signatures/Types/GenericInstanceTypeSignature.cs
@@ -14,9 +14,9 @@ public class GenericInstanceTypeSignature : TypeSignature, IGenericArgumentsProv
private ITypeDefOrRef _genericType;
private bool _isValueType;
- internal new static GenericInstanceTypeSignature FromReader(in BlobReadContext context, ref BinaryStreamReader reader)
+ internal new static GenericInstanceTypeSignature FromReader(ref BlobReaderContext context, ref BinaryStreamReader reader)
{
- var genericType = TypeSignature.FromReader(context, ref reader);
+ var genericType = TypeSignature.FromReader(ref context, ref reader);
var signature = new GenericInstanceTypeSignature(genericType.ToTypeDefOrRef(), genericType.ElementType == ElementType.ValueType);
if (!reader.TryReadCompressedUInt32(out uint count))
@@ -27,7 +27,7 @@ public class GenericInstanceTypeSignature : TypeSignature, IGenericArgumentsProv
signature._typeArguments.Capacity = (int) count;
for (int i = 0; i < count; i++)
- signature._typeArguments.Add(TypeSignature.FromReader(context, ref reader));
+ signature._typeArguments.Add(TypeSignature.FromReader(ref context, ref reader));
return signature;
}
@@ -89,7 +89,7 @@ public override string? Name
get
{
string genericArgString = string.Join(", ", TypeArguments);
- return $"{GenericType?.Name ?? NullTypeToString}<{genericArgString}>";
+ return $"{GenericType.Name ?? NullTypeToString}<{genericArgString}>";
}
}
diff --git a/src/AsmResolver.DotNet/Signatures/Types/ITypeSignatureResolver.cs b/src/AsmResolver.DotNet/Signatures/Types/ITypeSignatureResolver.cs
index 9b7faec67..5e67b8f34 100644
--- a/src/AsmResolver.DotNet/Signatures/Types/ITypeSignatureResolver.cs
+++ b/src/AsmResolver.DotNet/Signatures/Types/ITypeSignatureResolver.cs
@@ -13,7 +13,7 @@ public interface ITypeSignatureResolver
/// The blob reading context the type is situated in.
/// The token to resolve.
/// The type.
- ITypeDefOrRef ResolveToken(in BlobReadContext context, MetadataToken token);
+ ITypeDefOrRef ResolveToken(ref BlobReaderContext context, MetadataToken token);
///
/// Resolves an address to a runtime method table to a type signature.
@@ -21,7 +21,7 @@ public interface ITypeSignatureResolver
/// The blob reading context the type is situated in.
/// The address to resolve.
/// The type.
- TypeSignature ResolveRuntimeType(in BlobReadContext context, nint address);
+ TypeSignature ResolveRuntimeType(ref BlobReaderContext context, nint address);
}
}
diff --git a/src/AsmResolver.DotNet/Signatures/Types/PhysicalTypeSignatureResolver.cs b/src/AsmResolver.DotNet/Signatures/Types/PhysicalTypeSignatureResolver.cs
index b85f6b6aa..a934931e8 100644
--- a/src/AsmResolver.DotNet/Signatures/Types/PhysicalTypeSignatureResolver.cs
+++ b/src/AsmResolver.DotNet/Signatures/Types/PhysicalTypeSignatureResolver.cs
@@ -18,12 +18,12 @@ public static PhysicalTypeSignatureResolver Instance
} = new();
///
- public virtual ITypeDefOrRef ResolveToken(in BlobReadContext context, MetadataToken token)
+ public virtual ITypeDefOrRef ResolveToken(ref BlobReaderContext context, MetadataToken token)
{
switch (token.Table)
{
// Check for infinite recursion.
- case TableIndex.TypeSpec when !context.TraversedTokens.Add(token):
+ case TableIndex.TypeSpec when !context.StepInToken(token):
context.ReaderContext.BadImage("Infinite metadata loop was detected.");
return InvalidTypeDefOrRef.Get(InvalidTypeSignatureError.MetadataLoop);
@@ -34,6 +34,9 @@ public virtual ITypeDefOrRef ResolveToken(in BlobReadContext context, MetadataTo
if (context.ReaderContext.ParentModule.TryLookupMember(token, out var member)
&& member is ITypeDefOrRef typeDefOrRef)
{
+ if (token.Table == TableIndex.TypeSpec)
+ context.StepOutToken();
+
return typeDefOrRef;
}
@@ -47,7 +50,7 @@ public virtual ITypeDefOrRef ResolveToken(in BlobReadContext context, MetadataTo
}
///
- public virtual TypeSignature ResolveRuntimeType(in BlobReadContext context, nint address)
+ public virtual TypeSignature ResolveRuntimeType(ref BlobReaderContext context, nint address)
{
throw new NotSupportedException(
"Encountered an COR_ELEMENT_TYPE_INTERNAL type signature which is not supported by this "
diff --git a/src/AsmResolver.DotNet/Signatures/Types/TypeSignature.cs b/src/AsmResolver.DotNet/Signatures/Types/TypeSignature.cs
index 78ce8e2b9..6bd697c38 100644
--- a/src/AsmResolver.DotNet/Signatures/Types/TypeSignature.cs
+++ b/src/AsmResolver.DotNet/Signatures/Types/TypeSignature.cs
@@ -27,7 +27,7 @@ public abstract string? Namespace
}
///
- public string FullName => this.GetTypeFullName();
+ public string FullName => MemberNameGenerator.GetTypeFullName(this);
///
public abstract IResolutionScope? Scope
@@ -63,7 +63,7 @@ public abstract ElementType ElementType
/// The type signature.
/// Occurs when the blob reader points to an element type that is
/// invalid or unsupported.
- public static TypeSignature FromReader(in BlobReadContext context, ref BinaryStreamReader reader)
+ public static TypeSignature FromReader(ref BlobReaderContext context, ref BinaryStreamReader reader)
{
var elementType = (ElementType) reader.ReadByte();
switch (elementType)
@@ -89,16 +89,16 @@ public static TypeSignature FromReader(in BlobReadContext context, ref BinaryStr
return context.ReaderContext.ParentModule.CorLibTypeFactory.FromElementType(elementType)!;
case ElementType.ValueType:
- return new TypeDefOrRefSignature(ReadTypeDefOrRef(context, ref reader, false), true);
+ return new TypeDefOrRefSignature(ReadTypeDefOrRef(ref context, ref reader, false), true);
case ElementType.Class:
- return new TypeDefOrRefSignature(ReadTypeDefOrRef(context, ref reader, false), false);
+ return new TypeDefOrRefSignature(ReadTypeDefOrRef(ref context, ref reader, false), false);
case ElementType.Ptr:
- return new PointerTypeSignature(FromReader(context, ref reader));
+ return new PointerTypeSignature(FromReader(ref context, ref reader));
case ElementType.ByRef:
- return new ByReferenceTypeSignature(FromReader(context, ref reader));
+ return new ByReferenceTypeSignature(FromReader(ref context, ref reader));
case ElementType.Var:
return new GenericParameterSignature(context.ReaderContext.ParentModule,
@@ -111,40 +111,40 @@ public static TypeSignature FromReader(in BlobReadContext context, ref BinaryStr
(int) reader.ReadCompressedUInt32());
case ElementType.Array:
- return ArrayTypeSignature.FromReader(context, ref reader);
+ return ArrayTypeSignature.FromReader(ref context, ref reader);
case ElementType.GenericInst:
- return GenericInstanceTypeSignature.FromReader(context, ref reader);
+ return GenericInstanceTypeSignature.FromReader(ref context, ref reader);
case ElementType.FnPtr:
- return new FunctionPointerTypeSignature(MethodSignature.FromReader(context, ref reader));
+ return new FunctionPointerTypeSignature(MethodSignature.FromReader(ref context, ref reader));
case ElementType.SzArray:
- return new SzArrayTypeSignature(FromReader(context, ref reader));
+ return new SzArrayTypeSignature(FromReader(ref context, ref reader));
case ElementType.CModReqD:
return new CustomModifierTypeSignature(
- ReadTypeDefOrRef(context, ref reader, true),
+ ReadTypeDefOrRef(ref context, ref reader, true),
true,
- FromReader(context, ref reader));
+ FromReader(ref context, ref reader));
case ElementType.CModOpt:
return new CustomModifierTypeSignature(
- ReadTypeDefOrRef(context, ref reader, true),
+ ReadTypeDefOrRef(ref context, ref reader, true),
false,
- FromReader(context, ref reader));
+ FromReader(ref context, ref reader));
case ElementType.Sentinel:
return new SentinelTypeSignature();
case ElementType.Pinned:
- return new PinnedTypeSignature(FromReader(context, ref reader));
+ return new PinnedTypeSignature(FromReader(ref context, ref reader));
case ElementType.Boxed:
- return new BoxedTypeSignature(FromReader(context, ref reader));
+ return new BoxedTypeSignature(FromReader(ref context, ref reader));
case ElementType.Internal:
- return context.TypeSignatureResolver.ResolveRuntimeType(context, IntPtr.Size switch
+ return context.TypeSignatureResolver.ResolveRuntimeType(ref context, IntPtr.Size switch
{
4 => new IntPtr(reader.ReadInt32()),
_ => new IntPtr(reader.ReadInt64())
@@ -163,7 +163,7 @@ public static TypeSignature FromReader(in BlobReadContext context, ref BinaryStr
/// Indicates the coded index to the type is allowed to be decoded to a member in
/// the type specification table.
/// The decoded and resolved type definition or reference.
- protected static ITypeDefOrRef ReadTypeDefOrRef(in BlobReadContext context, ref BinaryStreamReader reader, bool allowTypeSpec)
+ protected static ITypeDefOrRef ReadTypeDefOrRef(ref BlobReaderContext context, ref BinaryStreamReader reader, bool allowTypeSpec)
{
if (!reader.TryReadCompressedUInt32(out uint codedIndex))
return InvalidTypeDefOrRef.Get(InvalidTypeSignatureError.BlobTooShort);
@@ -179,7 +179,7 @@ protected static ITypeDefOrRef ReadTypeDefOrRef(in BlobReadContext context, ref
return InvalidTypeDefOrRef.Get(InvalidTypeSignatureError.IllegalTypeSpec);
}
- return context.TypeSignatureResolver.ResolveToken(context, token);
+ return context.TypeSignatureResolver.ResolveToken(ref context, token);
}
///
@@ -206,7 +206,7 @@ protected void WriteTypeDefOrRef(BlobSerializationContext context, ITypeDefOrRef
context.Writer.WriteCompressedUInt32(index);
}
- internal static TypeSignature ReadFieldOrPropType(in BlobReadContext context, ref BinaryStreamReader reader)
+ internal static TypeSignature ReadFieldOrPropType(in BlobReaderContext context, ref BinaryStreamReader reader)
{
var module = context.ReaderContext.ParentModule;
diff --git a/src/AsmResolver.DotNet/TypeDefinition.cs b/src/AsmResolver.DotNet/TypeDefinition.cs
index b9f658544..ffe56e169 100644
--- a/src/AsmResolver.DotNet/TypeDefinition.cs
+++ b/src/AsmResolver.DotNet/TypeDefinition.cs
@@ -63,7 +63,7 @@ protected TypeDefinition(MetadataToken token)
/// The namespace the type resides in.
/// The name of the type.
/// The attributes associated to the type.
- public TypeDefinition(string? ns, string? name, TypeAttributes attributes)
+ public TypeDefinition(Utf8String? ns, Utf8String? name, TypeAttributes attributes)
: this(ns, name, attributes, null)
{
}
@@ -75,7 +75,7 @@ public TypeDefinition(string? ns, string? name, TypeAttributes attributes)
/// The name of the type.
/// The attributes associated to the type.
/// The super class that this type extends.
- public TypeDefinition(string? ns, string? name, TypeAttributes attributes, ITypeDefOrRef? baseType)
+ public TypeDefinition(Utf8String? ns, Utf8String? name, TypeAttributes attributes, ITypeDefOrRef? baseType)
: this(new MetadataToken(TableIndex.TypeDef, 0))
{
Namespace = ns;
@@ -115,7 +115,7 @@ public Utf8String? Name
///
/// Gets the full name (including namespace or declaring type full name) of the type.
///
- public string FullName => this.GetTypeFullName();
+ public string FullName => MemberNameGenerator.GetTypeFullName(this);
///
/// Gets or sets the attributes associated to the type.
diff --git a/src/AsmResolver.DotNet/TypeDescriptorExtensions.cs b/src/AsmResolver.DotNet/TypeDescriptorExtensions.cs
index 360ad9f54..5b586f18d 100644
--- a/src/AsmResolver.DotNet/TypeDescriptorExtensions.cs
+++ b/src/AsmResolver.DotNet/TypeDescriptorExtensions.cs
@@ -20,6 +20,28 @@ public static class TypeDescriptorExtensions
public static bool IsTypeOf(this ITypeDescriptor type, string? ns, string? name) =>
type.Name == name && type.Namespace == ns;
+ ///
+ /// Determines whether a type matches a namespace and name pair.
+ ///
+ /// The type.
+ /// The namespace.
+ /// The name.
+ /// true if the name and the namespace of the type matches the provided values,
+ /// false otherwise.
+ public static bool IsTypeOfUtf8(this ITypeDefOrRef type, Utf8String? ns, Utf8String? name) =>
+ type.Name == name && type.Namespace == ns;
+
+ ///
+ /// Determines whether a type matches a namespace and name pair.
+ ///
+ /// The type.
+ /// The namespace.
+ /// The name.
+ /// true if the name and the namespace of the type matches the provided values,
+ /// false otherwise.
+ public static bool IsTypeOfUtf8(this ExportedType type, Utf8String? ns, Utf8String? name) =>
+ type.Name == name && type.Namespace == ns;
+
///
/// Constructs a new single-dimension, zero based array signature with the provided type descriptor
/// as element type.
diff --git a/src/AsmResolver.DotNet/TypeReference.cs b/src/AsmResolver.DotNet/TypeReference.cs
index fef21335e..2db296a1a 100644
--- a/src/AsmResolver.DotNet/TypeReference.cs
+++ b/src/AsmResolver.DotNet/TypeReference.cs
@@ -37,7 +37,7 @@ protected TypeReference(MetadataToken token)
/// The scope that defines the type.
/// The namespace the type resides in.
/// The name of the type.
- public TypeReference(IResolutionScope? scope, string? ns, string? name)
+ public TypeReference(IResolutionScope? scope, Utf8String? ns, Utf8String? name)
: this(new MetadataToken(TableIndex.TypeRef, 0))
{
_scope.Value = scope;
@@ -52,7 +52,7 @@ public TypeReference(IResolutionScope? scope, string? ns, string? name)
/// The scope that defines the type.
/// The namespace the type resides in.
/// The name of the type.
- public TypeReference(ModuleDefinition? module, IResolutionScope? scope, string? ns, string? name)
+ public TypeReference(ModuleDefinition? module, IResolutionScope? scope, Utf8String? ns, Utf8String? name)
: this(new MetadataToken(TableIndex.TypeRef, 0))
{
_scope.Value = scope;
@@ -90,7 +90,7 @@ public Utf8String? Namespace
string? ITypeDescriptor.Namespace => Namespace;
///
- public string FullName => this.GetTypeFullName();
+ public string FullName => MemberNameGenerator.GetTypeFullName(this);
///
public IResolutionScope? Scope
diff --git a/src/AsmResolver.DotNet/TypeSpecification.cs b/src/AsmResolver.DotNet/TypeSpecification.cs
index aa4420351..d601ec7a7 100644
--- a/src/AsmResolver.DotNet/TypeSpecification.cs
+++ b/src/AsmResolver.DotNet/TypeSpecification.cs
@@ -61,7 +61,7 @@ public TypeSignature? Signature
string? ITypeDescriptor.Namespace => Namespace;
///
- public string FullName => this.GetTypeFullName();
+ public string FullName => MemberNameGenerator.GetTypeFullName(this);
///
public ModuleDefinition? Module => Signature?.Module;
diff --git a/src/AsmResolver.PE/DotNet/Cil/CilOpCodes.cs b/src/AsmResolver.PE/DotNet/Cil/CilOpCodes.cs
index 2c5f41b5a..6d7012b0f 100644
--- a/src/AsmResolver.PE/DotNet/Cil/CilOpCodes.cs
+++ b/src/AsmResolver.PE/DotNet/Cil/CilOpCodes.cs
@@ -18,7 +18,7 @@ public static class CilOpCodes
/// Gets a sorted list of all single-byte operation codes.
///
public static readonly CilOpCode[] SingleByteOpCodes = new CilOpCode[256];
-
+
///
/// Gets a sorted list of all multi-byte operation codes.
///
@@ -2824,7 +2824,7 @@ public static class CilOpCodes
(((ushort) CilCode.Endfinally & 0xFF) << ValueOffset)
| (((ushort) CilCode.Endfinally >> 15) << TwoBytesOffset)
| ((ushort) Push0 << StackBehaviourPushOffset)
- | ((ushort) Pop0 << StackBehaviourPopOffset)
+ | ((ushort) PopAll << StackBehaviourPopOffset)
| ((byte) Primitive << OpCodeTypeOffset)
| ((byte) InlineNone << OperandTypeOffset)
| ((byte) Return << FlowControlOffset));
@@ -2890,7 +2890,7 @@ public static class CilOpCodes
| ((byte) Next << FlowControlOffset));
///
- /// This prefix opcode is reserved and currently not implemented in the runtime
+ /// This prefix opcode is reserved and currently not implemented in the runtime
///
///
/// See also:
@@ -2905,7 +2905,7 @@ public static class CilOpCodes
| ((byte) Meta << FlowControlOffset));
///
- /// This prefix opcode is reserved and currently not implemented in the runtime
+ /// This prefix opcode is reserved and currently not implemented in the runtime
///
///
/// See also:
@@ -2920,7 +2920,7 @@ public static class CilOpCodes
| ((byte) Meta << FlowControlOffset));
///
- /// This prefix opcode is reserved and currently not implemented in the runtime
+ /// This prefix opcode is reserved and currently not implemented in the runtime
///
///
/// See also:
@@ -2935,7 +2935,7 @@ public static class CilOpCodes
| ((byte) Meta << FlowControlOffset));
///
- /// This prefix opcode is reserved and currently not implemented in the runtime
+ /// This prefix opcode is reserved and currently not implemented in the runtime
///
///
/// See also:
@@ -2950,7 +2950,7 @@ public static class CilOpCodes
| ((byte) Meta << FlowControlOffset));
///
- /// This prefix opcode is reserved and currently not implemented in the runtime
+ /// This prefix opcode is reserved and currently not implemented in the runtime
///
///
/// See also:
@@ -2965,7 +2965,7 @@ public static class CilOpCodes
| ((byte) Meta << FlowControlOffset));
///
- /// This prefix opcode is reserved and currently not implemented in the runtime
+ /// This prefix opcode is reserved and currently not implemented in the runtime
///
///
/// See also:
@@ -2980,7 +2980,7 @@ public static class CilOpCodes
| ((byte) Meta << FlowControlOffset));
///
- /// This prefix opcode is reserved and currently not implemented in the runtime
+ /// This prefix opcode is reserved and currently not implemented in the runtime
///
///
/// See also:
@@ -2995,7 +2995,7 @@ public static class CilOpCodes
| ((byte) Meta << FlowControlOffset));
///
- /// This prefix opcode is reserved and currently not implemented in the runtime
+ /// This prefix opcode is reserved and currently not implemented in the runtime
///
///
/// See also:
diff --git a/src/AsmResolver.Symbols.Pdb/Records/CodeViewSymbol.cs b/src/AsmResolver.Symbols.Pdb/Records/CodeViewSymbol.cs
index 5869c3acd..21d6191af 100644
--- a/src/AsmResolver.Symbols.Pdb/Records/CodeViewSymbol.cs
+++ b/src/AsmResolver.Symbols.Pdb/Records/CodeViewSymbol.cs
@@ -34,6 +34,8 @@ public static CodeViewSymbol FromReader(PdbReaderContext context, ref BinaryStre
CodeViewSymbolType.Pub32 => new SerializedPublicSymbol(dataReader),
CodeViewSymbolType.Udt => new SerializedUserDefinedTypeSymbol(context, dataReader),
CodeViewSymbolType.Constant => new SerializedConstantSymbol(context, dataReader),
+ CodeViewSymbolType.ProcRef => new SerializedProcedureReferenceSymbol(dataReader, false),
+ CodeViewSymbolType.LProcRef => new SerializedProcedureReferenceSymbol(dataReader, true),
_ => new UnknownSymbol(type, dataReader.ReadToEnd())
};
}
diff --git a/src/AsmResolver.Symbols.Pdb/Records/ProcedureReferenceSymbol.cs b/src/AsmResolver.Symbols.Pdb/Records/ProcedureReferenceSymbol.cs
new file mode 100644
index 000000000..0ee3f5782
--- /dev/null
+++ b/src/AsmResolver.Symbols.Pdb/Records/ProcedureReferenceSymbol.cs
@@ -0,0 +1,101 @@
+namespace AsmResolver.Symbols.Pdb.Records;
+
+///
+/// Represents a procedure reference symbol stored in a PDB symbol stream.
+///
+public class ProcedureReferenceSymbol : CodeViewSymbol
+{
+ private readonly LazyVariable _name;
+ private readonly bool _local;
+
+ ///
+ /// Initializes a new empty symbol.
+ ///
+ /// If true, this represents a local procedure reference.
+ protected ProcedureReferenceSymbol(bool local)
+ {
+ _name = new LazyVariable(GetName);
+ _local = local;
+ }
+
+ ///
+ /// Creates a new symbol.
+ ///
+ /// The checksum of the referenced symbol name.
+ /// The offset within the segment the symbol starts at.
+ /// Index of the module that contains this procedure record.
+ /// The name of the symbol.
+ /// If true, this represents a local procedure reference.
+ public ProcedureReferenceSymbol(uint checksum, uint offset, ushort module, Utf8String name, bool local)
+ {
+ Checksum = checksum;
+ Offset = offset;
+ Module = module;
+ _name = new LazyVariable(name);
+ _local = local;
+ }
+
+ ///
+ public override CodeViewSymbolType CodeViewSymbolType
+ {
+ get
+ {
+ return _local ? CodeViewSymbolType.LProcRef : CodeViewSymbolType.ProcRef;
+ }
+ }
+
+ ///
+ /// Is the symbol a Local Procedure Reference?
+ ///
+ public bool IsLocal => _local;
+
+ ///
+ /// Gets the checksum of the referenced symbol name. The checksum used is the
+ /// one specified in the header of the global symbols stream or static symbols stream.
+ ///
+ public uint Checksum
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets the offset of the procedure symbol record from the beginning of the
+ /// $$SYMBOL table for the module.
+ ///
+ public uint Offset
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Index of the module that contains this procedure record.
+ ///
+ public ushort Module
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Gets or sets the name of the symbol.
+ ///
+ public Utf8String Name
+ {
+ get => _name.Value;
+ set => _name.Value = value;
+ }
+
+ ///
+ /// Obtains the name of the symbol.
+ ///
+ /// The name.
+ ///
+ /// This method is called upon initialization of the property.
+ ///
+ protected virtual Utf8String GetName() => Utf8String.Empty;
+
+ ///
+ public override string ToString() => $"{CodeViewSymbolType}: [{Module:X4}:{Offset:X8}] {Name}";
+}
diff --git a/src/AsmResolver.Symbols.Pdb/Records/Serialized/SerializedProcedureReferenceSymbol.cs b/src/AsmResolver.Symbols.Pdb/Records/Serialized/SerializedProcedureReferenceSymbol.cs
new file mode 100644
index 000000000..e165013c0
--- /dev/null
+++ b/src/AsmResolver.Symbols.Pdb/Records/Serialized/SerializedProcedureReferenceSymbol.cs
@@ -0,0 +1,27 @@
+using AsmResolver.IO;
+
+namespace AsmResolver.Symbols.Pdb.Records.Serialized;
+
+///
+/// Represents a lazily initialized implementation of that is read from a PDB image.
+///
+public class SerializedProcedureReferenceSymbol : ProcedureReferenceSymbol
+{
+ private readonly BinaryStreamReader _nameReader;
+
+ ///
+ /// Reads a public symbol from the provided input stream.
+ ///
+ /// The input stream to read from.
+ /// If true, this represents a local procedure reference.
+ public SerializedProcedureReferenceSymbol(BinaryStreamReader reader, bool local) : base(local)
+ {
+ Checksum = reader.ReadUInt32();
+ Offset = reader.ReadUInt32();
+ Module = reader.ReadUInt16();
+ _nameReader = reader;
+ }
+
+ ///
+ protected override Utf8String GetName() => _nameReader.Fork().ReadUtf8String();
+}
diff --git a/src/AsmResolver/Collections/LazyList.cs b/src/AsmResolver/Collections/LazyList.cs
index 6a88b6193..2bfdab185 100644
--- a/src/AsmResolver/Collections/LazyList.cs
+++ b/src/AsmResolver/Collections/LazyList.cs
@@ -13,7 +13,6 @@ namespace AsmResolver.Collections
[DebuggerDisplay("Count = {" + nameof(Count) + "}")]
public abstract class LazyList : IList
{
- private readonly ReaderWriterLockSlim _lock = new(LockRecursionPolicy.NoRecursion);
private readonly List _items;
///
diff --git a/src/AsmResolver/Collections/OneToManyRelation.cs b/src/AsmResolver/Collections/OneToManyRelation.cs
index ce3e55a4a..80a2bbbe9 100644
--- a/src/AsmResolver/Collections/OneToManyRelation.cs
+++ b/src/AsmResolver/Collections/OneToManyRelation.cs
@@ -46,7 +46,13 @@ public bool Add(TKey key, TValue value)
{
if (!_memberOwners.ContainsKey(value))
{
- GetValues(key).Items.Add(value);
+ if (!_memberLists.TryGetValue(key, out var valueSet))
+ {
+ valueSet = new ValueSet();
+ _memberLists.Add(key, valueSet);
+ }
+
+ valueSet.Items.Add(value);
_memberOwners.Add(value, key);
return true;
}
@@ -59,34 +65,29 @@ public bool Add(TKey key, TValue value)
///
/// The key.
/// The values.
- public ValueSet GetValues(TKey key)
- {
- if (!_memberLists.TryGetValue(key, out var items))
- {
- items = new ValueSet();
- _memberLists.Add(key, items);
- }
-
- return items;
- }
+ public ValueSet GetValues(TKey key) => _memberLists.TryGetValue(key, out var valueSet)
+ ? valueSet
+ : ValueSet.Empty;
///
/// Gets the key that maps to the provided value.
///
/// The value.
/// The key.
- public TKey? GetKey(TValue value)
- {
- return _memberOwners.TryGetValue(value, out var key)
- ? key
- : default;
- }
+ public TKey? GetKey(TValue value) => _memberOwners.TryGetValue(value, out var key)
+ ? key
+ : default;
///
/// Represents a collection of values assigned to a single key in a one-to-many relation.
///
public class ValueSet : ICollection
{
+ ///
+ /// Represents the empty value set.
+ ///
+ public static readonly ValueSet Empty = new();
+
internal List Items
{
get;
diff --git a/test/AsmResolver.Benchmarks/AsmResolver.Benchmarks.csproj b/test/AsmResolver.Benchmarks/AsmResolver.Benchmarks.csproj
index bd140f317..9d08fac34 100644
--- a/test/AsmResolver.Benchmarks/AsmResolver.Benchmarks.csproj
+++ b/test/AsmResolver.Benchmarks/AsmResolver.Benchmarks.csproj
@@ -2,19 +2,21 @@
Exe
- net6.0;netcoreapp3.1
+ net6.0
+ enable
+
-
-
-
-
-
+
+
+
+
+
diff --git a/test/AsmResolver.Benchmarks/FullNameGeneratorBenchmark.cs b/test/AsmResolver.Benchmarks/FullNameGeneratorBenchmark.cs
new file mode 100644
index 000000000..06b08df4b
--- /dev/null
+++ b/test/AsmResolver.Benchmarks/FullNameGeneratorBenchmark.cs
@@ -0,0 +1,29 @@
+using AsmResolver.DotNet;
+using AsmResolver.DotNet.Signatures;
+using BenchmarkDotNet.Attributes;
+
+namespace AsmResolver.Benchmarks
+{
+ [MemoryDiagnoser]
+ public class FullNameGeneratorBenchmark
+ {
+ private MemberReference _memberReference = null!;
+
+ [GlobalSetup]
+ public void Setup()
+ {
+ var module = new ModuleDefinition("Dummy");
+ var factory = module.CorLibTypeFactory;
+ _memberReference = factory.CorLibScope
+ .CreateTypeReference("System", "Span`1")
+ .MakeGenericInstanceType(factory.Int32)
+ .ToTypeDefOrRef()
+ .CreateMemberReference(".ctor", MethodSignature.CreateStatic(
+ factory.Void,
+ factory.Int32));
+ }
+
+ [Benchmark]
+ public string FullName() => _memberReference.FullName;
+ }
+}
diff --git a/test/AsmResolver.Benchmarks/Program.cs b/test/AsmResolver.Benchmarks/Program.cs
index 1d3da5a53..c56e6149e 100644
--- a/test/AsmResolver.Benchmarks/Program.cs
+++ b/test/AsmResolver.Benchmarks/Program.cs
@@ -1,16 +1,66 @@
using System;
+using System.CommandLine;
+using System.CommandLine.Builder;
+using System.Linq;
+using System.Reflection;
+using System.Threading.Tasks;
+using BenchmarkDotNet.Configs;
+using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Running;
namespace AsmResolver.Benchmarks
{
internal static class Program
{
- public static void Main(string[] args)
+ public static async Task Main(string[] args)
{
- if (args.Length == 0)
- BenchmarkRunner.Run(typeof(Program).Assembly);
- else
- BenchmarkRunner.Run(Type.GetType($"AsmResolver.Benchmarks.{args[0]}"));
+ var root = new RootCommand();
+
+ var runCommand = new Command("run", "Run benchmarks");
+ root.AddCommand(runCommand);
+
+ var baselineVersionOption = new Option("--baseline",
+ "Compare the results to a different nuget version of AsmResolver.");
+ var onlyOption = new Option("--type",
+ "Only run the benchmarks in the specified benchmark type.");
+
+ runCommand.AddOption(baselineVersionOption);
+ runCommand.AddOption(onlyOption);
+
+ runCommand.SetHandler((baselineVersion, benchmarkType) =>
+ {
+ var config = new ManualConfig();
+ var job = Job.Default;
+
+ if (!string.IsNullOrEmpty(baselineVersion))
+ {
+ config.AddJob(job
+ .WithNuGet(new NuGetReferenceList
+ {
+ new("AsmResolver", baselineVersion),
+ new("AsmResolver.PE.File", baselineVersion),
+ new("AsmResolver.PE", baselineVersion),
+ new("AsmResolver.PE.Win32Resources", baselineVersion),
+ new("AsmResolver.DotNet", baselineVersion),
+ new("AsmResolver.DotNet.Dynamic", baselineVersion),
+ }).WithId(baselineVersion)
+ .AsBaseline());
+ }
+
+ config.AddExporter(DefaultConfig.Instance.GetExporters().ToArray());
+ config.AddLogger(DefaultConfig.Instance.GetLoggers().ToArray());
+ config.AddColumnProvider(DefaultConfig.Instance.GetColumnProviders().ToArray());
+ config.HideColumns("NuGetReferences");
+ config.AddJob(job);
+
+ if (string.IsNullOrEmpty(benchmarkType))
+ BenchmarkRunner.Run(Assembly.GetExecutingAssembly(), config);
+ else
+ BenchmarkRunner.Run(Type.GetType($"AsmResolver.Benchmarks.{benchmarkType}"), config);
+
+ }, baselineVersionOption, onlyOption);
+
+ return await root.InvokeAsync(args);
}
}
}
diff --git a/test/AsmResolver.DotNet.Dynamic.Tests/AsmResolver.DotNet.Dynamic.Tests.csproj b/test/AsmResolver.DotNet.Dynamic.Tests/AsmResolver.DotNet.Dynamic.Tests.csproj
index cbb134178..28574f7f7 100644
--- a/test/AsmResolver.DotNet.Dynamic.Tests/AsmResolver.DotNet.Dynamic.Tests.csproj
+++ b/test/AsmResolver.DotNet.Dynamic.Tests/AsmResolver.DotNet.Dynamic.Tests.csproj
@@ -8,9 +8,9 @@
-
+
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/test/AsmResolver.DotNet.Tests/AsmResolver.DotNet.Tests.csproj b/test/AsmResolver.DotNet.Tests/AsmResolver.DotNet.Tests.csproj
index 830749a8d..393b05e33 100644
--- a/test/AsmResolver.DotNet.Tests/AsmResolver.DotNet.Tests.csproj
+++ b/test/AsmResolver.DotNet.Tests/AsmResolver.DotNet.Tests.csproj
@@ -1,7 +1,7 @@
- net5.0
+ net6.0
false
@@ -9,7 +9,7 @@
-
+
all
diff --git a/test/AsmResolver.DotNet.Tests/AssemblyResolverTest.cs b/test/AsmResolver.DotNet.Tests/AssemblyResolverTest.cs
index 8673fb4df..aaf5d0427 100644
--- a/test/AsmResolver.DotNet.Tests/AssemblyResolverTest.cs
+++ b/test/AsmResolver.DotNet.Tests/AssemblyResolverTest.cs
@@ -202,5 +202,38 @@ public void PreferResolveFromGac64If64BitAssembly(bool legacy)
Assert.NotNull(resolved);
Assert.Contains("GAC_64", resolved.ManifestModule!.FilePath!);
}
+
+ [Fact]
+ public void ResolveReferenceWithExplicitPublicKey()
+ {
+ // https://github.com/Washi1337/AsmResolver/issues/381
+
+ var reference = new AssemblyReference(
+ "System.Collections",
+ new Version(6, 0, 0, 0),
+ true,
+ new byte[]
+ {
+ 0x00, 0x24, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x06, 0x02, 0x00, 0x00, 0x00,
+ 0x24, 0x00, 0x00, 0x52, 0x53, 0x41, 0x31, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x07, 0xD1,
+ 0xFA, 0x57, 0xC4, 0xAE, 0xD9, 0xF0, 0xA3, 0x2E, 0x84, 0xAA, 0x0F, 0xAE, 0xFD, 0x0D, 0xE9, 0xE8, 0xFD,
+ 0x6A, 0xEC, 0x8F, 0x87, 0xFB, 0x03, 0x76, 0x6C, 0x83, 0x4C, 0x99, 0x92, 0x1E, 0xB2, 0x3B, 0xE7, 0x9A,
+ 0xD9, 0xD5, 0xDC, 0xC1, 0xDD, 0x9A, 0xD2, 0x36, 0x13, 0x21, 0x02, 0x90, 0x0B, 0x72, 0x3C, 0xF9, 0x80,
+ 0x95, 0x7F, 0xC4, 0xE1, 0x77, 0x10, 0x8F, 0xC6, 0x07, 0x77, 0x4F, 0x29, 0xE8, 0x32, 0x0E, 0x92, 0xEA,
+ 0x05, 0xEC, 0xE4, 0xE8, 0x21, 0xC0, 0xA5, 0xEF, 0xE8, 0xF1, 0x64, 0x5C, 0x4C, 0x0C, 0x93, 0xC1, 0xAB,
+ 0x99, 0x28, 0x5D, 0x62, 0x2C, 0xAA, 0x65, 0x2C, 0x1D, 0xFA, 0xD6, 0x3D, 0x74, 0x5D, 0x6F, 0x2D, 0xE5,
+ 0xF1, 0x7E, 0x5E, 0xAF, 0x0F, 0xC4, 0x96, 0x3D, 0x26, 0x1C, 0x8A, 0x12, 0x43, 0x65, 0x18, 0x20, 0x6D,
+ 0xC0, 0x93, 0x34, 0x4D, 0x5A, 0xD2, 0x93
+ });
+
+ var module = new ModuleDefinition("Dummy", KnownCorLibs.SystemRuntime_v6_0_0_0);
+ module.AssemblyReferences.Add(reference);
+
+ var definition = reference.Resolve();
+
+ Assert.NotNull(definition);
+ Assert.Equal(reference.Name, definition.Name);
+ Assert.NotNull(definition.ManifestModule!.FilePath);
+ }
}
}
diff --git a/test/AsmResolver.DotNet.Tests/EventDefinitionTest.cs b/test/AsmResolver.DotNet.Tests/EventDefinitionTest.cs
index 6550c0d0d..0d55ccfbb 100644
--- a/test/AsmResolver.DotNet.Tests/EventDefinitionTest.cs
+++ b/test/AsmResolver.DotNet.Tests/EventDefinitionTest.cs
@@ -49,5 +49,15 @@ public void ReadEventSemantics()
Assert.NotNull(@event.RemoveMethod);
}
+ [Fact]
+ public void ReadFullName()
+ {
+ var module = ModuleDefinition.FromFile(typeof(SingleEvent).Assembly.Location);
+ var @event = (EventDefinition) module.LookupMember(
+ typeof(SingleEvent).GetEvent(nameof(SingleEvent.SimpleEvent)).MetadataToken);
+
+ Assert.Equal("System.EventHandler AsmResolver.DotNet.TestCases.Events.SingleEvent::SimpleEvent", @event.FullName);
+ }
+
}
-}
\ No newline at end of file
+}
diff --git a/test/AsmResolver.DotNet.Tests/FieldDefinitionTest.cs b/test/AsmResolver.DotNet.Tests/FieldDefinitionTest.cs
index 28737ee06..ffaf57fe7 100644
--- a/test/AsmResolver.DotNet.Tests/FieldDefinitionTest.cs
+++ b/test/AsmResolver.DotNet.Tests/FieldDefinitionTest.cs
@@ -80,6 +80,16 @@ public void PersistentFieldSignature()
Assert.True(newField.Signature.FieldType.IsTypeOf("System", "Byte"), "Field type should be System.Byte");
}
+ [Fact]
+ public void ReadFullName()
+ {
+ var module = ModuleDefinition.FromFile(typeof(SingleField).Assembly.Location);
+ var field = (FieldDefinition) module.LookupMember(
+ typeof(SingleField).GetField(nameof(SingleField.IntField)).MetadataToken);
+
+ Assert.Equal("System.Int32 AsmResolver.DotNet.TestCases.Fields.SingleField::IntField", field.FullName);
+ }
+
[Fact]
public void ReadFieldRva()
{
diff --git a/test/AsmResolver.DotNet.Tests/MethodDefinitionTest.cs b/test/AsmResolver.DotNet.Tests/MethodDefinitionTest.cs
index 1e2a6fc8f..ad21af54f 100644
--- a/test/AsmResolver.DotNet.Tests/MethodDefinitionTest.cs
+++ b/test/AsmResolver.DotNet.Tests/MethodDefinitionTest.cs
@@ -131,6 +131,54 @@ public void ReadMultipleParameterStatic()
"Expected third parameter to be of type AsmResolver.TestCases.DotNet.MultipleMethods.");
}
+ [Fact]
+ public void ReadParameterlessInt32MethodFullName()
+ {
+ var module = ModuleDefinition.FromFile(typeof(MultipleMethods).Assembly.Location);
+ var method = (MethodDefinition) module.LookupMember(
+ typeof(MultipleMethods).GetMethod(nameof(MultipleMethods.IntParameterlessMethod)).MetadataToken);
+
+ Assert.Equal(
+ "System.Int32 AsmResolver.DotNet.TestCases.Methods.MultipleMethods::IntParameterlessMethod()",
+ method.FullName);
+ }
+
+ [Fact]
+ public void ReadParameterlessMethodFullName()
+ {
+ var module = ModuleDefinition.FromFile(typeof(MultipleMethods).Assembly.Location);
+ var method = (MethodDefinition) module.LookupMember(
+ typeof(MultipleMethods).GetMethod(nameof(MultipleMethods.VoidParameterlessMethod)).MetadataToken);
+
+ Assert.Equal(
+ "System.Void AsmResolver.DotNet.TestCases.Methods.MultipleMethods::VoidParameterlessMethod()",
+ method.FullName);
+ }
+
+ [Fact]
+ public void ReadSingleParameterMethodFullName()
+ {
+ var module = ModuleDefinition.FromFile(typeof(MultipleMethods).Assembly.Location);
+ var method = (MethodDefinition) module.LookupMember(
+ typeof(MultipleMethods).GetMethod(nameof(MultipleMethods.SingleParameterMethod)).MetadataToken);
+
+ Assert.Equal(
+ "System.Void AsmResolver.DotNet.TestCases.Methods.MultipleMethods::SingleParameterMethod(System.Int32)",
+ method.FullName);
+ }
+
+ [Fact]
+ public void ReadMultipleParametersMethodFullName()
+ {
+ var module = ModuleDefinition.FromFile(typeof(MultipleMethods).Assembly.Location);
+ var method = (MethodDefinition) module.LookupMember(
+ typeof(MultipleMethods).GetMethod(nameof(MultipleMethods.MultipleParameterMethod)).MetadataToken);
+
+ Assert.Equal(
+ "System.Void AsmResolver.DotNet.TestCases.Methods.MultipleMethods::MultipleParameterMethod(System.Int32, System.String, AsmResolver.DotNet.TestCases.Methods.MultipleMethods)",
+ method.FullName);
+ }
+
[Fact]
public void ReadNormalMethod()
{
diff --git a/test/AsmResolver.DotNet.Tests/MethodSpecificationTest.cs b/test/AsmResolver.DotNet.Tests/MethodSpecificationTest.cs
index 2083e9946..975789ed7 100644
--- a/test/AsmResolver.DotNet.Tests/MethodSpecificationTest.cs
+++ b/test/AsmResolver.DotNet.Tests/MethodSpecificationTest.cs
@@ -25,6 +25,25 @@ public void ReadMethod()
Assert.Equal("GenericMethodInGenericType", specification.Method!.Name);
}
+ [Fact]
+ public void ReadFullName()
+ {
+ var module = ModuleDefinition.FromFile(typeof(GenericsTestClass).Assembly.Location);
+ var method = (MethodDefinition) module.LookupMember(typeof(GenericsTestClass)
+ .GetMethod(nameof(GenericsTestClass.MethodInstantiationFromGenericType))!.MetadataToken);
+
+ var call = method.CilMethodBody!.Instructions.First(i => i.OpCode.Code == CilCode.Call);
+ Assert.IsAssignableFrom(call.Operand);
+
+ var specification = (MethodSpecification) call.Operand;
+ Assert.Equal(
+ "System.Void AsmResolver.DotNet.TestCases.Generics.GenericType`3::GenericMethodInGenericType()",
+ specification.FullName);
+ Assert.Equal(
+ "System.Void AsmResolver.DotNet.TestCases.Generics.GenericType`3::GenericMethodInGenericType, ?, ?>()",
+ specification.Method!.FullName);
+ }
+
[Fact]
public void ReadSignature()
{
diff --git a/test/AsmResolver.DotNet.Tests/PropertyDefinitionTest.cs b/test/AsmResolver.DotNet.Tests/PropertyDefinitionTest.cs
index f639bfb2f..5bf3c0825 100644
--- a/test/AsmResolver.DotNet.Tests/PropertyDefinitionTest.cs
+++ b/test/AsmResolver.DotNet.Tests/PropertyDefinitionTest.cs
@@ -76,5 +76,25 @@ public void ReadReadWritePropertySemantics()
var property = type.Properties.First(m => m.Name == nameof(MultipleProperties.ReadWriteProperty));
Assert.Equal(2, property.Semantics.Count);
}
+
+ [Fact]
+ public void ReadParameterlessPropertyFullName()
+ {
+ var module = ModuleDefinition.FromFile(typeof(MultipleProperties).Assembly.Location);
+ var property = (PropertyDefinition) module.LookupMember(
+ typeof(MultipleProperties).GetProperty(nameof(MultipleProperties.ReadOnlyProperty)).MetadataToken);
+
+ Assert.Equal("System.Int32 AsmResolver.DotNet.TestCases.Properties.MultipleProperties::ReadOnlyProperty", property.FullName);
+ }
+
+ [Fact]
+ public void ReadParameterPropertyFullName()
+ {
+ var module = ModuleDefinition.FromFile(typeof(MultipleProperties).Assembly.Location);
+ var property = (PropertyDefinition) module.LookupMember(
+ typeof(MultipleProperties).GetProperty("Item").MetadataToken);
+
+ Assert.Equal("System.Int32 AsmResolver.DotNet.TestCases.Properties.MultipleProperties::Item[System.Int32]", property.FullName);
+ }
}
-}
\ No newline at end of file
+}
diff --git a/test/AsmResolver.DotNet.Tests/Signatures/MarshalDescriptorTest.cs b/test/AsmResolver.DotNet.Tests/Signatures/MarshalDescriptorTest.cs
index 90e8c7925..493aa2099 100644
--- a/test/AsmResolver.DotNet.Tests/Signatures/MarshalDescriptorTest.cs
+++ b/test/AsmResolver.DotNet.Tests/Signatures/MarshalDescriptorTest.cs
@@ -65,10 +65,24 @@ public void PersistentSimpleMarshaller()
{
var method = LookupMethod(nameof(PlatformInvoke.SimpleMarshaller));
var newMethod = RebuildAndLookup(method);
- Assert.Equal(method.Parameters[0].Definition.MarshalDescriptor.NativeType,
+ Assert.Equal(method.Parameters[0].Definition.MarshalDescriptor.NativeType,
newMethod.Parameters[0].Definition.MarshalDescriptor.NativeType);
}
-
+
+ [Fact]
+ public void PersistentLPArrayWithoutElementType()
+ {
+ var method = LookupMethod(nameof(PlatformInvoke.LPArrayFixedSizeMarshaller));
+ var originalMarshaller = (LPArrayMarshalDescriptor) method.Parameters[0].Definition!.MarshalDescriptor!;
+ originalMarshaller.ArrayElementType = null;
+
+ var newMethod = RebuildAndLookup(method);
+ var newArrayMarshaller = Assert.IsAssignableFrom(
+ newMethod.Parameters[0].Definition!.MarshalDescriptor);
+
+ Assert.Null(newArrayMarshaller.ArrayElementType);
+ }
+
[Fact]
public void ReadLPArrayMarshallerWithFixedSize()
{
@@ -85,7 +99,7 @@ public void PersistentLPArrayMarshallerWithFixedSize()
{
var method = LookupMethod(nameof(PlatformInvoke.LPArrayFixedSizeMarshaller));
var originalMarshaller = (LPArrayMarshalDescriptor) method.Parameters[0].Definition.MarshalDescriptor;
-
+
var newMethod = RebuildAndLookup(method);
var newMarshaller = newMethod.Parameters[0].Definition.MarshalDescriptor;
Assert.IsAssignableFrom(newMarshaller);
@@ -110,7 +124,7 @@ public void PersistentLPArrayMarshallerWithVariableSize()
{
var method = LookupMethod(nameof(PlatformInvoke.LPArrayVariableSizeMarshaller));
var originalMarshaller = (LPArrayMarshalDescriptor) method.Parameters[0].Definition.MarshalDescriptor;
-
+
var newMethod = RebuildAndLookup(method);
var marshaller = newMethod.Parameters[0].Definition.MarshalDescriptor;
Assert.IsAssignableFrom(marshaller);
@@ -135,7 +149,7 @@ public void PersistentSafeArrayMarshaller()
{
var method = LookupMethod(nameof(PlatformInvoke.SafeArrayMarshaller));
var originalMarshaller = (SafeArrayMarshalDescriptor) method.Parameters[0].Definition.MarshalDescriptor;
-
+
var newMethod = RebuildAndLookup(method);
var marshaller = newMethod.Parameters[0].Definition.MarshalDescriptor;
Assert.IsAssignableFrom(marshaller);
@@ -160,7 +174,7 @@ public void PersistentSafeArrayMarshallerWithSubType()
{
var method = LookupMethod(nameof(PlatformInvoke.SafeArrayMarshallerWithSubType));
var originalMarshaller = (SafeArrayMarshalDescriptor) method.Parameters[0].Definition.MarshalDescriptor;
-
+
var newMethod = RebuildAndLookup(method);
var marshaller = newMethod.Parameters[0].Definition.MarshalDescriptor;
Assert.IsAssignableFrom(marshaller);
@@ -186,7 +200,7 @@ public void PersistentSafeArrayMarshallerWithUserDefinedSubType()
{
var method = LookupMethod(nameof(PlatformInvoke.SafeArrayMarshallerWithUserSubType));
var originalMarshaller = (SafeArrayMarshalDescriptor) method.Parameters[0].Definition.MarshalDescriptor;
-
+
var newMethod = RebuildAndLookup(method);
var marshaller = newMethod.Parameters[0].Definition.MarshalDescriptor;
Assert.IsAssignableFrom(marshaller);
@@ -195,7 +209,7 @@ public void PersistentSafeArrayMarshallerWithUserDefinedSubType()
Assert.NotNull(arrayMarshaller.UserDefinedSubType);
Assert.Equal(originalMarshaller.UserDefinedSubType.Name, arrayMarshaller.UserDefinedSubType.Name);
}
-
+
[Fact]
public void ReadFixedArrayMarshaller()
{
@@ -203,7 +217,7 @@ public void ReadFixedArrayMarshaller()
var marshaller = field.MarshalDescriptor;
Assert.IsAssignableFrom(marshaller);
}
-
+
[Fact]
public void PersistentFixedArrayMarshaller()
{
@@ -212,18 +226,18 @@ public void PersistentFixedArrayMarshaller()
var marshaller = newField.MarshalDescriptor;
Assert.IsAssignableFrom(marshaller);
}
-
+
[Fact]
public void ReadFixedArrayMarshallerWithFixedSizeSpecifier()
{
var field = LookupField(nameof(Marshalling.FixedArrayMarshallerWithFixedSize));
var marshaller = field.MarshalDescriptor;
Assert.IsAssignableFrom(marshaller);
-
+
var arrayMarshaller = (FixedArrayMarshalDescriptor) marshaller;
Assert.Equal(10, arrayMarshaller.Size);
}
-
+
[Fact]
public void PersistentFixedArrayMarshallerWithFixedSizeSpecifier()
{
@@ -233,33 +247,33 @@ public void PersistentFixedArrayMarshallerWithFixedSizeSpecifier()
var newField = RebuildAndLookup(field);
var marshaller = newField.MarshalDescriptor;
Assert.IsAssignableFrom(marshaller);
-
+
var arrayMarshaller = (FixedArrayMarshalDescriptor) marshaller;
Assert.Equal(originalMarshaller.Size, arrayMarshaller.Size);
}
-
+
[Fact]
public void ReadFixedArrayMarshallerWithFixedSizeSpecifierAndArrayType()
{
var field = LookupField(nameof(Marshalling.FixedArrayMarshallerWithFixedSizeAndArrayType));
var marshaller = field.MarshalDescriptor;
Assert.IsAssignableFrom(marshaller);
-
+
var arrayMarshaller = (FixedArrayMarshalDescriptor) marshaller;
Assert.Equal(10, arrayMarshaller.Size);
Assert.Equal(NativeType.U1, arrayMarshaller.ArrayElementType);
}
-
+
[Fact]
public void PersistentFixedArrayMarshallerWithFixedSizeSpecifierAndArrayType()
{
var field = LookupField(nameof(Marshalling.FixedArrayMarshallerWithFixedSizeAndArrayType));
var originalMarshaller = (FixedArrayMarshalDescriptor) field.MarshalDescriptor;
-
+
var newField = RebuildAndLookup(field);
var marshaller = newField.MarshalDescriptor;
Assert.IsAssignableFrom(marshaller);
-
+
var arrayMarshaller = (FixedArrayMarshalDescriptor) marshaller;
Assert.Equal(originalMarshaller.Size, arrayMarshaller.Size);
Assert.Equal(originalMarshaller.ArrayElementType, arrayMarshaller.ArrayElementType);
@@ -271,7 +285,7 @@ public void ReadCustomMarshallerType()
var field = LookupField(nameof(Marshalling.CustomMarshallerWithCustomType));
var marshaller = field.MarshalDescriptor;
Assert.IsAssignableFrom(marshaller);
-
+
var customMarshaller = (CustomMarshalDescriptor) marshaller;
Assert.Equal(nameof(Marshalling), customMarshaller.MarshalType.Name);
}
@@ -281,11 +295,11 @@ public void PersistentCustomMarshallerType()
{
var field = LookupField(nameof(Marshalling.CustomMarshallerWithCustomType));
var originalMarshaller = (CustomMarshalDescriptor) field.MarshalDescriptor;
-
+
var newField = RebuildAndLookup(field);
var marshaller = newField.MarshalDescriptor;
Assert.IsAssignableFrom(marshaller);
-
+
var customMarshaller = (CustomMarshalDescriptor) marshaller;
Assert.Equal(originalMarshaller.MarshalType.Name, customMarshaller.MarshalType.Name);
}
@@ -296,7 +310,7 @@ public void ReadCustomMarshallerTypeWithCookie()
var field = LookupField(nameof(Marshalling.CustomMarshallerWithCustomTypeAndCookie));
var marshaller = field.MarshalDescriptor;
Assert.IsAssignableFrom(marshaller);
-
+
var customMarshaller = (CustomMarshalDescriptor) marshaller;
Assert.Equal(nameof(Marshalling), customMarshaller.MarshalType.Name);
Assert.Equal("abc", customMarshaller.Cookie);
@@ -307,11 +321,11 @@ public void PersistentCustomMarshallerTypeWithCookie()
{
var field = LookupField(nameof(Marshalling.CustomMarshallerWithCustomTypeAndCookie));
var originalMarshaller = (CustomMarshalDescriptor) field.MarshalDescriptor;
-
+
var newField = RebuildAndLookup(field);
var marshaller = newField.MarshalDescriptor;
Assert.IsAssignableFrom(marshaller);
-
+
var customMarshaller = (CustomMarshalDescriptor) marshaller;
Assert.Equal(originalMarshaller.MarshalType.Name, customMarshaller.MarshalType.Name);
Assert.Equal(originalMarshaller.Cookie, customMarshaller.Cookie);
@@ -323,7 +337,7 @@ public void ReadFixedSysString()
var field = LookupField(nameof(Marshalling.FixedSysString));
var marshaller = field.MarshalDescriptor;
Assert.IsAssignableFrom(marshaller);
-
+
var stringMarshaller = (FixedSysStringMarshalDescriptor) marshaller;
Assert.Equal(123, stringMarshaller.Size);
}
@@ -333,11 +347,11 @@ public void PersistentFixedSysString()
{
var field = LookupField(nameof(Marshalling.FixedSysString));
var originalMarshaller = (FixedSysStringMarshalDescriptor) field.MarshalDescriptor;
-
+
var newField = RebuildAndLookup(field);
var marshaller = newField.MarshalDescriptor;
Assert.IsAssignableFrom(marshaller);
-
+
var stringMarshaller = (FixedSysStringMarshalDescriptor) marshaller;
Assert.Equal(originalMarshaller.Size, stringMarshaller.Size);
}
@@ -348,7 +362,7 @@ public void ReadComInterface()
var method = LookupMethod(nameof(PlatformInvoke.ComInterface));
var marshaller = method.Parameters[0].Definition.MarshalDescriptor;
Assert.IsAssignableFrom(marshaller);
-
+
var comMarshaller = (ComInterfaceMarshalDescriptor) marshaller;
Assert.Null(comMarshaller.IidParameterIndex);
}
@@ -361,7 +375,7 @@ public void PersistentComInterface()
var newMethod = RebuildAndLookup(method);
var marshaller = newMethod.Parameters[0].Definition.MarshalDescriptor;
Assert.IsAssignableFrom(marshaller);
-
+
var comMarshaller = (ComInterfaceMarshalDescriptor) marshaller;
Assert.Null(comMarshaller.IidParameterIndex);
}
@@ -372,7 +386,7 @@ public void ReadComInterfaceWithParameterIndex()
var method = LookupMethod(nameof(PlatformInvoke.ComInterfaceWithIidParameter));
var marshaller = method.Parameters[0].Definition.MarshalDescriptor;
Assert.IsAssignableFrom(marshaller);
-
+
var comMarshaller = (ComInterfaceMarshalDescriptor) marshaller;
Assert.Equal(1, comMarshaller.IidParameterIndex);
}
@@ -382,13 +396,13 @@ public void PersistentComInterfaceWithParameterIndex()
{
var method = LookupMethod(nameof(PlatformInvoke.ComInterfaceWithIidParameter));
var originalMarshaller = (ComInterfaceMarshalDescriptor) method.Parameters[0].Definition.MarshalDescriptor;
-
+
var newMethod = RebuildAndLookup(method);
var marshaller = newMethod.Parameters[0].Definition.MarshalDescriptor;
Assert.IsAssignableFrom(marshaller);
-
+
var comMarshaller = (ComInterfaceMarshalDescriptor) marshaller;
Assert.Equal(originalMarshaller.IidParameterIndex, comMarshaller.IidParameterIndex);
}
}
-}
\ No newline at end of file
+}
diff --git a/test/AsmResolver.DotNet.Tests/Signatures/MethodSignatureTest.cs b/test/AsmResolver.DotNet.Tests/Signatures/MethodSignatureTest.cs
index 0b271d859..ed2b51265 100644
--- a/test/AsmResolver.DotNet.Tests/Signatures/MethodSignatureTest.cs
+++ b/test/AsmResolver.DotNet.Tests/Signatures/MethodSignatureTest.cs
@@ -1,4 +1,11 @@
+using System;
+using System.Linq;
+using AsmResolver.DotNet.Code.Cil;
using AsmResolver.DotNet.Signatures;
+using AsmResolver.DotNet.Signatures.Types;
+using AsmResolver.PE.DotNet.Cil;
+using AsmResolver.PE.DotNet.Metadata.Tables.Rows;
+using AsmResolver.PE.File.Headers;
using Xunit;
namespace AsmResolver.DotNet.Tests.Signatures
diff --git a/test/AsmResolver.DotNet.Tests/Signatures/TypeSignatureTest.cs b/test/AsmResolver.DotNet.Tests/Signatures/TypeSignatureTest.cs
new file mode 100644
index 000000000..69f25cbe7
--- /dev/null
+++ b/test/AsmResolver.DotNet.Tests/Signatures/TypeSignatureTest.cs
@@ -0,0 +1,126 @@
+using AsmResolver.DotNet.Signatures;
+using AsmResolver.DotNet.Signatures.Types;
+using AsmResolver.PE.DotNet.Metadata.Tables.Rows;
+using Xunit;
+
+namespace AsmResolver.DotNet.Tests.Signatures
+{
+ public class TypeSignatureTest
+ {
+ private readonly TypeDefinition _dummyType = new("Namespace", "Type", TypeAttributes.Class);
+
+ [Fact]
+ public void GetTypeDefOrRefFullName()
+ {
+ Assert.Equal("Namespace.Type", _dummyType.ToTypeSignature().FullName);
+ }
+
+ [Fact]
+ public void GetArrayTypeFullName()
+ {
+ Assert.Equal("Namespace.Type[0...9, 0...19]", _dummyType
+ .ToTypeSignature()
+ .MakeArrayType(
+ new ArrayDimension(10),
+ new ArrayDimension(20))
+ .FullName);
+ }
+
+ [Fact]
+ public void GetByReferenceTypeFullName()
+ {
+ Assert.Equal("Namespace.Type&", _dummyType
+ .ToTypeSignature()
+ .MakeByReferenceType()
+ .FullName);
+ }
+
+ [Fact]
+ public void GetCorLibTypeFullName()
+ {
+ var module = new ModuleDefinition("Dummy");
+ Assert.Equal("System.String", module.CorLibTypeFactory.String.FullName);
+ }
+
+ [Fact]
+ public void GetFunctionPointerTypeFullName()
+ {
+ var module = new ModuleDefinition("Dummy");
+ Assert.Equal("method System.String *(System.Object, System.Int32)",
+ MethodSignature.CreateStatic(
+ module.CorLibTypeFactory.String,
+ module.CorLibTypeFactory.Object,
+ module.CorLibTypeFactory.Int32)
+ .MakeFunctionPointerType().FullName);
+ }
+
+ [Fact]
+ public void GetInstanceFunctionPointerTypeFullName()
+ {
+ var module = new ModuleDefinition("Dummy");
+ Assert.Equal("method instance System.String *(System.Object, System.Int32)",
+ MethodSignature.CreateInstance(
+ module.CorLibTypeFactory.String,
+ module.CorLibTypeFactory.Object,
+ module.CorLibTypeFactory.Int32)
+ .MakeFunctionPointerType().FullName);
+ }
+
+ [Fact]
+ public void GetGenericInstanceTypeFullName()
+ {
+ var module = new ModuleDefinition("Dummy");
+ var genericInstance = _dummyType.MakeGenericInstanceType(
+ module.CorLibTypeFactory.Int32,
+ _dummyType.MakeGenericInstanceType(module.CorLibTypeFactory.Object));
+
+ Assert.Equal("Type>", genericInstance.Name);
+ Assert.Equal("Namespace.Type>", genericInstance.FullName);
+ }
+
+ [Fact]
+ public void GetGenericParameterFullName()
+ {
+ Assert.Equal("!2", new GenericParameterSignature(GenericParameterType.Type, 2).FullName);
+ Assert.Equal("!!2", new GenericParameterSignature(GenericParameterType.Method, 2).FullName);
+ }
+
+ [Fact]
+ public void GetPointerTypeFullName()
+ {
+ Assert.Equal("Namespace.Type*", _dummyType
+ .ToTypeSignature()
+ .MakePointerType()
+ .FullName);
+ }
+
+ [Fact]
+ public void GetSzArrayTypeFullName()
+ {
+ Assert.Equal("Namespace.Type[]", _dummyType
+ .ToTypeSignature()
+ .MakeSzArrayType()
+ .FullName);
+ }
+
+ [Fact]
+ public void GetRequiredModifierTypeFullName()
+ {
+ Assert.Equal("Namespace.Type modreq(Namespace.Type)",
+ _dummyType
+ .ToTypeSignature()
+ .MakeModifierType(_dummyType, true)
+ .FullName);
+ }
+
+ [Fact]
+ public void GetOptionalModifierTypeFullName()
+ {
+ Assert.Equal("Namespace.Type modopt(Namespace.Type)",
+ _dummyType
+ .ToTypeSignature()
+ .MakeModifierType(_dummyType, false)
+ .FullName);
+ }
+ }
+}
diff --git a/test/AsmResolver.DotNet.Tests/TypeDefinitionTest.cs b/test/AsmResolver.DotNet.Tests/TypeDefinitionTest.cs
index a30204992..4f321ad7b 100644
--- a/test/AsmResolver.DotNet.Tests/TypeDefinitionTest.cs
+++ b/test/AsmResolver.DotNet.Tests/TypeDefinitionTest.cs
@@ -89,6 +89,14 @@ public void ReadNamespace()
Assert.Equal("HelloWorld", module.TopLevelTypes[1].Namespace);
}
+ [Fact]
+ public void ReadTopLevelTypeFullName()
+ {
+ var module = ModuleDefinition.FromFile(typeof(Class).Assembly.Location);
+ var type = (TypeDefinition) module.LookupMember(typeof(Class).MetadataToken);
+ Assert.Equal("AsmResolver.DotNet.TestCases.Types.Class", type.FullName);
+ }
+
[Fact]
public void NonNullNamespaceIsPersistentAfterRebuild()
{
@@ -179,6 +187,22 @@ public void ReadNestedTypes()
Assert.Same(module, nested4.Module);
}
+ [Fact]
+ public void ReadNestedFullName()
+ {
+ var module = ModuleDefinition.FromFile(typeof(TopLevelClass1).Assembly.Location);
+ var type = (TypeDefinition) module.LookupMember(typeof(TopLevelClass1.Nested1).MetadataToken);
+ Assert.Equal("AsmResolver.DotNet.TestCases.NestedClasses.TopLevelClass1+Nested1", type.FullName);
+ }
+
+ [Fact]
+ public void ReadNestedNestedFullName()
+ {
+ var module = ModuleDefinition.FromFile(typeof(TopLevelClass1).Assembly.Location);
+ var type = (TypeDefinition) module.LookupMember(typeof(TopLevelClass1.Nested1.Nested1Nested2).MetadataToken);
+ Assert.Equal("AsmResolver.DotNet.TestCases.NestedClasses.TopLevelClass1+Nested1+Nested1Nested2", type.FullName);
+ }
+
[Fact]
public void ResolveNestedType()
{
diff --git a/test/AsmResolver.PE.File.Tests/AsmResolver.PE.File.Tests.csproj b/test/AsmResolver.PE.File.Tests/AsmResolver.PE.File.Tests.csproj
index 6b532fdfc..44c298a73 100644
--- a/test/AsmResolver.PE.File.Tests/AsmResolver.PE.File.Tests.csproj
+++ b/test/AsmResolver.PE.File.Tests/AsmResolver.PE.File.Tests.csproj
@@ -9,7 +9,7 @@
-
+
all
diff --git a/test/AsmResolver.PE.Tests/AsmResolver.PE.Tests.csproj b/test/AsmResolver.PE.Tests/AsmResolver.PE.Tests.csproj
index 3e76c6ef0..2c4967fcf 100644
--- a/test/AsmResolver.PE.Tests/AsmResolver.PE.Tests.csproj
+++ b/test/AsmResolver.PE.Tests/AsmResolver.PE.Tests.csproj
@@ -16,9 +16,9 @@
-
+
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/test/AsmResolver.PE.Win32Resources.Tests/AsmResolver.PE.Win32Resources.Tests.csproj b/test/AsmResolver.PE.Win32Resources.Tests/AsmResolver.PE.Win32Resources.Tests.csproj
index cec83bfea..66003d51f 100644
--- a/test/AsmResolver.PE.Win32Resources.Tests/AsmResolver.PE.Win32Resources.Tests.csproj
+++ b/test/AsmResolver.PE.Win32Resources.Tests/AsmResolver.PE.Win32Resources.Tests.csproj
@@ -8,13 +8,13 @@
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/test/AsmResolver.Symbols.Pdb.Tests/AsmResolver.Symbols.Pdb.Tests.csproj b/test/AsmResolver.Symbols.Pdb.Tests/AsmResolver.Symbols.Pdb.Tests.csproj
index 582e228ed..495bbf831 100644
--- a/test/AsmResolver.Symbols.Pdb.Tests/AsmResolver.Symbols.Pdb.Tests.csproj
+++ b/test/AsmResolver.Symbols.Pdb.Tests/AsmResolver.Symbols.Pdb.Tests.csproj
@@ -8,13 +8,13 @@
-
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
diff --git a/test/AsmResolver.Symbols.Pdb.Tests/Records/ProcedureReferenceSymbolTest.cs b/test/AsmResolver.Symbols.Pdb.Tests/Records/ProcedureReferenceSymbolTest.cs
new file mode 100644
index 000000000..ae534649b
--- /dev/null
+++ b/test/AsmResolver.Symbols.Pdb.Tests/Records/ProcedureReferenceSymbolTest.cs
@@ -0,0 +1,27 @@
+using System.Linq;
+using AsmResolver.Symbols.Pdb.Records;
+using Xunit;
+
+namespace AsmResolver.Symbols.Pdb.Tests.Records;
+
+public class ProcedureReferenceSymbolTest : IClassFixture
+{
+ private readonly MockPdbFixture _fixture;
+
+ public ProcedureReferenceSymbolTest(MockPdbFixture fixture)
+ {
+ _fixture = fixture;
+ }
+
+ [Fact]
+ public void Name()
+ {
+ Assert.Equal("DllMain", _fixture.SimplePdb.Symbols.OfType().First(s => !s.IsLocal).Name);
+ }
+
+ [Fact]
+ public void LocalName()
+ {
+ Assert.Equal("__get_entropy", _fixture.SimplePdb.Symbols.OfType().First(s => s.IsLocal).Name);
+ }
+}
diff --git a/test/AsmResolver.Tests/AsmResolver.Tests.csproj b/test/AsmResolver.Tests/AsmResolver.Tests.csproj
index 6d9327ffb..2bac4b411 100644
--- a/test/AsmResolver.Tests/AsmResolver.Tests.csproj
+++ b/test/AsmResolver.Tests/AsmResolver.Tests.csproj
@@ -8,7 +8,7 @@
-
+
all