Skip to content
Open
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
4 changes: 0 additions & 4 deletions Cpp2IL.Core/Model/Contexts/InjectedMethodAnalysisContext.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System.Collections.Generic;
using System.Reflection;

namespace Cpp2IL.Core.Model.Contexts;
Expand All @@ -19,9 +18,6 @@ public class InjectedMethodAnalysisContext : MethodAnalysisContext

protected override int CustomAttributeIndex => -1;

public override IEnumerable<MethodAnalysisContext> Overrides => OverridesList;
public List<MethodAnalysisContext> OverridesList { get; } = [];

public InjectedMethodAnalysisContext(
TypeAnalysisContext parent,
string name,
Expand Down
114 changes: 61 additions & 53 deletions Cpp2IL.Core/Model/Contexts/MethodAnalysisContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,84 +122,92 @@ public override List<GenericParameterTypeAnalysisContext> GenericParameters

public MethodAnalysisContext? BaseMethod => Overrides.FirstOrDefault(m => m.DeclaringType?.IsInterface is false);

private List<MethodAnalysisContext>? _overrides;

/// <summary>
/// The set of methods which this method overrides.
/// </summary>
public virtual IEnumerable<MethodAnalysisContext> Overrides
public List<MethodAnalysisContext> Overrides
{
get
{
if (Definition == null)
return [];
// Lazy load the overrides
return _overrides ??= GetOverrides().ToList();
}
}

var declaringTypeDefinition = DeclaringType?.Definition;
if (declaringTypeDefinition == null)
return [];
private IEnumerable<MethodAnalysisContext> GetOverrides()
{
if (Definition == null)
return [];

var declaringTypeDefinition = DeclaringType?.Definition;
if (declaringTypeDefinition == null)
return [];

var vtable = declaringTypeDefinition.VTable;
if (vtable == null)
return [];
var vtable = declaringTypeDefinition.VTable;
if (vtable == null)
return [];

return GetOverriddenMethods(declaringTypeDefinition, vtable);
return GetOverriddenMethods(declaringTypeDefinition, vtable);

bool TryGetMethodForSlot(TypeAnalysisContext declaringType, int slot, [NotNullWhen(true)] out MethodAnalysisContext? method)
bool TryGetMethodForSlot(TypeAnalysisContext declaringType, int slot, [NotNullWhen(true)] out MethodAnalysisContext? method)
{
if (declaringType is GenericInstanceTypeAnalysisContext genericInstanceType)
{
if (declaringType is GenericInstanceTypeAnalysisContext genericInstanceType)
var genericMethod = genericInstanceType.GenericType.Methods.FirstOrDefault(m => m.Slot == slot);
if (genericMethod is not null)
{
var genericMethod = genericInstanceType.GenericType.Methods.FirstOrDefault(m => m.Slot == slot);
if (genericMethod is not null)
{
method = new ConcreteGenericMethodAnalysisContext(genericMethod, genericInstanceType.GenericArguments, []);
return true;
}
method = new ConcreteGenericMethodAnalysisContext(genericMethod, genericInstanceType.GenericArguments, []);
return true;
}
else
}
else
{
var baseMethod = declaringType.Methods.FirstOrDefault(m => m.Slot == slot);
if (baseMethod is not null)
{
var baseMethod = declaringType.Methods.FirstOrDefault(m => m.Slot == slot);
if (baseMethod is not null)
{
method = baseMethod;
return true;
}
method = baseMethod;
return true;
}

method = null;
return false;
}

IEnumerable<MethodAnalysisContext> GetOverriddenMethods(Il2CppTypeDefinition declaringTypeDefinition, MetadataUsage?[] vtable)
method = null;
return false;
}

IEnumerable<MethodAnalysisContext> GetOverriddenMethods(Il2CppTypeDefinition declaringTypeDefinition, MetadataUsage?[] vtable)
{
for (var i = 0; i < vtable.Length; ++i)
{
for (var i = 0; i < vtable.Length; ++i)
{
var vtableEntry = vtable[i];
if (vtableEntry is null or { Type: not MetadataUsageType.MethodDef })
continue;
var vtableEntry = vtable[i];
if (vtableEntry is null or { Type: not MetadataUsageType.MethodDef })
continue;

if (vtableEntry.AsMethod() != Definition)
continue;
if (vtableEntry.AsMethod() != Definition)
continue;

// Normal inheritance
var baseType = DeclaringType?.BaseType;
while (baseType is not null)
// Normal inheritance
var baseType = DeclaringType?.DefaultBaseType;
while (baseType is not null)
{
if (TryGetMethodForSlot(baseType, i, out var method))
{
if (TryGetMethodForSlot(baseType, i, out var method))
{
yield return method;
break; // We only want direct overrides, not the entire inheritance chain.
}
baseType = baseType.BaseType;
yield return method;
break; // We only want direct overrides, not the entire inheritance chain.
}
baseType = baseType.DefaultBaseType;
}

// Interface inheritance
foreach (var interfaceOffset in declaringTypeDefinition.InterfaceOffsets)
// Interface inheritance
foreach (var interfaceOffset in declaringTypeDefinition.InterfaceOffsets)
{
if (i >= interfaceOffset.offset)
{
if (i >= interfaceOffset.offset)
var interfaceTypeContext = interfaceOffset.Type.ToContext(CustomAttributeAssembly);
if (interfaceTypeContext != null && TryGetMethodForSlot(interfaceTypeContext, i - interfaceOffset.offset, out var method))
{
var interfaceTypeContext = interfaceOffset.Type.ToContext(CustomAttributeAssembly);
if (interfaceTypeContext != null && TryGetMethodForSlot(interfaceTypeContext, i - interfaceOffset.offset, out var method))
{
yield return method;
}
yield return method;
}
}
}
Expand Down
Loading