File: CodeModel\InternalElements\AbstractKeyedCodeElement.cs
Web Access
Project: ..\..\..\src\VisualStudio\Core\Impl\Microsoft.VisualStudio.LanguageServices.Implementation_zmmkbl53_wpftmp.csproj (Microsoft.VisualStudio.LanguageServices.Implementation)
// 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.
 
#nullable disable
 
using System;
using System.Diagnostics;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities;
using Roslyn.Utilities;
 
namespace Microsoft.VisualStudio.LanguageServices.Implementation.CodeModel.InternalElements
{
    /// <summary>
    /// This is the base class of all code elements identified by a SyntaxNodeKey.
    /// </summary>
    public abstract class AbstractKeyedCodeElement : AbstractCodeElement
    {
        private SyntaxNodeKey _nodeKey;
        private readonly string _name;
 
        internal AbstractKeyedCodeElement(
            CodeModelState state,
            FileCodeModel fileCodeModel,
            SyntaxNodeKey nodeKey,
            int? nodeKind)
            : base(state, fileCodeModel, nodeKind)
        {
            _nodeKey = nodeKey;
            _name = null;
        }
 
        // This constructor is called for "unknown" code elements.
        internal AbstractKeyedCodeElement(
            CodeModelState state,
            FileCodeModel fileCodeModel,
            int nodeKind,
            string name)
            : base(state, fileCodeModel, nodeKind)
        {
            _nodeKey = new SyntaxNodeKey(name, -1);
            _name = name;
        }
 
        internal SyntaxNodeKey NodeKey
        {
            get { return _nodeKey; }
        }
 
        internal bool IsUnknown
        {
            get { return _nodeKey.Ordinal == -1; }
        }
 
        internal override SyntaxNode LookupNode()
            => CodeModelService.LookupNode(_nodeKey, GetSyntaxTree());
 
        internal override bool TryLookupNode(out SyntaxNode node)
            => CodeModelService.TryLookupNode(_nodeKey, GetSyntaxTree(), out node);
 
        /// <summary>
        /// This function re-acquires the key for this code element using the given syntax path.
        /// </summary>
        internal void ReacquireNodeKey(SyntaxPath syntaxPath, CancellationToken cancellationToken)
        {
            Debug.Assert(syntaxPath != null);
            if (!syntaxPath.TryResolve(GetSyntaxTree(), cancellationToken, out SyntaxNode node))
            {
                throw Exceptions.ThrowEFail();
            }
 
            var newNodeKey = CodeModelService.GetNodeKey(node);
 
            FileCodeModel.UpdateCodeElementNodeKey(this, _nodeKey, newNodeKey);
 
            _nodeKey = newNodeKey;
        }
 
        protected void UpdateNodeAndReacquireNodeKey<T>(Action<SyntaxNode, T> updater, T value, bool trackKinds = true)
        {
            FileCodeModel.EnsureEditor(() =>
            {
                // Sometimes, changing an element can result in needing to update its node key.
 
                var node = LookupNode();
                var nodePath = new SyntaxPath(node, trackKinds);
 
                updater(node, value);
 
                ReacquireNodeKey(nodePath, CancellationToken.None);
            });
        }
 
        protected override Document DeleteCore(Document document)
        {
            var result = base.DeleteCore(document);
 
            FileCodeModel.OnCodeElementDeleted(_nodeKey);
 
            return result;
        }
 
        protected override string GetName()
        {
            if (IsUnknown)
            {
                return _name;
            }
 
            return base.GetName();
        }
 
        protected override void SetName(string value)
        {
            FileCodeModel.EnsureEditor(() =>
            {
                var nodeKeyValidation = new NodeKeyValidation();
                nodeKeyValidation.AddFileCodeModel(this.FileCodeModel);
 
                var node = LookupNode();
 
                FileCodeModel.UpdateName(node, value);
 
                nodeKeyValidation.RestoreKeys();
            });
        }
    }
}