internal CodegenUnit(AssemblyName asmName) { var fileName = asmName.Name + ".dll"; var pdbName = asmName + ".pdb"; // so that we can run multiple tests at once and not lose the info if (UnitTest.CurrentTest != null) { fileName = asmName + ", " + UnitTest.PersistentId + ".dll"; pdbName = asmName + ".pdb"; } #if TRACE try { _asm = AppDomain.CurrentDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndSave); _mod = _asm.DefineDynamicModule(fileName, true); // Mark generated code as debuggable. // See http://blogs.msdn.com/jmstall/archive/2005/02/03/366429.aspx for explanation. var daCtor = typeof(DebuggableAttribute).GetConstructor(new [] { typeof(DebuggableAttribute.DebuggingModes) }); var daBuilder = new CustomAttributeBuilder(daCtor, new object[] { DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.Default }); _asm.SetCustomAttribute(daBuilder); // Mark generated code as non-user code. // See http://stackoverflow.com/questions/1423733/how-to-tell-if-a-net-assembly-is-dynamic for explanation. var cgCtor = typeof(CompilerGeneratedAttribute).GetConstructor(Type.EmptyTypes); var cgBuilder = new CustomAttributeBuilder(cgCtor, new object [] {}); _asm.SetCustomAttribute(cgBuilder); var hasAlreadyBeenDumped = false; Action dumpAssembly = () => { if (!hasAlreadyBeenDumped && _asm != null) { try { // todo. before dumping make sure that all types are completed or else the dump will simply crash // this is a complex task, but it needs to be resolved for generic case _asm.Save(fileName); } catch (Exception ex) { var trace = String.Format("Codegen unit '{0}' has failed to dump the asm:{1}{2}", asmName.FullName, Environment.NewLine, ex); Log.WriteLine(trace); SafetyTools.SafeDo(() => { File.WriteAllText(fileName, trace); File.Delete(pdbName); }); } finally { hasAlreadyBeenDumped = true; } } }; _dumpAssembly = dumpAssembly; // do not use DomainUnload here because it never gets fired for default domain // however, we need not to neglect because R#'s unit-test runner never exits process AppDomain.CurrentDomain.DomainUnload += (o, e) => dumpAssembly(); AppDomain.CurrentDomain.ProcessExit += (o, e) => dumpAssembly(); AppDomain.CurrentDomain.UnhandledException += (o, e) => dumpAssembly(); } catch (Exception ex) { var trace = String.Format("Codegen unit '{0}' has failed to initialize:{1}{2}", asmName.FullName, Environment.NewLine, ex); Log.WriteLine(trace); SafetyTools.SafeDo(() => { File.WriteAllText(fileName, trace); File.Delete(pdbName); }); throw; } #else _asm = AppDomain.CurrentDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.Run); _asm.SetCustomAttribute(new CustomAttributeBuilder(typeof(CompilerGeneratedAttribute).GetConstructor(Type.EmptyTypes), new object[] { })); _mod = _asm.DefineDynamicModule(fileName, false); #endif }
public static void Help(Type t_cfg) { var asm = t_cfg == null ? null : t_cfg.Assembly; if (t_cfg != null) { var @params = t_cfg.GetProperties(BF.AllInstance) .Where(p => p.HasAttr <ParamAttribute>()).OrderBy(p => p.Attr <ParamAttribute>().Priority).ToReadOnly(); var cfg_name = t_cfg.Attr <ConfigAttribute>().Name ?? asm.GetName().Name; var s_syntax = String.Format("Syntax: {0}", cfg_name); foreach (var p in @params) { var is_optional = t_cfg.GetProperty("Default" + p.Name, BF.AllStatic) != null; var alias = p.Attr <ParamAttribute>().Aliases.First(); s_syntax += String.Format(" {0}-{1}:{2}{3}", is_optional ? "[" : "", alias, p.Name, is_optional ? "]" : ""); } s_syntax += " [/verbose]"; Console.WriteLine(s_syntax); var shortcuts = t_cfg.Attrs <ShortcutAttribute>().OrderBy(shortcut => shortcut.Priority); if (shortcuts.IsNotEmpty()) { Console.EnsureBlankLine(); if (shortcuts.Count() == 1) { Console.WriteLine("Shortcut: "); } else { Console.WriteLine("Shortcuts:"); Console.Write(" "); } shortcuts.ForEach((shortcut, i) => { shortcut.Description.AssertNull(); Console.WriteLine(cfg_name + (shortcut.Schema.IsNullOrEmpty() ? "" : (" " + shortcut.Schema))); if (i != shortcuts.Count() - 1) { Console.Write(" "); } }); } Console.EnsureBlankLine(); Console.WriteLine("Parameters:"); var max_name = @params.MaxOrDefault(p => p.Name.Length); max_name = Math.Max("/verbose".Length, max_name); var feed = new String(' ', 4 + 1 + max_name + 2); var max_desc = 80 - feed.Length; (max_desc > 0).AssertTrue(); Action <String, String> write_name_desc = (name, desc) => { Console.Write(String.Format(" {0}{1}{2} ", name.StartsWith("/") ? "" : "%", name.PadRight(max_name), name.StartsWith("/") ? " " : "")); var num_lines = (int)Math.Ceiling(1.0 * desc.Length / max_desc); for (var i = 0; i < num_lines; ++i) { if (i != 0) { Console.Write(feed); } var line = desc.Substring(i * max_desc, Math.Min(max_desc, desc.Length - i * max_desc)); Console.WriteLine(line); } }; foreach (var p in @params) { var desc = p.Attr <ParamAttribute>().Description ?? String.Empty; var p_default = t_cfg.GetProperty("Default" + p.Name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (p_default != null) { var default_value = p_default.GetValue(null, null); if (default_value != null) { var s_default_value = default_value == null ? "null" : default_value.ToString(); if (default_value is DirectoryInfo) { var dir = default_value as DirectoryInfo; if (dir.FullName == Environment.CurrentDirectory) { s_default_value = "current dir"; } } var s_default = String.Format("Defaults to {0}.", s_default_value); if (!String.IsNullOrEmpty(desc)) { if (!desc.EndsWith(".")) { desc += "."; } desc += " "; } desc += s_default; } } if (!String.IsNullOrEmpty(desc)) { write_name_desc(p.Name, desc); } } write_name_desc("/verbose", "Turns verbose tracing on, useful for debugging."); } }