Model and Output: Implement generic type constraints
This commit is contained in:
@@ -104,7 +104,16 @@ namespace Il2CppInspector
|
||||
@base.Insert(0, type.GetEnumUnderlyingType().CSharpName);
|
||||
var baseText = @base.Count > 0 ? " : " + string.Join(", ", @base) : string.Empty;
|
||||
|
||||
writer.Write($"{type.CSharpTypeDeclarationName}{baseText} // TypeDefIndex: {type.Index}\n" + prefix + "{\n");
|
||||
writer.Write($"{type.CSharpTypeDeclarationName}{baseText} // TypeDefIndex: {type.Index}\n");
|
||||
|
||||
if (type.GenericTypeParameters != null)
|
||||
foreach (var gp in type.GenericTypeParameters) {
|
||||
var constraint = gp.GetTypeConstraintsString();
|
||||
if (constraint != string.Empty)
|
||||
writer.Write($"{prefix}\t{constraint}\n");
|
||||
}
|
||||
|
||||
writer.Write(prefix + "{\n");
|
||||
|
||||
// Fields
|
||||
if (!type.IsEnum) {
|
||||
@@ -273,8 +282,16 @@ namespace Il2CppInspector
|
||||
writer.Append($"{method.ReturnParameter.GetReturnParameterString()} {method.CSharpName}{method.GetTypeParametersString()}");
|
||||
else
|
||||
writer.Append($"{method.CSharpName}{method.ReturnType.CSharpName}");
|
||||
writer.Append("(" + method.GetParametersString());
|
||||
writer.Append(");" + (method.VirtualAddress != 0 ? $" // {method.VirtualAddress.ToAddressString()}" : "") + "\n");
|
||||
writer.Append("(" + method.GetParametersString() + ")");
|
||||
|
||||
if (method.GenericTypeParameters != null)
|
||||
foreach (var gp in method.GenericTypeParameters) {
|
||||
var constraint = gp.GetTypeConstraintsString();
|
||||
if (constraint != string.Empty)
|
||||
writer.Append($"\n{prefix}\t\t{constraint}");
|
||||
}
|
||||
|
||||
writer.Append(";" + (method.VirtualAddress != 0 ? $" // {method.VirtualAddress.ToAddressString()}" : "") + "\n");
|
||||
|
||||
return writer.ToString();
|
||||
}
|
||||
|
||||
@@ -382,8 +382,8 @@ namespace Il2CppInspector
|
||||
public int nameIndex; // StringIndex
|
||||
public short constraintsStart; // GenericParameterConstraintIndex
|
||||
public short constraintsCount;
|
||||
public ushort num;
|
||||
public ushort flags;
|
||||
public ushort num; // Generic parameter position
|
||||
public ushort flags; // GenericParameterAttributes
|
||||
}
|
||||
|
||||
public class Il2CppCustomAttributeTypeRange
|
||||
|
||||
@@ -76,8 +76,6 @@ namespace Il2CppInspector.Reflection
|
||||
var container = pkg.GenericContainers[Definition.genericContainerIndex];
|
||||
|
||||
GenericTypeParameters = pkg.GenericParameters.Skip((int)container.genericParameterStart).Take(container.type_argc).Select(p => new TypeInfo(this, p)).ToList();
|
||||
|
||||
// TODO: Constraints
|
||||
}
|
||||
|
||||
// Set method attributes
|
||||
|
||||
@@ -85,6 +85,18 @@ namespace Il2CppInspector.Reflection {
|
||||
// Get a field by its name
|
||||
public FieldInfo GetField(string name) => DeclaredFields.FirstOrDefault(f => f.Name == name);
|
||||
|
||||
private readonly int genericConstraintIndex;
|
||||
|
||||
private readonly int genericConstraintCount;
|
||||
|
||||
// Get type constraints on a generic parameter
|
||||
public TypeInfo[] GetGenericParameterConstraints() {
|
||||
var types = new TypeInfo[genericConstraintCount];
|
||||
for (int c = 0; c < genericConstraintCount; c++)
|
||||
types[c] = Assembly.Model.GetTypeFromUsage(Assembly.Model.Package.GenericConstraintIndices[genericConstraintIndex + c], MemberTypes.TypeInfo);
|
||||
return types;
|
||||
}
|
||||
|
||||
// Get a method by its name
|
||||
public MethodInfo GetMethod(string name) => DeclaredMethods.FirstOrDefault(m => m.Name == name);
|
||||
|
||||
@@ -126,6 +138,10 @@ namespace Il2CppInspector.Reflection {
|
||||
+ (IsArray? "[" + new string(',', GetArrayRank() - 1) + "]" : "")
|
||||
+ (IsPointer? "*" : "");
|
||||
|
||||
public GenericParameterAttributes GenericParameterAttributes { get; }
|
||||
|
||||
public int GenericParameterPosition { get; }
|
||||
|
||||
public List<TypeInfo> GenericTypeParameters { get; }
|
||||
|
||||
public List<TypeInfo> GenericTypeArguments { get; }
|
||||
@@ -227,8 +243,6 @@ namespace Il2CppInspector.Reflection {
|
||||
var container = pkg.GenericContainers[Definition.genericContainerIndex];
|
||||
|
||||
GenericTypeParameters = pkg.GenericParameters.Skip((int) container.genericParameterStart).Take(container.type_argc).Select(p => new TypeInfo(this, p)).ToList();
|
||||
|
||||
// TODO: Constraints
|
||||
}
|
||||
|
||||
// Add to global type definition list
|
||||
@@ -427,14 +441,23 @@ namespace Il2CppInspector.Reflection {
|
||||
// Same visibility attributes as declaring type
|
||||
Attributes = declaringType.Attributes;
|
||||
|
||||
// Same namespace as delcaring type
|
||||
// Same namespace as declaring type
|
||||
Namespace = declaringType.Namespace;
|
||||
|
||||
// Base type of object
|
||||
// TODO: This may change under constraints
|
||||
// Special constraints
|
||||
GenericParameterAttributes = (GenericParameterAttributes) param.flags;
|
||||
|
||||
// Type constraints
|
||||
genericConstraintIndex = param.constraintsStart;
|
||||
genericConstraintCount = param.constraintsCount;
|
||||
|
||||
// Base type of object (set by default)
|
||||
|
||||
// Name of parameter
|
||||
Name = declaringType.Assembly.Model.Package.Strings[param.nameIndex];
|
||||
Name = Assembly.Model.Package.Strings[param.nameIndex];
|
||||
|
||||
// Position
|
||||
GenericParameterPosition = param.num;
|
||||
|
||||
IsGenericParameter = true;
|
||||
IsGenericType = false;
|
||||
@@ -494,6 +517,27 @@ namespace Il2CppInspector.Reflection {
|
||||
return modifiers.ToString();
|
||||
}
|
||||
|
||||
public string GetTypeConstraintsString() {
|
||||
if (!IsGenericParameter)
|
||||
return string.Empty;
|
||||
|
||||
var typeConstraints = GetGenericParameterConstraints();
|
||||
if (GenericParameterAttributes == GenericParameterAttributes.None && typeConstraints.Length == 0)
|
||||
return string.Empty;
|
||||
|
||||
var constraintList = typeConstraints.Where(c => c.FullName != "System.ValueType").Select(c => c.CSharpTypeDeclarationName).ToList();
|
||||
|
||||
if ((GenericParameterAttributes & GenericParameterAttributes.NotNullableValueTypeConstraint) == GenericParameterAttributes.NotNullableValueTypeConstraint)
|
||||
constraintList.Add("struct");
|
||||
if ((GenericParameterAttributes & GenericParameterAttributes.ReferenceTypeConstraint) == GenericParameterAttributes.ReferenceTypeConstraint)
|
||||
constraintList.Add("class");
|
||||
if ((GenericParameterAttributes & GenericParameterAttributes.DefaultConstructorConstraint) == GenericParameterAttributes.DefaultConstructorConstraint
|
||||
&& !constraintList.Contains("struct"))
|
||||
constraintList.Add("new()");
|
||||
|
||||
return "where " + Name + " : " + string.Join(", ", constraintList);
|
||||
}
|
||||
|
||||
public override string ToString() => Name;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user