Index: clang-rename/RenamingAction.cpp =================================================================== --- clang-rename/RenamingAction.cpp +++ clang-rename/RenamingAction.cpp @@ -57,19 +57,16 @@ } auto PrevNameLen = PrevName.length(); - if (PrintLocations) - for (const auto &Loc : RenamingCandidates) { + for (const auto &Loc : RenamingCandidates) { + if (PrintLocations) { FullSourceLoc FullLoc(Loc, SourceMgr); errs() << "clang-rename: renamed at: " << SourceMgr.getFilename(Loc) << ":" << FullLoc.getSpellingLineNumber() << ":" << FullLoc.getSpellingColumnNumber() << "\n"; - Replaces.insert(tooling::Replacement(SourceMgr, Loc, PrevNameLen, - NewName)); } - else - for (const auto &Loc : RenamingCandidates) - Replaces.insert(tooling::Replacement(SourceMgr, Loc, PrevNameLen, - NewName)); + Replaces.insert(tooling::Replacement(SourceMgr, Loc, PrevNameLen, + NewName)); + } } private: Index: clang-rename/USRFinder.h =================================================================== --- clang-rename/USRFinder.h +++ clang-rename/USRFinder.h @@ -15,8 +15,14 @@ #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_RENAME_USR_FINDER_H #define LLVM_CLANG_TOOLS_EXTRA_CLANG_RENAME_USR_FINDER_H +#include "clang/AST/AST.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" #include +using namespace llvm; +using namespace clang::ast_matchers; + namespace clang { class ASTContext; class Decl; @@ -39,6 +45,37 @@ // Converts a Decl into a USR. std::string getUSRForDecl(const Decl *Decl); +// FIXME: This wouldn't be needed if +// RecursiveASTVisitor::VisitNestedNameSpecifier would have been implemented. +class NestedNameSpecifierLocFinder : public MatchFinder::MatchCallback { +public: + explicit NestedNameSpecifierLocFinder(ASTContext &Context) + : Context(Context) {} + + std::vector getNestedNameSpecifierLocations() { + addMatchers(); + Finder.matchAST(Context); + return Locations; + } + +private: + void addMatchers() { + const auto NestedNameSpecifierLocMatcher = + nestedNameSpecifierLoc().bind("nestedNameSpecifierLoc"); + Finder.addMatcher(NestedNameSpecifierLocMatcher, this); + } + + virtual void run(const MatchFinder::MatchResult &Result) { + const auto *NNS = + Result.Nodes.getNodeAs("nestedNameSpecifierLoc"); + Locations.push_back(*NNS); + } + + ASTContext &Context; + std::vector Locations; + MatchFinder Finder; +}; + } } Index: clang-rename/USRFinder.cpp =================================================================== --- clang-rename/USRFinder.cpp +++ clang-rename/USRFinder.cpp @@ -16,11 +16,13 @@ #include "clang/AST/AST.h" #include "clang/AST/ASTContext.h" #include "clang/AST/RecursiveASTVisitor.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Index/USRGeneration.h" #include "clang/Lex/Lexer.h" #include "llvm/ADT/SmallVector.h" using namespace llvm; +using namespace clang::ast_matchers; namespace clang { namespace rename { @@ -35,18 +37,15 @@ // \brief Finds the NamedDecl at a point in the source. // \param Point the location in the source to search for the NamedDecl. explicit NamedDeclFindingASTVisitor(const SourceManager &SourceMgr, - const SourceLocation Point) - : Result(nullptr), SourceMgr(SourceMgr), - Point(Point) { - } + const SourceLocation Point, + const ASTContext *Context) + : Result(nullptr), SourceMgr(SourceMgr), Point(Point), Context(Context) {} // \brief Finds the NamedDecl for a name in the source. // \param Name the fully qualified name. explicit NamedDeclFindingASTVisitor(const SourceManager &SourceMgr, const std::string &Name) - : Result(nullptr), SourceMgr(SourceMgr), - Name(Name) { - } + : Result(nullptr), SourceMgr(SourceMgr), Name(Name) {} // Declaration visitors: @@ -62,10 +61,6 @@ // Expression visitors: bool VisitDeclRefExpr(const DeclRefExpr *Expr) { - // Check the namespace specifier first. - if (!checkNestedNameSpecifierLoc(Expr->getQualifierLoc())) - return false; - const auto *Decl = Expr->getFoundDecl(); return setResult(Decl, Expr->getLocation(), Decl->getNameAsString().length()); @@ -77,26 +72,33 @@ Decl->getNameAsString().length()); } - // Other: + // Other visitors: - const NamedDecl *getNamedDecl() { - return Result; + bool VisitTypeLoc(const TypeLoc Loc) { + const auto TypeBeginLoc = Loc.getBeginLoc(), + TypeEndLoc = Lexer::getLocForEndOfToken( + TypeBeginLoc, 0, SourceMgr, Context->getLangOpts()); + return setResult(Loc.getType()->getAsCXXRecordDecl(), TypeBeginLoc, + TypeEndLoc); } -private: + // Other: + + const NamedDecl *getNamedDecl() { return Result; } + // \brief Determines if a namespace qualifier contains the point. // \returns false on success and sets Result. - bool checkNestedNameSpecifierLoc(NestedNameSpecifierLoc NameLoc) { + void handleNestedNameSpecifierLoc(NestedNameSpecifierLoc NameLoc) { while (NameLoc) { const auto *Decl = NameLoc.getNestedNameSpecifier()->getAsNamespace(); - if (Decl && !setResult(Decl, NameLoc.getLocalBeginLoc(), - Decl->getNameAsString().length())) - return false; + if (Decl) { + setResult(Decl, NameLoc.getLocalBeginLoc(), NameLoc.getLocalEndLoc()); + } NameLoc = NameLoc.getPrefix(); } - return true; } +private: // \brief Sets Result to Decl if the Point is within Start and End. // \returns false on success. bool setResult(const NamedDecl *Decl, SourceLocation Start, @@ -119,8 +121,7 @@ // \brief Sets Result to Decl if Point is within Loc and Loc + Offset. // \returns false on success. - bool setResult(const NamedDecl *Decl, SourceLocation Loc, - unsigned Offset) { + bool setResult(const NamedDecl *Decl, SourceLocation Loc, unsigned Offset) { // FIXME: Add test for Offset == 0. Add test for Offset - 1 (vs -2 etc). return Offset == 0 || setResult(Decl, Loc, Loc.getLocWithOffset(Offset - 1)); @@ -138,6 +139,7 @@ const SourceManager &SourceMgr; const SourceLocation Point; // The location to find the NamedDecl. const std::string Name; + const ASTContext *Context; }; } // namespace @@ -146,7 +148,7 @@ const auto &SourceMgr = Context.getSourceManager(); const auto SearchFile = SourceMgr.getFilename(Point); - NamedDeclFindingASTVisitor Visitor(SourceMgr, Point); + NamedDeclFindingASTVisitor Visitor(SourceMgr, Point, &Context); // We only want to search the decls that exist in the same file as the point. auto Decls = Context.getTranslationUnitDecl()->decls(); @@ -156,29 +158,24 @@ // FIXME: Add test. if (FileName == SearchFile) { Visitor.TraverseDecl(CurrDecl); - if (const NamedDecl *Result = Visitor.getNamedDecl()) { - return Result; - } } } - return nullptr; + NestedNameSpecifierLocFinder Finder(const_cast(Context)); + for (const auto &Location : Finder.getNestedNameSpecifierLocations()) { + Visitor.handleNestedNameSpecifierLoc(Location); + } + + return Visitor.getNamedDecl(); } const NamedDecl *getNamedDeclFor(const ASTContext &Context, const std::string &Name) { const auto &SourceMgr = Context.getSourceManager(); NamedDeclFindingASTVisitor Visitor(SourceMgr, Name); - auto Decls = Context.getTranslationUnitDecl()->decls(); - - for (auto &CurrDecl : Decls) { - Visitor.TraverseDecl(CurrDecl); - if (const NamedDecl *Result = Visitor.getNamedDecl()) { - return Result; - } - } + Visitor.TraverseDecl(Context.getTranslationUnitDecl()); - return nullptr; + return Visitor.getNamedDecl(); } std::string getUSRForDecl(const Decl *Decl) { Index: clang-rename/USRFindingAction.cpp =================================================================== --- clang-rename/USRFindingAction.cpp +++ clang-rename/USRFindingAction.cpp @@ -46,10 +46,6 @@ // AdditionalUSRFinder. AdditionalUSRFinder adds USRs of ctor and dtor if given // Decl refers to class and adds USRs of all overridden methods if Decl refers // to virtual method. -// -// FIXME: It's better to match ctors/dtors via typeLoc's instead of adding -// their USRs to the storage, because we can also match CXXConversionDecl's by -// typeLoc and we won't have to "manually" handle them here. class AdditionalUSRFinder : public MatchFinder::MatchCallback { public: explicit AdditionalUSRFinder(const Decl *FoundDecl, ASTContext &Context, @@ -90,23 +86,11 @@ void addUSRsFromOverrideSetsAndCtorDtors() { // If D is CXXRecordDecl we should add all USRs of its constructors. if (const auto *RecordDecl = dyn_cast(FoundDecl)) { - // Ignore destructors. Find the declaration of and explicit calls to a - // destructor through TagTypeLoc (and it is better for the purpose of - // renaming). - // - // For example, in the following code segment, - // 1 class C { - // 2 ~C(); - // 3 }; - // - // At line 3, there is a NamedDecl starting from '~' and a TagTypeLoc - // starting from 'C'. RecordDecl = RecordDecl->getDefinition(); - - // Iterate over all the constructors and add their USRs. for (const auto *CtorDecl : RecordDecl->ctors()) { USRSet.insert(getUSRForDecl(CtorDecl)); } + USRSet.insert(getUSRForDecl(RecordDecl->getDestructor())); } // If D is CXXMethodDecl we should add all USRs of its overriden methods. if (const auto *MethodDecl = dyn_cast(FoundDecl)) { Index: clang-rename/USRLocFinder.cpp =================================================================== --- clang-rename/USRLocFinder.cpp +++ clang-rename/USRLocFinder.cpp @@ -34,38 +34,18 @@ class USRLocFindingASTVisitor : public clang::RecursiveASTVisitor { public: - explicit USRLocFindingASTVisitor(StringRef USR, StringRef PrevName) - : USR(USR), PrevName(PrevName) {} + explicit USRLocFindingASTVisitor(StringRef USR, StringRef PrevName, + const ASTContext &Context) + : USR(USR), PrevName(PrevName), Context(Context) {} // Declaration visitors: - bool VisitNamedDecl(const NamedDecl *Decl) { - if (getUSRForDecl(Decl) == USR) { - LocationsFound.push_back(Decl->getLocation()); - } - return true; - } - - bool VisitVarDecl(clang::VarDecl *Decl) { - clang::QualType Type = Decl->getType(); - const clang::RecordDecl *RecordDecl = Type->getPointeeCXXRecordDecl(); - if (RecordDecl) { - if (getUSRForDecl(RecordDecl) == USR) { - // The declaration refers to a type that is to be renamed. - LocationsFound.push_back(Decl->getTypeSpecStartLoc()); - } - } - return true; - } - bool VisitCXXConstructorDecl(clang::CXXConstructorDecl *ConstructorDecl) { - const ASTContext &Context = ConstructorDecl->getASTContext(); for (auto &Initializer : ConstructorDecl->inits()) { if (Initializer->getSourceOrder() == -1) { // Ignore implicit initializers. continue; } - if (const clang::FieldDecl *FieldDecl = Initializer->getAnyMember()) { if (getUSRForDecl(FieldDecl) == USR) { // The initializer refers to a field that is to be renamed. @@ -81,33 +61,13 @@ } } } - - if (getUSRForDecl(ConstructorDecl) == USR) { - // This takes care of the class name part of a non-inline ctor definition. - LocationsFound.push_back(ConstructorDecl->getLocStart()); - } return true; } - bool VisitCXXDestructorDecl(clang::CXXDestructorDecl *DestructorDecl) { - if (getUSRForDecl(DestructorDecl->getParent()) == USR) { - // Handles "~Foo" from "Foo::~Foo". - SourceLocation Location = DestructorDecl->getLocation(); - const ASTContext &Context = DestructorDecl->getASTContext(); - StringRef LLVM_ATTRIBUTE_UNUSED TokenName = Lexer::getSourceText( - CharSourceRange::getTokenRange(Location), Context.getSourceManager(), - Context.getLangOpts()); - // 1 is the length of the "~" string that is not to be touched by the - // rename. - assert(TokenName.startswith("~")); - LocationsFound.push_back(Location.getLocWithOffset(1)); - - if (DestructorDecl->isThisDeclarationADefinition()) { - // Handles "Foo" from "Foo::~Foo". - LocationsFound.push_back(DestructorDecl->getLocStart()); - } + bool VisitNamedDecl(const NamedDecl *Decl) { + if (getUSRForDecl(Decl) == USR) { + checkAndAddLocation(Decl->getLocation()); } - return true; } @@ -116,11 +76,10 @@ bool VisitDeclRefExpr(const DeclRefExpr *Expr) { const auto *Decl = Expr->getFoundDecl(); - checkNestedNameSpecifierLoc(Expr->getQualifierLoc()); if (getUSRForDecl(Decl) == USR) { const SourceManager &Manager = Decl->getASTContext().getSourceManager(); SourceLocation Location = Manager.getSpellingLoc(Expr->getLocation()); - LocationsFound.push_back(Location); + checkAndAddLocation(Location); } return true; @@ -131,19 +90,8 @@ if (getUSRForDecl(Decl) == USR) { const SourceManager &Manager = Decl->getASTContext().getSourceManager(); SourceLocation Location = Manager.getSpellingLoc(Expr->getMemberLoc()); - LocationsFound.push_back(Location); - } - return true; - } - - bool VisitCXXConstructExpr(const CXXConstructExpr *Expr) { - CXXConstructorDecl *Decl = Expr->getConstructor(); - - if (getUSRForDecl(Decl) == USR) { - // This takes care of 'new ' expressions. - LocationsFound.push_back(Expr->getLocation()); + checkAndAddLocation(Location); } - return true; } @@ -163,6 +111,15 @@ return handleCXXNamedCastExpr(Expr); } + // Other visitors: + + bool VisitTypeLoc(const TypeLoc Loc) { + if (getUSRForDecl(Loc.getType()->getAsCXXRecordDecl()) == USR) { + checkAndAddLocation(Loc.getBeginLoc()); + } + return true; + } + // Non-visitors: // \brief Returns a list of unique locations. Duplicate or overlapping @@ -171,13 +128,13 @@ return LocationsFound; } -private: // Namespace traversal: - void checkNestedNameSpecifierLoc(NestedNameSpecifierLoc NameLoc) { + void handleNestedNameSpecifierLoc(NestedNameSpecifierLoc NameLoc) { while (NameLoc) { const auto *Decl = NameLoc.getNestedNameSpecifier()->getAsNamespace(); - if (Decl && getUSRForDecl(Decl) == USR) - LocationsFound.push_back(NameLoc.getLocalBeginLoc()); + if (Decl && getUSRForDecl(Decl) == USR) { + checkAndAddLocation(NameLoc.getLocalBeginLoc()); + } NameLoc = NameLoc.getPrefix(); } } @@ -194,25 +151,45 @@ if (Decl && getUSRForDecl(Decl) == USR) { SourceLocation Location = Expr->getTypeInfoAsWritten()->getTypeLoc().getBeginLoc(); - LocationsFound.push_back(Location); + checkAndAddLocation(Location); } return true; } +private: + void checkAndAddLocation(SourceLocation Loc) { + const auto BeginLoc = Loc, EndLoc = Lexer::getLocForEndOfToken( + BeginLoc, 0, Context.getSourceManager(), + Context.getLangOpts()); + StringRef TokenName = + Lexer::getSourceText(CharSourceRange::getTokenRange(BeginLoc, EndLoc), + Context.getSourceManager(), Context.getLangOpts()); + size_t Offset = TokenName.find(PrevName); + if (Offset != StringRef::npos) { + // The token of the source location we find actually has the old + // name. + LocationsFound.push_back(BeginLoc.getLocWithOffset(Offset)); + } + } + // All the locations of the USR were found. const std::string USR; // Old name that is renamed. const std::string PrevName; std::vector LocationsFound; + const ASTContext &Context; }; } // namespace std::vector getLocationsOfUSR(StringRef USR, StringRef PrevName, Decl *Decl) { - USRLocFindingASTVisitor Visitor(USR, PrevName); - + USRLocFindingASTVisitor Visitor(USR, PrevName, Decl->getASTContext()); Visitor.TraverseDecl(Decl); + NestedNameSpecifierLocFinder Finder(Decl->getASTContext()); + for (const auto &Location : Finder.getNestedNameSpecifierLocations()) { + Visitor.handleNestedNameSpecifierLoc(Location); + } return Visitor.getLocationsFound(); } Index: test/clang-rename/ClassAsTemplateArgumentFindByClass.cpp =================================================================== --- /dev/null +++ test/clang-rename/ClassAsTemplateArgumentFindByClass.cpp @@ -0,0 +1,20 @@ +// RUN: cat %s > %t.cpp +// RUN: clang-rename -offset=136 -new-name=Bar %t.cpp -i -- +// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s + +class Foo {}; // CHECK: class Bar {}; + +template +void func() {} + +template +class Baz {}; + +int main() { + func(); // CHECK: func(); + Baz obj; // CHECK: Baz obj; + return 0; +} + +// Use grep -FUbo 'Foo' to get the correct offset of Foo when changing +// this file. Index: test/clang-rename/ClassAsTemplateArgumentFindByTemplateArgument.cpp =================================================================== --- /dev/null +++ test/clang-rename/ClassAsTemplateArgumentFindByTemplateArgument.cpp @@ -0,0 +1,20 @@ +// RUN: cat %s > %t.cpp +// RUN: clang-rename -offset=304 -new-name=Bar %t.cpp -i -- +// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s + +class Foo {}; // CHECK: class Bar {}; + +template +void func() {} + +template +class Baz {}; + +int main() { + func(); // CHECK: func(); + Baz obj; // CHECK: Baz obj; + return 0; +} + +// Use grep -FUbo 'Foo' to get the correct offset of Cla when changing +// this file. Index: test/clang-rename/ClassNameInFunctionDefenition.cpp =================================================================== --- test/clang-rename/ClassNameInFunctionDefenition.cpp +++ test/clang-rename/ClassNameInFunctionDefenition.cpp @@ -1,17 +1,10 @@ -// Currently unsupported test. // RUN: cat %s > %t.cpp -// FIXME: clang-rename doesn't recognize symbol in class function definition. +// RUN: clang-rename -offset=136 -new-name=Bar %t.cpp -i -- +// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s -class Foo { +class Foo { // CHECK: class Bar { public: void foo(int x); }; -void Foo::foo(int x) {} -// ^ this one - -int main() { - Foo obj; - obj.foo(0); - return 0; -} +void Foo::foo(int x) {} // CHECK: void Bar::foo(int x) {} Index: test/clang-rename/ComplicatedClassType.cpp =================================================================== --- test/clang-rename/ComplicatedClassType.cpp +++ test/clang-rename/ComplicatedClassType.cpp @@ -1,30 +1,31 @@ -// Unsupported test. // RUN: cat %s > %t.cpp -// FIXME: This test contains very simple constructions likely to be seen in any -// project and therefore passing this test is a slight sign of success. -// Currently, the test fails badly. +// RUN: clang-rename -offset=220 -new-name=Bar %t.cpp -i -- +// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s + +// Forward declaration. +class Foo; // CHECK: class Bar; class Foo { // CHECK: class Bar { - public: - Foo(int value = 0) : x(value) {} // Bar(int value=0) : x(value) {} +public: + Foo(int value = 0) : x(value) {} // CHECK: Bar(int value = 0) : x(value) {} - Foo& operator++(int) { // Bar& operator++(int) { + Foo &operator++(int) { // CHECK: Bar &operator++(int) { x++; return *this; } - bool operator<(Foo const& rhs) { // bool operator<(Bar const &rhs) { + bool operator<(Foo const &rhs) { // CHECK: bool operator<(Bar const &rhs) { return this->x < rhs.x; } - private: +private: int x; }; int main() { - Foo* Pointer = 0; // CHECK: Bar *Pointer = 0; + Foo *Pointer = 0; // CHECK: Bar *Pointer = 0; Foo Variable = Foo(10); // CHECK: Bar Variable = Bar(10); - for (Foo it; it < Variable; it++) { // for (Bar it; it < Variable; it++) {} + for (Foo it; it < Variable; it++) { // CHECK: for (Bar it; it < Variable; it++) { } return 0; } Index: test/clang-rename/TemplateClassInstantiationFindByDeclaration.cpp =================================================================== --- /dev/null +++ test/clang-rename/TemplateClassInstantiationFindByDeclaration.cpp @@ -0,0 +1,44 @@ +// RUN: cat %s > %t.cpp +// RUN: clang-rename -offset=287 -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; +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 'C' to get the correct offset of foo when changing +// this file. Index: test/clang-rename/TemplateClassInstantiationFindByTypeUse.cpp =================================================================== --- /dev/null +++ test/clang-rename/TemplateClassInstantiationFindByTypeUse.cpp @@ -0,0 +1,44 @@ +// RUN: cat %s > %t.cpp +// RUN: clang-rename -offset=703 -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; +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. Index: test/clang-rename/TemplateFunctionFindByDeclaration.cpp =================================================================== --- /dev/null +++ test/clang-rename/TemplateFunctionFindByDeclaration.cpp @@ -0,0 +1,20 @@ +// RUN: cat %s > %t.cpp +// RUN: clang-rename -offset=241 -new-name=bar %t.cpp -i -- +// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s + +// FIXME: clang-rename should be able to rename functions with templates. +// XFAIL: * + +template +T foo(T value) { // CHECK: T boo(T value) { + return value; +} + +int main() { + foo(false); // CHECK: bar(false); + foo(0); // CHECK: bar(0); + return 0; +} + +// Use grep -FUbo 'foo' to get the correct offset of foo when changing +// this file. Index: test/clang-rename/TemplateFunctionFindByUse.cpp =================================================================== --- /dev/null +++ test/clang-rename/TemplateFunctionFindByUse.cpp @@ -0,0 +1,17 @@ +// RUN: cat %s > %t.cpp +// RUN: clang-rename -offset=290 -new-name=Bar %t.cpp -i -- +// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s + +// FIXME: clang-rename should be able to rename functions with templates. +// XFAIL: * + +template +T foo(T value) { + return value; +} + +int main() { + foo(false); + foo(0); + return 0; +} Index: test/clang-rename/TemplateTypename.cpp =================================================================== --- test/clang-rename/TemplateTypename.cpp +++ /dev/null @@ -1,12 +0,0 @@ -// Currently unsupported test. -// RUN: cat %s > %t.cpp -// FIXME: clang-rename should be able to rename template parameters correctly. - -template -T foo(T arg, T& ref, T* ptr) { - T value; - int number = 42; - value = (T)number; - value = static_cast(number); - return value; -} Index: test/clang-rename/TemplateTypenameFindByTemplateParam.cpp =================================================================== --- /dev/null +++ test/clang-rename/TemplateTypenameFindByTemplateParam.cpp @@ -0,0 +1,22 @@ +// RUN: cat %s > %t.cpp +// RUN: clang-rename -offset=270 -new-name=U %t.cpp -i -- +// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s + +// Currently unsupported test. +// FIXME: clang-rename should be able to rename template parameters correctly. +// XFAIL: * + +template // CHECK: template +class Foo { +T foo(T arg, T& ref, T* ptr) { // CHECK: U foo(U arg, U& ref, U* ptr) { + T value; // CHECK: U value; + int number = 42; + value = (T)number; // CHECK: value = (U)number; + value = static_cast(number); // CHECK: value = static_cast(number); + return value; +} + +static void foo(T value) {} // CHECK: static void foo(U value) {} + +T member; // CHECK: U member; +}; Index: test/clang-rename/TemplateTypenameFindByTypeInside.cpp =================================================================== --- /dev/null +++ test/clang-rename/TemplateTypenameFindByTypeInside.cpp @@ -0,0 +1,22 @@ +// RUN: cat %s > %t.cpp +// RUN: clang-rename -offset=350 -new-name=U %t.cpp -i -- +// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s + +// Currently unsupported test. +// FIXME: clang-rename should be able to rename template parameters correctly. +// XFAIL: * + +template // CHECK: template +class Foo { +T foo(T arg, T& ref, T* ptr) { // CHECK: U foo(U arg, U& ref, U* ptr) { + T value; // CHECK: U value; + int number = 42; + value = (T)number; // CHECK: value = (U)number; + value = static_cast(number); // CHECK: value = static_cast(number); + return value; +} + +static void foo(T value) {} // CHECK: static void foo(U value) {} + +T member; // CHECK: U member; +}; Index: test/clang-rename/UserDefinedConversion.cpp =================================================================== --- test/clang-rename/UserDefinedConversion.cpp +++ /dev/null @@ -1,13 +0,0 @@ -// Currently unsupported test. -// RUN: cat %s > %t.cpp -// FIXME: clang-rename should handle conversions from a class type to another -// type. - -class Foo {}; // CHECK: class Bar {}; - -class Baz { // CHECK: class Bar { - operator Foo() const { // CHECK: operator Bar() const { - Foo foo; // CHECK: Bar foo; - return foo; - } -}; Index: test/clang-rename/UserDefinedConversionFindByTypeDeclaration.cpp =================================================================== --- test/clang-rename/UserDefinedConversionFindByTypeDeclaration.cpp +++ test/clang-rename/UserDefinedConversionFindByTypeDeclaration.cpp @@ -1,7 +1,6 @@ -// Currently unsupported test. // RUN: cat %s > %t.cpp -// FIXME: while renaming class/struct clang-rename should be able to change -// this type name corresponding user-defined conversions, too. +// RUN: clang-rename -offset=136 -new-name=Bar %t.cpp -i -- +// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s class Foo { // CHECK: class Bar { // ^ offset must be here @@ -22,3 +21,6 @@ Foo foo = static_cast(boo); // CHECK: Bar foo = static_cast(boo); return 0; } + +// Use grep -FUbo 'Foo' to get the correct offset of Cla when changing +// this file.