void FindForwardReferences(List <ManagedClass> forwardRefs, ManagedClass @class)
        {
            var header = @class.Header.Native;

            foreach (var prop in @class.Properties)
            {
                AddForwardReference(forwardRefs, prop.Type, header);
            }

            var methods = @class.Methods.Where(m => m.Native.Access == AccessSpecifier.Public && !m.Native.IsExcluded);

            if (@class.Native.HidePublicConstructors)
            {
                methods = methods.Where(m => !m.Native.IsConstructor);
            }
            foreach (var method in methods)
            {
                AddForwardReference(forwardRefs, method.Native.ReturnType, header);

                foreach (var param in method.Parameters)
                {
                    AddForwardReference(forwardRefs, param.Native.Type, header);
                }
            }

            foreach (var cl in @class.NestedClasses)
            {
                FindForwardReferences(forwardRefs, cl);
            }
        }
Beispiel #2
0
 private static string GetFullNameManaged(ManagedClass @class)
 {
     if (@class.Parent != null)
     {
         return($"{GetFullNameManaged(@class.Parent)}.{@class.Name}");
     }
     return(@class.Name);
 }
 public ManagedMethod Copy(ManagedClass parent)
 {
     var m = new ManagedMethod(Native, parent, Name)
     {
         Property = Property
     };
     //TODO: params
     return m;
 }
        public ManagedMethod Copy(ManagedClass parent)
        {
            var m = new ManagedMethod(Native, parent, Name)
            {
                Property = Property
            };

            //TODO: params
            return(m);
        }
        bool ClassNeedsExtensions(ManagedClass c)
        {
            foreach (var prop in c.Properties)
            {
                if (_extensionClassesInternal.ContainsKey(GetName(prop.Type)))
                {
                    return true;
                }
            }

            return c.Methods.Any(MethodNeedsExtensions);
        }
Beispiel #6
0
        bool ClassNeedsExtensions(ManagedClass c)
        {
            foreach (var prop in c.Properties)
            {
                if (_extensionClassesInternal.ContainsKey(GetName(prop.Type)))
                {
                    return(true);
                }
            }

            return(c.Methods.Any(MethodNeedsExtensions));
        }
        }                                                // property that wraps this get/set method

        public ManagedMethod(MethodDefinition nativeMethod, ManagedClass parent, string name)
        {
            Native = nativeMethod;
            Parent = parent;
            Name   = name;

            Parameters = nativeMethod.Parameters.Select(p => new ManagedParameter(p)).ToArray();

            if (parent != null)
            {
                parent.Methods.Add(this);
            }
        }
Beispiel #8
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);
        }
        public ManagedMethod(MethodDefinition nativeMethod, ManagedClass parent, string name)
        {
            Native = nativeMethod;
            Parent = parent;
            Name = name;

            Parameters = nativeMethod.Parameters.Select(p => new ManagedParameter(p)).ToArray();
            if (nativeMethod.OutValueParameter != null)
            {
                OutValueParameter = new ManagedParameter(nativeMethod.OutValueParameter);
            }

            if (parent != null)
            {
                parent.Methods.Add(this);
            }
        }
