Hi revane, arielbernal, tareqsiraj,

With this changes cpp11-migrate now supports reformatting the changes made by
the migration. The changes are reformatted according to a given style (a YAML
configuration file or a builtin style, one of: LLVM, Mozilla, Google, Chromium).

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

Files:
  cpp11-migrate/Core/CMakeLists.txt
  cpp11-migrate/Core/FileOverrides.cpp
  cpp11-migrate/Core/FileOverrides.h
  cpp11-migrate/tool/Cpp11Migrate.cpp
  cpp11-migrate/tool/Makefile
  docs/MigratorUsage.rst
  test/cpp11-migrate/Core/reformat.cpp
  unittests/cpp11-migrate/CMakeLists.txt
  unittests/cpp11-migrate/FileOverridesTest.cpp
  unittests/cpp11-migrate/Makefile
  unittests/cpp11-migrate/TransformTest.cpp
Index: cpp11-migrate/Core/CMakeLists.txt
===================================================================
--- cpp11-migrate/Core/CMakeLists.txt
+++ cpp11-migrate/Core/CMakeLists.txt
@@ -9,7 +9,9 @@
   PerfSupport.cpp
   )
 target_link_libraries(migrateCore
+  clangFormat
   clangTooling
   clangBasic
   clangASTMatchers
+  clangRewriteFrontend
   )
Index: cpp11-migrate/Core/FileOverrides.cpp
===================================================================
--- cpp11-migrate/Core/FileOverrides.cpp
+++ cpp11-migrate/Core/FileOverrides.cpp
@@ -29,8 +29,9 @@
 using namespace clang;
 using namespace clang::tooling;
 
-SourceOverrides::SourceOverrides(llvm::StringRef MainFileName)
-    : MainFileName(MainFileName) {}
+SourceOverrides::SourceOverrides(llvm::StringRef MainFileName,
+                                 bool TrackChanges)
+    : MainFileName(MainFileName), TrackChanges(TrackChanges) {}
 
 void SourceOverrides::applyReplacements(tooling::Replacements &Replaces) {
   llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagOpts(
@@ -57,6 +58,8 @@
     llvm::errs() << "error: failed to apply some replacements.";
 
   applyRewrites(Rewrites);
+  if (TrackChanges)
+    collectReplacementData(Replaces);
 }
 
 void SourceOverrides::applyRewrites(Rewriter &Rewrites) {
@@ -96,6 +99,56 @@
   }
 }
 
+namespace {
+
+/// \brief A functor owning a replacement, that says if a FileChangeRange is
+/// "eaten" by the given replacement.
+struct FileChangeRangeContain {
+  const tooling::Replacement &R;
+  FileChangeRangeContain(const tooling::Replacement &R) : R(R) {}
+
+  bool operator()(FileChangeRange D) const {
+    unsigned ReplacementEnd = R.getOffset() + R.getLength();
+    return D.getBegin() >= R.getOffset() && D.getEnd() <= ReplacementEnd;
+  }
+};
+
+} // end anonymous namespace
+
+void SourceOverrides::collectReplacementData(const Replacements &Replaces) {
+  // first remove ranges "eaten" by the replacements
+  for (Replacements::iterator I = Replaces.begin(), E = Replaces.end(); I != E;
+       ++I) {
+    const tooling::Replacement &R = *I;
+    FileChangeRanges &Ranges = FileChangesMap[R.getFilePath()];
+
+    Ranges.erase(
+        std::remove_if(Ranges.begin(), Ranges.end(), FileChangeRangeContain(R)),
+        Ranges.end());
+  }
+
+  // then shift old ranges
+  for (FileChangeRangesMap::iterator I = FileChangesMap.begin(),
+                                     E = FileChangesMap.end();
+       I != E; ++I) {
+    FileChangeRanges &Ranges = I->getValue();
+
+    for (FileChangeRanges::iterator I = Ranges.begin(), E = Ranges.end();
+         I != E; ++I)
+      I->Offset = tooling::shiftedCodePosition(Replaces, I->Offset);
+  }
+
+  // then generate the new ranges from the replacements
+  for (Replacements::iterator I = Replaces.begin(), E = Replaces.end(); I != E;
+       ++I) {
+    const tooling::Replacement &R = *I;
+    unsigned Offset = tooling::shiftedCodePosition(Replaces, R.getOffset());
+    unsigned Length = R.getReplacementText().size();
+
+    FileChangesMap[R.getFilePath()].push_back(FileChangeRange(Offset, Length));
+  }
+}
+
 void SourceOverrides::applyOverrides(SourceManager &SM) const {
   FileManager &FM = SM.getFileManager();
 
@@ -113,6 +166,59 @@
   }
 }
 
