File: EditAndContinue\DeclarationBody.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.Generic;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using Microsoft.CodeAnalysis.Differencing;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.EditAndContinue;
 
internal abstract class DeclarationBody : IEquatable<DeclarationBody>
{
    public abstract SyntaxTree SyntaxTree { get; }
 
    /// <summary>
    /// Root nodes of the body. Descendant nodes of these roots include all nodes of the body and no nodes that do not belong to the body.
    /// Note: descendant nodes may include some tokens that are not part of the body and exclude some tokens that are.
    /// </summary>
    public abstract OneOrMany<SyntaxNode> RootNodes { get; }
 
    /// <summary>
    /// Returns all nodes of the body.
    /// </summary>
    /// <remarks>
    /// Note that VB lambda bodies are represented by a lambda header and that some lambda bodies share 
    /// their parent nodes with other bodies (e.g. join clause expressions).
    /// </remarks>
    public virtual IEnumerable<SyntaxNode> GetExpressionsAndStatements()
    {
        foreach (var root in RootNodes)
        {
            yield return root;
        }
    }
 
    public IEnumerable<SyntaxNode> GetDescendantNodes(Func<SyntaxNode, bool> descendIntoChildren)
    {
        foreach (var root in GetExpressionsAndStatements())
        {
            foreach (var node in root.DescendantNodesAndSelf(descendIntoChildren))
            {
                yield return node;
            }
        }
    }
 
    /// <summary>
    /// <see cref="SyntaxNode"/> that includes all active tokens (<see cref="MemberBody.GetActiveTokens"/>)
    /// and its span covers the entire <see cref="MemberBody.Envelope"/>.
    /// May include descendant nodes or tokens that do not belong to the body.
    /// </summary>
    public abstract SyntaxNode EncompassingAncestor { get; }
 
    public abstract StateMachineInfo GetStateMachineInfo();
 
    /// <summary>
    /// Analyzes data flow in the member body represented by the specified node and returns all captured variables and parameters (including "this").
    /// If the body is a field/property initializer analyzes the initializer expression only.
    /// </summary>
    public abstract ImmutableArray<ISymbol> GetCapturedVariables(SemanticModel model);
 
    /// <summary>
    /// Computes a statement-level syntax tree match of this body with <paramref name="newBody"/>.
    /// </summary>
    public virtual DeclarationBodyMap ComputeMap(DeclarationBody newBody, IEnumerable<KeyValuePair<SyntaxNode, SyntaxNode>>? knownMatches)
    {
        var primaryMatch = ComputeSingleRootMatch(newBody, knownMatches);
        return (primaryMatch != null) ? DeclarationBodyMap.FromMatch(primaryMatch) : DeclarationBodyMap.Empty;
    }
 
    /// <summary>
    /// If both this body and <paramref name="newBody"/> have single roots, computes a statement-level syntax tree match rooted in these roots.
    /// Otherwise, returns null (e.g. a primary constructor with implicit initializer does not have any body to match).
    /// </summary>
    public abstract Match<SyntaxNode>? ComputeSingleRootMatch(DeclarationBody newBody, IEnumerable<KeyValuePair<SyntaxNode, SyntaxNode>>? knownMatches);
 
    /// <summary>
    /// Matches old active statement node to new active statement node for nodes that are not accounted for in the body match or do not match but should be mapped
    /// (e.g. constructor initializers, opening brace of block body to expression body, etc.).
    /// </summary>
    public abstract bool TryMatchActiveStatement(DeclarationBody newBody, SyntaxNode oldStatement, ref int statementPart, [NotNullWhen(true)] out SyntaxNode? newStatement);
 
    public bool Equals(DeclarationBody? other)
        => ReferenceEquals(this, other) ||
           GetType() == other?.GetType() && RootNodes.SequenceEqual(other.RootNodes);
 
    public override bool Equals(object? obj)
        => Equals(obj as DeclarationBody);
 
    public override int GetHashCode()
        => RootNodes.First().GetHashCode();
}