private static async Task <(Data existingData, Data newData)> ComputeAndPersistTodoCommentsAsync(
            Document document,
            TodoCommentState state,
            TodoCommentTokens todoCommentTokens,
            CancellationToken cancellationToken)
        {
            // use tree version so that things like compiler option changes are considered
            var textVersion = await document.GetTextVersionAsync(cancellationToken).ConfigureAwait(false);

            var syntaxVersion = await document.GetSyntaxVersionAsync(cancellationToken).ConfigureAwait(false);

            var existingData = await state.TryGetExistingDataAsync(document, cancellationToken).ConfigureAwait(false);

            if (existingData != null)
            {
                // check whether we can use the data as it is (can happen when re-using persisted data from previous VS session)
                if (CheckVersions(document, textVersion, syntaxVersion, existingData))
                {
                    return(existingData, existingData);
                }
            }

            var tokens   = todoCommentTokens.GetTokens(document);
            var comments = await GetTodoCommentsAsync(document, tokens, cancellationToken).ConfigureAwait(false);

            var items = await CreateItemsAsync(document, comments, cancellationToken).ConfigureAwait(false);

            var data = new Data(textVersion, syntaxVersion, items);
            await state.PersistAsync(document, data, cancellationToken).ConfigureAwait(false);

            return(existingData, data);
        }
Example #2
0
        public async Task AnalyzeSyntaxAsync(Document document, InvocationReasons reasons, CancellationToken cancellationToken)
        {
            // it has an assumption that this will not be called concurrently for same document.
            // in fact, in current design, it won't be even called concurrently for different documents.
            // but, can be called concurrently for different documents in future if we choose to.
            Contract.ThrowIfFalse(document.IsFromPrimaryBranch());

            if (!document.Project.Solution.Options.GetOption(InternalFeatureOnOffOptions.TodoComments))
            {
                return;
            }

            // use tree version so that things like compiler option changes are considered
            var textVersion = await document.GetTextVersionAsync(cancellationToken).ConfigureAwait(false);

            var syntaxVersion = await document.GetSyntaxVersionAsync(cancellationToken).ConfigureAwait(false);

            var existingData = await _state.TryGetExistingDataAsync(document, cancellationToken).ConfigureAwait(false);

            if (existingData != null)
            {
                // check whether we can use the data as it is (can happen when re-using persisted data from previous VS session)
                if (CheckVersions(document, textVersion, syntaxVersion, existingData))
                {
                    Contract.Requires(_workspace == document.Project.Solution.Workspace);
                    RaiseTaskListUpdated(_workspace, document.Project.Solution, document.Id, existingData.Items);
                    return;
                }
            }

            var service = document.GetLanguageService <ITodoCommentService>();

            if (service == null)
            {
                return;
            }

            var tokens   = _todoCommentTokens.GetTokens(document, cancellationToken);
            var comments = await service.GetTodoCommentsAsync(document, tokens, cancellationToken).ConfigureAwait(false);

            var items = await CreateItemsAsync(document, comments, cancellationToken).ConfigureAwait(false);

            var data = new Data(textVersion, syntaxVersion, items);
            await _state.PersistAsync(document, data, cancellationToken).ConfigureAwait(false);

            // * NOTE * cancellation can't throw after this point.
            if (existingData == null || existingData.Items.Length > 0 || data.Items.Length > 0)
            {
                Contract.Requires(_workspace == document.Project.Solution.Workspace);
                RaiseTaskListUpdated(_workspace, document.Project.Solution, document.Id, data.Items);
            }
        }