Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Type Parameters in Call Analysis #255

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions Cpp2IL.Core/Model/Contexts/ArrayTypeAnalysisContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using AsmResolver.DotNet;
using AsmResolver.DotNet.Signatures.Types;
using Cpp2IL.Core.Utils;
using LibCpp2IL.BinaryStructures;

namespace Cpp2IL.Core.Model.Contexts;

public class ArrayTypeAnalysisContext : WrappedTypeAnalysisContext
{
public ArrayTypeAnalysisContext(TypeAnalysisContext elementType, int rank, AssemblyAnalysisContext referencedFrom) : base(elementType, referencedFrom)
{
Rank = rank;
}

public ArrayTypeAnalysisContext(Il2CppType rawType, AssemblyAnalysisContext referencedFrom)
: this(referencedFrom.ResolveIl2CppType(rawType.GetArrayElementType()), rawType.GetArrayRank(), referencedFrom)
{
}

public override Il2CppTypeEnum Type => Il2CppTypeEnum.IL2CPP_TYPE_ARRAY;

public override string DefaultName => $"{ElementType.Name}[{Rank}]";

public int Rank { get; }

public override TypeSignature ToTypeSignature(ModuleDefinition parentModule)
{
return ElementType.ToTypeSignature(parentModule).MakeArrayType(Rank);
}
}
28 changes: 28 additions & 0 deletions Cpp2IL.Core/Model/Contexts/ByRefTypeAnalysisContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using AsmResolver.DotNet;
using AsmResolver.DotNet.Signatures.Types;
using LibCpp2IL.BinaryStructures;

namespace Cpp2IL.Core.Model.Contexts;

public class ByRefTypeAnalysisContext : WrappedTypeAnalysisContext
{
public ByRefTypeAnalysisContext(TypeAnalysisContext elementType, AssemblyAnalysisContext referencedFrom) : base(elementType, referencedFrom)
{
}

public ByRefTypeAnalysisContext(Il2CppType rawType, AssemblyAnalysisContext referencedFrom)
: this(default(TypeAnalysisContext)!, referencedFrom)
{
}

public override Il2CppTypeEnum Type => Il2CppTypeEnum.IL2CPP_TYPE_BYREF;

public override string DefaultName => $"{ElementType.Name}&";

protected override TypeAnalysisContext ElementType => base.ElementType ?? throw new("TODO Support TYPE_BYREF");

public override TypeSignature ToTypeSignature(ModuleDefinition parentModule)
{
return ElementType.ToTypeSignature(parentModule).MakeByReferenceType();
}
}
53 changes: 45 additions & 8 deletions Cpp2IL.Core/Model/Contexts/ConcreteGenericMethodAnalysisContext.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using System.Reflection;
using Cpp2IL.Core.Utils;
using LibCpp2IL;

namespace Cpp2IL.Core.Model.Contexts;
Expand All @@ -6,27 +8,62 @@ public class ConcreteGenericMethodAnalysisContext : MethodAnalysisContext
{
public readonly AssemblyAnalysisContext DeclaringAsm;
public readonly Cpp2IlMethodRef MethodRef;
public TypeAnalysisContext BaseTypeContext;
public MethodAnalysisContext BaseMethodContext;
public readonly MethodAnalysisContext BaseMethodContext;

public sealed override ulong UnderlyingPointer => MethodRef.GenericVariantPtr;

public override bool IsStatic => BaseMethodContext.IsStatic;

public override bool IsVoid => BaseMethodContext.IsVoid;

public override string DefaultName => BaseMethodContext.DefaultName;

public ConcreteGenericMethodAnalysisContext(Cpp2IlMethodRef methodRef, ApplicationAnalysisContext context) : base(context)
public override MethodAttributes Attributes => BaseMethodContext.Attributes;

public override AssemblyAnalysisContext CustomAttributeAssembly => BaseMethodContext.CustomAttributeAssembly;

public ConcreteGenericMethodAnalysisContext(Cpp2IlMethodRef methodRef, ApplicationAnalysisContext context)
: this(methodRef, ResolveDeclaringAssembly(methodRef, context))
{
}

private ConcreteGenericMethodAnalysisContext(Cpp2IlMethodRef methodRef, AssemblyAnalysisContext declaringAssembly)
: base(null, ResolveDeclaringType(methodRef, declaringAssembly))
{
MethodRef = methodRef;
DeclaringAsm = context.GetAssemblyByName(methodRef.DeclaringType.DeclaringAssembly!.Name!) ?? throw new($"Unable to resolve declaring assembly {methodRef.DeclaringType.DeclaringAssembly.Name} for generic method {methodRef}");
BaseTypeContext = DeclaringAsm!.GetTypeByFullName(methodRef.DeclaringType.FullName!) ?? throw new($"Unable to resolve declaring type {methodRef.DeclaringType.FullName} for generic method {methodRef}");
BaseMethodContext = BaseTypeContext.GetMethod(methodRef.BaseMethod) ?? throw new($"Unable to resolve base method {methodRef.BaseMethod} for generic method {methodRef}");
DeclaringAsm = declaringAssembly;
BaseMethodContext = ResolveBaseMethod(methodRef, declaringAssembly.GetTypeByDefinition(methodRef.DeclaringType)!);

//TODO: Do we want to update this to populate known generic parameters based on the generic arguments?
Parameters.AddRange(BaseMethodContext.Parameters);

if(UnderlyingPointer != 0)
RawBytes = AppContext.InstructionSet.GetRawBytesForMethod(this, false);
}
}

