Beispiel #1
0
        void WriteDeleteMethodCS(ManagedMethod method, int level)
        {
            WriteLine(level + 1, "public void Dispose()");
            WriteLine(level + 1, "{");
            WriteLine(level + 2, "Dispose(true);");
            WriteLine(level + 2, "GC.SuppressFinalize(this);");
            WriteLine(level + 1, "}");
            WriteLine();

            WriteLine(level + 1, "protected virtual void Dispose(bool disposing)");
            WriteLine(level + 1, "{");
            WriteLine(level + 2, "if (_native != IntPtr.Zero)");
            WriteLine(level + 2, "{");
            if (method.Parent.Native.HasPreventDelete)
            {
                WriteLine(level + 3, "if (!_preventDelete)");
                WriteLine(level + 3, "{");
                WriteLine(level + 4, $"{GetFullNameC(method.Parent.Native)}_delete(_native);");
                WriteLine(level + 3, "}");
            }
            else
            {
                WriteLine(level + 3, $"{GetFullNameC(method.Parent.Native)}_delete(_native);");
            }
            WriteLine(level + 3, "_native = IntPtr.Zero;");
            WriteLine(level + 2, "}");
            WriteLine(level + 1, "}");

            // C# Destructor
            WriteLine();
            WriteLine(level + 1, $"~{method.Parent.Name}()");
            WriteLine(level + 1, "{");
            WriteLine(level + 2, "Dispose(false);");
            WriteLine(level + 1, "}");
        }
        void WriteDeleteMethodCS(ManagedMethod method, int level)
        {
            WriteLine(level + 1, "public void Dispose()");
            WriteLine(level + 1, "{");
            WriteLine(level + 2, "Dispose(true);");
            WriteLine(level + 2, "GC.SuppressFinalize(this);");
            WriteLine(level + 1, "}");
            WriteLine();

            WriteLine(level + 1, "protected virtual void Dispose(bool disposing)");
            WriteLine(level + 1, "{");
            WriteLine(level + 2, "if (_native != IntPtr.Zero)");
            WriteLine(level + 2, "{");
            if (method.Parent.Native.HasPreventDelete)
            {
                WriteLine(level + 3, "if (!_preventDelete)");
                WriteLine(level + 3, "{");
                WriteLine(level + 4, $"{GetFullNameC(method.Parent.Native)}_delete(_native);");
                WriteLine(level + 3, "}");
            }
            else
            {
                WriteLine(level + 3, $"{GetFullNameC(method.Parent.Native)}_delete(_native);");
            }
            WriteLine(level + 3, "_native = IntPtr.Zero;");
            WriteLine(level + 2, "}");
            WriteLine(level + 1, "}");

            // C# Destructor
            WriteLine();
            WriteLine(level + 1, $"~{method.Parent.Name}()");
            WriteLine(level + 1, "{");
            WriteLine(level + 2, "Dispose(false);");
            WriteLine(level + 1, "}");
        }
 public ManagedMethod Copy(ManagedClass parent)
 {
     var m = new ManagedMethod(Native, parent, Name)
     {
         Property = Property
     };
     //TODO: params
     return m;
 }
        private void WriteMethodMarshal(ManagedMethod method, int numParameters)
        {
            var    nativeMethod = method.Native;
            string methodName   = nativeMethod.IsConstructor ?
                                  $"{nativeMethod.Parent.FullyQualifiedName}" : $"{nativeMethod.Name}";

            var currentParams = method.Parameters.Take(numParameters);
            var paramStrings  = currentParams.Select(p =>
            {
                string marshal = BulletParser.GetTypeMarshalCppCli(p);
                if (!string.IsNullOrEmpty(marshal))
                {
                    return(marshal);
                }

                var paramType = p.Native.Type;
                if (paramType.IsBasic)
                {
                    return(p.Name);
                }

                string paramString = "";
                switch (paramType.Kind)
                {
                case TypeKind.Pointer:
                case TypeKind.LValueReference:
                    if (paramType.Kind == TypeKind.LValueReference)
                    {
                        // Dereference
                        paramString = "*";
                    }

                    if (paramType.Referenced.Target?.BaseClass != null)
                    {
                        // Cast native pointer from base class
                        paramString += $"({paramType.Referenced.FullName}*)";
                    }
                    break;
                }

                paramString += p.Name;
                if (paramType.Kind == TypeKind.Pointer && paramType.Referenced.Kind == TypeKind.Void)
                {
                    paramString += ".ToPointer()";
                }
                else
                {
                    paramString += "->_native";
                }
                return(paramString);
            });

            Write($"{methodName}(");
            string parameters = ListToLines(paramStrings, WriteTo.Source, 1);

            Write($"{parameters})");
        }
        public ManagedMethod Copy(ManagedClass parent)
        {
            var m = new ManagedMethod(Native, parent, Name)
            {
                Property = Property
            };

            //TODO: params
            return(m);
        }
