private static Matching ComputeMatching(SyntaxNode target, SyntaxNode source) { var groups = source.GetSubtrees().GroupBy(t => t.treeHash); var sourceTable = new MultiValueDict <int, SyntaxNode>(groups); var matching = new Matching(); foreach (var tree in target.GetSubtrees()) { foreach (var t in sourceTable.GetValues(tree.treeHash)) // `tree.hash = t.hash` { if (matching.ContainsValue(tree, t)) // Tree `t` has been visited before. { continue; } // Let's check if `tree` and `t` are really identical. if (tree.IdenticalTo(t)) // We find a match! { // Since `tree` is identical to `t`, so are their subtrees. tree.GetSubtrees() .Zip(t.GetSubtrees(), (t1, t2) => (tree: t1, t: t2)) .ToList() .ForEach(pair => matching.Add(pair.tree, pair.t)); } else { Log.Debug("Same hash {0} but different trees:", tree.treeHash); var printer = new IndentPrinter(); tree.PrintTo(printer); printer.PrintLine("<->"); t.PrintTo(printer); } } } return(matching); }