16 Commits
Author SHA1 Message Date
ds5678 2d68e67393 Bump version to 1.2.1
Updated the version number in the project properties from 1.2.0 to 1.2.1.
2025-09-15 15:47:05 -07:00
ds5678 d8230781d9 AddThrowNull 2025-09-15 14:43:00 -07:00
ds5678 2990c647c5 Add extensions from AssemblyDumper 2025-09-15 14:41:33 -07:00
ds5678 e871881517 Update project version to 1.2.0
Bump the version number in the project properties from 1.1.6 to 1.2.0.
2025-09-08 14:30:19 -07:00
ds5678 c1eceeda51 AsmResolver 6 beta 4
Resolves #2
2025-09-08 14:25:12 -07:00
ds5678 44996e27ff Update NuGet packages in project files
Updated several NuGet packages in `AssetRipper.CIL.Tests.csproj`:
- Microsoft.NET.Test.Sdk: 17.13.0 -> 17.14.1
- NUnit: 4.3.2 -> 4.4.0
- NUnit.Analyzers: 4.6.0 -> 4.10.0
- NUnit3TestAdapter: 5.0.0 -> 5.1.0

Also updated `System.Runtime.CompilerServices.Unsafe` in `AssetRipper.CIL.csproj` from version 6.1.1 to 6.1.2.
2025-09-08 14:20:20 -07:00
ds5678 0039dc95b3 Use IsAccessibleFromType when searching for a base constructor
* Related: #2
2025-04-08 15:06:57 -07:00
ds5678 0953640bf1 Add ReplaceMethodBodyWithThrowNull method
Introduces a new method `ReplaceMethodBodyWithThrowNull` in the `MethodDefinitionExtensions` class. This method modifies the body of a managed method to throw a `null` exception, with appropriate XML documentation. It includes checks to ensure the method is managed and has a body before making changes.
2025-03-23 20:20:02 -07:00
ds5678 c1e8657d67 Ensure references are imported 2025-03-21 19:23:54 -07:00
ds5678 09db4f64ae Bump version to 1.1.6 2025-03-20 23:03:22 -07:00
ds5678 0af62d2590 Support generating enums 2025-03-20 23:01:02 -07:00
ds5678 cc71118bfb Update package versions in project files
- Bump `coverlet.collector` to version `6.0.4`
- Bump `Microsoft.NET.Test.Sdk` to version `17.13.0`
- Bump `NUnit3TestAdapter` to version `5.0.0`
- Bump `AsmResolver.DotNet` to version `6.0.0-beta.3`
2025-03-20 22:01:39 -07:00
ds5678 21d8f70781 Add more extensions 2025-03-20 22:00:07 -07:00
ds5678 75a48b3ce0 Do not attempt to initialize fixed buffers 2025-03-20 21:11:29 -07:00
ds5678 c164acde5f Bump version 2025-01-23 14:28:47 -08:00
ds5678 8935137a6f Expand type check to include PointerTypeSignature
Modified conditions in CilInstructionCollectionExtensions.cs to check for both ByReferenceTypeSignature and PointerTypeSignature. This ensures null references are added and stored for both types.
2025-01-23 14:27:38 -08:00
16 changed files with 530 additions and 35 deletions

No files matched your search

