NSObjectTypeInfo ConvertType(TypeSystemService.ProjectContentWrapper dom, ITypeDefinition type) { string objcName = null; bool isModel = false; bool registeredInDesigner = true; foreach (var att in type.Attributes) { var attType = att.AttributeType; if (attType.Equals(Resolve(dom, registerAttType))) { if (type.GetProjectContent() != null) { registeredInDesigner &= MonoDevelop.DesignerSupport.CodeBehind.IsDesignerFile(att.Region.FileName); } //type registered with an explicit type name are up to the user to provide a valid name var posArgs = att.PositionalArguments; if (posArgs.Count == 1 || posArgs.Count == 2) { objcName = posArgs [0].ConstantValue as string; } //non-nested types in the root namespace have names accessible from obj-c else if (string.IsNullOrEmpty(type.Namespace) && type.Name.IndexOf('.') < 0) { objcName = type.Name; } } if (attType.Equals(Resolve(dom, modelAttType))) { isModel = true; } } if (string.IsNullOrEmpty(objcName)) { return(null); } string baseType = type.DirectBaseTypes.First().ReflectionName; if (baseType == "System.Object") { baseType = null; } bool isUserType = !type.ParentAssembly.Equals(Resolve(dom, nsobjectType).ParentAssembly); var info = new NSObjectTypeInfo(objcName, type.ReflectionName, null, baseType, isModel, isUserType, registeredInDesigner); if (info.IsUserType) { UpdateTypeMembers(dom, info, type); info.DefinedIn = type.Parts.Select(p => (string)p.Region.FileName).ToArray(); } return(info); }
bool TryResolveObjcToCli(string objcType, out NSObjectTypeInfo resolved) { if (objcTypes.TryGetValue(objcType, out resolved)) { return(true); } if (refObjcTypes.TryGetValue(objcType, out resolved)) { return(true); } #if false var msg = new StringBuilder("Can't resolve " + objcType + Environment.NewLine); foreach (var r in dom.References) { msg.Append("Referenced dom:"); msg.Append(r); var rDom = infoService.GetProjectInfo(r); if (rDom == null) { msg.AppendLine("projectinfo == null"); continue; } msg.Append("known types:"); msg.AppendLine(string.Join(",", rDom.objcTypes.Keys.ToArray())); } LoggingService.LogWarning(msg.ToString()); #endif resolved = null; return(false); }
void UpdateType(ProjectDom dom, NSObjectTypeInfo info, IType type) { info.Actions.Clear(); info.Outlets.Clear(); foreach (var prop in type.Properties) { foreach (var att in prop.Attributes) { if (att.AttributeType.FullName != connectAttType.FullName) { continue; } string name = null; if (att.PositionalArguments.Count == 1) { name = (string)((System.CodeDom.CodePrimitiveExpression)att.PositionalArguments[0]).Value; } if (string.IsNullOrEmpty(name)) { name = prop.Name; } info.Outlets.Add(new IBOutlet(name, prop.Name, null, prop.ReturnType.FullName)); break; } } foreach (var meth in type.Methods) { foreach (var att in meth.Attributes) { if (att.AttributeType.FullName != exportAttType.FullName) { continue; } string[] name = null; if (att.PositionalArguments.Count == 1) { var n = (string)((System.CodeDom.CodePrimitiveExpression)att.PositionalArguments[0]).Value; if (!string.IsNullOrEmpty(n)) { name = n.Split(colonChar); } } var action = new IBAction(name != null? name [0] : meth.Name, meth.Name); info.Actions.Add(action); int i = 1; foreach (var param in meth.Parameters) { string label = name != null && i < name.Length? name[i] : null; if (label != null && label.Length == 0) { label = null; } action.Parameters.Add(new IBActionParameter(label, param.Name, null, param.ReturnType.FullName)); } break; } } }
/// <summary> /// Merges CLI info from previous version of the type into the parsed objc-type. /// </summary> public void MergeCliInfo(NSObjectTypeInfo previousType) { CliName = previousType.CliName; DefinedIn = previousType.DefinedIn; IsModel = previousType.IsModel; BaseIsModel = previousType.BaseIsModel; IsUserType = previousType.IsUserType; var existingOutlets = new Dictionary <string, IBOutlet> (); foreach (var o in previousType.Outlets) { existingOutlets[o.ObjCName] = o; } var existingActions = new Dictionary <string, IBAction> (); foreach (var a in previousType.Actions) { existingActions[a.ObjCName] = a; } foreach (var a in Actions) { IBAction existing; if (existingActions.TryGetValue(a.ObjCName, out existing)) { a.CliName = existing.CliName; if (!existing.IsDesigner) { continue; } } else { a.CliName = a.ObjCName; } a.IsDesigner = true; } foreach (var o in Outlets) { IBOutlet existing; if (existingOutlets.TryGetValue(o.ObjCName, out existing)) { o.CliName = existing.CliName; if (!existing.IsDesigner) { continue; } } else { o.CliName = o.ObjCName; } o.IsDesigner = true; } }
NSObjectTypeInfo ConvertType(ProjectDom dom, IType type) { string objcName = null; bool isModel = false; bool registeredInDesigner = true; foreach (var part in type.Parts) { foreach (var att in part.Attributes) { if (att.AttributeType.FullName == registerAttType.FullName) { if (type.SourceProject != null) { registeredInDesigner &= MonoDevelop.DesignerSupport.CodeBehind.IsDesignerFile(part.CompilationUnit.FileName); } //type registered with an explicit type name are up to the user to provide a valid name // Note that the attribute now takes one *or* two parameters. if (att.PositionalArguments.Count == 1 || att.PositionalArguments.Count == 2) { objcName = (string)((System.CodeDom.CodePrimitiveExpression)att.PositionalArguments[0]).Value; } //non-nested types in the root namespace have names accessible from obj-c else if (string.IsNullOrEmpty(type.Namespace) && type.Name.IndexOf('.') < 0) { objcName = type.Name; } } if (att.AttributeType.FullName == modelAttType.FullName) { isModel = true; } } } if (string.IsNullOrEmpty(objcName)) { return(null); } var info = new NSObjectTypeInfo(objcName, type.DecoratedFullName, null, type.BaseType.DecoratedFullName, isModel, type.SourceProject != null, registeredInDesigner); if (info.IsUserType) { UpdateTypeMembers(dom, info, type); info.DefinedIn = type.Parts.Select(p => (string)p.CompilationUnit.FileName).ToArray(); } return(info); }
bool TryResolveCliToObjc(string cliType, out NSObjectTypeInfo resolved) { if (cliTypes.TryGetValue(cliType, out resolved)) { return(true); } if (refCliTypes.TryGetValue(cliType, out resolved)) { return(true); } resolved = null; return(false); }
bool TryResolveCliToObjc(string cliType, out NSObjectTypeInfo resolved) { if (cliTypes.TryGetValue(cliType, out resolved)) { return(true); } foreach (var r in dom.References) { var rDom = infoService.GetProjectInfo(r); if (rDom != null && rDom.cliTypes.TryGetValue(cliType, out resolved)) { return(true); } } resolved = null; return(false); }
public static NSObjectTypeInfo ParseHeader(string headerFile) { var text = System.IO.File.ReadAllText(headerFile); var matches = ibRegex.Matches(text); var type = new NSObjectTypeInfo(System.IO.Path.GetFileNameWithoutExtension(headerFile), null, null, null, false); foreach (Match match in matches) { var kind = match.Groups[1].Value; var def = match.Groups[2].Value; if (kind == "IBOutlet") { var split = def.Split(whitespaceChars, StringSplitOptions.RemoveEmptyEntries); if (split.Length != 2) { continue; } string objcType = split[1].TrimStart('*'); if (objcType == "id") { objcType = "NSObject"; } type.Outlets.Add(new IBOutlet((objcType), null, split[0].TrimEnd('*'), null)); } else { string[] split = def.Split(colonChar); var action = new IBAction(split[0].Trim(), null); string label = null; for (int i = 1; i < split.Length; i++) { var s = split[i].Split(splitActionParamsChars, StringSplitOptions.RemoveEmptyEntries); string objcType = s[0]; if (objcType == "id") { objcType = "NSObject"; } var par = new IBActionParameter(label, s[1], objcType, null); label = s.Length == 3? s[2] : null; action.Parameters.Add(par); } type.Actions.Add(action); } } return(type); }
NSObjectTypeInfo ConvertType(ProjectDom dom, IType type) { string objcName = null; bool isModel = false; foreach (var att in type.Attributes) { if (att.AttributeType.FullName == registerAttType.FullName) { //type registered with an explicit type name are up to the user to proide a valid name if (att.PositionalArguments.Count == 1) { objcName = (string)((System.CodeDom.CodePrimitiveExpression)att.PositionalArguments[0]).Value; } //non-nested types in the root namespace have names accessible from obj-c else if (string.IsNullOrEmpty(type.Namespace) && type.Name.IndexOf('.') < 0) { objcName = type.Name; } } if (att.AttributeType.FullName == modelAttType.FullName) { isModel = true; } } if (string.IsNullOrEmpty(objcName)) { return(null); } var info = new NSObjectTypeInfo(objcName, type.FullName, null, type.BaseType.FullName, isModel); info.IsUserType = type.SourceProject != null; if (info.IsUserType) { UpdateType(dom, info, type); info.DefinedIn = type.Parts.Select(p => (string)p.CompilationUnit.FileName).ToArray(); } return(info); }
/// <summary> /// Resolves the type by mapping the known Objective-C type information to .NET types. /// </summary> /// <returns> /// The number of unresolved types still remaining. /// </returns> /// <param name='type'> /// The NSObjectTypeInfo that contains the known Objective-C type information. /// Typically this will be the result of NSObjectInfoService.ParseHeader(). /// </param> /// <param name='provider'> /// A CodeDom provider which is used to make sure type names don't conflict with language keywords. /// </param> /// <param name='defaultNamespace'> /// The default namespace used when forcing type resolution. /// </param> public void ResolveObjcToCli (IProgressMonitor monitor, NSObjectTypeInfo type, CodeDomProvider provider, string defaultNamespace) { NSObjectTypeInfo resolved; // Resolve our base type if (type.BaseCliType == null) { if (TryResolveObjcToCli (type.BaseObjCType, out resolved)) { type.BaseCliType = resolved.CliName; } else { type.BaseCliType = defaultNamespace + "." + provider.CreateValidIdentifier (type.BaseObjCType); monitor.ReportWarning (string.Format ("Failed to resolve Objective-C type {0} to CLI type on type {1}", type.BaseObjCType, type.ObjCName)); } } // Resolve [Outlet] types foreach (var outlet in type.Outlets) { if (outlet.CliType != null) continue; if (TryResolveObjcToCli (outlet.ObjCType, out resolved)) { outlet.CliType = resolved.CliName; } else { outlet.CliType = defaultNamespace + "." + provider.CreateValidIdentifier (outlet.ObjCType); monitor.ReportWarning (string.Format ("Failed to resolve Objective-C type {0} to CLI type on outlet {1} on type {2}", outlet.ObjCType, outlet.ObjCName, type.ObjCName)); } } // Resolve [Action] param types foreach (var action in type.Actions) { foreach (var param in action.Parameters) { if (param.CliType != null) continue; if (TryResolveObjcToCli (param.ObjCType, out resolved)) { param.CliType = resolved.CliName; } else { param.CliType = defaultNamespace + "." + provider.CreateValidIdentifier (param.ObjCType); monitor.ReportWarning (string.Format ("Failed to resolve Objective-C type {0} to CLI type on action parameter {1} for action {2} on type {3}", param.ObjCType, param.Name, action.ObjCName, type.ObjCName)); } } } }
bool TryResolveCliToObjc (string cliType, out NSObjectTypeInfo resolved) { if (cliTypes.TryGetValue (cliType, out resolved)) return true; foreach (var r in dom.References) { var rDom = infoService.GetProjectInfo (r); if (rDom != null && rDom.cliTypes.TryGetValue (cliType, out resolved)) return true; } resolved = null; return false; }
public XcodeSyncedType (NSObjectTypeInfo type) { this.Type = type; }
/// <summary> /// Resolves the type by mapping the known Objective-C type information to .NET types. /// </summary> /// <returns> /// The number of unresolved types still remaining. /// </returns> /// <param name='type'> /// The NSObjectTypeInfo that contains the known Objective-C type information. /// Typically this will be the result of NSObjectInfoService.ParseHeader(). /// </param> /// <param name='provider'> /// A CodeDom provider which is used to make sure type names don't conflict with language keywords. /// </param> /// <param name='defaultNamespace'> /// The default namespace used when forcing type resolution. /// </param> public void ResolveObjcToCli(IProgressMonitor monitor, NSObjectTypeInfo type, CodeDomProvider provider, string defaultNamespace) { NSObjectTypeInfo resolved; // Resolve our base type if (type.BaseCliType == null) { if (TryResolveObjcToCli(type.BaseObjCType, out resolved)) { type.BaseCliType = resolved.CliName; } else { var reference = new GetClassTypeReference(defaultNamespace, provider.CreateValidIdentifier(type.BaseObjCType)); type.BaseCliType = reference.Resolve(dom.Compilation).ReflectionName; var message = string.Format("Failed to resolve Objective-C type '{0}' to a type in the current solution.", type.BaseObjCType); message += string.Format(" Adding a [Register (\"{0}\")] attribute to the class which corresponds to this will allow it to be synced to Objective-C.", type.BaseObjCType); monitor.ReportError(null, new UserException("Error while syncing", message)); } } // Resolve [Outlet] types foreach (var outlet in type.Outlets) { if (outlet.CliType != null) { continue; } if (TryResolveObjcToCli(outlet.ObjCType, out resolved)) { outlet.CliType = resolved.CliName; } else { outlet.CliType = defaultNamespace + "." + provider.CreateValidIdentifier(outlet.ObjCType); var message = string.Format("Failed to resolve Objective-C outlet '{0}' of type '{1}' to a type in the current solution.", outlet.ObjCName, outlet.ObjCType); message += string.Format(" Adding a [Register (\"{0}\")] attribute to the class which corresponds to this will allow it to be synced to Objective-C.", outlet.ObjCType); monitor.ReportError(null, new UserException("Error while syncing", message)); } } // Resolve [Action] param types foreach (var action in type.Actions) { foreach (var param in action.Parameters) { if (param.CliType != null) { continue; } if (TryResolveObjcToCli(param.ObjCType, out resolved)) { param.CliType = resolved.CliName; } else { param.CliType = defaultNamespace + "." + provider.CreateValidIdentifier(param.ObjCType); var message = string.Format("Failed to resolve paramater '{0}' of type '{2}' on Objective-C action '{1}' to a type in the current solution.", param.Name, action.ObjCName, param.ObjCType); message += string.Format(" Adding a [Register (\"{0}\")] attribute to the class which corresponds to this will allow it to be synced to Objective-C.", param.ObjCType); monitor.ReportError(null, new UserException("Error while syncing", message)); } } } }
void UpdateTypeMembers(ProjectDom dom, NSObjectTypeInfo info, IType type) { info.Actions.Clear(); info.Outlets.Clear(); foreach (var prop in type.Properties) { foreach (var att in prop.Attributes) { bool isIBOutlet = att.AttributeType.FullName == iboutletAttType.FullName; if (!isIBOutlet) { if (att.AttributeType.FullName != connectAttType.FullName) { continue; } } string name = null; if (att.PositionalArguments.Count == 1) { name = (string)((System.CodeDom.CodePrimitiveExpression)att.PositionalArguments[0]).Value; } if (string.IsNullOrEmpty(name)) { name = prop.Name; } // HACK: Work around bug #1586 in the least obtrusive way possible. Strip out any outlet // with the name 'view' on subclasses of MonoTouch.UIKit.UIViewController to avoid // conflicts with the view property mapped there if (name == "view") { if (dom.GetInheritanceTree(type).Any(p => p.FullName == "MonoTouch.UIKit.UIViewController")) { continue; } } var ol = new IBOutlet(name, prop.Name, null, prop.ReturnType.FullName); if (MonoDevelop.DesignerSupport.CodeBehind.IsDesignerFile(prop.DeclaringType.CompilationUnit.FileName)) { ol.IsDesigner = true; } info.Outlets.Add(ol); break; } } foreach (var meth in type.Methods) { foreach (var att in meth.Attributes) { bool isIBAction = att.AttributeType.FullName == ibactionAttType.FullName; if (!isIBAction) { if (att.AttributeType.FullName != exportAttType.FullName) { continue; } } bool isDesigner = MonoDevelop.DesignerSupport.CodeBehind.IsDesignerFile( meth.DeclaringType.CompilationUnit.FileName); //only support Export from old designer files, user code must be IBAction if (!isDesigner && !isIBAction) { continue; } string[] name = null; if (att.PositionalArguments.Count == 1) { var n = (string)((System.CodeDom.CodePrimitiveExpression)att.PositionalArguments[0]).Value; if (!string.IsNullOrEmpty(n)) { name = n.Split(colonChar); } } var action = new IBAction(name != null? name [0] : meth.Name, meth.Name); int i = 1; foreach (var param in meth.Parameters) { string label = name != null && i < name.Length? name[i] : null; if (label != null && label.Length == 0) { label = null; } action.Parameters.Add(new IBActionParameter(label, param.Name, null, param.ReturnType.FullName)); } if (MonoDevelop.DesignerSupport.CodeBehind.IsDesignerFile(meth.DeclaringType.CompilationUnit.FileName)) { action.IsDesigner = true; } info.Actions.Add(action); break; } } }
internal void InsertUpdatedType(NSObjectTypeInfo type) { objcTypes[type.ObjCName] = type; cliTypes[type.CliName] = type; }
public void GenerateObjcType(NSObjectTypeInfo type, string directory) { if (type.IsModel) { throw new ArgumentException("Cannot generate definition for model"); } string hFilePath = Path.Combine(directory, type.ObjCName + ".h"); string mFilePath = Path.Combine(directory, type.ObjCName + ".m"); using (var sw = File.CreateText(hFilePath)) { sw.WriteLine(modificationWarning); sw.WriteLine(); sw.WriteLine("#import <UIKit/UIKit.h>"); foreach (var reference in type.UserTypeReferences) { sw.WriteLine("#import \"{0}.h\"", reference); } sw.WriteLine(); sw.WriteLine("@interface {0} : {1} {{", type.ObjCName, type.BaseIsModel? "NSObject" : type.BaseObjCType); foreach (var outlet in type.Outlets) { sw.WriteLine("\t{0} *_{1};", outlet.ObjCType, outlet.ObjCName); } sw.WriteLine("}"); sw.WriteLine(); foreach (var outlet in type.Outlets) { sw.WriteLine("@property (nonatomic, retain) IBOutlet {0} *{1};", outlet.ObjCType, outlet.ObjCName); sw.WriteLine(); } foreach (var action in type.Actions) { if (action.Parameters.Any(p => p.ObjCType == null)) { continue; } WriteActionSignature(action, sw); sw.WriteLine(";"); sw.WriteLine(); } sw.WriteLine("@end"); } using (var sw = File.CreateText(mFilePath)) { sw.WriteLine(modificationWarning); sw.WriteLine(); sw.WriteLine("#import \"{0}.h\"", type.ObjCName); sw.WriteLine(); sw.WriteLine("@implementation {0}", type.ObjCName); sw.WriteLine(); bool hasOutlet = false; foreach (var outlet in type.Outlets) { sw.WriteLine("@synthesize {0} = _{0};", outlet.ObjCName); hasOutlet = true; } if (hasOutlet) { sw.WriteLine(); } foreach (var action in type.Actions) { if (action.Parameters.Any(p => p.ObjCType == null)) { continue; } WriteActionSignature(action, sw); sw.WriteLine(" {"); sw.WriteLine("}"); sw.WriteLine(); } sw.WriteLine("@end"); } }
NSObjectTypeInfo ConvertType (TypeSystemService.ProjectContentWrapper dom, ITypeDefinition type) { string objcName = null; bool isModel = false; bool registeredInDesigner = true; foreach (var att in type.Attributes) { var attType = att.AttributeType; if (attType.Equals (Resolve (dom, registerAttType))) { if (type.GetProjectContent () != null) { registeredInDesigner &= MonoDevelop.DesignerSupport.CodeBehind.IsDesignerFile (att.Region.FileName); } //type registered with an explicit type name are up to the user to provide a valid name var posArgs = att.PositionalArguments; if (posArgs.Count == 1 || posArgs.Count == 2) objcName = posArgs [0].ConstantValue as string; //non-nested types in the root namespace have names accessible from obj-c else if (string.IsNullOrEmpty (type.Namespace) && type.Name.IndexOf ('.') < 0) objcName = type.Name; } if (attType.Equals (Resolve (dom, modelAttType))) isModel = true; } if (string.IsNullOrEmpty (objcName)) return null; string baseType = type.DirectBaseTypes.First ().ReflectionName; if (baseType == "System.Object") baseType = null; bool isUserType = !type.ParentAssembly.Equals (Resolve (dom, nsobjectType).ParentAssembly); var info = new NSObjectTypeInfo (objcName, type.ReflectionName, null, baseType, isModel, isUserType, registeredInDesigner); if (info.IsUserType) { UpdateTypeMembers (dom, info, type); info.DefinedIn = type.Parts.Select (p => (string) p.Region.FileName).ToArray (); } return info; }
public void ResolveTypes (NSObjectTypeInfo type) { NSObjectTypeInfo resolved; if (type.BaseObjCType == null && type.BaseCliType != null) { if (TryResolveCliToObjc (type.BaseCliType, out resolved)) { if (resolved.IsModel) type.BaseIsModel = true; type.BaseObjCType = resolved.ObjCName; //FIXME: handle type references better if (resolved.IsUserType) type.UserTypeReferences.Add (resolved.ObjCName); } else { //managed classes many have implicitly registered base classes with a name not //expressible in obj-c. In this case, the best we can do is walk down the //hierarchy until we find a valid base class foreach (var bt in dom.GetInheritanceTree (dom.GetType (type.BaseCliType))) { if (bt.ClassType != ClassType.Class) continue; if (TryResolveCliToObjc (bt.FullName, out resolved)) { if (resolved.IsModel) type.BaseIsModel = true; type.BaseObjCType = resolved.ObjCName; if (resolved.IsUserType) type.UserTypeReferences.Add (resolved.ObjCName); break; } } } } if (type.BaseCliType == null && type.BaseObjCType != null) { if (TryResolveObjcToCli (type.BaseObjCType, out resolved)) type.BaseCliType = resolved.CliName; } foreach (var outlet in type.Outlets) { if (outlet.ObjCType == null) { if (TryResolveCliToObjc (outlet.CliType, out resolved)) { outlet.ObjCType = resolved.ObjCName; if (resolved.IsUserType) type.UserTypeReferences.Add (resolved.ObjCName); } } if (outlet.CliType == null) { if (TryResolveObjcToCli (outlet.ObjCType, out resolved)) { outlet.CliType = resolved.CliName; } else { MessageService.ShowError (GettextCatalog.GetString ("Error while syncing object c type."), string.Format (GettextCatalog.GetString ("Type '{0}' can't be resolved to a valid cli type."), outlet.ObjCType)); ContainsErrors = true; outlet.CliType = outlet.ObjCType; } } } foreach (var action in type.Actions) { foreach (var param in action.Parameters) { if (param.ObjCType == null) { if (TryResolveCliToObjc (param.CliType, out resolved)) { param.ObjCType = resolved.ObjCName; if (resolved.IsUserType) type.UserTypeReferences.Add (resolved.ObjCName); } } if (param.CliType == null) { if (TryResolveObjcToCli (param.ObjCType, out resolved)) param.CliType = resolved.CliName; } } } }
void UpdateUserType (NSObjectTypeInfo type) { if (userClasses.Add (type.ObjCName)) xcodeProjectDirty = true; //FIXME: types dep on other types on project, need better regeneration skipping //FilePath target = outputDir.Combine (type.ObjCName + ".h"); //if (File.Exists (target) && File.GetLastWriteTime (target) >= type.DefinedIn.Max (f => File.GetLastWriteTime (f))) // return; if (!Directory.Exists (outputDir)) Directory.CreateDirectory (outputDir); type.GenerateObjcType (outputDir); string fullH = outputDir.Combine (type.ObjCName + ".h"); trackedFiles[fullH] = File.GetLastWriteTime (fullH); }
public void GenerateObjcType (NSObjectTypeInfo type, string directory) { if (type.IsModel) throw new ArgumentException ("Cannot generate definition for model"); string hFilePath = Path.Combine (directory, type.ObjCName + ".h"); string mFilePath = Path.Combine (directory, type.ObjCName + ".m"); using (var sw = File.CreateText (hFilePath)) { sw.WriteLine (modificationWarning); sw.WriteLine (); sw.WriteLine ("#import <UIKit/UIKit.h>"); foreach (var reference in type.UserTypeReferences) { sw.WriteLine ("#import \"{0}.h\"", reference); } sw.WriteLine (); sw.WriteLine ("@interface {0} : {1} {{", type.ObjCName, type.BaseIsModel? "NSObject" : type.BaseObjCType); foreach (var outlet in type.Outlets) { sw.WriteLine ("\t{0} *_{1};", outlet.ObjCType, outlet.ObjCName); } sw.WriteLine ("}"); sw.WriteLine (); foreach (var outlet in type.Outlets) { sw.WriteLine ("@property (nonatomic, retain) IBOutlet {0} *{1};", outlet.ObjCType, outlet.ObjCName); sw.WriteLine (); } foreach (var action in type.Actions) { if (action.Parameters.Any (p => p.ObjCType == null)) continue; WriteActionSignature (action, sw); sw.WriteLine (";"); sw.WriteLine (); } sw.WriteLine ("@end"); } using (var sw = File.CreateText (mFilePath)) { sw.WriteLine (modificationWarning); sw.WriteLine (); sw.WriteLine ("#import \"{0}.h\"", type.ObjCName); sw.WriteLine (); sw.WriteLine ("@implementation {0}", type.ObjCName); sw.WriteLine (); bool hasOutlet = false; foreach (var outlet in type.Outlets) { sw.WriteLine ("@synthesize {0} = _{0};", outlet.ObjCName); hasOutlet = true; } if (hasOutlet) sw.WriteLine (); foreach (var action in type.Actions) { if (action.Parameters.Any (p => p.ObjCType == null)) continue; WriteActionSignature (action, sw); sw.WriteLine (" {"); sw.WriteLine ("}"); sw.WriteLine (); } sw.WriteLine ("@end"); } }
void ResolveTypes (ProjectDom dom, NSObjectTypeInfo type) { NSObjectTypeInfo resolved; if (type.BaseObjCType == null && type.BaseCliType != null) { if (cliTypes.TryGetValue (type.BaseCliType, out resolved)) { if (resolved.IsModel) type.BaseIsModel = true; type.BaseObjCType = resolved.ObjCName; if (resolved.IsUserType) type.UserTypeReferences.Add (resolved.ObjCName); } else { //managed classes many have implicitly registered base classes with a name not //expressible in obj-c. In this case, the best we can do is walk down the //hierarchy until we find a valid base class foreach (var bt in dom.GetInheritanceTree (dom.GetType (type.BaseCliType))) { if (cliTypes.TryGetValue (bt.FullName, out resolved)) { if (resolved.IsModel) type.BaseIsModel = true; type.BaseObjCType = resolved.ObjCName; if (resolved.IsUserType) type.UserTypeReferences.Add (resolved.ObjCName); break; } } if (type.BaseObjCType == null) Console.WriteLine ("Could not resolve CLI type '{0}'", type.BaseCliType); } } if (type.BaseCliType == null && type.BaseObjCType != null) { if (objcTypes.TryGetValue (type.BaseObjCType, out resolved)) type.BaseCliType = resolved.CliName; } foreach (var outlet in type.Outlets) { if (outlet.ObjCType == null) { if (cliTypes.TryGetValue (outlet.CliType, out resolved)) { outlet.ObjCType = resolved.ObjCName; if (resolved.IsUserType) type.UserTypeReferences.Add (resolved.ObjCName); } } if (outlet.CliType == null) { if (objcTypes.TryGetValue (outlet.ObjCType, out resolved)) outlet.CliType = resolved.CliName; } } foreach (var action in type.Actions) { foreach (var param in action.Parameters) { if (param.ObjCType == null) { if (cliTypes.TryGetValue (param.CliType, out resolved)) { param.ObjCType = resolved.ObjCName; if (resolved.IsUserType) type.UserTypeReferences.Add (resolved.ObjCName); } } if (param.CliType == null) { if (objcTypes.TryGetValue (param.ObjCType, out resolved)) param.CliType = resolved.CliName; } } } }
void ResolveTypes(NSObjectTypeInfo type) { NSObjectTypeInfo resolved; if (type.BaseObjCType == null && type.BaseCliType != null) { if (TryResolveCliToObjc(type.BaseCliType, out resolved)) { if (resolved.IsModel) { type.BaseIsModel = true; } type.BaseObjCType = resolved.ObjCName; //FIXME: handle type references better if (resolved.IsUserType) { type.UserTypeReferences.Add(resolved.ObjCName); } } else { //managed classes many have implicitly registered base classes with a name not //expressible in obj-c. In this case, the best we can do is walk down the //hierarchy until we find a valid base class foreach (var bt in dom.GetInheritanceTree(dom.GetType(type.BaseCliType))) { if (bt.ClassType != ClassType.Class) { continue; } if (TryResolveCliToObjc(bt.FullName, out resolved)) { if (resolved.IsModel) { type.BaseIsModel = true; } type.BaseObjCType = resolved.ObjCName; if (resolved.IsUserType) { type.UserTypeReferences.Add(resolved.ObjCName); } break; } } } } if (type.BaseCliType == null && type.BaseObjCType != null) { if (TryResolveObjcToCli(type.BaseObjCType, out resolved)) { type.BaseCliType = resolved.CliName; } } foreach (var outlet in type.Outlets) { if (outlet.ObjCType == null) { if (TryResolveCliToObjc(outlet.CliType, out resolved)) { outlet.ObjCType = resolved.ObjCName; if (resolved.IsUserType) { type.UserTypeReferences.Add(resolved.ObjCName); } } } if (outlet.CliType == null) { if (TryResolveObjcToCli(outlet.ObjCType, out resolved)) { outlet.CliType = resolved.CliName; } } } foreach (var action in type.Actions) { foreach (var param in action.Parameters) { if (param.ObjCType == null) { if (TryResolveCliToObjc(param.CliType, out resolved)) { param.ObjCType = resolved.ObjCName; if (resolved.IsUserType) { type.UserTypeReferences.Add(resolved.ObjCName); } } } if (param.CliType == null) { if (TryResolveObjcToCli(param.ObjCType, out resolved)) { param.CliType = resolved.CliName; } } } } }
bool TryResolveCliToObjc (string cliType, out NSObjectTypeInfo resolved) { if (cliTypes.TryGetValue (cliType, out resolved)) return true; if (refCliTypes.TryGetValue (cliType, out resolved)) return true; resolved = null; return false; }
/// <summary> /// Resolves the Objective-C types by mapping the known .NET type information. /// </summary> /// <param name='type'> /// An NSObjectTypeInfo with the .NET type information filled in. /// </param> public void ResolveCliToObjc (NSObjectTypeInfo type) { NSObjectTypeInfo resolved; if (type.BaseObjCType == null && type.BaseCliType != null) { if (TryResolveCliToObjc (type.BaseCliType, out resolved)) { if (resolved.IsModel) type.BaseIsModel = true; type.BaseObjCType = resolved.ObjCName; //FIXME: handle type references better if (resolved.IsUserType) type.UserTypeReferences.Add (resolved.ObjCName); } else { //managed classes many have implicitly registered base classes with a name not //expressible in obj-c. In this case, the best we can do is walk down the //hierarchy until we find a valid base class var reference = ReflectionHelper.ParseReflectionName (type.BaseCliType); var baseCliType = reference.Resolve (dom.Compilation); foreach (var bt in baseCliType.GetAllBaseTypeDefinitions ()) { if (bt.Kind != TypeKind.Class) continue; if (TryResolveCliToObjc (bt.ReflectionName, out resolved)) { if (resolved.IsModel) type.BaseIsModel = true; type.BaseObjCType = resolved.ObjCName; if (resolved.IsUserType) type.UserTypeReferences.Add (resolved.ObjCName); break; } } } } foreach (var outlet in type.Outlets) { if (outlet.ObjCType != null) continue; if (TryResolveCliToObjc (outlet.CliType, out resolved)) { outlet.ObjCType = resolved.ObjCName; if (resolved.IsUserType) type.UserTypeReferences.Add (resolved.ObjCName); } } foreach (var action in type.Actions) { foreach (var param in action.Parameters) { if (param.ObjCType != null) continue; if (TryResolveCliToObjc (param.CliType, out resolved)) { param.ObjCType = resolved.ObjCName; if (resolved.IsUserType) type.UserTypeReferences.Add (resolved.ObjCName); } } } }
void UpdateTypeMembers (TypeSystemService.ProjectContentWrapper dom, NSObjectTypeInfo info, ITypeDefinition type) { info.Actions.Clear (); info.Outlets.Clear (); foreach (var prop in type.Properties) { foreach (var att in prop.Attributes) { var attType = att.AttributeType; bool isIBOutlet = attType.Equals (Resolve (dom, iboutletAttType)); if (!isIBOutlet) { if (!attType.Equals (Resolve (dom, connectAttType))) continue; } string name = null; var posArgs = att.PositionalArguments; if (posArgs.Count == 1) name = posArgs [0].ConstantValue as string; if (string.IsNullOrEmpty (name)) name = prop.Name; // HACK: Work around bug #1586 in the least obtrusive way possible. Strip out any outlet // with the name 'view' on subclasses of MonoTouch.UIKit.UIViewController to avoid // conflicts with the view property mapped there if (name == "view") { if (type.GetAllBaseTypeDefinitions ().Any (p => p.ReflectionName == "MonoTouch.UIKit.UIViewController")) continue; } var ol = new IBOutlet (name, prop.Name, null, prop.ReturnType.ReflectionName); if (MonoDevelop.DesignerSupport.CodeBehind.IsDesignerFile (prop.Region.FileName)) ol.IsDesigner = true; info.Outlets.Add (ol); break; } } foreach (var meth in type.Methods) { foreach (var att in meth.Attributes) { var attType = att.AttributeType; bool isIBAction = attType.Equals (Resolve (dom, ibactionAttType)); if (!isIBAction) { if (!attType.Equals (Resolve (dom, exportAttType))) continue; } bool isDesigner = MonoDevelop.DesignerSupport.CodeBehind.IsDesignerFile ( meth.DeclaringTypeDefinition.Region.FileName); //only support Export from old designer files, user code must be IBAction if (!isDesigner && !isIBAction) continue; string[] name = null; var posArgs = att.PositionalArguments; if (posArgs.Count == 1 || posArgs.Count == 2) { var n = posArgs [0].ConstantValue as string; if (!string.IsNullOrEmpty (n)) name = n.Split (colonChar); } var action = new IBAction (name != null ? name [0] : meth.Name, meth.Name); int i = 1; foreach (var param in meth.Parameters) { string label = name != null && i < name.Length ? name [i] : null; if (label != null && label.Length == 0) label = null; action.Parameters.Add (new IBActionParameter (label, param.Name, null, param.Type.ReflectionName)); } if (MonoDevelop.DesignerSupport.CodeBehind.IsDesignerFile (meth.Region.FileName)) action.IsDesigner = true; info.Actions.Add (action); break; } } }
public ObjectiveCGenerationException (string message, NSObjectTypeInfo typeInfo) : base (message) { this.typeInfo = typeInfo; }
void UpdateTypeMembers (ProjectDom dom, NSObjectTypeInfo info, IType type) { info.Actions.Clear (); info.Outlets.Clear (); foreach (var prop in type.Properties) { foreach (var att in prop.Attributes) { bool isIBOutlet = att.AttributeType.FullName == iboutletAttType.FullName; if (!isIBOutlet) { if (att.AttributeType.FullName != connectAttType.FullName) continue; } string name = null; if (att.PositionalArguments.Count == 1) name = (string)((System.CodeDom.CodePrimitiveExpression)att.PositionalArguments[0]).Value; if (string.IsNullOrEmpty (name)) name = prop.Name; var ol = new IBOutlet (name, prop.Name, null, prop.ReturnType.FullName); if (MonoDevelop.DesignerSupport.CodeBehind.IsDesignerFile (prop.DeclaringType.CompilationUnit.FileName)) ol.IsDesigner = true; info.Outlets.Add (ol); break; } } foreach (var meth in type.Methods) { foreach (var att in meth.Attributes) { bool isIBAction = att.AttributeType.FullName == ibactionAttType.FullName; if (!isIBAction) { if (att.AttributeType.FullName != exportAttType.FullName) continue; } bool isDesigner = MonoDevelop.DesignerSupport.CodeBehind.IsDesignerFile ( meth.DeclaringType.CompilationUnit.FileName); //only support Export from old designer files, user code must be IBAction if (!isDesigner && !isIBAction) continue; string[] name = null; if (att.PositionalArguments.Count == 1) { var n = (string)((System.CodeDom.CodePrimitiveExpression)att.PositionalArguments[0]).Value; if (!string.IsNullOrEmpty (n)) name = n.Split (colonChar); } var action = new IBAction (name != null? name [0] : meth.Name, meth.Name); int i = 1; foreach (var param in meth.Parameters) { string label = name != null && i < name.Length? name[i] : null; if (label != null && label.Length == 0) label = null; action.Parameters.Add (new IBActionParameter (label, param.Name, null, param.ReturnType.FullName)); } if (MonoDevelop.DesignerSupport.CodeBehind.IsDesignerFile (meth.DeclaringType.CompilationUnit.FileName)) action.IsDesigner = true; info.Actions.Add (action); break; } } }
void UpdateUserType (NSObjectTypeInfo type) { if (userClasses.Add (type.ObjCName)) xcodeProjectDirty = true; FilePath target = outputDir.Combine (type.ObjCName + ".h"); if (File.Exists (target) && File.GetLastWriteTime (target) >= type.DefinedIn.Max (f => File.GetLastWriteTime (f))) return; if (!Directory.Exists (outputDir)) Directory.CreateDirectory (outputDir); typeTracker.GenerateObjcType (type, outputDir); }
static NSObjectTypeInfo ConvertType (ProjectDom dom, IType type) { string objcName = null; bool isModel = false; foreach (var att in type.Attributes) { if (att.AttributeType.FullName == registerAttType.FullName) { //type registered with an explicit type name are up to the user to proide a valid name if (att.PositionalArguments.Count == 1) objcName = (string)((System.CodeDom.CodePrimitiveExpression)att.PositionalArguments[0]).Value; //non-nested types in the root namespace have names accessible from obj-c else if (string.IsNullOrEmpty (type.Namespace) && type.Name.IndexOf ('.') < 0) objcName = type.Name; } if (att.AttributeType.FullName == modelAttType.FullName) { isModel = true; } } if (string.IsNullOrEmpty (objcName)) return null; var info = new NSObjectTypeInfo (objcName, type.FullName, null, type.BaseType.FullName, isModel); info.IsUserType = type.SourceProject != null; if (info.IsUserType) { UpdateTypeMembers (dom, info, type); info.DefinedIn = type.Parts.Select (p => (string) p.CompilationUnit.FileName).ToArray (); } return info; }
/// <summary> /// Resolves the Objective-C types by mapping the known .NET type information. /// </summary> /// <param name='type'> /// An NSObjectTypeInfo with the .NET type information filled in. /// </param> public void ResolveCliToObjc(NSObjectTypeInfo type) { NSObjectTypeInfo resolved; if (type.BaseObjCType == null && type.BaseCliType != null) { if (TryResolveCliToObjc(type.BaseCliType, out resolved)) { if (resolved.IsModel) { type.BaseIsModel = true; } type.BaseObjCType = resolved.ObjCName; //FIXME: handle type references better if (resolved.IsUserType) { type.UserTypeReferences.Add(resolved.ObjCName); } } else { //managed classes many have implicitly registered base classes with a name not //expressible in obj-c. In this case, the best we can do is walk down the //hierarchy until we find a valid base class var reference = ReflectionHelper.ParseReflectionName(type.BaseCliType); var baseCliType = reference.Resolve(dom.Compilation); foreach (var bt in GetAllBaseClassDefinitions(baseCliType)) { if (TryResolveCliToObjc(bt.ReflectionName, out resolved)) { if (resolved.IsModel) { type.BaseIsModel = true; } type.BaseObjCType = resolved.ObjCName; if (resolved.IsUserType) { type.UserTypeReferences.Add(resolved.ObjCName); } break; } } } } foreach (var outlet in type.Outlets) { if (outlet.ObjCType != null) { continue; } if (TryResolveCliToObjc(outlet.CliType, out resolved)) { outlet.ObjCType = resolved.ObjCName; if (resolved.IsUserType) { type.UserTypeReferences.Add(resolved.ObjCName); } } } foreach (var action in type.Actions) { foreach (var param in action.Parameters) { if (param.ObjCType != null) { continue; } if (TryResolveCliToObjc(param.CliType, out resolved)) { param.ObjCType = resolved.ObjCName; if (resolved.IsUserType) { type.UserTypeReferences.Add(resolved.ObjCName); } } } } }
static void UpdateTypeMembers (ProjectDom dom, NSObjectTypeInfo info, IType type) { info.Actions.Clear (); info.Outlets.Clear (); foreach (var prop in type.Properties) { foreach (var att in prop.Attributes) { if (att.AttributeType.FullName != connectAttType.FullName) continue; string name = null; if (att.PositionalArguments.Count == 1) name = (string)((System.CodeDom.CodePrimitiveExpression)att.PositionalArguments[0]).Value; if (string.IsNullOrEmpty (name)) name = prop.Name; info.Outlets.Add (new IBOutlet (name, prop.Name, null, prop.ReturnType.FullName)); break; } } foreach (var meth in type.Methods) { foreach (var att in meth.Attributes) { if (att.AttributeType.FullName != exportAttType.FullName) continue; string[] name = null; if (att.PositionalArguments.Count == 1) { var n = (string)((System.CodeDom.CodePrimitiveExpression)att.PositionalArguments[0]).Value; if (!string.IsNullOrEmpty (n)) name = n.Split (colonChar); } var action = new IBAction (name != null? name [0] : meth.Name, meth.Name); info.Actions.Add (action); int i = 1; foreach (var param in meth.Parameters) { string label = name != null && i < name.Length? name[i] : null; if (label != null && label.Length == 0) label = null; action.Parameters.Add (new IBActionParameter (label, param.Name, null, param.ReturnType.FullName)); } break; } } }
public XcodeSyncedType (NSObjectTypeInfo type, string[] frameworks) { Frameworks = frameworks; Type = type; }
public static NSObjectTypeInfo ParseHeader (string headerFile) { var text = System.IO.File.ReadAllText (headerFile); var matches = ibRegex.Matches (text); var type = new NSObjectTypeInfo (System.IO.Path.GetFileNameWithoutExtension (headerFile), null, null, null, false); foreach (Match match in matches) { var kind = match.Groups[1].Value; var def = match.Groups[2].Value; if (kind == "IBOutlet") { var split = def.Split (whitespaceChars, StringSplitOptions.RemoveEmptyEntries); if (split.Length != 2) continue; type.Outlets.Add (new IBOutlet (split[1].TrimStart ('*'), null, split[0].TrimEnd ('*'), null)); } else { string[] split = def.Split (colonChar); var action = new IBAction (split[0].Trim (), null); string label = null; for (int i = 1; i < split.Length; i++) { var s = split[i].Split (splitActionParamsChars, StringSplitOptions.RemoveEmptyEntries); var par = new IBActionParameter (label, s[1], s[0], null); label = s.Length == 3? s[2] : null; action.Parameters.Add (par); } type.Actions.Add (action); } } return type; }
public ObjectiveCGenerationException(string message, NSObjectTypeInfo typeInfo) : base(message) { this.typeInfo = typeInfo; }
void ResolveTypes(ProjectDom dom, NSObjectTypeInfo type) { NSObjectTypeInfo resolved; if (type.BaseObjCType == null && type.BaseCliType != null) { if (cliTypes.TryGetValue(type.BaseCliType, out resolved)) { if (resolved.IsModel) { type.BaseIsModel = true; } type.BaseObjCType = resolved.ObjCName; if (resolved.IsUserType) { type.UserTypeReferences.Add(resolved.ObjCName); } } else { //managed classes many have implicitly registered base classes with a name not //expressible in obj-c. In this case, the best we can do is walk down the //hierarchy until we find a valid base class foreach (var bt in dom.GetInheritanceTree(dom.GetType(type.BaseCliType))) { if (cliTypes.TryGetValue(bt.FullName, out resolved)) { if (resolved.IsModel) { type.BaseIsModel = true; } type.BaseObjCType = resolved.ObjCName; if (resolved.IsUserType) { type.UserTypeReferences.Add(resolved.ObjCName); } break; } } if (type.BaseObjCType == null) { Console.WriteLine("Could not resolve CLI type '{0}'", type.BaseCliType); } } } if (type.BaseCliType == null && type.BaseObjCType != null) { if (objcTypes.TryGetValue(type.BaseObjCType, out resolved)) { type.BaseCliType = resolved.CliName; } } foreach (var outlet in type.Outlets) { if (outlet.ObjCType == null) { if (cliTypes.TryGetValue(outlet.CliType, out resolved)) { outlet.ObjCType = resolved.ObjCName; if (resolved.IsUserType) { type.UserTypeReferences.Add(resolved.ObjCName); } } } if (outlet.CliType == null) { if (objcTypes.TryGetValue(outlet.ObjCType, out resolved)) { outlet.CliType = resolved.CliName; } } } foreach (var action in type.Actions) { foreach (var param in action.Parameters) { if (param.ObjCType == null) { if (cliTypes.TryGetValue(param.CliType, out resolved)) { param.ObjCType = resolved.ObjCName; if (resolved.IsUserType) { type.UserTypeReferences.Add(resolved.ObjCName); } } } if (param.CliType == null) { if (objcTypes.TryGetValue(param.ObjCType, out resolved)) { param.CliType = resolved.CliName; } } } } }
/// <summary> /// Resolves the Objective-C types by mapping the known .NET type information. /// </summary> /// <param name='type'> /// An NSObjectTypeInfo with the .NET type information filled in. /// </param> public void ResolveCliToObjc (NSObjectTypeInfo type) { NSObjectTypeInfo resolved; if (type.BaseObjCType == null && type.BaseCliType != null) { if (TryResolveCliToObjc (type.BaseCliType, out resolved)) { if (resolved.IsModel) type.BaseIsModel = true; type.BaseObjCType = resolved.ObjCName; //FIXME: handle type references better if (resolved.IsUserType) type.UserTypeReferences.Add (resolved.ObjCName); } else { // managed classes may have implicitly registered base classes with a name not // expressible in obj-c. In this case, the best we can do is walk down the // hierarchy until we find a valid base class foreach (var bt in dom.GetInheritanceTree (dom.GetType (type.BaseCliType))) { if (bt.ClassType != ClassType.Class) continue; if (TryResolveCliToObjc (bt.FullName, out resolved)) { if (resolved.IsModel) type.BaseIsModel = true; type.BaseObjCType = resolved.ObjCName; if (resolved.IsUserType) type.UserTypeReferences.Add (resolved.ObjCName); break; } } } } foreach (var outlet in type.Outlets) { if (outlet.ObjCType != null) continue; if (TryResolveCliToObjc (outlet.CliType, out resolved)) { outlet.ObjCType = resolved.ObjCName; if (resolved.IsUserType) type.UserTypeReferences.Add (resolved.ObjCName); } } foreach (var action in type.Actions) { foreach (var param in action.Parameters) { if (param.ObjCType != null) continue; if (TryResolveCliToObjc (param.CliType, out resolved)) { param.ObjCType = resolved.ObjCName; if (resolved.IsUserType) type.UserTypeReferences.Add (resolved.ObjCName); } } } }
public static NSObjectTypeInfo ParseHeader(string headerFile) { string text = File.ReadAllText(headerFile); string userType = null, userBaseType = null; MatchCollection matches; NSObjectTypeInfo type; // First, grep for classes matches = typeInfoRegex.Matches(text); foreach (Match match in matches) { if (match.Groups[1].Value != "interface") { continue; } if (userType != null) { // UNSUPPORTED: more than 1 user-type defined in this header return(null); } userType = match.Groups[2].Value; userBaseType = match.Groups[3].Value; } if (userType == null) { return(null); } type = new NSObjectTypeInfo(userType, null, userBaseType, null, false, true, true); // Now grep for IBActions and IBOutlets matches = ibRegex.Matches(text); foreach (Match match in matches) { var kind = match.Groups[1].Value; var def = match.Groups[2].Value; if (kind == "IBOutlet") { var split = def.Split(whitespaceChars, StringSplitOptions.RemoveEmptyEntries); string objcType = split[0].TrimEnd('*'); string objcName = null; for (int i = 1; i < split.Length; i++) { objcName = split[i].TrimStart('*'); if (string.IsNullOrEmpty(objcName)) { continue; } if (i + 1 < split.Length) { // This is a bad sign... what tokens are after the name?? objcName = null; break; } } if (string.IsNullOrEmpty(objcType) || string.IsNullOrEmpty(objcName)) { MessageService.ShowError(GettextCatalog.GetString("Error while parsing header file."), string.Format(GettextCatalog.GetString("The definition '{0}' can't be parsed."), def)); // We can't recover if objcName is empty... if (string.IsNullOrEmpty(objcName)) { continue; } // We can try using NSObject... objcType = "NSObject"; } if (objcType == "id") { objcType = "NSObject"; } IBOutlet outlet = new IBOutlet(objcName, objcName, objcType, null); outlet.IsDesigner = true; type.Outlets.Add(outlet); } else { string[] split = def.Split(colonChar); string name = split[0].Trim(); var action = new IBAction(name, name); action.IsDesigner = true; string label = null; for (int i = 1; i < split.Length; i++) { var s = split[i].Split(splitActionParamsChars, StringSplitOptions.RemoveEmptyEntries); string objcType = s[0]; if (objcType == "id") { objcType = "NSObject"; } var par = new IBActionParameter(label, s[1], objcType, null); label = s.Length == 3? s[2] : null; action.Parameters.Add(par); } type.Actions.Add(action); } } return(type); }
internal void InsertUpdatedType (NSObjectTypeInfo type) { objcTypes[type.ObjCName] = type; cliTypes[type.CliName] = type; }
NSObjectTypeInfo ConvertType (ProjectDom dom, IType type) { string objcName = null; bool isModel = false; bool registeredInDesigner = true; foreach (var part in type.Parts) { foreach (var att in part.Attributes) { if (att.AttributeType.FullName == registerAttType.FullName) { if (type.SourceProject != null) { registeredInDesigner &= MonoDevelop.DesignerSupport.CodeBehind.IsDesignerFile (part.CompilationUnit.FileName); } //type registered with an explicit type name are up to the user to provide a valid name // Note that the attribute now takes one *or* two parameters. if (att.PositionalArguments.Count == 1 || att.PositionalArguments.Count == 2) objcName = (string)((System.CodeDom.CodePrimitiveExpression)att.PositionalArguments[0]).Value; //non-nested types in the root namespace have names accessible from obj-c else if (string.IsNullOrEmpty (type.Namespace) && type.Name.IndexOf ('.') < 0) objcName = type.Name; } if (att.AttributeType.FullName == modelAttType.FullName) { isModel = true; } } } if (string.IsNullOrEmpty (objcName)) return null; var info = new NSObjectTypeInfo (objcName, type.FullName, null, type.BaseType.FullName, isModel, type.SourceProject != null, registeredInDesigner); if (info.IsUserType) { UpdateTypeMembers (dom, info, type); info.DefinedIn = type.Parts.Select (p => (string) p.CompilationUnit.FileName).ToArray (); } return info; }
bool TryResolveObjcToCli (string objcType, out NSObjectTypeInfo resolved) { if (objcTypes.TryGetValue (objcType, out resolved)) return true; if (refObjcTypes.TryGetValue (objcType, out resolved)) return true; #if false var msg = new StringBuilder ("Can't resolve "+ objcType + Environment.NewLine); foreach (var r in dom.References) { msg.Append ("Referenced dom:"); msg.Append (r); var rDom = infoService.GetProjectInfo (r); if (rDom == null) { msg.AppendLine ("projectinfo == null"); continue; } msg.Append ("known types:"); msg.AppendLine (string.Join (",", rDom.objcTypes.Keys.ToArray())); } LoggingService.LogWarning (msg.ToString ()); #endif resolved = null; return false; }
public static NSObjectTypeInfo ParseHeader (string headerFile) { string text = File.ReadAllText (headerFile); string userType = null, userBaseType = null; MatchCollection matches; NSObjectTypeInfo type; // First, grep for classes matches = typeInfoRegex.Matches (text); foreach (Match match in matches) { if (match.Groups[1].Value != "interface") continue; if (userType != null) { // UNSUPPORTED: more than 1 user-type defined in this header return null; } userType = match.Groups[2].Value; userBaseType = match.Groups[3].Value; } if (userType == null) return null; type = new NSObjectTypeInfo (userType, null, userBaseType, null, false, true, true); // Now grep for IBActions and IBOutlets matches = ibRegex.Matches (text); foreach (Match match in matches) { var kind = match.Groups[1].Value; var def = match.Groups[2].Value; if (kind == "IBOutlet") { var split = def.Split (whitespaceChars, StringSplitOptions.RemoveEmptyEntries); if (split.Length != 2) continue; string objcName = split[1].TrimStart ('*'); string objcType = split[0].TrimEnd ('*'); if (objcType == "id") objcType = "NSObject"; if (string.IsNullOrEmpty (objcType)) { MessageService.ShowError (GettextCatalog.GetString ("Error while parsing header file."), string.Format (GettextCatalog.GetString ("The definition '{0}' can't be parsed."), def)); objcType = "NSObject"; } IBOutlet outlet = new IBOutlet (objcName, objcName, objcType, null); outlet.IsDesigner = true; type.Outlets.Add (outlet); } else { string[] split = def.Split (colonChar); string name = split[0].Trim (); var action = new IBAction (name, name); action.IsDesigner = true; string label = null; for (int i = 1; i < split.Length; i++) { var s = split[i].Split (splitActionParamsChars, StringSplitOptions.RemoveEmptyEntries); string objcType = s[0]; if (objcType == "id") objcType = "NSObject"; var par = new IBActionParameter (label, s[1], objcType, null); label = s.Length == 3? s[2] : null; action.Parameters.Add (par); } type.Actions.Add (action); } } return type; }
/// <summary> /// Resolves the type by mapping the known Objective-C type information to .NET types. /// </summary> /// <returns> /// The number of unresolved types still remaining. /// </returns> /// <param name='type'> /// The NSObjectTypeInfo that contains the known Objective-C type information. /// Typically this will be the result of NSObjectInfoService.ParseHeader(). /// </param> /// <param name='provider'> /// A CodeDom provider which is used to make sure type names don't conflict with language keywords. /// </param> /// <param name='defaultNamespace'> /// The default namespace used when forcing type resolution. /// </param> public void ResolveObjcToCli (IProgressMonitor monitor, NSObjectTypeInfo type, CodeDomProvider provider, string defaultNamespace) { NSObjectTypeInfo resolved; // Resolve our base type if (type.BaseCliType == null) { if (TryResolveObjcToCli (type.BaseObjCType, out resolved)) { type.BaseCliType = resolved.CliName; } else { var reference = new GetClassTypeReference (defaultNamespace, provider.CreateValidIdentifier (type.BaseObjCType)); type.BaseCliType = reference.Resolve (dom.Compilation).ReflectionName; var message = string.Format ("Failed to resolve Objective-C type '{0}' to a type in the current solution.", type.BaseObjCType); message += string.Format (" Adding a [Register (\"{0}\")] attribute to the class which corresponds to this will allow it to be synced to Objective-C.", type.BaseObjCType); monitor.ReportError (null, new UserException ("Error while syncing", message)); } } // Resolve [Outlet] types foreach (var outlet in type.Outlets) { if (outlet.CliType != null) continue; if (TryResolveObjcToCli (outlet.ObjCType, out resolved)) { outlet.CliType = resolved.CliName; } else { outlet.CliType = defaultNamespace + "." + provider.CreateValidIdentifier (outlet.ObjCType); var message = string.Format ("Failed to resolve Objective-C outlet '{0}' of type '{1}' to a type in the current solution.", outlet.ObjCName, outlet.ObjCType); message += string.Format (" Adding a [Register (\"{0}\")] attribute to the class which corresponds to this will allow it to be synced to Objective-C.", outlet.ObjCType); monitor.ReportError (null, new UserException ("Error while syncing", message)); } } // Resolve [Action] param types foreach (var action in type.Actions) { foreach (var param in action.Parameters) { if (param.CliType != null) continue; if (TryResolveObjcToCli (param.ObjCType, out resolved)) { param.CliType = resolved.CliName; } else { param.CliType = defaultNamespace + "." + provider.CreateValidIdentifier (param.ObjCType); var message = string.Format ("Failed to resolve paramater '{0}' of type '{2}' on Objective-C action '{1}' to a type in the current solution.", param.Name, action.ObjCName, param.ObjCType); message += string.Format (" Adding a [Register (\"{0}\")] attribute to the class which corresponds to this will allow it to be synced to Objective-C.", param.ObjCType); monitor.ReportError (null, new UserException ("Error while syncing", message)); } } } }
void UpdateUserType (NSObjectTypeInfo type) { if (userClasses.Add (type.ObjCName)) xcodeProjectDirty = true; //FIXME: types dep on other types on project, need better regeneration skipping //FilePath target = outputDir.Combine (type.ObjCName + ".h"); //if (File.Exists (target) && File.GetLastWriteTime (target) >= type.DefinedIn.Max (f => File.GetLastWriteTime (f))) // return; if (!Directory.Exists (outputDir)) Directory.CreateDirectory (outputDir); type.GenerateObjcType (outputDir); string headerFlag = outputDir.Combine (type.ObjCName + ".h.modified"); if (File.Exists (headerFlag)) File.SetLastWriteTime (headerFlag, DateTime.Now); else File.WriteAllText (headerFlag, ""); }
void UpdateTypeMembers(TypeSystemService.ProjectContentWrapper dom, NSObjectTypeInfo info, ITypeDefinition type) { info.Actions.Clear(); info.Outlets.Clear(); foreach (var prop in type.Properties) { foreach (var att in prop.Attributes) { var attType = att.AttributeType; bool isIBOutlet = attType.Equals(Resolve(dom, iboutletAttType)); if (!isIBOutlet) { if (!attType.Equals(Resolve(dom, connectAttType))) { continue; } } string name = null; var posArgs = att.PositionalArguments; if (posArgs.Count == 1) { name = posArgs [0].ConstantValue as string; } if (string.IsNullOrEmpty(name)) { name = prop.Name; } // HACK: Work around bug #1586 in the least obtrusive way possible. Strip out any outlet // with the name 'view' on subclasses of MonoTouch.UIKit.UIViewController to avoid // conflicts with the view property mapped there if (name == "view") { if (type.GetAllBaseTypeDefinitions().Any(p => p.ReflectionName == "MonoTouch.UIKit.UIViewController")) { continue; } } var ol = new IBOutlet(name, prop.Name, null, prop.ReturnType.ReflectionName); if (MonoDevelop.DesignerSupport.CodeBehind.IsDesignerFile(prop.Region.FileName)) { ol.IsDesigner = true; } info.Outlets.Add(ol); break; } } foreach (var meth in type.Methods) { foreach (var att in meth.Attributes) { var attType = att.AttributeType; bool isIBAction = attType.Equals(Resolve(dom, ibactionAttType)); if (!isIBAction) { if (!attType.Equals(Resolve(dom, exportAttType))) { continue; } } bool isDesigner = MonoDevelop.DesignerSupport.CodeBehind.IsDesignerFile(meth.Region.FileName); //only support Export from old designer files, user code must be IBAction if (!isDesigner && !isIBAction) { continue; } string[] name = null; var posArgs = att.PositionalArguments; if (posArgs.Count == 1 || posArgs.Count == 2) { var n = posArgs [0].ConstantValue as string; if (!string.IsNullOrEmpty(n)) { name = n.Split(colonChar); } } var action = new IBAction(name != null ? name [0] : meth.Name, meth.Name); int i = 1; foreach (var param in meth.Parameters) { string label = name != null && i < name.Length ? name [i] : null; if (label != null && label.Length == 0) { label = null; } action.Parameters.Add(new IBActionParameter(label, param.Name, null, param.Type.ReflectionName)); } if (MonoDevelop.DesignerSupport.CodeBehind.IsDesignerFile(meth.Region.FileName)) { action.IsDesigner = true; } info.Actions.Add(action); break; } } }
/// <summary> /// Resolves the type by mapping the known Objective-C type information to .NET types. /// </summary> /// <returns> /// The number of unresolved types still remaining. /// </returns> /// <param name='type'> /// The NSObjectTypeInfo that contains the known Objective-C type information. /// Typically this will be the result of NSObjectInfoService.ParseHeader(). /// </param> /// <param name='provider'> /// A CodeDom provider which is used to make sure type names don't conflict with language keywords. /// </param> /// <param name='defaultNamespace'> /// The default namespace used when forcing type resolution. /// </param> public void ResolveObjcToCli(IProgressMonitor monitor, NSObjectTypeInfo type, CodeDomProvider provider, string defaultNamespace) { NSObjectTypeInfo resolved; // Resolve our base type if (type.BaseCliType == null) { if (TryResolveObjcToCli(type.BaseObjCType, out resolved)) { type.BaseCliType = resolved.CliName; } else { type.BaseCliType = defaultNamespace + "." + provider.CreateValidIdentifier(type.BaseObjCType); monitor.ReportWarning(string.Format("Failed to resolve Objective-C type {0} to CLI type on type {1}", type.BaseObjCType, type.ObjCName)); } } // Resolve [Outlet] types foreach (var outlet in type.Outlets) { if (outlet.CliType != null) { continue; } if (TryResolveObjcToCli(outlet.ObjCType, out resolved)) { outlet.CliType = resolved.CliName; } else { outlet.CliType = defaultNamespace + "." + provider.CreateValidIdentifier(outlet.ObjCType); monitor.ReportWarning(string.Format("Failed to resolve Objective-C type {0} to CLI type on outlet {1} on type {2}", outlet.ObjCType, outlet.ObjCName, type.ObjCName)); } } // Resolve [Action] param types foreach (var action in type.Actions) { foreach (var param in action.Parameters) { if (param.CliType != null) { continue; } if (TryResolveObjcToCli(param.ObjCType, out resolved)) { param.CliType = resolved.CliName; } else { param.CliType = defaultNamespace + "." + provider.CreateValidIdentifier(param.ObjCType); monitor.ReportWarning(string.Format("Failed to resolve Objective-C type {0} to CLI type on action parameter {1} for action {2} on type {3}", param.ObjCType, param.Name, action.ObjCName, type.ObjCName)); } } } }
public UserTypeChange(NSObjectTypeInfo type, UserTypeChangeKind kind) { this.Type = type; this.Kind = kind; }
public static XcodeSyncObjcBackJob NewType (NSObjectTypeInfo type, string relativePath) { return new XcodeSyncObjcBackJob () { RelativePath = relativePath, IsFreshlyAdded = true, Type = type, }; }
void UpdateTypeMembers (ProjectDom dom, NSObjectTypeInfo info, IType type) { info.Actions.Clear (); info.Outlets.Clear (); foreach (var prop in type.Properties) { foreach (var att in prop.Attributes) { bool isIBOutlet = att.AttributeType.FullName == iboutletAttType.FullName; if (!isIBOutlet) { if (att.AttributeType.FullName != connectAttType.FullName) continue; } string name = null; if (att.PositionalArguments.Count == 1) name = (string)((System.CodeDom.CodePrimitiveExpression)att.PositionalArguments[0]).Value; if (string.IsNullOrEmpty (name)) name = prop.Name; // HACK: Work around bug #1586 in the least obtrusive way possible. Strip out any outlet // with the name 'view' on subclasses of MonoTouch.UIKit.UIViewController to avoid // conflicts with the view property mapped there if (name == "view") if (dom.GetInheritanceTree (type).Any (p => p.FullName == "MonoTouch.UIKit.UIViewController")) continue; var ol = new IBOutlet (name, prop.Name, null, prop.ReturnType.FullName); if (MonoDevelop.DesignerSupport.CodeBehind.IsDesignerFile (prop.DeclaringType.CompilationUnit.FileName)) ol.IsDesigner = true; info.Outlets.Add (ol); break; } } foreach (var meth in type.Methods) { foreach (var att in meth.Attributes) { bool isIBAction = att.AttributeType.FullName == ibactionAttType.FullName; if (!isIBAction) { if (att.AttributeType.FullName != exportAttType.FullName) continue; } bool isDesigner = MonoDevelop.DesignerSupport.CodeBehind.IsDesignerFile ( meth.DeclaringType.CompilationUnit.FileName); //only support Export from old designer files, user code must be IBAction if (!isDesigner && !isIBAction) continue; string[] name = null; if (att.PositionalArguments.Count == 1) { var n = (string)((System.CodeDom.CodePrimitiveExpression)att.PositionalArguments[0]).Value; if (!string.IsNullOrEmpty (n)) name = n.Split (colonChar); } var action = new IBAction (name != null? name [0] : meth.Name, meth.Name); int i = 1; foreach (var param in meth.Parameters) { string label = name != null && i < name.Length? name[i] : null; if (label != null && label.Length == 0) label = null; action.Parameters.Add (new IBActionParameter (label, param.Name, null, param.ReturnType.FullName)); } if (MonoDevelop.DesignerSupport.CodeBehind.IsDesignerFile (meth.DeclaringType.CompilationUnit.FileName)) action.IsDesigner = true; info.Actions.Add (action); break; } } }
public static XcodeSyncObjcBackJob UpdateType (NSObjectTypeInfo type, string designerFile) { return new XcodeSyncObjcBackJob () { DesignerFile = designerFile, Type = type, }; }
public UserTypeChange (NSObjectTypeInfo type, UserTypeChangeKind kind) { this.Type = type; this.Kind = kind; }
/// <summary> /// Merges CLI info from previous version of the type into the parsed objc-type. /// </summary> public void MergeCliInfo (NSObjectTypeInfo previousType) { CliName = previousType.CliName; DefinedIn = previousType.DefinedIn; IsModel = previousType.IsModel; BaseIsModel = previousType.BaseIsModel; IsUserType = previousType.IsUserType; IsRegisteredInDesigner = previousType.IsRegisteredInDesigner; var existingOutlets = new Dictionary<string,IBOutlet> (); foreach (var o in previousType.Outlets) existingOutlets[o.ObjCName] = o; var existingActions = new Dictionary<string,IBAction> (); foreach (var a in previousType.Actions) existingActions[a.ObjCName] = a; foreach (var a in Actions) { IBAction existing; if (existingActions.TryGetValue (a.ObjCName, out existing)) { a.IsDesigner = existing.IsDesigner; a.CliName = existing.CliName; } } foreach (var o in Outlets) { IBOutlet existing; if (existingOutlets.TryGetValue (o.ObjCName, out existing)) { o.IsDesigner = existing.IsDesigner; o.CliName = existing.CliName; } } }