private IList<FilePath> GenerateCodeBehindForHeader(ProjectTypeCache cache, CodeBehindWriter writer, FilePath file) { IDELogger.Log ("CodeBehindHandler::GenerateCodeBehindForHeader -- Parsing {0}", file); // Parse and collect information from the document AntlrFileStream stream = new AntlrFileStream (file); ObjCLexer lexer = new ObjCLexer (stream); CommonTokenStream tokenStream = new CommonTokenStream (lexer); ObjCParser parser = new ObjCParser (tokenStream); ObjCParser.Translation_unitContext context = parser.translation_unit (); NativeClassDescriptionCollector<int> visitor = new NativeClassDescriptionCollector<int> (); context.Accept (visitor); /* IDELogger.Log ("CodeBehindHandler::GenerateCodeBehindForHeader -- Dump classes"); foreach (NativeClassDescriptor classDescriptor in visitor.Descriptors) { IDELogger.Log ("CodeBehindHandler::GenerateCodeBehindForHeader -- ClassName={0}", classDescriptor.ClassName); IDELogger.Log ("CodeBehindHandler::GenerateCodeBehindForHeader -- SuperClassName={0}", classDescriptor.SuperClassName); foreach (NativeMethodDescriptor descriptor in classDescriptor.Methods) { IDELogger.Log ("CodeBehindHandler::GenerateCodeBehindForHeader -- {0}", descriptor); } foreach (NativeInstanceVariableDescriptor descriptor in classDescriptor.InstanceVariables) { IDELogger.Log ("CodeBehindHandler::GenerateCodeBehindForHeader -- {0}", descriptor); } } */ List<FilePath> designerFiles = new List<FilePath> (); foreach (NativeClassDescriptor classDescriptor in visitor.Descriptors) { // Check if the class should be generated if (!ShouldGenerateForHeader (classDescriptor)) { IDELogger.Log ("CodeBehindHandler::GenerateCodeBehindForHeader -- Skipping {0} (no outlets or no actions)", classDescriptor.ClassName); continue; } // Generate the designer part FilePath designerFile = this.CodeGenerator.GenerateCodeBehindCode (cache, writer, classDescriptor.ClassName, new []{ classDescriptor }); if (designerFile != FilePath.Null) { designerFiles.Add (designerFile); } } return designerFiles; }
protected ObjectiveCWriter(MonobjcProject project) { this.project = project; this.cache = ProjectTypeCache.Get(this.project); }
private IList<FilePath> GenerateCodeBehindForXib(ProjectTypeCache cache, CodeBehindWriter writer, FilePath file) { IDELogger.Log ("CodeBehindHandler::GenerateCodeBehindForXib -- Parsing {0}", file); // Parse and collect information from the document IBDocument document = IBDocument.LoadFromFile (file); ClassDescriptionCollector visitor = new ClassDescriptionCollector (); document.Root.Accept (visitor); List<FilePath> designerFiles = new List<FilePath> (); foreach (string className in visitor.ClassNames) { // Check if the class should be generated if (!ShouldGenerateForXib (visitor, className)) { IDELogger.Log ("CodeBehindHandler::GenerateCodeBehindForXib -- Skipping {0} (no outlets, no actions or reserved name)", className); continue; } // Generate the designer part FilePath designerFile = this.CodeGenerator.GenerateCodeBehindCode (cache, writer, className, visitor [className]); if (designerFile != FilePath.Null) { designerFiles.Add (designerFile); } } return designerFiles; }
/// <summary> /// Get the type cache for the given project. /// </summary> public static ProjectTypeCache Get(MonobjcProject project) { ProjectTypeCache cache; if (!caches.TryGetValue (project, out cache)) { IDELogger.Log ("ProjectTypeCache::Get -- create cache for {0}", project.Name); cache = new ProjectTypeCache (project); caches.Add (project, cache); } return cache; }
/// <summary> /// Generates the design code for an Interface Builder file. /// </summary> /// <param name = "resolver">The type resolver.</param> /// <param name = "writer">The writer.</param> /// <param name = "className">Name of the class.</param> /// <param name = "enumerable">The class descriptions.</param> /// <returns>The path to the designer file.</returns> public FilePath GenerateCodeBehindCode(ProjectTypeCache cache, CodeBehindWriter writer, String className, IEnumerable<IIBClassDescriptor> descriptors) { FilePath designerFile = null; String defaultNamespace; MonobjcProject project = cache.Project; IDELogger.Log ("BaseCodeBehindGenerator::GenerateCodeBehindCode -- Generate designer code for '{0}'", className); IType type = cache.ResolvePartialType (className); FilePath mainFile = cache.GetMainFile (type); if (mainFile != FilePath.Null) { if (mainFile.Extension == ".dll") { IDELogger.Log ("BaseCodeBehindGenerator::GenerateCodeBehindCode -- Skipping '{0}' as it comes from a DLL", className); return FilePath.Null; } if (!cache.IsInProject (type)) { IDELogger.Log ("BaseCodeBehindGenerator::GenerateCodeBehindCode -- Skipping '{0}' as it comes from another project", className); return FilePath.Null; } // The filname is based on the compilation unit parent folder and the type name FilePath parentDirectory = mainFile.ParentDirectory; FilePath filename = project.LanguageBinding.GetFileName (type.Name + Constants.DOT_DESIGNER); designerFile = parentDirectory.Combine (filename); defaultNamespace = type.Namespace; } else { // Combine the filename in the default directory FilePath parentDirectory = project.BaseDirectory; FilePath filename = project.LanguageBinding.GetFileName (className + Constants.DOT_DESIGNER); designerFile = parentDirectory.Combine (filename); defaultNamespace = project.GetDefaultNamespace (designerFile); } IDELogger.Log ("BaseCodeBehindGenerator::GenerateCodeBehindCode -- Put designer code in '{0}'", designerFile); // Create the compilation unit CodeCompileUnit ccu = new CodeCompileUnit (); CodeNamespace ns = new CodeNamespace (defaultNamespace); ccu.Namespaces.Add (ns); // Create the partial class CodeTypeDeclaration typeDeclaration = new CodeTypeDeclaration (className); typeDeclaration.IsClass = true; typeDeclaration.IsPartial = true; // List for import collection Set<String> imports = new Set<string> (); imports.Add ("Monobjc"); // Create fields for outlets); foreach (IBOutletDescriptor outlet in descriptors.SelectMany(d => d.Outlets)) { IType outletType = cache.ResolvePartialType (outlet.ClassName); outletType = outletType ?? cache.ResolvePartialType ("id"); outletType = outletType ?? cache.ResolveType (typeof(IntPtr)); IDELogger.Log ("BaseCodeBehindGenerator::GenerateCodeBehindCode -- Resolving outlet '{0}' of type '{1}' => '{2}'", outlet.Name, outlet.ClassName, outletType.FullName); imports.Add (outletType.Namespace); CodeTypeMember property = this.GenerateOutletProperty (outletType, outlet.Name); typeDeclaration.Members.Add (property); } // Create methods for exposed actions foreach (IBActionDescriptor action in descriptors.SelectMany(d => d.Actions)) { IType argumentType = cache.ResolvePartialType (action.Argument); argumentType = argumentType ?? cache.ResolvePartialType ("id"); argumentType = argumentType ?? cache.ResolveType (typeof(IntPtr)); IDELogger.Log ("BaseCodeBehindGenerator::GenerateCodeBehindCode -- Resolving action '{0}' of type '{1}' => '{2}'", action.Message, action.Argument, argumentType.FullName); imports.Add (argumentType.Namespace); CodeTypeMember exposedMethod = this.GenerateActionExposedMethod (action.Message, argumentType); typeDeclaration.Members.Add (exposedMethod); CodeTypeMember partialMethod = this.GenerateActionPartialMethod (action.Message, argumentType); typeDeclaration.Members.Add (partialMethod); } // Add namespaces CodeNamespaceImport[] namespaceImports = imports.Select (import => new CodeNamespaceImport (import)).ToArray (); ns.Imports.AddRange (namespaceImports); // Add the type ns.Types.Add (typeDeclaration); // Write the result writer.WriteFile (designerFile, ccu); return designerFile; }
protected virtual CodeCompileUnit GenerateCodeCompileUnit(ProjectTypeCache cache, String defaultNamespace, String className, IEnumerable<IBPartialClassDescription> enumerable) { // Create the compilation unit CodeCompileUnit ccu = new CodeCompileUnit (); CodeNamespace ns = new CodeNamespace (defaultNamespace); ccu.Namespaces.Add (ns); // Create the partial class CodeTypeDeclaration typeDeclaration = new CodeTypeDeclaration (className); typeDeclaration.IsClass = true; typeDeclaration.IsPartial = true; // List for import collection Set<String> imports = new Set<string> (); imports.Add ("Monobjc"); // Create fields for outlets); foreach (IBOutletDescriptor outlet in enumerable.SelectMany(d => d.Outlets)) { IType outletType = cache.ResolvePartialType (outlet.ClassName); outletType = outletType ?? cache.ResolvePartialType ("id"); outletType = outletType ?? cache.ResolveType (typeof(IntPtr)); IDELogger.Log ("BaseCodeBehindGenerator::GenerateCodeBehindCode -- Resolving outlet '{0}' of type '{1}' => '{2}'", outlet.Name, outlet.ClassName, outletType.FullName); imports.Add (outletType.Namespace); CodeTypeMember property = this.GenerateOutletProperty (outletType, outlet.Name); typeDeclaration.Members.Add (property); } // Create methods for exposed actions foreach (IBActionDescriptor action in enumerable.SelectMany(d => d.Actions)) { IType argumentType = cache.ResolvePartialType (action.Argument); argumentType = argumentType ?? cache.ResolvePartialType ("id"); argumentType = argumentType ?? cache.ResolveType (typeof(IntPtr)); IDELogger.Log ("BaseCodeBehindGenerator::GenerateCodeBehindCode -- Resolving action '{0}' of type '{1}' => '{2}'", action.Message, action.Argument, argumentType.FullName); imports.Add (argumentType.Namespace); CodeTypeMember exposedMethod = this.GenerateActionExposedMethod (action.Message, argumentType); typeDeclaration.Members.Add (exposedMethod); CodeTypeMember partialMethod = this.GenerateActionPartialMethod (action.Message, argumentType); typeDeclaration.Members.Add (partialMethod); } // Add namespaces CodeNamespaceImport[] namespaceImports = imports.Select (import => new CodeNamespaceImport (import)).ToArray (); ns.Imports.AddRange (namespaceImports); // Add the type ns.Types.Add (typeDeclaration); return ccu; }
/// <summary> /// Generates the design code for framework loading. /// </summary> /// <param name = "resolver">The type resolver.</param> /// <param name = "frameworks">The frameworks.</param> /// <returns>The path to the designer file.</returns> public FilePath GenerateFrameworkLoadingCode(ProjectTypeCache cache, String[] frameworks) { IEnumerable<IType> entryPoints = cache.GetEntryPoints (); IType entryPoint = entryPoints.SingleOrDefault (); if (entryPoint != null) { IMethod method = cache.GetMainMethod (entryPoint); if (method != null) { // Get the start line of the method DomRegion region = method.BodyRegion; int startLine = region.BeginLine; // Load the entry point file String fileName = region.FileName; List<String> lines = File.ReadAllLines (fileName).ToList (); // Search for desginer region indices int startIndex = lines.FindIndex (startLine - 1, l => this.IsDesignerRegionDelimiter (l, true)); int endIndex = -1; if (startIndex != -1) { endIndex = lines.FindIndex (startIndex, l => this.IsDesignerRegionDelimiter (l, false)); } if (startIndex != -1 && endIndex != -1) { // Build a new list of lines with the new code List<String> newLines = new List<String> (); newLines.AddRange (lines.Take (startIndex)); newLines.AddRange (this.GenerateFrameworkLoadingcode (frameworks)); newLines.AddRange (lines.Skip (endIndex + 1)); // Write it to the file File.WriteAllLines (fileName, newLines.ToArray ()); return fileName; } } } return null; }