File: CodeModel\InternalElements\CodeProperty.cs
Web Access
Project: src\src\VisualStudio\Core\Impl\Microsoft.VisualStudio.LanguageServices.Implementation.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.Collections.Immutable;
using System.Runtime.InteropServices;
using Microsoft.CodeAnalysis;
using Microsoft.VisualStudio.LanguageServices.Implementation.Interop;
using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities;
 
namespace Microsoft.VisualStudio.LanguageServices.Implementation.CodeModel.InternalElements;
 
[ComVisible(true)]
[ComDefaultInterface(typeof(EnvDTE80.CodeProperty2))]
public sealed partial class CodeProperty : AbstractCodeMember, ICodeElementContainer<CodeParameter>, ICodeElementContainer<CodeAttribute>, EnvDTE.CodeProperty, EnvDTE80.CodeProperty2
{
    internal static EnvDTE.CodeProperty Create(
        CodeModelState state,
        FileCodeModel fileCodeModel,
        SyntaxNodeKey nodeKey,
        int? nodeKind)
    {
        var element = new CodeProperty(state, fileCodeModel, nodeKey, nodeKind);
        var result = (EnvDTE.CodeProperty)ComAggregate.CreateAggregatedObject(element);
 
        fileCodeModel.OnCodeElementCreated(nodeKey, (EnvDTE.CodeElement)result);
 
        return result;
    }
 
    internal static EnvDTE.CodeProperty CreateUnknown(
        CodeModelState state,
        FileCodeModel fileCodeModel,
        int nodeKind,
        string name)
    {
        var element = new CodeProperty(state, fileCodeModel, nodeKind, name);
        return (EnvDTE.CodeProperty)ComAggregate.CreateAggregatedObject(element);
    }
 
    private CodeProperty(
        CodeModelState state,
        FileCodeModel fileCodeModel,
        SyntaxNodeKey nodeKey,
        int? nodeKind)
        : base(state, fileCodeModel, nodeKey, nodeKind)
    {
    }
 
    private CodeProperty(
        CodeModelState state,
        FileCodeModel fileCodeModel,
        int nodeKind,
        string name)
        : base(state, fileCodeModel, nodeKind, name)
    {
    }
 
    private IPropertySymbol PropertySymbol
    {
        get { return (IPropertySymbol)LookupSymbol(); }
    }
 
    EnvDTE.CodeElements ICodeElementContainer<CodeParameter>.GetCollection()
        => this.Parameters;
 
    EnvDTE.CodeElements ICodeElementContainer<CodeAttribute>.GetCollection()
        => this.Attributes;
 
    internal override ImmutableArray<SyntaxNode> GetParameters()
        => [.. CodeModelService.GetParameterNodes(LookupNode())];
 
    protected override object GetExtenderNames()
        => CodeModelService.GetPropertyExtenderNames();
 
    protected override object GetExtender(string name)
        => CodeModelService.GetPropertyExtender(name, LookupNode(), LookupSymbol());
 
    public override EnvDTE.vsCMElement Kind
    {
        get { return EnvDTE.vsCMElement.vsCMElementProperty; }
    }
 
    public override object Parent
    {
        get
        {
            EnvDTE80.CodeProperty2 codeProperty = this;
            return codeProperty.Parent2;
        }
    }
 
    public EnvDTE.CodeElement Parent2
    {
        get
        {
            var containingTypeNode = GetContainingTypeNode();
            if (containingTypeNode == null)
            {
                throw Exceptions.ThrowEUnexpected();
            }
 
            return FileCodeModel.GetOrCreateCodeElement<EnvDTE.CodeElement>(containingTypeNode);
        }
    }
 
    EnvDTE.CodeClass EnvDTE.CodeProperty.Parent
    {
        get
        {
            if (this.Parent is EnvDTE.CodeClass parentClass)
            {
                return parentClass;
            }
            else
            {
                throw new InvalidOperationException();
            }
        }
    }
 
    EnvDTE.CodeClass EnvDTE80.CodeProperty2.Parent
    {
        get
        {
            EnvDTE.CodeProperty property = this;
            return property.Parent;
        }
    }
 
    public override EnvDTE.CodeElements Children
    {
        get { return this.Attributes; }
    }
 
    private bool HasAccessorNode(MethodKind methodKind)
        => CodeModelService.TryGetAccessorNode(LookupNode(), methodKind, out _);
 
    private bool IsExpressionBodiedProperty()
        => CodeModelService.IsExpressionBodiedProperty(LookupNode());
 
    public EnvDTE.CodeFunction Getter
    {
        get
        {
            if (!HasAccessorNode(MethodKind.PropertyGet) &&
                !IsExpressionBodiedProperty())
            {
                return null;
            }
 
            return CodeAccessorFunction.Create(this.State, this, MethodKind.PropertyGet);
        }
 
        set
        {
            throw Exceptions.ThrowENotImpl();
        }
    }
 
    public EnvDTE.CodeFunction Setter
    {
        get
        {
            if (!HasAccessorNode(MethodKind.PropertySet))
            {
                return null;
            }
 
            return CodeAccessorFunction.Create(this.State, this, MethodKind.PropertySet);
        }
 
        set
        {
            throw Exceptions.ThrowENotImpl();
        }
    }
 
    public EnvDTE.CodeTypeRef Type
    {
        get
        {
            return CodeTypeRef.Create(this.State, this, GetProjectId(), PropertySymbol.Type);
        }
 
        set
        {
            // The type is sometimes part of the node key, so we should be sure to reacquire
            // it after updating it. Note that we pass trackKinds: false because it's possible
            // that UpdateType might change the kind of a node (e.g. change a VB Sub to a Function).
 
            UpdateNodeAndReacquireNodeKey(FileCodeModel.UpdateType, value, trackKinds: false);
        }
    }
 
    public bool IsDefault
    {
        get
        {
            return CodeModelService.GetIsDefault(LookupNode());
        }
 
        set
        {
            UpdateNode(FileCodeModel.UpdateIsDefault, value);
        }
    }
 
    public EnvDTE80.vsCMPropertyKind ReadWrite
    {
        get { return CodeModelService.GetReadWrite(LookupNode()); }
    }
}