Model and Output: Implement generic type constraints

This commit is contained in:
Katy Coe
2019-11-11 21:48:04 +01:00
parent 0f8b1428e4
commit 06ed21747e
4 changed files with 72 additions and 13 deletions

View File

@@ -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();
}

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}
}