[clang-move] Enable dump all declarations in old header.

Summary:
* Add -dump_dels option to dump all declarations from old header. It
  will allow clang-move used as a frontend to get declarations from
  header. Further more, this will make debugging stuff easier. Currently only
  class/function types are supported.
* Refactoring code a little bit by creating a ClangMoveContext which
  holds all options for ClangMoveTool, which can simplify the code in
  some degree.

Reviewers: ioeric

Subscribers: cfe-commits

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

llvm-svn: 287863
diff --git a/clang-tools-extra/clang-move/ClangMove.cpp b/clang-tools-extra/clang-move/ClangMove.cpp
index d4d0af8..bd8bbe3 100644
--- a/clang-tools-extra/clang-move/ClangMove.cpp
+++ b/clang-tools-extra/clang-move/ClangMove.cpp
@@ -401,15 +401,11 @@
   return MatchFinder.newASTConsumer();
 }
 
-ClangMoveTool::ClangMoveTool(
-    const MoveDefinitionSpec &MoveSpec,
-    std::map<std::string, tooling::Replacements> &FileToReplacements,
-    llvm::StringRef OriginalRunningDirectory, llvm::StringRef FallbackStyle)
-    : Spec(MoveSpec), FileToReplacements(FileToReplacements),
-      OriginalRunningDirectory(OriginalRunningDirectory),
-      FallbackStyle(FallbackStyle) {
-  if (!Spec.NewHeader.empty())
-    CCIncludes.push_back("#include \"" + Spec.NewHeader + "\"\n");
+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 MovedDecl &Decl) {
@@ -421,24 +417,10 @@
 }
 
 void ClangMoveTool::registerMatchers(ast_matchers::MatchFinder *Finder) {
-  Optional<ast_matchers::internal::Matcher<NamedDecl>> HasAnySymbolNames;
-  for (StringRef SymbolName: 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 InOldHeader = isExpansionInFile(makeAbsolutePath(Spec.OldHeader));
-  auto InOldCC = isExpansionInFile(makeAbsolutePath(Spec.OldCC));
+  auto InOldHeader =
+      isExpansionInFile(makeAbsolutePath(Context->Spec.OldHeader));
+  auto InOldCC = isExpansionInFile(makeAbsolutePath(Context->Spec.OldCC));
   auto InOldFiles = anyOf(InOldHeader, InOldCC);
-  auto InMovedClass =
-      hasOutermostEnclosingClass(cxxRecordDecl(*HasAnySymbolNames));
-
   auto ForwardDecls =
       cxxRecordDecl(unless(anyOf(isImplicit(), isDefinition())));
 
@@ -448,15 +430,21 @@
   // Match all top-level named declarations (e.g. function, variable, enum) in
   // old header, exclude forward class declarations and namespace declarations.
   //
-  // The old header which contains only one declaration being moved and forward
-  // declarations is considered to be moved totally.
+  // We consider declarations inside a class belongs to the class. So these
+  // declarations will be ignored.
   auto AllDeclsInHeader = namedDecl(
       unless(ForwardDecls), unless(namespaceDecl()),
-      unless(usingDirectiveDecl()), // using namespace decl.
+      unless(usingDirectiveDecl()),                 // using namespace decl.
       unless(classTemplateDecl(has(ForwardDecls))), // template forward decl.
       InOldHeader,
-      hasParent(decl(anyOf(namespaceDecl(), translationUnitDecl()))));
+      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(ForwardDecls, InOldHeader).bind("fwd_decl"),
                      this);
@@ -484,6 +472,20 @@
 
   // 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));
   auto IsOldCCStaticDefinition =
       allOf(isDefinition(), unless(InMovedClass), InOldCCNamedOrGlobalNamespace,
             isStaticStorageClass());
@@ -531,7 +533,7 @@
     UnremovedDeclsInOldHeader.insert(D);
   } else if (const auto *FWD =
                  Result.Nodes.getNodeAs<clang::CXXRecordDecl>("fwd_decl")) {
-    // Skip all forwad declarations which appear after moved class declaration.
+    // Skip all forward declarations which appear after moved class declaration.
     if (RemovedDecls.empty()) {
       if (const auto *DCT = FWD->getDescribedClassTemplate())
         MovedDecls.emplace_back(DCT, &Result.Context->getSourceManager());
@@ -551,7 +553,7 @@
 }
 
 std::string ClangMoveTool::makeAbsolutePath(StringRef Path) {
-  return MakeAbsolutePath(OriginalRunningDirectory, Path);
+  return MakeAbsolutePath(Context->OriginalRunningDirectory, Path);
 }
 
 void ClangMoveTool::addIncludes(llvm::StringRef IncludeHeader, bool IsAngled,
@@ -561,7 +563,7 @@
                                 const SourceManager &SM) {
   SmallVector<char, 128> HeaderWithSearchPath;
   llvm::sys::path::append(HeaderWithSearchPath, SearchPath, IncludeHeader);
-  std::string AbsoluteOldHeader = makeAbsolutePath(Spec.OldHeader);
+  std::string AbsoluteOldHeader = makeAbsolutePath(Context->Spec.OldHeader);
   // FIXME: Add old.h to the new.cc/h when the new target has dependencies on
   // old.h/c. For instance, when moved class uses another class defined in
   // old.h, the old.h should be added in new.h.
@@ -579,7 +581,7 @@
   std::string AbsoluteCurrentFile = MakeAbsolutePath(SM, FileName);
   if (AbsoluteOldHeader == AbsoluteCurrentFile) {
     HeaderIncludes.push_back(IncludeLine);
-  } else if (makeAbsolutePath(Spec.OldCC) == AbsoluteCurrentFile) {
+  } else if (makeAbsolutePath(Context->Spec.OldCC) == AbsoluteCurrentFile) {
     CCIncludes.push_back(IncludeLine);
   }
 }
@@ -594,20 +596,22 @@
         clang::CharSourceRange::getCharRange(Range.getBegin(), Range.getEnd()),
         "");
     std::string FilePath = RemoveReplacement.getFilePath().str();
