in SharpGen/Transform/MarshalledElementFactory.cs [181:283]
public CsParameter Create(CppParameter cppParameter, string name)
{
CsParameter param = new(ioc, cppParameter, name);
CreateCore(param);
if (cppParameter.IsAttributeRuleRedundant)
Logger.Message("Parameter [{0}] has redundant attribute rule specification", cppParameter.FullName);
static bool HasFlag(ParamAttribute value, ParamAttribute flag) => (value & flag) == flag;
// --------------------------------------------------------------------------------
// Pointer - Handle special cases
// --------------------------------------------------------------------------------
if (param.HasPointer)
{
var paramRule = cppParameter.Rule;
var numIndirections = cppParameter.Pointer.Count(static p => p is '*' or '&');
bool isBuffer, isIn, isInOut, isOut;
{
var cppAttribute = cppParameter.Attribute;
// Force Interface** to be ParamAttribute.Out
if (param.PublicType is CsInterface && cppAttribute == ParamAttribute.In && numIndirections == 2)
cppAttribute = ParamAttribute.Out;
isBuffer = HasFlag(cppAttribute, ParamAttribute.Buffer);
isIn = HasFlag(cppAttribute, ParamAttribute.In);
isInOut = HasFlag(cppAttribute, ParamAttribute.InOut);
isOut = HasFlag(cppAttribute, ParamAttribute.Out);
}
// Either In, InOut or Out is set
Debug.Assert((isIn ? 1 : 0) + (isInOut ? 1 : 0) + (isOut ? 1 : 0) == 1);
// --------------------------------------------------------------------------------
// Handling Parameter Interface
// --------------------------------------------------------------------------------
if (param.PublicType is CsInterface)
{
// Simplify logic by assuming interface instance pointer is the interface itself.
--numIndirections;
if (isOut)
param.Attribute = CsParameterAttribute.Out;
}
else if (isIn)
{
var publicType = param.PublicType;
param.Attribute = publicType is CsFundamentalType {IsPointerSize: true}
|| publicType.IsWellKnownType(GlobalNamespace, WellKnownName.FunctionCallback)
? CsParameterAttribute.In
: CsParameterAttribute.RefIn;
}
else if (isInOut)
{
if (param.IsOptional)
{
param.SetPublicResetMarshalType(PointerType(paramRule));
param.Attribute = CsParameterAttribute.In;
}
else
{
param.Attribute = CsParameterAttribute.Ref;
}
}
else if (isOut)
{
param.Attribute = CsParameterAttribute.Out;
}
switch (param.PublicType)
{
// Handle void* with Buffer attribute
case CsFundamentalType {IsUntypedPointer: true} when isBuffer:
param.Attribute = CsParameterAttribute.In;
param.IsArray = false;
break;
// Handle strings with Out attribute
case CsFundamentalType {IsString: true} when isOut:
param.Attribute = CsParameterAttribute.In;
param.IsArray = false;
param.SetPublicResetMarshalType(TypeRegistry.IntPtr);
break;
// There's no way to know how to deallocate native-allocated memory correctly
// since we don't know what allocator the native memory uses,
// so we treat any extra pointer indirections as IntPtr
case not CsFundamentalType {IsUntypedPointer: true} when numIndirections > 1:
param.IsArray = false;
param.SetPublicResetMarshalType(TypeRegistry.IntPtr);
break;
}
}
if (param.Relations.OfType<StructSizeRelation>().Any())
Logger.Error(
LoggingCodes.InvalidRelation,
$"Parameter [{cppParameter}] marked with a struct-size relationship"
);
return param;
}