[clang-tools-extra] r356780 - Make clang-move use same file naming convention as other tools

Nico Weber via cfe-commits cfe-commits at lists.llvm.org
Fri Mar 22 09:34:39 PDT 2019


Author: nico
Date: Fri Mar 22 09:34:39 2019
New Revision: 356780

URL: http://llvm.org/viewvc/llvm-project?rev=356780&view=rev
Log:
Make clang-move use same file naming convention as other tools

In all the other clang-foo tools, the main library file is called
Foo.cpp and the file in the tool/ folder is called ClangFoo.cpp.
Do this for clang-move too.

No intended behavior change.

Differential Revision: https://reviews.llvm.org/D59700

Added:
    clang-tools-extra/trunk/clang-move/Move.cpp
    clang-tools-extra/trunk/clang-move/Move.h
    clang-tools-extra/trunk/clang-move/tool/ClangMove.cpp
Removed:
    clang-tools-extra/trunk/clang-move/ClangMove.cpp
    clang-tools-extra/trunk/clang-move/ClangMove.h
    clang-tools-extra/trunk/clang-move/tool/ClangMoveMain.cpp
Modified:
    clang-tools-extra/trunk/clang-move/CMakeLists.txt
    clang-tools-extra/trunk/clang-move/HelperDeclRefGraph.cpp
    clang-tools-extra/trunk/clang-move/tool/CMakeLists.txt