@@ -9,17 +9,17 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.3">
<PackageReference Include="coverlet.collector" Version="6.0.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="NUnit" Version="4.3.2" />
<PackageReference Include="NUnit.Analyzers" Version="4.6.0">
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
<PackageReference Include="NUnit" Version="4.4.0" />
<PackageReference Include="NUnit.Analyzers" Version="4.10.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />
<PackageReference Include="NUnit3TestAdapter" Version="5.1.0" />
</ItemGroup>
<ItemGroup>
+1 -1
View File
@@ -94,7 +94,7 @@ public class LoadIndirectTests
private static void AssertCorrectLoadIndirect(TypeSignature typeToLoad, CilCode expectedOpCode)
{
MethodDefinition method = new MethodDefinition("Test", MethodAttributes.Public | MethodAttributes.Static, null);
method.CilMethodBody = new(method);
method.CilMethodBody = new();
CilInstructionCollection instructions = method.CilMethodBody.Instructions;
instructions.AddLoadIndirect(typeToLoad);
Assert.That(instructions, Has.Count.EqualTo(1));
+1 -1
View File
@@ -94,7 +94,7 @@ public class StoreIndirectTests
private static void AssertCorrectStoreIndirect(TypeSignature typeToStore, CilCode expectedOpCode)
{
MethodDefinition method = new MethodDefinition("Test", MethodAttributes.Public | MethodAttributes.Static, null);
method.CilMethodBody = new(method);
method.CilMethodBody = new();
CilInstructionCollection instructions = method.CilMethodBody.Instructions;
instructions.AddStoreIndirect(typeToStore);
Assert.That(instructions, Has.Count.EqualTo(1));
+2 -1
View File
@@ -15,8 +15,9 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AsmResolver.DotNet" Version="6.0.0-beta.1" />
<PackageReference Include="AsmResolver.DotNet" Version="6.0.0-beta.4" />
<PackageReference Include="PolySharp" Version="1.15.0" PrivateAssets="all" IncludeAssets="runtime; build; native; contentfiles; analyzers; buildtransitive" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.1.2" />
</ItemGroup>
<ItemGroup>
@@ -22,7 +22,7 @@ public static class CilInstructionCollectionExtensions
{
instructions.AddDefaultPrimitiveValue(corLibTypeSignature);
}
else if (type is ByReferenceTypeSignature)
else if (type is ByReferenceTypeSignature or PointerTypeSignature)
{
instructions.AddNullRef();
}
@@ -43,7 +43,7 @@ public static class CilInstructionCollectionExtensions
{
instructions.InitializeDefaultPrimitiveValue(corLibTypeSignature, localVariable);
}
else if (type is ByReferenceTypeSignature)
else if (type is ByReferenceTypeSignature or PointerTypeSignature)
{
instructions.AddNullRef();
instructions.Add(CilOpCodes.Stloc, localVariable);
@@ -71,6 +71,12 @@ public static class CilInstructionCollectionExtensions
instructions.Add(CilOpCodes.Ceq);
}
public static void AddThrowNull(this CilInstructionCollection instructions)
{
instructions.Add(CilOpCodes.Ldnull);
instructions.Add(CilOpCodes.Throw);
}
public static CilInstruction AddLoadElement(this CilInstructionCollection instructions, TypeSignature elementType)
{
return elementType switch
@@ -0,0 +1,83 @@
using AsmResolver.DotNet.Signatures;
namespace AssetRipper.CIL;
internal static class CorLibTypeFactoryExtensions
{
public static CorLibTypeSignature? FromType(this CorLibTypeFactory factory, Type type)
{
if (type == typeof(bool))
{
return factory.Boolean;
}
if (type == typeof(char))
{
return factory.Char;
}
if (type == typeof(byte))
{
return factory.Byte;
}
if (type == typeof(sbyte))
{
return factory.SByte;
}
if (type == typeof(short))
{
return factory.Int16;
}
if (type == typeof(ushort))
{
return factory.UInt16;
}
if (type == typeof(int))
{
return factory.Int32;
}
if (type == typeof(uint))
{
return factory.UInt32;
}
if (type == typeof(long))
{
return factory.Int64;
}
if (type == typeof(ulong))
{
return factory.UInt64;
}
if (type == typeof(float))
{
return factory.Single;
}
if (type == typeof(double))
{
return factory.Double;
}
if (type == typeof(string))
{
return factory.String;
}
if (type == typeof(IntPtr))
{
return factory.IntPtr;
}
if (type == typeof(UIntPtr))
{
return factory.UIntPtr;
}
if (type == typeof(object))
{
return factory.Object;
}
if (type == typeof(void))
{
return factory.Void;
}
if (type == typeof(TypedReference))
{
return factory.TypedReference;
}
return null;
}
}
@@ -0,0 +1,30 @@
using AsmResolver.DotNet;
using AsmResolver.DotNet.Signatures;
namespace AssetRipper.CIL;
public static class CustomAttributeExtensions
{
public static CustomAttributeArgument AddFixedArgument(this CustomAttribute attribute, TypeSignature paramType, object paramValue)
{
attribute.Signature ??= new();
CustomAttributeArgument argument = new(paramType, paramValue);
attribute.Signature.FixedArguments.Add(argument);
return argument;
}
public static CustomAttributeArgument AddFixedArgument<T>(this CustomAttribute attribute, TypeSignature paramType, T[] paramValue)
{
CustomAttributeArgument argument = new CustomAttributeArgument(paramType, paramValue.Select(e => (object?)e));
attribute.Signature!.FixedArguments.Add(argument);
return argument;
}
public static CustomAttributeNamedArgument AddNamedArgument(this CustomAttribute attribute, TypeSignature memberType, string memberName, TypeSignature paramType, object paramValue, CustomAttributeArgumentMemberType memberKind)
{
CustomAttributeArgument argument = new CustomAttributeArgument(paramType, paramValue);
CustomAttributeNamedArgument namedArgument = new CustomAttributeNamedArgument(memberKind, memberName, memberType, argument);
attribute.Signature!.NamedArguments.Add(namedArgument);
return namedArgument;
}
}
@@ -57,4 +57,9 @@ public static class FieldDefinitionExtensions
return false;
}
}
public static bool IsFixedBuffer(this FieldDefinition field)
{
return field.HasCustomAttribute("System.Runtime.CompilerServices", "FixedBufferAttribute");
}
}
@@ -0,0 +1,104 @@
using AsmResolver.DotNet;
using AsmResolver.DotNet.Signatures;
using System.Runtime.CompilerServices;
namespace AssetRipper.CIL;
public static class IHasCustomAttributeExtensions
{
public static CustomAttribute AddCustomAttribute(this IHasCustomAttribute _this, IMethodDefOrRef constructor)
{
if (constructor is ICustomAttributeType usableConstructor)
{
CustomAttribute attribute = new(usableConstructor);
_this.CustomAttributes.Add(attribute);
return attribute;
}
else
{
throw new ArgumentException("Constructor is not ICustomAttributeType", nameof(constructor));
}
}
public static CustomAttribute AddCustomAttribute(this IHasCustomAttribute _this, IMethodDefOrRef constructor, TypeSignature paramType, object paramValue)
{
CustomAttribute attribute = _this.AddCustomAttribute(constructor);
attribute.AddFixedArgument(paramType, paramValue);
return attribute;
}
public static CustomAttribute AddCustomAttribute<T>(this IHasCustomAttribute _this, IMethodDefOrRef constructor, SzArrayTypeSignature paramType, T[] paramValue)
{
CustomAttribute attribute = _this.AddCustomAttribute(constructor);
attribute.AddFixedArgument(paramType, paramValue);
return attribute;
}
public static CustomAttribute AddCustomAttribute(this IHasCustomAttribute _this, IMethodDefOrRef constructor, params (TypeSignature, object)[] parameters)
{
CustomAttribute attribute = _this.AddCustomAttribute(constructor);
for (int i = 0; i < parameters.Length; i++)
{
attribute.AddFixedArgument(parameters[i].Item1, parameters[i].Item2);
}
return attribute;
}
internal static ModuleDefinition GetModule(this IHasCustomAttribute _this)
{
return (_this as IModuleProvider)?.ContextModule ?? throw new ArgumentException("Entity does not have a module", nameof(_this));
}
public static CustomAttribute AddFlagsAttribute(this IHasCustomAttribute _this)
{
ModuleDefinition module = _this.GetModule();
if (module.TryGetTopLevelType("System", nameof(FlagsAttribute), out TypeDefinition? flagsType))
{
return _this.AddCustomAttribute(flagsType.GetDefaultConstructor());
}
else
{
TypeReference flagsTypeRef = new(module.CorLibTypeFactory.CorLibScope, "System", nameof(FlagsAttribute));
MemberReference constructor = new(flagsTypeRef, ".ctor", MethodSignature.CreateInstance(module.CorLibTypeFactory.Void));
return _this.AddCustomAttribute(module.DefaultImporter.ImportMethod(constructor));
}
}
/// <summary>
/// Applies the <see cref="CompilerGeneratedAttribute"/>
/// </summary>
/// <param name="_this">The entity on which to apply the attribute</param>
/// <returns>The resulting custom attribute</returns>
public static CustomAttribute AddCompilerGeneratedAttribute(this IHasCustomAttribute _this)
{
ModuleDefinition module = _this.GetModule();
if (module.TryGetTopLevelType("System.Runtime.CompilerServices", nameof(CompilerGeneratedAttribute), out TypeDefinition? compilerGeneratedType))
{
return _this.AddCustomAttribute(compilerGeneratedType.GetDefaultConstructor());
}
else
{
AssemblyReference compilerServicesAssembly = GetOrAddReferenceToSystemRuntimeCompilerServices(module);
TypeReference compilerGeneratedTypeRef = new(compilerServicesAssembly, "System.Runtime.CompilerServices", nameof(CompilerGeneratedAttribute));
MemberReference constructor = new(compilerGeneratedTypeRef, ".ctor", MethodSignature.CreateInstance(module.CorLibTypeFactory.Void));
return _this.AddCustomAttribute(module.DefaultImporter.ImportMethod(constructor));
}
static AssemblyReference GetOrAddReferenceToSystemRuntimeCompilerServices(ModuleDefinition module)
{
AssemblyReference? compilerServicesAssembly = module.AssemblyReferences.FirstOrDefault(a => a.Name == "System.Runtime.CompilerServices");
if (compilerServicesAssembly is null)
{
Version version = module.CorLibTypeFactory.CorLibScope.GetAssembly()?.Version ?? new Version(0, 0, 0, 0);
compilerServicesAssembly = new("System.Runtime.CompilerServices", version);
module.AssemblyReferences.Add(compilerServicesAssembly);
}
return compilerServicesAssembly;
}
}
}
@@ -11,7 +11,7 @@ public sealed class SwitchRemover : ICilManipulator
{
public void Execute(CilManipulationContext context)
{
ModuleDefinition? module = context.Instructions.Owner.Owner.Module;
ModuleDefinition? module = context.Instructions.Owner.Owner?.DeclaringModule;
if (module is null)
{
return;
+27 -2
View File
@@ -1,6 +1,8 @@
using AsmResolver.DotNet;
using AsmResolver.DotNet.Code.Cil;
using AsmResolver.DotNet.Collections;
using AsmResolver.DotNet.Signatures;
using AsmResolver.PE.DotNet.Cil;
using AsmResolver.PE.DotNet.Metadata.Tables;
using System.Diagnostics.CodeAnalysis;
@@ -23,6 +25,24 @@ public static class MethodDefinitionExtensions
MethodStubber.FillMethodBodyWithStub(methodDefinition);
}
/// <summary>
/// Replaces the method body with: <code>throw null;</code>
/// </summary>
/// <remarks>
/// If the method is not managed or should not have a body, this method does nothing.
/// </remarks>
/// <param name="methodDefinition">The method to modify.</param>
public static void ReplaceMethodBodyWithThrowNull(this MethodDefinition methodDefinition)
{
if (!methodDefinition.IsManagedMethodWithBody())
{
return;
}
methodDefinition.CilMethodBody = new();
CilInstructionCollection methodInstructions = methodDefinition.CilMethodBody.Instructions;
methodInstructions.AddThrowNull();
}
public static bool IsInstance(this MethodDefinition methodDefinition)
{
return !methodDefinition.IsStatic;
@@ -72,6 +92,11 @@ public static class MethodDefinitionExtensions
&& !managedMethod.IsRuntime;
}
public static CilInstructionCollection GetInstructions(this MethodDefinition method)
{
return method.CilMethodBody?.Instructions ?? throw new ArgumentException("CilMethodBody was null", nameof(method));
}
public static bool IsAutoPropertyGetMethod(this MethodDefinition method, [NotNullWhen(true)] out FieldDefinition? backingField)
{
if (!method.IsGetMethod
@@ -131,12 +156,12 @@ public static class MethodDefinitionExtensions
}
}
public static Parameter AddParameter(this MethodDefinition method, TypeSignature parameterSignature, string parameterName)
public static Parameter AddParameter(this MethodDefinition method, TypeSignature parameterSignature, string? parameterName)
{
return method.AddParameter(parameterSignature, parameterName, out _);
}
public static Parameter AddParameter(this MethodDefinition method, TypeSignature parameterSignature, string parameterName, out ParameterDefinition parameterDefinition)
public static Parameter AddParameter(this MethodDefinition method, TypeSignature parameterSignature, string? parameterName, out ParameterDefinition parameterDefinition)
{
parameterDefinition = new ParameterDefinition((ushort)(method.Signature!.ParameterTypes.Count + 1), parameterName, default);
method.Signature.ParameterTypes.Add(parameterSignature);
+8 -15
View File
@@ -16,7 +16,7 @@ internal static class MethodStubber
return;
}
methodDefinition.CilMethodBody = new(methodDefinition);
methodDefinition.CilMethodBody = new();
CilInstructionCollection methodInstructions = methodDefinition.CilMethodBody.Instructions;
if (methodDefinition.IsAutoPropertyGetMethod(out FieldDefinition? backingField))
@@ -55,7 +55,7 @@ internal static class MethodStubber
TypeDefinition declaringType = methodDefinition.DeclaringType!;
foreach (FieldDefinition field in declaringType.Fields)
{
if (field.IsStatic || field.Signature is null)
if (field.IsStatic || field.Signature is null || field.IsFixedBuffer())
{
continue;
}
@@ -131,13 +131,13 @@ internal static class MethodStubber
return null;
}
MethodDefinition? baseConstructor = GetFirstCompatibleConstructor(methodDefinition.DeclaringType, baseTypeResolved);
if (baseConstructor is null || methodDefinition.DeclaringType.Module is null)
if (baseConstructor is null || methodDefinition.DeclaringType.DeclaringModule is null)
{
return null;
}
else
{
return methodDefinition.DeclaringType.Module.DefaultImporter.ImportMethod(baseConstructor);
return methodDefinition.DeclaringType.DeclaringModule.DefaultImporter.ImportMethod(baseConstructor);
}
}
else if (baseType is TypeSpecification baseTypeSpec)
@@ -153,11 +153,11 @@ internal static class MethodStubber
return null;
}
MethodDefinition? baseConstructor = GetFirstCompatibleConstructor(methodDefinition.DeclaringType, baseTypeResolved);
if (baseConstructor is null || methodDefinition.DeclaringType.Module is null)
if (baseConstructor is null || methodDefinition.DeclaringType.DeclaringModule is null)
{
return null;
}
IMethodDefOrRef baseConstructorImported = methodDefinition.DeclaringType.Module.DefaultImporter.ImportMethod(baseConstructor);
IMethodDefOrRef baseConstructorImported = methodDefinition.DeclaringType.DeclaringModule.DefaultImporter.ImportMethod(baseConstructor);
return new MemberReference(baseType, baseConstructorImported.Name, baseConstructorImported.Signature);
}
@@ -165,14 +165,7 @@ internal static class MethodStubber
static MethodDefinition? GetFirstCompatibleConstructor(TypeDefinition declaringType, TypeDefinition baseType)
{
if (declaringType.Module == baseType.Module)
{
return baseType.Methods.FirstOrDefault(m => m.IsInstanceConstructor() && !m.IsPrivate);
}
else
{
return baseType.Methods.FirstOrDefault(m => m.IsInstanceConstructor() && (m.IsFamily || m.IsPublic));
}
return baseType.Methods.FirstOrDefault(m => m.IsInstanceConstructor() && m.IsAccessibleFromType(declaringType));
}
}
@@ -190,7 +183,7 @@ internal static class MethodStubber
}
TypeSignature[] typeArguments = Enumerable.Range(0, field.DeclaringType.GenericParameters.Count)
.Select(i => new GenericParameterSignature(field.Module, GenericParameterType.Type, i))
.Select(i => new GenericParameterSignature(field.DeclaringModule, GenericParameterType.Type, i))
.ToArray();
return new MemberReference(field.DeclaringType.MakeGenericInstanceType(typeArguments).ToTypeDefOrRef(), field.Name, field.Signature);
@@ -0,0 +1,94 @@
using AsmResolver.DotNet;
using AsmResolver.DotNet.Signatures;
using AsmResolver.PE.DotNet.Metadata.Tables;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
namespace AssetRipper.CIL;
public static class ModuleDefinitionExtensions
{
public static bool TryGetTopLevelType(this ModuleDefinition module, string? @namespace, string? name, [NotNullWhen(true)] out TypeDefinition? type)
{
type = module.TopLevelTypes.FirstOrDefault(t => t.Namespace == @namespace && t.Name == name);
return type != null;
}
public static bool HasTopLevelType(this ModuleDefinition module, string? @namespace, string? name)
{
return module.TryGetTopLevelType(@namespace, name, out _);
}
public static TypeDefinition AddEmptyEnum(this ModuleDefinition module, string? @namespace, string? name, Visibility visibility, ElementType underlyingType)
{
CorLibTypeSignature underlyingTypeSignature = module.CorLibTypeFactory.FromElementType(underlyingType)
?? throw new ArgumentOutOfRangeException(nameof(underlyingType), underlyingType, null);
TypeReference baseType = new(module.CorLibTypeFactory.CorLibScope, "System", "Enum");
TypeDefinition type = new(@namespace, name, visibility.ToTypeAttributes() | TypeAttributes.Sealed, module.DefaultImporter.ImportType(baseType));
module.TopLevelTypes.Add(type);
AddEnumValue(type, underlyingTypeSignature);
return type;
static void AddEnumValue(TypeDefinition type, TypeSignature underlyingType)
{
FieldSignature fieldSignature = new FieldSignature(underlyingType);
FieldDefinition fieldDef = new FieldDefinition("value__", FieldAttributes.Public | FieldAttributes.SpecialName | FieldAttributes.RuntimeSpecialName, fieldSignature);
type.Fields.Add(fieldDef);
}
}
public static TypeDefinition AddExistingEnum<T>(this ModuleDefinition module) where T : struct, Enum
{
Type underlyingType = Enum.GetUnderlyingType(typeof(T));
bool isSigned = underlyingType == typeof(sbyte) || underlyingType == typeof(short) || underlyingType == typeof(int) || underlyingType == typeof(long);
CorLibTypeSignature underlyingTypeSignature = module.CorLibTypeFactory.FromType(underlyingType)
?? throw new InvalidOperationException($"Failed to get underlying type for {typeof(T)}");
TypeDefinition type = module.AddEmptyEnum(typeof(T).Namespace, typeof(T).Name, VisibilityExtensions.GetVisibility(typeof(T)), underlyingTypeSignature.ElementType);
foreach (T value in GetValues())
{
type.AddEnumField(value.ToString(), ToInt64(value));
}
if (typeof(T).CustomAttributes.Any(a => a.AttributeType is { Namespace: "System", Name: nameof(FlagsAttribute) }))
{
type.AddFlagsAttribute();
}
return type;
static IEnumerable<T> GetValues()
{
#if NETSTANDARD
return Enum.GetValues(typeof(T)).Cast<T>();
#else
return Enum.GetValues<T>();
#endif
}
long ToInt64(T value)
{
if (Unsafe.SizeOf<T>() == sizeof(long))
{
return Unsafe.As<T, long>(ref value);
}
else if (Unsafe.SizeOf<T>() == sizeof(int))
{
return isSigned ? Unsafe.As<T, int>(ref value) : Unsafe.As<T, uint>(ref value);
}
else if (Unsafe.SizeOf<T>() == sizeof(short))
{
return isSigned ? Unsafe.As<T, short>(ref value) : Unsafe.As<T, ushort>(ref value);
}
else if (Unsafe.SizeOf<T>() == sizeof(byte))
{
return isSigned ? Unsafe.As<T, sbyte>(ref value) : Unsafe.As<T, byte>(ref value);
}
else
{
throw new NotSupportedException($"Unsupported enum underlying type {typeof(T)}");
}
}
}
}
+75 -4
View File
@@ -7,14 +7,67 @@ namespace AssetRipper.CIL;
public static class TypeDefinitionExtensions
{
public static MethodDefinition AddMethod(this TypeDefinition type, string methodName, MethodAttributes methodAttributes, TypeSignature returnType)
public static FieldDefinition AddField(this TypeDefinition type, string? fieldName, TypeSignature fieldType, bool isStatic = false, Visibility visibility = Visibility.Public)
{
FieldAttributes fieldAttributes = visibility.ToFieldAttributes() | (isStatic ? FieldAttributes.Static : default);
FieldDefinition field = new FieldDefinition(fieldName, fieldAttributes, fieldType);
type.Fields.Add(field);
return field;
}
public static FieldDefinition AddConstantField(
this TypeDefinition type,
TypeSignature fieldType,
string fieldName,
Constant constant,
Visibility visibility = Visibility.Public)
{
FieldDefinition field = new FieldDefinition(
fieldName,
FieldAttributes.Static |
FieldAttributes.Literal |
FieldAttributes.HasDefault |
visibility.ToFieldAttributes(),
new FieldSignature(fieldType));
field.Constant = constant;
type.Fields.Add(field);
return field;
}
public static MethodDefinition AddMethod(this TypeDefinition type, string? methodName, MethodAttributes methodAttributes, TypeSignature returnType)
{
MethodDefinition method = CreateMethod(methodName, methodAttributes, returnType);
type.Methods.Add(method);
return method;
}
private static MethodDefinition CreateMethod(string methodName, MethodAttributes methodAttributes, TypeSignature returnType)
public static MethodDefinition AddConstructor(this TypeDefinition type, Visibility visibility = Visibility.Public)
{
MethodAttributes methodAttributes = visibility.ToMethodAttributes() | MethodAttributes.SpecialName | MethodAttributes.RuntimeSpecialName;
return type.AddMethod(".ctor", methodAttributes, type.DeclaringModule!.CorLibTypeFactory.Void);
}
public static FieldDefinition AddEnumField(this TypeDefinition type, string name, long value)
{
TypeSignature underlyingType = type.GetEnumUnderlyingType() ?? throw new ArgumentException("Type is not an enum", nameof(type));
return type.AddConstantField(type.ToTypeSignature(), name, FromValue(value, underlyingType.ElementType));
static Constant FromValue(long value, ElementType elementType) => elementType switch
{
ElementType.I1 => Constant.FromValue((sbyte)value),
ElementType.U1 => Constant.FromValue((byte)value),
ElementType.I2 => Constant.FromValue((short)value),
ElementType.U2 => Constant.FromValue((ushort)value),
ElementType.I4 => Constant.FromValue((int)value),
ElementType.U4 => Constant.FromValue((uint)value),
ElementType.I8 => Constant.FromValue(value),
ElementType.U8 => Constant.FromValue(unchecked((ulong)value)),
_ => throw new ArgumentOutOfRangeException(nameof(elementType)),
};
}
private static MethodDefinition CreateMethod(string? methodName, MethodAttributes methodAttributes, TypeSignature returnType)
{
bool isStatic = (methodAttributes & MethodAttributes.Static) != 0;
MethodSignature methodSignature = isStatic
@@ -22,12 +75,30 @@ public static class TypeDefinitionExtensions
: MethodSignature.CreateInstance(returnType);
MethodDefinition result = new MethodDefinition(methodName, methodAttributes, methodSignature);
result.CilMethodBody = new CilMethodBody(result);
result.CilMethodBody = new CilMethodBody();
return result;
}
public static bool IsStaticClass(this TypeDefinition type)
/// <summary>
/// Gets the default constructor for a <see cref="TypeDefinition"/>. Throws an exception if one doesn't exist.
/// </summary>
public static MethodDefinition GetDefaultConstructor(this TypeDefinition type)
{
return type.Methods.First(m => m.IsInstanceConstructor() && m.Parameters.Count == 0);
}
/// <summary>
/// Get all the instance constructors for a type
/// </summary>
/// <param name="type">The definition for the type</param>
/// <returns>All the instance constructors</returns>
public static IEnumerable<MethodDefinition> GetInstanceConstructors(this TypeDefinition type)
{
return type.Methods.Where(m => !m.IsStatic && m.IsConstructor);
}
public static bool IsStatic(this TypeDefinition type)
{
return type.IsSealed && type.IsAbstract;
}
+84
View File
@@ -0,0 +1,84 @@
using AsmResolver.PE.DotNet.Metadata.Tables;
namespace AssetRipper.CIL;
public enum Visibility
{
Public,
Protected,
Internal,
ProtectedInternal,
Private,
PrivateProtected
}
public static class VisibilityExtensions
{
public static MethodAttributes ToMethodAttributes(this Visibility visibility) => visibility switch
{
Visibility.Public => MethodAttributes.Public,
Visibility.Protected => MethodAttributes.Family,
Visibility.Internal => MethodAttributes.Assembly,
Visibility.ProtectedInternal => MethodAttributes.FamilyOrAssembly,
Visibility.Private => MethodAttributes.Private,
Visibility.PrivateProtected => MethodAttributes.FamilyAndAssembly,
_ => throw new ArgumentOutOfRangeException(nameof(visibility), visibility, null),
};
public static FieldAttributes ToFieldAttributes(this Visibility visibility) => visibility switch
{
Visibility.Public => FieldAttributes.Public,
Visibility.Protected => FieldAttributes.Family,
Visibility.Internal => FieldAttributes.Assembly,
Visibility.ProtectedInternal => FieldAttributes.FamilyOrAssembly,
Visibility.Private => FieldAttributes.Private,
Visibility.PrivateProtected => FieldAttributes.FamilyAndAssembly,
_ => throw new ArgumentOutOfRangeException(nameof(visibility), visibility, null),
};
public static TypeAttributes ToTypeAttributes(this Visibility visibility, bool nested = false) => nested
? visibility switch
{
Visibility.Public => TypeAttributes.NestedPublic,
Visibility.Protected => TypeAttributes.NestedFamily,
Visibility.Internal => TypeAttributes.NestedAssembly,
Visibility.ProtectedInternal => TypeAttributes.NestedFamilyOrAssembly,
Visibility.Private => TypeAttributes.NestedPrivate,
Visibility.PrivateProtected => TypeAttributes.NestedFamilyAndAssembly,
_ => throw new ArgumentOutOfRangeException(nameof(visibility), visibility, null),
}
: visibility switch
{
Visibility.Public => TypeAttributes.Public,
Visibility.Internal => TypeAttributes.NotPublic,
_ => throw new ArgumentOutOfRangeException(nameof(visibility), visibility, null),
};
internal static Visibility GetVisibility(Type type)
{
if (type.IsPublic || type.IsNestedPublic)
{
return Visibility.Public;
}
if (type.IsNestedFamily)
{
return Visibility.Protected;
}
if (type.IsNotPublic || type.IsNestedAssembly)
{
return Visibility.Internal;
}
if (type.IsNestedFamORAssem)
{
return Visibility.ProtectedInternal;
}
if (type.IsNestedPrivate)
{
return Visibility.Private;
}
if (type.IsNestedFamANDAssem)
{
return Visibility.PrivateProtected;
}
throw new ArgumentException($"Unknown visibility for type {type}", nameof(type));
}
}
+2 -3
View File
@@ -2,13 +2,12 @@
<PropertyGroup>
<LangVersion>Latest</LangVersion>
<Nullable>enable</Nullable>
<IsAotCompatible>true</IsAotCompatible>
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
<PolySharpIncludeRuntimeSupportedAttributes>true</PolySharpIncludeRuntimeSupportedAttributes>
<Version>1.1.4</Version>
<Version>1.2.1</Version>
<AssemblyVersion>$(Version)</AssemblyVersion>
<Copyright>Copyright (c) 2024 ds5678</Copyright>
<Copyright>Copyright (c) 2025 ds5678</Copyright>
<Authors>ds5678</Authors>
<Company>AssetRipper</Company>
<PackageLicenseExpression>MIT</PackageLicenseExpression>