File: FindSymbols\TopLevelSyntaxTree\TopLevelSyntaxTreeIndex.ExtensionMethodInfo.cs
Web Access
Project: src\src\Workspaces\Core\Portable\Microsoft.CodeAnalysis.Workspaces.csproj (Microsoft.CodeAnalysis.Workspaces)
// 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.Immutable;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.FindSymbols;
 
internal sealed partial class TopLevelSyntaxTreeIndex
{
    private readonly struct ExtensionMethodInfo(ImmutableDictionary<string, ImmutableArray<int>> receiverTypeNameToExtensionMethodMap)
    {
        // We divide extension methods into two categories, simple and complex, for filtering purpose.
        // Whether a method is simple is determined based on if we can determine it's receiver type easily
        // with a pure text matching. For complex methods, we will need to rely on symbol to decide if it's 
        // feasible.
        //
        // Complex methods include:
        // - Method declared in the document which includes using alias directive
        // - Generic method where the receiver type is a type-paramter (e.g. List<T> would be considered simple, not complex)
        // - If the receiver type name is Pointer type (i.e. name of the type for the first parameter) 
        //
        // The rest of methods are considered simple.
 
        /// <summary>
        /// Name of the extension method's receiver type to the index of its DeclaredSymbolInfo in `_declarationInfo`.
        /// 
        /// For simple types, the receiver type name is it's metadata name. All predefined types are converted to its metadata form.
        /// e.g. int => Int32. For generic types, type parameters are ignored.
        /// 
        /// For complex types, the receiver type name is "".
        /// 
        /// For any kind of array types, it's "{element's receiver type name}[]".
        /// e.g. 
        /// int[][,] => "Int32[]"
        /// T (where T is a type parameter) => ""
        /// T[,] (where T is a type parameter) => "T[]"
        /// </summary>
        public readonly ImmutableDictionary<string, ImmutableArray<int>> ReceiverTypeNameToExtensionMethodMap { get; } = receiverTypeNameToExtensionMethodMap;
 
        public bool ContainsExtensionMethod => !ReceiverTypeNameToExtensionMethodMap.IsEmpty;
 
        public void WriteTo(ObjectWriter writer)
        {
            writer.WriteInt32(ReceiverTypeNameToExtensionMethodMap.Count);
 
            foreach (var (name, indices) in ReceiverTypeNameToExtensionMethodMap)
            {
                writer.WriteString(name);
                writer.WriteArray(indices, static (w, i) => w.WriteInt32(i));
            }
        }
 
        public static ExtensionMethodInfo? TryReadFrom(ObjectReader reader)
        {
            try
            {
                var receiverTypeNameToExtensionMethodMapBuilder = ImmutableDictionary.CreateBuilder<string, ImmutableArray<int>>();
                var count = reader.ReadInt32();
 
                for (var i = 0; i < count; ++i)
                    receiverTypeNameToExtensionMethodMapBuilder[reader.ReadRequiredString()] = reader.ReadArray(static r => r.ReadInt32());
 
                return new ExtensionMethodInfo(receiverTypeNameToExtensionMethodMapBuilder.ToImmutable());
            }
            catch (Exception)
            {
            }
 
            return null;
        }
    }
}