Modified: clang-tools-extra/trunk/clang-move/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-move/CMakeLists.txt?rev=356780&r1=356779&r2=356780&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-move/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clang-move/CMakeLists.txt Fri Mar 22 09:34:39 2019
@@ -3,7 +3,7 @@ set(LLVM_LINK_COMPONENTS
   )
 
 add_clang_library(clangMove
-  ClangMove.cpp
+  Move.cpp
   HelperDeclRefGraph.cpp
 
   LINK_LIBS

Removed: clang-tools-extra/trunk/clang-move/ClangMove.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-move/ClangMove.cpp?rev=356779&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-move/ClangMove.cpp (original)
+++ clang-tools-extra/trunk/clang-move/ClangMove.cpp (removed)
@@ -1,937 +0,0 @@
-//===-- ClangMove.cpp - Implement ClangMove functationalities ---*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "ClangMove.h"
-#include "HelperDeclRefGraph.h"
-#include "clang/ASTMatchers/ASTMatchers.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Format/Format.h"
-#include "clang/Frontend/CompilerInstance.h"
-#include "clang/Lex/Lexer.h"
-#include "clang/Lex/Preprocessor.h"
-#include "clang/Rewrite/Core/Rewriter.h"
-#include "clang/Tooling/Core/Replacement.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/Path.h"
-
-#define DEBUG_TYPE "clang-move"
-
-using namespace clang::ast_matchers;
-
-namespace clang {
-namespace move {
-namespace {
-
-// FIXME: Move to ASTMatchers.
-AST_MATCHER(VarDecl, isStaticDataMember) { return Node.isStaticDataMember(); }
-
-AST_MATCHER(NamedDecl, notInMacro) { return !Node.getLocation().isMacroID(); }
-
-AST_MATCHER_P(Decl, hasOutermostEnclosingClass,
-              ast_matchers::internal::Matcher<Decl>, InnerMatcher) {
-  const auto *Context = Node.getDeclContext();
-  if (!Context)
-    return false;
-  while (const auto *NextContext = Context->getParent()) {
-    if (isa<NamespaceDecl>(NextContext) ||
-        isa<TranslationUnitDecl>(NextContext))
-      break;
-    Context = NextContext;
-  }
-  return InnerMatcher.matches(*Decl::castFromDeclContext(Context), Finder,
-                              Builder);
-}
-
-AST_MATCHER_P(CXXMethodDecl, ofOutermostEnclosingClass,
-              ast_matchers::internal::Matcher<CXXRecordDecl>, InnerMatcher) {
-  const CXXRecordDecl *Parent = Node.getParent();
-  if (!Parent)
-    return false;
-  while (const auto *NextParent =
-             dyn_cast<CXXRecordDecl>(Parent->getParent())) {
-    Parent = NextParent;
-  }
-
-  return InnerMatcher.matches(*Parent, Finder, Builder);
-}
-
-std::string CleanPath(StringRef PathRef) {
-  llvm::SmallString<128> Path(PathRef);
-  llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
-  // FIXME: figure out why this is necessary.
-  llvm::sys::path::native(Path);
-  return Path.str();
-}
-
-// Make the Path absolute using the CurrentDir if the Path is not an absolute
-// path. An empty Path will result in an empty string.
-std::string MakeAbsolutePath(StringRef CurrentDir, StringRef Path) {
-  if (Path.empty())
-    return "";
-  llvm::SmallString<128> InitialDirectory(CurrentDir);
-  llvm::SmallString<128> AbsolutePath(Path);
-  llvm::sys::fs::make_absolute(InitialDirectory, AbsolutePath);
-  return CleanPath(std::move(AbsolutePath));
-}
-
-// Make the Path absolute using the current working directory of the given
-// SourceManager if the Path is not an absolute path.
-//
-// The Path can be a path relative to the build directory, or retrieved from
-// the SourceManager.
-std::string MakeAbsolutePath(const SourceManager &SM, StringRef Path) {
-  llvm::SmallString<128> AbsolutePath(Path);
-  if (std::error_code EC =
-          SM.getFileManager().getVirtualFileSystem()->makeAbsolute(
-              AbsolutePath))
-    llvm::errs() << "Warning: could not make absolute file: '" << EC.message()
-                 << '\n';
-  // Handle symbolic link path cases.
-  // We are trying to get the real file path of the symlink.
-  const DirectoryEntry *Dir = SM.getFileManager().getDirectory(
-      llvm::sys::path::parent_path(AbsolutePath.str()));
-  if (Dir) {
-    StringRef DirName = SM.getFileManager().getCanonicalName(Dir);
-    // FIXME: getCanonicalName might fail to get real path on VFS.
-    if (llvm::sys::path::is_absolute(DirName)) {
-      SmallString<128> AbsoluteFilename;
-      llvm::sys::path::append(AbsoluteFilename, DirName,
-                              llvm::sys::path::filename(AbsolutePath.str()));
-      return CleanPath(AbsoluteFilename);
-    }
-  }
-  return CleanPath(AbsolutePath);
-}
-
-// Matches AST nodes that are expanded within the given AbsoluteFilePath.
-AST_POLYMORPHIC_MATCHER_P(isExpansionInFile,
-                          AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt, TypeLoc),
-                          std::string, AbsoluteFilePath) {
-  auto &SourceManager = Finder->getASTContext().getSourceManager();
-  auto ExpansionLoc = SourceManager.getExpansionLoc(Node.getBeginLoc());
-  if (ExpansionLoc.isInvalid())
-    return false;
-  auto FileEntry =
-      SourceManager.getFileEntryForID(SourceManager.getFileID(ExpansionLoc));
-  if (!FileEntry)
-    return false;
-  return MakeAbsolutePath(SourceManager, FileEntry->getName()) ==
-         AbsoluteFilePath;
-}
-
-class FindAllIncludes : public PPCallbacks {
-public:
-  explicit FindAllIncludes(SourceManager *SM, ClangMoveTool *const MoveTool)
-      : SM(*SM), MoveTool(MoveTool) {}
-
-  void InclusionDirective(SourceLocation HashLoc, const Token & /*IncludeTok*/,
-                          StringRef FileName, bool IsAngled,
-                          CharSourceRange FilenameRange,
-                          const FileEntry * /*File*/, StringRef SearchPath,
-                          StringRef /*RelativePath*/,
-                          const Module * /*Imported*/,
-                          SrcMgr::CharacteristicKind /*FileType*/) override {
-    if (const auto *FileEntry = SM.getFileEntryForID(SM.getFileID(HashLoc)))
-      MoveTool->addIncludes(FileName, IsAngled, SearchPath,
-                            FileEntry->getName(), FilenameRange, SM);
-  }
-
-private:
-  const SourceManager &SM;
-  ClangMoveTool *const MoveTool;
-};
-
-/// Add a declatration being moved to new.h/cc. Note that the declaration will
-/// also be deleted in old.h/cc.
-void MoveDeclFromOldFileToNewFile(ClangMoveTool *MoveTool, const NamedDecl *D) {
-  MoveTool->getMovedDecls().push_back(D);
-  MoveTool->addRemovedDecl(D);
-  MoveTool->getUnremovedDeclsInOldHeader().erase(D);
-}
-
-class FunctionDeclarationMatch : public MatchFinder::MatchCallback {
-public:
-  explicit FunctionDeclarationMatch(ClangMoveTool *MoveTool)
-      : MoveTool(MoveTool) {}
-
-  void run(const MatchFinder::MatchResult &Result) override {
-    const auto *FD = Result.Nodes.getNodeAs<FunctionDecl>("function");
-    assert(FD);
-    const NamedDecl *D = FD;
-    if (const auto *FTD = FD->getDescribedFunctionTemplate())
-      D = FTD;
-    MoveDeclFromOldFileToNewFile(MoveTool, D);
-  }
-
-private:
-  ClangMoveTool *MoveTool;
-};
-
-class VarDeclarationMatch : public MatchFinder::MatchCallback {
-public:
-  explicit VarDeclarationMatch(ClangMoveTool *MoveTool)
-      : MoveTool(MoveTool) {}
-
-  void run(const MatchFinder::MatchResult &Result) override {
-    const auto *VD = Result.Nodes.getNodeAs<VarDecl>("var");
-    assert(VD);
-    MoveDeclFromOldFileToNewFile(MoveTool, VD);
-  }
-
-private:
-  ClangMoveTool *MoveTool;
-};
-
-class TypeAliasMatch : public MatchFinder::MatchCallback {
-public:
-  explicit TypeAliasMatch(ClangMoveTool *MoveTool)
-      : MoveTool(MoveTool) {}
-
-  void run(const MatchFinder::MatchResult &Result) override {
-    if (const auto *TD = Result.Nodes.getNodeAs<TypedefDecl>("typedef"))
-      MoveDeclFromOldFileToNewFile(MoveTool, TD);
-    else if (const auto *TAD =
-                 Result.Nodes.getNodeAs<TypeAliasDecl>("type_alias")) {
-      const NamedDecl * D = TAD;
-      if (const auto * TD = TAD->getDescribedAliasTemplate())
-        D = TD;
-      MoveDeclFromOldFileToNewFile(MoveTool, D);
-    }
-  }
-
-private:
-  ClangMoveTool *MoveTool;
-};
-
-class EnumDeclarationMatch : public MatchFinder::MatchCallback {
-public:
-  explicit EnumDeclarationMatch(ClangMoveTool *MoveTool)
-      : MoveTool(MoveTool) {}
-
-  void run(const MatchFinder::MatchResult &Result) override {
-    const auto *ED = Result.Nodes.getNodeAs<EnumDecl>("enum");
-    assert(ED);
-    MoveDeclFromOldFileToNewFile(MoveTool, ED);
-  }
-
-private:
-  ClangMoveTool *MoveTool;
-};
-
-class ClassDeclarationMatch : public MatchFinder::MatchCallback {
-public:
-  explicit ClassDeclarationMatch(ClangMoveTool *MoveTool)
-      : MoveTool(MoveTool) {}
-  void run(const MatchFinder::MatchResult &Result) override {
-    SourceManager *SM = &Result.Context->getSourceManager();
-    if (const auto *CMD = Result.Nodes.getNodeAs<CXXMethodDecl>("class_method"))
-      MatchClassMethod(CMD, SM);
-    else if (const auto *VD =
-                 Result.Nodes.getNodeAs<VarDecl>("class_static_var_decl"))
-      MatchClassStaticVariable(VD, SM);
-    else if (const auto *CD =
-                 Result.Nodes.getNodeAs<CXXRecordDecl>("moved_class"))
-      MatchClassDeclaration(CD, SM);
-  }
-
-private:
-  void MatchClassMethod(const CXXMethodDecl *CMD, SourceManager *SM) {
-    // Skip inline class methods. isInline() ast matcher doesn't ignore this
-    // case.
-    if (!CMD->isInlined()) {
-      MoveTool->getMovedDecls().push_back(CMD);
-      MoveTool->addRemovedDecl(CMD);
-      // Get template class method from its method declaration as
-      // UnremovedDecls stores template class method.
-      if (const auto *FTD = CMD->getDescribedFunctionTemplate())
-        MoveTool->getUnremovedDeclsInOldHeader().erase(FTD);
-      else
-        MoveTool->getUnremovedDeclsInOldHeader().erase(CMD);
-    }
-  }
-
-  void MatchClassStaticVariable(const NamedDecl *VD, SourceManager *SM) {
-    MoveDeclFromOldFileToNewFile(MoveTool, VD);
-  }
-
-  void MatchClassDeclaration(const CXXRecordDecl *CD, SourceManager *SM) {
-    // Get class template from its class declaration as UnremovedDecls stores
-    // class template.
-    if (const auto *TC = CD->getDescribedClassTemplate())
-      MoveTool->getMovedDecls().push_back(TC);
-    else
-      MoveTool->getMovedDecls().push_back(CD);
-    MoveTool->addRemovedDecl(MoveTool->getMovedDecls().back());
-    MoveTool->getUnremovedDeclsInOldHeader().erase(
-        MoveTool->getMovedDecls().back());
-  }
-
-  ClangMoveTool *MoveTool;
-};
-
-// Expand to get the end location of the line where the EndLoc of the given
-// Decl.
-SourceLocation getLocForEndOfDecl(const Decl *D,
-                                  const LangOptions &LangOpts = LangOptions()) {
-  const auto &SM = D->getASTContext().getSourceManager();
-  // If the expansion range is a character range, this is the location of
-  // the first character past the end. Otherwise it's the location of the
-  // first character in the final token in the range.
-  auto EndExpansionLoc = SM.getExpansionRange(D->getEndLoc()).getEnd();
-  std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(EndExpansionLoc);
-  // Try to load the file buffer.
-  bool InvalidTemp = false;
-  llvm::StringRef File = SM.getBufferData(LocInfo.first, &InvalidTemp);
-  if (InvalidTemp)
-    return SourceLocation();
-
-  const char *TokBegin = File.data() + LocInfo.second;
-  // Lex from the start of the given location.
-  Lexer Lex(SM.getLocForStartOfFile(LocInfo.first), LangOpts, File.begin(),
-            TokBegin, File.end());
-
-  llvm::SmallVector<char, 16> Line;
-  // FIXME: this is a bit hacky to get ReadToEndOfLine work.
-  Lex.setParsingPreprocessorDirective(true);
-  Lex.ReadToEndOfLine(&Line);
-  SourceLocation EndLoc = EndExpansionLoc.getLocWithOffset(Line.size());
-  // If we already reach EOF, just return the EOF SourceLocation;
-  // otherwise, move 1 offset ahead to include the trailing newline character
-  // '\n'.
-  return SM.getLocForEndOfFile(LocInfo.first) == EndLoc
-             ? EndLoc
-             : EndLoc.getLocWithOffset(1);
-}
-
-// Get full range of a Decl including the comments associated with it.
-CharSourceRange getFullRange(const Decl *D,
-                             const LangOptions &options = LangOptions()) {
-  const auto &SM = D->getASTContext().getSourceManager();
-  SourceRange Full(SM.getExpansionLoc(D->getBeginLoc()), getLocForEndOfDecl(D));
-  // Expand to comments that are associated with the Decl.
-  if (const auto *Comment = D->getASTContext().getRawCommentForDeclNoCache(D)) {
-    if (SM.isBeforeInTranslationUnit(Full.getEnd(), Comment->getEndLoc()))
-      Full.setEnd(Comment->getEndLoc());
-    // FIXME: Don't delete a preceding comment, if there are no other entities
-    // it could refer to.
-    if (SM.isBeforeInTranslationUnit(Comment->getBeginLoc(), Full.getBegin()))
-      Full.setBegin(Comment->getBeginLoc());
-  }
-
-  return CharSourceRange::getCharRange(Full);
-}
-
-std::string getDeclarationSourceText(const Decl *D) {
-  const auto &SM = D->getASTContext().getSourceManager();
-  llvm::StringRef SourceText =
-      Lexer::getSourceText(getFullRange(D), SM, LangOptions());
-  return SourceText.str();
-}
-
-bool isInHeaderFile(const Decl *D, llvm::StringRef OriginalRunningDirectory,
-                    llvm::StringRef OldHeader) {
-  const auto &SM = D->getASTContext().getSourceManager();
-  if (OldHeader.empty())
-    return false;
-  auto ExpansionLoc = SM.getExpansionLoc(D->getBeginLoc());
-  if (ExpansionLoc.isInvalid())
-    return false;
-
-  if (const auto *FE = SM.getFileEntryForID(SM.getFileID(ExpansionLoc))) {
-    return MakeAbsolutePath(SM, FE->getName()) ==
-           MakeAbsolutePath(OriginalRunningDirectory, OldHeader);
-  }
-
-  return false;
-}
-
-std::vector<std::string> getNamespaces(const Decl *D) {
-  std::vector<std::string> Namespaces;
-  for (const auto *Context = D->getDeclContext(); Context;
-       Context = Context->getParent()) {
-    if (llvm::isa<TranslationUnitDecl>(Context) ||
-        llvm::isa<LinkageSpecDecl>(Context))
-      break;
-
-    if (const auto *ND = llvm::dyn_cast<NamespaceDecl>(Context))
-      Namespaces.push_back(ND->getName().str());
-  }
-  std::reverse(Namespaces.begin(), Namespaces.end());
-  return Namespaces;
-}
-
-tooling::Replacements
-createInsertedReplacements(const std::vector<std::string> &Includes,
-                           const std::vector<const NamedDecl *> &Decls,
-                           llvm::StringRef FileName, bool IsHeader = false,
-                           StringRef OldHeaderInclude = "") {
-  std::string NewCode;
-  std::string GuardName(FileName);
-  if (IsHeader) {
-    for (size_t i = 0; i < GuardName.size(); ++i) {
-      if (!isAlphanumeric(GuardName[i]))
-        GuardName[i] = '_';
-    }
-    GuardName = StringRef(GuardName).upper();
-    NewCode += "#ifndef " + GuardName + "\n";
-    NewCode += "#define " + GuardName + "\n\n";
-  }
-
-  NewCode += OldHeaderInclude;
-  // Add #Includes.
-  for (const auto &Include : Includes)
-    NewCode += Include;
-
-  if (!Includes.empty())
-    NewCode += "\n";
-
-  // Add moved class definition and its related declarations. All declarations
-  // in same namespace are grouped together.
-  //
-  // Record namespaces where the current position is in.
-  std::vector<std::string> CurrentNamespaces;
-  for (const auto *MovedDecl : Decls) {
-    // The namespaces of the declaration being moved.
-    std::vector<std::string> DeclNamespaces = getNamespaces(MovedDecl);
-    auto CurrentIt = CurrentNamespaces.begin();
-    auto DeclIt = DeclNamespaces.begin();
-    // Skip the common prefix.
-    while (CurrentIt != CurrentNamespaces.end() &&
-           DeclIt != DeclNamespaces.end()) {
-      if (*CurrentIt != *DeclIt)
-        break;
-      ++CurrentIt;
-      ++DeclIt;
-    }
-    // Calculate the new namespaces after adding MovedDecl in CurrentNamespace,
-    // which is used for next iteration of this loop.
-    std::vector<std::string> NextNamespaces(CurrentNamespaces.begin(),
-                                            CurrentIt);
-    NextNamespaces.insert(NextNamespaces.end(), DeclIt, DeclNamespaces.end());
-
-
-    // End with CurrentNamespace.
-    bool HasEndCurrentNamespace = false;
-    auto RemainingSize = CurrentNamespaces.end() - CurrentIt;
-    for (auto It = CurrentNamespaces.rbegin(); RemainingSize > 0;
-         --RemainingSize, ++It) {
-      assert(It < CurrentNamespaces.rend());
-      NewCode += "} // namespace " + *It + "\n";
-      HasEndCurrentNamespace = true;
-    }
-    // Add trailing '\n' after the nested namespace definition.
-    if (HasEndCurrentNamespace)
-      NewCode += "\n";
-
-    // If the moved declaration is not in CurrentNamespace, add extra namespace
-    // definitions.
-    bool IsInNewNamespace = false;
-    while (DeclIt != DeclNamespaces.end()) {
-      NewCode += "namespace " + *DeclIt + " {\n";
-      IsInNewNamespace = true;
-      ++DeclIt;
-    }
-    // If the moved declaration is in same namespace CurrentNamespace, add
-    // a preceeding `\n' before the moved declaration.
-    // FIXME: Don't add empty lines between using declarations.
-    if (!IsInNewNamespace)
-      NewCode += "\n";
-    NewCode += getDeclarationSourceText(MovedDecl);
-    CurrentNamespaces = std::move(NextNamespaces);
-  }
-  std::reverse(CurrentNamespaces.begin(), CurrentNamespaces.end());
-  for (const auto &NS : CurrentNamespaces)
-    NewCode += "} // namespace " + NS + "\n";
-
-  if (IsHeader)
-    NewCode += "\n#endif // " + GuardName + "\n";
-  return tooling::Replacements(tooling::Replacement(FileName, 0, 0, NewCode));
-}
-
-// Return a set of all decls which are used/referenced by the given Decls.
-// Specically, given a class member declaration, this method will return all
-// decls which are used by the whole class.
-llvm::DenseSet<const Decl *>
-getUsedDecls(const HelperDeclRefGraph *RG,
-             const std::vector<const NamedDecl *> &Decls) {
-  assert(RG);
-  llvm::DenseSet<const CallGraphNode *> Nodes;
-  for (const auto *D : Decls) {
-    auto Result = RG->getReachableNodes(
-        HelperDeclRGBuilder::getOutmostClassOrFunDecl(D));
-    Nodes.insert(Result.begin(), Result.end());
-  }
-  llvm::DenseSet<const Decl *> Results;
-  for (const auto *Node : Nodes)
-    Results.insert(Node->getDecl());
-  return Results;
-}
-
-} // namespace
-
-std::unique_ptr<ASTConsumer>
-ClangMoveAction::CreateASTConsumer(CompilerInstance &Compiler,
-                                   StringRef /*InFile*/) {
-  Compiler.getPreprocessor().addPPCallbacks(llvm::make_unique<FindAllIncludes>(
-      &Compiler.getSourceManager(), &MoveTool));
-  return MatchFinder.newASTConsumer();
-}
-
-ClangMoveTool::ClangMoveTool(ClangMoveContext *const Context,
-                             DeclarationReporter *const Reporter)
-    : Context(Context), Reporter(Reporter) {
-  if (!Context->Spec.NewHeader.empty())
-    CCIncludes.push_back("#include \"" + Context->Spec.NewHeader + "\"\n");
-}
-
-void ClangMoveTool::addRemovedDecl(const NamedDecl *Decl) {
-  const auto &SM = Decl->getASTContext().getSourceManager();
-  auto Loc = Decl->getLocation();
-  StringRef FilePath = SM.getFilename(Loc);
-  FilePathToFileID[FilePath] = SM.getFileID(Loc);
-  RemovedDecls.push_back(Decl);
-}
-
-void ClangMoveTool::registerMatchers(ast_matchers::MatchFinder *Finder) {
-  auto InOldHeader =
-      isExpansionInFile(makeAbsolutePath(Context->Spec.OldHeader));
-  auto InOldCC = isExpansionInFile(makeAbsolutePath(Context->Spec.OldCC));
-  auto InOldFiles = anyOf(InOldHeader, InOldCC);
-  auto classTemplateForwardDecls =
-      classTemplateDecl(unless(has(cxxRecordDecl(isDefinition()))));
-  auto ForwardClassDecls = namedDecl(
-      anyOf(cxxRecordDecl(unless(anyOf(isImplicit(), isDefinition()))),
-            classTemplateForwardDecls));
-  auto TopLevelDecl =
-      hasDeclContext(anyOf(namespaceDecl(), translationUnitDecl()));
-
-  //============================================================================
-  // Matchers for old header
-  //============================================================================
-  // Match all top-level named declarations (e.g. function, variable, enum) in
-  // old header, exclude forward class declarations and namespace declarations.
-  //
-  // We consider declarations inside a class belongs to the class. So these
-  // declarations will be ignored.
-  auto AllDeclsInHeader = namedDecl(
-      unless(ForwardClassDecls), unless(namespaceDecl()),
-      unless(usingDirectiveDecl()), // using namespace decl.
-      notInMacro(),
-      InOldHeader,
-      hasParent(decl(anyOf(namespaceDecl(), translationUnitDecl()))),
-      hasDeclContext(decl(anyOf(namespaceDecl(), translationUnitDecl()))));
-  Finder->addMatcher(AllDeclsInHeader.bind("decls_in_header"), this);
-
-  // Don't register other matchers when dumping all declarations in header.
-  if (Context->DumpDeclarations)
-    return;
-
-  // Match forward declarations in old header.
-  Finder->addMatcher(namedDecl(ForwardClassDecls, InOldHeader).bind("fwd_decl"),
-                     this);
-
-  //============================================================================
-  // Matchers for old cc
-  //============================================================================
-  auto IsOldCCTopLevelDecl = allOf(
-      hasParent(decl(anyOf(namespaceDecl(), translationUnitDecl()))), InOldCC);
-  // Matching using decls/type alias decls which are in named/anonymous/global
-  // namespace, these decls are always copied to new.h/cc. Those in classes,
-  // functions are covered in other matchers.
-  Finder->addMatcher(namedDecl(anyOf(usingDecl(IsOldCCTopLevelDecl),
-                                     usingDirectiveDecl(unless(isImplicit()),
-                                                        IsOldCCTopLevelDecl),
-                                     typeAliasDecl(IsOldCCTopLevelDecl)),
-                               notInMacro())
-                         .bind("using_decl"),
-                     this);
-
-  // Match static functions/variable definitions which are defined in named
-  // namespaces.
-  Optional<ast_matchers::internal::Matcher<NamedDecl>> HasAnySymbolNames;
-  for (StringRef SymbolName : Context->Spec.Names) {
-    llvm::StringRef GlobalSymbolName = SymbolName.trim().ltrim(':');
-    const auto HasName = hasName(("::" + GlobalSymbolName).str());
-    HasAnySymbolNames =
-        HasAnySymbolNames ? anyOf(*HasAnySymbolNames, HasName) : HasName;
-  }
-
-  if (!HasAnySymbolNames) {
-    llvm::errs() << "No symbols being moved.\n";
-    return;
-  }
-  auto InMovedClass =
-      hasOutermostEnclosingClass(cxxRecordDecl(*HasAnySymbolNames));
-
-  // Matchers for helper declarations in old.cc.
-  auto InAnonymousNS = hasParent(namespaceDecl(isAnonymous()));
-  auto NotInMovedClass= allOf(unless(InMovedClass), InOldCC);
-  auto IsOldCCHelper =
-      allOf(NotInMovedClass, anyOf(isStaticStorageClass(), InAnonymousNS));
-  // Match helper classes separately with helper functions/variables since we
-  // want to reuse these matchers in finding helpers usage below.
-  //
-  // There could be forward declarations usage for helpers, especially for
-  // classes and functions. We need include these forward declarations.
-  //
-  // Forward declarations for variable helpers will be excluded as these
-  // declarations (with "extern") are not supposed in cpp file.
-   auto HelperFuncOrVar =
-      namedDecl(notInMacro(), anyOf(functionDecl(IsOldCCHelper),
-                                    varDecl(isDefinition(), IsOldCCHelper)));
-  auto HelperClasses =
-      cxxRecordDecl(notInMacro(), NotInMovedClass, InAnonymousNS);
-  // Save all helper declarations in old.cc.
-  Finder->addMatcher(
-      namedDecl(anyOf(HelperFuncOrVar, HelperClasses)).bind("helper_decls"),
-      this);
-
-  // Construct an AST-based call graph of helper declarations in old.cc.
-  // In the following matcheres, "dc" is a caller while "helper_decls" and
-  // "used_class" is a callee, so a new edge starting from caller to callee will
-  // be add in the graph.
-  //
-  // Find helper function/variable usages.
-  Finder->addMatcher(
-      declRefExpr(to(HelperFuncOrVar), hasAncestor(decl().bind("dc")))
-          .bind("func_ref"),
-      &RGBuilder);
-  // Find helper class usages.
-  Finder->addMatcher(
-      typeLoc(loc(recordType(hasDeclaration(HelperClasses.bind("used_class")))),
-              hasAncestor(decl().bind("dc"))),
-      &RGBuilder);
-
-  //============================================================================
-  // Matchers for old files, including old.h/old.cc
-  //============================================================================
-  // Create a MatchCallback for class declarations.
-  MatchCallbacks.push_back(llvm::make_unique<ClassDeclarationMatch>(this));
-  // Match moved class declarations.
-  auto MovedClass = cxxRecordDecl(InOldFiles, *HasAnySymbolNames,
-                                  isDefinition(), TopLevelDecl)
-                        .bind("moved_class");
-  Finder->addMatcher(MovedClass, MatchCallbacks.back().get());
-  // Match moved class methods (static methods included) which are defined
-  // outside moved class declaration.
-  Finder->addMatcher(
-      cxxMethodDecl(InOldFiles, ofOutermostEnclosingClass(*HasAnySymbolNames),
-                    isDefinition())
-          .bind("class_method"),
-      MatchCallbacks.back().get());
-  // Match static member variable definition of the moved class.
-  Finder->addMatcher(
-      varDecl(InMovedClass, InOldFiles, isDefinition(), isStaticDataMember())
-          .bind("class_static_var_decl"),
-      MatchCallbacks.back().get());
-
-  MatchCallbacks.push_back(llvm::make_unique<FunctionDeclarationMatch>(this));
-  Finder->addMatcher(functionDecl(InOldFiles, *HasAnySymbolNames, TopLevelDecl)
-                         .bind("function"),
-                     MatchCallbacks.back().get());
-
-  MatchCallbacks.push_back(llvm::make_unique<VarDeclarationMatch>(this));
-  Finder->addMatcher(
-      varDecl(InOldFiles, *HasAnySymbolNames, TopLevelDecl).bind("var"),
-      MatchCallbacks.back().get());
-
-  // Match enum definition in old.h. Enum helpers (which are defined in old.cc)
-  // will not be moved for now no matter whether they are used or not.
-  MatchCallbacks.push_back(llvm::make_unique<EnumDeclarationMatch>(this));
-  Finder->addMatcher(
-      enumDecl(InOldHeader, *HasAnySymbolNames, isDefinition(), TopLevelDecl)
-          .bind("enum"),
-      MatchCallbacks.back().get());
-
-  // Match type alias in old.h, this includes "typedef" and "using" type alias
-  // declarations. Type alias helpers (which are defined in old.cc) will not be
-  // moved for now no matter whether they are used or not.
-  MatchCallbacks.push_back(llvm::make_unique<TypeAliasMatch>(this));
-  Finder->addMatcher(namedDecl(anyOf(typedefDecl().bind("typedef"),
-                                     typeAliasDecl().bind("type_alias")),
-                               InOldHeader, *HasAnySymbolNames, TopLevelDecl),
-                     MatchCallbacks.back().get());
-}
-
-void ClangMoveTool::run(const ast_matchers::MatchFinder::MatchResult &Result) {
-  if (const auto *D = Result.Nodes.getNodeAs<NamedDecl>("decls_in_header")) {
-    UnremovedDeclsInOldHeader.insert(D);
-  } else if (const auto *FWD =
-                 Result.Nodes.getNodeAs<CXXRecordDecl>("fwd_decl")) {
-    // Skip all forward declarations which appear after moved class declaration.
-    if (RemovedDecls.empty()) {
-      if (const auto *DCT = FWD->getDescribedClassTemplate())
-        MovedDecls.push_back(DCT);
-      else
-        MovedDecls.push_back(FWD);
-    }
-  } else if (const auto *ND =
-                 Result.Nodes.getNodeAs<NamedDecl>("helper_decls")) {
-    MovedDecls.push_back(ND);
-    HelperDeclarations.push_back(ND);
-    LLVM_DEBUG(llvm::dbgs() << "Add helper : " << ND->getNameAsString() << " ("
-                            << ND << ")\n");
-  } else if (const auto *UD = Result.Nodes.getNodeAs<NamedDecl>("using_decl")) {
-    MovedDecls.push_back(UD);
-  }
-}
-
-std::string ClangMoveTool::makeAbsolutePath(StringRef Path) {
-  return MakeAbsolutePath(Context->OriginalRunningDirectory, Path);
-}
-
-void ClangMoveTool::addIncludes(llvm::StringRef IncludeHeader, bool IsAngled,
-                                llvm::StringRef SearchPath,
-                                llvm::StringRef FileName,
-                                CharSourceRange IncludeFilenameRange,
-                                const SourceManager &SM) {
-  SmallVector<char, 128> HeaderWithSearchPath;
-  llvm::sys::path::append(HeaderWithSearchPath, SearchPath, IncludeHeader);
-  std::string AbsoluteIncludeHeader =
-      MakeAbsolutePath(SM, llvm::StringRef(HeaderWithSearchPath.data(),
-                                           HeaderWithSearchPath.size()));
-  std::string IncludeLine =
-      IsAngled ? ("#include <" + IncludeHeader + ">\n").str()
-               : ("#include \"" + IncludeHeader + "\"\n").str();
-
-  std::string AbsoluteOldHeader = makeAbsolutePath(Context->Spec.OldHeader);
-  std::string AbsoluteCurrentFile = MakeAbsolutePath(SM, FileName);
-  if (AbsoluteOldHeader == AbsoluteCurrentFile) {
-    // Find old.h includes "old.h".
-    if (AbsoluteOldHeader == AbsoluteIncludeHeader) {
-      OldHeaderIncludeRangeInHeader = IncludeFilenameRange;
-      return;
-    }
-    HeaderIncludes.push_back(IncludeLine);
-  } else if (makeAbsolutePath(Context->Spec.OldCC) == AbsoluteCurrentFile) {
-    // Find old.cc includes "old.h".
-    if (AbsoluteOldHeader == AbsoluteIncludeHeader) {
-      OldHeaderIncludeRangeInCC = IncludeFilenameRange;
-      return;
-    }
-    CCIncludes.push_back(IncludeLine);
-  }
-}
-
-void ClangMoveTool::removeDeclsInOldFiles() {
-  if (RemovedDecls.empty()) return;
-
-  // If old_header is not specified (only move declarations from old.cc), remain
-  // all the helper function declarations in old.cc as UnremovedDeclsInOldHeader
-  // is empty in this case, there is no way to verify unused/used helpers.
-  if (!Context->Spec.OldHeader.empty()) {
-    std::vector<const NamedDecl *> UnremovedDecls;
-    for (const auto *D : UnremovedDeclsInOldHeader)
-      UnremovedDecls.push_back(D);
-
-    auto UsedDecls = getUsedDecls(RGBuilder.getGraph(), UnremovedDecls);
-
-    // We remove the helper declarations which are not used in the old.cc after
-    // moving the given declarations.
-    for (const auto *D : HelperDeclarations) {
-      LLVM_DEBUG(llvm::dbgs() << "Check helper is used: "
-                              << D->getNameAsString() << " (" << D << ")\n");
-      if (!UsedDecls.count(HelperDeclRGBuilder::getOutmostClassOrFunDecl(
-              D->getCanonicalDecl()))) {
-        LLVM_DEBUG(llvm::dbgs() << "Helper removed in old.cc: "
-                                << D->getNameAsString() << " (" << D << ")\n");
-        RemovedDecls.push_back(D);
-      }
-    }
-  }
-
-  for (const auto *RemovedDecl : RemovedDecls) {
-    const auto &SM = RemovedDecl->getASTContext().getSourceManager();
-    auto Range = getFullRange(RemovedDecl);
-    tooling::Replacement RemoveReplacement(
-        SM, CharSourceRange::getCharRange(Range.getBegin(), Range.getEnd()),
-        "");
-    std::string FilePath = RemoveReplacement.getFilePath().str();
-    auto Err = Context->FileToReplacements[FilePath].add(RemoveReplacement);
-    if (Err)
-      llvm::errs() << llvm::toString(std::move(Err)) << "\n";
-  }
-  const auto &SM = RemovedDecls[0]->getASTContext().getSourceManager();
-
-  // Post process of cleanup around all the replacements.
-  for (auto &FileAndReplacements : Context->FileToReplacements) {
-    StringRef FilePath = FileAndReplacements.first;
-    // Add #include of new header to old header.
-    if (Context->Spec.OldDependOnNew &&
-        MakeAbsolutePath(SM, FilePath) ==
-            makeAbsolutePath(Context->Spec.OldHeader)) {
-      // FIXME: Minimize the include path like include-fixer.
-      std::string IncludeNewH =
-          "#include \"" + Context->Spec.NewHeader + "\"\n";
-      // This replacment for inserting header will be cleaned up at the end.
-      auto Err = FileAndReplacements.second.add(
-          tooling::Replacement(FilePath, UINT_MAX, 0, IncludeNewH));
-      if (Err)
-        llvm::errs() << llvm::toString(std::move(Err)) << "\n";
-    }
-
-    auto SI = FilePathToFileID.find(FilePath);
-    // Ignore replacements for new.h/cc.
-    if (SI == FilePathToFileID.end()) continue;
-    llvm::StringRef Code = SM.getBufferData(SI->second);
-    auto Style = format::getStyle(format::DefaultFormatStyle, FilePath,
-                                  Context->FallbackStyle);
-    if (!Style) {
-      llvm::errs() << llvm::toString(Style.takeError()) << "\n";
-      continue;
-    }
-    auto CleanReplacements = format::cleanupAroundReplacements(
-        Code, Context->FileToReplacements[FilePath], *Style);
-
-    if (!CleanReplacements) {
-      llvm::errs() << llvm::toString(CleanReplacements.takeError()) << "\n";
-      continue;
-    }
-    Context->FileToReplacements[FilePath] = *CleanReplacements;
-  }
-}
-
-void ClangMoveTool::moveDeclsToNewFiles() {
-  std::vector<const NamedDecl *> NewHeaderDecls;
-  std::vector<const NamedDecl *> NewCCDecls;
-  for (const auto *MovedDecl : MovedDecls) {
-    if (isInHeaderFile(MovedDecl, Context->OriginalRunningDirectory,
-                       Context->Spec.OldHeader))
-      NewHeaderDecls.push_back(MovedDecl);
-    else
-      NewCCDecls.push_back(MovedDecl);
-  }
-
-  auto UsedDecls = getUsedDecls(RGBuilder.getGraph(), RemovedDecls);
-  std::vector<const NamedDecl *> ActualNewCCDecls;
-
-  // Filter out all unused helpers in NewCCDecls.
-  // We only move the used helpers (including transively used helpers) and the
-  // given symbols being moved.
-  for (const auto *D : NewCCDecls) {
-    if (llvm::is_contained(HelperDeclarations, D) &&
-        !UsedDecls.count(HelperDeclRGBuilder::getOutmostClassOrFunDecl(
-            D->getCanonicalDecl())))
-      continue;
-
-    LLVM_DEBUG(llvm::dbgs() << "Helper used in new.cc: " << D->getNameAsString()
-                            << " " << D << "\n");
-    ActualNewCCDecls.push_back(D);
-  }
-
-  if (!Context->Spec.NewHeader.empty()) {
-    std::string OldHeaderInclude =
-        Context->Spec.NewDependOnOld
-            ? "#include \"" + Context->Spec.OldHeader + "\"\n"
-            : "";
-    Context->FileToReplacements[Context->Spec.NewHeader] =
-        createInsertedReplacements(HeaderIncludes, NewHeaderDecls,
-                                   Context->Spec.NewHeader, /*IsHeader=*/true,
-                                   OldHeaderInclude);
-  }
-  if (!Context->Spec.NewCC.empty())
-    Context->FileToReplacements[Context->Spec.NewCC] =
-        createInsertedReplacements(CCIncludes, ActualNewCCDecls,
-                                   Context->Spec.NewCC);
-}
-
-// Move all contents from OldFile to NewFile.
-void ClangMoveTool::moveAll(SourceManager &SM, StringRef OldFile,
-                            StringRef NewFile) {
-  const FileEntry *FE = SM.getFileManager().getFile(makeAbsolutePath(OldFile));
-  if (!FE) {
-    llvm::errs() << "Failed to get file: " << OldFile << "\n";
-    return;
-  }
-  FileID ID = SM.getOrCreateFileID(FE, SrcMgr::C_User);
-  auto Begin = SM.getLocForStartOfFile(ID);
-  auto End = SM.getLocForEndOfFile(ID);
-  tooling::Replacement RemoveAll(SM, CharSourceRange::getCharRange(Begin, End),
-                                 "");
-  std::string FilePath = RemoveAll.getFilePath().str();
-  Context->FileToReplacements[FilePath] = tooling::Replacements(RemoveAll);
-
-  StringRef Code = SM.getBufferData(ID);
-  if (!NewFile.empty()) {
-    auto AllCode =
-        tooling::Replacements(tooling::Replacement(NewFile, 0, 0, Code));
-    auto ReplaceOldInclude = [&](CharSourceRange OldHeaderIncludeRange) {
-      AllCode = AllCode.merge(tooling::Replacements(tooling::Replacement(
-          SM, OldHeaderIncludeRange, '"' + Context->Spec.NewHeader + '"')));
-    };
-    // Fix the case where old.h/old.cc includes "old.h", we replace the
-    // `#include "old.h"` with `#include "new.h"`.
-    if (Context->Spec.NewCC == NewFile && OldHeaderIncludeRangeInCC.isValid())
-      ReplaceOldInclude(OldHeaderIncludeRangeInCC);
-    else if (Context->Spec.NewHeader == NewFile &&
-             OldHeaderIncludeRangeInHeader.isValid())
-      ReplaceOldInclude(OldHeaderIncludeRangeInHeader);
-    Context->FileToReplacements[NewFile] = std::move(AllCode);
-  }
-}
-
-void ClangMoveTool::onEndOfTranslationUnit() {
-  if (Context->DumpDeclarations) {
-    assert(Reporter);
-    for (const auto *Decl : UnremovedDeclsInOldHeader) {
-      auto Kind = Decl->getKind();
-      bool Templated = Decl->isTemplated();
-      const std::string QualifiedName = Decl->getQualifiedNameAsString();
-      if (Kind == Decl::Kind::Var)
-        Reporter->reportDeclaration(QualifiedName, "Variable", Templated);
-      else if (Kind == Decl::Kind::Function ||
-               Kind == Decl::Kind::FunctionTemplate)
-        Reporter->reportDeclaration(QualifiedName, "Function", Templated);
-      else if (Kind == Decl::Kind::ClassTemplate ||
-               Kind == Decl::Kind::CXXRecord)
-        Reporter->reportDeclaration(QualifiedName, "Class", Templated);
-      else if (Kind == Decl::Kind::Enum)
-        Reporter->reportDeclaration(QualifiedName, "Enum", Templated);
-      else if (Kind == Decl::Kind::Typedef || Kind == Decl::Kind::TypeAlias ||
-               Kind == Decl::Kind::TypeAliasTemplate)
-        Reporter->reportDeclaration(QualifiedName, "TypeAlias", Templated);
-    }
-    return;
-  }
-
-  if (RemovedDecls.empty())
-    return;
-  // Ignore symbols that are not supported when checking if there is unremoved
-  // symbol in old header. This makes sure that we always move old files to new
-  // files when all symbols produced from dump_decls are moved.
-  auto IsSupportedKind = [](const NamedDecl *Decl) {
-    switch (Decl->getKind()) {
-    case Decl::Kind::Function:
-    case Decl::Kind::FunctionTemplate:
-    case Decl::Kind::ClassTemplate:
-    case Decl::Kind::CXXRecord:
-    case Decl::Kind::Enum:
-    case Decl::Kind::Typedef:
-    case Decl::Kind::TypeAlias:
-    case Decl::Kind::TypeAliasTemplate:
-    case Decl::Kind::Var:
-      return true;
-    default:
-      return false;
-    }
-  };
-  if (std::none_of(UnremovedDeclsInOldHeader.begin(),
-                   UnremovedDeclsInOldHeader.end(), IsSupportedKind) &&
-      !Context->Spec.OldHeader.empty()) {
-    auto &SM = RemovedDecls[0]->getASTContext().getSourceManager();
-    moveAll(SM, Context->Spec.OldHeader, Context->Spec.NewHeader);
-    moveAll(SM, Context->Spec.OldCC, Context->Spec.NewCC);
-    return;
-  }
-  LLVM_DEBUG(RGBuilder.getGraph()->dump());
-  moveDeclsToNewFiles();
-  removeDeclsInOldFiles();
-}
-
-} // namespace move
-} // namespace clang

