private bool CompareAttributes( AttributeSyntax oldAttribute, AttributeSyntax newAttribute, SyntaxNode newNodeParent, CodeModelEventQueue eventQueue) { Debug.Assert(oldAttribute != null && newAttribute != null); bool same = true; if (!CompareNames(oldAttribute.Name, newAttribute.Name)) { EnqueueChangeEvent(newAttribute, newNodeParent, CodeModelEventType.Rename, eventQueue); same = false; } // If arguments have changed enqueue a element changed (arguments changed) node if (!CompareAttributeArguments(oldAttribute.ArgumentList, newAttribute.ArgumentList)) { EnqueueChangeEvent(newAttribute, newNodeParent, CodeModelEventType.ArgChange, eventQueue); same = false; } return same; }
private bool CompareAttributeLists( AttributeListSyntax oldAttributeList, AttributeListSyntax newAttributeList, SyntaxNode newNodeParent, CodeModelEventQueue eventQueue) { return CompareChildren( CompareAttributes, oldAttributeList.Attributes.AsReadOnlyList(), newAttributeList.Attributes.AsReadOnlyList(), newNodeParent, CodeModelEventType.Unknown, eventQueue); }
private void CompareCompilationUnits( CompilationUnitSyntax oldCompilationUnit, CompilationUnitSyntax newCompilationUnit, CodeModelEventQueue eventQueue) { // Note: In the C# legacy code model, events are generated for the top-level // namespace that is at the root of every parse tree. In the Roslyn C# code model // implementation, we won't bother. CompareChildren( CompareNamespacesOrTypes, GetValidMembers(oldCompilationUnit), GetValidMembers(newCompilationUnit), (SyntaxNode)null, CodeModelEventType.Unknown, 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); } }
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, eventType, 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, eventType, oldCount - newCount, eventQueue); } else { FindAddedChild(compare, oldChildren, newChildren, newNodeParent, eventType, newCount - oldCount, eventQueue); } } return(false); }
private bool CompareTypeDeclarations( MemberDeclarationSyntax oldMember, MemberDeclarationSyntax newMember, SyntaxNode newNodeParent, CodeModelEventQueue eventQueue) { Debug.Assert(oldMember != null && newMember != null); Debug.Assert(oldMember is BaseTypeDeclarationSyntax || oldMember is DelegateDeclarationSyntax); Debug.Assert(newMember is BaseTypeDeclarationSyntax || newMember is DelegateDeclarationSyntax); // If the kind doesn't match, it has to be a remove/add. if (oldMember.Kind() != newMember.Kind()) { EnqueueRemoveEvent(oldMember, newNodeParent, eventQueue); EnqueueAddEvent(newMember, newNodeParent, eventQueue); return false; } if (oldMember is BaseTypeDeclarationSyntax) { var oldType = (BaseTypeDeclarationSyntax)oldMember; var newType = (BaseTypeDeclarationSyntax)newMember; var oldMembers = GetValidMembers(oldType); var newMembers = GetValidMembers(newType); bool same = true; // If the type name is different, it might mean that the whole type has been removed and a new one added. // In that case, we shouldn't do any other checks and instead return immediately. if (!StringComparer.Ordinal.Equals(oldType.Identifier.ToString(), newType.Identifier.ToString())) { var change = CompareRenamedDeclarations( CompareMemberDeclarations, oldMembers, newMembers, oldType, newType, newNodeParent, eventQueue); if (change == DeclarationChange.WholeDeclaration) { return false; } same = false; EnqueueChangeEvent(newType, newNodeParent, CodeModelEventType.Rename, eventQueue); } if (!CompareModifiers(oldType, newType)) { same = false; EnqueueChangeEvent(newType, newNodeParent, CodeModelEventType.Unknown, eventQueue); } if (!CompareBaseLists(oldType, newType)) { same = false; EnqueueChangeEvent(newType, newNodeParent, CodeModelEventType.BaseChange, eventQueue); } same &= CompareChildren( CompareAttributeLists, oldType.AttributeLists.AsReadOnlyList(), newType.AttributeLists.AsReadOnlyList(), newType, CodeModelEventType.Unknown, eventQueue); same &= CompareChildren( CompareMemberDeclarations, oldMembers, newMembers, newType, CodeModelEventType.Unknown, eventQueue); return same; } else if (oldMember is DelegateDeclarationSyntax) { var oldDelegate = (DelegateDeclarationSyntax)oldMember; var newDelegate = (DelegateDeclarationSyntax)newMember; bool same = true; // If the delegate name is different, it might mean that the whole delegate has been removed and a new one added. // In that case, we shouldn't do any other checks and instead return immediately. if (!StringComparer.Ordinal.Equals(oldDelegate.Identifier.ToString(), newDelegate.Identifier.ToString())) { var change = CompareRenamedDeclarations( CompareParameters, oldDelegate.ParameterList.Parameters.AsReadOnlyList(), newDelegate.ParameterList.Parameters.AsReadOnlyList(), oldDelegate, newDelegate, newNodeParent, eventQueue); if (change == DeclarationChange.WholeDeclaration) { return false; } same = false; EnqueueChangeEvent(newDelegate, newNodeParent, CodeModelEventType.Rename, eventQueue); } if (!CompareModifiers(oldDelegate, newDelegate)) { same = false; EnqueueChangeEvent(newDelegate, newNodeParent, CodeModelEventType.Unknown, eventQueue); } if (!CompareTypes(oldDelegate.ReturnType, newDelegate.ReturnType)) { same = false; EnqueueChangeEvent(newDelegate, newNodeParent, CodeModelEventType.TypeRefChange, eventQueue); } same &= CompareChildren( CompareAttributeLists, oldDelegate.AttributeLists.AsReadOnlyList(), newDelegate.AttributeLists.AsReadOnlyList(), newDelegate, CodeModelEventType.Unknown, eventQueue); same &= CompareChildren( CompareParameters, oldDelegate.ParameterList.Parameters.AsReadOnlyList(), newDelegate.ParameterList.Parameters.AsReadOnlyList(), newDelegate, CodeModelEventType.SigChange, eventQueue); return same; } return false; }
private bool CompareNamespaceDeclarations( NamespaceDeclarationSyntax oldNamespace, NamespaceDeclarationSyntax newNamespace, SyntaxNode newNodeParent, CodeModelEventQueue eventQueue) { Debug.Assert(oldNamespace != null && newNamespace != null); // Check if the namespace nodes are identical w.r.t Name if (!CompareNames(oldNamespace.Name, newNamespace.Name)) { var change = CompareRenamedDeclarations( CompareNamespacesOrTypes, GetValidMembers(oldNamespace), GetValidMembers(newNamespace), oldNamespace, newNamespace, newNodeParent, eventQueue); if (change == DeclarationChange.NameOnly) { EnqueueChangeEvent(newNamespace, newNodeParent, CodeModelEventType.Rename, eventQueue); } return false; } return CompareChildren( CompareNamespacesOrTypes, GetValidMembers(oldNamespace), GetValidMembers(newNamespace), newNamespace, CodeModelEventType.Unknown, eventQueue); }
private bool CompareMethodDeclarations( BaseMethodDeclarationSyntax oldMethod, BaseMethodDeclarationSyntax newMethod, SyntaxNode newNodeParent, CodeModelEventQueue eventQueue) { Debug.Assert(oldMethod != null && newMethod != null); if (!StringComparer.Ordinal.Equals(CodeModelService.GetName(oldMethod), CodeModelService.GetName(newMethod))) { var change = CompareRenamedDeclarations( CompareParameters, oldMethod.ParameterList.Parameters.AsReadOnlyList(), newMethod.ParameterList.Parameters.AsReadOnlyList(), oldMethod, newMethod, newNodeParent, eventQueue); if (change == DeclarationChange.NameOnly) { EnqueueChangeEvent(newMethod, newNodeParent, CodeModelEventType.Rename, eventQueue); } return false; } else { bool same = true; if (!CompareModifiers(oldMethod, newMethod)) { same = false; EnqueueChangeEvent(newMethod, newNodeParent, CodeModelEventType.Unknown, eventQueue); } if (!CompareTypes(GetReturnType(oldMethod), GetReturnType(newMethod))) { same = false; EnqueueChangeEvent(newMethod, newNodeParent, CodeModelEventType.TypeRefChange, eventQueue); } same &= CompareChildren( CompareAttributeLists, oldMethod.AttributeLists.AsReadOnlyList(), newMethod.AttributeLists.AsReadOnlyList(), newMethod, CodeModelEventType.Unknown, eventQueue); same &= CompareChildren( CompareParameters, oldMethod.ParameterList.Parameters.AsReadOnlyList(), newMethod.ParameterList.Parameters.AsReadOnlyList(), newMethod, CodeModelEventType.SigChange, eventQueue); return same; } }
protected abstract void CollectCore(SyntaxNode oldRoot, SyntaxNode newRoot, CodeModelEventQueue eventQueue);
private static void ChangeEventQueueForAttributes(AttributeSyntax attribute, SyntaxNode parent, CodeModelEventType eventType, CodeModelEventQueue eventQueue) { if (parent is BaseFieldDeclarationSyntax) { foreach (var variableDeclarator in ((BaseFieldDeclarationSyntax)parent).Declaration.Variables) { eventQueue.EnqueueChangeEvent(attribute, variableDeclarator, eventType); } } else { eventQueue.EnqueueChangeEvent(attribute, parent, eventType); } }
private bool CompareEnumMemberDeclarations( EnumMemberDeclarationSyntax oldEnumMember, EnumMemberDeclarationSyntax newEnumMember, SyntaxNode newNodeParent, CodeModelEventQueue eventQueue) { Debug.Assert(oldEnumMember != null && newEnumMember != null); bool same = true; if (!StringComparer.Ordinal.Equals(CodeModelService.GetName(oldEnumMember), CodeModelService.GetName(newEnumMember))) { EnqueueChangeEvent(newEnumMember, newNodeParent, CodeModelEventType.Rename, eventQueue); same = false; } same &= CompareChildren( CompareAttributeLists, oldEnumMember.AttributeLists.AsReadOnlyList(), newEnumMember.AttributeLists.AsReadOnlyList(), newEnumMember, CodeModelEventType.Unknown, eventQueue); return same; }
private bool CompareMemberDeclarations( MemberDeclarationSyntax oldMember, MemberDeclarationSyntax newMember, SyntaxNode newNodeParent, CodeModelEventQueue eventQueue) { Debug.Assert(oldMember != null && newMember != null); // If the kind doesn't match, it has to be a remove/add. if (oldMember.Kind() != newMember.Kind()) { EnqueueRemoveEvent(oldMember, newNodeParent, eventQueue); EnqueueAddEvent(newMember, newNodeParent, eventQueue); return false; } if (oldMember is BaseTypeDeclarationSyntax || oldMember is DelegateDeclarationSyntax) { return CompareTypeDeclarations(oldMember, newMember, newNodeParent, eventQueue); } else if (oldMember is BaseMethodDeclarationSyntax) { return CompareMethodDeclarations((BaseMethodDeclarationSyntax)oldMember, (BaseMethodDeclarationSyntax)newMember, newNodeParent, eventQueue); } else if (oldMember is BaseFieldDeclarationSyntax) { return CompareFieldDeclarations((BaseFieldDeclarationSyntax)oldMember, (BaseFieldDeclarationSyntax)newMember, newNodeParent, eventQueue); } else if (oldMember is BasePropertyDeclarationSyntax) { return ComparePropertyDeclarations((BasePropertyDeclarationSyntax)oldMember, (BasePropertyDeclarationSyntax)newMember, newNodeParent, eventQueue); } else if (oldMember is EnumMemberDeclarationSyntax) { return CompareEnumMemberDeclarations((EnumMemberDeclarationSyntax)oldMember, (EnumMemberDeclarationSyntax)newMember, newNodeParent, eventQueue); } throw new NotImplementedException(); }
private bool CompareParameters(ParameterSyntax oldParameter, ParameterSyntax newParameter, SyntaxNode newNodeParent, CodeModelEventQueue eventQueue) { Debug.Assert(oldParameter != null && newParameter != null); bool same = true; if (!StringComparer.Ordinal.Equals(CodeModelService.GetName(oldParameter), CodeModelService.GetName(newParameter))) { EnqueueChangeEvent(newParameter, newNodeParent, CodeModelEventType.Rename, eventQueue); same = false; } // If modifiers or the type have changed enqueue a element changed (unknown change) node if (!CompareModifiers(oldParameter, newParameter) || !CompareTypes(oldParameter.Type, newParameter.Type)) { EnqueueChangeEvent(newParameter, newNodeParent, CodeModelEventType.Unknown, eventQueue); same = false; } return same; }
protected abstract void EnqueueChangeEvent(SyntaxNode node, SyntaxNode parent, CodeModelEventType eventType, CodeModelEventQueue eventQueue);
protected abstract void EnqueueRemoveEvent(SyntaxNode node, SyntaxNode parent, CodeModelEventQueue eventQueue);
private bool ComparePropertyDeclarations( BasePropertyDeclarationSyntax oldProperty, BasePropertyDeclarationSyntax newProperty, SyntaxNode newNodeParent, CodeModelEventQueue eventQueue) { Debug.Assert(oldProperty != null && newProperty != null); bool same = true; if (!StringComparer.Ordinal.Equals(CodeModelService.GetName(oldProperty), CodeModelService.GetName(newProperty))) { EnqueueChangeEvent(newProperty, newNodeParent, CodeModelEventType.Rename, eventQueue); same = false; } // If modifiers have changed enqueue a element changed (unknown change) node if (!CompareModifiers(oldProperty, newProperty)) { EnqueueChangeEvent(newProperty, newNodeParent, CodeModelEventType.Unknown, eventQueue); same = false; } // If return type had changed enqueue a element changed (typeref changed) node if (!CompareTypes(oldProperty.Type, newProperty.Type)) { EnqueueChangeEvent(newProperty, newNodeParent, CodeModelEventType.TypeRefChange, eventQueue); same = false; } same &= CompareChildren( CompareAttributeLists, oldProperty.AttributeLists.AsReadOnlyList(), newProperty.AttributeLists.AsReadOnlyList(), newProperty, CodeModelEventType.Unknown, eventQueue); if (oldProperty is IndexerDeclarationSyntax) { var oldIndexer = (IndexerDeclarationSyntax)oldProperty; var newIndexer = (IndexerDeclarationSyntax)newProperty; same &= CompareChildren( CompareParameters, oldIndexer.ParameterList.Parameters.AsReadOnlyList(), newIndexer.ParameterList.Parameters.AsReadOnlyList(), newIndexer, CodeModelEventType.SigChange, eventQueue); } return same; }
private bool CompareNamespacesOrTypes( MemberDeclarationSyntax oldNamespaceOrType, MemberDeclarationSyntax newNamespaceOrType, SyntaxNode newNodeParent, CodeModelEventQueue eventQueue) { // If the kind doesn't match, it has to be a remove/add. if (oldNamespaceOrType.Kind() != newNamespaceOrType.Kind()) { EnqueueRemoveEvent(oldNamespaceOrType, newNodeParent, eventQueue); EnqueueAddEvent(newNamespaceOrType, newNodeParent, eventQueue); return false; } if (oldNamespaceOrType is BaseTypeDeclarationSyntax || oldNamespaceOrType is DelegateDeclarationSyntax) { return CompareTypeDeclarations(oldNamespaceOrType, newNamespaceOrType, newNodeParent, eventQueue); } else if (oldNamespaceOrType is NamespaceDeclarationSyntax) { return CompareNamespaceDeclarations((NamespaceDeclarationSyntax)oldNamespaceOrType, (NamespaceDeclarationSyntax)newNamespaceOrType, newNodeParent, eventQueue); } return false; }
private bool CompareVariableDeclarators( VariableDeclaratorSyntax oldVariableDeclarator, VariableDeclaratorSyntax newVariableDeclarator, SyntaxNode newNodeParent, CodeModelEventQueue eventQueue) { Debug.Assert(oldVariableDeclarator != null && newVariableDeclarator != null); if (!StringComparer.Ordinal.Equals(CodeModelService.GetName(oldVariableDeclarator), CodeModelService.GetName(newVariableDeclarator))) { EnqueueChangeEvent(newVariableDeclarator, newNodeParent, CodeModelEventType.Rename, eventQueue); return false; } return true; }
protected override void CollectCore(SyntaxNode oldRoot, SyntaxNode newRoot, CodeModelEventQueue eventQueue) { CompareCompilationUnits((CompilationUnitSyntax)oldRoot, (CompilationUnitSyntax)newRoot, eventQueue); }
private bool CompareFieldDeclarations( BaseFieldDeclarationSyntax oldField, BaseFieldDeclarationSyntax newField, SyntaxNode newNodeParent, CodeModelEventQueue eventQueue) { Debug.Assert(oldField != null && newField != null); bool same = true; same &= CompareChildren( CompareVariableDeclarators, oldField.Declaration.Variables.AsReadOnlyList(), newField.Declaration.Variables.AsReadOnlyList(), newNodeParent, CodeModelEventType.Unknown, eventQueue); // If modifiers have changed enqueue a element changed (unknown change) node if ((oldField.Kind() != newField.Kind()) || !CompareModifiers(oldField, newField)) { EnqueueChangeEvent(newField, newNodeParent, CodeModelEventType.Unknown, eventQueue); same = false; } // If type had changed enqueue a element changed (typeref changed) node if (!CompareTypes(oldField.Declaration.Type, newField.Declaration.Type)) { EnqueueChangeEvent(newField, newNodeParent, CodeModelEventType.TypeRefChange, eventQueue); same = false; } same &= CompareChildren( CompareAttributeLists, oldField.AttributeLists.AsReadOnlyList(), newField.AttributeLists.AsReadOnlyList(), newField, CodeModelEventType.Unknown, eventQueue); return same; }
protected override void EnqueueRemoveEvent(SyntaxNode node, SyntaxNode parent, CodeModelEventQueue eventQueue) { if (eventQueue == null) { return; } if (node is IncompleteMemberSyntax) { return; } if (node is BaseFieldDeclarationSyntax) { foreach (var variableDeclarator in ((BaseFieldDeclarationSyntax)node).Declaration.Variables) { eventQueue.EnqueueRemoveEvent(variableDeclarator, parent); } } else if (node is AttributeListSyntax) { foreach (var attribute in ((AttributeListSyntax)node).Attributes) { AddEventToEventQueueForAttributes(attribute, parent, eventQueue.EnqueueRemoveEvent); } } else if (node is AttributeSyntax) { AddEventToEventQueueForAttributes((AttributeSyntax)node, parent, eventQueue.EnqueueRemoveEvent); } else { eventQueue.EnqueueRemoveEvent(node, parent); } }
private void FindRemovedChild <TNode, TParent>( NodeComparison <TNode, TParent> compare, IReadOnlyList <TNode> oldChildren, IReadOnlyList <TNode> newChildren, TParent newNodeParent, 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 ); } } }