Beispiel #6
0
        private ManagedClass GetManagedClass(ClassDefinition @class)
        {
            if (@class == null)
            {
                return(null);
            }

            ManagedClass managedClass;

            if (Classes.TryGetValue(@class.FullyQualifiedName, out managedClass))
            {
                return(managedClass);
            }

            if (@class.IsExcluded)
            {
                return(null);
            }

            string managedName = GetManagedClassName(@class);
            var    parent      = GetManagedClass(@class.Parent);

            managedClass                       = new ManagedClass(@class, managedName, parent);
            managedClass.BaseClass             = GetManagedClass(@class.BaseClass);
            Classes[@class.FullyQualifiedName] = managedClass;

            // Set parent header or class
            managedClass.Header = GetManagedHeader(@class.Header);
            if (parent != null)
            {
                parent.NestedClasses.Add(managedClass);
            }
            else
            {
                managedClass.Header.Classes.Add(managedClass);
            }

            // Managed methods
            foreach (var method in @class.Methods)
            {
                managedName = GetManagedMethodName(method);
                var managedMethod = new ManagedMethod(method, managedClass, managedName);
                foreach (var param in managedMethod.Parameters)
                {
                    param.Name = GetManagedParameterName(param.Native);
                }
            }

            return(managedClass);
        }
        bool MethodNeedsExtensions(ManagedMethod method)
        {
            // Extension constructors & static extension methods not supported
            if (method.Native.IsConstructor || method.Native.IsStatic)
            {
                return false;
            }

            foreach (var param in method.Parameters)
            {
                if (_extensionClassesInternal.ContainsKey(GetName(param.Native.Type)))
                {
                    return true;
                }
            }
            return false;
        }
Beispiel #8
0
        bool MethodNeedsExtensions(ManagedMethod method)
        {
            // Extension constructors & static extension methods not supported
            if (method.Native.IsConstructor || method.Native.IsStatic)
            {
                return(false);
            }

            foreach (var param in method.Parameters)
            {
                if (_extensionClassesInternal.ContainsKey(GetName(param.Native.Type)))
                {
                    return(true);
                }
            }
            return(false);
        }
Beispiel #9
0
        string GetPropertyName(ManagedMethod getter)
        {
            string name = getter.Name;

            var propertyType = getter.Native.IsVoid ? getter.Parameters[0].Native.Type : getter.Native.ReturnType;

            if ("bool".Equals(propertyType.Name) && _booleanVerbs.Any(v => name.StartsWith(v)))
            {
                return(name);
            }

            if (name.StartsWith("Get"))
            {
                return(name.Substring(3));
            }

            throw new NotImplementedException();
        }