Beispiel #10
0
        // Accepts a ClassDefinition for recursion
        void WriteEnumClass(ManagedClass @class, int level)
        {
            var @enum = @class.Native as EnumDefinition;

            if (@enum == null)
            {
                foreach (var childClass in @class.NestedClasses)
                {
                    WriteEnumClass(childClass, level);
                }
                return;
            }

            EnsureWhiteSpace();

            if (@enum.IsFlags)
            {
                WriteLine(level, "[Flags]");
            }

            WriteLine(level, $"public enum {@class.Name}");
            WriteLine(level, "{");
            for (int i = 0; i < @enum.EnumConstants.Count; i++)
            {
                var constant = @enum.EnumConstants[i];
                if (constant.Value.Equals(""))
                {
                    Write(level + 1, constant.Constant);
                }
                else
                {
                    Write(level + 1, $"{constant.Constant} = {constant.Value}");
                }
                if (i < @enum.EnumConstants.Count - 1)
                {
                    Write(',');
                }
                WriteLine();
            }
            WriteLine(level, "}");
            hasCSWhiteSpace = false;
        }
        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;
        }
        void WriteClass(ManagedClass @class, int level)
        {
            var nativeClass = @class.Native;

            EnsureHeaderWhiteSpace();
            EnsureSourceWhiteSpace();

            var prevTo = To;

            To = WriteTo.Header;
            WriteTabs(level);

            // Access modifier
            if (level == 1)
            {
                Write("public ");
            }

            // Class definition
            Write($"ref class {@class.Name}");

            // abstract/sealed keywords
            if (nativeClass.IsAbstract)
            {
                Write(" abstract");
            }
            else if (nativeClass.IsStatic)
            {
                Write(" sealed");
            }

            // Inheritance
            if (@class.BaseClass != null)
            {
                WriteLine($" : {@class.BaseClass.Name}");
            }
            else if (nativeClass.IsTrackingDisposable)
            {
                WriteLine(" : ITrackingDisposable");
            }
            else
            {
                WriteLine();
            }

            // Class body start
            WriteLine(level, "{");

            // Default access for ref class
            var currentAccess = RefAccessSpecifier.Private;

            // Nested classes
            if ([email protected](IsExcludedClass))
            {
                WriteClasses(@class.NestedClasses, ref currentAccess, level);
                currentAccess = RefAccessSpecifier.Public;
                WriteLine(WriteTo.Source);
            }

            // Private constructor for classes that aren't instanced
            if (nativeClass.IsStatic)
            {
                EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Private);
                WriteLine(level + 1, $"{@class.Name}() {{}}");
                hasHeaderWhiteSpace = false;
            }

            // Downcast native pointer if any methods in a derived class use it
            if (@class.BaseClass != null && @class.Methods.Select(m => m.Native)
                .Any(m => !m.IsConstructor && !m.IsStatic && !m.IsExcluded &&
                     m.Access == AccessSpecifier.Public))
            {
                EnsureSourceWhiteSpace();
                WriteLine($"#define Native static_cast<{nativeClass.FullyQualifiedName}*>(_native)", WriteTo.Source);
                hasSourceWhiteSpace = false;
            }

            // Write the native pointer to the base class
            if (@class.BaseClass == null && !nativeClass.IsStatic)
            {
                if (@class.NestedClasses.Any(c => !IsExcludedClass(c)))
                {
                    WriteLine();
                }
                if (nativeClass.IsTrackingDisposable)
                {
                    EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Public);
                    WriteLine(level + 1, "virtual event EventHandler^ OnDisposing;");
                    WriteLine(level + 1, "virtual event EventHandler^ OnDisposed;");
                    hasHeaderWhiteSpace = false;
                }
                EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Internal);

                Write(level + 1, nativeClass.FullyQualifiedName);
                WriteLine("* _native;");
                hasHeaderWhiteSpace = false;
            }

            EnsureHeaderWhiteSpace();
            EnsureSourceWhiteSpace();

            // Private fields
            // _isDisposed flag
            if (nativeClass.IsTrackingDisposable)
            {
                EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Private);
                WriteLine(level + 1, "bool _isDisposed;");
                hasHeaderWhiteSpace = false;
            }
            // _preventDelete flag
            if (nativeClass.HasPreventDelete)
            {
                EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Private);
                WriteLine(level + 1, "bool _preventDelete;");
                hasHeaderWhiteSpace = false;
            }

            // Cached property fields
            foreach (var cachedProperty in @class.CachedProperties.OrderBy(p => p.Key))
            {
                EnsureAccess(level, ref currentAccess, cachedProperty.Value.Access);
                string typename  = GetTypeName(cachedProperty.Value.Property.Type);
                string fieldName = cachedProperty.Key;
                fieldName = char.ToLower(fieldName[0]) + fieldName.Substring(1);
                WriteLine(level + 1, $"{typename} _{fieldName};");
                hasHeaderWhiteSpace = false;
            }

            // Constructors and destructors
            if (!nativeClass.IsStatic)
            {
                // Write unmanaged constructor
                // TODO: Write constructor from unmanaged pointer only if the class is ever instantiated in this way.
                if (!nativeClass.NoInternalConstructor)
                {
                    // Declaration
                    To = WriteTo.Header;
                    EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Internal);
                    WriteLine(level + 1,
                              $"{@class.Name}({nativeClass.FullyQualifiedName}* native);");

                    // Definition
                    To = WriteTo.Source;
                    // TODO: use full name once class hierarchy flattening is implemented
                    //WriteLine($"{@class.FullNameCppCli}::{@class.ManagedName}({@class.FullyQualifiedName}* native)");
                    WriteLine($"{@class.Name}::{@class.Name}({nativeClass.FullyQualifiedName}* native)");
                    if (@class.BaseClass != null)
                    {
                        WriteLine(1, $": {@class.BaseClass.Name}(native)");
                    }

                    // Body
                    WriteLine('{');
                    if (@class.BaseClass == null)
                    {
                        WriteLine(1, "_native = native;");
                    }
                    WriteLine('}');

                    hasHeaderWhiteSpace = false;
                    hasSourceWhiteSpace = false;
                }

                // Write destructor & finalizer
                if (@class.BaseClass == null)
                {
                    To = WriteTo.Header;

                    // ECMA-372 19.13.1: "The access-specifier of a destructor in a ref class is ignored."
                    // ECMA-372 19.13.2: "The access-specifier of a finalizer in a ref class is ignored."
                    WriteLine(level + 1, $"~{@class.Name}();");
                    WriteLine(level + 1, $"!{@class.Name}();");
                    hasHeaderWhiteSpace = false;

                    To = WriteTo.Source;
                    EnsureSourceWhiteSpace();
                    WriteLine($"{GetFullNameManaged(@class)}::~{@class.Name}()");
                    WriteLine('{');
                    WriteLine(1, $"this->!{@class.Name}();");
                    WriteLine('}');
                    WriteLine();

                    WriteLine($"{GetFullNameManaged(@class)}::!{@class.Name}()");
                    WriteLine('{');
                    if (nativeClass.IsTrackingDisposable)
                    {
                        WriteLine(1, "if (this->IsDisposed)");
                        WriteLine(2, "return;");
                        WriteLine();
                        WriteLine(1, "OnDisposing(this, nullptr);");
                        WriteLine();
                    }
                    if (nativeClass.HasPreventDelete)
                    {
                        WriteLine(1, "if (!_preventDelete)");
                        WriteLine(1, "{");
                        WriteLine(2, "delete _native;");
                        WriteLine(1, "}");
                    }
                    else
                    {
                        WriteLine(1, "delete _native;");
                    }
                    if (nativeClass.IsTrackingDisposable)
                    {
                        WriteLine(1, "_isDisposed = true;");
                        WriteLine();
                        WriteLine(1, "OnDisposed(this, nullptr);");
                    }
                    else
                    {
                        WriteLine(1, "_native = NULL;");
                    }
                    WriteLine('}');
                    hasSourceWhiteSpace = false;
                }

                // Write public constructors
                if (!nativeClass.HidePublicConstructors && !nativeClass.IsAbstract)
                {
                    var constructors = @class.Methods.Where(m => m.Native.IsConstructor && m.Native.Access == AccessSpecifier.Public);
                    if (constructors.Any())
                    {
                        EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Public);

                        foreach (var constructor in constructors)
                        {
                            WriteMethod(constructor, level);
                        }
                    }
                }
            }

            // Write non-constructor methods
            var methods = @class.Methods
                          .Where(m => !m.Native.IsConstructor && !m.Native.IsExcluded &&
                                 m.Native.Access == AccessSpecifier.Public && m.Property == null);

            if (methods.Any())
            {
                EnsureHeaderWhiteSpace();

                foreach (var method in methods)
                {
                    EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Public);
                    WriteMethod(method, level);
                }
            }

            // Write properties (includes unmanaged fields and getters/setters)
            To = WriteTo.Header;
            foreach (PropertyDefinition prop in @class.Properties)
            {
                string typeConditional = GetTypeConditional(prop.Type, @class.Header);
                if (typeConditional != null)
                {
                    WriteLine($"#ifndef {typeConditional}", WriteTo.Header | WriteTo.Source);
                    hasSourceWhiteSpace = true;
                }
                else
                {
                    EnsureHeaderWhiteSpace();
                }

                EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Public);
                WriteLine(level + 1, $"property {GetTypeName(prop.Type)} {prop.Name}");
                WriteLine(level + 1, "{");

                // Getter/Setter
                WriteMethod(prop.Getter, level + 1);
                if (prop.Setter != null)
                {
                    WriteMethod(prop.Setter, level + 1);
                }

                WriteLine(level + 1, "}");

                if (typeConditional != null)
                {
                    WriteLine("#endif", WriteTo.Header | WriteTo.Source);
                    hasSourceWhiteSpace = false;
                }

                hasHeaderWhiteSpace = false;
            }

            WriteLine(level, "};");
            hasHeaderWhiteSpace = false;

            To = prevTo;
        }
        private void WriteClass(ManagedClass @class)
        {
            foreach (var child in @class.NestedClasses)
            {
                WriteClass(child);
            }

            if (!ClassNeedsExtensions(@class))
            {
                return;
            }

            _extensionMethods.Clear();

            To = WriteTo.CS;
            EnsureWhiteSpace();
            Write(1, "[EditorBrowsable(EditorBrowsableState.Never)]");
            WriteLine(1, $"public static class {@class.Name}Extensions");
            WriteLine(1, "{");

            To = WriteTo.Buffer;
            foreach (var prop in @class.Properties)
            {
                if (_extensionClassesInternal.ContainsKey(GetName(prop.Type)))
                {
                    string typeName = _extensionClassesExternal[GetName(prop.Type)];

                    // Getter with out parameter
                    ClearBuffer();
                    WriteLine(2, string.Format("public unsafe static void Get{0}(this {1} obj, out {2} value)",
                        prop.Name, @class.Name, typeName));
                    WriteLine(2, "{");

                    WriteLine(3, $"fixed ({typeName}* valuePtr = &value)");
                    WriteLine(3, "{");
                    Write(4, $"*({_extensionClassesInternal[GetName(prop.Type)]}");
                    WriteLine(string.Format("*({0}*)valuePtr = obj.{1};",
                        _extensionClassesInternal[GetName(prop.Type)], prop.Name));
                    WriteLine(3, "}");

                    WriteLine(2, "}");

                    _extensionMethods.Add(new KeyValuePair<string, string>("Get" + prop.Name, GetBufferString()));

                    // Getter with return value
                    ClearBuffer();
                    WriteLine(2, string.Format("public static {0} Get{1}(this {1} obj)",
                        typeName, prop.Name, @class.Name));
                    WriteLine(2, "{");

                    WriteLine(3, $"{typeName} value;");
                    WriteLine(3, $"Get{prop.Name}(obj, out value)");
                    WriteLine(3, "return value;");

                    WriteLine(2, "}");

                    _extensionMethods.Add(new KeyValuePair<string, string>("Get" + prop.Name, GetBufferString()));

                    if (prop.Setter == null)
                    {
                        continue;
                    }

                    // Setter with ref parameter
                    ClearBuffer();
                    WriteLine(2, string.Format("public unsafe static void Set{0}(this {1} obj, ref {2} value)",
                        prop.Name, @class.Name, typeName));
                    WriteLine(2, "{");

                    WriteLine(3, $"fixed ({typeName}* valuePtr = &value)");
                    WriteLine(3, "{");
                    WriteLine(4, string.Format("obj.{0} = *({1}*)valuePtr;",
                        prop.Name, _extensionClassesInternal[GetName(prop.Type)]));
                    WriteLine(3, "}");

                    WriteLine(2, "}");

                    _extensionMethods.Add(new KeyValuePair<string, string>("Set" + prop.Name, GetBufferString()));

                    // Setter with non-ref parameter
                    ClearBuffer();
                    WriteLine(2, string.Format("public static void Set{0}(this {1} obj, {2} value)",
                        prop.Name, @class.Name, typeName));
                    WriteLine(2, "{");
                    WriteLine(3, $"Set{prop.Name}(obj, ref value);");
                    WriteLine(2, "}");

                    _extensionMethods.Add(new KeyValuePair<string, string>("Set" + prop.Name, GetBufferString()));
                }
            }

            foreach (var method in @class.Methods)
            {
                if (!MethodNeedsExtensions(method))
                {
                    continue;
                }

                WriteMethod(method);
            }

            foreach (var method in _extensionMethods.OrderBy(key => key.Key))
            {
                EnsureWhiteSpace(WriteTo.CS);
                Write(method.Value, WriteTo.CS);
                hasCSWhiteSpace = false;
            }

            WriteLine(1, "}", WriteTo.CS);
            hasCSWhiteSpace = false;
        }
 private static string GetFullNameManaged(ManagedClass @class)
 {
     if (@class.Parent != null)
     {
         return $"{GetFullNameManaged(@class.Parent)}.{@class.Name}";
     }
     return @class.Name;
 }
        void WriteClass(ManagedClass @class, int level)
        {
            var nativeClass = @class.Native;

            // Write class definition
            EnsureWhiteSpace();
            Write(level, "public ");
            if (nativeClass.IsStatic) Write("static ");
            if (@class.Parent != null && @class.Parent.BaseClass != null)
            {
                if (@class.Parent.BaseClass.NestedClasses
                    .Any(c => c != @class && c.Name.Equals(@class.Name)))
                {
                    Write("new ");
                }
            }
            if (nativeClass.IsAbstract) Write("abstract ");
            Write($"class {@class.Name}");
            if (@class.BaseClass != null)
            {
                WriteLine($" : {GetFullNameManaged(@class.BaseClass)}");
            }
            else if (nativeClass.IsStatic)
            {
                WriteLine();
            }
            else
            {
                WriteLine(" : IDisposable");
            }
            WriteLine(level, "{");
            hasCSWhiteSpace = true;

            // Write child classes
            foreach (var c in @class.NestedClasses
                .Where(c => !IsExcludedClass(c))
                .OrderBy(GetFullNameManaged))
            {
                WriteClass(c, level + 1);
            }

            // Write the native pointer to the base class
            if (@class.BaseClass == null && !nativeClass.IsStatic)
            {
                EnsureWhiteSpace();
                WriteLine(level + 1, "internal IntPtr _native;");
                if (nativeClass.HasPreventDelete)
                {
                    WriteLine(level + 1, "bool _preventDelete;");
                }
                hasCSWhiteSpace = false;
            }

            // Write cached property fields
            if (@class.CachedProperties.Any())
            {
                EnsureWhiteSpace();
                foreach (var cachedProperty in @class.CachedProperties.OrderBy(p => p.Key))
                {
                    string fieldName = cachedProperty.Key;
                    fieldName = char.ToLower(fieldName[0]) + fieldName.Substring(1);
                    WriteLine(level + 1, string.Format("{0} {1} _{2};",
                        cachedProperty.Value.Access.ToString().ToLower(),
                        GetTypeNameCS(cachedProperty.Value.Property.Type),
                        fieldName));
                }
                hasCSWhiteSpace = false;
            }

            // Write methods
            ClearBuffer();

            // Write constructors
            if (!nativeClass.IsStatic)
            {
                // Write C# internal constructor
                if (!nativeClass.NoInternalConstructor)
                {
                    EnsureWhiteSpace();
                    Write(level + 1, $"internal {@class.Name}(IntPtr native");
                    if (nativeClass.HasPreventDelete)
                    {
                        Write(", bool preventDelete");
                    }
                    WriteLine(')');
                    if (@class.BaseClass != null)
                    {
                        Write(level + 2, ": base(native");
                        if (nativeClass.HasPreventDelete)
                        {
                            if ([email protected])
                            {
                                // Base class should also have preventDelete
                                //throw new NotImplementedException();
                            }
                            Write(", preventDelete");
                        }
                        else if (@class.BaseClass.Native.HasPreventDelete)
                        {
                            Write(", true");
                        }
                        WriteLine(')');
                    }
                    WriteLine(level + 1, "{");
                    if (@class.BaseClass == null)
                    {
                        WriteLine(level + 2, "_native = native;");
                        if (nativeClass.HasPreventDelete)
                        {
                            WriteLine(level + 2, "_preventDelete = preventDelete;");
                        }
                    }
                    WriteLine(level + 1, "}");
                    hasCSWhiteSpace = false;
                }

                // Write public constructors
                if (!nativeClass.HidePublicConstructors && !nativeClass.IsAbstract)
                {
                    int overloadIndex = 0;
                    var constructors = @class.Methods.Where(m => m.Native.IsConstructor && !m.Native.IsExcluded);
                    if (constructors.Any())
                    {
                        foreach (var constructor in constructors)
                        {
                            WriteMethod(constructor, level, ref overloadIndex);
                        }
                    }
                }
            }

            // Write methods
            var methods = @class.Methods.Where(m => !m.Native.IsConstructor && !m.Native.IsExcluded).OrderBy(m => m.Name);
            var methodsOverloads = methods.GroupBy(m => m.Name);
            foreach (var groupByName in methodsOverloads)
            {
                int overloadIndex = 0;
                foreach (var method in groupByName)
                {
                    WriteMethod(method, level, ref overloadIndex);
                }
            }

            // Write properties
            foreach (var prop in @class.Properties)
            {
                WriteProperty(prop, level);
            }

            // Write delete method
            // TODO: skip delete methods in classes that can't be constructed.
            /*
            if (@class.BaseClass == null && !nativeClass.IsStatic)
            {
                int overloadIndex = 0;
                var del = new MethodDefinition("delete", @class, 0);
                del.ReturnType = new TypeRefDefinition("void");
                WriteMethod(del, level, ref overloadIndex);
                @class.Methods.Remove(del);
            }
            */
            // Write DllImport clauses
            if (GetBufferString().Length != 0)
            {
                EnsureWhiteSpace(WriteTo.CS);
                Write(GetBufferString(), WriteTo.CS);
            }

            WriteLine(level, "}", WriteTo.CS);
            hasCSWhiteSpace = false;
        }
        // Accepts a ClassDefinition for recursion
        void WriteEnumClass(ManagedClass @class, int level)
        {
            var @enum = @class.Native as EnumDefinition;
            if (@enum == null)
            {
                foreach (var childClass in @class.NestedClasses)
                {
                    WriteEnumClass(childClass, level);
                }
                return;
            }

            EnsureWhiteSpace();

            if (@enum.IsFlags) WriteLine(level, "[Flags]");

            WriteLine(level, $"public enum {@class.Name}");
            WriteLine(level, "{");
            for (int i = 0; i < @enum.EnumConstants.Count; i++)
            {
                var constant = @enum.EnumConstants[i];
                if (constant.Value.Equals(""))
                {
                    Write(level + 1, constant.Constant);
                }
                else
                {
                    Write(level + 1, $"{constant.Constant} = {constant.Value}");
                }
                if (i < @enum.EnumConstants.Count - 1)
                {
                    Write(',');
                }
                WriteLine();
            }
            WriteLine(level, "}");
            hasCSWhiteSpace = false;
        }
 public ManagedClass(ClassDefinition nativeClass, string managedName, ManagedClass parent)
 {
     Native = nativeClass;
     Name   = managedName;
     Parent = parent;
 }
