public static void ImportCloneDetectiveResults(string fileName) { string solutionPath = VSPackage.Instance.GetSolutionPath(); if (solutionPath == null) { return; } string logPath = PathHelper.GetLogPath(solutionPath); string cloneReportPath = PathHelper.GetCloneReportPath(solutionPath); using (StreamWriter logWriter = new StreamWriter(logPath)) { try { logWriter.WriteLine("Opening clone report from '{0}'...", fileName); CloneReport cloneReport = CloneReport.FromFile(fileName); string oldRootPath = GetCommonRoot(cloneReport); string newRootPath = AskUserForNewRootPath(cloneReport, oldRootPath, Path.GetDirectoryName(solutionPath)); if (newRootPath == null) { logWriter.WriteLine("User aborted import."); return; } logWriter.WriteLine("Remapping paths from '{0}' to '{1}'...", oldRootPath, newRootPath); RemapPaths(cloneReport, oldRootPath, newRootPath); logWriter.WriteLine("Saving clone report to '{0}'...", cloneReportPath); CloneReport.ToFile(cloneReportPath, cloneReport); logWriter.WriteLine("Import of '{0}' succeeded.", fileName); LogHelper.WriteStatusInfo(logWriter, CloneDetectiveResultStatus.Succeeded, 0, TimeSpan.Zero); } catch (Exception ex) { LogHelper.WriteError(logWriter, ex); LogHelper.WriteStatusInfo(logWriter, CloneDetectiveResultStatus.Failed, 0, TimeSpan.Zero); } } CloneDetectiveResult = CloneDetectiveResult.FromSolutionPath(solutionPath); }
internal static void OnDocumentSaved(uint docCookie) { // The document identified by docCookie has been saved. Now we have to update // our internal data structures and persist them to file. This will ensure we // will display the same data again when the user closes and reopens the document. // If there is currently no clone report available there is nothing to do. if (!IsCloneReportAvailable) { return; } CloneDetectiveResult cloneDetectiveResult = CloneDetectiveResult; // Get the text buffer. We're done if this fails because that means it was not // a text document. IVsTextLines textLines = GetDocumentTextLines(docCookie); if (textLines == null) { return; } // Get the SourceFile of the document in our data structure. We're done if this // fails because that means the document was not included in clone detection. string path = GetDocumentPath(textLines); SourceNode sourceNode = cloneDetectiveResult.SourceTree.FindNode(path); if (sourceNode == null) { return; } SourceFile sourceFile = sourceNode.SourceFile; // And we need to be able to map existing clone markers to their corresponding // clone classes. If that fails we cannot update any clone information. DocumentInfo documentInfo; if (!_textLinesToDocInfos.TryGetValue(textLines, out documentInfo)) { return; } // If the hash of the file didn't match when we opened it, we don't want to save // any changes. if (!documentInfo.HashMatched) { return; } // Store the new line count of the file. Be aware of the fact that the last line // is not taken into account if it is empty. Replace the fingerprint of the file // with the new one such that we get no problems when opening up the file the // next time. int lastLineIndex; int lastLineLength; if (ErrorHandler.Failed(textLines.GetLastLineIndex(out lastLineIndex, out lastLineLength))) { return; } sourceFile.Length = lastLineIndex + ((lastLineLength > 0) ? 1 : 0); sourceFile.Fingerprint = GetHashFromFile(path); // We need to track which source file clone information was modified to be able // to update the rollups afterwards. HashSet <SourceFile> modifiedSourceFiles = new HashSet <SourceFile>(); // Clear old clone information of the saved document as we're going to rebuild // it from scratch. foreach (Clone clone in sourceFile.Clones) { clone.CloneClass.Clones.Remove(clone); } sourceFile.Clones.Clear(); modifiedSourceFiles.Add(sourceFile); // Store information about current position of each marker. foreach (KeyValuePair <IVsTextLineMarker, CloneClass> markerWithCloneClass in documentInfo.MarkersToCloneClasses) { // Retrieve the current text span of the marker we just enumerated. TextSpan[] span = new TextSpan[1]; ErrorHandler.ThrowOnFailure(markerWithCloneClass.Key.GetCurrentSpan(span)); // Create a new clone object and initialize it appropriately. Clone clone = new Clone(); clone.CloneClass = markerWithCloneClass.Value; clone.SourceFile = sourceFile; clone.StartLine = span[0].iStartLine; clone.LineCount = span[0].iEndLine - span[0].iStartLine + 1; // Add the clone to the clone class as well as the source file. clone.CloneClass.Clones.Add(clone); clone.SourceFile.Clones.Add(clone); } // Remove clone classes with less than two clones. List <CloneClass> cloneClasses = cloneDetectiveResult.CloneReport.CloneClasses; for (int i = cloneClasses.Count - 1; i >= 0; i--) { List <Clone> clones = cloneClasses[i].Clones; if (clones.Count < 2) { foreach (Clone clone in clones) { clone.SourceFile.Clones.Remove(clone); modifiedSourceFiles.Add(clone.SourceFile); } cloneClasses.RemoveAt(i); } } // Save the new clone report to disk. string solutionPath = VSPackage.Instance.GetSolutionPath(); string cloneReportPath = PathHelper.GetCloneReportPath(solutionPath); CloneReport.ToFile(cloneReportPath, cloneDetectiveResult.CloneReport); // Rollup changes within the SourceTree. foreach (SourceFile modifiedSourceFile in modifiedSourceFiles) { SourceNode modifiedSourceNode = cloneDetectiveResult.SourceTree.FindNode(modifiedSourceFile.Path); SourceTree.RecalculateRollups(modifiedSourceNode); } // Send notification about changed result to listeners. OnCloneDetectiveResultChanged(); }