I'm currently working on three-way merging on syntax trees using Roslyn.  I have a matching between all children on a a ClassDeclerationSyntax node, and want to perform a merge on the children, and then create a new tree based on that merge.
O is the input ClassDeclerationSyntax, and matching has three members (A, O, B) of the type MemberDeclerationSyntax.
var updated = O;
foreach (var m in matching)
{
    if (m.A != null && m.B != null && m.O != null) {
        var merge = Merge(m.A, m.O, m.B);
        var oldUpdated = updated;
        updated = updated.ReplaceNode(m.O, merge);
    }
    else if (m.A == null && m.O == null && m.B != null)
        updated = updated.AddMembers(m.B);
    else if (m.A != null && m.O == null && m.B == null)
        updated = updated.AddMembers(m.A);
}
This does not work. In the second iteration ReplaceNode returns a completely unmodified node (oldUpdated == updated is true).
It seems that after the first iteration of the loop, all children have been reconstructed as new objects, and the original children-objects stored in my matching can no longer be found in the children list (updated.ChildNodes().Where(x => x == m.O) is empty).
What would a good way be to do this?
My current approach:
var updateMember = new Dictionary<MemberDeclarationSyntax, MemberDeclarationSyntax>();
var addMembers = new List<MemberDeclarationSyntax>();
foreach (var m in matching) {
    if (m.A != null && m.B != null && m.O != null) {
        var mergeChild = Merge(m.A, m.B, M.O);
        updateMember.Add(m.O, child);
    }
    else if (m.A == null && m.O == null && m.B != null) 
        addMembers.Add(m.B);
    else if (m.A != null && m.O == null && m.B == null)
        addMembers.Add(m.A);
}
var merged = O.ReplaceNodes(updateMember.Keys.AsEnumerable(), (n1, n2) =>
{
    return updateMember[n1];
}).AddMembers(addMembers.ToArray());
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With