void GenerateCategory(Type definedType, Type extendedType, List <MethodInfo> methods)
        {
            var etn  = NameGenerator.GetTypeName(extendedType).Replace(" *", String.Empty);
            var name = $"{etn} ({NameGenerator.GetTypeName (definedType)})";

            headers.WriteLine($"/** Category {name}");
            headers.WriteLine($" *  Corresponding .NET Qualified Name: `{definedType.AssemblyQualifiedName}`");
            headers.WriteLine(" */");
            headers.WriteLine($"@interface {name}");
            headers.WriteLine();

            implementation.WriteLine($"@implementation {name}");
            implementation.WriteLine();

            foreach (var mi in methods)
            {
                ImplementMethod(mi, mi.Name.CamelCase(), true);
            }

            headers.WriteLine("@end");
            headers.WriteLine();

            implementation.WriteLine("@end");
            implementation.WriteLine();
        }
        public static string FormatRawValue(Type t, object o)
        {
            if (o == null)
            {
                return("nil");
            }

            switch (t.Namespace)
            {
            case "System":
                switch (t.Name)
                {
                case "String":
                    return($"@\"{o}\"");

                case "Single":
                    float f = (float)o;
                    if (Single.IsNaN(f))
                    {
                        return("NAN");
                    }
                    if (Single.IsInfinity(f))
                    {
                        return("INFINITY");
                    }
                    return(o + "f");

                case "Double":
                    double d = (double)o;
                    if (Double.IsNaN(d))
                    {
                        return("NAN");
                    }
                    if (Double.IsInfinity(d))
                    {
                        return("INFINITY");
                    }
                    return(o + "d");

                case "UInt32":
                    return(o + "ul");

                case "Int64":
                    return(o + "ll");

                case "UInt64":
                    return(o + "ull");
                }
                break;
            }
            if (t.IsEnum)
            {
                return(NameGenerator.GetTypeName(t) + t.GetEnumName(o));
            }
            return(o.ToString());
        }
        void ReturnValue(Type t)
        {
            switch (Type.GetTypeCode(t))
            {
            case TypeCode.String:
                implementation.WriteLine("return mono_embeddinator_get_nsstring ((MonoString *) __result);");
                break;

            case TypeCode.Boolean:
            case TypeCode.Char:
            case TypeCode.SByte:
            case TypeCode.Int16:
            case TypeCode.Int32:
            case TypeCode.Int64:
            case TypeCode.Byte:
            case TypeCode.UInt16:
            case TypeCode.UInt32:
            case TypeCode.UInt64:
            case TypeCode.Single:
            case TypeCode.Double:
                var name = NameGenerator.GetTypeName(t);
                implementation.WriteLine("void* __unbox = mono_object_unbox (__result);");
                implementation.WriteLine($"return *(({name}*)__unbox);");
                break;

            case TypeCode.Object:
                if (t.Namespace == "System" && t.Name == "Void")
                {
                    return;
                }
                if (!types.Contains(t) && !protocols.Contains(t))
                {
                    goto default;
                }

                implementation.WriteLine("if (!__result)");
                implementation.Indent++;
                implementation.WriteLine("return nil;");
                implementation.Indent--;
                // TODO: cheating by reusing `initForSuper` - maybe a better name is needed
                var tname = NameGenerator.GetTypeName(t);
                if (protocols.Contains(t))
                {
                    tname = "__" + tname + "Wrapper";
                }
                implementation.WriteLine($"\t{tname}* __peer = [[{tname} alloc] initForSuper];");
                implementation.WriteLine("__peer->_object = mono_embeddinator_create_object (__result);");
                implementation.WriteLine("return __peer;");
                break;

            default:
                throw new NotImplementedException($"Returning type {t.Name} from native code");
            }
        }
        public EquatableHelper(ProcessedMethod method, SourceWriter headers, SourceWriter implementation) :
            base(method, headers, implementation)
        {
            ReturnType = "bool";
            var pt       = method.Method.GetParameters() [0].ParameterType;
            var objc     = NameGenerator.GetTypeName(pt);
            var nullable = !pt.IsPrimitive ? " * _Nullable" : "";

            ParameterType = pt;
            ObjCSignature = $"isEqualTo{objc.PascalCase ()}:({objc}{nullable})other";
            MonoSignature = $"Equals({NameGenerator.GetMonoName (pt)})";
        }
