Skip to content

Commit

Permalink
Merge pull request #592 from Washi1337/issue/include-semantic-members
Browse files Browse the repository at this point in the history
BUGFIX: Include semantic member owners in ClonedMembers
  • Loading branch information
Washi1337 authored Nov 25, 2024
2 parents 48a472f + dae96ca commit bb04d6b
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 15 deletions.
22 changes: 13 additions & 9 deletions src/AsmResolver.DotNet/Cloning/MemberCloner.Semantics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ private void DeepCopyProperties(MemberCloneContext context)
{
declaringType.Properties.Add(clonedProperty);
}
var clonedMember = clonedProperty;
_listeners.OnClonedMember(property, clonedMember);
_listeners.OnClonedProperty(property, clonedMember);

context.ClonedMembers.Add(property, clonedProperty);
_listeners.OnClonedMember(property, clonedProperty);
_listeners.OnClonedProperty(property, clonedProperty);
}
}

Expand Down Expand Up @@ -54,9 +55,10 @@ private void DeepCopyEvents(MemberCloneContext context)
{
declaringType.Events.Add(clonedEvent);
}
var clonedMember = clonedEvent;
_listeners.OnClonedMember(@event, clonedMember);
_listeners.OnClonedEvent(@event, clonedMember);

context.ClonedMembers.Add(@event, clonedEvent);
_listeners.OnClonedMember(@event, clonedEvent);
_listeners.OnClonedEvent(@event, clonedEvent);
}
}

Expand All @@ -82,9 +84,11 @@ private static void CloneSemantics(MemberCloneContext context, IHasSemantics sem
{
foreach (var semantics in semanticsProvider.Semantics)
{
clonedProvider.Semantics.Add(new MethodSemantics(
(MethodDefinition) context.ClonedMembers[semantics.Method!],
semantics.Attributes));
if (context.ClonedMembers.TryGetValue(semantics.Method!, out var m)
&& m is MethodDefinition semanticMethod)
{
clonedProvider.Semantics.Add(new MethodSemantics(semanticMethod, semantics.Attributes));
}
}
}
}
Expand Down
33 changes: 31 additions & 2 deletions src/AsmResolver.DotNet/Cloning/MemberCloner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -245,9 +245,19 @@ public MemberCloner Include(FieldDefinition field)
/// </summary>
/// <param name="property">The property to include.</param>
/// <returns>The metadata cloner that the property is added to.</returns>
public MemberCloner Include(PropertyDefinition property)
public MemberCloner Include(PropertyDefinition property) => Include(property, true);

/// <summary>
/// Adds a single property to the list of members to clone.
/// </summary>
/// <param name="property">The property to include.</param>
/// <param name="recursive">Indicates the attached semantic methods (getters and setters) should be included.</param>
/// <returns>The metadata cloner that the property is added to.</returns>
public MemberCloner Include(PropertyDefinition property, bool recursive)
{
_propertiesToClone.Add(property);
if (recursive)
IncludeSemantics(property);
return this;
}

Expand All @@ -256,12 +266,31 @@ public MemberCloner Include(PropertyDefinition property)
/// </summary>
/// <param name="event">The event to include.</param>
/// <returns>The metadata cloner that the event is added to.</returns>
public MemberCloner Include(EventDefinition @event)
public MemberCloner Include(EventDefinition @event) => Include(@event, true);

/// <summary>
/// Adds a single event to the list of members to clone.
/// </summary>
/// <param name="event">The event to include.</param>
/// <param name="recursive">Indicates the attached semantic methods (add, remove, fire) should be included.</param>
/// <returns>The metadata cloner that the property is added to.</returns>
public MemberCloner Include(EventDefinition @event, bool recursive)
{
_eventsToClone.Add(@event);
if (recursive)
IncludeSemantics(@event);
return this;
}

private void IncludeSemantics(IHasSemantics member)
{
foreach (var semantic in member.Semantics)
{
if (semantic.Method is not null)
_methodsToClone.Add(semantic.Method);
}
}

