clang-replace: Delete change description files

Added a command line option "-remove-change-desc-files" that triggers
the deletion of the change description files after merging and applying
regardless of success.

Differential Revision: http://llvm-reviews.chandlerc.com/D1492

llvm-svn: 189268
diff --git a/clang-tools-extra/clang-replace/ApplyReplacements.cpp b/clang-tools-extra/clang-replace/ApplyReplacements.cpp
index eb0aa37..51e7cce 100644
--- a/clang-tools-extra/clang-replace/ApplyReplacements.cpp
+++ b/clang-tools-extra/clang-replace/ApplyReplacements.cpp
@@ -34,6 +34,7 @@
 llvm::error_code
 collectReplacementsFromDirectory(const llvm::StringRef Directory,
                                  TUReplacements &TUs,
+                                 TUReplacementFiles & TURFiles,
                                  clang::DiagnosticsEngine &Diagnostics) {
   using namespace llvm::sys::fs;
   using namespace llvm::sys::path;
@@ -51,6 +52,8 @@
     if (extension(I->path()) != ".yaml")
       continue;
 
+    TURFiles.push_back(I->path());
+
     OwningPtr<MemoryBuffer> Out;
     error_code BufferError = MemoryBuffer::getFile(I->path(), Out);
     if (BufferError) {
@@ -218,5 +221,22 @@
   return true;
 }
 
+bool deleteReplacementFiles(const TUReplacementFiles &Files,
+                            clang::DiagnosticsEngine &Diagnostics) {
+  bool Success = true;
+  for (TUReplacementFiles::const_iterator I = Files.begin(), E = Files.end();
+       I != E; ++I) {
+    error_code Error = llvm::sys::fs::remove(*I);
+    if (Error) {
+      Success = false;
+      // FIXME: Use Diagnostics for outputting errors.
+      errs() << "Error deleting file: " << *I << "\n";
+      errs() << Error.message() << "\n";
+      errs() << "Please delete the file manually\n";
+    }
+  }
+  return Success;
+}
+
 } // end namespace replace
 } // end namespace clang
diff --git a/clang-tools-extra/clang-replace/ApplyReplacements.h b/clang-tools-extra/clang-replace/ApplyReplacements.h
index cf2b3d7..c69e5bd 100644
--- a/clang-tools-extra/clang-replace/ApplyReplacements.h
+++ b/clang-tools-extra/clang-replace/ApplyReplacements.h
@@ -21,6 +21,7 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/system_error.h"
 #include <vector>
+#include <string>
 
 namespace clang {
 
@@ -32,6 +33,9 @@
 typedef std::vector<clang::tooling::TranslationUnitReplacements>
 TUReplacements;
 
+/// \brief Collection of TranslationUnitReplacement files.
+typedef std::vector<std::string> TUReplacementFiles;
+
 /// \brief Map mapping file name to Replacements targeting that file.
 typedef llvm::StringMap<std::vector<clang::tooling::Replacement> >
 FileToReplacementsMap;
@@ -47,6 +51,8 @@
 /// TranslationUnitReplacements.
 /// \param[out] TUs Collection of all found and deserialized
 /// TranslationUnitReplacements.
+/// \param[out] TURFiles Collection of all TranslationUnitReplacement files
+/// found in \c Directory.
 /// \param[in] Diagnostics DiagnosticsEngine used for error output.
 ///
 /// \returns An error_code indicating success or failure in navigating the
@@ -54,6 +60,7 @@
 llvm::error_code
 collectReplacementsFromDirectory(const llvm::StringRef Directory,
                                  TUReplacements &TUs,
+                                 TUReplacementFiles &TURFiles,
                                  clang::DiagnosticsEngine &Diagnostics);
 
 /// \brief Deduplicate, check for conflicts, and apply all Replacements stored
@@ -82,6 +89,17 @@
 bool applyReplacements(const FileToReplacementsMap &GroupedReplacements,
                        clang::SourceManager &SM);
 
+/// \brief Delete the replacement files.
+///
+/// \param[in] Files Replacement files to delete.
+/// \param[in] Diagnostics DiagnosticsEngine used for error output.
+///
+/// \returns \li true If all files have been deleted successfully.
+///          \li false If at least one or more failures occur when deleting
+/// files.
+bool deleteReplacementFiles(const TUReplacementFiles &Files,
+                            clang::DiagnosticsEngine &Diagnostics);
+
 } // end namespace replace
 } // end namespace clang
 
diff --git a/clang-tools-extra/clang-replace/tool/ClangReplaceMain.cpp b/clang-tools-extra/clang-replace/tool/ClangReplaceMain.cpp
index dae4652..bd6adca 100644
--- a/clang-tools-extra/clang-replace/tool/ClangReplaceMain.cpp
+++ b/clang-tools-extra/clang-replace/tool/ClangReplaceMain.cpp
@@ -25,6 +25,29 @@
 static cl::opt<std::string> Directory(cl::Positional, cl::Required,
                                       cl::desc("<Search Root Directory>"));
 
+static cl::opt<bool> RemoveTUReplacementFiles(
+    "remove-change-desc-files",
+    cl::desc("Remove the change description files regardless of successful\n"
+             "merging/replacing."),
+    cl::init(false));
+
+// Helper object to remove the TUReplacement files (triggered by
+// "remove-change-desc-files" command line option) when exiting current scope.
+class ScopedFileRemover {
+public:
+  ScopedFileRemover(const TUReplacementFiles &Files,
+                    clang::DiagnosticsEngine &Diagnostics)
+      : TURFiles(Files), Diag(Diagnostics) {}
+
+  ~ScopedFileRemover() {
+    deleteReplacementFiles(TURFiles, Diag);
+  }
+
+private:
+  const TUReplacementFiles &TURFiles;
+  clang::DiagnosticsEngine &Diag;
+};
+
 int main(int argc, char **argv) {
   cl::ParseCommandLineOptions(argc, argv);
 
@@ -34,9 +57,10 @@
       DiagOpts.getPtr());
 
   TUReplacements TUs;
+  TUReplacementFiles TURFiles;
 
   error_code ErrorCode =
-      collectReplacementsFromDirectory(Directory, TUs, Diagnostics);
+      collectReplacementsFromDirectory(Directory, TUs, TURFiles, Diagnostics);
 
   if (ErrorCode) {
     errs() << "Trouble iterating over directory '" << Directory
@@ -44,6 +68,12 @@
     return false;
   }
 
+  // Remove the TUReplacementFiles (triggered by "remove-change-desc-files"
+  // command line option) when exiting main().
+  OwningPtr<ScopedFileRemover> Remover;
+  if (RemoveTUReplacementFiles)
+    Remover.reset(new ScopedFileRemover(TURFiles, Diagnostics));
+
   FileManager Files((FileSystemOptions()));
   SourceManager SM(Diagnostics, Files);