void CSFunctionWriter::WriteManagedFunction(String& source)
{

    JSBClass* klass = function_->GetClass();
    JSBPackage* package = klass->GetPackage();

    String sig;
    String returnType = CSTypeHelper::GetManagedTypeString(function_->GetReturnType());

    GenManagedFunctionParameters(sig);

    String line = klass->IsInterface() ? "" : "public ";

    if (function_->IsStatic())
    {
        line += "static ";
    }

    bool marked = false;
    JSBClass* baseClass = klass->GetBaseClass();
    if (baseClass)
    {
        JSBFunction* override = baseClass->MatchFunction(function_, true);
        if (override)
        {
            marked = true;
            if (override->IsVirtual())
                line += "override ";
            else
                line += "new ";
        }
    }
void CSFunctionWriter::WriteManagedPInvokeFunctionSignature(String& source)
{
    JSBClass* klass = function_->GetClass();
    JSBPackage* package = klass->GetPackage();

    if (klass->IsInterface())
        return;

    source += "\n";

    // CoreCLR has pinvoke security demand code commented out, so we do not (currently) need this optimization:
    // https://github.com/dotnet/coreclr/issues/1605
    // line = "[SuppressUnmanagedCodeSecurity]\n";
    // source += IndentLine(line);

    String line = "[DllImport (Constants.LIBNAME, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]\n";
    source += IndentLine(line);

    String returnType = CSTypeHelper::GetPInvokeTypeString(function_->GetReturnType());

    // handled by out parameter
    if (function_->GetReturnType() && function_->GetReturnType()->type_->asVectorType())
        returnType = "void";

    if (returnType == "bool")
    {
        // default boolean marshal is 4 byte windows type BOOL and not 1 byte bool
        // https://blogs.msdn.microsoft.com/jaredpar/2008/10/14/pinvoke-and-bool-or-should-i-say-bool/        
        source += IndentLine("[return: MarshalAs(UnmanagedType.I1)]\n");
    }

    if (returnType == "string")
        returnType = "IntPtr";

    if (function_->IsConstructor())
        returnType = "IntPtr";

    const Vector<JSBFunctionType*>& parameters = function_->GetParameters();

    Vector<String> args;

    if (!function_->IsConstructor() && !function_->IsStatic())
    {
        args.Push("IntPtr self");
    }

    if (parameters.Size())
    {
        for (unsigned int i = 0; i < parameters.Size(); i++)
        {
            JSBFunctionType* ptype = parameters.At(i);

            String name = ptype->name_;

            if (name == "object")
                name = "_object";
            else if (name == "readonly")
                name = "readOnly";
            else if (name == "params")
                name = "parameters";

            // ignore "Context" parameters
            if (ptype->type_->asClassType())
            {
                JSBClassType* classType = ptype->type_->asClassType();
                JSBClass* klass = classType->class_;
                if (klass->GetName() == "Context")
                {
                    continue;
                }

                if (klass->IsNumberArray())
                {
                    args.Push("ref " + klass->GetName() + " " + name);
                }
                else
                {
                    args.Push("IntPtr " + name);
                }
            }
            else
            {
                args.Push(CSTypeHelper::GetPInvokeTypeString(ptype) + " " + name);
            }

        }
    }

    if (function_->GetReturnClass())
    {
        JSBClass* retClass = function_->GetReturnClass();

        if (retClass->IsNumberArray())
        {
            args.Push("ref " + retClass->GetName() + " retValue");
        }

    }
    else if (function_->GetReturnType() && function_->GetReturnType()->type_->asVectorType())
    {
        args.Push("IntPtr returnValue");
    }

    String pstring;
    pstring.Join(args, ", ");

    String fname = function_->IsConstructor() ? "Constructor" : function_->GetName();
    line = ToString("private static extern %s csb_%s_%s_%s_%u(%s);\n",
                    returnType.CString(), package->GetName().CString(), klass->GetName().CString(),
                    fname.CString(), function_->GetID(), pstring.CString());

    source += IndentLine(line);

    source += "\n";

}