+void SourceOverrides::reformatChanges(const clang::format::FormatStyle &Style) {
+  llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagOpts(
+      new DiagnosticOptions());
+  DiagnosticsEngine Diagnostics(
+      llvm::IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()),
+      DiagOpts.getPtr());
+  FileManager Files((FileSystemOptions()));
+  SourceManager SM(Diagnostics, Files);
+
+  reformatChanges(Style, SM);
+}
+
+void SourceOverrides::reformatChanges(const clang::format::FormatStyle &Style,
+                                      clang::SourceManager &SM) {
+  assert(TrackChanges && "reformatChanges expects TrackChanges to be enabled");
+  applyOverrides(SM);
+  if (isSourceOverriden())
+    reformatFileChanges(MainFileName, Style, SM);
+
+  for (HeaderOverrides::const_iterator I = Headers.begin(), E = Headers.end();
+       I != E; ++I)
+    reformatFileChanges(I->second.FileName, Style, SM);
+}
+
+void SourceOverrides::reformatFileChanges(llvm::StringRef Filename,
+                                          const format::FormatStyle &Style,
+                                          SourceManager &SM) {
+  const clang::FileEntry *Entry = SM.getFileManager().getFile(Filename);
+  assert(Entry && "expected an existing file");
+
+  FileID ID = SM.translateFile(Entry);
+  if (ID.isInvalid())
+    ID = SM.createFileID(Entry, SourceLocation(), clang::SrcMgr::C_User);
+
+  Lexer Lex(ID, SM.getBuffer(ID), SM, getFormattingLangOpts(Style.Standard));
+
+  FileChangeRangesMap::iterator ChangesIt = FileChangesMap.find(Filename);
+  if (ChangesIt == FileChangesMap.end())
+    return;
+
+  std::vector<CharSourceRange> ReformatRanges;
+  FileChangeRanges &Ranges = ChangesIt->second;
+  SourceLocation StartOfFile = SM.getLocForStartOfFile(ID);
+  for (std::size_t I = 0, N = Ranges.size(); I < N; ++I) {
+    SourceLocation Start = StartOfFile.getLocWithOffset(Ranges[I].Offset);
+    SourceLocation End = Start.getLocWithOffset(Ranges[I].Length);
+    ReformatRanges.push_back(CharSourceRange::getCharRange(Start, End));
+  }
+
+  Replacements Replaces = format::reformat(Style, Lex, SM, ReformatRanges);
+  applyReplacements(Replaces, SM);
+}
+
 bool generateReplacementsFileName(llvm::StringRef SourceFile,
                                     llvm::StringRef HeaderFile,
                                     llvm::SmallVectorImpl<char> &Result,
@@ -154,6 +260,6 @@
   SourceOverrides *&Override = Overrides[Filename];
 
   if (Override == NULL)
-    Override = new SourceOverrides(Filename);
+    Override = new SourceOverrides(Filename, TrackChanges);
   return *Override;
 }
