Skip to content

Commit 774a8b9

Browse files
ds5678SamboyCoding
authored andcommitted
Change the meaning of MethodAnalysisContext::Overrides
It now specifically refers to methods that use `.override` in IL.
1 parent 6ee2710 commit 774a8b9

File tree

3 files changed

+76
-62
lines changed

3 files changed

+76
-62
lines changed

Cpp2IL.Core.Tests/MethodOverridesTests.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,24 @@ public void OverridesTests()
1818
{
1919
// Simple override
2020
Assert.That(@enum.GetMethod("ToString", 0).BaseMethod, Is.Not.Null);
21-
Assert.That(@enum.GetMethod("ToString", 0).Overrides.Count(), Is.EqualTo(1));
21+
Assert.That(@enum.GetMethod("ToString", 0).Overrides, Is.Empty);
2222

2323
// Simple interface implementation
2424
Assert.That(list.GetMethod("get_Count").BaseMethod, Is.Null);
25-
Assert.That(list.GetMethod("get_Count").Overrides.Count(), Is.EqualTo(3)); // ICollection, ICollection<T>, IReadOnlyCollection<T>
25+
Assert.That(list.GetMethod("get_Count").Overrides, Has.Count.EqualTo(3)); // ICollection, ICollection<T>, IReadOnlyCollection<T>
2626

2727
// Explicit interface implementation
28-
Assert.That(list.GetMethod("System.Collections.Generic.ICollection<T>.get_IsReadOnly").Overrides.Count(), Is.EqualTo(1));
28+
Assert.That(list.GetMethod("System.Collections.Generic.ICollection<T>.get_IsReadOnly").Overrides, Has.Count.EqualTo(1));
2929

3030
// No override
31-
Assert.That(list.GetMethod("EnsureCapacity").Overrides.Count(), Is.EqualTo(0));
31+
Assert.That(list.GetMethod("EnsureCapacity").Overrides, Is.Empty);
3232

3333
// Check that the base method can be found even if higher up in the inheritance chain.
3434
// OrdinalComparer inherits from StringComparer, but StringComparer doesn't override GetHashCode.
3535
Assert.That(ordinalComparer.GetMethod("GetHashCode", 0).BaseMethod?.DeclaringType?.FullName, Is.EqualTo("System.Object"));
3636

3737
// Interface methods should not override anything
38-
Assert.That(iList.Methods.Select(m => m.Overrides.Count()), Is.All.EqualTo(0));
38+
Assert.That(iList.Methods.Select(m => m.Overrides.Count), Is.All.EqualTo(0));
3939
}
4040
}
4141

Cpp2IL.Core/Model/Contexts/MethodAnalysisContext.cs

Lines changed: 56 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -136,12 +136,41 @@ public TypeAnalysisContext ReturnType
136136

137137
protected Memory<byte>? rawMethodBody;
138138

139-
public MethodAnalysisContext? BaseMethod => Overrides.FirstOrDefault(m => m.DeclaringType?.IsInterface is false);
139+
public MethodAnalysisContext? BaseMethod
140+
{
141+
get
142+
{
143+
if (Definition == null)
144+
return null;
145+
146+
var vtable = DeclaringType?.Definition?.VTable;
147+
if (vtable == null)
148+
return null;
149+
150+
for (var i = 0; i < vtable.Length; ++i)
151+
{
152+
var vtableEntry = vtable[i];
153+
if (vtableEntry is null or { Type: not MetadataUsageType.MethodDef } || vtableEntry.AsMethod() != Definition)
154+
continue;
155+
156+
var baseType = DeclaringType?.DefaultBaseType;
157+
while (baseType is not null)
158+
{
159+
if (TryGetMethodForSlot(baseType, i, out var method))
160+
{
161+
return method;
162+
}
163+
baseType = baseType.DefaultBaseType;
164+
}
165+
}
166+
return null;
167+
}
168+
}
140169

141170
private List<MethodAnalysisContext>? _overrides;
142171