Beispiel #10
0
        void WriteMethod(ManagedMethod method, int level, ref int overloadIndex, int numOptionalParams = 0)
        {
            var nativeMethod = method.Native;

            int numOptionalParamsTotal = nativeMethod.NumOptionalParameters;
            int numParameters          = method.Parameters.Length - numOptionalParamsTotal + numOptionalParams;

            // TODO: outValueParameter
            WriteMethodDeclaration(method, numParameters, level, overloadIndex, null);

            // Skip methods wrapped by C# properties
            if (method.Property == null)
            {
                // Constructor base call
                if (nativeMethod.IsConstructor && method.Parent.BaseClass != null)
                {
                    Write(level + 2, ": base(", WriteTo.CS);
                }
                else
                {
                    WriteLine(level + 1, "{", WriteTo.CS);
                    WriteTabs(level + 2, WriteTo.CS);
                }

                // TODO: outValueParameter
                WriteMethodDefinition(method, numParameters, overloadIndex, level, null);
                WriteLine(level + 1, "}", WriteTo.CS);
                hasCSWhiteSpace = false;
            }

            // If there was an optional parameter,
            // write the method again without it.
            overloadIndex++;
            if (numOptionalParams < numOptionalParamsTotal)
            {
                WriteMethod(method, level, ref overloadIndex, numOptionalParams + 1);
            }
        }