Index: cpp11-migrate/Core/FileOverrides.h
===================================================================
--- cpp11-migrate/Core/FileOverrides.h
+++ cpp11-migrate/Core/FileOverrides.h
@@ -27,8 +27,32 @@
 namespace clang {
 class SourceManager;
 class Rewriter;
+namespace format {
+struct FormatStyle;
+} // namespace format
 } // namespace clang
 
+/// \brief Container for storing the range of a file change.
+///
+// FIXME: clang::tooling::Range could be used if they were a bit more flexible
+// (e.g: offset and length reassignable)
+struct FileChangeRange {
+  unsigned Offset;
+  unsigned Length;
+
+  FileChangeRange(unsigned Offset, unsigned Length)
+      : Offset(Offset), Length(Length) {}
+
+  /// \brief Get the start position.
+  unsigned getBegin() const { return Offset; }
+
+  /// \brief Get the end position of the range (Offset + Length).
+  unsigned getEnd() const { return Offset + Length; }
+};
+
+/// \brief List of change ranges.
+typedef std::vector<FileChangeRange> FileChangeRanges;
+
 /// \brief Container for storing override information for a single headers.
 struct HeaderOverride {
   HeaderOverride() {}
@@ -45,13 +69,25 @@
 /// any headers included by the source file either directly or indirectly to
 /// which changes have been made.
 class SourceOverrides {
+  /// \brief Map filenames to the list of change ranges.
+  typedef llvm::StringMap<FileChangeRanges> FileChangeRangesMap;
+
 public:
-  SourceOverrides(llvm::StringRef MainFileName);
+  SourceOverrides(llvm::StringRef MainFileName, bool TrackChanges);
 
   /// \brief Accessors.
   /// @{
   llvm::StringRef getMainFileName() const { return MainFileName; }
   llvm::StringRef getMainFileContent() const { return MainFileOverride; }
+
+  /// \brief Is file change tracking enabled?
+  ///
+  /// It is necessary to track changes before calling \c reformatChanges().
+  /// Collecting the changes implies some \em heavy computations so it has been
+  /// made optional.
+  ///
+  /// Note that this value is set by the constructor.
+  bool isTrackingFileChanges() const { return TrackChanges; }
   /// @}
 
   /// \brief Indicates if the source file has been overridden.
@@ -66,12 +102,31 @@
   /// \param SM A user provided SourceManager to be used when applying rewrites.
   void applyReplacements(clang::tooling::Replacements &Replaces,
                          clang::SourceManager &SM);
+
+  /// \brief Overload of \c applyReplacements() providing it's own
+  /// \c SourceManager.
   void applyReplacements(clang::tooling::Replacements &Replaces);
 
   /// \brief Convenience function for applying this source's overrides to
   /// the given SourceManager.
   void applyOverrides(clang::SourceManager &SM) const;
 
+  /// \brief Reformat the changes made to the file and headers.
+  ///
+  /// \param Style \c clang::format::FormatStyle to apply when reformatting.
+  /// \param SM A SourceManager where the overridens files can be found.
+  ///
+  /// Note that file change tracking has to be enabled for the reformatting to
+  /// work.
+  ///
+  /// \sa \c isTrackingFileChanges()
+  void reformatChanges(const clang::format::FormatStyle &Style,
+                       clang::SourceManager &SM);
+
+  /// \brief Overload of \c reformatChanges() providing it's own
+  /// \c SourceManager.
+  void reformatChanges(const clang::format::FormatStyle &Style);
+
   /// \brief Iterators.
   /// @{
   HeaderOverrides::iterator headers_begin() { return Headers.begin(); }
@@ -87,18 +142,41 @@
   /// file content overrides.
   void applyRewrites(clang::Rewriter &Rewrite);
 
+  /// \brief Keep track of the replacements so that we can reformat the code
+  /// later on.
+  ///
+  /// For each replacement it will create a FileChangeRange covering the
+  /// location of the change. If a range covers some previously registered
+  /// ranges these ones are removed.
+  void collectReplacementData(const clang::tooling::Replacements &Replaces);
+
+  /// \brief Subroutine used by \c reformatChanges() that reformat only one
+  /// file.
+  void reformatFileChanges(llvm::StringRef Filename,
+                           const clang::format::FormatStyle &Style,
+                           clang::SourceManager &SM);
+
+private:
   const std::string MainFileName;
+  const bool TrackChanges;
   std::string MainFileOverride;
   HeaderOverrides Headers;
+  // map filenames (main file and headers) to the list of change ranges
+  FileChangeRangesMap FileChangesMap;
 };
 
 /// \brief Maps source file names to content override information.
 class FileOverrides {
 public:
   typedef llvm::StringMap<SourceOverrides *> SourceOverridesMap;
   typedef SourceOverridesMap::const_iterator const_iterator;
 
-  FileOverrides() {}
+public:
+  /// \brief Construct the SourceOverrides manager.
+  ///
+  /// \param TrackChanges Wether or not the \c SourceOverrides should keep track
+  /// of changes. See \c SourceOverrides::isTrackingFileChanges().
+  FileOverrides(bool TrackChanges) : TrackChanges(TrackChanges) {}
   ~FileOverrides();
 
   const_iterator find(llvm::StringRef Filename) const {
@@ -120,6 +198,7 @@
   FileOverrides &operator=(const FileOverrides &) LLVM_DELETED_FUNCTION;
 
   SourceOverridesMap Overrides;
+  const bool TrackChanges;
 };
 
 /// \brief Generate a unique filename to store the replacements.
Index: cpp11-migrate/tool/Cpp11Migrate.cpp
===================================================================
--- cpp11-migrate/tool/Cpp11Migrate.cpp
+++ cpp11-migrate/tool/Cpp11Migrate.cpp
@@ -25,9 +25,11 @@
 #include "UseAuto/UseAuto.h"
 #include "AddOverride/AddOverride.h"
 #include "ReplaceAutoPtr/ReplaceAutoPtr.h"
+#include "clang/Format/Format.h"
 #include "clang/Frontend/FrontendActions.h"
 #include "clang/Tooling/CommonOptionsParser.h"
 #include "clang/Tooling/Tooling.h"
+#include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/Signals.h"
 
 namespace cl = llvm::cl;
@@ -43,9 +45,9 @@
     "  cpp11-migrate -use-auto path/to/file.cpp -- -Ipath/to/include/\n"
     "\n"
     "Convert for loops to the new ranged-based for loops on all files in a "
-    "subtree:\n\n"
+    "subtree\nand reformat the code automatically using the LLVM style:\n\n"
     "  find path/in/subtree -name '*.cpp' -exec \\\n"
-    "    cpp11-migrate -p build/path -loop-convert {} ';'\n"
+    "    cpp11-migrate -p build/path -format-style=LLVM -loop-convert {} ';'\n"
     "\n"
     "Make use of both nullptr and the override specifier, using git ls-files:\n"
     "\n"
@@ -70,6 +72,14 @@
     cl::desc("Check for correct syntax after applying transformations"),
     cl::init(false));
 
+static cl::opt<std::string> FormatStyleOpt(
+    "format-style",
+    cl::desc("Coding style to use on the replacements, either a builtin style\n"
+             "or a YAML config file (see: clang-format -dump-config).\n"
+             "Currently supports 4 builtins style:\n"
+             "  LLVM, Google, Chromium, Mozilla.\n"),
+    cl::value_desc("string"));
+
 static cl::opt<bool>
 SummaryMode("summary", cl::desc("Print transform summary"),
             cl::init(false));
@@ -137,6 +147,31 @@
   // against the default value when the command line option is not specified.
   GlobalOptions.EnableTiming = (TimingDirectoryName != NoTiming);
 
+  // Check the reformatting style option
+  llvm::OwningPtr<format::FormatStyle> ReformattingStyle;
+  if (FormatStyleOpt.getNumOccurrences() > 0) {
+    ReformattingStyle.reset(new format::FormatStyle());
+
+    if (!format::getPredefinedStyle(FormatStyleOpt, ReformattingStyle.get())) {
+      llvm::StringRef ConfigFilePath = FormatStyleOpt;
+      llvm::OwningPtr<llvm::MemoryBuffer> Text;
+      llvm::error_code ec;
+
+      ec = llvm::MemoryBuffer::getFile(ConfigFilePath, Text);
+      if (!ec)
+        ec = parseConfiguration(Text->getBuffer(), ReformattingStyle.get());
+
+      if (ec) {
+        llvm::errs() << argv[0] << ": invalid format style " << FormatStyleOpt
+                     << ": " << ec.message() << "\n";
+        return 1;
+      }
+    }
+
+    // force mode to C++11
+    ReformattingStyle->Standard = clang::format::FormatStyle::LS_Cpp11;
+  }
+
   // Populate the ModifiableHeaders structure if header modifications are
   // enabled.
   if (GlobalOptions.EnableHeaderModifications) {
@@ -153,7 +188,10 @@
     return 1;
   }
 
-  FileOverrides FileStates;
+  // if reformatting is enabled we wants to track file changes so that it's
+  // possible to reformat them.
+  bool TrackReplacements = static_cast<bool>(ReformattingStyle);
+  FileOverrides FileStates(TrackReplacements);
   SourcePerfData PerfData;
 
   // Apply transforms.
@@ -183,6 +221,14 @@
     }
   }
 
