SharpGen/Model/CsCallable.cs (128 lines of code) (raw):
using System;
using System.Collections.Generic;
using System.Linq;
using SharpGen.CppModel;
using SharpGen.Transform;
namespace SharpGen.Model
{
public abstract class CsCallable : CsBase, IExpiring
{
private CsBaseItemListCache<CsParameter> _parameters;
private Dictionary<PlatformDetectionType, InteropMethodSignature> interopSignatures;
protected readonly Ioc Ioc;
protected abstract int MaxSizeReturnParameter { get; }
protected CsCallable(Ioc ioc, CppCallable callable, string name) : base(callable, name)
{
Ioc = ioc ?? throw new ArgumentNullException(nameof(ioc));
if (callable == null)
return;
var tag = callable.Rule;
CheckReturnType = tag.MethodCheckReturnType ?? CheckReturnType;
ForceReturnType = tag.ParameterUsedAsReturnType ?? ForceReturnType;
AlwaysReturnHResult = tag.AlwaysReturnHResult ?? AlwaysReturnHResult;
RequestRawPtr = tag.RawPtr ?? RequestRawPtr;
CppSignature = callable.ToString();
ShortName = callable.ToShortString();
CppCallingConvention = callable.CallingConvention;
}
public CppCallingConvention CppCallingConvention { get; } = CppCallingConvention.Unknown;
public bool RequestRawPtr { get; }
private string CppSignature { get; }
private string ShortName { get; }
public bool CheckReturnType { get; }
public bool ForceReturnType { get; }
private bool AlwaysReturnHResult { get; }
public CsReturnValue ReturnValue { get; set; }
public bool SignatureOnly => GetParent<CsInterface>()?.IsCallback ?? false;
public override string DocUnmanagedName => CppSignature ?? "Unknown";
public override string DocUnmanagedShortName => ShortName;
public IReadOnlyList<CsParameter> Parameters => _parameters.GetList(this);
public IEnumerable<CsParameter> PublicParameters => _parameters.Enumerate(this)
.Where(param => !param.UsedAsReturn && param.Relations.Count == 0);
public IEnumerable<CsParameter> InRefInRefParameters => _parameters.Enumerate(this)
.Where(param => !param.IsOut);
public IEnumerable<CsParameter> LocalManagedReferenceParameters => _parameters.Enumerate(this)
.Where(param => param.IsLocalManagedReference);
public CsMarshalCallableBase ActualReturnValue
{
get
{
foreach (var param in _parameters.Enumerate(this).Where(param => param.UsedAsReturn))
{
return param;
}
return ReturnValue;
}
}
public override void FillDocItems(IList<string> docItems, IDocumentationLinker manager)
{
foreach (var param in PublicParameters)
docItems.Add("<param name=\"" + param.Name + "\">" + manager.GetSingleDoc(param) + "</param>");
if (HasReturnType)
docItems.Add("<returns>" + manager.GetSingleDoc(ActualReturnValue) + "</returns>");
}
public bool IsReturnStructLarge
{
get
{
// Workaround for https://github.com/dotnet/coreclr/issues/19474. This workaround is sufficient
// for DirectX on Windows x86 and x64. It may produce incorrect code on other platforms depending
// on the calling convention details.
if (ReturnValue.MarshalType is CsStruct csStruct)
{
return !csStruct.IsNativePrimitive && csStruct.Size > MaxSizeReturnParameter;
}
return false;
}
}
public Dictionary<PlatformDetectionType, InteropMethodSignature> InteropSignatures
{
get => interopSignatures ?? throw new InvalidOperationException($"Accessing non-initialized {nameof(InteropSignatures)}");
set
{
if (interopSignatures != null)
throw new InvalidOperationException($"Setting initialized {nameof(InteropSignatures)}");
interopSignatures = value;
}
}
// Hide return type only if it is a HRESULT and AlwaysReturnHResult is false
public bool IsReturnTypeHidden => CheckReturnType && IsReturnTypeResult && !AlwaysReturnHResult;
public bool IsReturnTypeResult => ReturnValue.PublicType.IsWellKnownType(Ioc.GlobalNamespace, WellKnownName.Result);
public bool HasReturnType => ReturnValue.PublicType != TypeRegistry.Void;
internal bool HasReturnStatement => HasReturnTypeParameter || HasReturnTypeValue;
internal bool HasReturnTypeValue => HasReturnType && (ForceReturnType || !IsReturnTypeHidden);
/// <summary>
/// Returns true if a parameter is marked to be used as the return type.
/// </summary>
public bool HasReturnTypeParameter => _parameters.Enumerate(this).Any(param => param.UsedAsReturn);
/// <summary>
/// Return the Public return type. If a out parameter is used as a public return type
/// then use the type of the out parameter for the public API.
/// </summary>
public string PublicReturnTypeQualifiedName
{
get
{
var returnValue = ActualReturnValue;
if (returnValue is CsParameter)
return returnValue.PublicType.QualifiedName;
if (IsReturnTypeHidden && !ForceReturnType)
return "void";
return returnValue.PublicType.QualifiedName;
}
}
/// <summary>
/// Return the name of the variable used to return the value
/// </summary>
public string ReturnName => ActualReturnValue.Name;
private protected override IEnumerable<IExpiring> ExpiringOnItemsChange
{
get
{
yield return _parameters.Expiring;
yield return this;
}
}
public virtual CsCallable Clone()
{
var method = (CsCallable) MemberwiseClone();
// Clear cached parameters
method.Expire();
method.ResetItems();
foreach (var parameter in Parameters)
method.Add(parameter.Clone());
method.ResetParentAfterClone();
return method;
}
public void Expire()
{
interopSignatures = null;
}
public override IEnumerable<CsBase> AdditionalItems => AppendNonNull(base.AdditionalItems, ReturnValue);
}
}