diff options
author | Haojian Wu <hokein@google.com> | 2017-10-17 14:14:41 +0000 |
---|---|---|
committer | Haojian Wu <hokein@google.com> | 2017-10-17 14:14:41 +0000 |
commit | 942e003931fb4d7107fbe5e439966e1452e9ed33 (patch) | |
tree | 253f51f24f773aee3e2a075f8503ba491fefc148 /lib/Tooling/Refactoring | |
parent | 19e976a47167c7239e742fc508d644b714f10016 (diff) |
[clang-rename] Rename enum.
Summary:
* Add unit tests for renaming enum.
* Support unscoped enum constants in expressions.
Reviewers: ioeric
Reviewed By: ioeric
Subscribers: klimek, mgorny, cfe-commits
Differential Revision: https://reviews.llvm.org/D38989
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@315999 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Tooling/Refactoring')
-rw-r--r-- | lib/Tooling/Refactoring/Rename/USRLocFinder.cpp | 44 |
1 files changed, 40 insertions, 4 deletions
diff --git a/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp b/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp index 7f14dc2e0f..d0576eb3c5 100644 --- a/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp +++ b/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp @@ -196,13 +196,46 @@ public: const NamedDecl *Decl = Expr->getFoundDecl(); // Get the underlying declaration of the shadow declaration introduced by a // using declaration. - if (auto* UsingShadow = llvm::dyn_cast<UsingShadowDecl>(Decl)) { + if (auto *UsingShadow = llvm::dyn_cast<UsingShadowDecl>(Decl)) { Decl = UsingShadow->getTargetDecl(); } + auto BeginLoc = Expr->getLocStart(); + auto EndLoc = Expr->getLocEnd(); + // In case of renaming an enum declaration, we have to explicitly handle + // unscoped enum constants referenced in expressions (e.g. + // "auto r = ns1::ns2::Green" where Green is an enum constant of an unscoped + // enum decl "ns1::ns2::Color") as these enum constants cannot be caught by + // TypeLoc. + if (const auto *T = llvm::dyn_cast<EnumConstantDecl>(Decl)) { + // FIXME: Handle the enum constant without prefix qualifiers (`a = Green`) + // when renaming an unscoped enum declaration with a new namespace. + if (!Expr->hasQualifier()) + return true; + + if (const auto *ED = + llvm::dyn_cast_or_null<EnumDecl>(getClosestAncestorDecl(*T))) { + if (ED->isScoped()) + return true; + Decl = ED; + } + // The current fix would qualify "ns1::ns2::Green" as + // "ns1::ns2::Color::Green". + // + // Get the EndLoc of the replacement by moving 1 character backward ( + // to exclude the last '::'). + // + // ns1::ns2::Green; + // ^ ^^ + // BeginLoc |EndLoc of the qualifier + // new EndLoc + EndLoc = Expr->getQualifierLoc().getEndLoc().getLocWithOffset(-1); + assert(EndLoc.isValid() && + "The enum constant should have prefix qualifers."); + } if (isInUSRSet(Decl)) { - RenameInfo Info = {Expr->getSourceRange().getBegin(), - Expr->getSourceRange().getEnd(), + RenameInfo Info = {BeginLoc, + EndLoc, Decl, getClosestAncestorDecl(*Expr), Expr->getQualifier(), @@ -364,10 +397,13 @@ private: // Get the supported declaration from a given typeLoc. If the declaration type // is not supported, returns nullptr. // - // FIXME: support more types, e.g. enum, type alias. + // FIXME: support more types, e.g. type alias. const NamedDecl *getSupportedDeclFromTypeLoc(TypeLoc Loc) { if (const auto *RD = Loc.getType()->getAsCXXRecordDecl()) return RD; + if (const auto *ED = + llvm::dyn_cast_or_null<EnumDecl>(Loc.getType()->getAsTagDecl())) + return ED; return nullptr; } |