Skip to content

Commit

Permalink
#470 Improved handling of sibling interfaces (#471)
Browse files Browse the repository at this point in the history
* #470 Improved handling of sibling interfaces
* Merged redundant linq calls
  • Loading branch information
mkaring authored Apr 6, 2022
1 parent 8d0a650 commit d4edb5c
Show file tree
Hide file tree
Showing 15 changed files with 190 additions and 18 deletions.
30 changes: 20 additions & 10 deletions Confuser.Renamer/Analyzers/VTableAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,17 @@ public static void Analyze(INameService service, ICollection<ModuleDefMD> module
// case here.
if (!TypeEqualityComparer.Instance.Equals(slot.MethodDef.DeclaringType, type)) {
SetupOverwriteReferences(service, modules, slot, type);
//CreateOverrideReference(service, slot.MethodDef, slot.Overrides.MethodDef);

// If required, create the sibling references, so the names of the interfaces line up correctly.
var existingReferences = service.GetReferences(slot.MethodDef);
var overrideDef = existingReferences
.OfType<MemberOverrideReference>()
.FirstOrDefault(r => !MethodEqualityComparer.CompareDeclaringTypes.Equals(r.BaseMemberDef as MethodDef, slot.Overrides.MethodDef));

if (!(overrideDef is null)) {
var baseMemberDef = overrideDef.BaseMemberDef;
CreateSiblingReference(slot.Overrides.MethodDef, ref baseMemberDef, service);
}
}

// For the case when method in base type implements an interface method for a derived type
Expand All @@ -67,9 +77,6 @@ public static void Analyze(INameService service, ICollection<ModuleDefMD> module
if (!method.IsVirtual)
return;

var vTbl = service.GetVTables()[method.DeclaringType];
var slots = vTbl.FindSlots(method).ToArray();

IMemberDef discoveredBaseMemberDef = null;
MethodDef discoveredBaseMethodDef = null;

Expand Down Expand Up @@ -118,6 +125,9 @@ public static void Analyze(INameService service, ICollection<ModuleDefMD> module
}

if (!method.IsAbstract) {
var vTbl = service.GetVTables()[method.DeclaringType];
var slots = vTbl.FindSlots(method).ToArray();

foreach (var slot in slots) {
if (slot.Overrides == null)
continue;
Expand All @@ -132,9 +142,9 @@ public static void Analyze(INameService service, ICollection<ModuleDefMD> module
}
}

static void CreateSiblingReference<T>(T basePropDef, ref T discoveredBaseMemberDef, INameService service) where T : class, IMemberDef {
static void CreateSiblingReference<T>(T baseMemberDef, ref T discoveredBaseMemberDef, INameService service) where T : class, IMemberDef {
if (discoveredBaseMemberDef is null)
discoveredBaseMemberDef = basePropDef;
discoveredBaseMemberDef = baseMemberDef;
else {
var references = service.GetReferences(discoveredBaseMemberDef)
.OfType<MemberSiblingReference>()
Expand All @@ -148,12 +158,12 @@ static void CreateSiblingReference<T>(T basePropDef, ref T discoveredBaseMemberD
}

// Check if the discovered base type is the current type. If so, nothing needs to be done.
if (ReferenceEquals(basePropDef, discoveredBaseMemberDef)) return;
if (ReferenceEquals(baseMemberDef, discoveredBaseMemberDef)) return;

var reference = new MemberSiblingReference(basePropDef, discoveredBaseMemberDef);
service.AddReference(basePropDef, reference);
var reference = new MemberSiblingReference(baseMemberDef, discoveredBaseMemberDef);
service.AddReference(baseMemberDef, reference);
service.AddReference(discoveredBaseMemberDef, reference);
UpdateOldestSiblingReference(discoveredBaseMemberDef, basePropDef, service);
UpdateOldestSiblingReference(discoveredBaseMemberDef, baseMemberDef, service);
}
}

Expand Down
12 changes: 6 additions & 6 deletions Confuser.Renamer/References/MemberOverrideReference.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@

namespace Confuser.Renamer.References {
public sealed class MemberOverrideReference : INameReference<IDnlibDef> {
readonly IMemberDef thisMemberDef;
internal IMemberDef ThisMemberDef { get; }
internal IMemberDef BaseMemberDef { get; }

public bool ShouldCancelRename => thisMemberDef.Module != BaseMemberDef.Module;
public bool ShouldCancelRename => ThisMemberDef.Module != BaseMemberDef.Module;

public MemberOverrideReference(IMemberDef thisMemberDef, IMemberDef baseMemberDef) {
this.thisMemberDef = thisMemberDef ?? throw new ArgumentNullException(nameof(thisMemberDef));
ThisMemberDef = thisMemberDef ?? throw new ArgumentNullException(nameof(thisMemberDef));
BaseMemberDef = baseMemberDef ?? throw new ArgumentNullException(nameof(baseMemberDef));
Debug.Assert(thisMemberDef != baseMemberDef);
}
Expand All @@ -24,8 +24,8 @@ public bool DelayRenaming(INameService service, IDnlibDef currentDef) =>
&& !service.IsRenamed(BaseMemberDef);

public bool UpdateNameReference(ConfuserContext context, INameService service) {
if (UTF8String.Equals(thisMemberDef.Name, BaseMemberDef.Name)) return false;
thisMemberDef.Name = BaseMemberDef.Name;
if (UTF8String.Equals(ThisMemberDef.Name, BaseMemberDef.Name)) return false;
ThisMemberDef.Name = BaseMemberDef.Name;
return true;
}

Expand All @@ -34,7 +34,7 @@ public bool UpdateNameReference(ConfuserContext context, INameService service) {
public string ToString(INameService nameService) {
var builder = new StringBuilder();
builder.Append("Member Override Reference").Append("(");
builder.Append("This ").AppendReferencedDef(thisMemberDef, nameService);
builder.Append("This ").AppendReferencedDef(ThisMemberDef, nameService);
builder.Append("; ");
builder.Append("Base ").AppendReferencedDef(BaseMemberDef, nameService);
builder.Append(")");
Expand Down
34 changes: 32 additions & 2 deletions Confuser2.sln
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlockingReferencesHelper",
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlockingReferences.Test", "Tests\BlockingReferences.Test\BlockingReferences.Test.csproj", "{4FB03AD0-96FF-4730-801A-4F997795D920}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "421_NewtonsoftJsonSerialization", "Tests\421_NewtonsoftJsonSerialization\421_NewtonsoftJsonSerialization.csproj", "{4EF73752-78B0-4E0D-A33B-B6637B6C2177}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "421_NewtonsoftJsonSerialization", "Tests\421_NewtonsoftJsonSerialization\421_NewtonsoftJsonSerialization.csproj", "{4EF73752-78B0-4E0D-A33B-B6637B6C2177}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "421_NewtonsoftJsonSerialization.Test", "Tests\421_NewtonsoftJsonSerialization.Test\421_NewtonsoftJsonSerialization.Test.csproj", "{B1CB9A30-FEA6-4467-BEC5-4803CCE9BF78}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "421_NewtonsoftJsonSerialization.Test", "Tests\421_NewtonsoftJsonSerialization.Test\421_NewtonsoftJsonSerialization.Test.csproj", "{B1CB9A30-FEA6-4467-BEC5-4803CCE9BF78}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "470_ImplementationInBaseClass", "Tests\470_ImplementationInBaseClass\470_ImplementationInBaseClass.csproj", "{5D10ED0A-6C52-49FE-90F5-CFAAECA8FABE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "470_ImplementationInBaseClass.Test", "Tests\470_ImplementationInBaseClass.Test\470_ImplementationInBaseClass.Test.csproj", "{F7581FB4-FAF5-4CD0-888A-B588F5BC69CD}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -937,6 +941,30 @@ Global
{B1CB9A30-FEA6-4467-BEC5-4803CCE9BF78}.Release|x64.Build.0 = Release|Any CPU
{B1CB9A30-FEA6-4467-BEC5-4803CCE9BF78}.Release|x86.ActiveCfg = Release|Any CPU
{B1CB9A30-FEA6-4467-BEC5-4803CCE9BF78}.Release|x86.Build.0 = Release|Any CPU
{5D10ED0A-6C52-49FE-90F5-CFAAECA8FABE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5D10ED0A-6C52-49FE-90F5-CFAAECA8FABE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5D10ED0A-6C52-49FE-90F5-CFAAECA8FABE}.Debug|x64.ActiveCfg = Debug|Any CPU
{5D10ED0A-6C52-49FE-90F5-CFAAECA8FABE}.Debug|x64.Build.0 = Debug|Any CPU
{5D10ED0A-6C52-49FE-90F5-CFAAECA8FABE}.Debug|x86.ActiveCfg = Debug|Any CPU
{5D10ED0A-6C52-49FE-90F5-CFAAECA8FABE}.Debug|x86.Build.0 = Debug|Any CPU
{5D10ED0A-6C52-49FE-90F5-CFAAECA8FABE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5D10ED0A-6C52-49FE-90F5-CFAAECA8FABE}.Release|Any CPU.Build.0 = Release|Any CPU
{5D10ED0A-6C52-49FE-90F5-CFAAECA8FABE}.Release|x64.ActiveCfg = Release|Any CPU
{5D10ED0A-6C52-49FE-90F5-CFAAECA8FABE}.Release|x64.Build.0 = Release|Any CPU
{5D10ED0A-6C52-49FE-90F5-CFAAECA8FABE}.Release|x86.ActiveCfg = Release|Any CPU
{5D10ED0A-6C52-49FE-90F5-CFAAECA8FABE}.Release|x86.Build.0 = Release|Any CPU
{F7581FB4-FAF5-4CD0-888A-B588F5BC69CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F7581FB4-FAF5-4CD0-888A-B588F5BC69CD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F7581FB4-FAF5-4CD0-888A-B588F5BC69CD}.Debug|x64.ActiveCfg = Debug|Any CPU
{F7581FB4-FAF5-4CD0-888A-B588F5BC69CD}.Debug|x64.Build.0 = Debug|Any CPU
{F7581FB4-FAF5-4CD0-888A-B588F5BC69CD}.Debug|x86.ActiveCfg = Debug|Any CPU
{F7581FB4-FAF5-4CD0-888A-B588F5BC69CD}.Debug|x86.Build.0 = Debug|Any CPU
{F7581FB4-FAF5-4CD0-888A-B588F5BC69CD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F7581FB4-FAF5-4CD0-888A-B588F5BC69CD}.Release|Any CPU.Build.0 = Release|Any CPU
{F7581FB4-FAF5-4CD0-888A-B588F5BC69CD}.Release|x64.ActiveCfg = Release|Any CPU
{F7581FB4-FAF5-4CD0-888A-B588F5BC69CD}.Release|x64.Build.0 = Release|Any CPU
{F7581FB4-FAF5-4CD0-888A-B588F5BC69CD}.Release|x86.ActiveCfg = Release|Any CPU
{F7581FB4-FAF5-4CD0-888A-B588F5BC69CD}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -999,6 +1027,8 @@ Global
{4FB03AD0-96FF-4730-801A-4F997795D920} = {356BDB31-853E-43BB-8F9A-D8AC08F69EBB}
{4EF73752-78B0-4E0D-A33B-B6637B6C2177} = {356BDB31-853E-43BB-8F9A-D8AC08F69EBB}
{B1CB9A30-FEA6-4467-BEC5-4803CCE9BF78} = {356BDB31-853E-43BB-8F9A-D8AC08F69EBB}
{5D10ED0A-6C52-49FE-90F5-CFAAECA8FABE} = {356BDB31-853E-43BB-8F9A-D8AC08F69EBB}
{F7581FB4-FAF5-4CD0-888A-B588F5BC69CD} = {356BDB31-853E-43BB-8F9A-D8AC08F69EBB}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0D937D9E-E04B-4A68-B639-D4260473A388}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net461</TargetFramework>
<RootNamespace>ImplementationInBaseClass.Test</RootNamespace>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Confuser.UnitTest\Confuser.UnitTest.csproj" />
<ProjectReference Include="..\470_ImplementationInBaseClass\470_ImplementationInBaseClass.csproj" />
</ItemGroup>

</Project>
46 changes: 46 additions & 0 deletions Tests/470_ImplementationInBaseClass.Test/RenameTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Confuser.Core;
using Confuser.Core.Project;
using Confuser.Renamer;
using Confuser.UnitTest;
using Xunit;
using Xunit.Abstractions;

namespace ImplementationInBaseClass.Test
{
public class RenameTest : TestBase
{
public RenameTest(ITestOutputHelper outputHelper) : base(outputHelper) { }

[Theory]
[MemberData(nameof(ResolveNameData))]
[Trait("Category", "Protection")]
[Trait("Protection", "rename")]
[Trait("Issue", "https://github.com/mkaring/ConfuserEx/issues/470")]
public async Task ResolveNameLoop(RenameMode mode, bool flatten) =>
await Run(
new[] {
"470_ImplementationInBaseClass.exe"
},
new[] {
"Called MyMethod",
"Called MyMethod",
"Called MyMethod",
"Called MyMethod"
},
new SettingItem<Protection>("rename") {
{ "mode", mode.ToString() },
{ "renPublic", "true" },
{ "flatten", flatten.ToString() }
},
$"_{mode}_{flatten}"
);

public static IEnumerable<object[]> ResolveNameData() {
foreach (var renameMode in new[] { RenameMode.Unicode, RenameMode.Sequential })
foreach (var flatten in new[] { true, false })
yield return new object[] { renameMode, flatten };
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net461</TargetFramework>
<RootNamespace>ImplementationInBaseClass</RootNamespace>
<LangVersion>7.3</LangVersion>
</PropertyGroup>

</Project>
5 changes: 5 additions & 0 deletions Tests/470_ImplementationInBaseClass/IMyInterfaceA.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace ImplementationInBaseClass {
public interface IMyInterfaceA {
void MyMethod();
}
}
5 changes: 5 additions & 0 deletions Tests/470_ImplementationInBaseClass/IMyInterfaceB.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace ImplementationInBaseClass {
public interface IMyInterfaceB {
void MyMethod();
}
}
5 changes: 5 additions & 0 deletions Tests/470_ImplementationInBaseClass/IMyInterfaceC.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace ImplementationInBaseClass {
public interface IMyInterfaceC {
void MyMethod();
}
}
7 changes: 7 additions & 0 deletions Tests/470_ImplementationInBaseClass/MyBaseClass.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
using System;

namespace ImplementationInBaseClass {
internal abstract class MyBaseClass {
public void MyMethod() => Console.WriteLine("Called " + nameof(MyMethod));
}
}
4 changes: 4 additions & 0 deletions Tests/470_ImplementationInBaseClass/MyClassA.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
namespace ImplementationInBaseClass {
internal class MyClassA : MyBaseClass, IMyInterfaceA {
}
}
4 changes: 4 additions & 0 deletions Tests/470_ImplementationInBaseClass/MyClassB.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
namespace ImplementationInBaseClass {
internal class MyClassB : MyBaseClass, IMyInterfaceB {
}
}
4 changes: 4 additions & 0 deletions Tests/470_ImplementationInBaseClass/MyClassB2.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
namespace ImplementationInBaseClass {
internal class MyClassB2 : MyBaseClass, IMyInterfaceB {
}
}
4 changes: 4 additions & 0 deletions Tests/470_ImplementationInBaseClass/MyClassC.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
namespace ImplementationInBaseClass {
internal class MyClassC : MyBaseClass, IMyInterfaceC {
}
}
24 changes: 24 additions & 0 deletions Tests/470_ImplementationInBaseClass/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System;

namespace ImplementationInBaseClass {
internal class Program {
internal static int Main(string[] args) {
Console.WriteLine("START");

var classA = new MyClassA();
classA.MyMethod();

var classB = new MyClassB();
classB.MyMethod();

var classB2 = new MyClassB2();
classB2.MyMethod();

var classC = new MyClassC();
classC.MyMethod();

Console.WriteLine("END");
return 42;
}
}
}

0 comments on commit d4edb5c

Please sign in to comment.