/// <summary>
/// Adds a member cloner listener to the cloner.
/// </summary>
Expand Down
39 changes: 35 additions & 4 deletions test/AsmResolver.DotNet.Tests/Cloning/MetadataClonerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using AsmResolver.DotNet.TestCases.Fields;
using AsmResolver.DotNet.TestCases.Generics;
using AsmResolver.DotNet.TestCases.Methods;
using AsmResolver.DotNet.TestCases.Properties;
using AsmResolver.DotNet.TestCases.Types;
using AsmResolver.PE.DotNet.Cil;
using AsmResolver.Tests.Listeners;
Expand Down Expand Up @@ -38,7 +39,7 @@ private static ModuleDefinition PrepareTempModule()
private static TypeDefinition CloneType(Type type, out TypeDefinition originalTypeDef)
{
var sourceModule = ModuleDefinition.FromFile(type.Module.Assembly.Location, TestReaderParameters);
originalTypeDef= (TypeDefinition) sourceModule.LookupMember(type.MetadataToken);
originalTypeDef= sourceModule.LookupMember<TypeDefinition>(type.MetadataToken);

var targetModule = PrepareTempModule();

Expand All @@ -60,23 +61,41 @@ private static TypeDefinition CloneType(Type type, out TypeDefinition originalTy
private static MethodDefinition CloneMethod(MethodBase methodBase, out MethodDefinition originalMethodDef)
{
var sourceModule = ModuleDefinition.FromFile(methodBase.Module.Assembly.Location, TestReaderParameters);
originalMethodDef = (MethodDefinition) sourceModule.LookupMember(methodBase.MetadataToken);
originalMethodDef = sourceModule.LookupMember<MethodDefinition>(methodBase.MetadataToken);

var targetModule = PrepareTempModule();

var result = new MemberCloner(targetModule)
.Include(originalMethodDef)
.Clone();


var clonedMethod = (MethodDefinition) result.ClonedMembers.First();
var clonedMethod = result.ClonedMembers.OfType<MethodDefinition>().First();

Assert.True(result.ContainsClonedMember(originalMethodDef));
Assert.Equal(clonedMethod, result.GetClonedMember(originalMethodDef));

return clonedMethod;
}

private static PropertyDefinition CloneProperty(PropertyInfo property, out PropertyDefinition originalProperty)
{
var sourceModule = ModuleDefinition.FromFile(property.Module.Assembly.Location, TestReaderParameters);
originalProperty = sourceModule.LookupMember<PropertyDefinition>(property.MetadataToken);

var targetModule = PrepareTempModule();

var result = new MemberCloner(targetModule)
.Include(originalProperty)
.Clone();

var clonedProperty = result.ClonedMembers.OfType<PropertyDefinition>().First();

Assert.True(result.ContainsClonedMember(originalProperty));
Assert.Equal(clonedProperty, result.GetClonedMember(originalProperty));

return clonedProperty;
}

private static FieldDefinition CloneInitializerField(FieldInfo field, out FieldDefinition originalFieldDef)
{
var sourceModule = ModuleDefinition.FromFile(field.Module.Assembly.Location, TestReaderParameters);
Expand Down Expand Up @@ -255,6 +274,18 @@ public void ReferencesToMethodSpecs()
Assert.NotSame(originalSpec.Module, newSpec.Module);
}

[Fact]
public void CloneSemantics()
{
var clonedProperty = CloneProperty(typeof(SingleProperty).GetProperty(nameof(SingleProperty.IntProperty)), out var originalProperty);

Assert.Equal(originalProperty.Name, clonedProperty.Name);
Assert.Equal(
originalProperty.Semantics.Select(x => x.Method!.Name),
clonedProperty.Semantics.Select(x => x.Method!.Name)
);
}

[Fact]
public void CloneImplMap()
{
Expand Down

0 comments on commit bb04d6b

Please sign in to comment.