diff options
author | Eric Liu <ioeric@google.com> | 2017-02-02 17:40:38 +0000 |
---|---|---|
committer | Eric Liu <ioeric@google.com> | 2017-02-02 17:40:38 +0000 |
commit | ad721e755d33fa5aa3a2f0c50ab7511d5c14537b (patch) | |
tree | 1679602e904b65c76e60ee94adb1a09c859fd186 /clang-tools-extra/change-namespace | |
parent | ee1e5aeb2ad7020fa884c2062359d4b9abd992dc (diff) |
[change-namespace] fix unscoped enum constant references.
Reviewers: bkramer
Subscribers: cfe-commits
Differential Revision: https://reviews.llvm.org/D29460
Diffstat (limited to 'clang-tools-extra/change-namespace')
-rw-r--r-- | clang-tools-extra/change-namespace/ChangeNamespace.cpp | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/clang-tools-extra/change-namespace/ChangeNamespace.cpp b/clang-tools-extra/change-namespace/ChangeNamespace.cpp index 728aa2b8bc2..7d0840ab8d0 100644 --- a/clang-tools-extra/change-namespace/ChangeNamespace.cpp +++ b/clang-tools-extra/change-namespace/ChangeNamespace.cpp @@ -282,6 +282,10 @@ bool isDeclVisibleAtLocation(const SourceManager &SM, const Decl *D, isNestedDeclContext(DeclCtx, D->getDeclContext())); } +AST_MATCHER(EnumDecl, isScoped) { + return Node.isScoped(); +} + } // anonymous namespace ChangeNamespaceTool::ChangeNamespaceTool( @@ -454,6 +458,17 @@ void ChangeNamespaceTool::registerMatchers(ast_matchers::MatchFinder *Finder) { to(GlobalVarMatcher.bind("var_decl"))) .bind("var_ref"), this); + + // Handle unscoped enum constant. + auto UnscopedEnumMatcher = enumConstantDecl(hasParent(enumDecl( + hasParent(namespaceDecl()), + unless(anyOf(isScoped(), IsInMovedNs, hasAncestor(cxxRecordDecl()), + hasAncestor(namespaceDecl(isAnonymous()))))))); + Finder->addMatcher( + declRefExpr(IsInMovedNs, hasAncestor(decl().bind("dc")), + to(UnscopedEnumMatcher.bind("enum_const_decl"))) + .bind("enum_const_ref"), + this); } void ChangeNamespaceTool::run( @@ -518,6 +533,21 @@ void ChangeNamespaceTool::run( assert(Context && "Empty decl context."); fixDeclRefExpr(Result, Context->getDeclContext(), llvm::cast<NamedDecl>(Var), VarRef); + } else if (const auto *EnumConstRef = + Result.Nodes.getNodeAs<DeclRefExpr>("enum_const_ref")) { + // Do not rename the reference if it is already scoped by the EnumDecl name. + if (EnumConstRef->hasQualifier() && + EnumConstRef->getQualifier()->getAsType()->isEnumeralType()) + return; + const auto *EnumConstDecl = + Result.Nodes.getNodeAs<EnumConstantDecl>("enum_const_decl"); + assert(EnumConstDecl); + const auto *Context = Result.Nodes.getNodeAs<Decl>("dc"); + assert(Context && "Empty decl context."); + // FIXME: this would qualify "ns::VALUE" as "ns::EnumValue::VALUE". Fix it + // if it turns out to be an issue. + fixDeclRefExpr(Result, Context->getDeclContext(), + llvm::cast<NamedDecl>(EnumConstDecl), EnumConstRef); } else if (const auto *FuncRef = Result.Nodes.getNodeAs<DeclRefExpr>("func_ref")) { // If this reference has been processed as a function call, we do not |