File: Completion\SharedSyntaxContextsWithSpeculativeModel.cs
Web Access
Project: src\src\Features\Core\Portable\Microsoft.CodeAnalysis.Features.csproj (Microsoft.CodeAnalysis.Features)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System;
using System.Collections.Concurrent;
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.Completion;
 
internal sealed class SharedSyntaxContextsWithSpeculativeModel
{
    private readonly Document _document;
    private readonly int _position;
 
    private readonly ConcurrentDictionary<Document, AsyncLazy<SyntaxContext>> _cache;
    private readonly Lazy<ImmutableArray<DocumentId>> _lazyRelatedDocumentIds;
 
    public SharedSyntaxContextsWithSpeculativeModel(Document document, int position)
    {
        _document = document;
        _position = position;
        _cache = [];
        _lazyRelatedDocumentIds = new(_document.GetLinkedDocumentIds, isThreadSafe: true);
    }
 
    public Task<SyntaxContext> GetSyntaxContextAsync(Document document, CancellationToken cancellationToken)
    {
        if (!_cache.TryGetValue(document, out var lazyContext))
        {
            if (_document.Id != document.Id && !_lazyRelatedDocumentIds.Value.Contains(document.Id))
                throw new ArgumentException("Don't support getting SyntaxContext for document unrelated to the original document");
 
            lazyContext = GetLazySyntaxContextWithSpeculativeModel(document, this);
        }
 
        return lazyContext.GetValueAsync(cancellationToken);
 
        // Extract a local function to avoid creating a closure for code path of cache hit.
        static AsyncLazy<SyntaxContext> GetLazySyntaxContextWithSpeculativeModel(Document document, SharedSyntaxContextsWithSpeculativeModel self)
        {
            return self._cache.GetOrAdd(document, d => AsyncLazy.Create(static (arg, cancellationToken)
                => Utilities.CreateSyntaxContextWithExistingSpeculativeModelAsync(arg.d, arg._position, cancellationToken), (d, self._position)));
        }
    }
}