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.cpp =================================================================== --- clang-rename/USRFinder.cpp +++ clang-rename/USRFinder.cpp @@ -35,18 +35,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: @@ -77,21 +74,31 @@ Decl->getNameAsString().length()); } - // Other: + // Other visitors: - const NamedDecl *getNamedDecl() { - return Result; + bool VisitTypeLoc(const TypeLoc Loc) { + const auto TypeEndLoc = Loc.getEndLoc(), + TypeBeginLoc = Lexer::GetBeginningOfToken( + TypeEndLoc, SourceMgr, Context->getLangOpts()); + return setResult(Loc.getType()->getAsCXXRecordDecl(), TypeBeginLoc, + TypeEndLoc); } + // Other: + + const NamedDecl *getNamedDecl() { return Result; } + private: // \brief Determines if a namespace qualifier contains the point. // \returns false on success and sets Result. bool checkNestedNameSpecifierLoc(NestedNameSpecifierLoc NameLoc) { while (NameLoc) { const auto *Decl = NameLoc.getNestedNameSpecifier()->getAsNamespace(); - if (Decl && !setResult(Decl, NameLoc.getLocalBeginLoc(), - Decl->getNameAsString().length())) + if (Decl && + !setResult(Decl, NameLoc.getLocalBeginLoc(), + Decl->getNameAsString().length())) { return false; + } NameLoc = NameLoc.getPrefix(); } return true; @@ -119,8 +126,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 +144,7 @@ const SourceManager &SourceMgr; const SourceLocation Point; // The location to find the NamedDecl. const std::string Name; + const ASTContext *Context; }; } // namespace @@ -146,7 +153,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(); Index: clang-rename/USRLocFinder.cpp =================================================================== --- clang-rename/USRLocFinder.cpp +++ clang-rename/USRLocFinder.cpp @@ -46,18 +46,6 @@ 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()) { @@ -136,17 +124,6 @@ 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()); - } - - return true; - } - bool VisitCXXStaticCastExpr(clang::CXXStaticCastExpr *Expr) { return handleCXXNamedCastExpr(Expr); } @@ -163,6 +140,19 @@ return handleCXXNamedCastExpr(Expr); } + // Other visitors: + + bool VisitTypeLoc(const TypeLoc Loc) { + if (getUSRForDecl(Loc.getType()->getAsCXXRecordDecl()) == USR) { + const auto &Context = + Loc.getType()->getAsCXXRecordDecl()->getASTContext(); + auto TypeBeginLoc = Lexer::GetBeginningOfToken( + Loc.getEndLoc(), Context.getSourceManager(), Context.getLangOpts()); + LocationsFound.push_back(TypeBeginLoc); + } + return true; + } + // Non-visitors: // \brief Returns a list of unique locations. Duplicate or overlapping 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/ComplicatedClassTypeInCustomNamespace.cpp =================================================================== --- /dev/null +++ test/clang-rename/ComplicatedClassTypeInCustomNamespace.cpp @@ -0,0 +1,37 @@ +// RUN: cat %s > %t.cpp +// RUN: clang-rename -offset=241 -new-name=Bar %t.cpp -i -- +// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s + +namespace baz { + +// Forward declaration. +class Foo; // CHECK: class Bar; + +class Foo { // CHECK: class Bar { + public: + Foo(int value = 0) : x(value) {} // CHECK: Bar(int value = 0) : x(value) {} + + Foo &operator++(int) { // CHECK: Bar &operator++(int) { + x++; + return *this; + } + + bool operator<(Foo const &rhs) { // CHECK: bool operator<(Bar const &rhs) { + return this->x < rhs.x; + } + + private: + int x; +}; + +Foo Instance; // CHECK: Bar Instance; + +} + +int main() { + baz::Foo *Pointer = 0; // CHECK: baz::Bar *Pointer = 0; + baz::Foo Variable = baz::Foo(10); // CHECK: baz::Bar Variable = baz::Bar(10); + for (baz::Foo it; it < Variable; it++) { // CHECK: for (baz::Bar it; it < Variable; it++) { + } + return 0; +} Index: test/clang-rename/NestedNamespace.cpp =================================================================== --- /dev/null +++ test/clang-rename/NestedNamespace.cpp @@ -0,0 +1,42 @@ +// RUN: cat %s > %t.cpp +// RUN: clang-rename -offset=274 -new-name=Bar %t.cpp -i -- +// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s + +// Currently unsupported test. +// FIXME: Teach clang-rename to rename namespace in nested constructions. +// XFAIL: * + +namespace Baz { +namespace Foo { // CHECK: namespace Bar { +class A { +public: + static int aFunction() { return 0; } +}; +int FooFunction() { return 0; } +namespace Qux { +class B { +public: + static int bFunction() { return 0; } +}; +int QuxFunction() { return 0; } +} // namespace Qux +} // namespace Foo +} // namespace Baz + +int main() { + + // Variable type tests. + Baz::Foo::A a; // CHECK: Baz::Bar::A a; + Baz::Foo::Qux::B b; // CHECK: Baz::Bar::Qux::B b; + unsigned i = 42; + for (Baz::Foo::A c; i < 100; i++); // CHECK: for (Baz::Bar::A c; i < 100; i++); + for (Baz::Foo::Qux::B d; i < 200; i++); // CHECK: for (Baz::Bar::Qux::B d; i < 200; i++); + + // Function tests. + int x = Baz::Foo::A::aFunction(); // CHECK: int x = Baz::Bar::A::aFunction(); + x = Baz::Foo::FooFunction(); // CHECK: x = Baz::Bar::FooFunction(); + x = Baz::Foo::Qux::B::bFunction(); // CHECK: x = Baz::Bar::Qux::B::bFunction(); + x = Baz::Foo::Qux::QuxFunction(); // CHECK: x = Baz::Bar::Qux::QuxFunction(); + + return 0; +} Index: test/clang-rename/TemplateTypename.cpp =================================================================== --- test/clang-rename/TemplateTypename.cpp +++ test/clang-rename/TemplateTypename.cpp @@ -1,12 +1,20 @@ -// Currently unsupported test. // 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 -T foo(T arg, T& ref, T* ptr) { - T value; +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; - value = static_cast(number); + value = (T)number; // CHECK: value = (U)number; + value = static_cast(number); // CHECK: value = static_cast(number); return value; } + +T member; // CHECK: U member; +}; Index: test/clang-rename/UserDefinedConversionFindByConversion.cpp =================================================================== --- test/clang-rename/UserDefinedConversionFindByConversion.cpp +++ test/clang-rename/UserDefinedConversionFindByConversion.cpp @@ -1,11 +1,10 @@ -// Currently unsupported test. // RUN: cat %s > %t.cpp -// FIXME: clang-rename should handle conversions from a class type to another -// type. +// RUN: clang-rename -offset=136 -new-name=Bar %t.cpp -i -- +// RUN: sed 's,//.*,,' %t.cpp | FileCheck %s class Foo {}; // CHECK: class Bar {}; -class Baz { // CHECK: class Bar { +class Baz { 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