Index: clang-rename/USRFinder.cpp =================================================================== --- clang-rename/USRFinder.cpp +++ clang-rename/USRFinder.cpp @@ -81,6 +81,11 @@ dyn_cast(Loc.getType())) { return setResult(TemplateTypeParm->getDecl(), TypeBeginLoc, TypeEndLoc); } + if (const auto *TemplateSpecType = + dyn_cast(Loc.getType())) { + return setResult(TemplateSpecType->getTemplateName().getAsTemplateDecl(), + TypeBeginLoc, TypeEndLoc); + } return setResult(Loc.getType()->getAsCXXRecordDecl(), TypeBeginLoc, TypeEndLoc); } Index: clang-rename/USRFindingAction.cpp =================================================================== --- clang-rename/USRFindingAction.cpp +++ clang-rename/USRFindingAction.cpp @@ -53,12 +53,14 @@ : FoundDecl(FoundDecl), Context(Context), USRs(USRs), USRSet(), Finder() {} void Find() { - USRSet.insert(getUSRForDecl(FoundDecl)); if (const auto *MethodDecl = dyn_cast(FoundDecl)) { addUSRsFromOverrideSets(MethodDecl); - } - if (const auto *RecordDecl = dyn_cast(FoundDecl)) { - addUSRsOfCtorDtors(RecordDecl); + } else if (const auto *RecordDecl = dyn_cast(FoundDecl)) { + handleCXXRecordDecl(RecordDecl); + } else if (const auto *TemplateDecl = dyn_cast(FoundDecl)) { + handleClassTemplateDecl(TemplateDecl); + } else { + USRSet.insert(getUSRForDecl(FoundDecl)); } addMatchers(); Finder.matchAST(Context); @@ -87,12 +89,29 @@ } } + void handleCXXRecordDecl(const CXXRecordDecl *RecordDecl) { + RecordDecl = RecordDecl->getDefinition(); + if (const auto *ClassTemplateSpecDecl + = dyn_cast(RecordDecl)) { + handleClassTemplateDecl(ClassTemplateSpecDecl->getSpecializedTemplate()); + } + addUSRsOfCtorDtors(RecordDecl); + } + + void handleClassTemplateDecl(const ClassTemplateDecl *TemplateDecl) { + for (const auto *Specialization : TemplateDecl->specializations()) { + addUSRsOfCtorDtors(Specialization); + } + addUSRsOfCtorDtors(TemplateDecl->getTemplatedDecl()); + } + void addUSRsOfCtorDtors(const CXXRecordDecl *RecordDecl) { RecordDecl = RecordDecl->getDefinition(); for (const auto *CtorDecl : RecordDecl->ctors()) { USRSet.insert(getUSRForDecl(CtorDecl)); } USRSet.insert(getUSRForDecl(RecordDecl->getDestructor())); + USRSet.insert(getUSRForDecl(RecordDecl)); } void addUSRsFromOverrideSets(const CXXMethodDecl *MethodDecl) { Index: test/clang-rename/TemplateClassInstantiationFindByDeclaration.cpp =================================================================== --- test/clang-rename/TemplateClassInstantiationFindByDeclaration.cpp +++ test/clang-rename/TemplateClassInstantiationFindByDeclaration.cpp @@ -1,14 +1,9 @@ // RUN: cat %s > %t.cpp -// RUN: clang-rename -offset=287 -new-name=Bar %t.cpp -i -- +// RUN: clang-rename -offset=159 -new-name=Bar %t.cpp -i -- // RUN: sed 's,//.*,,' %t.cpp | FileCheck %s -// Currently unsupported test. -// FIXME: clang-rename should be able to rename classes with templates -// correctly. -// XFAIL: * - template -class Foo { // CHECK: class Bar; +class Foo { // CHECK: class Bar { public: T foo(T arg, T& ref, T* ptr) { T value; Index: test/clang-rename/TemplateClassInstantiationFindByTypeUse.cpp =================================================================== --- test/clang-rename/TemplateClassInstantiationFindByTypeUse.cpp +++ test/clang-rename/TemplateClassInstantiationFindByTypeUse.cpp @@ -1,14 +1,9 @@ // RUN: cat %s > %t.cpp -// RUN: clang-rename -offset=703 -new-name=Bar %t.cpp -i -- +// RUN: clang-rename -offset=575 -new-name=Bar %t.cpp -i -- // RUN: sed 's,//.*,,' %t.cpp | FileCheck %s -// Currently unsupported test. -// FIXME: clang-rename should be able to rename classes with templates -// correctly. -// XFAIL: * - template -class Foo { // CHECK: class Bar; +class Foo { // CHECK: class Bar { public: T foo(T arg, T& ref, T* ptr) { T value; Index: test/clang-rename/TemplateClassInstantiationFindByUninstantiatedType.cpp =================================================================== --- /dev/null +++ test/clang-rename/TemplateClassInstantiationFindByUninstantiatedType.cpp @@ -0,0 +1,39 @@ +// RUN: cat %s > %t.cpp +// RUN: clang-rename -offset=440 -new-name=Bar %t.cpp -i -- +// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s + +template +class Foo { // CHECK: class Bar { +public: + T foo(T arg, T& ref, T* ptr) { + T value; + int number = 42; + value = (T)number; + value = static_cast(number); + return value; + } + static void foo(T value) {} + T member; +}; + +template +void func() { + Foo obj; // CHECK: Bar obj; + obj.member = T(); + Foo::foo(); // CHECK: Bar::foo(); +} + +int main() { + Foo i; // CHECK: Bar i; + i.member = 0; + Foo::foo(0); // CHECK: Bar::foo(0); + + Foo b; // CHECK: Bar b; + b.member = false; + Foo::foo(false); // CHECK: Bar::foo(false); + + return 0; +} + +// Use grep -FUbo 'Foo' to get the correct offset of foo when changing +// this file.