protected bool CompareChildren <TNode, TParent>( NodeComparison <TNode, TParent> compare, IReadOnlyList <TNode> oldChildren, IReadOnlyList <TNode> newChildren, TParent newNodeParent, CodeModelEventType eventType, CodeModelEventQueue eventQueue ) where TNode : SyntaxNode where TParent : SyntaxNode { var oldCount = oldChildren.Count; var newCount = newChildren.Count; if (oldCount == newCount) { return(FindDifferentChild( compare, oldChildren, newChildren, newNodeParent, eventQueue )); } else if (Math.Abs(oldCount - newCount) > MaxChildDelta) { // We got two discrepancies, enqueue element changed node for containing node EnqueueChangeEvent(newNodeParent, null, eventType, eventQueue); } else { if (oldCount > newCount) { FindRemovedChild( compare, oldChildren, newChildren, newNodeParent, oldCount - newCount, eventQueue ); } else { FindAddedChild( compare, oldChildren, newChildren, newNodeParent, newCount - oldCount, eventQueue ); } } return(false); }
private bool FindDifferentChild <TNode, TParent>( NodeComparison <TNode, TParent> compare, IReadOnlyList <TNode> oldChildren, IReadOnlyList <TNode> newChildren, TParent newNodeParent, CodeModelEventQueue eventQueue ) where TNode : SyntaxNode where TParent : SyntaxNode { Debug.Assert(oldChildren.Count == newChildren.Count); var eventCount = eventQueue != null ? eventQueue.Count : 0; var hasChanges = false; // Find first child that is different. int i; for (i = 0; i < oldChildren.Count; i++) { if (!compare(oldChildren[i], newChildren[i], newNodeParent, eventQueue)) { hasChanges = true; i++; break; } } // Look for a second different child. If there is one, we'll throw away any events from // the first different child and enqueue an unknown event on the containing node. for (; i < oldChildren.Count; i++) { if (!compare(oldChildren[i], newChildren[i], newNodeParent, null)) { // rollback any events added by the first difference if (eventQueue != null) { while (eventQueue.Count > eventCount) { eventQueue.Discard(); } } EnqueueChangeEvent( newNodeParent, null, CodeModelEventType.Unknown, eventQueue ); return(false); } } return(!hasChanges); }
private void FindRemovedChild <TNode, TParent>( NodeComparison <TNode, TParent> compare, IReadOnlyList <TNode> oldChildren, IReadOnlyList <TNode> newChildren, TParent newNodeParent, CodeModelEventType codeModelEventType, int delta, CodeModelEventQueue eventQueue) where TNode : SyntaxNode where TParent : SyntaxNode { Debug.Assert(oldChildren.Count - delta == newChildren.Count); // The strategy is to assume that all of the removed children are contiguous. // If that turns out not to be the case, an unknown change event is raised // for the containing node. var firstRemoved = -1; // Look for the first different child. If there is one, track that index as // the first added node. int oldIndex, newIndex; for (oldIndex = 0, newIndex = 0; oldIndex < oldChildren.Count; oldIndex++, newIndex++) { if (newIndex >= newChildren.Count || !compare(oldChildren[oldIndex], newChildren[newIndex], newNodeParent, null)) { firstRemoved = oldIndex; oldIndex += delta; break; } } // Look for a second different child. If there is one, we'll throw away any events from // the first different child and enqueue an unknown event on the containing node. for (; oldIndex < oldChildren.Count; oldIndex++, newIndex++) { if (!compare(oldChildren[oldIndex], newChildren[newIndex], newNodeParent, null)) { EnqueueChangeEvent(newNodeParent, null, CodeModelEventType.Unknown, eventQueue); return; } } if (firstRemoved >= 0) { for (var i = 0; i < delta; i++) { EnqueueRemoveEvent(oldChildren[firstRemoved + i], newNodeParent, eventQueue); } } }
protected DeclarationChange CompareRenamedDeclarations <TNode, TParent>( NodeComparison <TNode, TParent> compare, IReadOnlyList <TNode> oldChildren, IReadOnlyList <TNode> newChildren, SyntaxNode oldNode, SyntaxNode newNode, TParent newNodeParent, CodeModelEventQueue eventQueue ) where TNode : SyntaxNode where TParent : SyntaxNode { var oldCount = oldChildren.Count; var newCount = newChildren.Count; if (oldCount == newCount) { // We now check the children of the old and new types against each other. If any of them have changed, // it means that the old type has essentially been removed and a new one added. for (var i = 0; i < oldCount; i++) { if (!compare(oldChildren[i], newChildren[i], newNodeParent, null)) { EnqueueRemoveEvent(oldNode, newNodeParent, eventQueue); EnqueueAddEvent(newNode, newNodeParent, eventQueue); // Report that the whole declaration has changed return(DeclarationChange.WholeDeclaration); } } // The children are all the same, so only the name has changed. return(DeclarationChange.NameOnly); } else { // Since the number of members is different, essentially the old type has been removed, and a new one added. EnqueueRemoveEvent(oldNode, newNodeParent, eventQueue); EnqueueAddEvent(newNode, newNodeParent, eventQueue); // Report that the whole declaration has changed return(DeclarationChange.WholeDeclaration); } }
private static bool PerformRecursive(List <NodeBase> nodes) { List <NodeBase> valueNodes = new List <NodeBase>(); NodeBase firstNode = nodes[0]; bool isValueNodeLevel = firstNode is ValueNodeBase; List <List <NodeBase> > childNodeArrays = new List <List <NodeBase> >(); int childNodeCount = firstNode.Children.Count; for (int i = 0; i < childNodeCount; i++) { childNodeArrays.Add(new List <NodeBase>()); childNodeArrays[i].Add(firstNode.Children[i]); } for (int i = 1; i < nodes.Count; i++) { NodeBase node = nodes[i]; NodeComparison result = firstNode.ShallowCompare(node); if (result == NodeComparison.Incompatible) { return(false); } if (isValueNodeLevel) { valueNodes.Add(node); } else { if (result == NodeComparison.Unequal) { return(false); } // Handle children for (int j = 0; j < childNodeCount; j++) { childNodeArrays[j].Add(node.Children[j]); } } } if (isValueNodeLevel) { if (s_valueDiscrepancy != null) // There is already an existing recorded discrepancy (only one allowed) { return(false); } s_valueDiscrepancy = new ValueDiscrepancy(valueNodes, (firstNode as ValueNodeBase).TypeIndex); return(true); } for (int i = 0; i < childNodeCount; i++) { if (!PerformRecursive(childNodeArrays[i])) { return(false); } } return(true); }