- Addressed reviewer nits

Hi klimek,

http://llvm-reviews.chandlerc.com/D288

CHANGE SINCE LAST DIFF
  http://llvm-reviews.chandlerc.com/D288?vs=691&id=710#toc

Files:
  cpp11-migrate/CMakeLists.txt
  cpp11-migrate/Cpp11Migrate.cpp
  cpp11-migrate/LoopConvert/LoopConvert.cpp
  cpp11-migrate/LoopConvert/LoopConvert.h
  cpp11-migrate/Makefile
  cpp11-migrate/Transform.cpp
  cpp11-migrate/Transform.h
Index: cpp11-migrate/CMakeLists.txt
===================================================================
--- cpp11-migrate/CMakeLists.txt
+++ cpp11-migrate/CMakeLists.txt
@@ -5,6 +5,7 @@
 set (Cpp11MigrateSources
   Cpp11Migrate.cpp
   Transforms.cpp
+  Transform.cpp
   )
 
 # For each transform subdirectory.
Index: cpp11-migrate/Cpp11Migrate.cpp
===================================================================
--- cpp11-migrate/Cpp11Migrate.cpp
+++ cpp11-migrate/Cpp11Migrate.cpp
@@ -27,27 +27,26 @@
 ///
 //===----------------------------------------------------------------------===//
 
+#include "Transforms.h"
+#include "Transform.h"
 #include "clang/Frontend/FrontendActions.h"
 #include "clang/Tooling/CommonOptionsParser.h"
 #include "clang/Tooling/Tooling.h"
-#include "Transforms.h"
-#include "Transform.h"
 
 namespace cl = llvm::cl;
 using namespace clang::tooling;
 
