/// <summary> /// Creates the tree structure for the given clone report. /// </summary> /// <param name="report">The clone report to create the tree structure for.</param> private void FillSourceElements(CloneReport report) { // First we construct the root. _root = new SourceNode(); _root.Name = Path.GetFileNameWithoutExtension(_solutionPath); _root.FullPath = Path.GetDirectoryName(_solutionPath); // Enter the root. This is important in order to make sure that our // tree will only contain elements relative to the directory the solution // is contained in. _pathDictionary.Add(_root.FullPath, _root); // Add all files to the tree. foreach (SourceFile sourceFile in report.SourceFiles) { // Create the file node. SourceNode fileNode = new SourceNode(); fileNode.Name = Path.GetFileName(sourceFile.Path); fileNode.FullPath = sourceFile.Path; fileNode.SourceFile = sourceFile; // Enter the file node to our dictionary. This is not required by // GetSourceElementParent() but for FindNode(). _pathDictionary.Add(fileNode.FullPath, fileNode); // Get the node for the directory the file is contained in. string directory = Path.GetDirectoryName(sourceFile.Path); fileNode.Parent = GetSourceElementParent(_pathDictionary, directory); // Enter the file node to the children of the directory. fileNode.Parent.Children.Add(fileNode); } }
/// <summary> /// Writes a clone report to the given XML file. /// </summary> /// <param name="fileName">The fully qualified path to the ConQAT clone report file.</param> /// <param name="cloneReport">The clone report to be written.</param> public static void Write(string fileName, CloneReport cloneReport) { XmlDocument doc = new XmlDocument(); Write(doc, cloneReport); // We want to write the clone report in the same encoding as ConQAT would. using (XmlTextWriter writer = new XmlTextWriter(fileName, Encoding.GetEncoding("ISO-8859-1"))) { // Since we want to be able to read the result we will // use formatted output. writer.Formatting = Formatting.Indented; doc.Save(writer); } }
public static CloneDetectiveResult FromSolutionPath(string solutionPath) { // Get path to log file. string logPath = PathHelper.GetLogPath(solutionPath); string cloneReportPath = PathHelper.GetCloneReportPath(solutionPath); // If the log file does not exist no clone detective result can be // constructed (if only the clone report is missing it can). if (!File.Exists(logPath)) { return(null); } // Construct the clone detective result. CloneDetectiveResult result = new CloneDetectiveResult(); if (File.Exists(cloneReportPath)) { try { // We have a clone report. Parse it and construct the source tree from it. result.CloneReport = CloneReport.FromFile(cloneReportPath); result.SourceTree = SourceTree.FromCloneReport(result.CloneReport, solutionPath); } catch (Exception ex) { // If we could not parse the clone report we write an error to the // log file (which we will parse below). result.CloneReport = null; result.SourceTree = null; LogHelper.WriteError(logPath, ex); LogHelper.WriteStatusInfo(logPath, CloneDetectiveResultStatus.Failed, 0, TimeSpan.Zero); } } // Parse the summary information out of the log file. CloneDetectiveResultStatus status; long usedMemory; TimeSpan usedTime; LogHelper.ParseStatusInfo(logPath, out status, out usedMemory, out usedTime); result.Status = status; result.UsedMemory = usedMemory; result.UsedTime = usedTime; return(result); }
/// <summary> /// Reads a clone report from the given XML file. /// </summary> /// <param name="fileName">The fully qualified path to the ConQAT clone report file.</param> public static CloneReport Read(string fileName) { XmlDocument doc = new XmlDocument(); // First we try to load the document. try { doc.Load(fileName); } catch (Exception ex) { // NOTE: Here we intentionally catch all exceptions. XmlDocment.Load() lists ten possible exceptions. throw ExceptionBuilder.CannotLoadCloneReport(fileName, ex); } // Add schema so that we can validate the document is validated. using (StringReader stringReader = new StringReader(Resources.CloneReportSchema)) using (XmlTextReader xmlTextReader = new XmlTextReader(stringReader)) doc.Schemas.Add(null, xmlTextReader); // Now we can validate document against the loaded schema. List <XmlSchemaException> validationErrors = new List <XmlSchemaException>(); doc.Validate(delegate(object sender, ValidationEventArgs e) { validationErrors.Add(e.Exception); }); if (validationErrors.Count > 0) { throw ExceptionBuilder.InvalidCloneReport(fileName, validationErrors); } CloneReport cloneReport = Read(doc); // Make sure the source files are sorted by their path. // This property is required by some algorithms later on. cloneReport.SourceFiles.Sort(delegate(SourceFile x, SourceFile y) { return(String.Compare(x.Path, y.Path, StringComparison.OrdinalIgnoreCase)); }); return(cloneReport); }
/// <summary> /// Creates a <see cref="SourceTree"/> from the given <paramref name="cloneReport"/> and solution path. /// </summary> /// <param name="cloneReport">The clone report to create a source tree from.</param> /// <param name="solutionPath">The path to the solution of the clone report.</param> /// <returns>A hierarchical representation of the clone report.</returns> public static SourceTree FromCloneReport(CloneReport cloneReport, string solutionPath) { // Create the source and initialize path to solution. SourceTree sourceTree = new SourceTree(); sourceTree.SolutionPath = solutionPath; // Create the tree structure. sourceTree.FillSourceElements(cloneReport); // Traverse tree and calculate statistics. PropagateDetails(sourceTree.Root); // Sort tree elements so that directories come before files and both // are sorted by name. SortSourceElements(sourceTree.Root); return(sourceTree); }
/// <summary> /// Writes the clone report to the given ConQAT clone report file. /// </summary> /// <param name="fileName">The fully qualified path of the clone report file.</param> /// <param name="cloneReport">The clone report to be written.</param> public static void ToFile(string fileName, CloneReport cloneReport) { CloneReportWriter.Write(fileName, cloneReport); }
/// <summary> /// Reads a clone report from the given XML document. /// </summary> /// <param name="doc">The XML document to read the clone report from.</param> private static CloneReport Read(XmlDocument doc) { XmlNamespaceManager manager = new XmlNamespaceManager(doc.NameTable); manager.AddNamespace("cr", Resources.CloneReportSchemaNamespace); CloneReport cloneReport = new CloneReport(); cloneReport.SystemDate = GetOptionalAttributeString(doc, "/cr:cloneReport/@systemdate", manager); // In order to associate source files and clones we need to map // source file ids to source file objects. Dictionary <int, SourceFile> sourceFileDictionary = new Dictionary <int, SourceFile>(); // Read all source files. XmlNodeList sourceFiles = doc.SelectNodes("/cr:cloneReport/cr:sourceFile", manager); foreach (XmlNode sourceFileNode in sourceFiles) { // Create source file object and parse attributes. SourceFile sourceFile = new SourceFile(); sourceFile.Id = XmlConvert.ToInt32(sourceFileNode.Attributes["id"].Value); sourceFile.Path = sourceFileNode.Attributes["path"].Value; sourceFile.Length = XmlConvert.ToInt32(sourceFileNode.Attributes["length"].Value); sourceFile.Fingerprint = sourceFileNode.Attributes["fingerprint"].Value; // Add source file object to list of all source files. cloneReport.SourceFiles.Add(sourceFile); // Add mapping sourceFile.Id -> sourceFile for later use. sourceFileDictionary.Add(sourceFile.Id, sourceFile); } // Read all clone classes. XmlNodeList cloneClasses = doc.SelectNodes("/cr:cloneReport/cr:cloneClass", manager); foreach (XmlNode cloneClassNode in cloneClasses) { // Create clone class and parse attributes. CloneClass cloneClass = new CloneClass(); cloneClass.Id = XmlConvert.ToInt32(cloneClassNode.Attributes["id"].Value); cloneClass.UniqueId = GetOptionalAttributeString(cloneClassNode, "@uniqueId", manager); cloneClass.NormalizedLength = XmlConvert.ToInt32(cloneClassNode.Attributes["normalizedLength"].Value); cloneClass.Fingerprint = cloneClassNode.Attributes["fingerprint"].Value; // Add clone class to list of all clone classes. cloneReport.CloneClasses.Add(cloneClass); // Read all key-value pairs associated with this clone class. XmlNodeList cloneClassValues = cloneClassNode.SelectNodes("cr:values/cr:value", manager); ReadValues(cloneClassValues, cloneClass.Values); // Read all clones. XmlNodeList clones = cloneClassNode.SelectNodes("cr:clone", manager); foreach (XmlNode cloneNode in clones) { // Parse source file id and get associated source file object. int sourceFileId = XmlConvert.ToInt32(cloneNode.Attributes["sourceFileId"].Value); SourceFile sourceFile = sourceFileDictionary[sourceFileId]; // Create clone and parse attributes. Clone clone = new Clone(); clone.Id = GetOptionalAttributeInt32(cloneNode, "@id", manager); clone.UniqueId = GetOptionalAttributeString(cloneNode, "@uniqueId", manager); clone.SourceFile = sourceFile; clone.StartLine = XmlConvert.ToInt32(cloneNode.Attributes["startLine"].Value); clone.LineCount = XmlConvert.ToInt32(cloneNode.Attributes["lineCount"].Value); clone.StartUnitIndexInFile = XmlConvert.ToInt32(cloneNode.Attributes["startUnitIndexInFile"].Value); clone.LengthInUnits = XmlConvert.ToInt32(cloneNode.Attributes["lengthInUnits"].Value); clone.DeltaInUnits = XmlConvert.ToInt32(cloneNode.Attributes["deltaInUnits"].Value); clone.Gaps = cloneNode.Attributes["gaps"].Value; clone.Fingerprint = cloneNode.Attributes["fingerprint"].Value; // Read all key-value pairs associated with this clone. XmlNodeList cloneValues = cloneNode.SelectNodes("cr:values/cr:value", manager); ReadValues(cloneValues, clone.Values); clone.CloneClass = cloneClass; // Add clone to the clone class' list of clones. cloneClass.Clones.Add(clone); // Add clone to the source file's list of clones. clone.SourceFile.Clones.Add(clone); } } return(cloneReport); }
/// <summary> /// Writes a clone report to the given XML document. /// </summary> /// <param name="doc">The XML document to write to.</param> /// <param name="cloneReport">The clone report to be written.</param> private static void Write(XmlDocument doc, CloneReport cloneReport) { // Create root node. XmlNode reportNode = doc.AppendChild(doc.CreateElement("cloneReport", Resources.CloneReportSchemaNamespace)); if (cloneReport.SystemDate != null) { reportNode.Attributes.Append(doc.CreateAttribute("systemdate")).Value = cloneReport.SystemDate; } // Write all source files. foreach (SourceFile sourceFile in cloneReport.SourceFiles) { // Create source file node and write attributes. XmlNode sourceFileNode = reportNode.AppendChild(doc.CreateElement("sourceFile", Resources.CloneReportSchemaNamespace)); sourceFileNode.Attributes.Append(doc.CreateAttribute("id")).Value = XmlConvert.ToString(sourceFile.Id); sourceFileNode.Attributes.Append(doc.CreateAttribute("path")).Value = sourceFile.Path; sourceFileNode.Attributes.Append(doc.CreateAttribute("length")).Value = XmlConvert.ToString(sourceFile.Length); sourceFileNode.Attributes.Append(doc.CreateAttribute("fingerprint")).Value = sourceFile.Fingerprint; } // Write all clone classes. foreach (CloneClass cloneClass in cloneReport.CloneClasses) { // Create clone class node and write attributes. XmlNode cloneClassNode = reportNode.AppendChild(doc.CreateElement("cloneClass", Resources.CloneReportSchemaNamespace)); cloneClassNode.Attributes.Append(doc.CreateAttribute("id")).Value = XmlConvert.ToString(cloneClass.Id); if (cloneClass.UniqueId != null) { cloneClassNode.Attributes.Append(doc.CreateAttribute("uniqueId")).Value = cloneClass.UniqueId; } cloneClassNode.Attributes.Append(doc.CreateAttribute("normalizedLength")).Value = XmlConvert.ToString(cloneClass.NormalizedLength); cloneClassNode.Attributes.Append(doc.CreateAttribute("fingerprint")).Value = cloneClass.Fingerprint; // Write all key-value pairs of the current clone class. if (cloneClass.Values.Count > 0) { XmlNode valuesNode = cloneClassNode.AppendChild(doc.CreateElement("values", Resources.CloneReportSchemaNamespace)); WriteValues(valuesNode, cloneClass.Values); } // Write all clones of the current clone class. foreach (Clone clone in cloneClass.Clones) { XmlNode cloneNode = cloneClassNode.AppendChild(doc.CreateElement("clone", Resources.CloneReportSchemaNamespace)); if (clone.Id != null) { cloneNode.Attributes.Append(doc.CreateAttribute("id")).Value = XmlConvert.ToString(clone.Id.Value); } if (clone.UniqueId != null) { cloneNode.Attributes.Append(doc.CreateAttribute("uniqueId")).Value = clone.UniqueId; } cloneNode.Attributes.Append(doc.CreateAttribute("sourceFileId")).Value = XmlConvert.ToString(clone.SourceFile.Id); cloneNode.Attributes.Append(doc.CreateAttribute("startLine")).Value = XmlConvert.ToString(clone.StartLine); cloneNode.Attributes.Append(doc.CreateAttribute("lineCount")).Value = XmlConvert.ToString(clone.LineCount); cloneNode.Attributes.Append(doc.CreateAttribute("startUnitIndexInFile")).Value = XmlConvert.ToString(clone.LineCount); cloneNode.Attributes.Append(doc.CreateAttribute("lengthInUnits")).Value = XmlConvert.ToString(clone.LengthInUnits); cloneNode.Attributes.Append(doc.CreateAttribute("deltaInUnits")).Value = XmlConvert.ToString(clone.DeltaInUnits); cloneNode.Attributes.Append(doc.CreateAttribute("gaps")).Value = clone.Gaps; cloneNode.Attributes.Append(doc.CreateAttribute("fingerprint")).Value = clone.Fingerprint; // Write all key-value pairs of the current clone. if (clone.Values.Count > 0) { XmlNode valuesNode = cloneNode.AppendChild(doc.CreateElement("values", Resources.CloneReportSchemaNamespace)); WriteValues(valuesNode, clone.Values); } } } }