internal class FSharpCompiledExtensionMemberInfo()

in ReSharper.FSharp/src/FSharp/FSharp.Psi/src/Impl/Cache2/Compiled/FSharpCompiledExtensionMemberInfo.cs [15:87]


internal class FSharpCompiledExtensionMemberInfo([NotNull] FSharpMetadataValue value, FSharpCompiledModule owner)
  : ICompiledExtensionMemberProxy
{
  public IPsiModule PsiModule => owner.Module;

  public IPsiSourceFile TryGetSourceFile() => null;

  public HybridCollection<ITypeMember> FindExtensionMember()
  {
    var result = new LocalList<ITypeMember>();
    foreach (var member in owner.GetMembers())
    {
      if (Matches(member))
        result.Add(member);
    }

    return new HybridCollection<ITypeMember>(result.ReadOnlyList());

    bool Matches(ITypeMember member)
    {
      if (member is not IMethod method)
        return false;

      var shortName = method.ShortName;
      if (shortName != value.CompiledName?.Value)
        return false;

      if (shortName.EndsWith(".Static", StringComparison.OrdinalIgnoreCase))
        return true;

      if (value.ApparentEnclosingTypeReference is not FSharpMetadataTypeReference.NonLocal typeRef)
        return false;

      var parameters = method.Parameters;
      if (parameters.Count == 0)
        return false;

      // todo: test nested types
      // todo: check full name
      if (parameters[0].Type is IDeclaredType declaredType && declaredType.GetTypeElement() is { } typeElement)
        return typeElement.GetSourceName() == typeRef.ShortName?.Value;

      return false;
    }
  }

  public string ShortName
  {
    get
    {
      // todo: check IsProperty instead of checking the name
      var name = value.LogicalName;
      if (name.StartsWith("get_", StringComparison.Ordinal) || name.StartsWith("set_", StringComparison.Ordinal))
        return name.Substring(4);
      return name;
    }
  }

  public ExtensionMemberKind Kind => FSharpExtensionMemberKind.INSTANCE;

  public CompiledReceiverTypeDescriptor? TryGetExtensionReceiverType()
  {
    if (value.ApparentEnclosingTypeReference is FSharpMetadataTypeReference.NonLocal typeRef)
    {
      if (typeRef.typeNames.LastOrDefault() is { } name)
      {
        return new CompiledReceiverTypeDescriptor(name.SubstringBeforeLast("`"), isArray: false);
      }
    }

    return null;
  }
}