Пример #5
0
        protected void GenerateIndexedSubscriptingWrite(Type indexType, Type propertyType)
        {
            string indexTypeString = NameGenerator.GetTypeName(indexType);

            headers.WriteLine($"- (void)setObject:(id)obj atIndexedSubscript:({indexTypeString})idx;");

            implementation.WriteLine($"- (void)setObject:(id)obj atIndexedSubscript:({indexTypeString})idx");
            implementation.WriteLine("{");
            implementation.Indent++;
            implementation.WriteLine($"[self setItem:idx value:{FromNSObject (propertyType, "obj")}];");
            implementation.Indent--;
            implementation.WriteLine("}");
            implementation.WriteLine();
        }
Пример #6
0
        protected void GenerateIndexedSubscriptingRead(Type indexType, Type propertyType)
        {
            string indexTypeString = NameGenerator.GetTypeName(indexType);

            headers.WriteLine($"- (id)objectAtIndexedSubscript:({indexTypeString})idx;");

            implementation.WriteLine($"- (id)objectAtIndexedSubscript:({indexTypeString})idx");
            implementation.WriteLine("{");
            implementation.Indent++;
            implementation.WriteLine($"return {ToNSObject (propertyType, "[self getItem:idx]")};");
            implementation.Indent--;
            implementation.WriteLine("}");
            implementation.WriteLine();
        }
