Skip to content

Commit

Permalink
Fix target object emit (#125)
Browse files Browse the repository at this point in the history
* Rewrite PopParent to properly reset PropertyTargetObject

* Add ProvideValueTarget_TargetObject_Is_Valid_After_Nested_PushPop test
  • Loading branch information
maxkatz6 authored Sep 14, 2024
1 parent e13c3ef commit e524acf
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 8 deletions.
28 changes: 20 additions & 8 deletions src/XamlX/IL/RuntimeContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -444,22 +444,34 @@ private void EmitPushPopParent(IXamlTypeBuilder<IXamlILEmitter> builder, IXamlTy
.LdThisFld(parentListField)
.EmitCall(objectListType.GetMethod(m => m.Name == "get_Count"))
.Ldc_I4(1).Emit(OpCodes.Sub).Stloc(idx);
// this.PropertyTargetObject = _parents[idx];

pop
// _parents.RemoveAt(idx);
.LdThisFld(parentListField)
.Ldloc(idx)
.EmitCall(objectListType.GetMethod(m => m.Name == "RemoveAt"));

// this.PropertyTargetObject = idx != 0 ? _parents[idx - 1] : null;
if (TargetObjectField != null)
{
var elseLabel = pop.DefineLabel();
var endIfLabel = pop.DefineLabel();
pop
.Ldarg_0()
.LdThisFld(parentListField)
.Ldarg(0)
.Ldloc(idx)
.Brfalse(elseLabel) // if `idx != 0`
.LdThisFld(parentListField) // then '_parents[idx - 1]'
.Ldloc(idx)
.Ldc_I4(1).Emit(OpCodes.Sub)
.EmitCall(objectListType.GetMethod(m => m.Name == "get_Item"))
.Br(endIfLabel)
.MarkLabel(elseLabel) // else
.Ldnull() // then 'null'
.MarkLabel(endIfLabel) // endif
.Stfld(TargetObjectField);
}
// _parents.RemoveAt(idx);
pop
.LdThisFld(parentListField)
.Ldloc(idx).EmitCall(objectListType.GetMethod(m => m.Name == "RemoveAt"))
.Ret();

pop.Ret();
}

private IXamlMethodBuilder<IXamlILEmitter> ImplementInterfacePropertyGetter(IXamlTypeBuilder<IXamlILEmitter> builder ,
Expand Down
33 changes: 33 additions & 0 deletions tests/XamlParserTests/ServiceProviderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ namespace XamlParserTests
{
public class CallbackExtension
{
public object? Nested { get; set; }

public object? ProvideValue(IServiceProvider provider)
{
return provider.GetRequiredService<CallbackExtensionCallback>()(provider);
Expand Down Expand Up @@ -168,6 +170,37 @@ public void ProvideValueTarget_Provides_Info_About_Properties()
Assert.Equal(2, num);
}

[Fact]
public void ProvideValueTarget_TargetObject_Is_Valid_After_Nested_PushPop()
{
var num = 0;
CompileAndRun(@"
<ServiceProviderTestsClass xmlns='test'
Property='{Callback Nested={Callback}}'
ServiceProviderTests.AttachedProperty='{Callback}'
/>", sp =>
{
var pt = sp.GetRequiredService<ITestProvideValueTarget>();
if (num == 0)
{
Assert.IsType<CallbackExtension>(pt.TargetObject);
Assert.Equal("Nested", pt.TargetProperty);
}
else if (num == 1)
{
Assert.IsType<ServiceProviderTestsClass>(pt.TargetObject);
Assert.Equal("Property", pt.TargetProperty);
}
else if (num == 2)
{
Assert.IsType<ServiceProviderTestsClass>(pt.TargetObject);
Assert.Equal("AttachedProperty", pt.TargetProperty);
}
num++;
return num.ToString();
}, null);
Assert.Equal(3, num);
}

class InnerProvider : IServiceProvider, ITestRootObjectProvider
{
Expand Down

0 comments on commit e524acf

Please sign in to comment.