File: SymbolKey.PropertySymbolKey.cs
Web Access
Project: ..\..\..\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.
 
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.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();
                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, 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,
                IPropertySymbol property)
            {
                if (reader.ParameterTypesMatch(
                        property,
                        getContextualType: static (property, i) => SafeGet(property.OriginalDefinition.Parameters, i)?.Type,
                        property.OriginalDefinition.Parameters))
                {
                    return property;
                }
 
                return null;
            }
        }
    }
}