[change-namespace] move template class forward-declarations and don't move fwd-decls...
authorEric Liu <ioeric@google.com>
Wed, 7 Dec 2016 14:20:52 +0000 (14:20 +0000)
committerEric Liu <ioeric@google.com>
Wed, 7 Dec 2016 14:20:52 +0000 (14:20 +0000)
Summary:
Forward declarations in moved namespaces should be moved back to the old
namespaces. We should also move template class forward declarations.

Also fix a bug that moves forward declarations of nested classes.

Reviewers: bkramer

Subscribers: cfe-commits

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

llvm-svn: 288908

clang-tools-extra/change-namespace/ChangeNamespace.cpp
clang-tools-extra/change-namespace/ChangeNamespace.h
clang-tools-extra/unittests/change-namespace/ChangeNamespaceTests.cpp

index c0a8fe0..a18ad9b 100644 (file)
@@ -303,10 +303,18 @@ void ChangeNamespaceTool::registerMatchers(ast_matchers::MatchFinder *Finder) {
           .bind("old_ns"),
       this);
 
-  // Match forward-declarations in the old namespace.
+  // Match class forward-declarations in the old namespace.
+  // Note that forward-declarations in classes are not matched.
+  Finder->addMatcher(cxxRecordDecl(unless(anyOf(isImplicit(), isDefinition())),
+                                   IsInMovedNs, hasParent(namespaceDecl()))
+                         .bind("class_fwd_decl"),
+                     this);
+
+  // Match template class forward-declarations in the old namespace.
   Finder->addMatcher(
-      cxxRecordDecl(unless(anyOf(isImplicit(), isDefinition())), IsInMovedNs)
-          .bind("fwd_decl"),
+      classTemplateDecl(unless(hasDescendant(cxxRecordDecl(isDefinition()))),
+                        IsInMovedNs, hasParent(namespaceDecl()))
+          .bind("template_class_fwd_decl"),
       this);
 
   // Match references to types that are not defined in the old namespace.
@@ -401,8 +409,12 @@ void ChangeNamespaceTool::run(
                  Result.Nodes.getNodeAs<NamespaceDecl>("old_ns")) {
     moveOldNamespace(Result, NsDecl);
   } else if (const auto *FwdDecl =
-                 Result.Nodes.getNodeAs<CXXRecordDecl>("fwd_decl")) {
-    moveClassForwardDeclaration(Result, FwdDecl);
+                 Result.Nodes.getNodeAs<CXXRecordDecl>("class_fwd_decl")) {
+    moveClassForwardDeclaration(Result, cast<NamedDecl>(FwdDecl));
+  } else if (const auto *TemplateFwdDecl =
+                 Result.Nodes.getNodeAs<ClassTemplateDecl>(
+                     "template_class_fwd_decl")) {
+    moveClassForwardDeclaration(Result, cast<NamedDecl>(TemplateFwdDecl));
   } else if (const auto *UsingWithShadow =
                  Result.Nodes.getNodeAs<UsingDecl>("using_with_shadow")) {
     fixUsingShadowDecl(Result, UsingWithShadow);
@@ -539,7 +551,7 @@ void ChangeNamespaceTool::moveOldNamespace(
 //   }  // x
 void ChangeNamespaceTool::moveClassForwardDeclaration(
     const ast_matchers::MatchFinder::MatchResult &Result,
-    const CXXRecordDecl *FwdDecl) {
+    const NamedDecl *FwdDecl) {
   SourceLocation Start = FwdDecl->getLocStart();
   SourceLocation End = FwdDecl->getLocEnd();
   SourceLocation AfterSemi = Lexer::findLocationAfterToken(
index 300579d..048c32f 100644 (file)
@@ -64,7 +64,7 @@ private:
 
   void moveClassForwardDeclaration(
       const ast_matchers::MatchFinder::MatchResult &Result,
-      const CXXRecordDecl *FwdDecl);
+      const NamedDecl *FwdDecl);
 
   void replaceQualifiedSymbolInDeclContext(
       const ast_matchers::MatchFinder::MatchResult &Result,
index 53684be..450e4a4 100644 (file)
@@ -278,6 +278,7 @@ TEST_F(ChangeNamespaceTest, LeaveForwardDeclarationBehind) {
   std::string Code = "namespace na {\n"
                      "namespace nb {\n"
                      "class FWD;\n"
+                     "class FWD2;\n"
                      "class A {\n"
                      "  FWD *fwd;\n"
                      "};\n"
@@ -286,6 +287,7 @@ TEST_F(ChangeNamespaceTest, LeaveForwardDeclarationBehind) {
   std::string Expected = "namespace na {\n"
                          "namespace nb {\n"
                          "class FWD;\n"
+                         "class FWD2;\n"
                          "} // namespace nb\n"
                          "} // namespace na\n"
                          "namespace x {\n"
@@ -299,6 +301,58 @@ TEST_F(ChangeNamespaceTest, LeaveForwardDeclarationBehind) {
   EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
 }
 
+TEST_F(ChangeNamespaceTest, TemplateClassForwardDeclaration) {
+  std::string Code = "namespace na {\n"
+                     "namespace nb {\n"
+                     "class FWD;\n"
+                     "template<typename T> class FWD_TEMP;\n"
+                     "class A {\n"
+                     "  FWD *fwd;\n"
+                     "};\n"
+                     "template<typename T> class TEMP {};\n"
+                     "} // namespace nb\n"
+                     "} // namespace na\n";
+  std::string Expected = "namespace na {\n"
+                         "namespace nb {\n"
+                         "class FWD;\n"
+                         "template<typename T> class FWD_TEMP;\n"
+                         "} // namespace nb\n"
+                         "} // namespace na\n"
+                         "namespace x {\n"
+                         "namespace y {\n"
+                         "\n"
+                         "class A {\n"
+                         "  na::nb::FWD *fwd;\n"
+                         "};\n"
+                         "template<typename T> class TEMP {};\n"
+                         "} // namespace y\n"
+                         "} // namespace x\n";
+  EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, DontMoveForwardDeclarationInClass) {
+  std::string Code = "namespace na {\n"
+                     "namespace nb {\n"
+                     "class A {\n"
+                     "  class FWD;\n"
+                     "  FWD *fwd;\n"
+                     "  template<typename T> class FWD_TEMP;\n"
+                     "};\n"
+                     "} // namespace nb\n"
+                     "} // namespace na\n";
+  std::string Expected = "\n\n"
+                         "namespace x {\n"
+                         "namespace y {\n"
+                         "class A {\n"
+                         "  class FWD;\n"
+                         "  FWD *fwd;\n"
+                         "  template<typename T> class FWD_TEMP;\n"
+                         "};\n"
+                         "} // namespace y\n"
+                         "} // namespace x\n";
+  EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
 TEST_F(ChangeNamespaceTest, MoveFunctions) {
   std::string Code = "namespace na {\n"
                      "class C_A {};\n"