summaryrefslogtreecommitdiffstats
path: root/lib/Tooling/Refactoring
diff options
context:
space:
mode:
authorHaojian Wu <hokein@google.com>2017-10-17 14:14:41 +0000
committerHaojian Wu <hokein@google.com>2017-10-17 14:14:41 +0000
commit942e003931fb4d7107fbe5e439966e1452e9ed33 (patch)
tree253f51f24f773aee3e2a075f8503ba491fefc148 /lib/Tooling/Refactoring
parent19e976a47167c7239e742fc508d644b714f10016 (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.cpp44
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;
}