File: src\Workspaces\SharedUtilitiesAndExtensions\Compiler\Core\SymbolKey\SymbolKey.PropertySymbolKey.cs
Web Access
Project: src\src\CodeStyle\Core\Analyzers\Microsoft.CodeAnalysis.CodeStyle.csproj (Microsoft.CodeAnalysis.CodeStyle)
// 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.Diagnostics;
 
namespace Microsoft.CodeAnalysis;
 
internal partial struct SymbolKey
{
    private sealed class PropertySymbolKey : AbstractSymbolKey<IPropertySymbol>
    {
        public static readonly PropertySymbolKey Instance = new();
 
        public sealed override void Create(IPropertySymbol symbol, SymbolKeyWriter visitor)
        {
            visitor.WriteString(symbol.MetadataName);
            visitor.WriteSymbolKey(symbol.ContainingSymbol);
            visitor.WriteBoolean(symbol.IsIndexer);
            visitor.WriteBoolean(symbol.PartialDefinitionPart != null);
            visitor.WriteRefKindArray(symbol.Parameters);
            visitor.WriteParameterTypesArray(symbol.OriginalDefinition.Parameters);
        }
 
        protected sealed override SymbolKeyResolution Resolve(
            SymbolKeyReader reader, IPropertySymbol? contextualSymbol, out string? failureReason)
        {
            var metadataName = reader.ReadString();
 
            var containingTypeResolution = reader.ReadSymbolKey(contextualSymbol?.ContainingSymbol, out var containingTypeFailureReason);
 
            var isIndexer = reader.ReadBoolean();
            var isPartialImplementationPart = reader.ReadBoolean();
            using var refKinds = reader.ReadRefKindArray();
 
            using var properties = GetMembersOfNamedType<IPropertySymbol>(containingTypeResolution, metadataName: null);
            using var result = PooledArrayBuilder<IPropertySymbol>.GetInstance();
 
            // For each property that we look at, we'll have to resolve the parameter list and return type in the
            // context of that method.  This makes sure we can attempt to resolve the parameter list types against
            // error types in the property we're currently looking at.
            //
            // Because of this, we keep track of where we are in the reader.  Before resolving every parameter list,
            // we'll mark which method we're on and we'll rewind to this point.
            var beforeParametersPosition = reader.Position;
 
            IPropertySymbol? property = null;
            foreach (var candidate in properties)
            {
                if (candidate.Parameters.Length != refKinds.Count ||
                    candidate.MetadataName != metadataName ||
                    candidate.IsIndexer != isIndexer ||
                    !ParameterRefKindsMatch(candidate.OriginalDefinition.Parameters, refKinds))
                {
                    continue;
                }
 
                property = Resolve(reader, isPartialImplementationPart, candidate);
                if (property != null)
                    break;
 
                // reset ourselves so we can check the return-type/parameters against the next candidate.
                reader.Position = beforeParametersPosition;
            }
 
            if (reader.Position == beforeParametersPosition)
            {
                // We didn't find a match.  Read through the stream one final time so we're at the correct location
                // after this PropertySymbolKey.
 
                _ = reader.ReadSymbolKeyArray<IPropertySymbol, ITypeSymbol>(
                    contextualSymbol: null, getContextualSymbol: null, failureReason: out _);
            }
 
            if (containingTypeFailureReason != null)
            {
                failureReason = $"({nameof(PropertySymbolKey)} {nameof(containingTypeResolution)} failed -> {containingTypeFailureReason})";
                return default;
            }
 
            if (property == null)
            {
                failureReason = $"({nameof(PropertySymbolKey)} '{metadataName}' not found)";
                return default;
            }
 
            failureReason = null;
            return new SymbolKeyResolution(property);
        }
 
        private static IPropertySymbol? Resolve(
            SymbolKeyReader reader,
            bool isPartialImplementationPart,
            IPropertySymbol property)
        {
            if (reader.ParameterTypesMatch(
                    property,
                    getContextualType: static (property, i) => SafeGet(property.OriginalDefinition.Parameters, i)?.Type,
                    property.OriginalDefinition.Parameters))
            {
                if (isPartialImplementationPart)
                    property = property.PartialImplementationPart ?? property;
 
                Debug.Assert(property != null);
                return property;
            }
 
            return null;
        }
    }
}