Beispiel #11
0
        void WriteMethodDefinition(ManagedMethod method, int numParameters, int overloadIndex, int level,
                                   ManagedParameter outValueParameter)
        {
            var nativeMethod = method.Native;

            if (nativeMethod.IsConstructor)
            {
                if (method.Parent.BaseClass == null)
                {
                    Write("_native = ");
                }
                Write($"{GetFullNameC(method.Parent.Native)}_new");
            }
            else
            {
                if (!nativeMethod.IsVoid)
                {
                    if (outValueParameter != null)
                    {
                        // Temporary variable
                        WriteLine(string.Format("{0} {1};",
                                                DotNetParser.GetManaged(outValueParameter.Native.Type.Referenced.Target).Name,
                                                outValueParameter.Name));
                        WriteTabs(level + 2);
                    }
                    else
                    {
                        Write($"return {BulletParser.GetTypeMarshalConstructorStartCS(nativeMethod)}");
                    }
                }

                Write($"{GetFullNameC(method.Parent.Native)}_{method.Native.Name}");
            }

            if (overloadIndex != 0)
            {
                Write((overloadIndex + 1).ToString());
            }

            Write('(');

            var parameters = method.Parameters.Take(numParameters)
                             .Select(p => GetParameterMarshal(p));

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

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

            Write(ListToLines(parameters, WriteTo.CS, level + 2));

            if (nativeMethod.IsConstructor && method.Parent.BaseClass != null)
            {
                Write(")");
                if (method.Parent.BaseClass.Native.HasPreventDelete)
                {
                    Write(", false");
                }
                WriteLine(")");
                WriteLine(level + 1, "{");
            }
            else
            {
                if (!nativeMethod.IsConstructor && !nativeMethod.IsVoid)
                {
                    Write(BulletParser.GetTypeMarshalConstructorEndCS(nativeMethod));
                }
                WriteLine(");");
            }

            // Cache property values
            if (nativeMethod.IsConstructor)
            {
                var methodParent = method.Parent;
                while (methodParent != null)
                {
                    foreach (var cachedProperty in methodParent.CachedProperties.OrderBy(p => p.Key))
                    {
                        foreach (var param in method.Parameters)
                        {
                            if (param.Name.ToLower().Equals(cachedProperty.Key.ToLower()) &&
                                GetName(param.Native.Type).Equals(GetName(cachedProperty.Value.Property.Type)))
                            {
                                WriteLine(level + 2,
                                          $"{cachedProperty.Value.CacheFieldName} = {param.Name};");
                            }
                        }
                    }
                    methodParent = methodParent.BaseClass;
                }
            }

            // Return temporary variable
            if (outValueParameter != null)
            {
                WriteLine(level + 2, $"return {outValueParameter.Name};");
            }
        }
        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 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);
        }
        string GetPropertyName(ManagedMethod getter)
        {
            string name = getter.Name;

            var propertyType = getter.Native.IsVoid ? getter.Parameters[0].Native.Type : getter.Native.ReturnType;
            if ("bool".Equals(propertyType.Name) && _booleanVerbs.Any(v => name.StartsWith(v)))
            {
                return name;
            }

            if (name.StartsWith("Get"))
            {
                return name.Substring(3);
            }

            throw new NotImplementedException();
        }
        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;
        }
        void WriteMethod(ManagedMethod method, int level, ref int overloadIndex, int numOptionalParams = 0)
        {
            var nativeMethod = method.Native;

            int numOptionalParamsTotal = nativeMethod.NumOptionalParameters;
            int numParameters = method.Parameters.Length - numOptionalParamsTotal + numOptionalParams;

            WriteMethodDeclaration(method, numParameters, level, overloadIndex);

            // Skip methods wrapped by C# properties
            if (method.Property == null)
            {
                // Constructor base call
                if (nativeMethod.IsConstructor && method.Parent.BaseClass != null)
                {
                    Write(level + 2, ": base(", WriteTo.CS);
                }
                else
                {
                    WriteLine(level + 1, "{", WriteTo.CS);
                    WriteTabs(level + 2, WriteTo.CS);
                }

                WriteMethodDefinition(method, numParameters, overloadIndex, level);
                WriteLine(level + 1, "}", WriteTo.CS);
                hasCSWhiteSpace = false;
            }

            // If there was an optional parameter,
            // write the method again without it.
            overloadIndex++;
            if (numOptionalParams < numOptionalParamsTotal)
            {
                WriteMethod(method, level, ref overloadIndex, numOptionalParams + 1);
            }
        }
        private void WriteMethod(ManagedMethod method, int numOptionalParams = 0)
        {
            var returnType = method.Native.ReturnType;
            bool convertReturnType = _extensionClassesInternal.ContainsKey(GetName(returnType));

            ClearBuffer();
            Write(2, "public unsafe static ");
            if (convertReturnType)
            {
                Write(_extensionClassesExternal[GetName(returnType)]);
            }
            else
            {
                Write(GetName(returnType));
            }
            Write($" {method.Name}(this {method.Parent.Name} obj");

            var extendedParams = new List<ParameterDefinition>();
            int numParameters = method.Parameters.Length - numOptionalParams;
            for (int i = 0; i < numParameters; i++)
            {
                Write(", ");

                var param = method.Parameters[i];
                if (_extensionClassesInternal.ContainsKey(GetName(param.Native.Type)))
                {
                    Write($"ref {_extensionClassesExternal[GetName(param.Native.Type)]} {param.Name}");
                    extendedParams.Add(param.Native);
                }
                else
                {
                    Write($"{GetName(param.Native.Type)} {param.Name}");
                }
            }
            WriteLine(')');

            WriteLine(2, "{");

            // Fix parameter pointers
            int tabs = 3;
            foreach (var param in extendedParams)
            {
                WriteLine(tabs, string.Format("fixed ({0}* {1}Ptr = &{2})",
                    _extensionClassesExternal[GetName(param.Type)], param.Name, param.Name));
                WriteLine(tabs, "{");
                tabs++;
            }

            WriteTabs(tabs);
            if (returnType.Kind != ClangSharp.TypeKind.Void)
            {
                Write("return ");
            }
            Write($"obj.{method.Name}(");
            bool hasOptionalParam = false;
            for (int i = 0; i < numParameters; i++)
            {
                var param = method.Parameters[i];
                if (_extensionClassesInternal.ContainsKey(GetName(param.Native.Type)))
                {
                    Write(string.Format("ref *({0}*){1}Ptr",
                        _extensionClassesInternal[GetName(param.Native.Type)], param.Name));
                }
                else
                {
                    Write(param.Name);
                }

                if (param.Native.IsOptional)
                {
                    hasOptionalParam = true;
                }

                if (i != numParameters - 1)
                {
                    Write(", ");
                }
            }
            Write(')');
            if (convertReturnType)
            {
                Write(_returnTypeConversion[GetName(returnType)]);
            }
            WriteLine(';');

            // Close fixed blocks
            while (tabs != 2)
            {
                tabs--;
                WriteLine(tabs, "}");
            }

            _extensionMethods.Add(new KeyValuePair<string, string>(method.Name, GetBufferString()));

            if (hasOptionalParam)
            {
                WriteMethod(method, numOptionalParams + 1);
            }
        }