private static AssemblyAnalysisContext ResolveDeclaringAssembly(Cpp2IlMethodRef methodRef, ApplicationAnalysisContext context)
{
return context.GetAssemblyByName(methodRef.DeclaringType.DeclaringAssembly!.Name!)
?? throw new($"Unable to resolve declaring assembly {methodRef.DeclaringType.DeclaringAssembly.Name} for generic method {methodRef}");
}

private static TypeAnalysisContext ResolveDeclaringType(Cpp2IlMethodRef methodRef, AssemblyAnalysisContext declaringAssembly)
{
var baseType = declaringAssembly.AppContext.ResolveContextForType(methodRef.DeclaringType)
?? throw new($"Unable to resolve declaring type {methodRef.DeclaringType.FullName} for generic method {methodRef}");

var genericParams = new TypeAnalysisContext[methodRef.TypeGenericParams.Length];
for (var i = 0; i < methodRef.TypeGenericParams.Length; i++)
{
genericParams[i] = methodRef.TypeGenericParams[i].ToContext(declaringAssembly)
?? throw new($"Unable to resolve generic parameter {methodRef.TypeGenericParams[i]} for generic method {methodRef}");
}
return new GenericInstanceTypeAnalysisContext(baseType, genericParams, declaringAssembly);
}

private static MethodAnalysisContext ResolveBaseMethod(Cpp2IlMethodRef methodRef, TypeAnalysisContext declaringType)
{
return declaringType.GetMethod(methodRef.BaseMethod)
?? throw new($"Unable to resolve base method {methodRef.BaseMethod} for generic method {methodRef}");
}
}
26 changes: 24 additions & 2 deletions Cpp2IL.Core/Model/Contexts/GenericInstanceTypeAnalysisContext.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
using System.Linq;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AsmResolver.DotNet;
using AsmResolver.DotNet.Signatures.Types;
using Cpp2IL.Core.Utils;
using LibCpp2IL.BinaryStructures;

