private void EnqueueEvent(CodeModelEvent @event)
        {
            // Don't bother with events that are already queued.
            foreach (var queuedEvent in _eventQueue)
            {
                if (queuedEvent.Equals(@event))
                {
                    return;
                }
            }

            // Events are added to the end of the queue, so we only check the
            // last event to see if we can combine it with the new event. The
            // other events will be for prior edits, and should remain distinct.
            // In order to combine the events, they must both be for the same node, 
            // and they must both be change events.

            if (_eventQueue.Count > 0)
            {
                var priorEvent = _eventQueue.Peek();
                if (priorEvent.Node == @event.Node &&
                    priorEvent.Type.IsChange() &&
                    @event.Type.IsChange())
                {
                    priorEvent.Type |= @event.Type;
                    return;
                }
            }

            _eventQueue.Enqueue(@event);
        }
        private EnvDTE.CodeElement GetAttributeArgumentForCodeModelEvent(CodeModelEvent codeModelEvent, EnvDTE.CodeElements parentAttributeArguments, object parentElement)
        {
            if (parentAttributeArguments == null)
            {
                return null;
            }

            CodeModelService.GetAttributeArgumentParentAndIndex(codeModelEvent.Node, out var attributeNode, out var ordinal);

            if (codeModelEvent.Type == CodeModelEventType.Remove)
            {
                var parentCodeElement = ComAggregate.TryGetManagedObject<CodeAttribute>(parentElement);
                if (parentCodeElement != null)
                {
                    return (EnvDTE.CodeElement)CodeAttributeArgument.Create(this.State, parentCodeElement, ordinal);
                }
            }
            else
            {
                return parentAttributeArguments.Item(ordinal + 1); // Needs to be 1-based to call back into code model
            }

            return null;
        }
        private EnvDTE.CodeElement GetAttributeArgumentElementForCodeModelEvent(CodeModelEvent codeModelEvent, object parentElement)
        {
            var parentAttribute = parentElement as EnvDTE80.CodeAttribute2;
            if (parentAttribute != null)
            {
                return GetAttributeArgumentForCodeModelEvent(codeModelEvent, parentAttribute.Arguments, parentElement);
            }

            return null;
        }
        private EnvDTE.CodeElement GetAttributeElementForCodeModelEvent(CodeModelEvent codeModelEvent, object parentElement)
        {
            var node = codeModelEvent.Node;
            var parentNode = codeModelEvent.ParentNode;
            var eventType = codeModelEvent.Type;

            var parentType = parentElement as EnvDTE.CodeType;
            if (parentType != null)
            {
                return GetAttributeElementForCodeModelEvent(node, parentNode, eventType, parentType.Attributes, parentElement);
            }

            var parentFunction = parentElement as EnvDTE.CodeFunction;
            if (parentFunction != null)
            {
                return GetAttributeElementForCodeModelEvent(node, parentNode, eventType, parentFunction.Attributes, parentElement);
            }

            var parentProperty = parentElement as EnvDTE.CodeProperty;
            if (parentProperty != null)
            {
                return GetAttributeElementForCodeModelEvent(node, parentNode, eventType, parentProperty.Attributes, parentElement);
            }

            var parentEvent = parentElement as EnvDTE80.CodeEvent;
            if (parentEvent != null)
            {
                return GetAttributeElementForCodeModelEvent(node, parentNode, eventType, parentEvent.Attributes, parentElement);
            }

            var parentVariable = parentElement as EnvDTE.CodeVariable;
            if (parentVariable != null)
            {
                return GetAttributeElementForCodeModelEvent(node, parentNode, eventType, parentVariable.Attributes, parentElement);
            }

            // In the following case, parentNode is null and the root should be used instead.
            var parentFileCodeModel = parentElement as EnvDTE.FileCodeModel;
            if (parentFileCodeModel != null)
            {
                var fileCodeModel = ComAggregate.TryGetManagedObject<FileCodeModel>(parentElement);
                parentNode = fileCodeModel.GetSyntaxRoot();

                return GetAttributeElementForCodeModelEvent(node, parentNode, eventType, parentFileCodeModel.CodeElements, parentElement);
            }

            return null;
        }
        private EnvDTE.CodeElement GetParameterElementForCodeModelEvent(CodeModelEvent codeModelEvent, EnvDTE.CodeElements parentParameters, object parentElement)
        {
            if (parentParameters == null)
            {
                return null;
            }

            var parameterName = this.CodeModelService.GetName(codeModelEvent.Node);

            if (codeModelEvent.Type == CodeModelEventType.Remove)
            {
                var parentCodeElement = ComAggregate.TryGetManagedObject<AbstractCodeMember>(parentElement);
                if (parentCodeElement != null)
                {
                    return (EnvDTE.CodeElement)CodeParameter.Create(this.State, parentCodeElement, parameterName);
                }
            }
            else
            {
                return parentParameters.Item(parameterName);
            }

            return null;
        }
        private EnvDTE.CodeElement GetParameterElementForCodeModelEvent(CodeModelEvent codeModelEvent, object parentElement)
        {
            var parentDelegate = parentElement as EnvDTE.CodeDelegate;
            if (parentDelegate != null)
            {
                return GetParameterElementForCodeModelEvent(codeModelEvent, parentDelegate.Parameters, parentElement);
            }

            var parentFunction = parentElement as EnvDTE.CodeFunction;
            if (parentFunction != null)
            {
                return GetParameterElementForCodeModelEvent(codeModelEvent, parentFunction.Parameters, parentElement);
            }

            var parentProperty = parentElement as EnvDTE80.CodeProperty2;
            if (parentProperty != null)
            {
                return GetParameterElementForCodeModelEvent(codeModelEvent, parentProperty.Parameters, parentElement);
            }

            return null;
        }
        private object GetParentElementForCodeModelEvent(CodeModelEvent codeModelEvent)
        {
            if (this.CodeModelService.IsParameterNode(codeModelEvent.Node) ||
                this.CodeModelService.IsAttributeArgumentNode(codeModelEvent.Node))
            {
                if (codeModelEvent.ParentNode != null)
                {
                    return this.GetOrCreateCodeElement<EnvDTE.CodeElement>(codeModelEvent.ParentNode);
                }
            }
            else if (this.CodeModelService.IsAttributeNode(codeModelEvent.Node))
            {
                if (codeModelEvent.ParentNode != null)
                {
                    return this.GetOrCreateCodeElement<EnvDTE.CodeElement>(codeModelEvent.ParentNode);
                }
                else
                {
                    return this;
                }
            }
            else if (codeModelEvent.Type == CodeModelEventType.Remove)
            {
                if (codeModelEvent.ParentNode != null &&
                    codeModelEvent.ParentNode.Parent != null)
                {
                    return this.GetOrCreateCodeElement<EnvDTE.CodeElement>(codeModelEvent.ParentNode);
                }
                else
                {
                    return this;
                }
            }

            return null;
        }
        // internal for testing
        internal void GetElementsForCodeModelEvent(CodeModelEvent codeModelEvent, out EnvDTE.CodeElement element, out object parentElement)
        {
            parentElement = GetParentElementForCodeModelEvent(codeModelEvent);

            if (codeModelEvent.Node == null)
            {
                element = this.CodeModelService.CreateUnknownRootNamespaceCodeElement(this.State, this);
            }
            else if (this.CodeModelService.IsParameterNode(codeModelEvent.Node))
            {
                element = GetParameterElementForCodeModelEvent(codeModelEvent, parentElement);
            }
            else if (this.CodeModelService.IsAttributeNode(codeModelEvent.Node))
            {
                element = GetAttributeElementForCodeModelEvent(codeModelEvent, parentElement);
            }
            else if (this.CodeModelService.IsAttributeArgumentNode(codeModelEvent.Node))
            {
                element = GetAttributeArgumentElementForCodeModelEvent(codeModelEvent, parentElement);
            }
            else
            {
                if (codeModelEvent.Type == CodeModelEventType.Remove)
                {
                    element = this.CodeModelService.CreateUnknownCodeElement(this.State, this, codeModelEvent.Node);
                }
                else
                {
                    element = this.GetOrCreateCodeElement<EnvDTE.CodeElement>(codeModelEvent.Node);
                }
            }

            if (element == null)
            {
                Debug.Fail("We should have created an element for this event!");
            }

            Debug.Assert(codeModelEvent.Type != CodeModelEventType.Remove || parentElement != null);
        }