-    auto Err = FileToReplacements[FilePath].add(RemoveReplacement);
+    auto Err = Context->FileToReplacements[FilePath].add(RemoveReplacement);
     if (Err)
       llvm::errs() << llvm::toString(std::move(Err)) << "\n";
   }
   const SourceManager* SM = RemovedDecls[0].SM;
 
   // Post process of cleanup around all the replacements.
-  for (auto& FileAndReplacements: FileToReplacements) {
+  for (auto &FileAndReplacements : Context->FileToReplacements) {
     StringRef FilePath = FileAndReplacements.first;
     // Add #include of new header to old header.
-    if (Spec.OldDependOnNew &&
-        MakeAbsolutePath(*SM, FilePath) == makeAbsolutePath(Spec.OldHeader)) {
+    if (Context->Spec.OldDependOnNew &&
+        MakeAbsolutePath(*SM, FilePath) ==
+            makeAbsolutePath(Context->Spec.OldHeader)) {
       // FIXME: Minimize the include path like include-fixer.
-      std::string IncludeNewH = "#include \""  + Spec.NewHeader + "\"\n";
+      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));
@@ -620,15 +624,15 @@
     if (SI == FilePathToFileID.end()) continue;
     llvm::StringRef Code = SM->getBufferData(SI->second);
     format::FormatStyle Style =
-        format::getStyle("file", FilePath, FallbackStyle);
+        format::getStyle("file", FilePath, Context->FallbackStyle);
     auto CleanReplacements = format::cleanupAroundReplacements(
-        Code, FileToReplacements[FilePath], Style);
+        Code, Context->FileToReplacements[FilePath], Style);
 
     if (!CleanReplacements) {
       llvm::errs() << llvm::toString(CleanReplacements.takeError()) << "\n";
       continue;
     }
-    FileToReplacements[FilePath] = *CleanReplacements;
+    Context->FileToReplacements[FilePath] = *CleanReplacements;
   }
 }
 
@@ -636,23 +640,27 @@
   std::vector<MovedDecl> NewHeaderDecls;
   std::vector<MovedDecl> NewCCDecls;
   for (const auto &MovedDecl : MovedDecls) {
-    if (isInHeaderFile(*MovedDecl.SM, MovedDecl.Decl, OriginalRunningDirectory,
-                       Spec.OldHeader))
+    if (isInHeaderFile(*MovedDecl.SM, MovedDecl.Decl,
+                       Context->OriginalRunningDirectory,
+                       Context->Spec.OldHeader))
       NewHeaderDecls.push_back(MovedDecl);
     else
       NewCCDecls.push_back(MovedDecl);
   }
 