+  if (ReformattingStyle)
+    for (FileOverrides::const_iterator I = FileStates.begin(),
+                                       E = FileStates.end();
+         I != E; ++I) {
+      SourceOverrides &FileState = *I->second;
+      FileState.reformatChanges(*ReformattingStyle);
+    }
+
   if (FinalSyntaxCheck)
     if (!doSyntaxCheck(OptionsParser.getCompilations(),
                        OptionsParser.getSourcePathList(), FileStates))
Index: cpp11-migrate/tool/Makefile
===================================================================
--- cpp11-migrate/tool/Makefile
+++ cpp11-migrate/tool/Makefile
@@ -34,10 +34,10 @@
 BUILT_SOURCES += $(ObjDir)/../ReplaceAutoPtr/.objdir
 
 LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc mcparser option
-USEDLIBS = migrateCore.a clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \
-		   clangRewriteFrontend.a clangRewriteCore.a clangParse.a \
-		   clangSema.a clangAnalysis.a \
-		   clangAST.a clangASTMatchers.a clangEdit.a clangLex.a clangBasic.a
+USEDLIBS = migrateCore.a clangFormat.a clangTooling.a clangFrontend.a \
+	   clangSerialization.a clangDriver.a clangRewriteFrontend.a \
+	   clangRewriteCore.a clangParse.a clangSema.a clangAnalysis.a \
+	   clangAST.a clangASTMatchers.a clangEdit.a clangLex.a clangBasic.a
 
 include $(CLANG_LEVEL)/Makefile
 
