ioeric updated this revision to Diff 71116.
ioeric marked 13 inline comments as done.
ioeric added a comment.
Herald added a subscriber: mgorny.

- Addressed review comments.
- Separate getAffectedFiles into its own interface.


https://reviews.llvm.org/D24380

Files:
  CMakeLists.txt
  migrate-tool/AffectedFilesFinder.h
  migrate-tool/BuildManager.h
  migrate-tool/CMakeLists.txt
  migrate-tool/HeaderGenerator.cpp
  migrate-tool/HeaderGenerator.h
  migrate-tool/MigrateTool.cpp
  migrate-tool/MigrateTool.h
  migrate-tool/RefactoringManager.h
  unittests/CMakeLists.txt
  unittests/migrate-tool/CMakeLists.txt
  unittests/migrate-tool/HeaderBuildTest.cpp

Index: unittests/migrate-tool/HeaderBuildTest.cpp
===================================================================
--- /dev/null
+++ unittests/migrate-tool/HeaderBuildTest.cpp
@@ -0,0 +1,100 @@
+//===-- HeaderGeneratorTest.cpp - HeaderGenerator unit tests ----------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "HeaderGenerator.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace migrate_tool {
+
+TEST(HeaderGenerator, Empty) {
+  HeaderGenerator Hdr("a.h");
+  std::string Expected = "#ifndef A_H\n"
+                         "#define A_H\n"
+                         "\n"
+                         "#endif // A_H";
+  EXPECT_EQ(Expected, Hdr.generateContent());
+}
+
+TEST(HeaderGenerator, SingleAlias) {
+  HeaderGenerator Hdr("a/b/c.h");
+  Hdr.addAlias("na::nb::C", "x::y::Z");
+  std::string Expected = "#ifndef A_B_C_H\n"
+                         "#define A_B_C_H\n"
+                         "namespace na {\n"
+                         "namespace nb {\n"
+                         "using C = ::x::y::Z;\n"
+                         "} // namespace nb\n"
+                         "} // namespace na\n"
+                         "#endif // A_B_C_H";
+  EXPECT_EQ(Expected, Hdr.generateContent());
+}
+
+TEST(HeaderGenerator, SingleAliasWithIncludes) {
+  HeaderGenerator Hdr("a/b/c.h");
+  Hdr.addInclude("x/y/z.h");
+  Hdr.addInclude("x/y/zz.h");
+  Hdr.addAlias("na::nb::C", "x::y::Z");
+  std::string Expected = "#ifndef A_B_C_H\n"
+                         "#define A_B_C_H\n"
+                         "#include \"x/y/z.h\"\n"
+                         "#include \"x/y/zz.h\"\n"
+                         "namespace na {\n"
+                         "namespace nb {\n"
+                         "using C = ::x::y::Z;\n"
+                         "} // namespace nb\n"
+                         "} // namespace na\n"
+                         "#endif // A_B_C_H";
+  EXPECT_EQ(Expected, Hdr.generateContent());
+}
+
+TEST(HeaderGenerator, MultipleAliasInOneNamespace) {
+  HeaderGenerator Hdr("a/b/c.h");
+  Hdr.addAlias("na::nb::C", "x::y::Z");
+  Hdr.addAlias("na::nb::D", "x::y::D");
+  Hdr.addAlias("na::nb::Q", "x::y::Q");
+  std::string Expected = "#ifndef A_B_C_H\n"
+                         "#define A_B_C_H\n"
+                         "namespace na {\n"
+                         "namespace nb {\n"
+                         "using C = ::x::y::Z;\n"
+                         "using D = ::x::y::D;\n"
+                         "using Q = ::x::y::Q;\n"
+                         "} // namespace nb\n"
+                         "} // namespace na\n"
+                         "#endif // A_B_C_H";
+  EXPECT_EQ(Expected, Hdr.generateContent());
+}
+
+TEST(HeaderGenerator, AliasesInMultipleNamespace) {
+  HeaderGenerator Hdr("a/b/c.h");
+  Hdr.addAlias("nb::Q", "x::Q");
+  Hdr.addAlias("na::nb::C", "x::y::Z");
+  Hdr.addAlias("na::nc::D", "x::y::D");
+  Hdr.addAlias("na::nb::Q", "x::y::Q");
+  std::string Expected = "#ifndef A_B_C_H\n"
+                         "#define A_B_C_H\n"
+                         "namespace nb {\n"
+                         "using Q = ::x::Q;\n"
+                         "} // namespace nb\n"
+                         "namespace na {\n"
+                         "namespace nb {\n"
+                         "using C = ::x::y::Z;\n"
+                         "using Q = ::x::y::Q;\n"
+                         "} // namespace nb\n"
+                         "namespace nc {\n"
+                         "using D = ::x::y::D;\n"
+                         "} // namespace nc\n"
+                         "} // namespace na\n"
+                         "#endif // A_B_C_H";
+  EXPECT_EQ(Expected, Hdr.generateContent());
+}
+
+} // namespace migrate_tool
+} // namespace clang
Index: unittests/migrate-tool/CMakeLists.txt
===================================================================
--- /dev/null
+++ unittests/migrate-tool/CMakeLists.txt
@@ -0,0 +1,25 @@
+set(LLVM_LINK_COMPONENTS
+  support
+  )
+
+get_filename_component(MIGRATE_TOOL_SOURCE_DIR
+  ${CMAKE_CURRENT_SOURCE_DIR}/../../migrate-tool REALPATH)
+include_directories(
+  ${MIGRATE_TOOL_SOURCE_DIR}
+  )
+
+# We'd like to clang/unittests/Tooling/RewriterTestContext.h in the test.
+include_directories(${CLANG_SOURCE_DIR})
+
+add_extra_unittest(MigrateToolTests
+  HeaderBuildTest.cpp
+  )
+
+target_link_libraries(MigrateToolTests
+  migrateTool
+  clangBasic
+  clangFormat
+  clangRewrite
+  clangTooling
+  clangToolingCore
+  )
Index: unittests/CMakeLists.txt
===================================================================
--- unittests/CMakeLists.txt
+++ unittests/CMakeLists.txt
@@ -10,3 +10,4 @@
 add_subdirectory(clang-query)
 add_subdirectory(clang-tidy)
 add_subdirectory(include-fixer)
