public XmlTraverser(IDictionary<string, XContract[]> contracts, DocTracker docTracker, Options options) { Contract.Requires(contracts != null); Contract.Requires(docTracker != null); this.contracts = contracts; this.docTracker = docTracker; this.options = options; }
/// <summary> /// The "real" main. This is where all the work in the program starts. /// </summary> ///<remarks> ///Due to technical reasons (see the remarks on "WriteContracts" and "GetContracts"), ///the contracts are gathered first then they are written out. This is instead of ///writting the contracts while they are being found. ///</remarks> ///<remarks> ///The contracts are gathered first then they are written out. We make one pass over the assembly ///to gather contracts, then one pass over the XML file to write out the contracts. This is instead ///of writing the contracts as they are being found, because all members in the assembly may not ///be represented in the XML file or may appear in a different order. ///</remarks> public static int RealMain(string[] args) { #region Parse options var options = new Options(); options.Parse(args); if (options.HelpRequested) { options.PrintOptions(""); return 1; } if (options.HasErrors) { options.PrintErrorsAndExit(Console.Out); return -1; } if (options.breakIntoDebugger) { System.Diagnostics.Debugger.Break(); } if (options.assembly == null && options.GeneralArguments.Count > 0) { options.assembly = options.GeneralArguments[0]; } #endregion try { TrySendLeaderBoardPing(options); #region Set up the DocTracker. (Used for debug output.) TextWriter writer = null; //A null writer is allowed. if (options.debug) { if (options.outFile != null) writer = new StreamWriter(options.outFile); else writer = Console.Out; } DocTracker docTracker = new DocTracker(writer); #endregion #region Collect and write contracts var contracts = GetContracts(options, docTracker); WriteContracts(contracts, options, docTracker); #endregion #region Write contract statistics docTracker.WriteContractsPerKind(MemberKind.Type); docTracker.WriteContractsPerKind(MemberKind.Property); docTracker.WriteContractsPerKind(MemberKind.Method); #endregion } catch { SendLeaderBoardFailure(); throw; } return 0; //success }
/// <summary> /// Creates a ContractTraverser /// </summary> /// <param name="contracts">The dictionary of contracts. This gets filled with contracts during the traversal.</param> /// <param name="options">The options.</param> /// <param name="host">The host environment of the traverser used to load any required assemblies.</param> /// <param name="docTracker">The DocTracker used to provide metrics and to be written into during the traversal.</param> public ContractVisitor(CodeContractAwareHostEnvironment host, IDictionary<string, XContract[]> contracts, Options options, DocTracker docTracker) { Contract.Requires(host != null); Contract.Requires(contracts != null); //Contract.Requires(options != null); Contract.Requires(docTracker != null); this.contracts = contracts; //this.options = options; this.docTracker = docTracker; this.host = host; }
/// <summary> /// Traverse the given assembly (located in options.Assembly) for contracts and return the contracts. /// </summary> /// <remarks> /// We use dictionary mapping special string ids that are unique to each member in an XML file to /// the contracts that that member has. /// </remarks> static IDictionary<string, XContract[]> GetContracts(Options options, DocTracker docTracker) { Contract.Requires(options != null); Contract.Requires(docTracker != null); Contract.Ensures(Contract.Result<IDictionary<string,XContract[]>>() != null); #region Establish host and load assembly Contract.Assume(options.resolvedPaths != null); var host = new CodeContractAwareHostEnvironment(options.libpaths); foreach (var p in options.resolvedPaths) { host.AddResolvedPath(p); } IModule module = host.LoadUnitFrom(options.assembly) as IModule; if (module == null || module == Dummy.Module || module == Dummy.Assembly) { Console.WriteLine("'{0}' is not a PE file containing a CLR module or assembly.", options.assembly); Environment.Exit(1); } #endregion #region Create the contracts dictionary Dictionary<string, XContract[]> contracts = new Dictionary<string, XContract[]>(StringComparer.Ordinal); //Use Ordinal compare for faster string comparison. #endregion #region Traverse module and extract contracts var contractsVisitor = new ContractVisitor(host, contracts, options, docTracker); var traverser = new ContractTraverser(host); traverser.PreorderVisitor = contractsVisitor; traverser.Traverse(module); #endregion return contracts; }
/// <summary> /// Write contracts from dictionary to XML file. /// </summary> static void WriteContracts(IDictionary<string, XContract[]> contracts, Options options, DocTracker docTracker) { Contract.Requires(options != null); Contract.Requires(docTracker != null); Contract.Requires(contracts != null); string xmlDocName = options.xmlFile; #region If an XML file isn't provided, create a new one. if (string.IsNullOrEmpty(xmlDocName) || !File.Exists(xmlDocName)) { docTracker.WriteLine("XML file not provided. Creating a new one."); #region Trim assembly name var trimmedAssemblyName = options.assembly; trimmedAssemblyName = Path.GetFileNameWithoutExtension(trimmedAssemblyName); #endregion if (string.IsNullOrEmpty(xmlDocName)) { xmlDocName = trimmedAssemblyName + ".xml"; } Contract.Assert(xmlDocName != null); #region Create new document XmlDocument doc = new XmlDocument(); doc.AppendChild(doc.CreateXmlDeclaration("1.0", null, null)); var docNode = doc.AppendChild(doc.CreateElement("doc")); var assemblyNode = docNode.AppendChild(doc.CreateElement("assembly")); var nameNode = assemblyNode.AppendChild(doc.CreateElement("name")); nameNode.AppendChild(doc.CreateTextNode(trimmedAssemblyName)); docNode.AppendChild(doc.CreateElement("members")); #endregion doc.Save(xmlDocName); } #endregion #region Traverse the XML file and create a new XML file with contracts var xmlDocTempName = xmlDocName + ".temp"; // xmlDocName may have a path, so don't prepend! using (var reader = XmlReader.Create(xmlDocName)) { docTracker.WriteLine("Reading {0}...", xmlDocName); var settings = new XmlWriterSettings(); settings.Indent = true; settings.NewLineHandling = NewLineHandling.None; using (var writer = XmlWriter.Create(xmlDocTempName, settings)) { docTracker.WriteLine("Writing to {0} ...", xmlDocTempName); XmlTraverser xmlTraverser = new XmlTraverser(contracts, docTracker, options); xmlTraverser.Transform(reader, writer); writer.Flush(); } } #endregion #region Rename the output XML file if (String.IsNullOrEmpty(options.outputFile)) { File.Replace(xmlDocTempName, xmlDocName, xmlDocName + ".old"); } else { var outFile = options.outputFile; var ext = Path.GetExtension(outFile); if (ext != "xml") outFile = Path.ChangeExtension(outFile, ".xml"); if (File.Exists(outFile)) { File.Replace(xmlDocTempName, outFile, xmlDocName + ".old"); } else { File.Copy(xmlDocTempName, outFile); } } #endregion }
private static void TrySendLeaderBoardPing(Options options) { #if LeaderBoard try { LeaderBoard.LeaderBoardAPI.SendLeaderBoardFeatureUse(LeaderBoardFeatureMask_CCDoc); } catch { } #endif }