Пример #7
0
        protected void GenerateKeyedSubscriptingRead(Type indexType, Type propertyType)
        {
            string indexTypeString = NameGenerator.GetTypeName(indexType);

            // TODO - Technically the argument here can be anything, not just id
            headers.WriteLine($"- (id)objectForKeyedSubscript:(id)key;");

            implementation.WriteLine($"- (id)objectForKeyedSubscript:(id)key;");
            implementation.WriteLine("{");
            implementation.Indent++;
            implementation.WriteLine($"return {ToNSObject (propertyType, "[self getItem:key]")};");
            implementation.Indent--;
            implementation.WriteLine("}");
            implementation.WriteLine();
        }
        void GenerateEnum(ProcessedType type)
        {
            Type t               = type.Type;
            var  managed_name    = type.ObjCName;
            var  underlying_type = t.GetEnumUnderlyingType();
            var  base_type       = NameGenerator.GetTypeName(underlying_type);

            // it's nicer to expose flags as unsigned integers - but .NET defaults to `int`
            bool flags = t.HasCustomAttribute("System", "FlagsAttribute");

            if (flags)
            {
                switch (Type.GetTypeCode(underlying_type))
                {
                case TypeCode.SByte:
                case TypeCode.Int16:
                case TypeCode.Int32:
                case TypeCode.Int64:
                    base_type = "unsigned " + base_type;
                    break;
                }
            }

            var macro = flags ? "NS_OPTIONS" : "NS_ENUM";

            headers.WriteLine($"/** Enumeration {managed_name}");
            headers.WriteLine($" *  Corresponding .NET Qualified Name: `{t.AssemblyQualifiedName}`");
            headers.WriteLine(" */");
            headers.WriteLine($"typedef {macro}({base_type}, {managed_name}) {{");
            headers.Indent++;
            foreach (var name in t.GetEnumNames())
            {
                var value = t.GetField(name).GetRawConstantValue();
                headers.Write($"{managed_name}{name} = ");
                if (flags)
                {
                    headers.Write($"0x{value:x}");
                }
                else
                {
                    headers.Write(value);
                }
                headers.WriteLine(',');
            }
            headers.Indent--;
            headers.WriteLine("};");
            headers.WriteLine();
        }
        public string GetReturnType(Type declaringType, Type returnType)
        {
            if (protocols.Contains(returnType))
            {
                return("id<" + NameGenerator.GetTypeName(returnType) + ">");
            }
            if (declaringType == returnType)
            {
                return("instancetype");
            }

            var return_type = NameGenerator.GetTypeName(returnType);

            if (types.Contains(returnType))
            {
                return_type += "*";
            }
            return(return_type);
        }
        protected override void Generate(ProcessedProperty property)
        {
            PropertyInfo pi     = property.Property;
            var          getter = pi.GetGetMethod();
            var          setter = pi.GetSetMethod();

            // setter-only properties are handled as methods (and should not reach this code)
            if (getter == null && setter != null)
            {
                throw new EmbeddinatorException(99, "Internal error `setter only`. Please file a bug report with a test case (https://github.com/mono/Embeddinator-4000/issues");
            }

            var name = pi.Name.CamelCase();

            headers.Write("@property (nonatomic");
            if (getter.IsStatic)
            {
                headers.Write(", class");
            }
            if (setter == null)
            {
                headers.Write(", readonly");
            }
            var pt            = pi.PropertyType;
            var property_type = NameGenerator.GetTypeName(pt);

            if (types.Contains(pt))
            {
                property_type += " *";
            }

            var spacing = property_type [property_type.Length - 1] == '*' ? string.Empty : " ";

            headers.WriteLine($") {property_type}{spacing}{name};");

            ImplementMethod(getter, name, false, pi);
            if (setter == null)
            {
                return;
            }

            ImplementMethod(setter, "set" + pi.Name, false, pi);
        }
        void GenerateDefaultValuesWrapper(string name, MethodBase mb, ParameterInfo[] parameters, int start)
        {
            MethodInfo    mi = mb as MethodInfo;
            string        objcsig;
            string        monosig;
            var           parametersInfo = parameters;
            var           plist          = new List <ParameterInfo> ();
            StringBuilder arguments      = new StringBuilder();

            headers.WriteLine("/** This is an helper method that inlines the following default values:");
            foreach (var p in parameters)
            {
                string pName = NameGenerator.GetExtendedParameterName(p, parameters);
                if (arguments.Length == 0)
                {
                    arguments.Append(p.Name.PascalCase()).Append(':');
                }
                else
                {
                    arguments.Append(' ').Append(p.Name.CamelCase()).Append(':');
                }
                if (p.Position >= start && p.HasDefaultValue)
                {
                    var raw = FormatRawValue(p.ParameterType, p.RawDefaultValue);
                    headers.WriteLine($" *     ({NameGenerator.GetTypeName (p.ParameterType)}) {pName} = {raw};");
                    arguments.Append(raw);
                }
                else
                {
                    arguments.Append(pName);
                    plist.Add(p);
                }
            }
            headers.WriteLine(" *");
            headers.WriteLine($" *  @see {name}");
            headers.WriteLine(" */");

            if (mi == null)
            {
                name = start == 0 ? "init" : "initWith";
            }
            else
            {
                name = mb.Name.CamelCase();
            }

            GetSignatures(name, mb.Name, mb, plist.ToArray(), false, false, out objcsig, out monosig);
            var type    = mb.DeclaringType;
            var builder = new MethodHelper(headers, implementation)
            {
                IsStatic      = mb.IsStatic,
                ReturnType    = mi == null ? "nullable instancetype" : GetReturnType(type, mi.ReturnType),
                ObjCSignature = objcsig,
            };

            builder.WriteHeaders();
            headers.WriteLine();

            builder.BeginImplementation();
            if (mi == null || !mi.ReturnType.Is("System", "Void"))
            {
                implementation.Write("return [");
            }
            if (mb.IsStatic)
            {
                implementation.Write(NameGenerator.GetObjCName(mi.DeclaringType));
                implementation.Write(' ');
            }
            else
            {
                implementation.Write("self ");
            }
            if (mi == null)
            {
                name = "initWith";
            }
            implementation.WriteLine($"{name}{arguments}];");
            builder.EndImplementation();
        }
        protected void Generate(ProcessedFieldInfo field)
        {
            FieldInfo fi        = field.Field;
            bool      read_only = fi.IsInitOnly || fi.IsLiteral;

            headers.Write("@property (nonatomic");
            if (fi.IsStatic)
            {
                headers.Write(", class");
            }
            if (read_only)
            {
                headers.Write(", readonly");
            }
            var ft    = fi.FieldType;
            var bound = types.Contains(ft);

            if (bound && ft.IsValueType)
            {
                headers.Write(", nonnull");
            }

            var field_type = NameGenerator.GetTypeName(ft);

            if (bound)
            {
                field_type += " *";
            }

            var name = fi.Name.CamelCase();

            var spacing = field_type [field_type.Length - 1] == '*' ? string.Empty : " ";

            headers.WriteLine($") {field_type}{spacing}{name};");

            // it's similar, but different from implementing a method

            var type = fi.DeclaringType;
            var managed_type_name = NameGenerator.GetObjCName(type);
            var return_type       = GetReturnType(type, fi.FieldType);

            implementation.Write(fi.IsStatic ? '+' : '-');
            implementation.WriteLine($" ({return_type}) {name}");
            implementation.WriteLine("{");
            implementation.Indent++;
            implementation.WriteLine("static MonoClassField* __field = nil;");
            implementation.WriteLine("if (!__field) {");
            implementation.Indent++;
            implementation.WriteLineUnindented("#if TOKENLOOKUP");
            implementation.WriteLine($"__field = mono_class_get_field ({managed_type_name}_class, 0x{fi.MetadataToken:X8});");
            implementation.WriteLineUnindented("#else");
            implementation.WriteLine($"const char __field_name [] = \"{fi.Name}\";");
            implementation.WriteLine($"__field = mono_class_get_field_from_name ({managed_type_name}_class, __field_name);");
            implementation.WriteLineUnindented("#endif");
            implementation.Indent--;
            implementation.WriteLine("}");
            var instance = "nil";

            if (!fi.IsStatic)
            {
                implementation.WriteLine($"MonoObject* __instance = mono_gchandle_get_target (_object->_handle);");
                instance = "__instance";
            }
            implementation.WriteLine($"MonoObject* __result = mono_field_get_value_object (__mono_context.domain, __field, {instance});");
            if (types.Contains(ft))
            {
                implementation.WriteLine("if (!__result)");
                implementation.Indent++;
                implementation.WriteLine("return nil;");
                implementation.Indent--;
            }
            ReturnValue(fi.FieldType);
            implementation.Indent--;
            implementation.WriteLine("}");
            implementation.WriteLine();

            if (read_only)
            {
                return;
            }
            implementation.Write(fi.IsStatic ? '+' : '-');
            implementation.WriteLine($" (void) set{fi.Name}:({field_type})value");
            implementation.WriteLine("{");
            implementation.Indent++;
            implementation.WriteLine("static MonoClassField* __field = nil;");
            implementation.WriteLine("if (!__field) {");
            implementation.Indent++;
            implementation.WriteLineUnindented("#if TOKENLOOKUP");
            implementation.WriteLine($"__field = mono_class_get_field ({managed_type_name}_class, 0x{fi.MetadataToken:X8});");
            implementation.WriteLineUnindented("#else");
            implementation.WriteLine($"const char __field_name [] = \"{fi.Name}\";");
            implementation.WriteLine($"__field = mono_class_get_field_from_name ({managed_type_name}_class, __field_name);");
            implementation.WriteLineUnindented("#endif");
            implementation.Indent--;
            implementation.WriteLine("}");
            StringBuilder sb = null;

            implementation.WriteLine($"void* __value;");
            GenerateArgument("value", "__value", fi.FieldType, ref sb);
            if (fi.IsStatic)
            {
                implementation.WriteLine($"MonoVTable *__vtable = mono_class_vtable (__mono_context.domain, {managed_type_name}_class);");
                implementation.WriteLine("mono_field_static_set_value (__vtable, __field, __value);");
            }
            else
            {
                implementation.WriteLine($"MonoObject* __instance = mono_gchandle_get_target (_object->_handle);");
                implementation.WriteLine("mono_field_set_value (__instance, __field, __value);");
            }
            implementation.Indent--;
            implementation.WriteLine("}");
            implementation.WriteLine();
        }
        protected override void Generate(ProcessedType type)
        {
            Type t           = type.Type;
            var  aname       = t.Assembly.GetName().Name.Sanitize();
            var  static_type = t.IsSealed && t.IsAbstract;

            var managed_name = NameGenerator.GetObjCName(t);

            List <string> conformed_protocols = new List <string> ();

            foreach (var i in t.GetInterfaces())
            {
                if (protocols.Contains(i))
                {
                    conformed_protocols.Add(NameGenerator.GetObjCName(i));
                }
            }

            var tbuilder = new ClassHelper(headers, implementation)
            {
                AssemblyQualifiedName = t.AssemblyQualifiedName,
                AssemblyName          = aname,
                BaseTypeName          = NameGenerator.GetTypeName(t.BaseType),
                Name            = NameGenerator.GetTypeName(t),
                Namespace       = t.Namespace,
                ManagedName     = t.Name,
                Protocols       = conformed_protocols,
                IsBaseTypeBound = types.Contains(t.BaseType),
                IsStatic        = t.IsSealed && t.IsAbstract,
                MetadataToken   = t.MetadataToken,
            };

            tbuilder.BeginHeaders();
            tbuilder.BeginImplementation();

            var default_init = false;
            List <ProcessedConstructor> constructors;

            if (ctors.TryGetValue(t, out constructors))
            {
                // First get the unavailable init ctor selectors in parent class
                var unavailableCtors = GetUnavailableParentCtors(t, constructors);
                if (unavailableCtors.Count() > 0)
                {
                    // TODO: Print a #pragma mark once we have a well defined header structure http://nshipster.com/pragma/
                    foreach (var uctor in unavailableCtors)
                    {
                        var    ctorparams = uctor.Constructor.GetParameters();
                        string name       = "init";
                        string signature  = ".ctor()";
                        if (ctorparams.Length > 0)
                        {
                            GetSignatures("initWith", uctor.Constructor.Name, uctor.Constructor, ctorparams, uctor.FallBackToTypeName, false, out name, out signature);
                        }
                        headers.WriteLine("/** This initializer is not available as it was not re-exposed from the base type");
                        headers.WriteLine(" *  For more details consult https://github.com/mono/Embeddinator-4000/blob/master/docs/ObjC.md#constructors-vs-initializers");
                        headers.WriteLine(" */");
                        headers.WriteLine($"- (nullable instancetype){name} NS_UNAVAILABLE;");
                        headers.WriteLine();
                    }
                }

                foreach (var ctor in constructors)
                {
                    var pcount = ctor.Constructor.ParameterCount;
                    default_init |= pcount == 0;

                    var    parameters = ctor.Constructor.GetParameters();
                    string name       = "init";
                    string signature  = ".ctor()";
                    if (parameters.Length > 0)
                    {
                        GetSignatures("initWith", ctor.Constructor.Name, ctor.Constructor, parameters, ctor.FallBackToTypeName, false, out name, out signature);
                    }

                    var builder = new MethodHelper(headers, implementation)
                    {
                        AssemblySafeName = aname,
                        ReturnType       = "nullable instancetype",
                        ManagedTypeName  = t.FullName,
                        MetadataToken    = ctor.Constructor.MetadataToken,
                        MonoSignature    = signature,
                        ObjCSignature    = name,
                        ObjCTypeName     = managed_name,
                        IsConstructor    = true,
                        IsValueType      = t.IsValueType,
                        IgnoreException  = true,
                    };

                    builder.WriteHeaders();

                    builder.BeginImplementation();
                    builder.WriteMethodLookup();

                    // TODO: this logic will need to be update for managed NSObject types (e.g. from XI / XM) not to call [super init]
                    implementation.WriteLine("if (!_object) {");
                    implementation.Indent++;
                    implementation.WriteLine($"MonoObject* __instance = mono_object_new (__mono_context.domain, {managed_name}_class);");

                    string postInvoke = String.Empty;
                    var    args       = "nil";
                    if (pcount > 0)
                    {
                        Generate(parameters, false, out postInvoke);
                        args = "__args";
                    }
                    builder.WriteInvoke(args);
                    implementation.Write(postInvoke);
                    implementation.WriteLine("_object = mono_embeddinator_create_object (__instance);");
                    implementation.Indent--;
                    implementation.WriteLine("}");
                    if (types.Contains(t.BaseType))
                    {
                        implementation.WriteLine("return self = [super initForSuper];");
                    }
                    else
                    {
                        implementation.WriteLine("return self = [super init];");
                    }
                    builder.EndImplementation();

                    headers.WriteLine();

                    if (members_with_default_values.Contains(ctor.Constructor))
                    {
                        default_init |= GenerateDefaultValuesWrappers(name, ctor.Constructor);
                    }
                }
            }

            // generate an `init` for a value type (even if none was defined, the default one is usable)
            if (!default_init && t.IsValueType)
            {
                var builder = new MethodHelper(headers, implementation)
                {
                    AssemblySafeName = aname,
                    ReturnType       = "nullable instancetype",
                    ManagedTypeName  = t.FullName,
                    MonoSignature    = ".ctor()",
                    ObjCSignature    = "init",
                    ObjCTypeName     = managed_name,
                    IsConstructor    = true,
                    IsValueType      = t.IsValueType,
                    IgnoreException  = true,
                };

                builder.WriteHeaders();
                builder.BeginImplementation();
                // no call to `WriteMethodLookup` since there is not such method if we reached this case

                implementation.WriteLine("if (!_object) {");
                implementation.Indent++;
                implementation.WriteLine($"MonoObject* __instance = mono_object_new (__mono_context.domain, {managed_name}_class);");
                // no call to `WriteInvoke` since there is not such method if we reached this case
                implementation.WriteLine("_object = mono_embeddinator_create_object (__instance);");
                implementation.Indent--;
                implementation.WriteLine("}");
                if (types.Contains(t.BaseType))
                {
                    implementation.WriteLine("return self = [super initForSuper];");
                }
                else
                {
                    implementation.WriteLine("return self = [super init];");
                }
                builder.EndImplementation();

                headers.WriteLine();
                default_init = true;
            }

            if (!default_init || static_type)
            {
                tbuilder.DefineNoDefaultInit();
            }

            List <ProcessedProperty> props;

            if (properties.TryGetValue(t, out props))
            {
                headers.WriteLine();
                foreach (var pi in props)
                {
                    Generate(pi);
                }
            }

            List <ProcessedFieldInfo> f;

            if (fields.TryGetValue(t, out f))
            {
                headers.WriteLine();
                foreach (var fi in f)
                {
                    Generate(fi);
                }
            }

            List <ProcessedProperty> s;

            if (subscriptProperties.TryGetValue(t, out s))
            {
                headers.WriteLine();
                foreach (var si in s)
                {
                    GenerateSubscript(si);
                }
            }

            List <ProcessedMethod> meths;

            if (methods.TryGetValue(t, out meths))
            {
                headers.WriteLine();
                foreach (var mi in meths)
                {
                    Generate(mi);
                }
            }

            MethodInfo m;

            if (icomparable.TryGetValue(t, out m))
            {
                var pt      = m.GetParameters() [0].ParameterType;
                var builder = new ComparableHelper(headers, implementation)
                {
                    ObjCSignature    = $"compare:({managed_name} * _Nullable)other",
                    AssemblySafeName = aname,
                    MetadataToken    = m.MetadataToken,
                    ObjCTypeName     = managed_name,
                    ManagedTypeName  = t.FullName,
                    MonoSignature    = $"CompareTo({NameGenerator.GetMonoName (pt)})",
                };
                builder.WriteHeaders();
                builder.WriteImplementation();
            }

            if (equals.TryGetValue(t, out m))
            {
                var builder = new EqualsHelper(headers, implementation)
                {
                    AssemblySafeName = aname,
                    MetadataToken    = m.MetadataToken,
                    ObjCTypeName     = managed_name,
                    ManagedTypeName  = t.FullName,
                };

                builder.WriteHeaders();
                builder.WriteImplementation();
            }

            if (hashes.TryGetValue(t, out m))
            {
                var builder = new HashHelper(headers, implementation)
                {
                    AssemblySafeName = aname,
                    MetadataToken    = m.MetadataToken,
                    ObjCTypeName     = managed_name,
                    ManagedTypeName  = t.FullName,
                };

                builder.WriteHeaders();
                builder.WriteImplementation();
            }

            tbuilder.EndHeaders();
            tbuilder.EndImplementation();
        }
        void GenerateProtocol(ProcessedType type)
        {
            Type t        = type.Type;
            var  pbuilder = new ProtocolHelper(headers, implementation)
            {
                AssemblyQualifiedName = t.AssemblyQualifiedName,
                AssemblyName          = t.Assembly.GetName().Name.Sanitize(),
                ProtocolName          = NameGenerator.GetTypeName(t),
                Namespace             = t.Namespace,
                ManagedName           = t.Name,
                MetadataToken         = t.MetadataToken,
            };

            pbuilder.BeginHeaders();

            // no need to iterate constructors or fields as they cannot be part of net interfaces
            // do not generate implementations for protocols
            implementation.Enabled = false;

            List <ProcessedProperty> props;

            if (properties.TryGetValue(t, out props))
            {
                headers.WriteLine();
                foreach (var pi in props)
                {
                    Generate(pi);
                }
            }

            List <ProcessedMethod> meths;

            if (methods.TryGetValue(t, out meths))
            {
                headers.WriteLine();
                foreach (var mi in meths)
                {
                    Generate(mi);
                }
            }

            pbuilder.EndHeaders();

            // wrappers are internal so not part of the headers
            headers.Enabled        = false;
            implementation.Enabled = true;

            pbuilder.BeginImplementation();

            if (properties.TryGetValue(t, out props))
            {
                implementation.WriteLine();
                foreach (var pi in props)
                {
                    Generate(pi);
                }
            }

            if (methods.TryGetValue(t, out meths))
            {
                implementation.WriteLine();
                foreach (var mi in meths)
                {
                    Generate(mi);
                }
            }

            pbuilder.EndImplementation();
            headers.Enabled = true;
        }