Add name mangling to Methods/MethodInfo/TypeInfo/TypeRef, remove Boxing from ValueTypes when used as the this parameter, fix crashes when a module has no attributes
This commit is contained in:
@@ -487,7 +487,7 @@ namespace Il2CppInspector.Cpp
|
||||
} else {
|
||||
if (declaringType.IsValueType) {
|
||||
// Methods for structs take the boxed object as the this param
|
||||
paramList.Add(("this", types.GetType(TypeNamer.GetName(declaringType) + "__Boxed *")));
|
||||
paramList.Add(("this", types.GetType(TypeNamer.GetName(declaringType) + " *"))); // + "__Boxed *")));
|
||||
} else {
|
||||
paramList.Add(("this", AsCType(declaringType)));
|
||||
}
|
||||
|
||||
204
Il2CppInspector.Common/Cpp/MangledNameBuilder.cs
Normal file
204
Il2CppInspector.Common/Cpp/MangledNameBuilder.cs
Normal file
@@ -0,0 +1,204 @@
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using Il2CppInspector.Reflection;
|
||||
|
||||
namespace Il2CppInspector.Cpp;
|
||||
|
||||
// This follows Itanium/GCC mangling specifications.
|
||||
public class MangledNameBuilder
|
||||
{
|
||||
private readonly StringBuilder _sb = new("_Z");
|
||||
|
||||
public override string ToString()
|
||||
=> _sb.ToString();
|
||||
|
||||
public static string Method(MethodBase method)
|
||||
{
|
||||
var builder = new MangledNameBuilder();
|
||||
builder.BuildMethod(method);
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
public static string MethodInfo(MethodBase method)
|
||||
{
|
||||
var builder = new MangledNameBuilder();
|
||||
builder.BuildMethod(method, "MethodInfo");
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
public static string TypeInfo(TypeInfo type)
|
||||
{
|
||||
var builder = new MangledNameBuilder();
|
||||
builder.BeginName();
|
||||
builder.WriteIdentifier("TypeInfo");
|
||||
builder.WriteTypeName(type);
|
||||
builder.WriteEnd();
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
public static string TypeRef(TypeInfo type)
|
||||
{
|
||||
var builder = new MangledNameBuilder();
|
||||
builder.BeginName();
|
||||
builder.WriteIdentifier("TypeRef");
|
||||
builder.WriteTypeName(type);
|
||||
builder.WriteEnd();
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
private void BuildMethod(MethodBase method, string prefix = "")
|
||||
{
|
||||
/*
|
||||
* We do not have any CV-qualifiers nor ref-qualifiers,
|
||||
* so we immediately write the nested name.
|
||||
*/
|
||||
|
||||
BeginName();
|
||||
|
||||
if (prefix.Length > 0)
|
||||
WriteIdentifier(prefix);
|
||||
|
||||
WriteTypeName(method.DeclaringType);
|
||||
|
||||
switch (method.Name)
|
||||
{
|
||||
case ".ctor":
|
||||
_sb.Append("C1"); // Constructor
|
||||
break;
|
||||
case ".cctor":
|
||||
WriteIdentifier("cctor");
|
||||
break;
|
||||
default:
|
||||
WriteIdentifier(method.Name);
|
||||
break;
|
||||
}
|
||||
|
||||
var genericParams = method.GetGenericArguments();
|
||||
|
||||
WriteGenericParams(genericParams);
|
||||
|
||||
WriteEnd(); // End nested name
|
||||
|
||||
// Now write the method parameters
|
||||
|
||||
if (genericParams.Length > 0 && method is MethodInfo mInfo)
|
||||
{
|
||||
// If this is a generic method, the first parameter needs to be the return type
|
||||
WriteType(mInfo.ReturnType);
|
||||
}
|
||||
|
||||
if (method.DeclaredParameters.Count == 0)
|
||||
_sb.Append('v');
|
||||
else
|
||||
{
|
||||
foreach (var param in method.DeclaredParameters)
|
||||
WriteType(param.ParameterType);
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteTypeName(TypeInfo type)
|
||||
{
|
||||
if (type.HasElementType)
|
||||
type = type.ElementType;
|
||||
|
||||
WriteName(type.Namespace);
|
||||
|
||||
if (type.DeclaringType != null)
|
||||
WriteIdentifier(type.DeclaringType.Name);
|
||||
|
||||
WriteIdentifier(type.CSharpBaseName);
|
||||
WriteGenericParams(type.GenericTypeArguments);
|
||||
}
|
||||
|
||||
private void WriteType(TypeInfo type)
|
||||
{
|
||||
if (type.FullName == "System.Void")
|
||||
{
|
||||
_sb.Append('v');
|
||||
return;
|
||||
}
|
||||
|
||||
if (type.IsByRef)
|
||||
_sb.Append('R');
|
||||
|
||||
if (type.IsPointer)
|
||||
_sb.Append('P');
|
||||
|
||||
if (type.IsArray)
|
||||
_sb.Append("A_");
|
||||
|
||||
if (type.IsPrimitive && type.Name != "Decimal")
|
||||
{
|
||||
if (type.Name is "IntPtr" or "UIntPtr")
|
||||
_sb.Append("Pv"); // void*
|
||||
else
|
||||
{
|
||||
_sb.Append(type.Name switch
|
||||
{
|
||||
"Boolean" => 'b',
|
||||
"Byte" => 'h',
|
||||
"SByte" => 'a',
|
||||
"Int16" => 's',
|
||||
"UInt16" => 't',
|
||||
"Int32" => 'i',
|
||||
"UInt32" => 'j',
|
||||
"Int64" => 'l',
|
||||
"UInt64" => 'm',
|
||||
"Char" => 'w',
|
||||
"Single" => 'f',
|
||||
"Double" => 'd',
|
||||
_ => throw new UnreachableException()
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BeginName();
|
||||
WriteTypeName(type);
|
||||
WriteEnd();
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteGenericParams(TypeInfo[] generics)
|
||||
{
|
||||
if (generics.Length > 0)
|
||||
{
|
||||
BeginGenerics();
|
||||
|
||||
foreach (var arg in generics)
|
||||
WriteType(arg);
|
||||
|
||||
WriteEnd();
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteIdentifier(string identifier)
|
||||
{
|
||||
_sb.Append(identifier.Length);
|
||||
_sb.Append(identifier);
|
||||
}
|
||||
|
||||
private void WriteName(string name)
|
||||
{
|
||||
foreach (var part in name.Split("."))
|
||||
{
|
||||
if (part.Length > 0)
|
||||
WriteIdentifier(part);
|
||||
}
|
||||
}
|
||||
|
||||
private void BeginName()
|
||||
{
|
||||
_sb.Append('N');
|
||||
}
|
||||
|
||||
private void BeginGenerics()
|
||||
{
|
||||
_sb.Append('I');
|
||||
}
|
||||
|
||||
private void WriteEnd()
|
||||
{
|
||||
_sb.Append('E');
|
||||
}
|
||||
}
|
||||
@@ -273,7 +273,8 @@ namespace Il2CppInspector
|
||||
attsByToken.Add(token, index);
|
||||
}
|
||||
|
||||
AttributeIndicesByToken.Add(image.customAttributeStart, attsByToken);
|
||||
if (attsByToken.Count > 0)
|
||||
AttributeIndicesByToken.Add(image.customAttributeStart, attsByToken);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,45 +1,50 @@
|
||||
/*
|
||||
Copyright 2020-2021 Katy Coe - http://www.djkaty.com - https://github.com/djkaty
|
||||
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
using Il2CppInspector.Cpp;
|
||||
using Il2CppInspector.Reflection;
|
||||
|
||||
namespace Il2CppInspector.Model
|
||||
{
|
||||
// Class that represents a composite IL/C++ method
|
||||
public class AppMethod
|
||||
{
|
||||
// The logical group this method is part of
|
||||
// This is purely for querying methods in related groups and has no bearing on the code
|
||||
public string Group { get; set; }
|
||||
|
||||
// The corresponding C++ function pointer type
|
||||
public CppFnPtrType CppFnPtrType { get; internal set; }
|
||||
|
||||
// The corresponding .NET method
|
||||
public MethodBase Method { get; internal set; }
|
||||
|
||||
// The VA of the MethodInfo* (VA of the pointer to the MethodInfo) object which defines this method
|
||||
// Methods not referenced by the binary will be 0xffffffff_ffffffff
|
||||
public ulong MethodInfoPtrAddress { get; internal set; }
|
||||
|
||||
// The VA of the method code itself
|
||||
// Generic method definitions do not have a code address but may have a reference above
|
||||
public ulong MethodCodeAddress => Method.VirtualAddress?.Start ?? 0xffffffff_ffffffff;
|
||||
|
||||
// Helpers
|
||||
public bool HasMethodInfo => MethodInfoPtrAddress != 0xffffffff_ffffffff;
|
||||
public bool HasCompiledCode => Method.VirtualAddress.HasValue && Method.VirtualAddress.Value.Start != 0;
|
||||
|
||||
public AppMethod(MethodBase method, CppFnPtrType cppMethod, ulong methodInfoPtr = 0xffffffff_ffffffff) {
|
||||
Method = method;
|
||||
CppFnPtrType = cppMethod;
|
||||
MethodInfoPtrAddress = methodInfoPtr;
|
||||
}
|
||||
|
||||
public override string ToString() => CppFnPtrType.ToSignatureString();
|
||||
}
|
||||
}
|
||||
/*
|
||||
Copyright 2020-2021 Katy Coe - http://www.djkaty.com - https://github.com/djkaty
|
||||
Copyright 2023 LukeFZ - https://github.com/LukeFZ
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
using System.Diagnostics;
|
||||
using Il2CppInspector.Cpp;
|
||||
using Il2CppInspector.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace Il2CppInspector.Model
|
||||
{
|
||||
// Class that represents a composite IL/C++ method
|
||||
public class AppMethod
|
||||
{
|
||||
// The logical group this method is part of
|
||||
// This is purely for querying methods in related groups and has no bearing on the code
|
||||
public string Group { get; set; }
|
||||
|
||||
// The corresponding C++ function pointer type
|
||||
public CppFnPtrType CppFnPtrType { get; internal set; }
|
||||
|
||||
// The corresponding .NET method
|
||||
public MethodBase Method { get; internal set; }
|
||||
|
||||
// The VA of the MethodInfo* (VA of the pointer to the MethodInfo) object which defines this method
|
||||
// Methods not referenced by the binary will be 0xffffffff_ffffffff
|
||||
public ulong MethodInfoPtrAddress { get; internal set; }
|
||||
|
||||
// The VA of the method code itself
|
||||
// Generic method definitions do not have a code address but may have a reference above
|
||||
public ulong MethodCodeAddress => Method.VirtualAddress?.Start ?? 0xffffffff_ffffffff;
|
||||
|
||||
// Helpers
|
||||
public bool HasMethodInfo => MethodInfoPtrAddress != 0xffffffff_ffffffff;
|
||||
public bool HasCompiledCode => Method.VirtualAddress.HasValue && Method.VirtualAddress.Value.Start != 0;
|
||||
|
||||
public AppMethod(MethodBase method, CppFnPtrType cppMethod, ulong methodInfoPtr = 0xffffffff_ffffffff) {
|
||||
Method = method;
|
||||
CppFnPtrType = cppMethod;
|
||||
MethodInfoPtrAddress = methodInfoPtr;
|
||||
}
|
||||
|
||||
public override string ToString() => CppFnPtrType.ToSignatureString();
|
||||
|
||||
public string ToMangledString() => MangledNameBuilder.Method(Method);
|
||||
public string ToMangledMethodInfoString() => MangledNameBuilder.MethodInfo(Method);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,8 +51,8 @@ namespace Il2CppInspector.Model
|
||||
// For il2cpp < 19, the key is the string literal ordinal instead of the address
|
||||
public Dictionary<ulong, string> Strings { get; } = [];
|
||||
|
||||
public Dictionary<ulong, (string Name, string Value)> Fields { get; } = [];
|
||||
public Dictionary<ulong, (string Name, string Value)> FieldRvas { get; } = [];
|
||||
public Dictionary<ulong, (FieldInfo Field, string Value)> Fields { get; } = [];
|
||||
public Dictionary<ulong, (FieldInfo Field, string Value)> FieldRvas { get; } = [];
|
||||
|
||||
public bool StringIndexesAreOrdinals => Package.Version < 19;
|
||||
|
||||
@@ -254,10 +254,6 @@ namespace Il2CppInspector.Model
|
||||
var fieldType = TypeModel.GetMetadataUsageType(usage);
|
||||
var field = fieldType.DeclaredFields.First(f => f.Index == fieldType.Definition.fieldStart + fieldRef.fieldIndex);
|
||||
|
||||
var name = usage.Type == MetadataUsageType.FieldInfo
|
||||
? $"{fieldType.Name}.{field.Name}".ToCIdentifier()
|
||||
: $"{fieldType.Name}.{field.Name}_FieldRva".ToCIdentifier();
|
||||
|
||||
var value = field.HasFieldRVA
|
||||
? Convert.ToHexString(Package.Metadata.ReadBytes(
|
||||
(long) field.DefaultValueMetadataAddress, field.FieldType.Sizes.nativeSize))
|
||||
@@ -265,9 +261,9 @@ namespace Il2CppInspector.Model
|
||||
|
||||
|
||||
if (usage.Type == MetadataUsageType.FieldInfo)
|
||||
Fields[usage.VirtualAddress] = (name, value);
|
||||
Fields[usage.VirtualAddress] = (field, value);
|
||||
else
|
||||
FieldRvas[usage.VirtualAddress] = (name, value);
|
||||
FieldRvas[usage.VirtualAddress] = (field, value);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -345,11 +341,8 @@ namespace Il2CppInspector.Model
|
||||
// Get the address map for the model
|
||||
// This takes a while to construct so we only build it if requested
|
||||
private AddressMap addressMap;
|
||||
public AddressMap GetAddressMap() {
|
||||
if (addressMap == null)
|
||||
addressMap = new AddressMap(this);
|
||||
return addressMap;
|
||||
}
|
||||
public AddressMap GetAddressMap()
|
||||
=> addressMap ??= new AddressMap(this);
|
||||
|
||||
// Get the byte offset in Il2CppClass for this app's Unity version to the vtable
|
||||
public int GetVTableOffset() => CppTypeCollection.GetComplexType("Il2CppClass")["vtable"].OffsetBytes;
|
||||
|
||||
@@ -1,52 +1,56 @@
|
||||
/*
|
||||
Copyright 2020-2021 Katy Coe - http://www.djkaty.com - https://github.com/djkaty
|
||||
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
using Il2CppInspector.Cpp;
|
||||
using Il2CppInspector.Reflection;
|
||||
|
||||
namespace Il2CppInspector.Model
|
||||
{
|
||||
// Class that represents a composite IL/C++ type
|
||||
public class AppType
|
||||
{
|
||||
// The logical group this type is part of
|
||||
// This is purely for querying types in related groups and has no bearing on the code
|
||||
public string Group { get; set; }
|
||||
|
||||
// The corresponding C++ type definition which represents an instance of the object
|
||||
// This is derived from Il2CppObject
|
||||
// If the underlying .NET type is a struct (value type), this will return the boxed version
|
||||
public CppComplexType CppType { get; internal set; }
|
||||
|
||||
// For an underlying .NET type which is a struct (value type), the unboxed type, otherwise null
|
||||
public CppComplexType CppValueType { get; internal set; }
|
||||
|
||||
// The type in the .NET type model this object maps to
|
||||
public TypeInfo Type { get; internal set; }
|
||||
|
||||
// The VA of the Il2CppClass object which defines this type (ClassName__TypeInfo)
|
||||
public ulong TypeClassAddress { get; internal set; }
|
||||
|
||||
// The VA of the Il2CppType* (VA of the pointer to the Il2CppType) object which references this type (ClassName__TypeRef)
|
||||
public ulong TypeRefPtrAddress { get; internal set; }
|
||||
|
||||
public AppType(TypeInfo ilType, CppComplexType cppType, CppComplexType valueType = null,
|
||||
ulong cppClassPtr = 0xffffffff_ffffffff, ulong cppTypeRefPtr = 0xffffffff_ffffffff) {
|
||||
CppType = cppType;
|
||||
Type = ilType;
|
||||
CppValueType = valueType;
|
||||
TypeClassAddress = cppClassPtr;
|
||||
TypeRefPtrAddress = cppTypeRefPtr;
|
||||
}
|
||||
|
||||
// The C++ name of the type
|
||||
// TODO: Known issue here where we should be using CppDeclarationGenerator.TypeNamer to ensure uniqueness
|
||||
// Prefer Foo over Foo__Boxed; if there is no C++ type defined, just convert the IL type to a C identifier
|
||||
public string Name => CppValueType?.Name ?? CppType?.Name ?? Type.Name.ToCIdentifier();
|
||||
|
||||
public override string ToString() => Type.FullName + " -> " + CppType.Name;
|
||||
}
|
||||
/*
|
||||
Copyright 2020-2021 Katy Coe - http://www.djkaty.com - https://github.com/djkaty
|
||||
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
using Il2CppInspector.Cpp;
|
||||
using Il2CppInspector.Reflection;
|
||||
|
||||
namespace Il2CppInspector.Model
|
||||
{
|
||||
// Class that represents a composite IL/C++ type
|
||||
public class AppType
|
||||
{
|
||||
// The logical group this type is part of
|
||||
// This is purely for querying types in related groups and has no bearing on the code
|
||||
public string Group { get; set; }
|
||||
|
||||
// The corresponding C++ type definition which represents an instance of the object
|
||||
// This is derived from Il2CppObject
|
||||
// If the underlying .NET type is a struct (value type), this will return the boxed version
|
||||
public CppComplexType CppType { get; internal set; }
|
||||
|
||||
// For an underlying .NET type which is a struct (value type), the unboxed type, otherwise null
|
||||
public CppComplexType CppValueType { get; internal set; }
|
||||
|
||||
// The type in the .NET type model this object maps to
|
||||
public TypeInfo Type { get; internal set; }
|
||||
|
||||
// The VA of the Il2CppClass object which defines this type (ClassName__TypeInfo)
|
||||
public ulong TypeClassAddress { get; internal set; }
|
||||
|
||||
// The VA of the Il2CppType* (VA of the pointer to the Il2CppType) object which references this type (ClassName__TypeRef)
|
||||
public ulong TypeRefPtrAddress { get; internal set; }
|
||||
|
||||
public AppType(TypeInfo ilType, CppComplexType cppType, CppComplexType valueType = null,
|
||||
ulong cppClassPtr = 0xffffffff_ffffffff, ulong cppTypeRefPtr = 0xffffffff_ffffffff) {
|
||||
CppType = cppType;
|
||||
Type = ilType;
|
||||
CppValueType = valueType;
|
||||
TypeClassAddress = cppClassPtr;
|
||||
TypeRefPtrAddress = cppTypeRefPtr;
|
||||
}
|
||||
|
||||
// The C++ name of the type
|
||||
// TODO: Known issue here where we should be using CppDeclarationGenerator.TypeNamer to ensure uniqueness
|
||||
// Prefer Foo over Foo__Boxed; if there is no C++ type defined, just convert the IL type to a C identifier
|
||||
public string Name => CppValueType?.Name ?? CppType?.Name ?? Type.Name.ToCIdentifier();
|
||||
|
||||
public override string ToString() => Type.FullName + " -> " + CppType.Name;
|
||||
|
||||
public string ToMangledTypeInfoString() => MangledNameBuilder.TypeInfo(Type);
|
||||
|
||||
public string ToMangledTypeRefString() => MangledNameBuilder.TypeRef(Type);
|
||||
}
|
||||
}
|
||||
@@ -67,7 +67,7 @@ namespace Il2CppInspector.Outputs
|
||||
""");
|
||||
|
||||
if (_useBetterArraySize)
|
||||
writeCode("#define il2cpp_array_size_t actual_il2cpp_array_size_t");
|
||||
writeCode("#define actual_il2cpp_array_size_t il2cpp_array_size_t");
|
||||
|
||||
writeSectionHeader("IL2CPP internal types");
|
||||
writeCode(_model.UnityHeaders.GetTypeHeaderText(_model.WordSizeBits));
|
||||
@@ -82,7 +82,7 @@ namespace Il2CppInspector.Outputs
|
||||
actual_il2cpp_array_size_t value;
|
||||
} better_il2cpp_array_size_t;
|
||||
|
||||
#define il2cpp_array_size_t better_il2cpp_array_size_t
|
||||
#define better_il2cpp_array_size_t il2cpp_array_size_t
|
||||
""");
|
||||
|
||||
if (_model.TargetCompiler == CppCompilerType.MSVC)
|
||||
|
||||
@@ -72,7 +72,7 @@ namespace Il2CppInspector.Outputs
|
||||
private void writeMethods(IEnumerable<AppMethod> methods) {
|
||||
foreach (var method in methods.Where(m => m.HasCompiledCode)) {
|
||||
writeObject(() => {
|
||||
writeTypedFunctionName(method.MethodCodeAddress, method.CppFnPtrType.ToSignatureString(), method.CppFnPtrType.Name);
|
||||
writeTypedFunctionName(method.MethodCodeAddress, method.CppFnPtrType.ToSignatureString(), method.ToMangledString());
|
||||
writeDotNetSignature(method.Method);
|
||||
});
|
||||
}
|
||||
@@ -105,7 +105,7 @@ namespace Il2CppInspector.Outputs
|
||||
|
||||
if (type.TypeClassAddress != 0xffffffff_ffffffff) {
|
||||
writeObject(() => {
|
||||
writeTypedName(type.TypeClassAddress, $"struct {type.Name}__Class *", $"{type.Name}__TypeInfo");
|
||||
writeTypedName(type.TypeClassAddress, $"struct {type.Name}__Class *", type.ToMangledTypeInfoString());
|
||||
writeDotNetTypeName(type.Type);
|
||||
});
|
||||
}
|
||||
@@ -119,7 +119,7 @@ namespace Il2CppInspector.Outputs
|
||||
if (type.TypeRefPtrAddress != 0xffffffff_ffffffff) {
|
||||
writeObject(() => {
|
||||
// A generic type definition does not have any direct C++ types, but may have a reference
|
||||
writeName(type.TypeRefPtrAddress, $"{type.Name}__TypeRef");
|
||||
writeName(type.TypeRefPtrAddress, type.ToMangledTypeRefString());
|
||||
writeDotNetTypeName(type.Type);
|
||||
});
|
||||
}
|
||||
@@ -131,7 +131,7 @@ namespace Il2CppInspector.Outputs
|
||||
() => {
|
||||
foreach (var method in model.Methods.Values.Where(m => m.HasMethodInfo)) {
|
||||
writeObject(() => {
|
||||
writeName(method.MethodInfoPtrAddress, $"{method.CppFnPtrType.Name}__MethodInfo");
|
||||
writeName(method.MethodInfoPtrAddress, method.ToMangledMethodInfoString());
|
||||
writeDotNetSignature(method.Method);
|
||||
});
|
||||
}
|
||||
@@ -221,13 +221,13 @@ namespace Il2CppInspector.Outputs
|
||||
writeArray("fields", () =>
|
||||
{
|
||||
foreach (var (addr, field) in model.Fields)
|
||||
writeFieldObject(addr, field.Name, field.Value);
|
||||
writeFieldObject(addr, (field.Field + "_Field").ToCIdentifier(), field.Value);
|
||||
});
|
||||
|
||||
writeArray("fieldRvas", () =>
|
||||
{
|
||||
foreach (var (addr, rva) in model.FieldRvas)
|
||||
writeFieldObject(addr, rva.Name, rva.Value);
|
||||
writeFieldObject(addr, (rva.Field + "_FieldRva").ToCIdentifier(), rva.Value);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
@@ -68,7 +69,9 @@ namespace Il2CppInspector.Reflection {
|
||||
public bool IsLiteral => (Attributes & FieldAttributes.Literal) == FieldAttributes.Literal;
|
||||
|
||||
// True if the field has the NonSerialized attribute
|
||||
#pragma warning disable SYSLIB0050
|
||||
public bool IsNotSerialized => (Attributes & FieldAttributes.NotSerialized) == FieldAttributes.NotSerialized;
|
||||
#pragma warning restore SYSLIB0050
|
||||
|
||||
// True if the field is extern
|
||||
public bool IsPinvokeImpl => (Attributes & FieldAttributes.PinvokeImpl) == FieldAttributes.PinvokeImpl;
|
||||
|
||||
@@ -702,7 +702,9 @@ namespace Il2CppInspector.Reflection
|
||||
public bool IsPrimitive => Namespace == "System" && new[] { "Boolean", "Byte", "SByte", "Int16", "UInt16", "Int32", "UInt32", "Int64", "UInt64", "IntPtr", "UIntPtr", "Char", "Decimal", "Double", "Single" }.Contains(Name);
|
||||
public bool IsPublic => (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.Public;
|
||||
public bool IsSealed => (Attributes & TypeAttributes.Sealed) == TypeAttributes.Sealed;
|
||||
#pragma warning disable SYSLIB0050
|
||||
public bool IsSerializable => (Attributes & TypeAttributes.Serializable) == TypeAttributes.Serializable;
|
||||
#pragma warning restore SYSLIB0050
|
||||
public bool IsSpecialName => (Attributes & TypeAttributes.SpecialName) == TypeAttributes.SpecialName;
|
||||
public bool IsValueType => BaseType?.FullName == "System.ValueType";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user