private void WriteMethodDeclaration(ManagedMethod method, int numParameters, int level, int overloadIndex)
        {
            var nativeMethod = method.Native;

            EnsureWhiteSpace(WriteTo.CS);

            WriteTo cs;
            WriteTo dllImport = WriteTo.Buffer;

            if (method.Property != null)
            {
                // Do not write accessor methods of C# properties here
                cs = WriteTo.None;

                // Cached properties that are initialized only once
                // do not need a DllImport for the get method
                if (method.Parent.CachedProperties.ContainsKey(method.Property.Name) &&
                    method.Equals(method.Property.Getter))
                {
                    dllImport = WriteTo.None;
                }
            }
            else if (method.Name.Equals("delete"))
            {
                WriteDeleteMethodCS(method, level);
                cs = WriteTo.None;
            }
            else
            {
                Write(level + 1, "public ", WriteTo.CS);
                cs = WriteTo.CS;
            }

            // DllImport clause
            WriteLine(level + 1,
                "[DllImport(Native.Dll, CallingConvention = Native.Conv), SuppressUnmanagedCodeSecurity]",
                dllImport);
            if (nativeMethod.ReturnType != null && nativeMethod.ReturnType.Kind == TypeKind.Bool)
            {
                WriteLine(level + 1, "[return: MarshalAs(UnmanagedType.I1)]", dllImport);
            }
            Write(level + 1, "static extern ", dllImport);

            // Return type
            if (nativeMethod.IsConstructor)
            {
                Write("IntPtr ", dllImport);
            }
            else
            {
                var returnType = nativeMethod.ReturnType.Canonical;

                if (nativeMethod.IsStatic) Write("static ", cs);
                Write($"{GetTypeNameCS(returnType)} ", cs);

                if (method.OutValueParameter != null)
                {
                    Write("void ", dllImport);
                }
                else
                {
                    if (returnType.IsBasic)
                    {
                        Write(GetTypeNameCS(returnType), dllImport);
                    }
                    else if (returnType.Referenced != null)
                    {
                        if (returnType.Kind == TypeKind.LValueReference &&
                            returnType.Referenced.IsConst && returnType.Referenced.Canonical.IsBasic)
                        {
                            Write(GetTypeNameCS(returnType.Referenced.Canonical), dllImport);
                        }
                        else
                        {
                            Write("IntPtr", dllImport);
                        }
                    }
                    else
                    {
                        // Return structures to an additional out parameter, not immediately
                        Write("void", dllImport);
                    }
                    Write(' ', dllImport);
                }
            }


            // Name
            string methodName = nativeMethod.IsConstructor ? "new" : method.Native.Name;
            if (overloadIndex != 0)
            {
                methodName += (overloadIndex + 1).ToString();
            }
            Write($"{GetFullNameC(method.Parent.Native)}_{methodName}(", dllImport);
            Write($"{method.Name}(", cs);


            // Parameters
            var parameters = method.Parameters.Take(numParameters);
            var parametersCs = parameters.Select(p => $"{GetParameterTypeNameCS(p.Native)} {p.Name}");
            WriteLine($"{ListToLines(parametersCs, WriteTo.CS, level + 1)})", cs);

            if (method.OutValueParameter != null) parameters = parameters.Concat(new[] { method.OutValueParameter });

            var parametersDllImport = parameters.Select(p => $"{GetParameterTypeNameDllImport(p.Native)} {p.Native.Name}");

            // The first parameter is the instance pointer (if not constructor or static method)
            if (!nativeMethod.IsConstructor && !nativeMethod.IsStatic)
            {
                parametersDllImport =
                    new[] { "IntPtr obj" }.Concat(parametersDllImport);
            }

            WriteLine($"{string.Join(", ", parametersDllImport)});", dllImport);
        }
        private void WriteMethod(ManagedMethod method, int level, int numOptionalParams = 0)
        {
            var nativeMethod = method.Native;
            var parentClass = method.Parent;

            // No whitespace between get/set methods
            if (!(method.Property != null &&
                method.Equals(method.Property.Setter)))
            {
                EnsureSourceWhiteSpace();
                hasHeaderWhiteSpace = false;
            }

            // #ifndef DISABLE_FEATURE
            bool hasConditional = false;
            if (method.Property == null)
            {
                foreach (var param in method.Parameters)
                {
                    string typeConditional = GetTypeConditional(param.Native.Type, parentClass.Header);
                    if (typeConditional != null)
                    {
                        WriteLine($"#ifndef {typeConditional}", WriteTo.Header | WriteTo.Source);
                        hasSourceWhiteSpace = true;
                        hasConditional = true;
                    }
                }
            }

            WriteMethodDeclaration(method, level, numOptionalParams);

            var prevTo = To;
            To = WriteTo.Source;

            // Constructor chaining
            int numParameters = method.Parameters.Length - numOptionalParams;
            // Getters with parameter for return value
            if (numParameters == 1 && method.Property != null && method.Equals(method.Property.Getter))
            {
                numParameters = 0;
            }
            var currentParams = method.Parameters.Take(numParameters).ToList();

            bool doConstructorChaining = false;
            if (nativeMethod.IsConstructor && parentClass.BaseClass != null)
            {
                // If there is no need for marshalling code, we can chain constructors
                doConstructorChaining = currentParams.All(p => !DefaultParser.TypeRequiresMarshal(p.Native.Type));

                Write(1, $": {parentClass.BaseClass.Name}(");

                if (doConstructorChaining)
                {
                    Write("new ");
                    WriteMethodMarshal(method, numParameters);
                    if (parentClass.BaseClass.Native.HasPreventDelete)
                    {
                        Write(", false");
                    }
                }
                else
                {
                    Write('0');
                }

                WriteLine(')');
            }

            // Method body
            WriteLine('{');
            if (!doConstructorChaining)
            {
                WriteMethodDefinition(method, numParameters);
            }

            // Cache property values
            if (nativeMethod.IsConstructor)
            {
                var assignments = new List<string>();
                var methodParent = method.Parent;
                while (methodParent != null)
                {
                    foreach (var cachedProperty in methodParent.CachedProperties.OrderBy(p => p.Key))
                    {
                        foreach (var param in currentParams)
                        {
                            if (!param.Name.ToLower().Equals(cachedProperty.Key.ToLower())) continue;

                            var paramType = GetName(param.Native.Type);
                            var propType = GetName(cachedProperty.Value.Property.Type);
                            if (!paramType.Equals(propType)) return;

                            string assignment = $"\t{cachedProperty.Value.CacheFieldName} = {param.Name};";
                            assignments.Add(assignment);
                        }
                    }
                    methodParent = methodParent.BaseClass;
                }
                if (assignments.Count != 0)
                {
                    EnsureSourceWhiteSpace();
                    foreach (string assignment in assignments)
                    {
                        WriteLine(assignment);
                    }
                    hasSourceWhiteSpace = false;
                }
            }
            WriteLine('}');
            hasSourceWhiteSpace = false;

            // #endif // DISABLE_FEATURE
            if (hasConditional)
            {
                foreach (var param in currentParams)
                {
                    string typeConditional = GetTypeConditional(param.Native.Type, method.Parent.Header);
                    if (typeConditional != null)
                    {
                        WriteLine("#endif", WriteTo.Header | WriteTo.Source);
                        hasHeaderWhiteSpace = true;
                    }
                }
            }

            // If there are optional parameters, then output all possible combinations of calls
            if (currentParams.Any() && currentParams.Last().Native.IsOptional)
            {
                WriteMethod(method, level, numOptionalParams + 1);
            }

            To = prevTo;
        }
