// Internal for testing
        internal void OnDocumentStructureChanged(object state)
        {
            _dispatcher.AssertForegroundThread();

            if (_disposed)
            {
                return;
            }

            var args = (DocumentStructureChangedEventArgs)state;

            if (_latestChangeReference == null || // extra hardening
                !_latestChangeReference.IsAssociatedWith(args) ||
                args.Snapshot != TextBuffer.CurrentSnapshot)
            {
                // In the middle of parsing a newer change or about to parse a newer change.
                return;
            }

            _latestChangeReference = null;
            _codeDocument          = args.CodeDocument;
            _snapshot      = args.Snapshot;
            _partialParser = new RazorSyntaxTreePartialParser(CodeDocument.GetSyntaxTree());

            DocumentStructureChanged?.Invoke(this, args);
        }
        // Internal for testing
        internal void OnDocumentStructureChanged(object state)
        {
            _dispatcher.AssertForegroundThread();

            if (_disposed)
            {
                return;
            }

            var backgroundParserArgs = (BackgroundParserResultsReadyEventArgs)state;

            if (_latestChangeReference == null || // extra hardening
                _latestChangeReference != backgroundParserArgs.ChangeReference ||
                backgroundParserArgs.ChangeReference.Snapshot != TextBuffer.CurrentSnapshot)
            {
                // In the middle of parsing a newer change or about to parse a newer change.
                return;
            }

            _latestChangeReference = null;
            _codeDocument          = backgroundParserArgs.CodeDocument;
            _snapshot      = backgroundParserArgs.ChangeReference.Snapshot;
            _partialParser = new RazorSyntaxTreePartialParser(CodeDocument.GetSyntaxTree());

            var documentStructureChangedArgs = new DocumentStructureChangedEventArgs(
                backgroundParserArgs.ChangeReference.Change,
                backgroundParserArgs.ChangeReference.Snapshot,
                backgroundParserArgs.CodeDocument);

            DocumentStructureChanged?.Invoke(this, documentStructureChangedArgs);
        }
        // Internal for testing
        internal void OnDocumentStructureChanged(object state)
        {
            _dispatcher.AssertForegroundThread();

            if (_disposed)
            {
                return;
            }

            var backgroundParserArgs = (BackgroundParserResultsReadyEventArgs)state;
            if (_latestChangeReference == null || // extra hardening
                _latestChangeReference != backgroundParserArgs.ChangeReference)
            {
                // In the middle of parsing a newer change or about to parse a newer change.
                return;
            }

            if (backgroundParserArgs.ChangeReference.Snapshot != TextBuffer.CurrentSnapshot)
            {
                // Changes have impacted the snapshot after our we recorded our last change reference.
                // This can happen for a multitude of reasons, usually because of a user auto-completing
                // C# statements (causes multiple edits in quick succession). This ensures that our latest
                // parse corresponds to the current snapshot.
                QueueReparse();
                return;
            }

            _latestChangeReference = null;

            var documentStructureChangedArgs = new DocumentStructureChangedEventArgs(
                backgroundParserArgs.ChangeReference.Change,
                backgroundParserArgs.ChangeReference.Snapshot,
                backgroundParserArgs.CodeDocument);
            DocumentStructureChanged?.Invoke(this, documentStructureChangedArgs);
        }