Index: docs/MigratorUsage.rst
===================================================================
--- docs/MigratorUsage.rst
+++ docs/MigratorUsage.rst
@@ -66,6 +66,37 @@
   earlier transforms are already caught when subsequent transforms parse the
   file.
 
+.. option:: -format-style=<string>
+
+  After all transformations have been applied it's possible to reformat the
+  changes using this option. The ``string`` arguments can be either a builtin
+  style, one of: LLVM, Google, Chromium, Mozilla or a YAML configuration file.
+  ClangFormat_ can generates the configuration file for with ``clang-format
+  -dump-config``.
+
+  Reformatting example using the builtin LLVM style:
+
+  ``cpp11-migrate -format-style=LLVM -use-auto reformat-example.cpp --``
+  
+  .. code-block:: c++
+    :emphasize-lines: 6-8
+
+     #include <string>
+     #include <map>
+
+     struct MapDumper {
+       void dump(const std::map<std::string, std::string> &MyMap) {
+    -    std::map<std::string, std::string>::const_reverse_iterator I =
+    -        MyMap.rbegin();
+    +    auto I = MyMap.rbegin();
+
+         // <...>
+       }
+     };
+
+
+.. _ClangFormat: http://clang.llvm.org/docs/ClangFormat.html
+
 .. option:: -summary
 
   Displays a summary of the number of changes each transform made or could have
