diff options
author | Haojian Wu <hokein@google.com> | 2017-10-18 12:10:11 +0000 |
---|---|---|
committer | Haojian Wu <hokein@google.com> | 2017-10-18 12:10:11 +0000 |
commit | 977de9aa100fb9012a1c37d4b1f683b87846e65d (patch) | |
tree | 20d894663de0d9bdcf87ed828f209adee0062780 /lib/Tooling | |
parent | aed3a60e367b760d907954563f404458f9dbd478 (diff) |
[clang-rename] Rename alias.
Summary:
* Support rename alias.
* Add unittests for renaming alias.
* Don't generate fixes for the SourceLocations that are invalid or in temporary
buffer, otherwise crash would be happened when generating AtomicChanges.
Reviewers: ioeric
Reviewed By: ioeric
Subscribers: klimek, mgorny, cfe-commits
Differential Revision: https://reviews.llvm.org/D39043
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316074 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Tooling')
-rw-r--r-- | lib/Tooling/Refactoring/Rename/USRLocFinder.cpp | 119 |
1 files changed, 59 insertions, 60 deletions
diff --git a/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp b/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp index d0576eb3c5..265e3c2072 100644 --- a/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp +++ b/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp @@ -39,6 +39,17 @@ namespace tooling { namespace { +// Returns true if the given Loc is valid for edit. We don't edit the +// SourceLocations that are valid or in temporary buffer. +bool IsValidEditLoc(const clang::SourceManager& SM, clang::SourceLocation Loc) { + if (Loc.isInvalid()) + return false; + const clang::FullSourceLoc FullLoc(Loc, SM); + std::pair<clang::FileID, unsigned> FileIdAndOffset = + FullLoc.getSpellingLoc().getDecomposedLoc(); + return SM.getFileEntryForID(FileIdAndOffset.first) != nullptr; +} + // \brief This visitor recursively searches for all instances of a USR in a // translation unit and stores them for later usage. class USRLocFindingASTVisitor @@ -181,13 +192,22 @@ public: return true; if (isInUSRSet(Decl)) { - RenameInfo Info = {Decl->getLocation(), - Decl->getLocation(), - /*FromDecl=*/nullptr, - /*Context=*/nullptr, - /*Specifier=*/nullptr, - /*IgnorePrefixQualifers=*/true}; - RenameInfos.push_back(Info); + // For the case of renaming an alias template, we actually rename the + // underlying alias declaration of the template. + if (const auto* TAT = dyn_cast<TypeAliasTemplateDecl>(Decl)) + Decl = TAT->getTemplatedDecl(); + + auto StartLoc = Decl->getLocation(); + auto EndLoc = StartLoc; + if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) { + RenameInfo Info = {StartLoc, + EndLoc, + /*FromDecl=*/nullptr, + /*Context=*/nullptr, + /*Specifier=*/nullptr, + /*IgnorePrefixQualifers=*/true}; + RenameInfos.push_back(Info); + } } return true; } @@ -200,7 +220,7 @@ public: Decl = UsingShadow->getTargetDecl(); } - auto BeginLoc = Expr->getLocStart(); + auto StartLoc = 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. @@ -233,8 +253,9 @@ public: assert(EndLoc.isValid() && "The enum constant should have prefix qualifers."); } - if (isInUSRSet(Decl)) { - RenameInfo Info = {BeginLoc, + if (isInUSRSet(Decl) && + IsValidEditLoc(Context.getSourceManager(), StartLoc)) { + RenameInfo Info = {StartLoc, EndLoc, Decl, getClosestAncestorDecl(*Expr), @@ -259,8 +280,6 @@ public: bool VisitNestedNameSpecifierLocations(NestedNameSpecifierLoc NestedLoc) { if (!NestedLoc.getNestedNameSpecifier()->getAsType()) return true; - if (IsTypeAliasWhichWillBeRenamedElsewhere(NestedLoc.getTypeLoc())) - return true; if (const auto *TargetDecl = getSupportedDeclFromTypeLoc(NestedLoc.getTypeLoc())) { @@ -278,9 +297,6 @@ public: } bool VisitTypeLoc(TypeLoc Loc) { - if (IsTypeAliasWhichWillBeRenamedElsewhere(Loc)) - return true; - auto Parents = Context.getParents(Loc); TypeLoc ParentTypeLoc; if (!Parents.empty()) { @@ -314,13 +330,18 @@ public: if (!ParentTypeLoc.isNull() && isInUSRSet(getSupportedDeclFromTypeLoc(ParentTypeLoc))) return true; - RenameInfo Info = {StartLocationForType(Loc), - EndLocationForType(Loc), - TargetDecl, - getClosestAncestorDecl(Loc), - GetNestedNameForType(Loc), - /*IgnorePrefixQualifers=*/false}; - RenameInfos.push_back(Info); + + auto StartLoc = StartLocationForType(Loc); + auto EndLoc = EndLocationForType(Loc); + if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) { + RenameInfo Info = {StartLoc, + EndLoc, + TargetDecl, + getClosestAncestorDecl(Loc), + GetNestedNameForType(Loc), + /*IgnorePrefixQualifers=*/false}; + RenameInfos.push_back(Info); + } return true; } } @@ -344,15 +365,20 @@ public: if (!ParentTypeLoc.isNull() && llvm::isa<ElaboratedType>(ParentTypeLoc.getType())) TargetLoc = ParentTypeLoc; - RenameInfo Info = { - StartLocationForType(TargetLoc), - EndLocationForType(TargetLoc), - TemplateSpecType->getTemplateName().getAsTemplateDecl(), - getClosestAncestorDecl( - ast_type_traits::DynTypedNode::create(TargetLoc)), - GetNestedNameForType(TargetLoc), - /*IgnorePrefixQualifers=*/false}; - RenameInfos.push_back(Info); + + auto StartLoc = StartLocationForType(TargetLoc); + auto EndLoc = EndLocationForType(TargetLoc); + if (IsValidEditLoc(Context.getSourceManager(), StartLoc)) { + RenameInfo Info = { + StartLoc, + EndLoc, + TemplateSpecType->getTemplateName().getAsTemplateDecl(), + getClosestAncestorDecl( + ast_type_traits::DynTypedNode::create(TargetLoc)), + GetNestedNameForType(TargetLoc), + /*IgnorePrefixQualifers=*/false}; + RenameInfos.push_back(Info); + } } } return true; @@ -367,38 +393,11 @@ public: } private: - // FIXME: This method may not be suitable for renaming other types like alias - // types. Need to figure out a way to handle it. - bool IsTypeAliasWhichWillBeRenamedElsewhere(TypeLoc TL) const { - while (!TL.isNull()) { - // SubstTemplateTypeParm is the TypeLocation class for a substituted type - // inside a template expansion so we ignore these. For example: - // - // template<typename T> struct S { - // T t; // <-- this T becomes a TypeLoc(int) with class - // // SubstTemplateTypeParm when S<int> is instantiated - // } - if (TL.getTypeLocClass() == TypeLoc::SubstTemplateTypeParm) - return true; - - // Typedef is the TypeLocation class for a type which is a typedef to the - // type we want to replace. We ignore the use of the typedef as we will - // replace the definition of it. For example: - // - // typedef int T; - // T a; // <--- This T is a TypeLoc(int) with class Typedef. - if (TL.getTypeLocClass() == TypeLoc::Typedef) - return true; - TL = TL.getNextTypeLoc(); - } - return false; - } - // Get the supported declaration from a given typeLoc. If the declaration type // is not supported, returns nullptr. - // - // FIXME: support more types, e.g. type alias. const NamedDecl *getSupportedDeclFromTypeLoc(TypeLoc Loc) { + if (const auto* TT = Loc.getType()->getAs<clang::TypedefType>()) + return TT->getDecl(); if (const auto *RD = Loc.getType()->getAsCXXRecordDecl()) return RD; if (const auto *ED = |