Index: clang-tools-extra/trunk/clang-move/ClangMove.cpp =================================================================== --- clang-tools-extra/trunk/clang-move/ClangMove.cpp +++ clang-tools-extra/trunk/clang-move/ClangMove.cpp @@ -364,16 +364,15 @@ isDefinition()) .bind("class_method"), this); - - //============================================================================ - // Matchers for old cc - //============================================================================ // Match static member variable definition of the moved class. Finder->addMatcher( - varDecl(InMovedClass, InOldCC, isDefinition(), isStaticDataMember()) + varDecl(InMovedClass, InOldFiles, isDefinition(), isStaticDataMember()) .bind("class_static_var_decl"), this); + //============================================================================ + // Matchers for old cc + //============================================================================ auto InOldCCNamedNamespace = allOf(hasParent(namespaceDecl(unless(isAnonymous()))), InOldCC); // Matching using decls/type alias decls which are in named namespace. Those @@ -412,25 +411,36 @@ if (!CMD->isInlined()) { MovedDecls.emplace_back(CMD, &Result.Context->getSourceManager()); RemovedDecls.push_back(MovedDecls.back()); + // Get template class method from its method declaration as + // UnremovedDecls stores template class method. + if (const auto *FTD = CMD->getDescribedFunctionTemplate()) + UnremovedDeclsInOldHeader.erase(FTD); + else + UnremovedDeclsInOldHeader.erase(CMD); } } else if (const auto *VD = Result.Nodes.getNodeAs( "class_static_var_decl")) { MovedDecls.emplace_back(VD, &Result.Context->getSourceManager()); RemovedDecls.push_back(MovedDecls.back()); - } else if (const auto *class_decl = + UnremovedDeclsInOldHeader.erase(MovedDecls.back().Decl); + } else if (const auto *CD = Result.Nodes.getNodeAs("moved_class")) { - MovedDecls.emplace_back(class_decl, &Result.Context->getSourceManager()); + // Get class template from its class declaration as UnremovedDecls stores + // class template. + if (const auto * TC = CD->getDescribedClassTemplate()) + MovedDecls.emplace_back(TC, &Result.Context->getSourceManager()); + else + MovedDecls.emplace_back(CD, &Result.Context->getSourceManager()); RemovedDecls.push_back(MovedDecls.back()); - UnremovedDeclsInOldHeader.erase(class_decl); + UnremovedDeclsInOldHeader.erase(MovedDecls.back().Decl); } else if (const auto *FWD = Result.Nodes.getNodeAs("fwd_decl")) { // Skip all forwad declarations which appear after moved class declaration. if (RemovedDecls.empty()) { - if (const auto *DCT = FWD->getDescribedClassTemplate()) { + if (const auto *DCT = FWD->getDescribedClassTemplate()) MovedDecls.emplace_back(DCT, &Result.Context->getSourceManager()); - } else { + else MovedDecls.emplace_back(FWD, &Result.Context->getSourceManager()); - } } } else if (const auto *ANS = Result.Nodes.getNodeAs("anonymous_ns")) { Index: clang-tools-extra/trunk/test/clang-move/Inputs/template_class_test.h =================================================================== --- clang-tools-extra/trunk/test/clang-move/Inputs/template_class_test.h +++ clang-tools-extra/trunk/test/clang-move/Inputs/template_class_test.h @@ -0,0 +1,30 @@ +#ifndef TEMPLATE_CLASS_TEST_H // comment 1 +#define TEMPLATE_CLASS_TEST_H + +template +class A { + public: + void f(); + void g(); + template void h(); + template void k(); + static int b; + static int c; +}; + +template +void A::f() {} + +template +template +void A::h() {} + +template +int A::b = 2; + +class B { + public: + void f(); +}; + +#endif // TEMPLATE_CLASS_TEST_H Index: clang-tools-extra/trunk/test/clang-move/Inputs/template_class_test.cpp =================================================================== --- clang-tools-extra/trunk/test/clang-move/Inputs/template_class_test.cpp +++ clang-tools-extra/trunk/test/clang-move/Inputs/template_class_test.cpp @@ -0,0 +1,13 @@ +#include "template_class_test.h" + +template +void A::g() {} + +template +template +void A::k() {} + +template +int A::c = 2; + +void B::f() {} Index: clang-tools-extra/trunk/test/clang-move/move-template-class.cpp =================================================================== --- clang-tools-extra/trunk/test/clang-move/move-template-class.cpp +++ clang-tools-extra/trunk/test/clang-move/move-template-class.cpp @@ -0,0 +1,86 @@ +// RUN: mkdir -p %T/move-template-class +// RUN: cp %S/Inputs/template_class_test* %T/move-template-class +// RUN: cd %T/move-template-class +// RUN: clang-move -names="A,B" -new_cc=%T/move-template-class/new_template_class_test.cpp -new_header=%T/move-template-class/new_template_class_test.h -old_cc=%T/move-template-class/template_class_test.cpp -old_header=../move-template-class/template_class_test.h %T/move-template-class/template_class_test.cpp -- +// RUN: FileCheck -input-file=%T/move-template-class/template_class_test.cpp -check-prefix=CHECK-OLD-TEST-EMPTY -allow-empty %s +// RUN: FileCheck -input-file=%T/move-template-class/template_class_test.h -check-prefix=CHECK-OLD-TEST-EMPTY -allow-empty %s +// RUN: FileCheck -input-file=%T/move-template-class/new_template_class_test.cpp -check-prefix=CHECK-NEW-TEST-CPP-CASE1 %s +// RUN: FileCheck -input-file=%T/move-template-class/new_template_class_test.h -check-prefix=CHECK-NEW-TEST-H-CASE1 %s +// +// RUN: cp %S/Inputs/template_class_test* %T/move-template-class +// RUN: clang-move -names="A" -new_cc=%T/move-template-class/new_template_class_test.cpp -new_header=%T/move-template-class/new_template_class_test.h -old_cc=%T/move-template-class/template_class_test.cpp -old_header=../move-template-class/template_class_test.h %T/move-template-class/template_class_test.cpp -- +// RUN: FileCheck -input-file=%T/move-template-class/template_class_test.h -check-prefix=CHECK-OLD-TEST-H-CASE2 %s +// RUN: FileCheck -input-file=%T/move-template-class/template_class_test.cpp -check-prefix=CHECK-OLD-TEST-CPP-CASE2 %s +// RUN: FileCheck -input-file=%T/move-template-class/new_template_class_test.h -check-prefix=CHECK-NEW-TEST-H-CASE2 %s +// RUN: FileCheck -input-file=%T/move-template-class/new_template_class_test.cpp -check-prefix=CHECK-NEW-TEST-CPP-CASE2 %s +// +// +// CHECK-OLD-TEST-EMPTY: {{^}}{{$}} +// +// CHECK-NEW-TEST-H-CASE1: #ifndef TEMPLATE_CLASS_TEST_H // comment 1 +// CHECK-NEW-TEST-H-CASE1: #define TEMPLATE_CLASS_TEST_H +// CHECK-NEW-TEST-H-CASE1: template +// CHECK-NEW-TEST-H-CASE1: class A { +// CHECK-NEW-TEST-H-CASE1: public: +// CHECK-NEW-TEST-H-CASE1: void f(); +// CHECK-NEW-TEST-H-CASE1: void g(); +// CHECK-NEW-TEST-H-CASE1: template void h(); +// CHECK-NEW-TEST-H-CASE1: template void k(); +// CHECK-NEW-TEST-H-CASE1: static int b; +// CHECK-NEW-TEST-H-CASE1: static int c; +// CHECK-NEW-TEST-H-CASE1: }; +// CHECK-NEW-TEST-H-CASE1: template +// CHECK-NEW-TEST-H-CASE1: void A::f() {} +// CHECK-NEW-TEST-H-CASE1: template +// CHECK-NEW-TEST-H-CASE1: template +// CHECK-NEW-TEST-H-CASE1: void A::h() {} +// CHECK-NEW-TEST-H-CASE1: template +// CHECK-NEW-TEST-H-CASE1: int A::b = 2; +// CHECK-NEW-TEST-H-CASE1: class B { +// CHECK-NEW-TEST-H-CASE1: public: +// CHECK-NEW-TEST-H-CASE1: void f(); +// CHECK-NEW-TEST-H-CASE1: }; +// CHECK-NEW-TEST-H-CASE1: #endif // TEMPLATE_CLASS_TEST_H +// +// CHECK-NEW-TEST-CPP-CASE1: #include "{{.*}}new_template_class_test.h" +// CHECK-NEW-TEST-CPP-CASE1: template +// CHECK-NEW-TEST-CPP-CASE1: void A::g() {} +// CHECK-NEW-TEST-CPP-CASE1: template +// CHECK-NEW-TEST-CPP-CASE1: template +// CHECK-NEW-TEST-CPP-CASE1: void A::k() {} +// CHECK-NEW-TEST-CPP-CASE1: template +// CHECK-NEW-TEST-CPP-CASE1: int A::c = 2; +// CHECK-NEW-TEST-CPP-CASE1: void B::f() {} +// +// CHECK-OLD-TEST-H-CASE2: #ifndef TEMPLATE_CLASS_TEST_H // comment 1 +// CHECK-OLD-TEST-H-CASE2: #define TEMPLATE_CLASS_TEST_H +// CHECK-OLD-TEST-H-CASE2: class B { +// CHECK-OLD-TEST-H-CASE2: public: +// CHECK-OLD-TEST-H-CASE2: void f(); +// CHECK-OLD-TEST-H-CASE2: }; +// CHECK-OLD-TEST-H-CASE2: #endif // TEMPLATE_CLASS_TEST_H +// +// CHECK-OLD-TEST-CPP-CASE2: #include "template_class_test.h" +// CHECK-OLD-TEST-CPP-CASE2: void B::f() {} +// +// CHECK-NEW-TEST-H-CASE2: #ifndef {{.*}}NEW_TEMPLATE_CLASS_TEST_H +// CHECK-NEW-TEST-H-CASE2: #define {{.*}}NEW_TEMPLATE_CLASS_TEST_H +// CHECK-NEW-TEST-H-CASE2: template +// CHECK-NEW-TEST-H-CASE2: class A { +// CHECK-NEW-TEST-H-CASE2: public: +// CHECK-NEW-TEST-H-CASE2: void f(); +// CHECK-NEW-TEST-H-CASE2: void g(); +// CHECK-NEW-TEST-H-CASE2: template void h(); +// CHECK-NEW-TEST-H-CASE2: template void k(); +// CHECK-NEW-TEST-H-CASE2: static int b; +// CHECK-NEW-TEST-H-CASE2: static int c; +// CHECK-NEW-TEST-H-CASE2: }; +// CHECK-NEW-TEST-H-CASE2: template void A::f() {} +// CHECK-NEW-TEST-H-CASE2: template template void A::h() {} +// CHECK-NEW-TEST-H-CASE2: template int A::b = 2; +// CHECK-NEW-TEST-H-CASE2: #endif // {{.*}}NEW_TEMPLATE_CLASS_TEST_H +// +// CHECK-NEW-TEST-CPP-CASE2: #include "{{.*}}new_template_class_test.h" +// CHECK-NEW-TEST-CPP-CASE2: template void A::g() {} +// CHECK-NEW-TEST-CPP-CASE2: template template void A::k() {} +// CHECK-NEW-TEST-CPP-CASE2: template int A::c = 2;