Beispiel #18
0
        void WriteClass(ManagedClass @class, int level)
        {
            var nativeClass = @class.Native;

            // Write class definition
            EnsureWhiteSpace();
            Write(level, "public ");
            if (nativeClass.IsStatic)
            {
                Write("static ");
            }
            if (@class.Parent != null && @class.Parent.BaseClass != null)
            {
                if (@class.Parent.BaseClass.NestedClasses
                    .Any(c => c != @class && c.Name.Equals(@class.Name)))
                {
                    Write("new ");
                }
            }
            if (nativeClass.IsAbstract)
            {
                Write("abstract ");
            }
            Write($"class {@class.Name}");
            if (@class.BaseClass != null)
            {
                WriteLine($" : {GetFullNameManaged(@class.BaseClass)}");
            }
            else if (nativeClass.IsStatic)
            {
                WriteLine();
            }
            else
            {
                WriteLine(" : IDisposable");
            }
            WriteLine(level, "{");
            hasCSWhiteSpace = true;

            // Write child classes
            foreach (var c in @class.NestedClasses
                     .Where(c => !IsExcludedClass(c))
                     .OrderBy(GetFullNameManaged))
            {
                WriteClass(c, level + 1);
            }

            // Write the native pointer to the base class
            if (@class.BaseClass == null && !nativeClass.IsStatic)
            {
                EnsureWhiteSpace();
                WriteLine(level + 1, "internal IntPtr _native;");
                if (nativeClass.HasPreventDelete)
                {
                    WriteLine(level + 1, "bool _preventDelete;");
                }
                hasCSWhiteSpace = false;
            }

            // Write cached property fields
            if (@class.CachedProperties.Any())
            {
                EnsureWhiteSpace();
                foreach (var cachedProperty in @class.CachedProperties.OrderBy(p => p.Key))
                {
                    string fieldName = cachedProperty.Key;
                    fieldName = char.ToLower(fieldName[0]) + fieldName.Substring(1);
                    WriteLine(level + 1, string.Format("{0} {1} _{2};",
                                                       cachedProperty.Value.Access.ToString().ToLower(),
                                                       GetTypeNameCS(cachedProperty.Value.Property.Type),
                                                       fieldName));
                }
                hasCSWhiteSpace = false;
            }

            // Write methods
            ClearBuffer();

            // Write constructors
            if (!nativeClass.IsStatic)
            {
                // Write C# internal constructor
                if (!nativeClass.NoInternalConstructor)
                {
                    EnsureWhiteSpace();
                    Write(level + 1, $"internal {@class.Name}(IntPtr native");
                    if (nativeClass.HasPreventDelete)
                    {
                        Write(", bool preventDelete");
                    }
                    WriteLine(')');
                    if (@class.BaseClass != null)
                    {
                        Write(level + 2, ": base(native");
                        if (nativeClass.HasPreventDelete)
                        {
                            if ([email protected])
                            {
                                // Base class should also have preventDelete
                                //throw new NotImplementedException();
                            }
                            Write(", preventDelete");
                        }
                        else if (@class.BaseClass.Native.HasPreventDelete)
                        {
                            Write(", true");
                        }
                        WriteLine(')');
                    }
                    WriteLine(level + 1, "{");
                    if (@class.BaseClass == null)
                    {
                        WriteLine(level + 2, "_native = native;");
                        if (nativeClass.HasPreventDelete)
                        {
                            WriteLine(level + 2, "_preventDelete = preventDelete;");
                        }
                    }
                    WriteLine(level + 1, "}");
                    hasCSWhiteSpace = false;
                }

                // Write public constructors
                if (!nativeClass.HidePublicConstructors && !nativeClass.IsAbstract)
                {
                    int overloadIndex = 0;
                    var constructors  = @class.Methods.Where(m => m.Native.IsConstructor && !m.Native.IsExcluded);
                    if (constructors.Any())
                    {
                        foreach (var constructor in constructors)
                        {
                            WriteMethod(constructor, level, ref overloadIndex);
                        }
                    }
                }
            }

            // Write methods
            var methods          = @class.Methods.Where(m => !m.Native.IsConstructor && !m.Native.IsExcluded).OrderBy(m => m.Name);
            var methodsOverloads = methods.GroupBy(m => m.Name);

            foreach (var groupByName in methodsOverloads)
            {
                int overloadIndex = 0;
                foreach (var method in groupByName)
                {
                    WriteMethod(method, level, ref overloadIndex);
                }
            }

            // Write properties
            foreach (var prop in @class.Properties)
            {
                WriteProperty(prop, level);
            }

            // Write delete method
            // TODO: skip delete methods in classes that can't be constructed.

            /*
             * if (@class.BaseClass == null && !nativeClass.IsStatic)
             * {
             *  int overloadIndex = 0;
             *  var del = new MethodDefinition("delete", @class, 0);
             *  del.ReturnType = new TypeRefDefinition("void");
             *  WriteMethod(del, level, ref overloadIndex);
             *  @class.Methods.Remove(del);
             * }
             */
            // Write DllImport clauses
            if (GetBufferString().Length != 0)
            {
                EnsureWhiteSpace(WriteTo.CS);
                Write(GetBufferString(), WriteTo.CS);
            }

            WriteLine(level, "}", WriteTo.CS);
            hasCSWhiteSpace = false;
        }
 public ManagedClass(ClassDefinition nativeClass, string managedName, ManagedClass parent)
 {
     Native = nativeClass;
     Name = managedName;
     Parent = parent;
 }
        void FindForwardReferences(List<ManagedClass> forwardRefs, ManagedClass @class)
        {
            var header = @class.Header.Native;

            foreach (var prop in @class.Properties)
            {
                AddForwardReference(forwardRefs, prop.Type, header);
            }

            var methods = @class.Methods.Where(m => m.Native.Access == AccessSpecifier.Public && !m.Native.IsExcluded);
            if (@class.Native.HidePublicConstructors) methods = methods.Where(m => !m.Native.IsConstructor);
            foreach (var method in methods)
            {
                AddForwardReference(forwardRefs, method.Native.ReturnType, header);

                foreach (var param in method.Parameters)
                {
                    AddForwardReference(forwardRefs, param.Native.Type, header);
                }
            }

            foreach (var cl in @class.NestedClasses)
            {
                FindForwardReferences(forwardRefs, cl);
            }
        }
        void WriteClass(ManagedClass @class, int level)
        {
            var nativeClass = @class.Native;

            EnsureHeaderWhiteSpace();
            EnsureSourceWhiteSpace();

            var prevTo = To;

            To = WriteTo.Header;
            WriteTabs(level);

            // Access modifier
            if (level == 1) Write("public ");

            // Class definition
            Write($"ref class {@class.Name}");

            // abstract/sealed keywords
            if (nativeClass.IsAbstract) Write(" abstract");
            else if (nativeClass.IsStatic) Write(" sealed");

            // Inheritance
            if (@class.BaseClass != null)
            {
                WriteLine($" : {@class.BaseClass.Name}");
            }
            else if (nativeClass.IsTrackingDisposable) WriteLine(" : ITrackingDisposable");
            else WriteLine();

            // Class body start
            WriteLine(level, "{");

            // Default access for ref class
            var currentAccess = RefAccessSpecifier.Private;

            // Nested classes
            if ([email protected](IsExcludedClass))
            {
                WriteClasses(@class.NestedClasses, ref currentAccess, level);
                currentAccess = RefAccessSpecifier.Public;
                WriteLine(WriteTo.Source);
            }

            // Private constructor for classes that aren't instanced
            if (nativeClass.IsStatic)
            {
                EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Private);
                WriteLine(level + 1, $"{@class.Name}() {{}}");
                hasHeaderWhiteSpace = false;
            }

            // Downcast native pointer if any methods in a derived class use it
            if (@class.BaseClass != null && @class.Methods.Select(m => m.Native)
                .Any(m => !m.IsConstructor && !m.IsStatic && !m.IsExcluded &&
                    m.Access == AccessSpecifier.Public))
            {
                EnsureSourceWhiteSpace();
                WriteLine($"#define Native static_cast<{nativeClass.FullyQualifiedName}*>(_native)", WriteTo.Source);
                hasSourceWhiteSpace = false;
            }

            // Write the native pointer to the base class
            if (@class.BaseClass == null && !nativeClass.IsStatic)
            {
                if (@class.NestedClasses.Any(c => !IsExcludedClass(c)))
                {
                    WriteLine();
                }
                if (nativeClass.IsTrackingDisposable)
                {
                    EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Public);
                    WriteLine(level + 1, "virtual event EventHandler^ OnDisposing;");
                    WriteLine(level + 1, "virtual event EventHandler^ OnDisposed;");
                    hasHeaderWhiteSpace = false;
                }
                EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Internal);

                Write(level + 1, nativeClass.FullyQualifiedName);
                WriteLine("* _native;");
                hasHeaderWhiteSpace = false;
            }

            EnsureHeaderWhiteSpace();
            EnsureSourceWhiteSpace();

            // Private fields
            // _isDisposed flag
            if (nativeClass.IsTrackingDisposable)
            {
                EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Private);
                WriteLine(level + 1, "bool _isDisposed;");
                hasHeaderWhiteSpace = false;
            }
            // _preventDelete flag
            if (nativeClass.HasPreventDelete)
            {
                EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Private);
                WriteLine(level + 1, "bool _preventDelete;");
                hasHeaderWhiteSpace = false;
            }

            // Cached property fields
            foreach (var cachedProperty in @class.CachedProperties.OrderBy(p => p.Key))
            {
                EnsureAccess(level, ref currentAccess, cachedProperty.Value.Access);
                string typename = GetTypeName(cachedProperty.Value.Property.Type);
                string fieldName = cachedProperty.Key;
                fieldName = char.ToLower(fieldName[0]) + fieldName.Substring(1);
                WriteLine(level + 1, $"{typename} _{fieldName};");
                hasHeaderWhiteSpace = false;
            }

            // Constructors and destructors
            if (!nativeClass.IsStatic)
            {
                // Write unmanaged constructor
                // TODO: Write constructor from unmanaged pointer only if the class is ever instantiated in this way.
                if (!nativeClass.NoInternalConstructor)
                {
                    // Declaration
                    To = WriteTo.Header;
                    EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Internal);
                    WriteLine(level + 1,
                        $"{@class.Name}({nativeClass.FullyQualifiedName}* native);");

                    // Definition
                    To = WriteTo.Source;
                    // TODO: use full name once class hierarchy flattening is implemented
                    //WriteLine($"{@class.FullNameCppCli}::{@class.ManagedName}({@class.FullyQualifiedName}* native)");
                    WriteLine($"{@class.Name}::{@class.Name}({nativeClass.FullyQualifiedName}* native)");
                    if (@class.BaseClass != null)
                    {
                        WriteLine(1, $": {@class.BaseClass.Name}(native)");
                    }

                    // Body
                    WriteLine('{');
                    if (@class.BaseClass == null) WriteLine(1, "_native = native;");
                    WriteLine('}');

                    hasHeaderWhiteSpace = false;
                    hasSourceWhiteSpace = false;
                }

                // Write destructor & finalizer
                if (@class.BaseClass == null)
                {
                    To = WriteTo.Header;

                    // ECMA-372 19.13.1: "The access-specifier of a destructor in a ref class is ignored."
                    // ECMA-372 19.13.2: "The access-specifier of a finalizer in a ref class is ignored."
                    WriteLine(level + 1, $"~{@class.Name}();");
                    WriteLine(level + 1, $"!{@class.Name}();");
                    hasHeaderWhiteSpace = false;

                    To = WriteTo.Source;
                    EnsureSourceWhiteSpace();
                    WriteLine($"{GetFullNameManaged(@class)}::~{@class.Name}()");
                    WriteLine('{');
                    WriteLine(1, $"this->!{@class.Name}();");
                    WriteLine('}');
                    WriteLine();

                    WriteLine($"{GetFullNameManaged(@class)}::!{@class.Name}()");
                    WriteLine('{');
                    if (nativeClass.IsTrackingDisposable)
                    {
                        WriteLine(1, "if (this->IsDisposed)");
                        WriteLine(2, "return;");
                        WriteLine();
                        WriteLine(1, "OnDisposing(this, nullptr);");
                        WriteLine();
                    }
                    if (nativeClass.HasPreventDelete)
                    {
                        WriteLine(1, "if (!_preventDelete)");
                        WriteLine(1, "{");
                        WriteLine(2, "delete _native;");
                        WriteLine(1, "}");
                    }
                    else
                    {
                        WriteLine(1, "delete _native;");
                    }
                    if (nativeClass.IsTrackingDisposable)
                    {
                        WriteLine(1, "_isDisposed = true;");
                        WriteLine();
                        WriteLine(1, "OnDisposed(this, nullptr);");
                    }
                    else
                    {
                        WriteLine(1, "_native = NULL;");
                    }
                    WriteLine('}');
                    hasSourceWhiteSpace = false;
                }

                // Write public constructors
                if (!nativeClass.HidePublicConstructors && !nativeClass.IsAbstract)
                {
                    var constructors = @class.Methods.Where(m => m.Native.IsConstructor && m.Native.Access == AccessSpecifier.Public);
                    if (constructors.Any())
                    {
                        EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Public);

                        foreach (var constructor in constructors)
                        {
                            WriteMethod(constructor, level);
                        }
                    }
                }
            }

            // Write non-constructor methods
            var methods = @class.Methods
                .Where(m => !m.Native.IsConstructor && !m.Native.IsExcluded &&
                    m.Native.Access == AccessSpecifier.Public && m.Property == null);
            if (methods.Any())
            {
                EnsureHeaderWhiteSpace();

                foreach (var method in methods)
                {
                    EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Public);
                    WriteMethod(method, level);
                }
            }

            // Write properties (includes unmanaged fields and getters/setters)
            To = WriteTo.Header;
            foreach (ManagedProperty prop in @class.Properties)
            {
                string typeConditional = GetTypeConditional(prop.Type, @class.Header);
                if (typeConditional != null)
                {
                    WriteLine($"#ifndef {typeConditional}", WriteTo.Header | WriteTo.Source);
                    hasSourceWhiteSpace = true;
                }
                else
                {
                    EnsureHeaderWhiteSpace();
                }

                EnsureAccess(level, ref currentAccess, RefAccessSpecifier.Public);
                WriteLine(level + 1, $"property {GetTypeName(prop.Type)} {prop.Name}");
                WriteLine(level + 1, "{");

                // Getter/Setter
                WriteMethod(prop.Getter, level + 1);
                if (prop.Setter != null)
                {
                    WriteMethod(prop.Setter, level + 1);
                }

                WriteLine(level + 1, "}");

                if (typeConditional != null)
                {
                    WriteLine("#endif", WriteTo.Header | WriteTo.Source);
                    hasSourceWhiteSpace = false;
                }

                hasHeaderWhiteSpace = false;
            }

            WriteLine(level, "};");
            hasHeaderWhiteSpace = false;

            To = prevTo;
        }