Removed: clang-tools-extra/trunk/clang-move/ClangMove.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-move/ClangMove.h?rev=356779&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-move/ClangMove.h (original)
+++ clang-tools-extra/trunk/clang-move/ClangMove.h (removed)
@@ -1,240 +0,0 @@
-//===-- ClangMove.h - Clang move  -----------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_MOVE_CLANGMOVE_H
-#define LLVM_CLANG_TOOLS_EXTRA_CLANG_MOVE_CLANGMOVE_H
-
-#include "HelperDeclRefGraph.h"
-#include "clang/ASTMatchers/ASTMatchFinder.h"
-#include "clang/Frontend/FrontendAction.h"
-#include "clang/Tooling/Core/Replacement.h"
-#include "clang/Tooling/Tooling.h"
-#include "llvm/ADT/SmallPtrSet.h"
-#include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/StringRef.h"
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-namespace clang {
-namespace move {
-
-// A reporter which collects and reports declarations in old header.
-class DeclarationReporter {
-public:
-  DeclarationReporter() = default;
-  ~DeclarationReporter() = default;
-
-  void reportDeclaration(llvm::StringRef DeclarationName, llvm::StringRef Type,
-                         bool Templated) {
-    DeclarationList.emplace_back(DeclarationName, Type, Templated);
-  };
-
-  struct Declaration {
-    Declaration(llvm::StringRef QName, llvm::StringRef Kind, bool Templated)
-        : QualifiedName(QName), Kind(Kind), Templated(Templated) {}
-
-    friend bool operator==(const Declaration &LHS, const Declaration &RHS) {
-      return std::tie(LHS.QualifiedName, LHS.Kind, LHS.Templated) ==
-             std::tie(RHS.QualifiedName, RHS.Kind, RHS.Templated);
-    }
-    std::string QualifiedName; // E.g. A::B::Foo.
-    std::string Kind;          // E.g. Function, Class
-    bool Templated = false;    // Whether the declaration is templated.
-  };
-
-  const std::vector<Declaration> getDeclarationList() const {
-    return DeclarationList;
-  }
-
-private:
-  std::vector<Declaration> DeclarationList;
-};
-
-// Specify declarations being moved. It contains all information of the moved
-// declarations.
-struct MoveDefinitionSpec {
-  // The list of fully qualified names, e.g. Foo, a::Foo, b::Foo.
-  SmallVector<std::string, 4> Names;
-  // The file path of old header, can be relative path and absolute path.
-  std::string OldHeader;
-  // The file path of old cc, can be relative path and absolute path.
-  std::string OldCC;
-  // The file path of new header, can be relative path and absolute path.
-  std::string NewHeader;
-  // The file path of new cc, can be relative path and absolute path.
-  std::string NewCC;
-  // Whether old.h depends on new.h. If true, #include "new.h" will be added
-  // in old.h.
-  bool OldDependOnNew = false;
-  // Whether new.h depends on old.h. If true, #include "old.h" will be added
-  // in new.h.
-  bool NewDependOnOld = false;
-};
-
-// A Context which contains extra options which are used in ClangMoveTool.
-struct ClangMoveContext {
-  MoveDefinitionSpec Spec;
-  // The Key is file path, value is the replacements being applied to the file.
-  std::map<std::string, tooling::Replacements> &FileToReplacements;
-  // The original working directory where the local clang-move binary runs.
-  //
-  // clang-move will change its current working directory to the build
-  // directory when analyzing the source file. We save the original working
-  // directory in order to get the absolute file path for the fields in Spec.
-  std::string OriginalRunningDirectory;
-  // The name of a predefined code style.
-  std::string FallbackStyle;
-  // Whether dump all declarations in old header.
-  bool DumpDeclarations;
-};
-
-// This tool is used to move class/function definitions from the given source
-// files (old.h/cc) to new files (new.h/cc).
-// The goal of this tool is to make the new/old files as compilable as possible.
-//
-// When moving a symbol,all used helper declarations (e.g. static
-// functions/variables definitions in global/named namespace,
-// functions/variables/classes definitions in anonymous namespace) used by the
-// moved symbol in old.cc are moved to the new.cc. In addition, all
-// using-declarations in old.cc are also moved to new.cc; forward class
-// declarations in old.h are also moved to new.h.
-//
-// The remaining helper declarations which are unused by non-moved symbols in
-// old.cc will be removed.
-//
-// Note: When all declarations in old header are being moved, all code in
-// old.h/cc will be moved, which means old.h/cc are empty. This ignores symbols
-// that are not supported (e.g. typedef and enum) so that we always move old
-// files to new files when all symbols produced from dump_decls are moved.
-class ClangMoveTool : public ast_matchers::MatchFinder::MatchCallback {
-public:
-  ClangMoveTool(ClangMoveContext *const Context,
-                DeclarationReporter *const Reporter);
-
-  void registerMatchers(ast_matchers::MatchFinder *Finder);
-
-  void run(const ast_matchers::MatchFinder::MatchResult &Result) override;
-
-  void onEndOfTranslationUnit() override;
-
-  /// Add #includes from old.h/cc files.
-  ///
-  /// \param IncludeHeader The name of the file being included, as written in
-  /// the source code.
-  /// \param IsAngled Whether the file name was enclosed in angle brackets.
-  /// \param SearchPath The search path which was used to find the IncludeHeader
-  /// in the file system. It can be a relative path or an absolute path.
-  /// \param FileName The name of file where the IncludeHeader comes from.
-  /// \param IncludeFilenameRange The source range for the written file name in
-  /// #include (i.e. "old.h" for #include "old.h") in old.cc.
-  /// \param SM The SourceManager.
-  void addIncludes(llvm::StringRef IncludeHeader, bool IsAngled,
-                   llvm::StringRef SearchPath, llvm::StringRef FileName,
-                   clang::CharSourceRange IncludeFilenameRange,
-                   const SourceManager &SM);
-
-  std::vector<const NamedDecl *> &getMovedDecls() { return MovedDecls; }
-
-  /// Add declarations being removed from old.h/cc. For each declarations, the
-  /// method also records the mapping relationship between the corresponding
-  /// FilePath and its FileID.
-  void addRemovedDecl(const NamedDecl *Decl);
-
-  llvm::SmallPtrSet<const NamedDecl *, 8> &getUnremovedDeclsInOldHeader() {
-    return UnremovedDeclsInOldHeader;
-  }
-
-private:
-  // Make the Path absolute using the OrignalRunningDirectory if the Path is not
-  // an absolute path. An empty Path will result in an empty string.
-  std::string makeAbsolutePath(StringRef Path);
-
-  void removeDeclsInOldFiles();
-  void moveDeclsToNewFiles();
-  void moveAll(SourceManager& SM, StringRef OldFile, StringRef NewFile);
-
-  // Stores all MatchCallbacks created by this tool.
-  std::vector<std::unique_ptr<ast_matchers::MatchFinder::MatchCallback>>
-      MatchCallbacks;
-  // Store all potential declarations (decls being moved, forward decls) that
-  // might need to move to new.h/cc. It includes all helper declarations
-  // (include unused ones) by default. The unused ones will be filtered out in
-  // the last stage. Saving in an AST-visited order.
-  std::vector<const NamedDecl *> MovedDecls;
-  // The declarations that needs to be removed in old.cc/h.
-  std::vector<const NamedDecl *> RemovedDecls;
-  // The #includes in old_header.h.
-  std::vector<std::string> HeaderIncludes;
-  // The #includes in old_cc.cc.
-  std::vector<std::string> CCIncludes;
-  // Records all helper declarations (function/variable/class definitions in
-  // anonymous namespaces, static function/variable definitions in global/named
-  // namespaces) in old.cc. saving in an AST-visited order.
-  std::vector<const NamedDecl *> HelperDeclarations;
-  // The unmoved named declarations in old header.
-  llvm::SmallPtrSet<const NamedDecl*, 8> UnremovedDeclsInOldHeader;
-  /// The source range for the written file name in #include (i.e. "old.h" for
-  /// #include "old.h") in old.cc,  including the enclosing quotes or angle
-  /// brackets.
-  clang::CharSourceRange OldHeaderIncludeRangeInCC;
-  /// The source range for the written file name in #include (i.e. "old.h" for
-  /// #include "old.h") in old.h,  including the enclosing quotes or angle
-  /// brackets.
-  clang::CharSourceRange OldHeaderIncludeRangeInHeader;
-  /// Mapping from FilePath to FileID, which can be used in post processes like
-  /// cleanup around replacements.
-  llvm::StringMap<FileID> FilePathToFileID;
-  /// A context contains all running options. It is not owned.
-  ClangMoveContext *const Context;
-  /// A reporter to report all declarations from old header. It is not owned.
-  DeclarationReporter *const Reporter;
-  /// Builder for helper declarations reference graph.
-  HelperDeclRGBuilder RGBuilder;
-};
-
-class ClangMoveAction : public clang::ASTFrontendAction {
-public:
-  ClangMoveAction(ClangMoveContext *const Context,
-                  DeclarationReporter *const Reporter)
-      : MoveTool(Context, Reporter) {
-    MoveTool.registerMatchers(&MatchFinder);
-  }
-
-  ~ClangMoveAction() override = default;
-
-  std::unique_ptr<clang::ASTConsumer>
-  CreateASTConsumer(clang::CompilerInstance &Compiler,
-                    llvm::StringRef InFile) override;
-
-private:
-  ast_matchers::MatchFinder MatchFinder;
-  ClangMoveTool MoveTool;
-};
-
-class ClangMoveActionFactory : public tooling::FrontendActionFactory {
-public:
-  ClangMoveActionFactory(ClangMoveContext *const Context,
-                         DeclarationReporter *const Reporter = nullptr)
-      : Context(Context), Reporter(Reporter) {}
-
-  clang::FrontendAction *create() override {
-    return new ClangMoveAction(Context, Reporter);
-  }
-
-private:
-  // Not owned.
-  ClangMoveContext *const Context;
-  DeclarationReporter *const Reporter;
-};
-
-} // namespace move
-} // namespace clang
-
-#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_MOVE_CLANGMOVE_H