-  if (!Spec.NewHeader.empty()) {
+  if (!Context->Spec.NewHeader.empty()) {
     std::string OldHeaderInclude =
-        Spec.NewDependOnOld ? "#include \"" + Spec.OldHeader + "\"\n" : "";
-    FileToReplacements[Spec.NewHeader] = createInsertedReplacements(
-        HeaderIncludes, NewHeaderDecls, Spec.NewHeader, /*IsHeader=*/true,
-        OldHeaderInclude);
+        Context->Spec.NewDependOnOld
+            ? "#include \"" + Context->Spec.OldHeader + "\"\n"
+            : "";
+    Context->FileToReplacements[Context->Spec.NewHeader] =
+        createInsertedReplacements(HeaderIncludes, NewHeaderDecls,
+                                   Context->Spec.NewHeader, /*IsHeader=*/true,
+                                   OldHeaderInclude);
   }
-  if (!Spec.NewCC.empty())
-    FileToReplacements[Spec.NewCC] =
-        createInsertedReplacements(CCIncludes, NewCCDecls, Spec.NewCC);
+  if (!Context->Spec.NewCC.empty())
+    Context->FileToReplacements[Context->Spec.NewCC] =
+        createInsertedReplacements(CCIncludes, NewCCDecls, Context->Spec.NewCC);
 }
 
 // Move all contents from OldFile to NewFile.
@@ -669,7 +677,8 @@
   clang::tooling::Replacement RemoveAll (
       SM, clang::CharSourceRange::getCharRange(Begin, End), "");
   std::string FilePath = RemoveAll.getFilePath().str();
-  FileToReplacements[FilePath] = clang::tooling::Replacements(RemoveAll);
+  Context->FileToReplacements[FilePath] =
+      clang::tooling::Replacements(RemoveAll);
 
   StringRef Code = SM.getBufferData(ID);
   if (!NewFile.empty()) {
@@ -677,22 +686,36 @@
         clang::tooling::Replacement(NewFile, 0, 0, Code));
     // If we are moving from old.cc, an extra step is required: excluding
     // the #include of "old.h", instead, we replace it with #include of "new.h".
-    if (Spec.NewCC == NewFile && OldHeaderIncludeRange.isValid()) {
+    if (Context->Spec.NewCC == NewFile && OldHeaderIncludeRange.isValid()) {
       AllCode = AllCode.merge(
           clang::tooling::Replacements(clang::tooling::Replacement(
-              SM, OldHeaderIncludeRange, '"' + Spec.NewHeader + '"')));
+              SM, OldHeaderIncludeRange, '"' + Context->Spec.NewHeader + '"')));
     }
-    FileToReplacements[NewFile] = std::move(AllCode);
+    Context->FileToReplacements[NewFile] = std::move(AllCode);
   }
 }
 
 void ClangMoveTool::onEndOfTranslationUnit() {
+  if (Context->DumpDeclarations) {
+    assert(Reporter);
+    for (const auto *Decl : UnremovedDeclsInOldHeader) {
+      auto Kind = Decl->getKind();
+      const std::string QualifiedName = Decl->getQualifiedNameAsString();
+      if (Kind == Decl::Kind::Function || Kind == Decl::Kind::FunctionTemplate)
+        Reporter->reportDeclaration(QualifiedName, "Function");
+      else if (Kind == Decl::Kind::ClassTemplate ||
+               Kind == Decl::Kind::CXXRecord)
+        Reporter->reportDeclaration(QualifiedName, "Class");
+    }
+    return;
+  }
+
   if (RemovedDecls.empty())
     return;
-  if (UnremovedDeclsInOldHeader.empty() && !Spec.OldHeader.empty()) {
+  if (UnremovedDeclsInOldHeader.empty() && !Context->Spec.OldHeader.empty()) {
     auto &SM = *RemovedDecls[0].SM;
-    moveAll(SM, Spec.OldHeader, Spec.NewHeader);
-    moveAll(SM, Spec.OldCC, Spec.NewCC);
+    moveAll(SM, Context->Spec.OldHeader, Context->Spec.NewHeader);
+    moveAll(SM, Context->Spec.OldCC, Context->Spec.NewCC);
     return;
   }
   removeClassDefinitionInOldFiles();