Expand All @@ -9,7 +12,11 @@ public class GenericInstanceTypeAnalysisContext : ReferencedTypeAnalysisContext
{
protected override TypeAnalysisContext ElementType { get; }

public GenericInstanceTypeAnalysisContext(Il2CppType rawType, AssemblyAnalysisContext referencedFrom) : base(rawType, referencedFrom)
public override string DefaultName => $"{ElementType.Name}<{string.Join(", ", GenericArguments.Select(a => a.Name))}>";

public override Il2CppTypeEnum Type => Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST;

public GenericInstanceTypeAnalysisContext(Il2CppType rawType, AssemblyAnalysisContext referencedFrom) : base(referencedFrom)
{
//Element type has to be a type definition
var gClass = rawType.GetGenericClass();
Expand All @@ -18,6 +25,21 @@ public GenericInstanceTypeAnalysisContext(Il2CppType rawType, AssemblyAnalysisCo
GenericArguments.AddRange(gClass.Context.ClassInst.Types.Select(referencedFrom.ResolveIl2CppType)!);
}

public GenericInstanceTypeAnalysisContext(TypeAnalysisContext elementType, IEnumerable<TypeAnalysisContext> genericArguments, AssemblyAnalysisContext referencedFrom) : base(referencedFrom)
{
ElementType = elementType;
GenericArguments.AddRange(genericArguments);
OverrideBaseType = elementType.BaseType;
}

public override TypeSignature ToTypeSignature(ModuleDefinition parentModule)
{
var elementType = ElementType.ToTypeSignature(parentModule).ToTypeDefOrRef();
var genericArguments = GenericArguments.Select(a => a.ToTypeSignature(parentModule)).ToArray();

return new GenericInstanceTypeSignature(elementType, IsValueType, genericArguments);
}

public override string GetCSharpSourceString()
{
var sb = new StringBuilder();
Expand Down
37 changes: 32 additions & 5 deletions Cpp2IL.Core/Model/Contexts/GenericParameterTypeAnalysisContext.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,43 @@
using LibCpp2IL.BinaryStructures;
using System;
using AsmResolver.DotNet;
using AsmResolver.DotNet.Signatures.Types;
using LibCpp2IL.BinaryStructures;
using LibCpp2IL.Metadata;

namespace Cpp2IL.Core.Model.Contexts;

public class GenericParameterTypeAnalysisContext : ReferencedTypeAnalysisContext
{
public override string DefaultName { get; }

public int Index { get; }

public override Il2CppTypeEnum Type { get; }

protected override TypeAnalysisContext ElementType => throw new("Attempted to get element type of a generic parameter");

public GenericParameterTypeAnalysisContext(Il2CppType rawType, AssemblyAnalysisContext referencedFrom) : base(rawType, referencedFrom)
public GenericParameterTypeAnalysisContext(Il2CppType rawType, AssemblyAnalysisContext referencedFrom)
: this(rawType.GetGenericParameterDef(), rawType.Type, referencedFrom)
{
}

public GenericParameterTypeAnalysisContext(Il2CppGenericParameter genericParameter, Il2CppTypeEnum type, AssemblyAnalysisContext referencedFrom)
: this(genericParameter.Name ?? "T", genericParameter.genericParameterIndexInOwner, type, referencedFrom)
{
if(rawType.Type is not Il2CppTypeEnum.IL2CPP_TYPE_VAR and not Il2CppTypeEnum.IL2CPP_TYPE_MVAR)
throw new($"Generic parameter type is not a generic parameter, but {rawType.Type}");
}

public GenericParameterTypeAnalysisContext(string name, int index, Il2CppTypeEnum type, AssemblyAnalysisContext referencedFrom) : base(referencedFrom)
{
if (type is not Il2CppTypeEnum.IL2CPP_TYPE_VAR and not Il2CppTypeEnum.IL2CPP_TYPE_MVAR)
throw new ArgumentException($"Generic parameter type is not a generic parameter, but {type}", nameof(type));

GenericParameter = rawType.GetGenericParameterDef();
DefaultName = name;
Index = index;
Type = type;
}

public override TypeSignature ToTypeSignature(ModuleDefinition parentModule)
{
return new GenericParameterSignature(Type == Il2CppTypeEnum.IL2CPP_TYPE_VAR ? GenericParameterType.Type : GenericParameterType.Method, Index);
}
}
2 changes: 0 additions & 2 deletions Cpp2IL.Core/Model/Contexts/MethodAnalysisContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ public class MethodAnalysisContext : HasCustomAttributesAndName, IMethodInfoProv

/// <summary>
/// The analysis context for the declaring type of this method.
///
/// Null iff this is a subclass.
/// </summary>
public readonly TypeAnalysisContext? DeclaringType;

Expand Down
27 changes: 27 additions & 0 deletions Cpp2IL.Core/Model/Contexts/PointerTypeAnalysisContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using AsmResolver.DotNet;
using AsmResolver.DotNet.Signatures.Types;
using Cpp2IL.Core.Utils;
using LibCpp2IL.BinaryStructures;

namespace Cpp2IL.Core.Model.Contexts;

public class PointerTypeAnalysisContext : WrappedTypeAnalysisContext
{
public PointerTypeAnalysisContext(TypeAnalysisContext elementType, AssemblyAnalysisContext referencedFrom) : base(elementType, referencedFrom)
{
}

public PointerTypeAnalysisContext(Il2CppType rawType, AssemblyAnalysisContext referencedFrom)
: this(referencedFrom.ResolveIl2CppType(rawType.GetEncapsulatedType()), referencedFrom)
{
}

public override Il2CppTypeEnum Type => Il2CppTypeEnum.IL2CPP_TYPE_PTR;

public override string DefaultName => $"{ElementType.Name}*";

public override TypeSignature ToTypeSignature(ModuleDefinition parentModule)
{
return ElementType.ToTypeSignature(parentModule).MakePointerType();
}
}
26 changes: 4 additions & 22 deletions Cpp2IL.Core/Model/Contexts/ReferencedTypeAnalysisContext.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using LibCpp2IL.BinaryStructures;
using LibCpp2IL.Metadata;

namespace Cpp2IL.Core.Model.Contexts;

Expand All @@ -11,28 +8,14 @@ namespace Cpp2IL.Core.Model.Contexts;
/// </summary>
public abstract class ReferencedTypeAnalysisContext : TypeAnalysisContext
{
public Il2CppType RawType { get; }
public abstract Il2CppTypeEnum Type { get; } //Must be set by derived classes

protected abstract TypeAnalysisContext ElementType { get; } //Must be set by derived classes

protected List<TypeAnalysisContext> GenericArguments { get; } = new();

protected Il2CppGenericParameter? GenericParameter { get; set; }

public override string DefaultNs => ElementType.Namespace;

public override string DefaultName => RawType.Type switch
{
Il2CppTypeEnum.IL2CPP_TYPE_PTR => $"{ElementType.Name}*",
Il2CppTypeEnum.IL2CPP_TYPE_BYREF => $"{ElementType.Name}&",
Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY => $"{ElementType.Name}[]",
Il2CppTypeEnum.IL2CPP_TYPE_ARRAY => $"{ElementType.Name}[{RawType.GetArrayRank()}]",
Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST => $"{ElementType.Name}<{string.Join(", ", GenericArguments.Select(a => a.Name))}>",
Il2CppTypeEnum.IL2CPP_TYPE_VAR => GenericParameter!.Name!,
Il2CppTypeEnum.IL2CPP_TYPE_MVAR => GenericParameter!.Name!,
_ => throw new ArgumentOutOfRangeException(),
};

protected override int CustomAttributeIndex => -1;

public sealed override bool IsGenericInstance => GenericArguments.Count > 0;
Expand All @@ -41,14 +24,13 @@ public abstract class ReferencedTypeAnalysisContext : TypeAnalysisContext

public override AssemblyAnalysisContext CustomAttributeAssembly => DeclaringAssembly;

protected ReferencedTypeAnalysisContext(Il2CppType rawType, AssemblyAnalysisContext referencedFrom) : base(null, referencedFrom)
protected ReferencedTypeAnalysisContext(AssemblyAnalysisContext referencedFrom) : base(null, referencedFrom)
{
RawType = rawType;
}

public override string ToString()
{
return $"{DefaultName}";
return DefaultName;
}

public override string GetCSharpSourceString()
Expand Down
27 changes: 27 additions & 0 deletions Cpp2IL.Core/Model/Contexts/SzArrayTypeAnalysisContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using AsmResolver.DotNet;
using AsmResolver.DotNet.Signatures.Types;
using Cpp2IL.Core.Utils;
using LibCpp2IL.BinaryStructures;

namespace Cpp2IL.Core.Model.Contexts;

public class SzArrayTypeAnalysisContext : WrappedTypeAnalysisContext
{
public SzArrayTypeAnalysisContext(TypeAnalysisContext elementType, AssemblyAnalysisContext referencedFrom) : base(elementType, referencedFrom)
{
}

public SzArrayTypeAnalysisContext(Il2CppType rawType, AssemblyAnalysisContext referencedFrom)
: this(referencedFrom.ResolveIl2CppType(rawType.GetEncapsulatedType()), referencedFrom)
{
}

public override Il2CppTypeEnum Type => Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY;

public override string DefaultName => $"{ElementType.Name}[]";

public override TypeSignature ToTypeSignature(ModuleDefinition parentModule)
{
return ElementType.ToTypeSignature(parentModule).MakeSzArrayType();
}
}
9 changes: 9 additions & 0 deletions Cpp2IL.Core/Model/Contexts/TypeAnalysisContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
using System.Linq;
using System.Reflection;
using System.Text;
using AsmResolver.DotNet;
using AsmResolver.DotNet.Signatures.Types;
using Cpp2IL.Core.Api;
using Cpp2IL.Core.Utils;
using LibCpp2IL.BinaryStructures;
Expand Down Expand Up @@ -141,6 +143,13 @@ public TypeAnalysisContext(Il2CppTypeDefinition? il2CppTypeDefinition, AssemblyA
public List<MethodAnalysisContext> GetConstructors() => Methods.Where(m => m.Definition!.Name == ".ctor").ToList();

public override string ToString() => $"Type: {Definition?.FullName}";

public virtual TypeSignature ToTypeSignature(ModuleDefinition parentModule)
{
var typeDefinition = GetExtraData<TypeDefinition>("AsmResolverType") ?? throw new($"AsmResolver type not found in type analysis context for {FullName}");
return parentModule.DefaultImporter.ImportType(typeDefinition).ToTypeSignature();
}

public virtual string GetCSharpSourceString()
{
if (Definition != null)
Expand Down
Loading
Loading