Esempio n. 3
0
        private void WriteMethodDeclaration(ManagedMethod method, int numParameters, int level, int overloadIndex,
                                            ManagedParameter outValueParameter = null)
        {
            var nativeMethod = method.Native;

            EnsureWhiteSpace(WriteTo.CS);

            WriteTo cs;
            WriteTo dllImport = WriteTo.Buffer;

            if (method.Property != null)
            {
                // Do not write accessor methods of C# properties here
                cs = WriteTo.None;

                // Cached properties that are initialized only once
                // do not need a DllImport for the get method
                if (method.Parent.CachedProperties.ContainsKey(method.Property.Name) &&
                    method.Equals(method.Property.Getter))
                {
                    dllImport = WriteTo.None;
                }
            }
            else if (method.Name.Equals("delete"))
            {
                WriteDeleteMethodCS(method, level);
                cs = WriteTo.None;
            }
            else
            {
                Write(level + 1, "public ", WriteTo.CS);
                cs = WriteTo.CS;
            }

            // DllImport clause
            WriteLine(level + 1,
                      "[DllImport(Native.Dll, CallingConvention = Native.Conv), SuppressUnmanagedCodeSecurity]",
                      dllImport);
            if (nativeMethod.ReturnType != null && nativeMethod.ReturnType.Kind == TypeKind.Bool)
            {
                WriteLine(level + 1, "[return: MarshalAs(UnmanagedType.I1)]", dllImport);
            }
            Write(level + 1, "static extern ", dllImport);

            // Return type
            if (nativeMethod.IsConstructor)
            {
                Write("IntPtr ", dllImport);
            }
            else
            {
                var returnType = nativeMethod.ReturnType.Canonical;

                if (nativeMethod.IsStatic)
                {
                    Write("static ", cs);
                }
                Write($"{GetTypeNameCS(returnType)} ", cs);

                if (outValueParameter != null)
                {
                    Write("void ", dllImport);
                }
                else
                {
                    if (returnType.IsBasic)
                    {
                        Write(GetTypeNameCS(returnType), dllImport);
                    }
                    else if (returnType.Referenced != null)
                    {
                        if (returnType.Kind == TypeKind.LValueReference &&
                            returnType.Referenced.IsConst && returnType.Referenced.Canonical.IsBasic)
                        {
                            Write(GetTypeNameCS(returnType.Referenced.Canonical), dllImport);
                        }
                        else
                        {
                            Write("IntPtr", dllImport);
                        }
                    }
                    else
                    {
                        // Return structures to an additional out parameter, not immediately
                        Write("void", dllImport);
                    }
                    Write(' ', dllImport);
                }
            }


            // Name
            string methodName = nativeMethod.IsConstructor ? "new" : method.Native.Name;

            if (overloadIndex != 0)
            {
                methodName += (overloadIndex + 1).ToString();
            }
            Write($"{GetFullNameC(method.Parent.Native)}_{methodName}(", dllImport);
            Write($"{method.Name}(", cs);


            // Parameters
            var parameters   = method.Parameters.Take(numParameters);
            var parametersCs = parameters.Select(p => $"{GetParameterTypeNameCS(p.Native)} {p.Name}");

            WriteLine($"{ListToLines(parametersCs, WriteTo.CS, level + 1)})", cs);

            if (outValueParameter != null)
            {
                parameters = parameters.Concat(new[] { outValueParameter });
            }

            var parametersDllImport = parameters.Select(p => $"{GetParameterTypeNameDllImport(p.Native)} {p.Native.Name}");

            // The first parameter is the instance pointer (if not constructor or static method)
            if (!nativeMethod.IsConstructor && !nativeMethod.IsStatic)
            {
                parametersDllImport =
                    new[] { "IntPtr obj" }.Concat(parametersDllImport);
            }

            WriteLine($"{string.Join(", ", parametersDllImport)});", dllImport);
        }
        private void WriteMethodDeclaration(ManagedMethod method, int level, int numOptionalParams)
        {
            var nativeMethod = method.Native;

            WriteTabs(level + 1, WriteTo.Header);

            if (nativeMethod.IsStatic) Write("static ", WriteTo.Header);

            // Return type
            if (!nativeMethod.IsConstructor)
            {
                var returnType = nativeMethod.ReturnType;

                if (method.Property != null)
                {
                    if (method.Equals(method.Property.Getter))
                    {
                        // If property name matches type name, resolve ambiguity
                        if (method.Property.Name.Equals(GetName(method.Property.Type)))
                        {
                            Write(Project.NamespaceName + "::", WriteTo.Header);
                        }

                        // Getter with parameter for return value
                        if (method.Parameters.Length == 1)
                        {
                            returnType = method.Parameters[0].Native.Type;
                        }
                    }
                }

                Write($"{GetTypeName(returnType)} ", WriteTo.Header | WriteTo.Source);
            }


            // Name
            string headerMethodName;
            string sourceMethodName;
            if (nativeMethod.IsConstructor)
            {
                headerMethodName = method.Parent.Name;
                sourceMethodName = headerMethodName;
            }
            else if (method.Property != null)
            {
                headerMethodName = method.Property.Getter.Equals(method) ? "get" : "set";
                sourceMethodName = $"{method.Property.Name}::{headerMethodName}";
            }
            else
            {
                headerMethodName = method.Name;
                sourceMethodName = headerMethodName;
            }
            Write($"{headerMethodName}(", WriteTo.Header);
            Write($"{GetFullNameManaged(method.Parent)}::{sourceMethodName}(", WriteTo.Source);


            // Parameters
            int numParameters = method.Parameters.Length - numOptionalParams;
            // Getters with parameter for return value
            if (numParameters == 1 && method.Property != null && method.Equals(method.Property.Getter))
            {
                numParameters = 0;
            }
            var currentParams = method.Parameters.Take(numParameters).ToList();
            var paramStrings = currentParams
                .Select(p => $"{GetParameterMarshal(p.Native)} {p.Name}").ToList();

            string parameters = ListToLines(paramStrings, WriteTo.Header, level + 1);
            WriteLine($"{parameters});", WriteTo.Header);

            parameters = ListToLines(paramStrings, WriteTo.Source);
            WriteLine($"{parameters})", WriteTo.Source);
        }
        void WriteMethodDefinition(ManagedMethod method, int numParameters)
        {
            var nativeMethod = method.Native;
            var parentClass = method.Parent.Native;

            // Type marshalling prologue
            bool needTypeMarshalEpilogue = false;
            if (nativeMethod.Field == null)
            {
                foreach (var param in method.Parameters)
                {
                    string prologue = BulletParser.GetTypeMarshalPrologueCppCli(param);
                    if (!string.IsNullOrEmpty(prologue))
                    {
                        WriteLine(1, prologue);
                    }

                    // Do we need a type marshalling epilogue?
                    if (!needTypeMarshalEpilogue)
                    {
                        string epilogue = BulletParser.GetTypeMarshalEpilogueCppCli(param);
                        if (!string.IsNullOrEmpty(epilogue))
                        {
                            needTypeMarshalEpilogue = true;
                        }
                    }
                }
            }

            WriteTabs(1);
            if (nativeMethod.IsConstructor)
            {
                Write("_native = new ");
            }
            else if (!nativeMethod.IsVoid)
            {
                //if (method.ReturnType.IsBasic || method.ReturnType.Referenced != null)
                if (needTypeMarshalEpilogue)
                {
                    // Return after epilogue (cleanup)
                    Write($"{GetTypeName(nativeMethod.ReturnType)} ret = ");
                }
                else
                {
                    // Return immediately
                    Write("return ");
                }
                Write(BulletParser.GetTypeMarshalConstructorStart(nativeMethod));
            }
            else if (method.Property != null && method.Equals(method.Property.Getter))
            {
                Write(BulletParser.GetTypeMarshalConstructorStart(nativeMethod));
            }

            // Native is defined as static_cast<className*>(_native)
            string nativePointer = (parentClass.BaseClass != null) ? "Native" : "_native";

            if (nativeMethod.Field != null)
            {
                var property = method.Property;
                if (method.Equals(property.Getter))
                {
                    CachedProperty cachedProperty;
                    if (method.Parent.CachedProperties.TryGetValue(property.Name, out cachedProperty))
                    {
                        Write(cachedProperty.CacheFieldName);
                    }
                    else
                    {
                        Write($"{nativePointer}->{nativeMethod.Field.Name}");
                    }
                }
                else if (property.Setter != null && method.Equals(property.Setter))
                {
                    var param = method.Parameters[0];
                    var paramType = param.Native.Type;
                    var fieldSet = BulletParser.GetTypeMarshalFieldSetCppCli(nativeMethod.Field, param, nativePointer);
                    if (!string.IsNullOrEmpty(fieldSet))
                    {
                        Write(fieldSet);
                    }
                    else
                    {
                        Write($"{nativePointer}->{nativeMethod.Field.Name} = ");
                        switch (paramType.Kind)
                        {
                            case TypeKind.Pointer:
                            case TypeKind.LValueReference:
                                if (paramType.Kind == TypeKind.LValueReference)
                                {
                                    // Dereference
                                    Write('*');
                                }

                                if (paramType.Referenced.Target != null &&
                                    paramType.Referenced.Target.BaseClass != null)
                                {
                                    // Cast native pointer from base class
                                    Write($"({paramType.Referenced.FullName}*)");
                                }
                                break;
                        }
                        Write(param.Name);
                        if (!paramType.IsBasic)
                        {
                            Write("->_native");
                        }
                    }
                }
            }
            else
            {
                if (nativeMethod.IsConstructor)
                {
                }
                else if (nativeMethod.IsStatic)
                {
                    Write(parentClass.FullyQualifiedName + "::");
                }
                else
                {
                    Write(nativePointer + "->");
                }
                To = WriteTo.Source;
                WriteMethodMarshal(method, numParameters);
            }
            if (!nativeMethod.IsConstructor && !nativeMethod.IsVoid)
            {
                Write(BulletParser.GetTypeMarshalConstructorEnd(nativeMethod));
            }
            WriteLine(';');

            // Write type marshalling epilogue
            if (needTypeMarshalEpilogue)
            {
                foreach (var param in method.Parameters)
                {
                    string epilogue = BulletParser.GetTypeMarshalEpilogueCppCli(param);
                    if (!string.IsNullOrEmpty(epilogue))
                    {
                        WriteLine(1, epilogue);
                    }
                }
                if (!nativeMethod.IsVoid)
                {
                    WriteLine(1, "return ret;");
                }
            }
        }
        private void WriteMethod(ManagedMethod method, int level, int numOptionalParams = 0)
        {
            var nativeMethod = method.Native;
            var parentClass  = method.Parent;

            // No whitespace between get/set methods
            if (!(method.Property != null &&
                  method.Equals(method.Property.Setter)))
            {
                EnsureSourceWhiteSpace();
                hasHeaderWhiteSpace = false;
            }

            // #ifndef DISABLE_FEATURE
            bool hasConditional = false;

            if (method.Property == null)
            {
                foreach (var param in method.Parameters)
                {
                    string typeConditional = GetTypeConditional(param.Native.Type, parentClass.Header);
                    if (typeConditional != null)
                    {
                        WriteLine($"#ifndef {typeConditional}", WriteTo.Header | WriteTo.Source);
                        hasSourceWhiteSpace = true;
                        hasConditional      = true;
                    }
                }
            }

            WriteMethodDeclaration(method, level, numOptionalParams);

            var prevTo = To;

            To = WriteTo.Source;

            // Constructor chaining
            int numParameters = method.Parameters.Length - numOptionalParams;

            // Getters with parameter for return value
            if (numParameters == 1 && method.Property != null && method.Equals(method.Property.Getter))
            {
                numParameters = 0;
            }
            var currentParams = method.Parameters.Take(numParameters).ToList();

            bool doConstructorChaining = false;

            if (nativeMethod.IsConstructor && parentClass.BaseClass != null)
            {
                // If there is no need for marshalling code, we can chain constructors
                doConstructorChaining = currentParams.All(p => !DefaultParser.TypeRequiresMarshal(p.Native.Type));

                Write(1, $": {parentClass.BaseClass.Name}(");

                if (doConstructorChaining)
                {
                    Write("new ");
                    WriteMethodMarshal(method, numParameters);
                    if (parentClass.BaseClass.Native.HasPreventDelete)
                    {
                        Write(", false");
                    }
                }
                else
                {
                    Write('0');
                }

                WriteLine(')');
            }

            // Method body
            WriteLine('{');
            if (!doConstructorChaining)
            {
                WriteMethodDefinition(method, numParameters);
            }

            // Cache property values
            if (nativeMethod.IsConstructor)
            {
                var assignments  = new List <string>();
                var methodParent = method.Parent;
                while (methodParent != null)
                {
                    foreach (var cachedProperty in methodParent.CachedProperties.OrderBy(p => p.Key))
                    {
                        foreach (var param in currentParams)
                        {
                            if (!param.Name.ToLower().Equals(cachedProperty.Key.ToLower()))
                            {
                                continue;
                            }

                            var paramType = GetName(param.Native.Type);
                            var propType  = GetName(cachedProperty.Value.Property.Type);
                            if (!paramType.Equals(propType))
                            {
                                return;
                            }

                            string assignment = $"\t{cachedProperty.Value.CacheFieldName} = {param.Name};";
                            assignments.Add(assignment);
                        }
                    }
                    methodParent = methodParent.BaseClass;
                }
                if (assignments.Count != 0)
                {
                    EnsureSourceWhiteSpace();
                    foreach (string assignment in assignments)
                    {
                        WriteLine(assignment);
                    }
                    hasSourceWhiteSpace = false;
                }
            }
            WriteLine('}');
            hasSourceWhiteSpace = false;

            // #endif // DISABLE_FEATURE
            if (hasConditional)
            {
                foreach (var param in currentParams)
                {
                    string typeConditional = GetTypeConditional(param.Native.Type, method.Parent.Header);
                    if (typeConditional != null)
                    {
                        WriteLine("#endif", WriteTo.Header | WriteTo.Source);
                        hasHeaderWhiteSpace = true;
                    }
                }
            }

            // If there are optional parameters, then output all possible combinations of calls
            if (currentParams.Any() && currentParams.Last().Native.IsOptional)
            {
                WriteMethod(method, level, numOptionalParams + 1);
            }

            To = prevTo;
        }
        private void WriteMethodDeclaration(ManagedMethod method, int level, int numOptionalParams)
        {
            var nativeMethod = method.Native;

            WriteTabs(level + 1, WriteTo.Header);

            if (nativeMethod.IsStatic)
            {
                Write("static ", WriteTo.Header);
            }

            // Return type
            if (!nativeMethod.IsConstructor)
            {
                var returnType = nativeMethod.ReturnType;

                if (method.Property != null)
                {
                    if (method.Equals(method.Property.Getter))
                    {
                        // If property name matches type name, resolve ambiguity
                        if (method.Property.Name.Equals(GetName(method.Property.Type)))
                        {
                            Write(Project.NamespaceName + "::", WriteTo.Header);
                        }

                        // Getter with parameter for return value
                        if (method.Parameters.Length == 1)
                        {
                            returnType = method.Parameters[0].Native.Type;
                        }
                    }
                }

                Write($"{GetTypeName(returnType)} ", WriteTo.Header | WriteTo.Source);
            }


            // Name
            string headerMethodName;
            string sourceMethodName;

            if (nativeMethod.IsConstructor)
            {
                headerMethodName = method.Parent.Name;
                sourceMethodName = headerMethodName;
            }
            else if (method.Property != null)
            {
                headerMethodName = method.Property.Getter.Equals(method) ? "get" : "set";
                sourceMethodName = $"{method.Property.Name}::{headerMethodName}";
            }
            else
            {
                headerMethodName = method.Name;
                sourceMethodName = headerMethodName;
            }
            Write($"{headerMethodName}(", WriteTo.Header);
            Write($"{GetFullNameManaged(method.Parent)}::{sourceMethodName}(", WriteTo.Source);


            // Parameters
            int numParameters = method.Parameters.Length - numOptionalParams;

            // Getters with parameter for return value
            if (numParameters == 1 && method.Property != null && method.Equals(method.Property.Getter))
            {
                numParameters = 0;
            }
            var currentParams = method.Parameters.Take(numParameters).ToList();
            var paramStrings  = currentParams
                                .Select(p => $"{GetParameterMarshal(p.Native)} {p.Name}").ToList();

            string parameters = ListToLines(paramStrings, WriteTo.Header, level + 1);

            WriteLine($"{parameters});", WriteTo.Header);

            parameters = ListToLines(paramStrings, WriteTo.Source);
            WriteLine($"{parameters})", WriteTo.Source);
        }
        void WriteMethodDefinition(ManagedMethod method, int numParameters)
        {
            var nativeMethod = method.Native;
            var parentClass  = method.Parent.Native;

            // Type marshalling prologue
            bool needTypeMarshalEpilogue = false;

            if (nativeMethod.Field == null)
            {
                foreach (var param in method.Parameters)
                {
                    string prologue = BulletParser.GetTypeMarshalPrologueCppCli(param);
                    if (!string.IsNullOrEmpty(prologue))
                    {
                        WriteLine(1, prologue);
                    }

                    // Do we need a type marshalling epilogue?
                    if (!needTypeMarshalEpilogue)
                    {
                        string epilogue = BulletParser.GetTypeMarshalEpilogueCppCli(param);
                        if (!string.IsNullOrEmpty(epilogue))
                        {
                            needTypeMarshalEpilogue = true;
                        }
                    }
                }
            }

            WriteTabs(1);
            if (nativeMethod.IsConstructor)
            {
                Write("_native = new ");
            }
            else if (!nativeMethod.IsVoid)
            {
                //if (method.ReturnType.IsBasic || method.ReturnType.Referenced != null)
                if (needTypeMarshalEpilogue)
                {
                    // Return after epilogue (cleanup)
                    Write($"{GetTypeName(nativeMethod.ReturnType)} ret = ");
                }
                else
                {
                    // Return immediately
                    Write("return ");
                }
                Write(BulletParser.GetTypeMarshalConstructorStart(nativeMethod));
            }
            else if (method.Property != null && method.Equals(method.Property.Getter))
            {
                Write(BulletParser.GetTypeMarshalConstructorStart(nativeMethod));
            }

            // Native is defined as static_cast<className*>(_native)
            string nativePointer = (parentClass.BaseClass != null) ? "Native" : "_native";

            if (nativeMethod.Field != null)
            {
                var property = method.Property;
                if (method.Equals(property.Getter))
                {
                    CachedProperty cachedProperty;
                    if (method.Parent.CachedProperties.TryGetValue(property.Name, out cachedProperty))
                    {
                        Write(cachedProperty.CacheFieldName);
                    }
                    else
                    {
                        Write($"{nativePointer}->{nativeMethod.Field.Name}");
                    }
                }
                else if (property.Setter != null && method.Equals(property.Setter))
                {
                    var param     = method.Parameters[0];
                    var paramType = param.Native.Type;
                    var fieldSet  = BulletParser.GetTypeMarshalFieldSetCppCli(nativeMethod.Field, param, nativePointer);
                    if (!string.IsNullOrEmpty(fieldSet))
                    {
                        Write(fieldSet);
                    }
                    else
                    {
                        Write($"{nativePointer}->{nativeMethod.Field.Name} = ");
                        switch (paramType.Kind)
                        {
                        case TypeKind.Pointer:
                        case TypeKind.LValueReference:
                            if (paramType.Kind == TypeKind.LValueReference)
                            {
                                // Dereference
                                Write('*');
                            }

                            if (paramType.Referenced.Target != null &&
                                paramType.Referenced.Target.BaseClass != null)
                            {
                                // Cast native pointer from base class
                                Write($"({paramType.Referenced.FullName}*)");
                            }
                            break;
                        }
                        Write(param.Name);
                        if (!paramType.IsBasic)
                        {
                            Write("->_native");
                        }
                    }
                }
            }
            else
            {
                if (nativeMethod.IsConstructor)
                {
                }
                else if (nativeMethod.IsStatic)
                {
                    Write(parentClass.FullyQualifiedName + "::");
                }
                else
                {
                    Write(nativePointer + "->");
                }
                To = WriteTo.Source;
                WriteMethodMarshal(method, numParameters);
            }
            if (!nativeMethod.IsConstructor && !nativeMethod.IsVoid)
            {
                Write(BulletParser.GetTypeMarshalConstructorEnd(nativeMethod));
            }
            WriteLine(';');

            // Write type marshalling epilogue
            if (needTypeMarshalEpilogue)
            {
                foreach (var param in method.Parameters)
                {
                    string epilogue = BulletParser.GetTypeMarshalEpilogueCppCli(param);
                    if (!string.IsNullOrEmpty(epilogue))
                    {
                        WriteLine(1, epilogue);
                    }
                }
                if (!nativeMethod.IsVoid)
                {
                    WriteLine(1, "return ret;");
                }
            }
        }