+add_subdirectory(migrate-tool)
Index: migrate-tool/RefactoringManager.h
===================================================================
--- /dev/null
+++ migrate-tool/RefactoringManager.h
@@ -0,0 +1,54 @@
+//===-- RefactoringManager.h - Perform refactoring on files. ------*- C++ -*-=//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_MIGRATE_TOOL_REFACTORINGMANAGER_H
+#define LLVM_CLANG_TOOLS_EXTRA_MIGRATE_TOOL_REFACTORINGMANAGER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+#include <set>
+
+namespace clang {
+namespace migrate_tool {
+
+// This defines interfaces for a codebase-dependent `RefactoringManager` that
+// performs some refactoring operations.
+class RefactoringManager {
+public:
+  // Adds #include directives in \p Includes to each file in \p Files.
+  virtual llvm::Error
+  addIncludesToFiles(const std::set<llvm::StringRef> &Includes,
+                     llvm::ArrayRef<std::string> Files) = 0;
+
+  // Applies all rename rules in \p Renames on all \p Files.
+  // Rename rules are a set of <Old Name, New Name> pair.
+  virtual llvm::Error renameSymbolsInFiles(
+      llvm::ArrayRef<std::pair<llvm::StringRef, llvm::StringRef>> Renames,
+      llvm::ArrayRef<std::string> Files) = 0;
+
+  // Changes namespace \p OldNamespace to \p NewNamespace in \p Files and
+  // the corresponding files in translation units that match the given \p
+  // FilePattern.
+  virtual llvm::Error changeNamespaceInFiles(
+      llvm::StringRef OldNamespace, llvm::StringRef NewNamespace,
+      llvm::StringRef FilePattern, llvm::ArrayRef<llvm::StringRef> Files) = 0;
+
+  // Moves definitions of \p Symbols from \p OldHeader and the corresponding
+  // source file to \p NewHeader and the new source file.
+  virtual llvm::Error
+  moveSymbolsAcrossFiles(llvm::ArrayRef<llvm::StringRef> Symbols,
+                         llvm::StringRef OldHeader,
+                         llvm::StringRef NewHeader) = 0;
+};
+
+} // namespace migrate_tool
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_MIGRATE_TOOL_REFACTORINGMANAGER_H
Index: migrate-tool/MigrateTool.h
===================================================================
--- /dev/null
+++ migrate-tool/MigrateTool.h
@@ -0,0 +1,100 @@
+//===-- MigrateTool.h - Migrate class, function etc. ------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_MIGRATE_TOOL_MIGRATETOOL_H
+#define LLVM_CLANG_TOOLS_EXTRA_MIGRATE_TOOL_MIGRATETOOL_H
+
+#include "AffectedFilesFinder.h"
+#include "BuildManager.h"
+#include "RefactoringManager.h"
+#include "llvm/Support/Error.h"
+
+namespace clang {
+namespace migrate_tool {
+
+// This tool automates the entire process of migrating a C++ symbol (class,
+// function, enum etc.) including renaming a symbol and/or moving a symbol
+// across namespace and/or files. Besides moving the symbol definition, it also
+// takes care of users of the symbol (i.e. update all references of old symbol
+// to new symbol) as well as build rules.
+// The migration path is divided into 3 phases:
+//   1. Preparation phase.
+//      Create an alias from the old symbol name to to new symbol name. If the
+//      symbol is to be moved acrossed files, a new temporary header containing
+//      type alias is created.
+//   2. Renaming phase.
+//      Update all affected projects (i.e. users of the old symbol) to use the
+//      new symbol name via the alias above.
+//   3. Migration phase.
+//      Actual migration happens at this phase after all affected projects are
+//      updated.
+//      Move the symbol definition to the new file if the symbol is to be moved
+//      to a different file.
+//      Rename the symbol (i.e. the definition) if the symbol is to be renamed.
+//      Change the namespace in which the symbol is defined if the symbol is to
+//      be moved to a different namespace.
+// With this migration path, we can divide the three phases into three separate
+// patches. For large scale changes where many projects are affected, the
+// renaming phase can be splitted into multiple smaller patches to make the
+// both refactoring and review process easier.
+class MigrateTool {
+public:
+  class MigrateSpec {
+  public:
+    enum class MigrateType {
+      Class,
+      Unknown,
+    };
+
+    llvm::StringRef getOldHeader() const { return OldHeader; }
+    llvm::StringRef getNewHeader() const { return NewHeader; }
+    llvm::StringRef getOldName() const { return OldName; }
+    llvm::StringRef getNewName() const { return NewName; }
+
+  private:
+    std::string OldHeader;
+    std::string NewHeader;
+    std::string OldName;
+    std::string NewName;
+  };
+
+  // FIXME: support handling multiple `MigrateSpec`s in one run.
+  MigrateTool(const MigrateSpec &Spec, BuildManager *BuildMgr,
+              RefactoringManager *Refactor, AffectedFilesFinder *Finder);
+
+  llvm::Error run();
+
+private:
+  // Preparation phase. See comment for the class above.
+  llvm::Error prepare();
+
+  // Renaming phase. See comment for the class above.
+  llvm::Error rename();
+
+  // Migration phase. See comment for the class above.
+  llvm::Error migrate();
+
+  // Create a new file with the given `Content`.
+  llvm::Error createFile(llvm::StringRef FilePath, llvm::StringRef Content);
+
+  MigrateSpec Spec;
+  // A codebase-dependent `BuildManager` that takes care of build rules during
+  // the migration.
+  BuildManager *BuildMgr;
+  // A codebase-dependent `RefactoringManager` that performs some refactoring
+  // operations.
+  RefactoringManager *RefactorMgr;
+  // Finds files that are affected by refactoring actions.
+  AffectedFilesFinder *Finder;
+};
+
+} // namespace migrate_tool
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_MIGRATE_TOOL_MIGRATETOOL_H
Index: migrate-tool/MigrateTool.cpp
===================================================================
--- /dev/null
+++ migrate-tool/MigrateTool.cpp
@@ -0,0 +1,134 @@
+//===-- MigrateTool.cpp - Migrate class, function etc. ----------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MigrateTool.h"
+#include "HeaderGenerator.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Process.h"
+#include <fstream>
+#include <set>
+
+namespace clang {
+namespace migrate_tool {
+
+MigrateTool::MigrateTool(const MigrateSpec &Spec, BuildManager *BuildMgr,
+                         RefactoringManager *Refactor,
+                         AffectedFilesFinder *Finder)
+    : Spec(Spec), BuildMgr(BuildMgr), RefactorMgr(Refactor), Finder(Finder) {}
+
+llvm::Error MigrateTool::createFile(llvm::StringRef FilePath,
+                                    llvm::StringRef Content) {
+  std::error_code EC;
+  llvm::raw_fd_ostream File(FilePath.str(), EC,
+                            llvm::sys::fs::OpenFlags::F_None);
+  if (EC)
+    return llvm::errorCodeToError(EC);
+  File << Content.str();
+  File.close();
+  return llvm::Error::success();
+}
+
+llvm::Error MigrateTool::prepare() {
+  llvm::outs() << "Preparation phase.\n";
+  HeaderGenerator NewHeader(Spec.getNewHeader());
+  if (Spec.getNewHeader() == Spec.getOldHeader()) {
+    // FIXME: rename class within the same file. No need for new header. Just
+    // insert the alias in the old header.
+    return llvm::make_error<llvm::StringError>(
+        "Inplace renaming is not supported yet.",
+        llvm::inconvertibleErrorCode());
+  }
+  // Construct a new header for the symbol alias.
+  NewHeader.addInclude(Spec.getOldHeader());
+  if (Spec.getNewName() != Spec.getOldName())
+    NewHeader.addAlias(Spec.getNewName(), Spec.getOldName());
+
+  // Create new header and build target.
+  std::string Code = NewHeader.generateContent();
+  if (auto Err = createFile(NewHeader.getName(), Code))
+    return Err;
+  BuildMgr->addLibrary({NewHeader.getName()});
+
+  return llvm::Error::success();
+}
+
+llvm::Error MigrateTool::rename() {
+  llvm::outs() << "Rename phase.\n";
+  // Get all files that are affected by the migration, i.e. users of the symbol.
+  auto Files = Finder->getAffectedFiles(Spec.getOldName());
+  if (!Files)
+    return Files.takeError();
+  llvm::SmallVector<std::pair<llvm::StringRef, llvm::StringRef>, 4> Renames;
+  std::set<llvm::StringRef> NewIncludes;
+  if (Spec.getOldName() != Spec.getNewName())
+    Renames.emplace_back(Spec.getOldName(), Spec.getNewName());
+  if (Spec.getOldHeader() != Spec.getNewHeader())
+    NewIncludes.insert(Spec.getNewHeader());
+  if (auto Err = RefactorMgr->renameSymbolsInFiles(Renames, *Files))
+    return Err;
+  if (auto Err = RefactorMgr->addIncludesToFiles(NewIncludes, *Files))
+    return Err;
+  // Add dependency to affected target.
+  std::string NewTarget = BuildMgr->getBuildTargetForFile(Spec.getNewHeader());
+  for (llvm::StringRef File : *Files)
+    BuildMgr->addDependency(BuildMgr->getBuildTargetForFile(File), NewTarget);
+  return llvm::Error::success();
+}
+
+static inline llvm::StringRef
+extractNamespaceFromQualifiedName(llvm::StringRef QualifiedName) {
+  return QualifiedName.rsplit(':').second;
+}
+
+llvm::Error MigrateTool::migrate() {
+  llvm::outs() << "Migrate phase.\n";
+  // Move symbol definitions, rename symbol definitions, change
+  // surroudning namespaces, and update build rules if necessary.
+  llvm::SmallVector<std::pair<llvm::StringRef, llvm::StringRef>, 4> Renames;
+  if (Spec.getOldName() != Spec.getNewName())
+    Renames.emplace_back(Spec.getOldName(), Spec.getNewName());
+  llvm::SmallVector<llvm::StringRef, 4> MovedSymbols;
+  MovedSymbols.push_back(Spec.getOldName());
+  // FIXME: consider source files. Need to determine whether source files send
+  // with ".cpp" or ".cc" etc.
+  // FIXME: copy dependencies from old target to new target.
+  if (auto Err = RefactorMgr->moveSymbolsAcrossFiles(
+          MovedSymbols, Spec.getOldHeader(), Spec.getNewHeader()))
+    return Err;
+  if (auto Err =
+          RefactorMgr->renameSymbolsInFiles(Renames, {Spec.getNewHeader()}))
+    return Err;
+
+  llvm::StringRef OldNamespace =
+      extractNamespaceFromQualifiedName(Spec.getOldName());
+  llvm::StringRef NewNamespace =
+      extractNamespaceFromQualifiedName(Spec.getNewName());
+
+  llvm::SmallVector<llvm::StringRef, 4> Files;
+  Files.push_back(Spec.getNewHeader());
+  if (auto Err = RefactorMgr->changeNamespaceInFiles(
+          OldNamespace, NewNamespace, Spec.getNewHeader(), Files))
+    return Err;
+
+  return llvm::Error::success();
+}
+
+llvm::Error MigrateTool::run() {
+  if (auto Err = prepare())
+    return Err;
+  if (auto Err = rename())
+    return Err;
+  if (auto Err = migrate())
+    return Err;
+  return llvm::Error::success();
+}
+
+} // namespace migrate_tool
+} // namespace clang
Index: migrate-tool/HeaderGenerator.h
===================================================================
--- /dev/null
+++ migrate-tool/HeaderGenerator.h
@@ -0,0 +1,58 @@
+//===-- HeaderGenerator.h - Generate new headers. ----------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_MIGRATE_TOOL_HEADERGENERATOR_H
+#define LLVM_CLANG_TOOLS_EXTRA_MIGRATE_TOOL_HEADERGENERATOR_H
+
+#include "llvm/ADT/StringRef.h"
+#include <vector>
+
+namespace clang {
+namespace migrate_tool {
+
+// This constructs a C++ header containing type aliases.
+class HeaderGenerator {
+public:
+  HeaderGenerator(llvm::StringRef HeaderName);
+
+  // Returns the name of the header.
+  llvm::StringRef getName() const { return HeaderName; }
+
+  /// \brief Adds an `using` shadow declaration from \p TypeName to \p NewName.
+  /// Both names should be fully-qualified.
+  /// For example, if \p NewName is `a::b::New` and TypeName is `x::y::Old`.
+  /// Then, the following code will be added into the header:
+  /// \code
+  ///   namespace a {
+  ///   namespace b {
+  ///   using New = ::x::y::Old;
+  ///   } // namespace b
+  ///   } // namespace a
+  /// \endcode
+  void addAlias(llvm::StringRef NewName, llvm::StringRef TypeName);
+
+  // Adds an #include into the header.
+  void addInclude(llvm::StringRef IncludeHeader);
+
+  // Generates the header content containing given aliases and #include's.
+  // FIXME: consider code style.
+  std::string generateContent() const;
+
+private:
+  std::string HeaderName;
+  std::string HeaderGuard;
+  // Old symbol name, New symbol name pairs.
+  std::vector<std::pair<std::string, std::string>> Aliases;
+  std::vector<std::string> Includes;
+};
+
+} // namespace migrate_tool
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_MIGRATE_TOOL_HEADERGENERATOR_H
Index: migrate-tool/HeaderGenerator.cpp
===================================================================
--- /dev/null
+++ migrate-tool/HeaderGenerator.cpp
@@ -0,0 +1,112 @@
+//===-- HeaderGenerator.cpp - Generate new headers. -------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "HeaderGenerator.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <sstream>
+
+namespace clang {
+namespace migrate_tool {
+
+namespace {
+
+class Namespace {
+public:
+  Namespace(llvm::StringRef Name, bool IsTopLevel = false)
+      : Name(Name), IsTopLevel(IsTopLevel) {
+    assert(!(!Name.empty() && IsTopLevel) &&
+           "A namespace must be either a top-level namespace with no name or "
+           "not a top-level namespace with name.");
+  }
+
+  void addAlias(llvm::StringRef NewName, llvm::StringRef TypeName) {
+    std::string OS;
+    llvm::raw_string_ostream SS(OS);
+    SS << "using " << NewName.str() << " = ::" << TypeName.str() << ";";
+    SS.flush();
+    CodeBlocks.push_back(OS);
+  }
+
+  Namespace *addNestedNamespace(llvm::StringRef Name) {
+    auto Pair = NestedNamespaces.try_emplace(Name, Name);
+    return &Pair.first->getValue();
+  }
+
+  std::string GenerateNamespaceCodeBlock() const {
+    std::vector<std::string> Lines;
+    if (!IsTopLevel)
+      Lines.push_back("namespace " + Name + " {");
+    // Add code blocks.
+    Lines.insert(Lines.end(), CodeBlocks.begin(), CodeBlocks.end());
+    // Add nested namespaces.
+    // If there are multiple nested namespaces, add newlines around each
+    // namespace.
+    for (const auto &Entry : NestedNamespaces)
+      Lines.push_back(Entry.second.GenerateNamespaceCodeBlock());
+    if (!IsTopLevel)
+      Lines.push_back("} // namespace " + Name);
+    return llvm::join(Lines.begin(), Lines.end(), "\n");
+  }
+
+private:
+  std::string Name;
+  bool IsTopLevel;
+  std::vector<std::string> CodeBlocks;
+  llvm::StringMap<Namespace> NestedNamespaces;
+};
+
+} // namespace
+
+HeaderGenerator::HeaderGenerator(llvm::StringRef HeaderName)
+    : HeaderName(HeaderName), HeaderGuard(HeaderName) {
+  // FIXME: use clang-tidy to generate the header guard.
+  std::replace(HeaderGuard.begin(), HeaderGuard.end(), '/', '_');
+  std::replace(HeaderGuard.begin(), HeaderGuard.end(), '.', '_');
+  HeaderGuard = llvm::StringRef(HeaderGuard).upper();
+}
+
+void HeaderGenerator::addAlias(llvm::StringRef NewName, llvm::StringRef TypeName) {
+  Aliases.emplace_back(NewName, TypeName);
+}
+
+void HeaderGenerator::addInclude(llvm::StringRef IncludeHeader) {
+  Includes.push_back(IncludeHeader);
+}
+
+// FIXME: format generated code.
+std::string HeaderGenerator::generateContent() const {
+  std::vector<std::string> Lines;
+  Lines.push_back("#ifndef " + HeaderGuard);
+  Lines.push_back("#define " + HeaderGuard);
+  for (const auto &Include : Includes)
+    Lines.push_back("#include \"" + Include + "\"");
+
+  Namespace TopNs("", /*IsTopLevel=*/true);
+  // Generate namespces containing aliases.
+  for (const auto &Entry : Aliases) {
+    llvm::StringRef NewName = Entry.first;
+    llvm::SmallVector<llvm::StringRef, 4> NewNameSplitted;
+    NewName.split(NewNameSplitted, "::");
+    auto *CurNs = &TopNs;
+    for (auto I = NewNameSplitted.begin(), E = NewNameSplitted.end() - 1;
+         I != E; ++I)
+      CurNs = CurNs->addNestedNamespace(*I);
+    CurNs->addAlias(NewNameSplitted.back(), Entry.second);
+  }
+
+  Lines.push_back(TopNs.GenerateNamespaceCodeBlock());
+  Lines.push_back("#endif // " + HeaderGuard);
+  return llvm::join(Lines.begin(), Lines.end(), "\n");
+}
+
+} // namespace migrate_tool
+} // namespace clang
Index: migrate-tool/CMakeLists.txt
===================================================================
--- /dev/null
+++ migrate-tool/CMakeLists.txt
@@ -0,0 +1,15 @@
+set(LLVM_LINK_COMPONENTS
+  support
+  )
+
+add_clang_library(migrateTool
+  HeaderGenerator.cpp
+  MigrateTool.cpp
+
+  LINK_LIBS
+  clangAST
+  clangBasic
+  clangFormat
+  clangTooling
+  clangToolingCore
+  )
Index: migrate-tool/BuildManager.h
===================================================================
--- /dev/null
+++ migrate-tool/BuildManager.h
@@ -0,0 +1,39 @@
+//===-- BuildManager.h - Manages build targets ------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_MIGRATE_TOOL_BUILDMANAGER_H
+#define LLVM_CLANG_TOOLS_EXTRA_MIGRATE_TOOL_BUILDMANAGER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace clang {
+namespace migrate_tool {
+
+// This defines interfaces for a codebase-dependent build manager.
+class BuildManager {
+public:
+  // Adds a new library build target with \p Sources as source files. The name
+  // of the new library will be \p Name if it is provided; otherwise, the name
+  // will be auto-generated.
+  virtual bool addLibrary(llvm::ArrayRef<std::string> Sources,
+                          llvm::StringRef Name = llvm::StringRef()) = 0;
+
+  // Adds a new dependency to the build target.
+  virtual bool addDependency(llvm::StringRef BuildTarget,
+                             llvm::StringRef Dependency) = 0;
+
+  // Returns the name of the build target containing \p File.
+  virtual std::string getBuildTargetForFile(llvm::StringRef File) = 0;
+};
+
+} // namespace migrate_tool
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_MIGRATE_TOOL_BUILDMANAGER_H
Index: migrate-tool/AffectedFilesFinder.h
===================================================================
--- /dev/null
+++ migrate-tool/AffectedFilesFinder.h
@@ -0,0 +1,33 @@
+//===-- AffectedFilesFinder.h - Finds files affected by a refactor.-*- C++ -*=//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_MIGRATE_TOOL_AFFECTEDFILESINGFINDER_H
+#define LLVM_CLANG_TOOLS_EXTRA_MIGRATE_TOOL_AFFECTEDFILESINGFINDER_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+#include <vector>
+
+namespace clang {
+namespace migrate_tool {
+
+// This defines interface for finding files that are affected by a refactoring
+// action, e.g. renaming a symbol.
+class AffectedFilesFinder {
+public:
+  // Get all files that need to be updated when a symbol is renamed and/or
+  // moved.
+  virtual llvm::Expected<std::vector<std::string>>
+  getAffectedFiles(llvm::StringRef Symbol) = 0;
+};
+
+} // namespace migrate_tool
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_MIGRATE_TOOL_AFFECTEDFILESINGFINDER_H
Index: CMakeLists.txt
===================================================================
--- CMakeLists.txt
+++ CMakeLists.txt
@@ -1,6 +1,7 @@
 add_subdirectory(clang-apply-replacements)
 add_subdirectory(clang-rename)
 add_subdirectory(clang-reorder-fields)
+add_subdirectory(migrate-tool)
 add_subdirectory(modularize)
 if(CLANG_ENABLE_STATIC_ANALYZER)
 add_subdirectory(clang-tidy)
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to