Beispiel #18
0
        private void WriteMethod(ManagedMethod method, int numOptionalParams = 0)
        {
            var  returnType        = method.Native.ReturnType;
            bool convertReturnType = _extensionClassesInternal.ContainsKey(GetName(returnType));

            ClearBuffer();
            Write(2, "public unsafe static ");
            if (convertReturnType)
            {
                Write(_extensionClassesExternal[GetName(returnType)]);
            }
            else
            {
                Write(GetName(returnType));
            }
            Write($" {method.Name}(this {method.Parent.Name} obj");

            var extendedParams = new List <ParameterDefinition>();
            int numParameters  = method.Parameters.Length - numOptionalParams;

            for (int i = 0; i < numParameters; i++)
            {
                Write(", ");

                var param = method.Parameters[i];
                if (_extensionClassesInternal.ContainsKey(GetName(param.Native.Type)))
                {
                    Write($"ref {_extensionClassesExternal[GetName(param.Native.Type)]} {param.Name}");
                    extendedParams.Add(param.Native);
                }
                else
                {
                    Write($"{GetName(param.Native.Type)} {param.Name}");
                }
            }
            WriteLine(')');

            WriteLine(2, "{");

            // Fix parameter pointers
            int tabs = 3;

            foreach (var param in extendedParams)
            {
                WriteLine(tabs, string.Format("fixed ({0}* {1}Ptr = &{2})",
                                              _extensionClassesExternal[GetName(param.Type)], param.Name, param.Name));
                WriteLine(tabs, "{");
                tabs++;
            }

            WriteTabs(tabs);
            if (returnType.Kind != ClangSharp.TypeKind.Void)
            {
                Write("return ");
            }
            Write($"obj.{method.Name}(");
            bool hasOptionalParam = false;

            for (int i = 0; i < numParameters; i++)
            {
                var param = method.Parameters[i];
                if (_extensionClassesInternal.ContainsKey(GetName(param.Native.Type)))
                {
                    Write(string.Format("ref *({0}*){1}Ptr",
                                        _extensionClassesInternal[GetName(param.Native.Type)], param.Name));
                }
                else
                {
                    Write(param.Name);
                }

                if (param.Native.IsOptional)
                {
                    hasOptionalParam = true;
                }

                if (i != numParameters - 1)
                {
                    Write(", ");
                }
            }
            Write(')');
            if (convertReturnType)
            {
                Write(_returnTypeConversion[GetName(returnType)]);
            }
            WriteLine(';');

            // Close fixed blocks
            while (tabs != 2)
            {
                tabs--;
                WriteLine(tabs, "}");
            }

            _extensionMethods.Add(new KeyValuePair <string, string>(method.Name, GetBufferString()));

            if (hasOptionalParam)
            {
                WriteMethod(method, numOptionalParams + 1);
            }
        }
