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