Index: test/cpp11-migrate/Core/reformat.cpp
===================================================================
--- /dev/null
+++ test/cpp11-migrate/Core/reformat.cpp
@@ -0,0 +1,47 @@
+// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
+// RUN: not cpp11-migrate -format-style=FOO -use-auto %t.cpp -- -std=c++11
+// RUN: not cpp11-migrate -format-style=/tmp/ -use-auto %t.cpp -- -std=c++11
+// RUN: cpp11-migrate -format-style=LLVM -replace-auto_ptr -loop-convert \
+// RUN:                                  -use-auto -use-nullptr %t.cpp -- \
+// RUN:                                  -std=c++11
+// RUN: FileCheck --strict-whitespace -input-file=%t.cpp %s
+
+#include <iostream>
+#include <memory>
+#include <vector>
+
+void take_auto_ptrs(std::auto_ptr<int>, std::auto_ptr<int>);
+
+// Test with one transform, auto_ptr replacement.
+void f_1() {
+  std::auto_ptr<int> aaaaaaaa;
+  std::auto_ptr<int> bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;
+  // CHECK: std::unique_ptr<int> aaaaaaaa;
+  // CHECK-NEXT: std::unique_ptr<int>
+  // CHECK-NEXT: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;
+
+  aaaaaaaa = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;
+  // CHECK: aaaaaaaa =
+  // CHECK-Next:     std::move(bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb);
+
+  std::auto_ptr<int> cccccccccccccccccccccccccccc, dddddddddddddddddddddddddddd;
+  // CHECK: std::unique_ptr<int> cccccccccccccccccccccccccccc,
+  // CHECK-NEXT:     dddddddddddddddddddddddddddd;
+
+  take_auto_ptrs(cccccccccccccccccccccccccccc, dddddddddddddddddddddddddddd);
+  // CHECK: take_auto_ptrs(std::move(cccccccccccccccccccccccccccc),
+  // CHECK-NEXT:                std::move(dddddddddddddddddddddddddddd));
+}
+
+// Test combined modifications, when the same part of code has been modified by
+// more than one transform.
+void f_2(const std::vector<int> &Vect) {
+  // In this case:
+  // - the for loop is modified to a for-range based loop
+  // - the const_iterator type is replaced by auto
+  for (std::vector<int>::const_iterator I = Vect.begin(), E = Vect.end();
+       I != E; ++I)
+    std::cout << *I << std::endl;
+  // CHECK: for (auto const &elem : Vect)
+  // CHECK-NEXT:   std::cout << elem << std::endl;
+}
Index: unittests/cpp11-migrate/CMakeLists.txt
===================================================================
--- unittests/cpp11-migrate/CMakeLists.txt
+++ unittests/cpp11-migrate/CMakeLists.txt
@@ -16,7 +16,9 @@
 
 target_link_libraries(Cpp11MigrateTests
   migrateCore
+  clangFormat
   clangTooling
   clangBasic
   clangASTMatchers
+  clangRewriteFrontend
   )
Index: unittests/cpp11-migrate/FileOverridesTest.cpp
===================================================================
--- unittests/cpp11-migrate/FileOverridesTest.cpp
+++ unittests/cpp11-migrate/FileOverridesTest.cpp
@@ -13,44 +13,121 @@
 #include "clang/Basic/DiagnosticOptions.h"
 #include "clang/Basic/FileManager.h"
 #include "clang/Basic/SourceManager.h"
