public string Generate() { using (var sb = new AutoIndentStringBuilder ()) { using (var hdr = new AutoIndentStringBuilder ()) { using (var decls = new AutoIndentStringBuilder ()) { using (var mthds = new AutoIndentStringBuilder ()) { hdr.WriteLine ("#pragma clang diagnostic ignored \"-Wdeprecated-declarations\""); hdr.WriteLine ("#pragma clang diagnostic ignored \"-Wtypedef-redefinition\""); // temporary hack until we can stop including glib.h hdr.WriteLine ("#pragma clang diagnostic ignored \"-Wobjc-designated-initializers\""); if (Driver.EnableDebug) hdr.WriteLine ("#define DEBUG 1"); hdr.WriteLine ("#include <stdarg.h>"); hdr.WriteLine ("#include <xamarin/xamarin.h>"); hdr.WriteLine ("#include <objc/objc.h>"); hdr.WriteLine ("#include <objc/runtime.h>"); header = hdr; declarations = decls; methods = mthds; Specialize (sb); header = null; declarations = null; methods = null; FlushTrace (); return hdr.ToString () + "\n" + decls.ToString () + "\n" + mthds.ToString () + "\n" + sb.ToString (); } } } } }
string CheckStructure(TypeDefinition structure, string descriptiveMethodName, MemberReference inMember) { string n; StringBuilder name = new StringBuilder (); var body = new AutoIndentStringBuilder (1); int size = 0; ProcessStructure (name, body, structure, ref size, descriptiveMethodName, structure, inMember); n = "struct trampoline_struct_" + name.ToString (); if (!structures.Contains (n)) { structures.Add (n); declarations.WriteLine ("{0} {{\n{1}}};", n, body.ToString ()); } return n; }
void Specialize(AutoIndentStringBuilder sb) { List<Exception> exceptions = new List<Exception> (); List<ObjCMember> skip = new List<ObjCMember> (); var map = new AutoIndentStringBuilder (1); var map_init = new AutoIndentStringBuilder (); var i = 0; map.AppendLine ("static MTClassMap __xamarin_class_map [] = {"); if (string.IsNullOrEmpty (single_assembly)) { map_init.AppendLine ("void xamarin_create_classes () {"); } else { map_init.AppendLine ("void xamarin_create_classes_{0} () {{", single_assembly.Replace ('.', '_').Replace ('-', '_')); } // Select the types that needs to be registered. var allTypes = new List<ObjCType> (); foreach (var @class in Types.Values) { if (!string.IsNullOrEmpty (single_assembly) && single_assembly != @class.Type.Module.Assembly.Name.Name) continue; #if !MONOMAC var isPlatformType = IsPlatformType (@class.Type); if (isPlatformType && IsSimulatorOrDesktop && IsMetalType (@class)) continue; // Metal isn't supported in the simulator. #endif if (@class.IsFakeProtocol) continue; allTypes.Add (@class); } // Move all the custom types to the end of the list, respecting // existing order (so that a derived type always comes after // its base type; the Types.Values has that property, and we // need to keep it that way). var mappedEnd = allTypes.Count; var counter = 0; while (counter < mappedEnd) { if (!IsPlatformType (allTypes [counter].Type)) { var t = allTypes [counter]; allTypes.RemoveAt (counter); allTypes.Add (t); mappedEnd--; } else { counter++; } } var customTypeCount = 0; foreach (var @class in allTypes) { var isPlatformType = IsPlatformType (@class.Type); skip.Clear (); if ([email protected] && [email protected] && [email protected]) { if (!isPlatformType) customTypeCount++; CheckNamespace (@class, exceptions); map.AppendLine ("{{\"{0}\", \"{1}\", NULL }},", @class.ExportedName, GetAssemblyQualifiedName (@class.Type)); bool use_dynamic; if (@class.Type.Resolve ().Module.Assembly.Name.Name == PlatformAssembly) { // we don't need to use the static ref to prevent the linker from removing (otherwise unreferenced) code for monotouch.dll types. use_dynamic = true; // be smarter: we don't need to use dynamic refs for types available in the lowest version (target deployment) we building for. // We do need to use dynamic class lookup when the following conditions are all true: // * The class is not available in the target deployment version. // * The class is not in a weakly linked framework (for instance if an existing framework introduces a new class, we don't // weakly link the framework because it already exists in the target deployment version - but since the class doesn't, we // must use dynamic class lookup to determine if it's available or not. } else { use_dynamic = false; } switch (@class.ExportedName) { case "EKObject": // EKObject's class is a private symbol, so we can't link with it... use_dynamic = true; break; } string get_class; if (use_dynamic) { get_class = string.Format ("objc_getClass (\"{0}\")", @class.ExportedName); } else { get_class = string.Format ("[{0} class]", EncodeNonAsciiCharacters (@class.ExportedName)); } map_init.AppendLine ("__xamarin_class_map [{1}].handle = {0};", get_class, i++); } if (@class.IsWrapper && isPlatformType) continue; if (@class.Methods == null && isPlatformType && [email protected] && [email protected]) continue; if (@class.IsModel) continue; CheckNamespace (@class, exceptions); if (@class.BaseType != null) CheckNamespace (@class.BaseType, exceptions); var class_name = EncodeNonAsciiCharacters (@class.ExportedName); var is_protocol = @class.IsProtocol; if (@class.IsCategory) { sb.Write ("@interface {0} ({1})", EncodeNonAsciiCharacters (@class.BaseType.ExportedName), @class.CategoryName); } else if (is_protocol) { sb.Write ("@protocol ").Write (EncodeNonAsciiCharacters (@class.ProtocolName)); } else { sb.Write ("@interface {0} : {1}", class_name, EncodeNonAsciiCharacters (@class.SuperType.ExportedName)); } bool any_protocols = false; ObjCType tp = @class; while (tp != null && tp != tp.BaseType) { if (tp.IsWrapper) break; // no need to declare protocols for wrapper types, they do it already in their headers. if (tp.Protocols != null) { for (int p = 0; p < tp.Protocols.Length; p++) { if (tp.Protocols [p].ProtocolName == "UIAppearance") continue; sb.Append (any_protocols ? ", " : "<"); any_protocols = true; sb.Append (tp.Protocols [p].ProtocolName); CheckNamespace (tp.Protocols [p], exceptions); } } tp = tp.BaseType; } if (any_protocols) sb.Append (">"); if (is_protocol) { sb.WriteLine (); } else { sb.WriteLine (" {"); if (@class.Fields != null) { foreach (var field in @class.Fields.Values) { try { switch (field.FieldType) { case "@": sb.Write ("id "); break; case "^v": sb.Write ("void *"); break; case "XamarinObject": sb.Write ("XamarinObject "); break; default: throw ErrorHelper.CreateError (4120, "The registrar found an unknown field type '{0}' in field '{1}.{2}'. Please file a bug report at http://bugzilla.xamarin.com", field.FieldType, field.DeclaringType.Type.FullName, field.Name); } sb.Write (field.Name); sb.WriteLine (";"); } catch (Exception ex) { exceptions.Add (ex); } } } sb.WriteLine ("}"); } sb.Indent (); if (@class.Properties != null) { foreach (var property in @class.Properties) { try { if (is_protocol) sb.Write (property.IsOptional ? "@optional " : "@required "); sb.Write ("@property (nonatomic"); switch (property.ArgumentSemantic) { case ArgumentSemantic.Copy: sb.Write (", copy"); break; case ArgumentSemantic.Retain: sb.Write (", retain"); break; case ArgumentSemantic.Assign: case ArgumentSemantic.None: default: sb.Write (", assign"); break; } if (property.IsReadOnly) sb.Write (", readonly"); if (property.Selector != null) { if (property.GetterSelector != null && property.Selector != property.GetterSelector) sb.Write (", getter = ").Write (property.GetterSelector); if (property.SetterSelector != null) { var setterSel = string.Format ("set{0}{1}:", char.ToUpperInvariant (property.Selector [0]), property.Selector.Substring (1)); if (setterSel != property.SetterSelector) sb.Write (", setter = ").Write (property.SetterSelector); } } sb.Write (") "); try { sb.Write (ToObjCParameterType (property.PropertyType, property.DeclaringType.Type.FullName, exceptions, property.Property)); } catch (ProductException mte) { exceptions.Add (CreateException (4138, mte, property.Property, "The registrar cannot marshal the property type '{0}' of the property '{1}.{2}'.", GetTypeFullName (property.PropertyType), property.DeclaringType.Type.FullName, property.Name)); } sb.Write (" ").Write (property.Selector); sb.WriteLine (";"); } catch (Exception ex) { exceptions.Add (ex); } } } if (@class.Methods != null) { foreach (var method in @class.Methods) { try { if (is_protocol) sb.Write (method.IsOptional ? "@optional " : "@required "); sb.WriteLine ("{0};", GetObjCSignature (method, exceptions)); } catch (ProductException ex) { skip.Add (method); exceptions.Add (ex); } catch (Exception ex) { skip.Add (method); exceptions.Add (ErrorHelper.CreateError (4114, ex, "Unexpected error in the registrar for the method '{0}.{1}' - Please file a bug report at http://bugzilla.xamarin.com", method.DeclaringType.Type.FullName, method.Method.Name)); } } } sb.Unindent (); sb.WriteLine ("@end"); if (!is_protocol && [email protected]) { if (@class.IsCategory) { sb.WriteLine ("@implementation {0} ({1})", EncodeNonAsciiCharacters (@class.BaseType.ExportedName), @class.CategoryName); } else { sb.WriteLine ("@implementation {0} {{ }} ", class_name); } sb.Indent (); if (@class.Methods != null) { foreach (var method in @class.Methods) { if (skip.Contains (method)) continue; try { Specialize (sb, method, exceptions); } catch (Exception ex) { exceptions.Add (ex); } } } sb.Unindent (); sb.WriteLine ("@end"); } sb.WriteLine (); } map.AppendLine ("{ NULL, NULL, NULL },"); map.AppendLine ("};"); map.AppendLine (); map.AppendLine ("static const char *__xamarin_registration_assemblies []= {"); int count = 0; var registered_assemblies = new List<string> (); if (string.IsNullOrEmpty (single_assembly)) { foreach (var assembly in GetAssemblies ()) registered_assemblies.Add (GetAssemblyName (assembly)); } else { registered_assemblies.Add (single_assembly); } foreach (var assembly in registered_assemblies) { count++; if (count > 1) map.AppendLine (", "); map.Append ("\""); map.Append (assembly); map.Append ("\""); } map.AppendLine (); map.AppendLine ("};"); map.AppendLine (); map.AppendLine ("static struct MTRegistrationMap __xamarin_registration_map = {"); map.AppendLine ("NULL,"); map.AppendLine ("__xamarin_registration_assemblies,"); map.AppendLine ("__xamarin_class_map,"); map.AppendLine ("{0},", count); map.AppendLine ("{0},", i); map.AppendLine ("{0}", customTypeCount); map.AppendLine ("};"); map_init.AppendLine ("xamarin_add_registration_map (&__xamarin_registration_map);"); map_init.AppendLine ("}"); sb.WriteLine (map.ToString ()); sb.WriteLine (map_init.ToString ()); if (exceptions.Count > 0) throw new AggregateException (exceptions); }
public AutoIndentStringBuilder AppendLine(AutoIndentStringBuilder isb) { if (isb.Length > 0) { sb.Append (isb.ToString ()); AppendLine (); } return this; }