143172
/// <summary>
144-
/// The set of methods which this method overrides.
173+
/// The set of interface methods which this method explicitly overrides.
145174
/// </summary>
146175
public List<MethodAnalysisContext> Overrides
147176
{
@@ -167,31 +196,6 @@ private IEnumerable<MethodAnalysisContext> GetOverrides()
167196

168197
return GetOverriddenMethods(declaringTypeDefinition, vtable);
169198

170-
bool TryGetMethodForSlot(TypeAnalysisContext declaringType, int slot, [NotNullWhen(true)] out MethodAnalysisContext? method)
171-
{
172-
if (declaringType is GenericInstanceTypeAnalysisContext genericInstanceType)
173-
{
174-
var genericMethod = genericInstanceType.GenericType.Methods.FirstOrDefault(m => m.Slot == slot);
175-
if (genericMethod is not null)
176-
{
177-
method = new ConcreteGenericMethodAnalysisContext(genericMethod, genericInstanceType.GenericArguments, []);
178-
return true;
179-
}
180-
}
181-
else
182-
{
183-
var baseMethod = declaringType.Methods.FirstOrDefault(m => m.Slot == slot);
184-
if (baseMethod is not null)
185-
{
186-
method = baseMethod;
187-
return true;
188-
}
189-
}
190-
191-
method = null;
192-
return false;
193-
}
194-
195199
IEnumerable<MethodAnalysisContext> GetOverriddenMethods(Il2CppTypeDefinition declaringTypeDefinition, MetadataUsage?[] vtable)
196200
{
197201
for (var i = 0; i < vtable.Length; ++i)
@@ -203,18 +207,6 @@ IEnumerable<MethodAnalysisContext> GetOverriddenMethods(Il2CppTypeDefinition dec
203207
if (vtableEntry.AsMethod() != Definition)
204208
continue;
205209

206-
// Normal inheritance
207-
var baseType = DeclaringType?.DefaultBaseType;
208-
while (baseType is not null)
209-
{
210-
if (TryGetMethodForSlot(baseType, i, out var method))
211-
{
212-
yield return method;
213-
break; // We only want direct overrides, not the entire inheritance chain.
214-
}
215-
baseType = baseType.DefaultBaseType;
216-
}
217-
218210
// Interface inheritance
219211
foreach (var interfaceOffset in declaringTypeDefinition.InterfaceOffsets)
220212
{
@@ -231,6 +223,31 @@ IEnumerable<MethodAnalysisContext> GetOverriddenMethods(Il2CppTypeDefinition dec
231223
}
232224
}
233225

226+
private static bool TryGetMethodForSlot(TypeAnalysisContext declaringType, int slot, [NotNullWhen(true)] out MethodAnalysisContext? method)
227+
{
228+
if (declaringType is GenericInstanceTypeAnalysisContext genericInstanceType)
229+
{
230+
var genericMethod = genericInstanceType.GenericType.Methods.FirstOrDefault(m => m.Slot == slot);
231+
if (genericMethod is not null)
232+
{
233+
method = new ConcreteGenericMethodAnalysisContext(genericMethod, genericInstanceType.GenericArguments, []);
234+
return true;
235+
}
236+
}
237+
else
238+
{
239+
var baseMethod = declaringType.Methods.FirstOrDefault(m => m.Slot == slot);
240+
if (baseMethod is not null)
241+
{
242+
method = baseMethod;
243+
return true;
244+
}
245+
}
246+
247+
method = null;
248+
return false;
249+
}
250+
234251
private static readonly List<IBlockProcessor> blockProcessors =
235252
[
236253
new MetadataProcessor(),

Cpp2IL.Core/Utils/AsmResolver/AsmResolverAssemblyPopulator.cs

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -533,26 +533,23 @@ private static void AddExplicitInterfaceImplementations(TypeDefinition type, Typ
533533

534534
foreach (var overrideContext in methodContext.Overrides)
535535
{
536-
if (overrideContext.DeclaringType?.IsInterface ?? false)
536+
var interfaceMethod = (IMethodDefOrRef)overrideContext.ToMethodDescriptor(importer.TargetModule);
537+
var method = methodContext.GetExtraData<MethodDefinition>("AsmResolverMethod") ?? throw new($"AsmResolver method not found in method analysis context for {methodContext}");
538+
type.MethodImplementations.Add(new MethodImplementation(interfaceMethod, method));
539+
var interfaceMethodResolved = interfaceMethod.Resolve();
540+
if (interfaceMethodResolved != null)
537541
{
538-
var interfaceMethod = (IMethodDefOrRef)overrideContext.ToMethodDescriptor(importer.TargetModule);
539-
var method = methodContext.GetExtraData<MethodDefinition>("AsmResolverMethod") ?? throw new($"AsmResolver method not found in method analysis context for {methodContext}");
540-
type.MethodImplementations.Add(new MethodImplementation(interfaceMethod, method));
541-
var interfaceMethodResolved = interfaceMethod.Resolve();
542-
if (interfaceMethodResolved != null)
542+
if (interfaceMethodResolved.IsGetMethod && !method.IsGetMethod)
543543
{
544-
if (interfaceMethodResolved.IsGetMethod && !method.IsGetMethod)
545-
{
546-
getMethodsToCreate ??= [];
547-
var interfacePropertyResolved = interfaceMethodResolved.DeclaringType!.Properties.First(p => p.Semantics.Contains(interfaceMethodResolved.Semantics));
548-
getMethodsToCreate.Add((interfacePropertyResolved, interfaceMethod.DeclaringType!.ToTypeSignature(), method));
549-
}
550-
else if (interfaceMethodResolved.IsSetMethod && !method.IsSetMethod)
551-
{
552-
setMethodsToCreate ??= [];
553-
var interfacePropertyResolved = interfaceMethodResolved.DeclaringType!.Properties.First(p => p.Semantics.Contains(interfaceMethodResolved.Semantics));
554-
setMethodsToCreate.Add((interfacePropertyResolved, interfaceMethod.DeclaringType!.ToTypeSignature(), method));
555-
}
544+
getMethodsToCreate ??= [];
545+
var interfacePropertyResolved = interfaceMethodResolved.DeclaringType!.Properties.First(p => p.Semantics.Contains(interfaceMethodResolved.Semantics));
546+
getMethodsToCreate.Add((interfacePropertyResolved, interfaceMethod.DeclaringType!.ToTypeSignature(), method));
547+
}
548+
else if (interfaceMethodResolved.IsSetMethod && !method.IsSetMethod)
549+
{
550+
setMethodsToCreate ??= [];
551+
var interfacePropertyResolved = interfaceMethodResolved.DeclaringType!.Properties.First(p => p.Semantics.Contains(interfaceMethodResolved.Semantics));
552+
setMethodsToCreate.Add((interfacePropertyResolved, interfaceMethod.DeclaringType!.ToTypeSignature(), method));
556553
}
557554
}
558555
}

0 commit comments

Comments
 (0)