+#include "clang/Format/Format.h"
 
 using namespace llvm;
 using namespace clang;
 
-TEST(SourceOverridesTest, Interface) {
-  llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagOpts(
-      new DiagnosticOptions());
-  DiagnosticsEngine Diagnostics(
-      llvm::IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()),
-      DiagOpts.getPtr());
-  FileManager Files((FileSystemOptions()));
-  SourceManager SM(Diagnostics, Files);
-  StringRef FileName = "<text>";
-  StringRef Code =
-      "std::vector<such_a_long_name_for_a_type>::const_iterator long_type =\n"
-      "    vec.begin();\n"
-      "int   x;"; // to test that it's not the whole file that is reformatted
-  llvm::MemoryBuffer *Buf = llvm::MemoryBuffer::getMemBuffer(Code, FileName);
-  const clang::FileEntry *Entry =
-      Files.getVirtualFile(FileName, Buf->getBufferSize(), 0);
-  SM.overrideFileContents(Entry, Buf);
+// Test fixture object that setup some files once for all test cases and remove
+// them when the tests are done.
+class SourceOverridesTest : public ::testing::Test {
+protected:
+  static void SetUpTestCase() {
+    DiagOpts =
+        new IntrusiveRefCntPtr<DiagnosticOptions>(new DiagnosticOptions());
+    Diagnostics = new DiagnosticsEngine(
+        IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()),
+        DiagOpts->getPtr());
+  }
+
+  static void TearDownTestCase() {
+    delete DiagOpts;
+    delete Diagnostics;
+  }
+
+  virtual void SetUp() {
+    Files = new FileManager(FileSystemOptions());
+    Sources = NULL;
+    FileName = NULL;
+    Code = NULL;
+  }
+
+  void setFilename(const char *F) { FileName = F; }
+  void setCode(const char *C) { Code = C; }
+
+  virtual void TearDown() {
+    delete Files;
+    delete Sources;
+  }
 
-  SourceOverrides Overrides(FileName);
+  // Creates a new SourceManager with the virtual file and content
+  SourceManager &getNewSourceManager() {
+    assert(FileName && Code && "expected Code and FileName to be set.");
+    delete Sources;
+    Sources = new SourceManager(*Diagnostics, *Files);
+    MemoryBuffer *Buf = MemoryBuffer::getMemBuffer(Code, FileName);
+    const FileEntry *Entry = Files->getVirtualFile(
+        FileName, Buf->getBufferSize(), /*ModificationTime=*/0);
+    Sources->overrideFileContents(Entry, Buf);
+    return *Sources;
+  }
+
+  static SourceManager *Sources;
+  static const char *FileName;
+  static const char *Code;
+
+private:
+  static IntrusiveRefCntPtr<DiagnosticOptions> *DiagOpts;
+  static DiagnosticsEngine *Diagnostics;
+  static FileManager *Files;
+};
+
+IntrusiveRefCntPtr<DiagnosticOptions> *SourceOverridesTest::DiagOpts = NULL;
+DiagnosticsEngine *SourceOverridesTest::Diagnostics = NULL;
+FileManager *SourceOverridesTest::Files = NULL;
+SourceManager *SourceOverridesTest::Sources = NULL;
+const char *SourceOverridesTest::FileName;
+const char *SourceOverridesTest::Code;
+
+TEST_F(SourceOverridesTest, Interface) {
+  setFilename("<test-file>");
+  setCode(
+      "std::vector<such_a_long_name_for_a_type>::const_iterator long_type =\n"
+      "    vec.begin();\n");
+  SourceOverrides Overrides(FileName, /*TrackFileChanges=*/false);
 
   EXPECT_EQ(FileName, Overrides.getMainFileName());
   EXPECT_FALSE(Overrides.isSourceOverriden());
+  EXPECT_FALSE(Overrides.isTrackingFileChanges());
 
   tooling::Replacements Replaces;
   unsigned ReplacementLength =
       strlen("std::vector<such_a_long_name_for_a_type>::const_iterator");
-  Replaces.insert(
-      tooling::Replacement(FileName, 0, ReplacementLength, "auto"));
-  Overrides.applyReplacements(Replaces, SM);
+  Replaces.insert(tooling::Replacement(FileName, 0, ReplacementLength, "auto"));
+  Overrides.applyReplacements(Replaces, getNewSourceManager());
   EXPECT_TRUE(Overrides.isSourceOverriden());
 
   std::string ExpectedContent = "auto long_type =\n"
-                                "    vec.begin();\n"
-                                "int   x;";
+                                "    vec.begin();\n";
 
   EXPECT_EQ(ExpectedContent, Overrides.getMainFileContent());
 }