Beispiel #22
0
        private void WriteClass(ManagedClass @class)
        {
            foreach (var child in @class.NestedClasses)
            {
                WriteClass(child);
            }

            if (!ClassNeedsExtensions(@class))
            {
                return;
            }

            _extensionMethods.Clear();

            To = WriteTo.CS;
            EnsureWhiteSpace();
            Write(1, "[EditorBrowsable(EditorBrowsableState.Never)]");
            WriteLine(1, $"public static class {@class.Name}Extensions");
            WriteLine(1, "{");

            To = WriteTo.Buffer;
            foreach (var prop in @class.Properties)
            {
                if (_extensionClassesInternal.ContainsKey(GetName(prop.Type)))
                {
                    string typeName = _extensionClassesExternal[GetName(prop.Type)];

                    // Getter with out parameter
                    ClearBuffer();
                    WriteLine(2, string.Format("public unsafe static void Get{0}(this {1} obj, out {2} value)",
                                               prop.Name, @class.Name, typeName));
                    WriteLine(2, "{");

                    WriteLine(3, $"fixed ({typeName}* valuePtr = &value)");
                    WriteLine(3, "{");
                    Write(4, $"*({_extensionClassesInternal[GetName(prop.Type)]}");
                    WriteLine(string.Format("*({0}*)valuePtr = obj.{1};",
                                            _extensionClassesInternal[GetName(prop.Type)], prop.Name));
                    WriteLine(3, "}");

                    WriteLine(2, "}");

                    _extensionMethods.Add(new KeyValuePair <string, string>("Get" + prop.Name, GetBufferString()));

                    // Getter with return value
                    ClearBuffer();
                    WriteLine(2, string.Format("public static {0} Get{1}(this {1} obj)",
                                               typeName, prop.Name, @class.Name));
                    WriteLine(2, "{");

                    WriteLine(3, $"{typeName} value;");
                    WriteLine(3, $"Get{prop.Name}(obj, out value)");
                    WriteLine(3, "return value;");

                    WriteLine(2, "}");

                    _extensionMethods.Add(new KeyValuePair <string, string>("Get" + prop.Name, GetBufferString()));

                    if (prop.Setter == null)
                    {
                        continue;
                    }

                    // Setter with ref parameter
                    ClearBuffer();
                    WriteLine(2, string.Format("public unsafe static void Set{0}(this {1} obj, ref {2} value)",
                                               prop.Name, @class.Name, typeName));
                    WriteLine(2, "{");

                    WriteLine(3, $"fixed ({typeName}* valuePtr = &value)");
                    WriteLine(3, "{");
                    WriteLine(4, string.Format("obj.{0} = *({1}*)valuePtr;",
                                               prop.Name, _extensionClassesInternal[GetName(prop.Type)]));
                    WriteLine(3, "}");

                    WriteLine(2, "}");

                    _extensionMethods.Add(new KeyValuePair <string, string>("Set" + prop.Name, GetBufferString()));

                    // Setter with non-ref parameter
                    ClearBuffer();
                    WriteLine(2, string.Format("public static void Set{0}(this {1} obj, {2} value)",
                                               prop.Name, @class.Name, typeName));
                    WriteLine(2, "{");
                    WriteLine(3, $"Set{prop.Name}(obj, ref value);");
                    WriteLine(2, "}");

                    _extensionMethods.Add(new KeyValuePair <string, string>("Set" + prop.Name, GetBufferString()));
                }
            }

            foreach (var method in @class.Methods)
            {
                if (!MethodNeedsExtensions(method))
                {
                    continue;
                }

                WriteMethod(method);
            }

            foreach (var method in _extensionMethods.OrderBy(key => key.Key))
            {
                EnsureWhiteSpace(WriteTo.CS);
                Write(method.Value, WriteTo.CS);
                hasCSWhiteSpace = false;
            }

            WriteLine(1, "}", WriteTo.CS);
            hasCSWhiteSpace = false;
        }