[clang-tools-extra] r290873 - [clang-move] Only move used helper declarations.

Haojian Wu via cfe-commits cfe-commits at lists.llvm.org
Tue Jan 3 01:00:53 PST 2017


Author: hokein
Date: Tue Jan  3 03:00:51 2017
New Revision: 290873

URL: http://llvm.org/viewvc/llvm-project?rev=290873&view=rev
Log:
[clang-move] Only move used helper declarations.

Summary:
Instead of moving all the helper declarations blindly, this patch
implements an AST-based call graph solution to make clang-move only move used
helper decls to new.cc and remove unused decls in old.cc.

Depends on D27674.

Reviewers: ioeric

Subscribers: mgorny, cfe-commits

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

Added:
    clang-tools-extra/trunk/clang-move/HelperDeclRefGraph.cpp
    clang-tools-extra/trunk/clang-move/HelperDeclRefGraph.h
    clang-tools-extra/trunk/test/clang-move/Inputs/helper_decls_test.cpp
    clang-tools-extra/trunk/test/clang-move/Inputs/helper_decls_test.h
    clang-tools-extra/trunk/test/clang-move/move-used-helper-decls.cpp
Modified:
    clang-tools-extra/trunk/clang-move/CMakeLists.txt
    clang-tools-extra/trunk/clang-move/ClangMove.cpp
    clang-tools-extra/trunk/clang-move/ClangMove.h
    clang-tools-extra/trunk/test/clang-move/Inputs/multiple_class_test.cpp
    clang-tools-extra/trunk/test/clang-move/move-multiple-classes.cpp
    clang-tools-extra/trunk/unittests/clang-move/ClangMoveTests.cpp

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=290873&r1=290872&r2=290873&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-move/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clang-move/CMakeLists.txt Tue Jan  3 03:00:51 2017
@@ -4,8 +4,10 @@ set(LLVM_LINK_COMPONENTS
 
 add_clang_library(clangMove
   ClangMove.cpp
+  HelperDeclRefGraph.cpp
 
   LINK_LIBS
+  clangAnalysis
   clangAST
   clangASTMatchers
   clangBasic

Modified: clang-tools-extra/trunk/clang-move/ClangMove.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-move/ClangMove.cpp?rev=290873&r1=290872&r2=290873&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-move/ClangMove.cpp (original)
+++ clang-tools-extra/trunk/clang-move/ClangMove.cpp Tue Jan  3 03:00:51 2017
@@ -8,6 +8,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "ClangMove.h"
+#include "HelperDeclRefGraph.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Format/Format.h"
@@ -16,8 +17,11 @@
 #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 {
@@ -394,6 +398,25 @@ createInsertedReplacements(const std::ve
       clang::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<clang::ASTConsumer>
@@ -455,24 +478,18 @@ void ClangMoveTool::registerMatchers(ast
   //============================================================================
   // Matchers for old cc
   //============================================================================
-  auto InOldCCNamedOrGlobalNamespace =
-      allOf(hasParent(decl(anyOf(namespaceDecl(unless(isAnonymous())),
-                                 translationUnitDecl()))),
-            InOldCC);
-  // Matching using decls/type alias decls which are in named namespace or
-  // global namespace. Those in classes, functions and anonymous namespaces are
-  // covered in other matchers.
+  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(InOldCCNamedOrGlobalNamespace),
-                      usingDirectiveDecl(InOldCCNamedOrGlobalNamespace),
-                      typeAliasDecl( InOldCCNamedOrGlobalNamespace)))
+      namedDecl(anyOf(usingDecl(IsOldCCTopLevelDecl),
+                      usingDirectiveDecl(IsOldCCTopLevelDecl),
+                      typeAliasDecl(IsOldCCTopLevelDecl)))
           .bind("using_decl"),
       this);
 
-  // Match anonymous namespace decl in old cc.
-  Finder->addMatcher(namespaceDecl(isAnonymous(), InOldCC).bind("anonymous_ns"),
-                     this);
-
   // Match static functions/variable definitions which are defined in named
   // namespaces.
   Optional<ast_matchers::internal::Matcher<NamedDecl>> HasAnySymbolNames;
@@ -489,13 +506,37 @@ void ClangMoveTool::registerMatchers(ast
   }
   auto InMovedClass =
       hasOutermostEnclosingClass(cxxRecordDecl(*HasAnySymbolNames));
-  auto IsOldCCStaticDefinition =
-      allOf(isDefinition(), unless(InMovedClass), InOldCCNamedOrGlobalNamespace,
-            isStaticStorageClass());
-  Finder->addMatcher(namedDecl(anyOf(functionDecl(IsOldCCStaticDefinition),
-                                     varDecl(IsOldCCStaticDefinition)))
-                         .bind("static_decls"),
-                     this);
+
+  // Matchers for helper declarations in old.cc.
+  auto InAnonymousNS = hasParent(namespaceDecl(isAnonymous()));
+  auto DefinitionInOldCC = allOf(isDefinition(), unless(InMovedClass), InOldCC);
+  auto IsOldCCHelperDefinition =
+      allOf(DefinitionInOldCC, anyOf(isStaticStorageClass(), InAnonymousNS));
+  // Match helper classes separately with helper functions/variables since we
+  // want to reuse these matchers in finding helpers usage below.
+  auto HelperFuncOrVar = namedDecl(anyOf(functionDecl(IsOldCCHelperDefinition),
+                                         varDecl(IsOldCCHelperDefinition)));
+  auto HelperClasses = cxxRecordDecl(DefinitionInOldCC, 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
@@ -543,12 +584,13 @@ void ClangMoveTool::run(const ast_matche
       else
         MovedDecls.push_back(FWD);
     }
-  } else if (const auto *ANS =
-                 Result.Nodes.getNodeAs<clang::NamespaceDecl>("anonymous_ns")) {
-    MovedDecls.push_back(ANS);
   } else if (const auto *ND =
                  Result.Nodes.getNodeAs<clang::NamedDecl>("static_decls")) {
     MovedDecls.push_back(ND);
+  } else if (const auto *ND =
+                 Result.Nodes.getNodeAs<clang::NamedDecl>("helper_decls")) {
+    MovedDecls.push_back(ND);
+    HelperDeclarations.push_back(ND);
   } else if (const auto *UD =
                  Result.Nodes.getNodeAs<clang::NamedDecl>("using_decl")) {
     MovedDecls.push_back(UD);
@@ -567,9 +609,6 @@ void ClangMoveTool::addIncludes(llvm::St
   SmallVector<char, 128> HeaderWithSearchPath;
   llvm::sys::path::append(HeaderWithSearchPath, SearchPath, IncludeHeader);
   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.
   if (AbsoluteOldHeader ==
       MakeAbsolutePath(SM, llvm::StringRef(HeaderWithSearchPath.data(),
                                            HeaderWithSearchPath.size()))) {
@@ -591,6 +630,28 @@ void ClangMoveTool::addIncludes(llvm::St
 
 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) {
+      if (!UsedDecls.count(HelperDeclRGBuilder::getOutmostClassOrFunDecl(D))) {
+        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);
@@ -650,6 +711,22 @@ void ClangMoveTool::moveDeclsToNewFiles(
       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)))
+      continue;
+
+    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
@@ -662,7 +739,8 @@ void ClangMoveTool::moveDeclsToNewFiles(
   }
   if (!Context->Spec.NewCC.empty())
     Context->FileToReplacements[Context->Spec.NewCC] =
-        createInsertedReplacements(CCIncludes, NewCCDecls, Context->Spec.NewCC);
+        createInsertedReplacements(CCIncludes, ActualNewCCDecls,
+                                   Context->Spec.NewCC);
 }
 
 // Move all contents from OldFile to NewFile.
@@ -737,8 +815,9 @@ void ClangMoveTool::onEndOfTranslationUn
     moveAll(SM, Context->Spec.OldCC, Context->Spec.NewCC);
     return;
   }
-  removeDeclsInOldFiles();
+  DEBUG(RGBuilder.getGraph()->dump());
   moveDeclsToNewFiles();
+  removeDeclsInOldFiles();
 }
 
 } // namespace move