Modified: clang-tools-extra/trunk/clang-move/HelperDeclRefGraph.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-move/HelperDeclRefGraph.cpp?rev=356780&r1=356779&r2=356780&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-move/HelperDeclRefGraph.cpp (original)
+++ clang-tools-extra/trunk/clang-move/HelperDeclRefGraph.cpp Fri Mar 22 09:34:39 2019
@@ -7,7 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "HelperDeclRefGraph.h"
-#include "ClangMove.h"
+#include "Move.h"
 #include "clang/AST/Decl.h"
 #include "llvm/Support/Debug.h"
 #include <vector>

Added: clang-tools-extra/trunk/clang-move/Move.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-move/Move.cpp?rev=356780&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-move/Move.cpp (added)
+++ clang-tools-extra/trunk/clang-move/Move.cpp Fri Mar 22 09:34:39 2019
@@ -0,0 +1,937 @@
+//===-- Move.cpp - Implement ClangMove functationalities --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Move.h"
+#include "HelperDeclRefGraph.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Format/Format.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Path.h"
+
+#define DEBUG_TYPE "clang-move"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace move {
+namespace {
+
+// FIXME: Move to ASTMatchers.
+AST_MATCHER(VarDecl, isStaticDataMember) { return Node.isStaticDataMember(); }
+
+AST_MATCHER(NamedDecl, notInMacro) { return !Node.getLocation().isMacroID(); }
+
+AST_MATCHER_P(Decl, hasOutermostEnclosingClass,
+              ast_matchers::internal::Matcher<Decl>, InnerMatcher) {
+  const auto *Context = Node.getDeclContext();
+  if (!Context)
+    return false;
+  while (const auto *NextContext = Context->getParent()) {
+    if (isa<NamespaceDecl>(NextContext) ||
+        isa<TranslationUnitDecl>(NextContext))
+      break;
+    Context = NextContext;
+  }
+  return InnerMatcher.matches(*Decl::castFromDeclContext(Context), Finder,
+                              Builder);
+}
+
+AST_MATCHER_P(CXXMethodDecl, ofOutermostEnclosingClass,
+              ast_matchers::internal::Matcher<CXXRecordDecl>, InnerMatcher) {
+  const CXXRecordDecl *Parent = Node.getParent();
+  if (!Parent)
+    return false;
+  while (const auto *NextParent =
+             dyn_cast<CXXRecordDecl>(Parent->getParent())) {
+    Parent = NextParent;
+  }
+
+  return InnerMatcher.matches(*Parent, Finder, Builder);
+}
+
+std::string CleanPath(StringRef PathRef) {
+  llvm::SmallString<128> Path(PathRef);
+  llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
+  // FIXME: figure out why this is necessary.
+  llvm::sys::path::native(Path);
+  return Path.str();
+}
+
+// Make the Path absolute using the CurrentDir if the Path is not an absolute
+// path. An empty Path will result in an empty string.
+std::string MakeAbsolutePath(StringRef CurrentDir, StringRef Path) {
+  if (Path.empty())
+    return "";
+  llvm::SmallString<128> InitialDirectory(CurrentDir);
+  llvm::SmallString<128> AbsolutePath(Path);
+  llvm::sys::fs::make_absolute(InitialDirectory, AbsolutePath);
+  return CleanPath(std::move(AbsolutePath));
+}
+
+// Make the Path absolute using the current working directory of the given
+// SourceManager if the Path is not an absolute path.
+//
+// The Path can be a path relative to the build directory, or retrieved from
+// the SourceManager.
+std::string MakeAbsolutePath(const SourceManager &SM, StringRef Path) {
+  llvm::SmallString<128> AbsolutePath(Path);
+  if (std::error_code EC =
+          SM.getFileManager().getVirtualFileSystem()->makeAbsolute(
+              AbsolutePath))
+    llvm::errs() << "Warning: could not make absolute file: '" << EC.message()
+                 << '\n';
+  // Handle symbolic link path cases.
+  // We are trying to get the real file path of the symlink.
+  const DirectoryEntry *Dir = SM.getFileManager().getDirectory(
+      llvm::sys::path::parent_path(AbsolutePath.str()));
+  if (Dir) {
+    StringRef DirName = SM.getFileManager().getCanonicalName(Dir);
+    // FIXME: getCanonicalName might fail to get real path on VFS.
+    if (llvm::sys::path::is_absolute(DirName)) {
+      SmallString<128> AbsoluteFilename;
+      llvm::sys::path::append(AbsoluteFilename, DirName,
+                              llvm::sys::path::filename(AbsolutePath.str()));
+      return CleanPath(AbsoluteFilename);
+    }
+  }
+  return CleanPath(AbsolutePath);
+}
+
+// Matches AST nodes that are expanded within the given AbsoluteFilePath.
+AST_POLYMORPHIC_MATCHER_P(isExpansionInFile,
+                          AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt, TypeLoc),
+                          std::string, AbsoluteFilePath) {
+  auto &SourceManager = Finder->getASTContext().getSourceManager();
+  auto ExpansionLoc = SourceManager.getExpansionLoc(Node.getBeginLoc());
+  if (ExpansionLoc.isInvalid())
+    return false;
+  auto FileEntry =
+      SourceManager.getFileEntryForID(SourceManager.getFileID(ExpansionLoc));
+  if (!FileEntry)
+    return false;
+  return MakeAbsolutePath(SourceManager, FileEntry->getName()) ==
+         AbsoluteFilePath;
+}
+
+class FindAllIncludes : public PPCallbacks {
+public:
+  explicit FindAllIncludes(SourceManager *SM, ClangMoveTool *const MoveTool)
+      : SM(*SM), MoveTool(MoveTool) {}
+
+  void InclusionDirective(SourceLocation HashLoc, const Token & /*IncludeTok*/,
+                          StringRef FileName, bool IsAngled,
+                          CharSourceRange FilenameRange,
+                          const FileEntry * /*File*/, StringRef SearchPath,
+                          StringRef /*RelativePath*/,
+                          const Module * /*Imported*/,
+                          SrcMgr::CharacteristicKind /*FileType*/) override {
+    if (const auto *FileEntry = SM.getFileEntryForID(SM.getFileID(HashLoc)))
+      MoveTool->addIncludes(FileName, IsAngled, SearchPath,
+                            FileEntry->getName(), FilenameRange, SM);
+  }
+
+private:
+  const SourceManager &SM;
+  ClangMoveTool *const MoveTool;
+};
+
+/// Add a declatration being moved to new.h/cc. Note that the declaration will
+/// also be deleted in old.h/cc.
+void MoveDeclFromOldFileToNewFile(ClangMoveTool *MoveTool, const NamedDecl *D) {
+  MoveTool->getMovedDecls().push_back(D);
+  MoveTool->addRemovedDecl(D);
+  MoveTool->getUnremovedDeclsInOldHeader().erase(D);
+}
+
+class FunctionDeclarationMatch : public MatchFinder::MatchCallback {
+public:
+  explicit FunctionDeclarationMatch(ClangMoveTool *MoveTool)
+      : MoveTool(MoveTool) {}
+
+  void run(const MatchFinder::MatchResult &Result) override {
+    const auto *FD = Result.Nodes.getNodeAs<FunctionDecl>("function");
+    assert(FD);
+    const NamedDecl *D = FD;
+    if (const auto *FTD = FD->getDescribedFunctionTemplate())
+      D = FTD;
+    MoveDeclFromOldFileToNewFile(MoveTool, D);
+  }
+
+private:
+  ClangMoveTool *MoveTool;
+};
+
+class VarDeclarationMatch : public MatchFinder::MatchCallback {
+public:
+  explicit VarDeclarationMatch(ClangMoveTool *MoveTool)
+      : MoveTool(MoveTool) {}
+
+  void run(const MatchFinder::MatchResult &Result) override {
+    const auto *VD = Result.Nodes.getNodeAs<VarDecl>("var");
+    assert(VD);
+    MoveDeclFromOldFileToNewFile(MoveTool, VD);
+  }
+
+private:
+  ClangMoveTool *MoveTool;
+};
+
+class TypeAliasMatch : public MatchFinder::MatchCallback {
+public:
+  explicit TypeAliasMatch(ClangMoveTool *MoveTool)
+      : MoveTool(MoveTool) {}
+
+  void run(const MatchFinder::MatchResult &Result) override {
+    if (const auto *TD = Result.Nodes.getNodeAs<TypedefDecl>("typedef"))
+      MoveDeclFromOldFileToNewFile(MoveTool, TD);
+    else if (const auto *TAD =
+                 Result.Nodes.getNodeAs<TypeAliasDecl>("type_alias")) {
+      const NamedDecl * D = TAD;
+      if (const auto * TD = TAD->getDescribedAliasTemplate())
+        D = TD;
+      MoveDeclFromOldFileToNewFile(MoveTool, D);
+    }
+  }
+
+private:
+  ClangMoveTool *MoveTool;
+};
+
+class EnumDeclarationMatch : public MatchFinder::MatchCallback {
+public:
+  explicit EnumDeclarationMatch(ClangMoveTool *MoveTool)
+      : MoveTool(MoveTool) {}
+
+  void run(const MatchFinder::MatchResult &Result) override {
+    const auto *ED = Result.Nodes.getNodeAs<EnumDecl>("enum");
+    assert(ED);
+    MoveDeclFromOldFileToNewFile(MoveTool, ED);
+  }
+
+private:
+  ClangMoveTool *MoveTool;
+};
+
+class ClassDeclarationMatch : public MatchFinder::MatchCallback {
+public:
+  explicit ClassDeclarationMatch(ClangMoveTool *MoveTool)
+      : MoveTool(MoveTool) {}
+  void run(const MatchFinder::MatchResult &Result) override {
+    SourceManager *SM = &Result.Context->getSourceManager();
+    if (const auto *CMD = Result.Nodes.getNodeAs<CXXMethodDecl>("class_method"))
+      MatchClassMethod(CMD, SM);
+    else if (const auto *VD =
+                 Result.Nodes.getNodeAs<VarDecl>("class_static_var_decl"))
+      MatchClassStaticVariable(VD, SM);
+    else if (const auto *CD =
+                 Result.Nodes.getNodeAs<CXXRecordDecl>("moved_class"))
+      MatchClassDeclaration(CD, SM);
+  }
+
+private:
+  void MatchClassMethod(const CXXMethodDecl *CMD, SourceManager *SM) {
+    // Skip inline class methods. isInline() ast matcher doesn't ignore this
+    // case.
+    if (!CMD->isInlined()) {
+      MoveTool->getMovedDecls().push_back(CMD);
+      MoveTool->addRemovedDecl(CMD);
+      // Get template class method from its method declaration as
+      // UnremovedDecls stores template class method.
+      if (const auto *FTD = CMD->getDescribedFunctionTemplate())
+        MoveTool->getUnremovedDeclsInOldHeader().erase(FTD);
+      else
+        MoveTool->getUnremovedDeclsInOldHeader().erase(CMD);
+    }
+  }
+
+  void MatchClassStaticVariable(const NamedDecl *VD, SourceManager *SM) {
+    MoveDeclFromOldFileToNewFile(MoveTool, VD);
+  }
+
+  void MatchClassDeclaration(const CXXRecordDecl *CD, SourceManager *SM) {
+    // Get class template from its class declaration as UnremovedDecls stores
+    // class template.
+    if (const auto *TC = CD->getDescribedClassTemplate())
+      MoveTool->getMovedDecls().push_back(TC);
+    else
+      MoveTool->getMovedDecls().push_back(CD);
+    MoveTool->addRemovedDecl(MoveTool->getMovedDecls().back());
+    MoveTool->getUnremovedDeclsInOldHeader().erase(
+        MoveTool->getMovedDecls().back());
+  }
+
+  ClangMoveTool *MoveTool;
+};
+
+// Expand to get the end location of the line where the EndLoc of the given
+// Decl.
+SourceLocation getLocForEndOfDecl(const Decl *D,
+                                  const LangOptions &LangOpts = LangOptions()) {
+  const auto &SM = D->getASTContext().getSourceManager();
+  // If the expansion range is a character range, this is the location of
+  // the first character past the end. Otherwise it's the location of the
+  // first character in the final token in the range.
+  auto EndExpansionLoc = SM.getExpansionRange(D->getEndLoc()).getEnd();
+  std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(EndExpansionLoc);
+  // Try to load the file buffer.
+  bool InvalidTemp = false;
+  llvm::StringRef File = SM.getBufferData(LocInfo.first, &InvalidTemp);
+  if (InvalidTemp)
+    return SourceLocation();
+
+  const char *TokBegin = File.data() + LocInfo.second;
+  // Lex from the start of the given location.
+  Lexer Lex(SM.getLocForStartOfFile(LocInfo.first), LangOpts, File.begin(),
+            TokBegin, File.end());
+
+  llvm::SmallVector<char, 16> Line;
+  // FIXME: this is a bit hacky to get ReadToEndOfLine work.
+  Lex.setParsingPreprocessorDirective(true);
+  Lex.ReadToEndOfLine(&Line);
+  SourceLocation EndLoc = EndExpansionLoc.getLocWithOffset(Line.size());
+  // If we already reach EOF, just return the EOF SourceLocation;
+  // otherwise, move 1 offset ahead to include the trailing newline character
+  // '\n'.
+  return SM.getLocForEndOfFile(LocInfo.first) == EndLoc
+             ? EndLoc
+             : EndLoc.getLocWithOffset(1);
+}
+
+// Get full range of a Decl including the comments associated with it.
+CharSourceRange getFullRange(const Decl *D,
+                             const LangOptions &options = LangOptions()) {
+  const auto &SM = D->getASTContext().getSourceManager();
+  SourceRange Full(SM.getExpansionLoc(D->getBeginLoc()), getLocForEndOfDecl(D));
+  // Expand to comments that are associated with the Decl.
+  if (const auto *Comment = D->getASTContext().getRawCommentForDeclNoCache(D)) {
+    if (SM.isBeforeInTranslationUnit(Full.getEnd(), Comment->getEndLoc()))
+      Full.setEnd(Comment->getEndLoc());
+    // FIXME: Don't delete a preceding comment, if there are no other entities
+    // it could refer to.
+    if (SM.isBeforeInTranslationUnit(Comment->getBeginLoc(), Full.getBegin()))
+      Full.setBegin(Comment->getBeginLoc());
+  }
+
+  return CharSourceRange::getCharRange(Full);
+}
+
+std::string getDeclarationSourceText(const Decl *D) {
+  const auto &SM = D->getASTContext().getSourceManager();
+  llvm::StringRef SourceText =
+      Lexer::getSourceText(getFullRange(D), SM, LangOptions());
+  return SourceText.str();
+}
+
+bool isInHeaderFile(const Decl *D, llvm::StringRef OriginalRunningDirectory,
+                    llvm::StringRef OldHeader) {
+  const auto &SM = D->getASTContext().getSourceManager();
+  if (OldHeader.empty())
+    return false;
+  auto ExpansionLoc = SM.getExpansionLoc(D->getBeginLoc());
+  if (ExpansionLoc.isInvalid())
+    return false;
+
+  if (const auto *FE = SM.getFileEntryForID(SM.getFileID(ExpansionLoc))) {
+    return MakeAbsolutePath(SM, FE->getName()) ==
+           MakeAbsolutePath(OriginalRunningDirectory, OldHeader);
+  }
+
+  return false;
+}
+
+std::vector<std::string> getNamespaces(const Decl *D) {
+  std::vector<std::string> Namespaces;
+  for (const auto *Context = D->getDeclContext(); Context;
+       Context = Context->getParent()) {
+    if (llvm::isa<TranslationUnitDecl>(Context) ||
+        llvm::isa<LinkageSpecDecl>(Context))
+      break;
+
+    if (const auto *ND = llvm::dyn_cast<NamespaceDecl>(Context))
+      Namespaces.push_back(ND->getName().str());
+  }
+  std::reverse(Namespaces.begin(), Namespaces.end());
+  return Namespaces;
+}
+
+tooling::Replacements
+createInsertedReplacements(const std::vector<std::string> &Includes,
+                           const std::vector<const NamedDecl *> &Decls,
+                           llvm::StringRef FileName, bool IsHeader = false,
+                           StringRef OldHeaderInclude = "") {
+  std::string NewCode;
+  std::string GuardName(FileName);
+  if (IsHeader) {
+    for (size_t i = 0; i < GuardName.size(); ++i) {
+      if (!isAlphanumeric(GuardName[i]))
+        GuardName[i] = '_';
+    }
+    GuardName = StringRef(GuardName).upper();
+    NewCode += "#ifndef " + GuardName + "\n";
+    NewCode += "#define " + GuardName + "\n\n";
+  }
+
+  NewCode += OldHeaderInclude;
+  // Add #Includes.
+  for (const auto &Include : Includes)
+    NewCode += Include;
+
+  if (!Includes.empty())
+    NewCode += "\n";
+
+  // Add moved class definition and its related declarations. All declarations
+  // in same namespace are grouped together.
+  //
+  // Record namespaces where the current position is in.
+  std::vector<std::string> CurrentNamespaces;
+  for (const auto *MovedDecl : Decls) {
+    // The namespaces of the declaration being moved.
+    std::vector<std::string> DeclNamespaces = getNamespaces(MovedDecl);
+    auto CurrentIt = CurrentNamespaces.begin();
+    auto DeclIt = DeclNamespaces.begin();
+    // Skip the common prefix.
+    while (CurrentIt != CurrentNamespaces.end() &&
+           DeclIt != DeclNamespaces.end()) {
+      if (*CurrentIt != *DeclIt)
+        break;
+      ++CurrentIt;
+      ++DeclIt;
+    }
+    // Calculate the new namespaces after adding MovedDecl in CurrentNamespace,
+    // which is used for next iteration of this loop.
+    std::vector<std::string> NextNamespaces(CurrentNamespaces.begin(),
+                                            CurrentIt);
+    NextNamespaces.insert(NextNamespaces.end(), DeclIt, DeclNamespaces.end());
+
+
+    // End with CurrentNamespace.
+    bool HasEndCurrentNamespace = false;
+    auto RemainingSize = CurrentNamespaces.end() - CurrentIt;
+    for (auto It = CurrentNamespaces.rbegin(); RemainingSize > 0;
+         --RemainingSize, ++It) {
+      assert(It < CurrentNamespaces.rend());
+      NewCode += "} // namespace " + *It + "\n";
+      HasEndCurrentNamespace = true;
+    }
+    // Add trailing '\n' after the nested namespace definition.
+    if (HasEndCurrentNamespace)
+      NewCode += "\n";
+
+    // If the moved declaration is not in CurrentNamespace, add extra namespace
+    // definitions.
+    bool IsInNewNamespace = false;
+    while (DeclIt != DeclNamespaces.end()) {
+      NewCode += "namespace " + *DeclIt + " {\n";
+      IsInNewNamespace = true;
+      ++DeclIt;
+    }
+    // If the moved declaration is in same namespace CurrentNamespace, add
+    // a preceeding `\n' before the moved declaration.
+    // FIXME: Don't add empty lines between using declarations.
+    if (!IsInNewNamespace)
+      NewCode += "\n";
+    NewCode += getDeclarationSourceText(MovedDecl);
+    CurrentNamespaces = std::move(NextNamespaces);
+  }
+  std::reverse(CurrentNamespaces.begin(), CurrentNamespaces.end());
+  for (const auto &NS : CurrentNamespaces)
+    NewCode += "} // namespace " + NS + "\n";
+
+  if (IsHeader)
+    NewCode += "\n#endif // " + GuardName + "\n";
+  return tooling::Replacements(tooling::Replacement(FileName, 0, 0, NewCode));
+}
+
+// Return a set of all decls which are used/referenced by the given Decls.
+// Specically, given a class member declaration, this method will return all
+// decls which are used by the whole class.
+llvm::DenseSet<const Decl *>
+getUsedDecls(const HelperDeclRefGraph *RG,
+             const std::vector<const NamedDecl *> &Decls) {
+  assert(RG);
+  llvm::DenseSet<const CallGraphNode *> Nodes;
+  for (const auto *D : Decls) {
+    auto Result = RG->getReachableNodes(
+        HelperDeclRGBuilder::getOutmostClassOrFunDecl(D));
+    Nodes.insert(Result.begin(), Result.end());
+  }
+  llvm::DenseSet<const Decl *> Results;
+  for (const auto *Node : Nodes)
+    Results.insert(Node->getDecl());
+  return Results;
+}
+
+} // namespace
+
+std::unique_ptr<ASTConsumer>
+ClangMoveAction::CreateASTConsumer(CompilerInstance &Compiler,
+                                   StringRef /*InFile*/) {
+  Compiler.getPreprocessor().addPPCallbacks(llvm::make_unique<FindAllIncludes>(
+      &Compiler.getSourceManager(), &MoveTool));
+  return MatchFinder.newASTConsumer();
+}
+
+ClangMoveTool::ClangMoveTool(ClangMoveContext *const Context,
+                             DeclarationReporter *const Reporter)
+    : Context(Context), Reporter(Reporter) {
+  if (!Context->Spec.NewHeader.empty())
+    CCIncludes.push_back("#include \"" + Context->Spec.NewHeader + "\"\n");
+}
+
+void ClangMoveTool::addRemovedDecl(const NamedDecl *Decl) {
+  const auto &SM = Decl->getASTContext().getSourceManager();
+  auto Loc = Decl->getLocation();
+  StringRef FilePath = SM.getFilename(Loc);
+  FilePathToFileID[FilePath] = SM.getFileID(Loc);
+  RemovedDecls.push_back(Decl);
+}
+
+void ClangMoveTool::registerMatchers(ast_matchers::MatchFinder *Finder) {
+  auto InOldHeader =
+      isExpansionInFile(makeAbsolutePath(Context->Spec.OldHeader));
+  auto InOldCC = isExpansionInFile(makeAbsolutePath(Context->Spec.OldCC));
+  auto InOldFiles = anyOf(InOldHeader, InOldCC);
+  auto classTemplateForwardDecls =
+      classTemplateDecl(unless(has(cxxRecordDecl(isDefinition()))));
+  auto ForwardClassDecls = namedDecl(
+      anyOf(cxxRecordDecl(unless(anyOf(isImplicit(), isDefinition()))),
+            classTemplateForwardDecls));
+  auto TopLevelDecl =
+      hasDeclContext(anyOf(namespaceDecl(), translationUnitDecl()));
+
+  //============================================================================
+  // Matchers for old header
+  //============================================================================
+  // Match all top-level named declarations (e.g. function, variable, enum) in
+  // old header, exclude forward class declarations and namespace declarations.
+  //
+  // We consider declarations inside a class belongs to the class. So these
+  // declarations will be ignored.
+  auto AllDeclsInHeader = namedDecl(
+      unless(ForwardClassDecls), unless(namespaceDecl()),
+      unless(usingDirectiveDecl()), // using namespace decl.
+      notInMacro(),
+      InOldHeader,
+      hasParent(decl(anyOf(namespaceDecl(), translationUnitDecl()))),
+      hasDeclContext(decl(anyOf(namespaceDecl(), translationUnitDecl()))));
+  Finder->addMatcher(AllDeclsInHeader.bind("decls_in_header"), this);
+
+  // Don't register other matchers when dumping all declarations in header.
+  if (Context->DumpDeclarations)
+    return;
+
+  // Match forward declarations in old header.
+  Finder->addMatcher(namedDecl(ForwardClassDecls, InOldHeader).bind("fwd_decl"),
+                     this);
+
+  //============================================================================
+  // Matchers for old cc
+  //============================================================================
+  auto IsOldCCTopLevelDecl = allOf(
+      hasParent(decl(anyOf(namespaceDecl(), translationUnitDecl()))), InOldCC);
+  // Matching using decls/type alias decls which are in named/anonymous/global
+  // namespace, these decls are always copied to new.h/cc. Those in classes,
+  // functions are covered in other matchers.
+  Finder->addMatcher(namedDecl(anyOf(usingDecl(IsOldCCTopLevelDecl),
+                                     usingDirectiveDecl(unless(isImplicit()),
+                                                        IsOldCCTopLevelDecl),
+                                     typeAliasDecl(IsOldCCTopLevelDecl)),
+                               notInMacro())
+                         .bind("using_decl"),
+                     this);
+
+  // Match static functions/variable definitions which are defined in named
+  // namespaces.
+  Optional<ast_matchers::internal::Matcher<NamedDecl>> HasAnySymbolNames;
+  for (StringRef SymbolName : Context->Spec.Names) {
+    llvm::StringRef GlobalSymbolName = SymbolName.trim().ltrim(':');
+    const auto HasName = hasName(("::" + GlobalSymbolName).str());
+    HasAnySymbolNames =
+        HasAnySymbolNames ? anyOf(*HasAnySymbolNames, HasName) : HasName;
+  }
+
+  if (!HasAnySymbolNames) {
+    llvm::errs() << "No symbols being moved.\n";
+    return;
+  }
+  auto InMovedClass =
+      hasOutermostEnclosingClass(cxxRecordDecl(*HasAnySymbolNames));
+
+  // Matchers for helper declarations in old.cc.
+  auto InAnonymousNS = hasParent(namespaceDecl(isAnonymous()));
+  auto NotInMovedClass= allOf(unless(InMovedClass), InOldCC);
+  auto IsOldCCHelper =
+      allOf(NotInMovedClass, anyOf(isStaticStorageClass(), InAnonymousNS));
+  // Match helper classes separately with helper functions/variables since we
+  // want to reuse these matchers in finding helpers usage below.
+  //
+  // There could be forward declarations usage for helpers, especially for
+  // classes and functions. We need include these forward declarations.
+  //
+  // Forward declarations for variable helpers will be excluded as these
+  // declarations (with "extern") are not supposed in cpp file.
+   auto HelperFuncOrVar =
+      namedDecl(notInMacro(), anyOf(functionDecl(IsOldCCHelper),
+                                    varDecl(isDefinition(), IsOldCCHelper)));
+  auto HelperClasses =
+      cxxRecordDecl(notInMacro(), NotInMovedClass, InAnonymousNS);
+  // Save all helper declarations in old.cc.
+  Finder->addMatcher(
+      namedDecl(anyOf(HelperFuncOrVar, HelperClasses)).bind("helper_decls"),
+      this);
+
+  // Construct an AST-based call graph of helper declarations in old.cc.
+  // In the following matcheres, "dc" is a caller while "helper_decls" and
+  // "used_class" is a callee, so a new edge starting from caller to callee will
+  // be add in the graph.
+  //
+  // Find helper function/variable usages.
+  Finder->addMatcher(
+      declRefExpr(to(HelperFuncOrVar), hasAncestor(decl().bind("dc")))
+          .bind("func_ref"),
+      &RGBuilder);
+  // Find helper class usages.
+  Finder->addMatcher(
+      typeLoc(loc(recordType(hasDeclaration(HelperClasses.bind("used_class")))),
+              hasAncestor(decl().bind("dc"))),
+      &RGBuilder);
+
+  //============================================================================
+  // Matchers for old files, including old.h/old.cc
+  //============================================================================
+  // Create a MatchCallback for class declarations.
+  MatchCallbacks.push_back(llvm::make_unique<ClassDeclarationMatch>(this));
+  // Match moved class declarations.
+  auto MovedClass = cxxRecordDecl(InOldFiles, *HasAnySymbolNames,
+                                  isDefinition(), TopLevelDecl)
+                        .bind("moved_class");
+  Finder->addMatcher(MovedClass, MatchCallbacks.back().get());
+  // Match moved class methods (static methods included) which are defined
+  // outside moved class declaration.
+  Finder->addMatcher(
+      cxxMethodDecl(InOldFiles, ofOutermostEnclosingClass(*HasAnySymbolNames),
+                    isDefinition())
+          .bind("class_method"),
+      MatchCallbacks.back().get());
+  // Match static member variable definition of the moved class.
+  Finder->addMatcher(
+      varDecl(InMovedClass, InOldFiles, isDefinition(), isStaticDataMember())
+          .bind("class_static_var_decl"),
+      MatchCallbacks.back().get());
+
+  MatchCallbacks.push_back(llvm::make_unique<FunctionDeclarationMatch>(this));
+  Finder->addMatcher(functionDecl(InOldFiles, *HasAnySymbolNames, TopLevelDecl)
+                         .bind("function"),
+                     MatchCallbacks.back().get());
+
+  MatchCallbacks.push_back(llvm::make_unique<VarDeclarationMatch>(this));
+  Finder->addMatcher(
+      varDecl(InOldFiles, *HasAnySymbolNames, TopLevelDecl).bind("var"),
+      MatchCallbacks.back().get());
+
+  // Match enum definition in old.h. Enum helpers (which are defined in old.cc)
+  // will not be moved for now no matter whether they are used or not.
+  MatchCallbacks.push_back(llvm::make_unique<EnumDeclarationMatch>(this));
+  Finder->addMatcher(
+      enumDecl(InOldHeader, *HasAnySymbolNames, isDefinition(), TopLevelDecl)
+          .bind("enum"),
+      MatchCallbacks.back().get());
+
+  // Match type alias in old.h, this includes "typedef" and "using" type alias
+  // declarations. Type alias helpers (which are defined in old.cc) will not be
+  // moved for now no matter whether they are used or not.
+  MatchCallbacks.push_back(llvm::make_unique<TypeAliasMatch>(this));
+  Finder->addMatcher(namedDecl(anyOf(typedefDecl().bind("typedef"),
+                                     typeAliasDecl().bind("type_alias")),
+                               InOldHeader, *HasAnySymbolNames, TopLevelDecl),
+                     MatchCallbacks.back().get());
+}
+
+void ClangMoveTool::run(const ast_matchers::MatchFinder::MatchResult &Result) {
+  if (const auto *D = Result.Nodes.getNodeAs<NamedDecl>("decls_in_header")) {
+    UnremovedDeclsInOldHeader.insert(D);
+  } else if (const auto *FWD =
+                 Result.Nodes.getNodeAs<CXXRecordDecl>("fwd_decl")) {
+    // Skip all forward declarations which appear after moved class declaration.
+    if (RemovedDecls.empty()) {
+      if (const auto *DCT = FWD->getDescribedClassTemplate())
+        MovedDecls.push_back(DCT);
+      else
+        MovedDecls.push_back(FWD);
+    }
+  } else if (const auto *ND =
+                 Result.Nodes.getNodeAs<NamedDecl>("helper_decls")) {
+    MovedDecls.push_back(ND);
+    HelperDeclarations.push_back(ND);
+    LLVM_DEBUG(llvm::dbgs() << "Add helper : " << ND->getNameAsString() << " ("
+                            << ND << ")\n");
+  } else if (const auto *UD = Result.Nodes.getNodeAs<NamedDecl>("using_decl")) {
+    MovedDecls.push_back(UD);
+  }
+}
+
+std::string ClangMoveTool::makeAbsolutePath(StringRef Path) {
+  return MakeAbsolutePath(Context->OriginalRunningDirectory, Path);
+}
+
+void ClangMoveTool::addIncludes(llvm::StringRef IncludeHeader, bool IsAngled,
+                                llvm::StringRef SearchPath,
+                                llvm::StringRef FileName,
+                                CharSourceRange IncludeFilenameRange,
+                                const SourceManager &SM) {
+  SmallVector<char, 128> HeaderWithSearchPath;
+  llvm::sys::path::append(HeaderWithSearchPath, SearchPath, IncludeHeader);
+  std::string AbsoluteIncludeHeader =
+      MakeAbsolutePath(SM, llvm::StringRef(HeaderWithSearchPath.data(),
+                                           HeaderWithSearchPath.size()));
+  std::string IncludeLine =
+      IsAngled ? ("#include <" + IncludeHeader + ">\n").str()
+               : ("#include \"" + IncludeHeader + "\"\n").str();
+
+  std::string AbsoluteOldHeader = makeAbsolutePath(Context->Spec.OldHeader);
+  std::string AbsoluteCurrentFile = MakeAbsolutePath(SM, FileName);
+  if (AbsoluteOldHeader == AbsoluteCurrentFile) {
+    // Find old.h includes "old.h".
+    if (AbsoluteOldHeader == AbsoluteIncludeHeader) {
+      OldHeaderIncludeRangeInHeader = IncludeFilenameRange;
+      return;
+    }
+    HeaderIncludes.push_back(IncludeLine);
+  } else if (makeAbsolutePath(Context->Spec.OldCC) == AbsoluteCurrentFile) {
+    // Find old.cc includes "old.h".
+    if (AbsoluteOldHeader == AbsoluteIncludeHeader) {
+      OldHeaderIncludeRangeInCC = IncludeFilenameRange;
+      return;
+    }
+    CCIncludes.push_back(IncludeLine);
+  }
+}
+
+void ClangMoveTool::removeDeclsInOldFiles() {
+  if (RemovedDecls.empty()) return;
+
+  // If old_header is not specified (only move declarations from old.cc), remain
+  // all the helper function declarations in old.cc as UnremovedDeclsInOldHeader
+  // is empty in this case, there is no way to verify unused/used helpers.
+  if (!Context->Spec.OldHeader.empty()) {
+    std::vector<const NamedDecl *> UnremovedDecls;
+    for (const auto *D : UnremovedDeclsInOldHeader)
+      UnremovedDecls.push_back(D);
+
+    auto UsedDecls = getUsedDecls(RGBuilder.getGraph(), UnremovedDecls);
+
+    // We remove the helper declarations which are not used in the old.cc after
+    // moving the given declarations.
+    for (const auto *D : HelperDeclarations) {
+      LLVM_DEBUG(llvm::dbgs() << "Check helper is used: "
+                              << D->getNameAsString() << " (" << D << ")\n");
+      if (!UsedDecls.count(HelperDeclRGBuilder::getOutmostClassOrFunDecl(
+              D->getCanonicalDecl()))) {
+        LLVM_DEBUG(llvm::dbgs() << "Helper removed in old.cc: "
+                                << D->getNameAsString() << " (" << D << ")\n");
+        RemovedDecls.push_back(D);
+      }
+    }
+  }
+
+  for (const auto *RemovedDecl : RemovedDecls) {
+    const auto &SM = RemovedDecl->getASTContext().getSourceManager();
+    auto Range = getFullRange(RemovedDecl);
+    tooling::Replacement RemoveReplacement(
+        SM, CharSourceRange::getCharRange(Range.getBegin(), Range.getEnd()),
+        "");
+    std::string FilePath = RemoveReplacement.getFilePath().str();
+    auto Err = Context->FileToReplacements[FilePath].add(RemoveReplacement);
+    if (Err)
+      llvm::errs() << llvm::toString(std::move(Err)) << "\n";
+  }
+  const auto &SM = RemovedDecls[0]->getASTContext().getSourceManager();
+
+  // Post process of cleanup around all the replacements.
+  for (auto &FileAndReplacements : Context->FileToReplacements) {
+    StringRef FilePath = FileAndReplacements.first;
+    // Add #include of new header to old header.
+    if (Context->Spec.OldDependOnNew &&
+        MakeAbsolutePath(SM, FilePath) ==
+            makeAbsolutePath(Context->Spec.OldHeader)) {
+      // FIXME: Minimize the include path like include-fixer.
+      std::string IncludeNewH =
+          "#include \"" + Context->Spec.NewHeader + "\"\n";
+      // This replacment for inserting header will be cleaned up at the end.
+      auto Err = FileAndReplacements.second.add(
+          tooling::Replacement(FilePath, UINT_MAX, 0, IncludeNewH));
+      if (Err)
+        llvm::errs() << llvm::toString(std::move(Err)) << "\n";
+    }
+
+    auto SI = FilePathToFileID.find(FilePath);
+    // Ignore replacements for new.h/cc.
+    if (SI == FilePathToFileID.end()) continue;
+    llvm::StringRef Code = SM.getBufferData(SI->second);
+    auto Style = format::getStyle(format::DefaultFormatStyle, FilePath,
+                                  Context->FallbackStyle);
+    if (!Style) {
+      llvm::errs() << llvm::toString(Style.takeError()) << "\n";
+      continue;
+    }
+    auto CleanReplacements = format::cleanupAroundReplacements(
+        Code, Context->FileToReplacements[FilePath], *Style);
+
+    if (!CleanReplacements) {
+      llvm::errs() << llvm::toString(CleanReplacements.takeError()) << "\n";
+      continue;
+    }
+    Context->FileToReplacements[FilePath] = *CleanReplacements;
+  }
+}
+
+void ClangMoveTool::moveDeclsToNewFiles() {
+  std::vector<const NamedDecl *> NewHeaderDecls;
+  std::vector<const NamedDecl *> NewCCDecls;
+  for (const auto *MovedDecl : MovedDecls) {
+    if (isInHeaderFile(MovedDecl, Context->OriginalRunningDirectory,
+                       Context->Spec.OldHeader))
+      NewHeaderDecls.push_back(MovedDecl);
+    else
+      NewCCDecls.push_back(MovedDecl);
+  }
+
+  auto UsedDecls = getUsedDecls(RGBuilder.getGraph(), RemovedDecls);
+  std::vector<const NamedDecl *> ActualNewCCDecls;
+
+  // Filter out all unused helpers in NewCCDecls.
+  // We only move the used helpers (including transively used helpers) and the
+  // given symbols being moved.
+  for (const auto *D : NewCCDecls) {
+    if (llvm::is_contained(HelperDeclarations, D) &&
+        !UsedDecls.count(HelperDeclRGBuilder::getOutmostClassOrFunDecl(
+            D->getCanonicalDecl())))
+      continue;
+
+    LLVM_DEBUG(llvm::dbgs() << "Helper used in new.cc: " << D->getNameAsString()
+                            << " " << D << "\n");
+    ActualNewCCDecls.push_back(D);
+  }
+
+  if (!Context->Spec.NewHeader.empty()) {
+    std::string OldHeaderInclude =
+        Context->Spec.NewDependOnOld
+            ? "#include \"" + Context->Spec.OldHeader + "\"\n"
+            : "";
+    Context->FileToReplacements[Context->Spec.NewHeader] =
+        createInsertedReplacements(HeaderIncludes, NewHeaderDecls,
+                                   Context->Spec.NewHeader, /*IsHeader=*/true,
+                                   OldHeaderInclude);
+  }
+  if (!Context->Spec.NewCC.empty())
+    Context->FileToReplacements[Context->Spec.NewCC] =
+        createInsertedReplacements(CCIncludes, ActualNewCCDecls,
+                                   Context->Spec.NewCC);
+}
+
+// Move all contents from OldFile to NewFile.
+void ClangMoveTool::moveAll(SourceManager &SM, StringRef OldFile,
+                            StringRef NewFile) {
+  const FileEntry *FE = SM.getFileManager().getFile(makeAbsolutePath(OldFile));
+  if (!FE) {
+    llvm::errs() << "Failed to get file: " << OldFile << "\n";
+    return;
+  }
+  FileID ID = SM.getOrCreateFileID(FE, SrcMgr::C_User);
+  auto Begin = SM.getLocForStartOfFile(ID);
+  auto End = SM.getLocForEndOfFile(ID);
+  tooling::Replacement RemoveAll(SM, CharSourceRange::getCharRange(Begin, End),
+                                 "");
+  std::string FilePath = RemoveAll.getFilePath().str();
+  Context->FileToReplacements[FilePath] = tooling::Replacements(RemoveAll);
+
+  StringRef Code = SM.getBufferData(ID);
+  if (!NewFile.empty()) {
+    auto AllCode =
+        tooling::Replacements(tooling::Replacement(NewFile, 0, 0, Code));
+    auto ReplaceOldInclude = [&](CharSourceRange OldHeaderIncludeRange) {
+      AllCode = AllCode.merge(tooling::Replacements(tooling::Replacement(
+          SM, OldHeaderIncludeRange, '"' + Context->Spec.NewHeader + '"')));
+    };
+    // Fix the case where old.h/old.cc includes "old.h", we replace the
+    // `#include "old.h"` with `#include "new.h"`.
+    if (Context->Spec.NewCC == NewFile && OldHeaderIncludeRangeInCC.isValid())
+      ReplaceOldInclude(OldHeaderIncludeRangeInCC);
+    else if (Context->Spec.NewHeader == NewFile &&
+             OldHeaderIncludeRangeInHeader.isValid())
+      ReplaceOldInclude(OldHeaderIncludeRangeInHeader);
+    Context->FileToReplacements[NewFile] = std::move(AllCode);
+  }
+}
+
+void ClangMoveTool::onEndOfTranslationUnit() {
+  if (Context->DumpDeclarations) {
+    assert(Reporter);
+    for (const auto *Decl : UnremovedDeclsInOldHeader) {
+      auto Kind = Decl->getKind();
+      bool Templated = Decl->isTemplated();
+      const std::string QualifiedName = Decl->getQualifiedNameAsString();
+      if (Kind == Decl::Kind::Var)
+        Reporter->reportDeclaration(QualifiedName, "Variable", Templated);
+      else if (Kind == Decl::Kind::Function ||
+               Kind == Decl::Kind::FunctionTemplate)
+        Reporter->reportDeclaration(QualifiedName, "Function", Templated);
+      else if (Kind == Decl::Kind::ClassTemplate ||
+               Kind == Decl::Kind::CXXRecord)
+        Reporter->reportDeclaration(QualifiedName, "Class", Templated);
+      else if (Kind == Decl::Kind::Enum)
+        Reporter->reportDeclaration(QualifiedName, "Enum", Templated);
+      else if (Kind == Decl::Kind::Typedef || Kind == Decl::Kind::TypeAlias ||
+               Kind == Decl::Kind::TypeAliasTemplate)
+        Reporter->reportDeclaration(QualifiedName, "TypeAlias", Templated);
+    }
+    return;
+  }
+
+  if (RemovedDecls.empty())
+    return;
+  // Ignore symbols that are not supported when checking if there is unremoved
+  // symbol in old header. This makes sure that we always move old files to new
+  // files when all symbols produced from dump_decls are moved.
+  auto IsSupportedKind = [](const NamedDecl *Decl) {
+    switch (Decl->getKind()) {
+    case Decl::Kind::Function:
+    case Decl::Kind::FunctionTemplate:
+    case Decl::Kind::ClassTemplate:
+    case Decl::Kind::CXXRecord:
+    case Decl::Kind::Enum:
+    case Decl::Kind::Typedef:
+    case Decl::Kind::TypeAlias:
+    case Decl::Kind::TypeAliasTemplate:
+    case Decl::Kind::Var:
+      return true;
+    default:
+      return false;
+    }
+  };
+  if (std::none_of(UnremovedDeclsInOldHeader.begin(),
+                   UnremovedDeclsInOldHeader.end(), IsSupportedKind) &&
+      !Context->Spec.OldHeader.empty()) {
+    auto &SM = RemovedDecls[0]->getASTContext().getSourceManager();
+    moveAll(SM, Context->Spec.OldHeader, Context->Spec.NewHeader);
+    moveAll(SM, Context->Spec.OldCC, Context->Spec.NewCC);
+    return;
+  }
+  LLVM_DEBUG(RGBuilder.getGraph()->dump());
+  moveDeclsToNewFiles();
+  removeDeclsInOldFiles();
+}
+
+} // namespace move
+} // namespace clang