+
+TEST_F(SourceOverridesTest, reformatChanges) {
+  setFilename("<test-file>");
+  // 'int   foo;' tests that we don't reformat more code than needed
+  setCode(
+      "std::vector<such_a_long_name_for_a_type>::const_iterator long_type =\n"
+      "    vec.begin();\n"
+      "int   foo;\n");
+  SourceOverrides Overrides(FileName, /*TrackFileChanges=*/true);
+
+  EXPECT_TRUE(Overrides.isTrackingFileChanges());
+  tooling::Replacements Replaces;
+  unsigned ReplacementLength =
+      strlen("std::vector<such_a_long_name_for_a_type>::const_iterator");
+  Replaces.insert(tooling::Replacement(FileName, 0, ReplacementLength, "auto"));
+  Overrides.applyReplacements(Replaces, getNewSourceManager());
+
+  std::string BeforeReformatContent = "auto long_type =\n"
+                                      "    vec.begin();\n"
+                                      "int   foo;\n";
+  EXPECT_EQ(BeforeReformatContent, Overrides.getMainFileContent());
+
+  format::FormatStyle Style = format::getLLVMStyle();
+  std::string AfterReformatContent = "auto long_type = vec.begin();\n"
+                                     "int   foo;\n";
+
+  Overrides.reformatChanges(Style, getNewSourceManager());
+  EXPECT_EQ(AfterReformatContent, Overrides.getMainFileContent());
+}
Index: unittests/cpp11-migrate/Makefile
===================================================================
--- unittests/cpp11-migrate/Makefile
+++ unittests/cpp11-migrate/Makefile
@@ -12,10 +12,10 @@
 
 TESTNAME = Cpp11MigrateTests
 LINK_COMPONENTS := asmparser bitreader support MC MCParser option
-USEDLIBS = migrateCore.a clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \
-		   clangRewriteFrontend.a clangRewriteCore.a clangParse.a \
-		   clangSema.a clangAnalysis.a \
-		   clangAST.a clangASTMatchers.a clangEdit.a clangLex.a clangBasic.a
+USEDLIBS = migrateCore.a clangFormat.a clangTooling.a clangFrontend.a \
+	   clangSerialization.a clangDriver.a clangRewriteFrontend.a \
+	   clangRewriteCore.a clangParse.a clangSema.a clangAnalysis.a \
+	   clangAST.a clangASTMatchers.a clangEdit.a clangLex.a clangBasic.a
 
 include $(CLANG_LEVEL)/Makefile
 MAKEFILE_UNITTEST_NO_INCLUDE_COMMON := 1
Index: unittests/cpp11-migrate/TransformTest.cpp
===================================================================
--- unittests/cpp11-migrate/TransformTest.cpp
+++ unittests/cpp11-migrate/TransformTest.cpp
@@ -161,7 +161,7 @@
 
   // Transform's handle* functions require FileOverrides to be set, even if
   // there aren't any.
-  FileOverrides Overrides;
+  FileOverrides Overrides(/*TrackFileChanges=*/false);
   T.setOverrides(Overrides);
 
   Tool.run(clang::tooling::newFrontendActionFactory(&Factory, &Callbacks));
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to