Beispiel #19
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 WriteMethodMarshal(ManagedMethod method, int numParameters)
        {
            var nativeMethod = method.Native;
            string methodName = nativeMethod.IsConstructor ?
                $"{nativeMethod.Parent.FullyQualifiedName}" : $"{nativeMethod.Name}";

            var currentParams = method.Parameters.Take(numParameters);
            var paramStrings = currentParams.Select(p =>
            {
                string marshal = BulletParser.GetTypeMarshalCppCli(p);
                if (!string.IsNullOrEmpty(marshal)) { return marshal; }

                var paramType = p.Native.Type;
                if (paramType.IsBasic) { return p.Name; }

                string paramString = "";
                switch (paramType.Kind)
                {
                    case TypeKind.Pointer:
                    case TypeKind.LValueReference:
                        if (paramType.Kind == TypeKind.LValueReference)
                        {
                            // Dereference
                            paramString = "*";
                        }

                        if (paramType.Referenced.Target?.BaseClass != null)
                        {
                            // Cast native pointer from base class
                            paramString += $"({paramType.Referenced.FullName}*)";
                        }
                        break;
                }

                paramString += p.Name;
                if (paramType.Kind == TypeKind.Pointer && paramType.Referenced.Kind == TypeKind.Void)
                {
                    paramString += ".ToPointer()";
                }
                else
                {
                    paramString += "->_native";
                }
                return paramString;
            });

            Write($"{methodName}(");
            string parameters = ListToLines(paramStrings, WriteTo.Source, 1);
            Write($"{parameters})");
        }
        void WriteMethodDefinition(ManagedMethod method, int numParameters, int overloadIndex, int level)
        {
            var nativeMethod = method.Native;
            if (nativeMethod.IsConstructor)
            {
                if (method.Parent.BaseClass == null)
                {
                    Write("_native = ");
                }
                Write($"{GetFullNameC(method.Parent.Native)}_new");
            }
            else
            {
                if (!nativeMethod.IsVoid)
                {
                    if (method.OutValueParameter != null)
                    {
                        // Temporary variable
                        WriteLine(string.Format("{0} {1};",
                            DotNetParser.GetManaged(method.OutValueParameter.Native.Type.Referenced.Target).Name,
                            method.OutValueParameter.Name));
                        WriteTabs(level + 2);
                    }
                    else
                    {
                        Write($"return {BulletParser.GetTypeMarshalConstructorStartCS(nativeMethod)}");
                    }
                }

                Write($"{GetFullNameC(method.Parent.Native)}_{method.Native.Name}");
            }

            if (overloadIndex != 0)
            {
                Write((overloadIndex + 1).ToString());
            }

            Write('(');

            var parameters = method.Parameters.Take(numParameters)
                .Select(p => GetParameterMarshal(p));
            if (method.OutValueParameter != null)
            {
                parameters = parameters.Concat(new[] { $"out {method.OutValueParameter.Name }" });
            }

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

            Write(ListToLines(parameters, WriteTo.CS, level + 2));

            if (nativeMethod.IsConstructor && method.Parent.BaseClass != null)
            {
                Write(")");
                if (method.Parent.BaseClass.Native.HasPreventDelete)
                {
                    Write(", false");
                }
                WriteLine(")");
                WriteLine(level + 1, "{");
            }
            else
            {
                if (!nativeMethod.IsConstructor && !nativeMethod.IsVoid)
                {
                    Write(BulletParser.GetTypeMarshalConstructorEndCS(nativeMethod));
                }
                WriteLine(");");
            }

            // Cache property values
            if (nativeMethod.IsConstructor)
            {
                var methodParent = method.Parent;
                while (methodParent != null)
                {
                    foreach (var cachedProperty in methodParent.CachedProperties.OrderBy(p => p.Key))
                    {
                        foreach (var param in method.Parameters)
                        {
                            if (param.Name.ToLower().Equals(cachedProperty.Key.ToLower())
                                && GetName(param.Native.Type).Equals(GetName(cachedProperty.Value.Property.Type)))
                            {
                                WriteLine(level + 2,
                                    $"{cachedProperty.Value.CacheFieldName} = {param.Name};");
                            }
                        }
                    }
                    methodParent = methodParent.BaseClass;
                }
            }

            // Return temporary variable
            if (method.OutValueParameter != null)
            {
                WriteLine(level + 2, $"return {method.OutValueParameter.Name};");
            }
        }
        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 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 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);
        }
        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 ManagedClass GetManagedClass(ClassDefinition @class)
        {
            if (@class == null) return null;

            ManagedClass managedClass;
            if (Classes.TryGetValue(@class.FullyQualifiedName, out managedClass))
            {
                return managedClass;
            }

            if (@class.IsExcluded) return null;

            string managedName = GetManagedClassName(@class);
            var parent = GetManagedClass(@class.Parent);
            managedClass = new ManagedClass(@class, managedName, parent);
            managedClass.BaseClass = GetManagedClass(@class.BaseClass);
            Classes[@class.FullyQualifiedName] = managedClass;

            // Set parent header or class
            managedClass.Header = GetManagedHeader(@class.Header);
            if (parent != null)
            {
                parent.NestedClasses.Add(managedClass);
            }
            else
            {
                managedClass.Header.Classes.Add(managedClass);
            }

            // Managed methods
            foreach (var method in @class.Methods)
            {
                managedName = GetManagedMethodName(method);
                var managedMethod = new ManagedMethod(method, managedClass, managedName);
                foreach (var param in managedMethod.Parameters)
                {
                    param.Name = GetManagedParameterName(param.Native);
                }
            }

            return managedClass;
        }