Added: clang-tools-extra/trunk/clang-move/Move.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-move/Move.h?rev=356780&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-move/Move.h (added)
+++ clang-tools-extra/trunk/clang-move/Move.h Fri Mar 22 09:34:39 2019
@@ -0,0 +1,240 @@
+//===-- Move.h - Clang move  ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_MOVE_CLANGMOVE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_MOVE_CLANGMOVE_H
+
+#include "HelperDeclRefGraph.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace move {
+
+// A reporter which collects and reports declarations in old header.
+class DeclarationReporter {
+public:
+  DeclarationReporter() = default;
+  ~DeclarationReporter() = default;
+
+  void reportDeclaration(llvm::StringRef DeclarationName, llvm::StringRef Type,
+                         bool Templated) {
+    DeclarationList.emplace_back(DeclarationName, Type, Templated);
+  };
+
+  struct Declaration {
+    Declaration(llvm::StringRef QName, llvm::StringRef Kind, bool Templated)
+        : QualifiedName(QName), Kind(Kind), Templated(Templated) {}
+
+    friend bool operator==(const Declaration &LHS, const Declaration &RHS) {
+      return std::tie(LHS.QualifiedName, LHS.Kind, LHS.Templated) ==
+             std::tie(RHS.QualifiedName, RHS.Kind, RHS.Templated);
+    }
+    std::string QualifiedName; // E.g. A::B::Foo.
+    std::string Kind;          // E.g. Function, Class
+    bool Templated = false;    // Whether the declaration is templated.
+  };
+
+  const std::vector<Declaration> getDeclarationList() const {
+    return DeclarationList;
+  }
+
+private:
+  std::vector<Declaration> DeclarationList;
+};
+
+// Specify declarations being moved. It contains all information of the moved
+// declarations.
+struct MoveDefinitionSpec {
+  // The list of fully qualified names, e.g. Foo, a::Foo, b::Foo.
+  SmallVector<std::string, 4> Names;
+  // The file path of old header, can be relative path and absolute path.
+  std::string OldHeader;
+  // The file path of old cc, can be relative path and absolute path.
+  std::string OldCC;
+  // The file path of new header, can be relative path and absolute path.
+  std::string NewHeader;
+  // The file path of new cc, can be relative path and absolute path.
+  std::string NewCC;
+  // Whether old.h depends on new.h. If true, #include "new.h" will be added
+  // in old.h.
+  bool OldDependOnNew = false;
+  // Whether new.h depends on old.h. If true, #include "old.h" will be added
+  // in new.h.
+  bool NewDependOnOld = false;
+};
+
+// A Context which contains extra options which are used in ClangMoveTool.
+struct ClangMoveContext {
+  MoveDefinitionSpec Spec;
+  // The Key is file path, value is the replacements being applied to the file.
+  std::map<std::string, tooling::Replacements> &FileToReplacements;
+  // The original working directory where the local clang-move binary runs.
+  //
+  // clang-move will change its current working directory to the build
+  // directory when analyzing the source file. We save the original working
+  // directory in order to get the absolute file path for the fields in Spec.
+  std::string OriginalRunningDirectory;
+  // The name of a predefined code style.
+  std::string FallbackStyle;
+  // Whether dump all declarations in old header.
+  bool DumpDeclarations;
+};
+
+// This tool is used to move class/function definitions from the given source
+// files (old.h/cc) to new files (new.h/cc).
+// The goal of this tool is to make the new/old files as compilable as possible.
+//
+// When moving a symbol,all used helper declarations (e.g. static
+// functions/variables definitions in global/named namespace,
+// functions/variables/classes definitions in anonymous namespace) used by the
+// moved symbol in old.cc are moved to the new.cc. In addition, all
+// using-declarations in old.cc are also moved to new.cc; forward class
+// declarations in old.h are also moved to new.h.
+//
+// The remaining helper declarations which are unused by non-moved symbols in
+// old.cc will be removed.
+//
+// Note: When all declarations in old header are being moved, all code in
+// old.h/cc will be moved, which means old.h/cc are empty. This ignores symbols
+// that are not supported (e.g. typedef and enum) so that we always move old
+// files to new files when all symbols produced from dump_decls are moved.
+class ClangMoveTool : public ast_matchers::MatchFinder::MatchCallback {
+public:
+  ClangMoveTool(ClangMoveContext *const Context,
+                DeclarationReporter *const Reporter);
+
+  void registerMatchers(ast_matchers::MatchFinder *Finder);
+
+  void run(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+  void onEndOfTranslationUnit() override;
+
+  /// Add #includes from old.h/cc files.
+  ///
+  /// \param IncludeHeader The name of the file being included, as written in
+  /// the source code.
+  /// \param IsAngled Whether the file name was enclosed in angle brackets.
+  /// \param SearchPath The search path which was used to find the IncludeHeader
+  /// in the file system. It can be a relative path or an absolute path.
+  /// \param FileName The name of file where the IncludeHeader comes from.
+  /// \param IncludeFilenameRange The source range for the written file name in
+  /// #include (i.e. "old.h" for #include "old.h") in old.cc.
+  /// \param SM The SourceManager.
+  void addIncludes(llvm::StringRef IncludeHeader, bool IsAngled,
+                   llvm::StringRef SearchPath, llvm::StringRef FileName,
+                   clang::CharSourceRange IncludeFilenameRange,
+                   const SourceManager &SM);
+
+  std::vector<const NamedDecl *> &getMovedDecls() { return MovedDecls; }
+
+  /// Add declarations being removed from old.h/cc. For each declarations, the
+  /// method also records the mapping relationship between the corresponding
+  /// FilePath and its FileID.
+  void addRemovedDecl(const NamedDecl *Decl);
+
+  llvm::SmallPtrSet<const NamedDecl *, 8> &getUnremovedDeclsInOldHeader() {
+    return UnremovedDeclsInOldHeader;
+  }
+
+private:
+  // Make the Path absolute using the OrignalRunningDirectory if the Path is not
+  // an absolute path. An empty Path will result in an empty string.
+  std::string makeAbsolutePath(StringRef Path);
+
+  void removeDeclsInOldFiles();
+  void moveDeclsToNewFiles();
+  void moveAll(SourceManager& SM, StringRef OldFile, StringRef NewFile);
+
+  // Stores all MatchCallbacks created by this tool.
+  std::vector<std::unique_ptr<ast_matchers::MatchFinder::MatchCallback>>
+      MatchCallbacks;
+  // Store all potential declarations (decls being moved, forward decls) that
+  // might need to move to new.h/cc. It includes all helper declarations
+  // (include unused ones) by default. The unused ones will be filtered out in
+  // the last stage. Saving in an AST-visited order.
+  std::vector<const NamedDecl *> MovedDecls;
+  // The declarations that needs to be removed in old.cc/h.
+  std::vector<const NamedDecl *> RemovedDecls;
+  // The #includes in old_header.h.
+  std::vector<std::string> HeaderIncludes;
+  // The #includes in old_cc.cc.
+  std::vector<std::string> CCIncludes;
+  // Records all helper declarations (function/variable/class definitions in
+  // anonymous namespaces, static function/variable definitions in global/named
+  // namespaces) in old.cc. saving in an AST-visited order.
+  std::vector<const NamedDecl *> HelperDeclarations;
+  // The unmoved named declarations in old header.
+  llvm::SmallPtrSet<const NamedDecl*, 8> UnremovedDeclsInOldHeader;
+  /// The source range for the written file name in #include (i.e. "old.h" for
+  /// #include "old.h") in old.cc,  including the enclosing quotes or angle
+  /// brackets.
+  clang::CharSourceRange OldHeaderIncludeRangeInCC;
+  /// The source range for the written file name in #include (i.e. "old.h" for
+  /// #include "old.h") in old.h,  including the enclosing quotes or angle
+  /// brackets.
+  clang::CharSourceRange OldHeaderIncludeRangeInHeader;
+  /// Mapping from FilePath to FileID, which can be used in post processes like
+  /// cleanup around replacements.
+  llvm::StringMap<FileID> FilePathToFileID;
+  /// A context contains all running options. It is not owned.
+  ClangMoveContext *const Context;
+  /// A reporter to report all declarations from old header. It is not owned.
+  DeclarationReporter *const Reporter;
+  /// Builder for helper declarations reference graph.
+  HelperDeclRGBuilder RGBuilder;
+};
+
+class ClangMoveAction : public clang::ASTFrontendAction {
+public:
+  ClangMoveAction(ClangMoveContext *const Context,
+                  DeclarationReporter *const Reporter)
+      : MoveTool(Context, Reporter) {
+    MoveTool.registerMatchers(&MatchFinder);
+  }
+
+  ~ClangMoveAction() override = default;
+
+  std::unique_ptr<clang::ASTConsumer>
+  CreateASTConsumer(clang::CompilerInstance &Compiler,
+                    llvm::StringRef InFile) override;
+
+private:
+  ast_matchers::MatchFinder MatchFinder;
+  ClangMoveTool MoveTool;
+};
+
+class ClangMoveActionFactory : public tooling::FrontendActionFactory {
+public:
+  ClangMoveActionFactory(ClangMoveContext *const Context,
+                         DeclarationReporter *const Reporter = nullptr)
+      : Context(Context), Reporter(Reporter) {}
+
+  clang::FrontendAction *create() override {
+    return new ClangMoveAction(Context, Reporter);
+  }
+
+private:
+  // Not owned.
+  ClangMoveContext *const Context;
+  DeclarationReporter *const Reporter;
+};
+
+} // namespace move
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_MOVE_CLANGMOVE_H

