File: SemanticModelReuse\CSharpSemanticModelReuseLanguageService.cs
Web Access
Project: src\src\Workspaces\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.Workspaces.csproj (Microsoft.CodeAnalysis.CSharp.Workspaces)
// 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.Composition;
using Microsoft.CodeAnalysis.CSharp.LanguageService;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.LanguageService;
using Microsoft.CodeAnalysis.SemanticModelReuse;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.CSharp.SemanticModelReuse;
 
[ExportLanguageService(typeof(ISemanticModelReuseLanguageService), LanguageNames.CSharp), Shared]
internal class CSharpSemanticModelReuseLanguageService : AbstractSemanticModelReuseLanguageService<
    MemberDeclarationSyntax,
    BasePropertyDeclarationSyntax,
    AccessorDeclarationSyntax>
{
    [ImportingConstructor]
    [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
    public CSharpSemanticModelReuseLanguageService()
    {
    }
 
    protected override ISyntaxFacts SyntaxFacts => CSharpSyntaxFacts.Instance;
 
    protected override BasePropertyDeclarationSyntax GetBasePropertyDeclaration(AccessorDeclarationSyntax accessor)
    {
        Contract.ThrowIfFalse(accessor.Parent is AccessorListSyntax);
        Contract.ThrowIfFalse(accessor.Parent.Parent is BasePropertyDeclarationSyntax);
        return (BasePropertyDeclarationSyntax)accessor.Parent.Parent;
    }
 
    protected override SyntaxList<AccessorDeclarationSyntax> GetAccessors(BasePropertyDeclarationSyntax baseProperty)
        => baseProperty.AccessorList!.Accessors;
 
    public override SyntaxNode? TryGetContainingMethodBodyForSpeculation(SyntaxNode node)
    {
        for (SyntaxNode? previous = null, current = node; current != null; previous = current, current = current.Parent)
        {
            // These are the exact types that SemanticModel.TryGetSpeculativeSemanticModelForMethodBody accepts.
            if (current is BaseMethodDeclarationSyntax baseMethod)
                return previous != null && baseMethod.Body == previous ? baseMethod : null;
 
            if (current is AccessorDeclarationSyntax accessor)
                return previous != null && accessor.Body == previous ? accessor : null;
        }
 
        return null;
    }
 
    protected override SemanticModel? TryGetSpeculativeSemanticModelWorker(SemanticModel previousSemanticModel, SyntaxNode previousBodyNode, SyntaxNode currentBodyNode)
    {
        if (previousBodyNode is BaseMethodDeclarationSyntax previousBaseMethod &&
            currentBodyNode is BaseMethodDeclarationSyntax currentBaseMethod &&
            previousBaseMethod.Body != null &&
            previousSemanticModel.TryGetSpeculativeSemanticModelForMethodBody(previousBaseMethod.Body.SpanStart, currentBaseMethod, out var speculativeModel))
        {
            return speculativeModel;
        }
 
        if (previousBodyNode is AccessorDeclarationSyntax previousAccessorDeclaration &&
            currentBodyNode is AccessorDeclarationSyntax currentAccessorDeclaration &&
            previousAccessorDeclaration.Body != null &&
            previousSemanticModel.TryGetSpeculativeSemanticModelForMethodBody(previousAccessorDeclaration.Body.SpanStart, currentAccessorDeclaration, out speculativeModel))
        {
            return speculativeModel;
        }
 
        return null;
    }
}