diff --git a/Cpp2IL.Core.Tests/MethodOverridesTests.cs b/Cpp2IL.Core.Tests/MethodOverridesTests.cs index 7d9c2c49..f3be0b76 100644 --- a/Cpp2IL.Core.Tests/MethodOverridesTests.cs +++ b/Cpp2IL.Core.Tests/MethodOverridesTests.cs @@ -1,5 +1,4 @@ using System.Linq; -using Cpp2IL.Core.Model.Contexts; namespace Cpp2IL.Core.Tests; @@ -39,4 +38,62 @@ public void OverridesTests() Assert.That(iList.Methods.Select(m => m.Overrides.Count()), Is.All.EqualTo(0)); } } + + [Test] + public void InterfaceMethodsShouldNotOverrideAnything() + { + var appContext = TestGameLoader.LoadSimple2019Game(); + + using (Assert.EnterMultipleScope()) + { + var count = 0; + foreach (var assembly in appContext.Assemblies) + { + foreach (var type in assembly.Types) + { + if (!type.IsInterface) + continue; + + foreach (var method in type.Methods) + { + if (!method.IsVirtual && !method.IsAbstract) + continue; + + if (method.IsStatic || !method.IsNewSlot) + continue; + + Assert.That(method.Overrides, Is.Empty); + count++; + } + } + } + Assert.That(count, Is.GreaterThan(0)); + } + } + + [Test] + public void InterfaceMethodsShouldHaveNoBaseMethod() + { + var appContext = TestGameLoader.LoadSimple2019Game(); + + using (Assert.EnterMultipleScope()) + { + var count = 0; + foreach (var assembly in appContext.Assemblies) + { + foreach (var type in assembly.Types) + { + if (!type.IsInterface) + continue; + + foreach (var method in type.Methods) + { + Assert.That(method.BaseMethod, Is.Null); + count++; + } + } + } + Assert.That(count, Is.GreaterThan(0)); + } + } } diff --git a/Cpp2IL.Core.Tests/TypeAnalysisContextTests.cs b/Cpp2IL.Core.Tests/TypeAnalysisContextTests.cs new file mode 100644 index 00000000..e9d36ca6 --- /dev/null +++ b/Cpp2IL.Core.Tests/TypeAnalysisContextTests.cs @@ -0,0 +1,52 @@ +namespace Cpp2IL.Core.Tests; + +public class TypeAnalysisContextTests +{ + [Test] + public void InterfacesHaveNoBaseType() + { + var appContext = TestGameLoader.LoadSimple2019Game(); + + using (Assert.EnterMultipleScope()) + { + var count = 0; + foreach (var assembly in appContext.Assemblies) + { + foreach (var type in assembly.Types) + { + if (!type.IsInterface) + continue; + + Assert.That(type.DefaultBaseType, Is.Null); + Assert.That(type.BaseType, Is.Null); + count++; + } + } + Assert.That(count, Is.GreaterThan(0)); + } + } + + [Test] + public void StaticClassesHaveObjectBaseType() + { + var appContext = TestGameLoader.LoadSimple2019Game(); + + using (Assert.EnterMultipleScope()) + { + var count = 0; + foreach (var assembly in appContext.Assemblies) + { + foreach (var type in assembly.Types) + { + if (!type.IsStatic) + continue; + + Assert.That(type.DefaultBaseType, Is.EqualTo(appContext.SystemTypes.SystemObjectType)); + Assert.That(type.BaseType, Is.EqualTo(appContext.SystemTypes.SystemObjectType)); + count++; + } + } + Assert.That(count, Is.GreaterThan(0)); + } + } +} diff --git a/Cpp2IL.Core/Model/Contexts/MethodAnalysisContext.cs b/Cpp2IL.Core/Model/Contexts/MethodAnalysisContext.cs index e20e75a7..4be56dce 100644 --- a/Cpp2IL.Core/Model/Contexts/MethodAnalysisContext.cs +++ b/Cpp2IL.Core/Model/Contexts/MethodAnalysisContext.cs @@ -64,6 +64,10 @@ public class MethodAnalysisContext : HasGenericParameters, IMethodInfoProvider public bool IsVirtual => (Attributes & MethodAttributes.Virtual) != 0; + public bool IsAbstract => (Attributes & MethodAttributes.Abstract) != 0; + + public bool IsNewSlot => (Attributes & MethodAttributes.NewSlot) != 0; + protected override int CustomAttributeIndex => Definition?.customAttributeIndex ?? throw new("Subclasses of MethodAnalysisContext should override CustomAttributeIndex if they have custom attributes"); public override AssemblyAnalysisContext CustomAttributeAssembly => DeclaringType?.DeclaringAssembly ?? throw new("Subclasses of MethodAnalysisContext should override CustomAttributeAssembly if they have custom attributes"); diff --git a/Cpp2IL.Core/Model/Contexts/TypeAnalysisContext.cs b/Cpp2IL.Core/Model/Contexts/TypeAnalysisContext.cs index 1bb0e9ff..a7f2aeec 100644 --- a/Cpp2IL.Core/Model/Contexts/TypeAnalysisContext.cs +++ b/Cpp2IL.Core/Model/Contexts/TypeAnalysisContext.cs @@ -71,7 +71,7 @@ public class TypeAnalysisContext : HasGenericParameters, ITypeInfoProvider, ICSh public TypeAttributes Attributes => OverrideAttributes ?? DefaultAttributes; - public virtual TypeAnalysisContext? DefaultBaseType => Definition == null ? null : DeclaringAssembly.ResolveIl2CppType(Definition.RawBaseType); + public virtual TypeAnalysisContext? DefaultBaseType => Definition == null || DefaultAttributes.HasFlag(TypeAttributes.Interface) ? null : DeclaringAssembly.ResolveIl2CppType(Definition.RawBaseType); public TypeAnalysisContext? OverrideBaseType { get; set; }