Modified: clang-tools-extra/trunk/clang-move/tool/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-move/tool/CMakeLists.txt?rev=356780&r1=356779&r2=356780&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-move/tool/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clang-move/tool/CMakeLists.txt Fri Mar 22 09:34:39 2019
@@ -1,7 +1,7 @@
 include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
 
 add_clang_executable(clang-move
-  ClangMoveMain.cpp
+  ClangMove.cpp
   )
 
 target_link_libraries(clang-move

Added: clang-tools-extra/trunk/clang-move/tool/ClangMove.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-move/tool/ClangMove.cpp?rev=356780&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-move/tool/ClangMove.cpp (added)
+++ clang-tools-extra/trunk/clang-move/tool/ClangMove.cpp Fri Mar 22 09:34:39 2019
@@ -0,0 +1,212 @@
+//===-- ClangMove.cpp - move defintion to new file --------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Move.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Tooling/ArgumentsAdjusters.h"
+#include "clang/Tooling/CommonOptionsParser.h"
+#include "clang/Tooling/Refactoring.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/YAMLTraits.h"
+#include <set>
+#include <string>
+
+using namespace clang;
+using namespace llvm;
+
+namespace {
+
+std::error_code CreateNewFile(const llvm::Twine &path) {
+  int fd = 0;
+  if (std::error_code ec = llvm::sys::fs::openFileForWrite(
+          path, fd, llvm::sys::fs::CD_CreateAlways, llvm::sys::fs::F_Text))
+    return ec;
+
+  return llvm::sys::Process::SafelyCloseFileDescriptor(fd);
+}
+
+cl::OptionCategory ClangMoveCategory("clang-move options");
+
+cl::list<std::string> Names("names", cl::CommaSeparated,
+                            cl::desc("The list of the names of classes being "
+                                     "moved, e.g. \"Foo,a::Foo,b::Foo\"."),
+                            cl::cat(ClangMoveCategory));
+
+cl::opt<std::string>
+    OldHeader("old_header",
+              cl::desc("The relative/absolute file path of old header."),
+              cl::cat(ClangMoveCategory));
+
+cl::opt<std::string>
+    OldCC("old_cc", cl::desc("The relative/absolute file path of old cc."),
+          cl::cat(ClangMoveCategory));
+
+cl::opt<std::string>
+    NewHeader("new_header",
+              cl::desc("The relative/absolute file path of new header."),
+              cl::cat(ClangMoveCategory));
+
+cl::opt<std::string>
+    NewCC("new_cc", cl::desc("The relative/absolute file path of new cc."),
+          cl::cat(ClangMoveCategory));
+
+cl::opt<bool>
+    OldDependOnNew("old_depend_on_new",
+                   cl::desc("Whether old header will depend on new header. If "
+                            "true, clang-move will "
+                            "add #include of new header to old header."),
+                   cl::init(false), cl::cat(ClangMoveCategory));
+
+cl::opt<bool>
+    NewDependOnOld("new_depend_on_old",
+                   cl::desc("Whether new header will depend on old header. If "
+                            "true, clang-move will "
+                            "add #include of old header to new header."),
+                   cl::init(false), cl::cat(ClangMoveCategory));
+
+cl::opt<std::string>
+    Style("style",
+          cl::desc("The style name used for reformatting. Default is \"llvm\""),
+          cl::init("llvm"), cl::cat(ClangMoveCategory));
+
+cl::opt<bool> Dump("dump_result",
+                   cl::desc("Dump results in JSON format to stdout."),
+                   cl::cat(ClangMoveCategory));
+
+cl::opt<bool> DumpDecls(
+    "dump_decls",
+    cl::desc("Dump all declarations in old header (JSON format) to stdout. If "
+             "the option is specified, other command options will be ignored. "
+             "An empty JSON will be returned if old header isn't specified."),
+    cl::cat(ClangMoveCategory));
+
+} // namespace
+
+int main(int argc, const char **argv) {
+  llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
+  tooling::CommonOptionsParser OptionsParser(argc, argv, ClangMoveCategory);
+
+  if (OldDependOnNew && NewDependOnOld) {
+    llvm::errs() << "Provide either --old_depend_on_new or "
+                    "--new_depend_on_old. clang-move doesn't support these two "
+                    "options at same time (It will introduce include cycle).\n";
+    return 1;
+  }
+
+  tooling::RefactoringTool Tool(OptionsParser.getCompilations(),
+                                OptionsParser.getSourcePathList());
+  // Add "-fparse-all-comments" compile option to make clang parse all comments.
+  Tool.appendArgumentsAdjuster(tooling::getInsertArgumentAdjuster(
+      "-fparse-all-comments", tooling::ArgumentInsertPosition::BEGIN));
+  move::MoveDefinitionSpec Spec;
+  Spec.Names = {Names.begin(), Names.end()};
+  Spec.OldHeader = OldHeader;
+  Spec.NewHeader = NewHeader;
+  Spec.OldCC = OldCC;
+  Spec.NewCC = NewCC;
+  Spec.OldDependOnNew = OldDependOnNew;
+  Spec.NewDependOnOld = NewDependOnOld;
+
+  llvm::SmallString<128> InitialDirectory;
+  if (std::error_code EC = llvm::sys::fs::current_path(InitialDirectory))
+    llvm::report_fatal_error("Cannot detect current path: " +
+                             Twine(EC.message()));
+
+  move::ClangMoveContext Context{Spec, Tool.getReplacements(),
+                                 InitialDirectory.str(), Style, DumpDecls};
+  move::DeclarationReporter Reporter;
+  move::ClangMoveActionFactory Factory(&Context, &Reporter);
+
+  int CodeStatus = Tool.run(&Factory);
+  if (CodeStatus)
+    return CodeStatus;
+
+  if (DumpDecls) {
+    llvm::outs() << "[\n";
+    const auto &Declarations = Reporter.getDeclarationList();
+    for (auto I = Declarations.begin(), E = Declarations.end(); I != E; ++I) {
+      llvm::outs() << "  {\n";
+      llvm::outs() << "    \"DeclarationName\": \"" << I->QualifiedName
+                   << "\",\n";
+      llvm::outs() << "    \"DeclarationType\": \"" << I->Kind << "\",\n";
+      llvm::outs() << "    \"Templated\": " << (I->Templated ? "true" : "false")
+                   << "\n";
+      llvm::outs() << "  }";
+      // Don't print trailing "," at the end of last element.
+      if (I != std::prev(E))
+        llvm::outs() << ",\n";
+    }
+    llvm::outs() << "\n]\n";
+    return 0;
+  }
+
+  if (!NewCC.empty()) {
+    std::error_code EC = CreateNewFile(NewCC);
+    if (EC) {
+      llvm::errs() << "Failed to create " << NewCC << ": " << EC.message()
+                   << "\n";
+      return EC.value();
+    }
+  }
+  if (!NewHeader.empty()) {
+    std::error_code EC = CreateNewFile(NewHeader);
+    if (EC) {
+      llvm::errs() << "Failed to create " << NewHeader << ": " << EC.message()
+                   << "\n";
+      return EC.value();
+    }
+  }
+
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions());
+  clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts);
+  DiagnosticsEngine Diagnostics(
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
+      &DiagnosticPrinter, false);
+  auto &FileMgr = Tool.getFiles();
+  SourceManager SM(Diagnostics, FileMgr);
+  Rewriter Rewrite(SM, LangOptions());
+
+  if (!formatAndApplyAllReplacements(Tool.getReplacements(), Rewrite, Style)) {
+    llvm::errs() << "Failed applying all replacements.\n";
+    return 1;
+  }
+
+  if (Dump) {
+    std::set<llvm::StringRef> Files;
+    for (const auto &it : Tool.getReplacements())
+      Files.insert(it.first);
+    auto WriteToJson = [&](llvm::raw_ostream &OS) {
+      OS << "[\n";
+      for (auto I = Files.begin(), E = Files.end(); I != E; ++I) {
+        OS << "  {\n";
+        OS << "    \"FilePath\": \"" << *I << "\",\n";
+        const auto *Entry = FileMgr.getFile(*I);
+        auto ID = SM.translateFile(Entry);
+        std::string Content;
+        llvm::raw_string_ostream ContentStream(Content);
+        Rewrite.getEditBuffer(ID).write(ContentStream);
+        OS << "    \"SourceText\": \""
+           << llvm::yaml::escape(ContentStream.str()) << "\"\n";
+        OS << "  }";
+        if (I != std::prev(E))
+          OS << ",\n";
+      }
+      OS << "\n]\n";
+    };
+    WriteToJson(llvm::outs());
+    return 0;
+  }
+
+  return Rewrite.overwriteChangedFiles();
+}

