File: Shared\Extensions\IMethodSymbolExtensions.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.Generic;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeGeneration;
using Microsoft.CodeAnalysis.LanguageService;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.Shared.Extensions;
 
internal static partial class IMethodSymbolExtensions
{
    public static bool CompatibleSignatureToDelegate(this IMethodSymbol method, INamedTypeSymbol delegateType)
    {
        Contract.ThrowIfFalse(delegateType.TypeKind == TypeKind.Delegate);
 
        var invoke = delegateType.DelegateInvokeMethod;
        if (invoke == null)
        {
            // It's possible to get events with no invoke method from metadata.  We will assume
            // that no method can be an event handler for one.
            return false;
        }
 
        if (method.Parameters.Length != invoke.Parameters.Length)
        {
            return false;
        }
 
        if (method.ReturnsVoid != invoke.ReturnsVoid)
        {
            return false;
        }
 
        if (!method.ReturnType.InheritsFromOrEquals(invoke.ReturnType))
        {
            return false;
        }
 
        for (var i = 0; i < method.Parameters.Length; i++)
        {
            if (!invoke.Parameters[i].Type.InheritsFromOrEquals(method.Parameters[i].Type))
            {
                return false;
            }
        }
 
        return true;
    }
 
    public static bool? IsMoreSpecificThan(this IMethodSymbol method1, IMethodSymbol method2)
    {
        var p1 = method1.Parameters;
        var p2 = method2.Parameters;
 
        // If the methods don't have the same parameter count, then method1 can't be more or 
        // less specific than method2.
        if (p1.Length != p2.Length)
        {
            return null;
        }
 
        // If the methods' parameter types differ, or they have different names, then one can't
        // be more specific than the other.
        if (!SignatureComparer.Instance.HaveSameSignature(method1.Parameters, method2.Parameters) ||
            !method1.Parameters.Select(p => p.Name).SequenceEqual(method2.Parameters.Select(p => p.Name)))
        {
            return null;
        }
 
        // Ok.  We have two methods that look extremely similar to each other.  However, one might
        // be more specific if, for example, it was actually written with concrete types (like 'int') 
        // versus the other which may have been instantiated from a type parameter.   i.e.
        //
        // class C<T> { void Goo(T t); void Goo(int t); }
        //
        // THe latter Goo is more specific when comparing "C<int>.Goo(int t)" (method1) vs 
        // "C<int>.Goo(int t)" (method2).
        p1 = method1.OriginalDefinition.Parameters;
        p2 = method2.OriginalDefinition.Parameters;
        return p1.Select(p => p.Type).ToList().AreMoreSpecificThan(p2.Select(p => p.Type).ToList());
    }
}