-static cl::opt<RiskLevel>
-MaxRiskLevel("risk", cl::desc("Select a maximum risk level:"),
-             cl::values(
-               clEnumValN(RL_Safe, "safe", "Only safe transformations"),
-                 clEnumValN(RL_Reasonable, "reasonable",
-                           "Enable transformations that might change "
-                           "semantics (default)"),
-                 clEnumValN(RL_Risky, "risky",
-                           "Enable transformations that are likely to "
-                           "change semantics"),
+static cl::opt<RiskLevel> MaxRiskLevel(
+    "risk", cl::desc("Select a maximum risk level:"),
+    cl::values(clEnumValN(RL_Safe, "safe", "Only safe transformations"),
+               clEnumValN(RL_Reasonable, "reasonable",
+                          "Enable transformations that might change "
+                          "semantics (default)"),
+               clEnumValN(RL_Risky, "risky",
+                          "Enable transformations that are likely to "
+                          "change semantics"),
                clEnumValEnd),
-             cl::init(RL_Reasonable));
+    cl::init(RL_Reasonable));
 
 int main(int argc, const char **argv) {
   Transforms TransformManager;
@@ -74,23 +73,53 @@
     return 1;
   }
 
+  unsigned int NumFiles = OptionsParser.getSourcePathList().size();
+
+  FileContentsByPath FileStates1, FileStates2,
+      *InputFileStates = &FileStates1, *OutputFileStates = &FileStates2;
+  FileStates1.reserve(NumFiles);
+  FileStates2.reserve(NumFiles);
+
   // Apply transforms.
   for (Transforms::const_iterator I = TransformManager.begin(),
-       E = TransformManager.end(); I != E; ++I) {
-    if ((*I)->apply(MaxRiskLevel, OptionsParser.getCompilations(),
-                    OptionsParser.getSourcePathList()) != 0) {
+                                  E = TransformManager.end();
+       I != E; ++I) {
+    if ((*I)->apply(*InputFileStates, MaxRiskLevel,
+                    OptionsParser.getCompilations(),
+                    OptionsParser.getSourcePathList(), *OutputFileStates) !=
+        0) {
+      // FIXME: Improve ClangTool to not abort if just one file fails.
       return 1;
     }
+    std::swap(InputFileStates, OutputFileStates);
+    OutputFileStates->clear();
   }
 
+  // Final state of files is pointed at by InputFileStates.
+
   // Final Syntax check.
   ClangTool EndSyntaxTool(OptionsParser.getCompilations(),
                           OptionsParser.getSourcePathList());
-  if (EndSyntaxTool.run(
-        newFrontendActionFactory<clang::SyntaxOnlyAction>()) != 0) {
-    // FIXME: Revert changes made to files that fail the syntax test.
+  for (FileContentsByPath::const_iterator I = InputFileStates->begin(),
+                                          E = InputFileStates->end();
+       I != E; ++I) {
+    EndSyntaxTool.mapVirtualFile(I->first, I->second);
+  }
+
+  if (EndSyntaxTool.run(newFrontendActionFactory<clang::SyntaxOnlyAction>()) !=
+      0) {
     return 1;
   }
 
+  // Syntax check passed, write results to file.
+  for (FileContentsByPath::const_iterator I = InputFileStates->begin(),
+                                          E = InputFileStates->end();
+       I != E; ++I) {
+    std::string ErrorInfo;
+    llvm::raw_fd_ostream FileStream(I->first.c_str(), ErrorInfo,
+                                    llvm::raw_fd_ostream::F_Binary);
+    FileStream << I->second;
+  }
+
   return 0;
 }
Index: cpp11-migrate/LoopConvert/LoopConvert.cpp
===================================================================
--- cpp11-migrate/LoopConvert/LoopConvert.cpp
+++ cpp11-migrate/LoopConvert/LoopConvert.cpp
@@ -19,15 +19,25 @@
 #include "clang/Frontend/FrontendActions.h"
 #include "clang/Tooling/Refactoring.h"
 #include "clang/Tooling/Tooling.h"
+#include "clang/Rewrite/Core/Rewriter.h"
 
 using clang::ast_matchers::MatchFinder;
 using namespace clang::tooling;
 using namespace clang;
 
-int LoopConvertTransform::apply(RiskLevel MaxRisk,
+int LoopConvertTransform::apply(const FileContentsByPath &InputStates,
+                                RiskLevel MaxRisk,
                                 const CompilationDatabase &Database,
-                                const std::vector<std::string> &SourcePaths) {
+                                const std::vector<std::string> &SourcePaths,
+                                FileContentsByPath &ResultStates) {
   RefactoringTool LoopTool(Database, SourcePaths);
+
+  for (FileContentsByPath::const_iterator I = InputStates.begin(),
+       E = InputStates.end();
+       I != E; ++I) {
+    LoopTool.mapVirtualFile(I->first, I->second);
+  }
+
   StmtAncestorASTVisitor ParentFinder;
   StmtGeneratedVarNameMap GeneratedDecls;
   ReplacedVarsMap ReplacedVars;
@@ -53,11 +63,19 @@
                                   &RejectedChanges,
                                   MaxRisk, LFK_PseudoArray);
   Finder.addMatcher(makePseudoArrayLoopMatcher(), &PseudoarrrayLoopFixer);
-  if (int result = LoopTool.runAndSave(newFrontendActionFactory(&Finder))) {
+
+  if (int result = LoopTool.run(newFrontendActionFactory(&Finder))) {
     llvm::errs() << "Error encountered during translation.\n";
     return result;
   }
 
+  RewriterContainer Rewrite(LoopTool.getFiles());
+
+  // FIXME: Do something if some replacements didn't get applied?
+  LoopTool.applyAllReplacements(Rewrite.getRewriter());
+
+  collectResults(Rewrite.getRewriter(), ResultStates);
+
   if (AcceptedChanges > 0) {
     setChangesMade();
   }
Index: cpp11-migrate/LoopConvert/LoopConvert.h
===================================================================
--- cpp11-migrate/LoopConvert/LoopConvert.h
+++ cpp11-migrate/LoopConvert/LoopConvert.h
@@ -17,13 +17,19 @@
 #define LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_LOOP_CONVERT_H
 
 #include "Transform.h"
+#include "llvm/Support/Compiler.h" // For LLVM_OVERRIDE
 
+/// \brief Subclass of Transform that transforms for-loops into range-based
+/// for-loops where possible.
 class LoopConvertTransform : public Transform {
 public:
 
-  virtual int apply(RiskLevel MaxRiskLEvel,
+  /// \brief \see Transform::run().
+  virtual int apply(const FileContentsByPath &InputStates,
+                    RiskLevel MaxRiskLevel,
                     const clang::tooling::CompilationDatabase &Database,
-                    const std::vector<std::string> &SourcePaths) LLVM_OVERRIDE;
+                    const std::vector<std::string> &SourcePaths,
+                    FileContentsByPath &ResultStates) LLVM_OVERRIDE;
 };
 
 #endif // LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_LOOP_CONVERT_H
Index: cpp11-migrate/Makefile
===================================================================
--- cpp11-migrate/Makefile
+++ cpp11-migrate/Makefile
@@ -17,7 +17,7 @@
 
 include $(CLANG_LEVEL)/../../Makefile.config
 
-SOURCES = Cpp11Migrate.cpp Transforms.cpp
+SOURCES = Cpp11Migrate.cpp Transforms.cpp Transform.cpp
 
 # For each Transform subdirectory add to SOURCES and BUILT_SOURCES.
 # BUILT_SOURCES ensures a subdirectory is created to house object files from
Index: cpp11-migrate/Transform.cpp
===================================================================
--- /dev/null
+++ cpp11-migrate/Transform.cpp
@@ -0,0 +1,35 @@
+#include "Transform.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+
+void collectResults(clang::Rewriter &Rewrite,
+                    FileContentsByPath &Results) {
+  for (Rewriter::buffer_iterator I = Rewrite.buffer_begin(),
+                                 E = Rewrite.buffer_end();
+       I != E; ++I) {
+    const FileEntry *Entry = Rewrite.getSourceMgr().getFileEntryForID(I->first);
+    assert(Entry != 0 && "Expected a FileEntry");
+    assert(Entry->getName() != 0 &&
+           "Unexpected NULL return from FileEntry::getName()");
+
+    FileContentsByPath::value_type ResultEntry;
+
+    ResultEntry.first = Entry->getName();
+
+    // Get a copy of the rewritten buffer from the Rewriter.
+    llvm::raw_string_ostream StringStream(ResultEntry.second);
+    I->second.write(StringStream);
+
+    // Cause results to be written to ResultEntry.second.
+    StringStream.str();
+
+    // FIXME: Use move semantics to avoid copies of the buffer contents if
+    // benchmarking shows the copies are expensive, especially for large source
+    // files.
+    Results.push_back(ResultEntry);
+  }
+}
Index: cpp11-migrate/Transform.h
===================================================================
--- cpp11-migrate/Transform.h
+++ cpp11-migrate/Transform.h
@@ -15,8 +15,18 @@
 #ifndef LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_TRANSFORM_H
 #define LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_TRANSFORM_H
 
-#include "clang/Tooling/CompilationDatabase.h"
 #include <vector>
+#include <string>
+
+// For RewriterContainer
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/Support/raw_ostream.h"
+////
+
 
 /// \brief Description of the riskiness of actions that can be taken by
 /// transforms.
@@ -31,13 +41,56 @@
   RL_Risky
 };
 
-// Forward Declarations
+// Forward declarations
 namespace clang {
 namespace tooling {
 class CompilationDatabase;
 } // namespace tooling
 } // namespace clang
 
+/// \brief First item in the pair is the path of a file and the second is a
+/// buffer with the possibly modified contents of that file.
+typedef std::vector<std::pair<std::string, std::string> > FileContentsByPath;
+
+/// \brief In \p Results place copies of the buffers resulting from applying
+/// all rewrites represented by \p Rewrite.
+///
+/// \p Results is made up of pairs {filename, buffer contents}. Pairs are
+/// simply appended to \p Results.
+void collectResults(clang::Rewriter &Rewrite, FileContentsByPath &Results);
+
+/// \brief Class for containing a Rewriter instance and all of
+/// its lifetime dependencies.
+///
+/// Subclasses of Transform using RefactoringTools will need to create
+/// Rewriters in order to apply Replacements and get the resulting buffer.
+/// Rewriter requires some objects to exist at least as long as it does so this
+/// class contains instances of those objects.
+///
+/// FIXME: These objects should really come from somewhere more global instead
+/// of being recreated for every Transform subclass, especially diagnostics.
+class RewriterContainer {
+public:
+  RewriterContainer(clang::FileManager &Files)
+    : DiagOpts(new clang::DiagnosticOptions()),
+      DiagnosticPrinter(llvm::errs(), DiagOpts.getPtr()),
+      Diagnostics(llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs>(
+                    new clang::DiagnosticIDs()),
+                  DiagOpts.getPtr(), &DiagnosticPrinter, false),
+      Sources(Diagnostics, Files),
+      Rewrite(Sources, DefaultLangOptions) {}
+
+  clang::Rewriter &getRewriter() { return Rewrite; }
+
+private:
+  clang::LangOptions DefaultLangOptions;
+  llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagOpts;
+  clang::TextDiagnosticPrinter DiagnosticPrinter;
+  clang::DiagnosticsEngine Diagnostics;
+  clang::SourceManager Sources;
+  clang::Rewriter Rewrite;
+};
+
 /// \brief Abstract base class for all C++11 migration transforms.
 class Transform {
 public:
@@ -49,11 +102,16 @@
 
   /// \brief Apply a transform to all files listed in \p SourcePaths.
   ///
-  /// \p Database must contain information for how to compile all files in
-  /// \p SourcePaths.
-  virtual int apply(RiskLevel MaxRiskLevel,
+  /// \p Database must contain information for how to compile all files in \p
+  /// SourcePaths. \p InputStates contains the file contents of files in \p
+  /// SourcePaths and should take precedence over content of files on disk.
+  /// Upon return, \p ResultStates shall contain the result of performing this
+  /// transform on the files listed in \p SourcePaths.
+  virtual int apply(const FileContentsByPath &InputStates,
+                    RiskLevel MaxRiskLevel,
                     const clang::tooling::CompilationDatabase &Database,
-                    const std::vector<std::string> &SourcePaths) = 0;
+                    const std::vector<std::string> &SourcePaths,
+                    FileContentsByPath &ResultStates) = 0;
 
   /// \brief Query if changes were made during the last call to apply().
   bool getChangesMade() const { return ChangesMade; }
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to