Removed: clang-tools-extra/trunk/clang-move/tool/ClangMoveMain.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-move/tool/ClangMoveMain.cpp?rev=356779&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-move/tool/ClangMoveMain.cpp (original)
+++ clang-tools-extra/trunk/clang-move/tool/ClangMoveMain.cpp (removed)
@@ -1,212 +0,0 @@
-//===-- ClangMoveMain.cpp - move defintion to new file ----------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "ClangMove.h"
-#include "clang/Frontend/TextDiagnosticPrinter.h"
-#include "clang/Rewrite/Core/Rewriter.h"
-#include "clang/Tooling/ArgumentsAdjusters.h"
-#include "clang/Tooling/CommonOptionsParser.h"
-#include "clang/Tooling/Refactoring.h"
-#include "clang/Tooling/Tooling.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/Process.h"
-#include "llvm/Support/Signals.h"
-#include "llvm/Support/YAMLTraits.h"
-#include <set>
-#include <string>
-
-using namespace clang;
-using namespace llvm;
-
-namespace {
-
-std::error_code CreateNewFile(const llvm::Twine &path) {
-  int fd = 0;
-  if (std::error_code ec = llvm::sys::fs::openFileForWrite(
-          path, fd, llvm::sys::fs::CD_CreateAlways, llvm::sys::fs::F_Text))
-    return ec;
-
-  return llvm::sys::Process::SafelyCloseFileDescriptor(fd);
-}
-
-cl::OptionCategory ClangMoveCategory("clang-move options");
-
-cl::list<std::string> Names("names", cl::CommaSeparated,
-                            cl::desc("The list of the names of classes being "
-                                     "moved, e.g. \"Foo,a::Foo,b::Foo\"."),
-                            cl::cat(ClangMoveCategory));
-
-cl::opt<std::string>
-    OldHeader("old_header",
-              cl::desc("The relative/absolute file path of old header."),
-              cl::cat(ClangMoveCategory));
-
-cl::opt<std::string>
-    OldCC("old_cc", cl::desc("The relative/absolute file path of old cc."),
-          cl::cat(ClangMoveCategory));
-
-cl::opt<std::string>
-    NewHeader("new_header",
-              cl::desc("The relative/absolute file path of new header."),
-              cl::cat(ClangMoveCategory));
-
-cl::opt<std::string>
-    NewCC("new_cc", cl::desc("The relative/absolute file path of new cc."),
-          cl::cat(ClangMoveCategory));
-
-cl::opt<bool>
-    OldDependOnNew("old_depend_on_new",
-                   cl::desc("Whether old header will depend on new header. If "
-                            "true, clang-move will "
-                            "add #include of new header to old header."),
-                   cl::init(false), cl::cat(ClangMoveCategory));
-
-cl::opt<bool>
-    NewDependOnOld("new_depend_on_old",
-                   cl::desc("Whether new header will depend on old header. If "
-                            "true, clang-move will "
-                            "add #include of old header to new header."),
-                   cl::init(false), cl::cat(ClangMoveCategory));
-
-cl::opt<std::string>
-    Style("style",
-          cl::desc("The style name used for reformatting. Default is \"llvm\""),
-          cl::init("llvm"), cl::cat(ClangMoveCategory));
-
-cl::opt<bool> Dump("dump_result",
-                   cl::desc("Dump results in JSON format to stdout."),
-                   cl::cat(ClangMoveCategory));
-
-cl::opt<bool> DumpDecls(
-    "dump_decls",
-    cl::desc("Dump all declarations in old header (JSON format) to stdout. If "
-             "the option is specified, other command options will be ignored. "
-             "An empty JSON will be returned if old header isn't specified."),
-    cl::cat(ClangMoveCategory));
-
-} // namespace
-
-int main(int argc, const char **argv) {
-  llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
-  tooling::CommonOptionsParser OptionsParser(argc, argv, ClangMoveCategory);
-
-  if (OldDependOnNew && NewDependOnOld) {
-    llvm::errs() << "Provide either --old_depend_on_new or "
-                    "--new_depend_on_old. clang-move doesn't support these two "
-                    "options at same time (It will introduce include cycle).\n";
-    return 1;
-  }
-
-  tooling::RefactoringTool Tool(OptionsParser.getCompilations(),
-                                OptionsParser.getSourcePathList());
-  // Add "-fparse-all-comments" compile option to make clang parse all comments.
-  Tool.appendArgumentsAdjuster(tooling::getInsertArgumentAdjuster(
-      "-fparse-all-comments", tooling::ArgumentInsertPosition::BEGIN));
-  move::MoveDefinitionSpec Spec;
-  Spec.Names = {Names.begin(), Names.end()};
-  Spec.OldHeader = OldHeader;
-  Spec.NewHeader = NewHeader;
-  Spec.OldCC = OldCC;
-  Spec.NewCC = NewCC;
-  Spec.OldDependOnNew = OldDependOnNew;
-  Spec.NewDependOnOld = NewDependOnOld;
-
-  llvm::SmallString<128> InitialDirectory;
-  if (std::error_code EC = llvm::sys::fs::current_path(InitialDirectory))
-    llvm::report_fatal_error("Cannot detect current path: " +
-                             Twine(EC.message()));
-
-  move::ClangMoveContext Context{Spec, Tool.getReplacements(),
-                                 InitialDirectory.str(), Style, DumpDecls};
-  move::DeclarationReporter Reporter;
-  move::ClangMoveActionFactory Factory(&Context, &Reporter);
-
-  int CodeStatus = Tool.run(&Factory);
-  if (CodeStatus)
-    return CodeStatus;
-
-  if (DumpDecls) {
-    llvm::outs() << "[\n";
-    const auto &Declarations = Reporter.getDeclarationList();
-    for (auto I = Declarations.begin(), E = Declarations.end(); I != E; ++I) {
-      llvm::outs() << "  {\n";
-      llvm::outs() << "    \"DeclarationName\": \"" << I->QualifiedName
-                   << "\",\n";
-      llvm::outs() << "    \"DeclarationType\": \"" << I->Kind << "\",\n";
-      llvm::outs() << "    \"Templated\": " << (I->Templated ? "true" : "false")
-                   << "\n";
-      llvm::outs() << "  }";
-      // Don't print trailing "," at the end of last element.
-      if (I != std::prev(E))
-        llvm::outs() << ",\n";
-    }
-    llvm::outs() << "\n]\n";
-    return 0;
-  }
-
-  if (!NewCC.empty()) {
-    std::error_code EC = CreateNewFile(NewCC);
-    if (EC) {
-      llvm::errs() << "Failed to create " << NewCC << ": " << EC.message()
-                   << "\n";
-      return EC.value();
-    }
-  }
-  if (!NewHeader.empty()) {
-    std::error_code EC = CreateNewFile(NewHeader);
-    if (EC) {
-      llvm::errs() << "Failed to create " << NewHeader << ": " << EC.message()
-                   << "\n";
-      return EC.value();
-    }
-  }
-
-  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions());
-  clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts);
-  DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
-      &DiagnosticPrinter, false);
-  auto &FileMgr = Tool.getFiles();
-  SourceManager SM(Diagnostics, FileMgr);
-  Rewriter Rewrite(SM, LangOptions());
-
-  if (!formatAndApplyAllReplacements(Tool.getReplacements(), Rewrite, Style)) {
-    llvm::errs() << "Failed applying all replacements.\n";
-    return 1;
-  }
-
-  if (Dump) {
-    std::set<llvm::StringRef> Files;
-    for (const auto &it : Tool.getReplacements())
-      Files.insert(it.first);
-    auto WriteToJson = [&](llvm::raw_ostream &OS) {
-      OS << "[\n";
-      for (auto I = Files.begin(), E = Files.end(); I != E; ++I) {
-        OS << "  {\n";
-        OS << "    \"FilePath\": \"" << *I << "\",\n";
-        const auto *Entry = FileMgr.getFile(*I);
-        auto ID = SM.translateFile(Entry);
-        std::string Content;
-        llvm::raw_string_ostream ContentStream(Content);
-        Rewrite.getEditBuffer(ID).write(ContentStream);
-        OS << "    \"SourceText\": \""
-           << llvm::yaml::escape(ContentStream.str()) << "\"\n";
-        OS << "  }";
-        if (I != std::prev(E))
-          OS << ",\n";
-      }
-      OS << "\n]\n";
-    };
-    WriteToJson(llvm::outs());
-    return 0;
-  }
-
-  return Rewrite.overwriteChangedFiles();
-}




More information about the cfe-commits mailing list