Modified: clang-tools-extra/trunk/clang-move/ClangMove.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-move/ClangMove.h?rev=290873&r1=290872&r2=290873&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-move/ClangMove.h (original)
+++ clang-tools-extra/trunk/clang-move/ClangMove.h Tue Jan  3 03:00:51 2017
@@ -10,6 +10,7 @@
 #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"
@@ -88,11 +89,18 @@ struct ClangMoveContext {
 };
 
 // This tool is used to move class/function definitions from the given source
-// files (old.h/cc) to new files (new.h/cc). When moving a class, all its
-// members are also moved. In addition, all helper functions (anonymous
-// namespace declarations, static declarations, using declarations) in old.cc
-// and forward class declarations in old.h are copied to the new files.
-// The goal of this tool is to make the new files as compliable as possible.
+// 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
@@ -148,8 +156,10 @@ private:
   // Stores all MatchCallbacks created by this tool.
   std::vector<std::unique_ptr<ast_matchers::MatchFinder::MatchCallback>>
       MatchCallbacks;
-  // All declarations (the class decl being moved, forward decls) that need to
-  // be moved/copy to the new files, saving in an AST-visited order.
+  // 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;
@@ -157,6 +167,10 @@ private:
   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
@@ -170,6 +184,8 @@ private:
   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 {

Added: clang-tools-extra/trunk/clang-move/HelperDeclRefGraph.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-move/HelperDeclRefGraph.cpp?rev=290873&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-move/HelperDeclRefGraph.cpp (added)
+++ clang-tools-extra/trunk/clang-move/HelperDeclRefGraph.cpp Tue Jan  3 03:00:51 2017
@@ -0,0 +1,128 @@
+//===-- UsedHelperDeclFinder.cpp - AST-based call graph for helper decls --===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "HelperDeclRefGraph.h"
+#include "ClangMove.h"
+#include "clang/AST/Decl.h"
+#include <vector>
+
+namespace clang {
+namespace move {
+
+void HelperDeclRefGraph::print(raw_ostream &OS) const {
+  OS << " --- Call graph Dump --- \n";
+  for (auto I = DeclMap.begin(); I != DeclMap.end(); ++I) {
+    const CallGraphNode *N = (I->second).get();
+
+    OS << "  Declarations: ";
+    N->print(OS);
+    OS << " (" << N << ") ";
+    OS << " calls: ";
+    for (auto CI = N->begin(), CE = N->end(); CI != CE; ++CI) {
+      (*CI)->print(OS);
+      OS << " (" << CI << ") ";
+    }
+    OS << '\n';
+  }
+  OS.flush();
+}
+
+void HelperDeclRefGraph::addEdge(const Decl *Caller, const Decl *Callee) {
+  assert(Caller);
+  assert(Callee);
+
+  // Ignore the case where Caller equals Callee. This happens in the static
+  // class member definitions in global namespace like "int CLASS::static_var =
+  // 1;", its DC is a VarDel whose outmost enclosing declaration is the "CLASS"
+  // CXXRecordDecl.
+  if (Caller == Callee) return;
+
+  // Allocate a new node, mark it as root, and process it's calls.
+  CallGraphNode *CallerNode = getOrInsertNode(const_cast<Decl *>(Caller));
+  CallGraphNode *CalleeNode = getOrInsertNode(const_cast<Decl *>(Callee));
+  CallerNode->addCallee(CalleeNode);
+}
+
+void HelperDeclRefGraph::dump() const { print(llvm::errs()); }
+
+CallGraphNode *HelperDeclRefGraph::getOrInsertNode(Decl *F) {
+  F = F->getCanonicalDecl();
+  std::unique_ptr<CallGraphNode> &Node = DeclMap[F];
+  if (Node)
+    return Node.get();
+
+  Node = llvm::make_unique<CallGraphNode>(F);
+  return Node.get();
+}
+
+CallGraphNode *HelperDeclRefGraph::getNode(const Decl *D) const {
+  auto I = DeclMap.find(D->getCanonicalDecl());
+  return I == DeclMap.end() ? nullptr : I->second.get();
+}
+
+llvm::DenseSet<const CallGraphNode *>
+HelperDeclRefGraph::getReachableNodes(const Decl *Root) const {
+  const auto *RootNode = getNode(Root);
+  if (!RootNode)
+    return {};
+  llvm::DenseSet<const CallGraphNode *> ConnectedNodes;
+  std::function<void(const CallGraphNode *)> VisitNode =
+      [&](const CallGraphNode *Node) {
+        if (ConnectedNodes.count(Node))
+          return;
+        ConnectedNodes.insert(Node);
+        for (auto It = Node->begin(), End = Node->end(); It != End; ++It)
+          VisitNode(*It);
+      };
+
+  VisitNode(RootNode);
+  return ConnectedNodes;
+}
+
+const Decl *HelperDeclRGBuilder::getOutmostClassOrFunDecl(const Decl *D) {
+  const auto *DC = D->getDeclContext();
+  const auto *Result = D;
+  while (DC) {
+    if (const auto *RD = dyn_cast<CXXRecordDecl>(DC))
+      Result = RD;
+    else if (const auto *FD = dyn_cast<FunctionDecl>(DC))
+      Result = FD;
+    DC = DC->getParent();
+  }
+  return Result;
+}
+
+void HelperDeclRGBuilder::run(
+    const ast_matchers::MatchFinder::MatchResult &Result) {
+  // Construct the graph by adding a directed edge from caller to callee.
+  //
+  // "dc" is the closest ancestor declaration of "func_ref" or "used_class", it
+  // might be not the targetted Caller Decl, we always use the outmost enclosing
+  // FunctionDecl/CXXRecordDecl of "dc". For example,
+  //
+  //   int MoveClass::F() { int a = helper(); return a; }
+  //
+  // The matched "dc" of "helper" DeclRefExpr is a VarDecl, we traverse up AST
+  // to find the outmost "MoveClass" CXXRecordDecl and use it as Caller.
+  if (const auto *FuncRef = Result.Nodes.getNodeAs<DeclRefExpr>("func_ref")) {
+    const auto *DC = Result.Nodes.getNodeAs<Decl>("dc");
+    assert(DC);
+
+    RG->addEdge(getOutmostClassOrFunDecl(DC->getCanonicalDecl()),
+                getOutmostClassOrFunDecl(FuncRef->getDecl()));
+  } else if (const auto *UsedClass =
+                 Result.Nodes.getNodeAs<CXXRecordDecl>("used_class")) {
+    const auto *DC = Result.Nodes.getNodeAs<Decl>("dc");
+    assert(DC);
+    RG->addEdge(getOutmostClassOrFunDecl(DC->getCanonicalDecl()), UsedClass);
+  }
+}
+
+} // namespace move
+} // namespace clang

Added: clang-tools-extra/trunk/clang-move/HelperDeclRefGraph.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-move/HelperDeclRefGraph.h?rev=290873&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-move/HelperDeclRefGraph.h (added)
+++ clang-tools-extra/trunk/clang-move/HelperDeclRefGraph.h Tue Jan  3 03:00:51 2017
@@ -0,0 +1,99 @@
+//===-- UsedHelperDeclFinder.h - AST-based call graph for helper decls ----===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_MOVE_USED_HELPER_DECL_FINDER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_MOVE_USED_HELPER_DECL_FINDER_H
+
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Analysis/CallGraph.h"
+#include "llvm/ADT/DenseSet.h"
+#include <memory>
+#include <vector>
+
+namespace clang {
+namespace move {
+
+// A reference graph for finding used/unused helper declarations in a single
+// translation unit (e.g. old.cc). We don't reuse CallGraph in clang/Analysis
+// because that CallGraph only supports function declarations.
+//
+// Helper declarations include following types:
+//   * function/variable/class definitions in an anonymous namespace.
+//   * static function/variable definitions in a global/named namespace.
+//
+// The reference graph is a directed graph. Each node in the graph represents a
+// helper declaration in old.cc or a non-moved/moved declaration (e.g. class,
+// function) in old.h, which means each node is associated with a Decl.
+//
+// To construct the graph, we use AST matcher to find interesting Decls (usually
+// a pair of Caller and Callee), and add an edge from the Caller node to the
+// Callee node.
+//
+// Specially, for a class, it might have multiple declarations such methods
+// and member variables. We only use a single node to present this class, and
+// this node is associated with the class declaration (CXXRecordDecl).
+//
+// The graph has 3 types of edges:
+//   1. moved_decl => helper_decl
+//   2. non_moved_decl => helper_decl
+//   3. helper_decl => helper_decl
+class HelperDeclRefGraph {
+public:
+  HelperDeclRefGraph() = default;
+  ~HelperDeclRefGraph() = default;
+
+  // Add a directed edge from the caller node to the callee node.
+  // A new node will be created if the node for Caller/Callee doesn't exist.
+  //
+  // Note that, all class member declarations are represented by a single node
+  // in the graph. The corresponding Decl of this node is the class declaration.
+  void addEdge(const Decl *Caller, const Decl *Callee);
+  CallGraphNode *getNode(const Decl *D) const;
+
+  // Get all reachable nodes in the graph from the given declaration D's node,
+  // including D.
+  llvm::DenseSet<const CallGraphNode *> getReachableNodes(const Decl *D) const;
+
+  // Dump the call graph for debug purpose.
+  void dump() const;
+
+private:
+  void print(raw_ostream &OS) const;
+  // Lookup a node for the given declaration D. If not found, insert a new
+  // node into the graph.
+  CallGraphNode *getOrInsertNode(Decl *D);
+
+  typedef llvm::DenseMap<const Decl *, std::unique_ptr<CallGraphNode>>
+      DeclMapTy;
+
+  // DeclMap owns all CallGraphNodes.
+  DeclMapTy DeclMap;
+};
+
+// A builder helps to construct a call graph of helper declarations.
+class HelperDeclRGBuilder : public ast_matchers::MatchFinder::MatchCallback {
+public:
+  HelperDeclRGBuilder() : RG(new HelperDeclRefGraph) {}
+  void run(const ast_matchers::MatchFinder::MatchResult &Result) override;
+  const HelperDeclRefGraph *getGraph() const { return RG.get(); }
+
+  // Find out the outmost enclosing class/function declaration of a given D.
+  // For a CXXMethodDecl, get its CXXRecordDecl; For a VarDecl/FunctionDecl, get
+  // its outmost enclosing FunctionDecl or CXXRecordDecl.
+  // Return D if not found.
+  static const Decl *getOutmostClassOrFunDecl(const Decl *D);
+
+private:
+  std::unique_ptr<HelperDeclRefGraph> RG;
+};
+
+} // namespace move
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_MOVE_USED_HELPER_DECL_FINDER_H

Added: clang-tools-extra/trunk/test/clang-move/Inputs/helper_decls_test.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-move/Inputs/helper_decls_test.cpp?rev=290873&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-move/Inputs/helper_decls_test.cpp (added)
+++ clang-tools-extra/trunk/test/clang-move/Inputs/helper_decls_test.cpp Tue Jan  3 03:00:51 2017
@@ -0,0 +1,78 @@
+#include "helper_decls_test.h"
+
+namespace {
+class HelperC1 {
+public:
+  static int I;
+};
+
+int HelperC1::I = 0;
+
+class HelperC2 {};
+
+class HelperC3 {
+ public:
+  static int I;
+};
+
+int HelperC3::I = 0;
+
+void HelperFun1() {}
+
+void HelperFun2() { HelperFun1(); }
+
+const int K1 = 1;
+} // namespace
+
+static const int K2 = 2;
+static void HelperFun3() { K2; }
+
+namespace a {
+
+static const int K3 = 3;
+static const int K4 = HelperC3::I;
+static const int K5 = 5;
+static const int K6 = 6;
+
+static void HelperFun4() {}
+static void HelperFun6() {}
+
+void Class1::f() { HelperFun2(); }
+
+void Class2::f() {
+  HelperFun1();
+  HelperFun3();
+}
+
+void Class3::f() { HelperC1::I; }
+
+void Class4::f() { HelperC2 c2; }
+
+void Class5::f() {
+  int Result = K1 + K2 + K3;
+  HelperFun4();
+}
+
+int Class6::f() {
+  int R = K4;
+  return R;
+}
+
+int Class7::f() {
+  int R = K6;
+  return R;
+}
+
+int Class7::g() {
+  HelperFun6();
+  return 1;
+}
+
+static int HelperFun5() {
+  int R = K5;
+  return R;
+}
+
+void Fun1() { HelperFun5(); }
+
+} // namespace a

Added: clang-tools-extra/trunk/test/clang-move/Inputs/helper_decls_test.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-move/Inputs/helper_decls_test.h?rev=290873&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-move/Inputs/helper_decls_test.h (added)
+++ clang-tools-extra/trunk/test/clang-move/Inputs/helper_decls_test.h Tue Jan  3 03:00:51 2017
@@ -0,0 +1,35 @@
+namespace a {
+class Class1 {
+  void f();
+};
+
+class Class2 {
+  void f();
+};
+
+class Class3 {
+  void f();
+};
+
+class Class4 {
+  void f();
+};
+
+class Class5 {
+  void f();
+};
+
+class Class6 {
+  int f();
+};
+
+class Class7 {
+  int f();
+  int g();
+};
+
+void Fun1();
+
+inline void Fun2() {}
+
+} // namespace a

Modified: clang-tools-extra/trunk/test/clang-move/Inputs/multiple_class_test.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-move/Inputs/multiple_class_test.cpp?rev=290873&r1=290872&r2=290873&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/clang-move/Inputs/multiple_class_test.cpp (original)
+++ clang-tools-extra/trunk/test/clang-move/Inputs/multiple_class_test.cpp Tue Jan  3 03:00:51 2017
@@ -15,7 +15,7 @@ namespace {
 using a::Move1;
 using namespace a;
 static int k = 0;
-} // anonymous namespace
+} // namespace
 
 namespace b {
 using a::Move1;
@@ -34,19 +34,19 @@ int Move3::f() {
 }
 
 int Move4::f() {
-  return 0;
+  return k;
 }
 
 int EnclosingMove5::a = 1;
 
 int EnclosingMove5::Nested::f() {
-  return 0;
+  return g;
 }
 
 int EnclosingMove5::Nested::b = 1;
 
 int NoMove::f() {
   static int F = 0;
-  return 0;
+  return g;
 }
 } // namespace c

Modified: clang-tools-extra/trunk/test/clang-move/move-multiple-classes.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-move/move-multiple-classes.cpp?rev=290873&r1=290872&r2=290873&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/clang-move/move-multiple-classes.cpp (original)
+++ clang-tools-extra/trunk/test/clang-move/move-multiple-classes.cpp Tue Jan  3 03:00:51 2017
@@ -25,8 +25,7 @@
 // CHECK-OLD-TEST-CPP: namespace {
 // CHECK-OLD-TEST-CPP: using a::Move1;
 // CHECK-OLD-TEST-CPP: using namespace a;
-// CHECK-OLD-TEST-CPP: static int k = 0;
-// CHECK-OLD-TEST-CPP: } // anonymous namespace
+// CHECK-OLD-TEST-CPP: } // namespace
 // CHECK-OLD-TEST-CPP: namespace b {
 // CHECK-OLD-TEST-CPP: using a::Move1;
 // CHECK-OLD-TEST-CPP: using namespace a;
@@ -35,7 +34,7 @@
 // CHECK-OLD-TEST-CPP: namespace c {
 // CHECK-OLD-TEST-CPP: int NoMove::f() {
 // CHECK-OLD-TEST-CPP:   static int F = 0;
-// CHECK-OLD-TEST-CPP:   return 0;
+// CHECK-OLD-TEST-CPP:   return g;
 // CHECK-OLD-TEST-CPP: }
 // CHECK-OLD-TEST-CPP: } // namespace c
 
@@ -85,7 +84,7 @@
 // CHECK-NEW-TEST-CPP: using a::Move1;
 // CHECK-NEW-TEST-CPP: using namespace a;
 // CHECK-NEW-TEST-CPP: static int k = 0;
-// CHECK-NEW-TEST-CPP: } // anonymous namespace
+// CHECK-NEW-TEST-CPP: } // namespace
 // CHECK-NEW-TEST-CPP: namespace b {
 // CHECK-NEW-TEST-CPP: using a::Move1;
 // CHECK-NEW-TEST-CPP: using namespace a;
@@ -98,8 +97,8 @@
 // CHECK-NEW-TEST-CPP:   using namespace b;
 // CHECK-NEW-TEST-CPP:   return 0;
 // CHECK-NEW-TEST-CPP: }
-// CHECK-NEW-TEST-CPP: int Move4::f() { return 0; }
+// CHECK-NEW-TEST-CPP: int Move4::f() { return k; }
 // CHECK-NEW-TEST-CPP: int EnclosingMove5::a = 1;
-// CHECK-NEW-TEST-CPP: int EnclosingMove5::Nested::f() { return 0; }
+// CHECK-NEW-TEST-CPP: int EnclosingMove5::Nested::f() { return g; }
 // CHECK-NEW-TEST-CPP: int EnclosingMove5::Nested::b = 1;
 // CHECK-NEW-TEST-CPP: } // namespace c

Added: clang-tools-extra/trunk/test/clang-move/move-used-helper-decls.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-move/move-used-helper-decls.cpp?rev=290873&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-move/move-used-helper-decls.cpp (added)
+++ clang-tools-extra/trunk/test/clang-move/move-used-helper-decls.cpp Tue Jan  3 03:00:51 2017
@@ -0,0 +1,388 @@
+// RUN: mkdir -p %T/used-helper-decls
+// RUN: cp %S/Inputs/helper_decls_test*  %T/used-helper-decls/
+// RUN: cd %T/used-helper-decls
+
+// ----------------------------------------------------------------------------
+// Test moving used helper function and its transively used functions.
+// ----------------------------------------------------------------------------
+// RUN: clang-move -names="a::Class1" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11
+// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CLASS1-CPP %s
+// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-CLASS1-CPP %s
+
+// CHECK-NEW-CLASS1-CPP: #include "{{.*}}new_helper_decls_test.h"
+// CHECK-NEW-CLASS1-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS1-CPP-NEXT: namespace {
+// CHECK-NEW-CLASS1-CPP-NEXT: void HelperFun1() {}
+// CHECK-NEW-CLASS1-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS1-CPP-NEXT: void HelperFun2() { HelperFun1(); }
+// CHECK-NEW-CLASS1-CPP-NEXT: } // namespace
+// CHECK-NEW-CLASS1-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS1-CPP-NEXT: namespace a {
+// CHECK-NEW-CLASS1-CPP-NEXT: void Class1::f() { HelperFun2(); }
+// CHECK-NEW-CLASS1-CPP-NEXT: } // namespace a
+//
+// CHECK-OLD-CLASS1-CPP: void HelperFun1() {}
+// CHECK-OLD-CLASS1-CPP-NOT: void HelperFun2() { HelperFun1(); }
+// CHECK-OLD-CLASS1-CPP-NOT: void Class1::f() { HelperFun2(); }
+// CHECK-OLD-CLASS1-CPP: void Class2::f() {
+// CHECK-OLD-CLASS1-CPP:   HelperFun1();
+
+
+// ----------------------------------------------------------------------------
+// Test moving used helper function and its transively used static variables.
+// ----------------------------------------------------------------------------
+// RUN: cp %S/Inputs/helper_decls_test*  %T/used-helper-decls/
+// RUN: clang-move -names="a::Class2" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11
+// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CLASS2-CPP %s
+// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-CLASS2-CPP %s
+
+// CHECK-NEW-CLASS2-CPP: #include "{{.*}}new_helper_decls_test.h"
+// CHECK-NEW-CLASS2-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS2-CPP-NEXT: namespace {
+// CHECK-NEW-CLASS2-CPP-NEXT: void HelperFun1() {}
+// CHECK-NEW-CLASS2-CPP-NEXT: } // namespace
+// CHECK-NEW-CLASS2-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS2-CPP-NEXT: static const int K2 = 2;
+// CHECK-NEW-CLASS2-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS2-CPP-NEXT: static void HelperFun3() { K2; }
+// CHECK-NEW-CLASS2-CPP-NEXT: namespace a {
+// CHECK-NEW-CLASS2-CPP-NEXT: void Class2::f() {
+// CHECK-NEW-CLASS2-CPP-NEXT:   HelperFun1();
+// CHECK-NEW-CLASS2-CPP-NEXT:   HelperFun3();
+// CHECK-NEW-CLASS2-CPP-NEXT: }
+// CHECK-NEW-CLASS2-CPP-NEXT: } // namespace a
+
+// CHECK-OLD-CLASS2-CPP: void HelperFun1() {}
+// CHECK-OLD-CLASS2-CPP: void HelperFun2() { HelperFun1(); }
+// CHECK-OLD-CLASS2-CPP: const int K1 = 1;
+// CHECK-OLD-CLASS2-CPP: static const int K2 = 2;
+// CHECK-OLD-CLASS2-CPP-NOT: static void HelperFun3() { K2; }
+// CHECK-OLD-CLASS2-CPP-NOT: void Class2::f() {
+// CHECK-OLD-CLASS2-CPP-NOT:   HelperFun1();
+// CHECK-OLD-CLASS2-CPP-NOT:   HelperFun3();
+// CHECK-OLD-CLASS2-CPP: void Class5::f() {
+// CHECK-OLD-CLASS2-CPP-NEXT: int Result = K1 + K2 + K3;
+
+
+// ----------------------------------------------------------------------------
+// Test using a static member variable of a helper class.
+// ----------------------------------------------------------------------------
+// RUN: cp %S/Inputs/helper_decls_test*  %T/used-helper-decls/
+// RUN: clang-move -names="a::Class3" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11
+// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CLASS3-CPP %s
+// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-CLASS3-CPP %s
+
+// CHECK-NEW-CLASS3-CPP: #include "{{.*}}new_helper_decls_test.h"
+// CHECK-NEW-CLASS3-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS3-CPP-NEXT: namespace {
+// CHECK-NEW-CLASS3-CPP-NEXT: class HelperC1 {
+// CHECK-NEW-CLASS3-CPP-NEXT: public:
+// CHECK-NEW-CLASS3-CPP-NEXT:   static int I;
+// CHECK-NEW-CLASS3-CPP-NEXT: };
+// CHECK-NEW-CLASS3-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS3-CPP-NEXT: int HelperC1::I = 0;
+// CHECK-NEW-CLASS3-CPP-NEXT: } // namespace
+// CHECK-NEW-CLASS3-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS3-CPP-NEXT: namespace a {
+// CHECK-NEW-CLASS3-CPP-NEXT: void Class3::f() { HelperC1::I; }
+// CHECK-NEW-CLASS3-CPP-NEXT: } // namespace a
+
+// CHECK-OLD-CLASS3-CPP: namespace {
+// CHECK-OLD-CLASS3-CPP-NOT: class HelperC1 {
+// CHECK-OLD-CLASS3-CPP-NOT: public:
+// CHECK-OLD-CLASS3-CPP-NOT:   static int I;
+// CHECK-OLD-CLASS3-CPP-NOT: };
+// CHECK-OLD-CLASS3-CPP-NOT: int HelperC1::I = 0;
+// CHECK-OLD-CLASS3-CPP: class HelperC2 {};
+
+
+// ----------------------------------------------------------------------------
+// Test moving helper classes.
+// ----------------------------------------------------------------------------
+// RUN: cp %S/Inputs/helper_decls_test*  %T/used-helper-decls/
+// RUN: clang-move -names="a::Class4" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11
+// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CLASS4-CPP %s
+// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-CLASS4-CPP %s
+
+// CHECK-NEW-CLASS4-CPP: #include "{{.*}}new_helper_decls_test.h"
+// CHECK-NEW-CLASS4-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS4-CPP-NEXT: namespace {
+// CHECK-NEW-CLASS4-CPP-NEXT: class HelperC2 {};
+// CHECK-NEW-CLASS4-CPP-NEXT: } // namespace
+// CHECK-NEW-CLASS4-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS4-CPP-NEXT: namespace a {
+// CHECK-NEW-CLASS4-CPP-NEXT: void Class4::f() { HelperC2 c2; }
+// CHECK-NEW-CLASS4-CPP-NEXT: } // namespace a
+
+// CHECK-OLD-CLASS4-CPP-NOT: class HelperC2 {};
+
+
+// ----------------------------------------------------------------------------
+// Test moving helper variables and helper functions together.
+// ----------------------------------------------------------------------------
+// RUN: cp %S/Inputs/helper_decls_test*  %T/used-helper-decls/
+// RUN: clang-move -names="a::Class5" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11
+// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CLASS5-CPP %s
+// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-CLASS5-CPP %s
+
+// CHECK-NEW-CLASS5-CPP: #include "{{.*}}new_helper_decls_test.h"
+// CHECK-NEW-CLASS5-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS5-CPP-NEXT: namespace {
+// CHECK-NEW-CLASS5-CPP-NEXT: const int K1 = 1;
+// CHECK-NEW-CLASS5-CPP-NEXT: } // namespace
+// CHECK-NEW-CLASS5-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS5-CPP-NEXT: static const int K2 = 2;
+// CHECK-NEW-CLASS5-CPP-NEXT: namespace a {
+// CHECK-NEW-CLASS5-CPP-NEXT: static const int K3 = 3;
+// CHECK-NEW-CLASS5-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS5-CPP-NEXT: static void HelperFun4() {}
+// CHECK-NEW-CLASS5-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS5-CPP-NEXT: void Class5::f() {
+// CHECK-NEW-CLASS5-CPP-NEXT:   int Result = K1 + K2 + K3;
+// CHECK-NEW-CLASS5-CPP-NEXT:   HelperFun4();
+// CHECK-NEW-CLASS5-CPP-NEXT: }
+// CHECK-NEW-CLASS5-CPP-NEXT: } // namespace a
+
+// CHECK-OLD-CLASS5-CPP-NOT: const int K1 = 1;
+// CHECK-OLD-CLASS5-CPP: static const int K2 = 2;
+// CHECK-OLD-CLASS5-CPP: static void HelperFun3() { K2; }
+// CHECK-OLD-CLASS5-CPP: static const int K4 = HelperC3::I;
+// CHECK-OLD-CLASS5-CPP-NOT: void Class5::f() {
+
+
+// ----------------------------------------------------------------------------
+// Test moving helper variables and their transively used helper classes.
+// ----------------------------------------------------------------------------
+// RUN: cp %S/Inputs/helper_decls_test*  %T/used-helper-decls/
+// RUN: clang-move -names="a::Class6" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11
+// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CLASS6-CPP %s
+// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-CLASS6-CPP %s
+
+// CHECK-NEW-CLASS6-CPP: #include "{{.*}}new_helper_decls_test.h"
+// CHECK-NEW-CLASS6-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS6-CPP-NEXT: namespace {
+// CHECK-NEW-CLASS6-CPP-NEXT: class HelperC3 {
+// CHECK-NEW-CLASS6-CPP-NEXT: public:
+// CHECK-NEW-CLASS6-CPP-NEXT:   static int I;
+// CHECK-NEW-CLASS6-CPP-NEXT: };
+// CHECK-NEW-CLASS6-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS6-CPP-NEXT: int HelperC3::I = 0;
+// CHECK-NEW-CLASS6-CPP-NEXT: } // namespace
+// CHECK-NEW-CLASS6-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS6-CPP-NEXT: namespace a {
+// CHECK-NEW-CLASS6-CPP-NEXT: static const int K4 = HelperC3::I;
+// CHECK-NEW-CLASS6-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS6-CPP-NEXT: int Class6::f() {
+// CHECK-NEW-CLASS6-CPP-NEXT:   int R = K4;
+// CHECK-NEW-CLASS6-CPP-NEXT:   return R;
+// CHECK-NEW-CLASS6-CPP-NEXT: }
+// CHECK-NEW-CLASS6-CPP-NEXT: } // namespace a
+
+// CHECK-OLD-CLASS6-CPP-NOT: class HelperC3 {
+// CHECK-OLD-CLASS6-CPP-NOT: int HelperC3::I = 0;
+// CHECK-OLD-CLASS6-CPP-NOT: static const int K4 = HelperC3::I;
+
+
+// ----------------------------------------------------------------------------
+// Test moving classes where its methods use helpers.
+// ----------------------------------------------------------------------------
+// RUN: cp %S/Inputs/helper_decls_test*  %T/used-helper-decls/
+// RUN: clang-move -names="a::Class7" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11
+// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CLASS7-CPP %s
+// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-CLASS7-CPP %s
+
+// CHECK-NEW-CLASS7-CPP: #include "{{.*}}new_helper_decls_test.h"
+// CHECK-NEW-CLASS7-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS7-CPP-NEXT: namespace a {
+// CHECK-NEW-CLASS7-CPP-NEXT: static const int K6 = 6;
+// CHECK-NEW-CLASS7-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS7-CPP-NEXT: static void HelperFun6() {}
+// CHECK-NEW-CLASS7-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS7-CPP-NEXT: int Class7::f() {
+// CHECK-NEW-CLASS7-CPP-NEXT:   int R = K6;
+// CHECK-NEW-CLASS7-CPP-NEXT:   return R;
+// CHECK-NEW-CLASS7-CPP-NEXT: }
+// CHECK-NEW-CLASS7-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CLASS7-CPP-NEXT: int Class7::g() {
+// CHECK-NEW-CLASS7-CPP-NEXT:   HelperFun6();
+// CHECK-NEW-CLASS7-CPP-NEXT:   return 1;
+// CHECK-NEW-CLASS7-CPP-NEXT: }
+// CHECK-NEW-CLASS7-CPP-NEXT: } // namespace a
+//
+// CHECK-OLD-CLASS7-CPP-NOT: static const int K6 = 6;
+// CHECK-OLD-CLASS7-CPP-NOT: static void HelperFun6() {}
+// CHECK-OLD-CLASS7-CPP-NOT: int Class7::f() {
+// CHECK-OLD-CLASS7-CPP-NOT: int Class7::g() {
+
+
+// ----------------------------------------------------------------------------
+// Test moving helper function and its transively used helper variables.
+// ----------------------------------------------------------------------------
+// RUN: cp %S/Inputs/helper_decls_test*  %T/used-helper-decls/
+// RUN: clang-move -names="a::Fun1" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11
+// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-FUN1-CPP %s
+// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -check-prefix=CHECK-OLD-FUN1-CPP %s
+
+// CHECK-NEW-FUN1-CPP: #include "{{.*}}new_helper_decls_test.h"
+// CHECK-NEW-FUN1-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-FUN1-CPP-NEXT: namespace a {
+// CHECK-NEW-FUN1-CPP-NEXT: static const int K5 = 5;
+// CHECK-NEW-FUN1-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-FUN1-CPP-NEXT: static int HelperFun5() {
+// CHECK-NEW-FUN1-CPP-NEXT:   int R = K5;
+// CHECK-NEW-FUN1-CPP-NEXT:   return R;
+// CHECK-NEW-FUN1-CPP-NEXT: }
+// CHECK-NEW-FUN1-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-FUN1-CPP-NEXT: void Fun1() { HelperFun5(); }
+// CHECK-NEW-FUN1-CPP-NEXT: } // namespace a
+
+// CHECK-OLD-FUN1-CPP-NOT: static const int K5 = 5;
+// CHECK-OLD-FUN1-CPP-NOT: static int HelperFun5() {
+// CHECK-OLD-FUN1-CPP-NOT: void Fun1() { HelperFun5(); }
+
+
+// ----------------------------------------------------------------------------
+// Test no moving helpers when moving inline functions in header.
+// ----------------------------------------------------------------------------
+// RUN: cp %S/Inputs/helper_decls_test*  %T/used-helper-decls/
+// RUN: clang-move -names="a::Fun2" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11
+// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-FUN2-CPP %s
+// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.h -check-prefix=CHECK-NEW-FUN2-H %s
+// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.h -check-prefix=CHECK-OLD-FUN2-H %s
+
+// CHECK-NEW-FUN2-H: namespace a {
+// CHECK-NEW-FUN2-H-NEXT: inline void Fun2() {}
+// CHECK-NEW-FUN2-H-NEXT: } // namespace a
+
+// CHECK-NEW-FUN2-CPP: #include "{{.*}}new_helper_decls_test.h"
+// CHECK-NEW-FUN2-CPP-SAME: {{[[:space:]]}}
+
+// CHECK-OLD-FUN2-H-NOT: inline void Fun2() {}
+
+
+// ----------------------------------------------------------------------------
+// Test moving all symbols in headers.
+// ----------------------------------------------------------------------------
+// RUN: cp %S/Inputs/helper_decls_test*  %T/used-helper-decls/
+// RUN: clang-move -names="a::Class1, a::Class2, a::Class3, a::Class4, a::Class5, a::Class5, a::Class6, a::Class7, a::Fun1, a::Fun2" -new_cc=%T/used-helper-decls/new_helper_decls_test.cpp -new_header=%T/used-helper-decls/new_helper_decls_test.h -old_cc=%T/used-helper-decls/helper_decls_test.cpp -old_header=../used-helper-decls/helper_decls_test.h %T/used-helper-decls/helper_decls_test.cpp -- -std=c++11
+// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.h -check-prefix=CHECK-NEW-H %s
+// RUN: FileCheck -input-file=%T/used-helper-decls/new_helper_decls_test.cpp -check-prefix=CHECK-NEW-CPP %s
+// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.h -allow-empty -check-prefix=CHECK-EMPTY %s
+// RUN: FileCheck -input-file=%T/used-helper-decls/helper_decls_test.cpp -allow-empty -check-prefix=CHECK-EMPTY %s
+
+
+// CHECK-NEW-H: namespace a {
+// CHECK-NEW-H-NEXT: class Class1 {
+// CHECK-NEW-H-NEXT:   void f();
+// CHECK-NEW-H-NEXT: };
+// CHECK-NEW-H-SAME: {{[[:space:]]}}
+// CHECK-NEW-H-NEXT: class Class2 {
+// CHECK-NEW-H-NEXT:   void f();
+// CHECK-NEW-H-NEXT: };
+// CHECK-NEW-H-SAME: {{[[:space:]]}}
+// CHECK-NEW-H-NEXT: class Class3 {
+// CHECK-NEW-H-NEXT:   void f();
+// CHECK-NEW-H-NEXT: };
+// CHECK-NEW-H-SAME: {{[[:space:]]}}
+// CHECK-NEW-H-NEXT: class Class4 {
+// CHECK-NEW-H-NEXT:   void f();
+// CHECK-NEW-H-NEXT: };
+// CHECK-NEW-H-SAME: {{[[:space:]]}}
+// CHECK-NEW-H-NEXT: class Class5 {
+// CHECK-NEW-H-NEXT:   void f();
+// CHECK-NEW-H-NEXT: };
+// CHECK-NEW-H-SAME: {{[[:space:]]}}
+// CHECK-NEW-H-NEXT: class Class6 {
+// CHECK-NEW-H-NEXT:   int f();
+// CHECK-NEW-H-NEXT: };
+// CHECK-NEW-H-SAME: {{[[:space:]]}}
+// CHECK-NEW-H-NEXT: class Class7 {
+// CHECK-NEW-H-NEXT:   int f();
+// CHECK-NEW-H-NEXT:   int g();
+// CHECK-NEW-H-NEXT: };
+// CHECK-NEW-H-SAME: {{[[:space:]]}}
+// CHECK-NEW-H-NEXT: void Fun1();
+// CHECK-NEW-H-SAME: {{[[:space:]]}}
+// CHECK-NEW-H-NEXT: inline void Fun2() {}
+// CHECK-NEW-H-SAME: {{[[:space:]]}}
+// CHECK-NEW-H-NEXT: } // namespace a
+
+
+// CHECK-NEW-CPP: namespace {
+// CHECK-NEW-CPP-NEXT: class HelperC1 {
+// CHECK-NEW-CPP-NEXT: public:
+// CHECK-NEW-CPP-NEXT:   static int I;
+// CHECK-NEW-CPP-NEXT: };
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: int HelperC1::I = 0;
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: class HelperC2 {};
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: class HelperC3 {
+// CHECK-NEW-CPP-NEXT:  public:
+// CHECK-NEW-CPP-NEXT:   static int I;
+// CHECK-NEW-CPP-NEXT: };
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: int HelperC3::I = 0;
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: void HelperFun1() {}
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: void HelperFun2() { HelperFun1(); }
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: const int K1 = 1;
+// CHECK-NEW-CPP-NEXT: } // namespace
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: static const int K2 = 2;
+// CHECK-NEW-CPP-NEXT: static void HelperFun3() { K2; }
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: namespace a {
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: static const int K3 = 3;
+// CHECK-NEW-CPP-NEXT: static const int K4 = HelperC3::I;
+// CHECK-NEW-CPP-NEXT: static const int K5 = 5;
+// CHECK-NEW-CPP-NEXT: static const int K6 = 6;
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: static void HelperFun4() {}
+// CHECK-NEW-CPP-NEXT: static void HelperFun6() {}
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: void Class1::f() { HelperFun2(); }
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: void Class2::f() {
+// CHECK-NEW-CPP-NEXT:   HelperFun1();
+// CHECK-NEW-CPP-NEXT:   HelperFun3();
+// CHECK-NEW-CPP-NEXT: }
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: void Class3::f() { HelperC1::I; }
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: void Class4::f() { HelperC2 c2; }
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: void Class5::f() {
+// CHECK-NEW-CPP-NEXT:   int Result = K1 + K2 + K3;
+// CHECK-NEW-CPP-NEXT:   HelperFun4();
+// CHECK-NEW-CPP-NEXT: }
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: int Class6::f() {
+// CHECK-NEW-CPP-NEXT:   int R = K4;
+// CHECK-NEW-CPP-NEXT:   return R;
+// CHECK-NEW-CPP-NEXT: }
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: int Class7::f() {
+// CHECK-NEW-CPP-NEXT:   int R = K6;
+// CHECK-NEW-CPP-NEXT:   return R;
+// CHECK-NEW-CPP-NEXT: }
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: int Class7::g() {
+// CHECK-NEW-CPP-NEXT:   HelperFun6();
+// CHECK-NEW-CPP-NEXT:   return 1;
+// CHECK-NEW-CPP-NEXT: }
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: static int HelperFun5() {
+// CHECK-NEW-CPP-NEXT:   int R = K5;
+// CHECK-NEW-CPP-NEXT:   return R;
+// CHECK-NEW-CPP-NEXT: }
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: void Fun1() { HelperFun5(); }
+// CHECK-NEW-CPP-SAME: {{[[:space:]]}}
+// CHECK-NEW-CPP-NEXT: } // namespace a
+
+// CHECK-EMPTY: {{^}}{{$}}

Modified: clang-tools-extra/trunk/unittests/clang-move/ClangMoveTests.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-move/ClangMoveTests.cpp?rev=290873&r1=290872&r2=290873&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clang-move/ClangMoveTests.cpp (original)
+++ clang-tools-extra/trunk/unittests/clang-move/ClangMoveTests.cpp Tue Jan  3 03:00:51 2017
@@ -73,13 +73,21 @@ const char TestCC[] = "#include \"foo.h\
                       "\n"
                       "// comment5\n"
                       "// comment5\n"
-                      "void Foo::f() { f1(); }\n"
+                      "void Foo::f() {\n"
+                      "  f1();\n"
+                      "  kConstInt1;\n"
+                      "  kConstInt2;\n"
+                      "  help();\n"
+                      "}\n"
                       "\n"
                       "/////////////\n"
                       "// comment //\n"
                       "/////////////\n"
                       "int Foo::b = 2;\n"
                       "int Foo2::f() {\n"
+                      "  kConstInt1;\n"
+                      "  kConstInt2;\n"
+                      "  help();\n"
                       "  f1();\n"
                       "  return 1;\n"
                       "}\n"
@@ -119,6 +127,9 @@ const char ExpectedTestCC[] = "#include
                               "}\n"
                               "\n"
                               "int Foo2::f() {\n"
+                              "  kConstInt1;\n"
+                              "  kConstInt2;\n"
+                              "  help();\n"
                               "  f1();\n"
                               "  return 1;\n"
                               "}\n"
@@ -154,6 +165,7 @@ const char ExpectedNewCC[] = "namespace
                              "namespace {\n"
                              "// comment1.\n"
                              "void f1() {}\n"
+                             "\n"
                              "/// comment2.\n"
                              "int kConstInt1 = 0;\n"
                              "} // namespace\n"
@@ -170,7 +182,12 @@ const char ExpectedNewCC[] = "namespace
                              "\n"
                              "// comment5\n"
                              "// comment5\n"
-                             "void Foo::f() { f1(); }\n"
+                             "void Foo::f() {\n"
+                             "  f1();\n"
+                             "  kConstInt1;\n"
+                             "  kConstInt2;\n"
+                             "  help();\n"
+                             "}\n"
                              "\n"
                              "/////////////\n"
                              "// comment //\n"




More information about the cfe-commits mailing list