Index: clang-tools-extra/trunk/change-namespace/ChangeNamespace.h =================================================================== --- clang-tools-extra/trunk/change-namespace/ChangeNamespace.h +++ clang-tools-extra/trunk/change-namespace/ChangeNamespace.h @@ -76,6 +76,10 @@ void fixUsingShadowDecl(const ast_matchers::MatchFinder::MatchResult &Result, const UsingDecl *UsingDeclaration); + void fixDeclRefExpr(const ast_matchers::MatchFinder::MatchResult &Result, + const DeclContext *UseContext, const NamedDecl *From, + const DeclRefExpr *Ref); + // Information about moving an old namespace. struct MoveNamespace { // The start offset of the namespace block being moved in the original Index: clang-tools-extra/trunk/change-namespace/ChangeNamespace.cpp =================================================================== --- clang-tools-extra/trunk/change-namespace/ChangeNamespace.cpp +++ clang-tools-extra/trunk/change-namespace/ChangeNamespace.cpp @@ -369,11 +369,13 @@ hasAncestor(namespaceDecl(isAnonymous())), hasAncestor(cxxRecordDecl()))), hasParent(namespaceDecl())); - Finder->addMatcher( - decl(forEachDescendant(callExpr(callee(FuncMatcher)).bind("call")), - IsInMovedNs, unless(isImplicit())) - .bind("dc"), - this); + Finder->addMatcher(decl(forEachDescendant(expr(anyOf( + callExpr(callee(FuncMatcher)).bind("call"), + declRefExpr(to(FuncMatcher.bind("func_decl"))) + .bind("func_ref")))), + IsInMovedNs, unless(isImplicit())) + .bind("dc"), + this); auto GlobalVarMatcher = varDecl( hasGlobalStorage(), hasParent(namespaceDecl()), @@ -421,26 +423,32 @@ assert(Var); if (Var->getCanonicalDecl()->isStaticDataMember()) return; - const clang::Decl *Context = Result.Nodes.getNodeAs("dc"); + const auto *Context = Result.Nodes.getNodeAs("dc"); assert(Context && "Empty decl context."); - clang::SourceRange VarRefRange = VarRef->getSourceRange(); - replaceQualifiedSymbolInDeclContext( - Result, Context->getDeclContext(), VarRefRange.getBegin(), - VarRefRange.getEnd(), llvm::cast(Var)); + fixDeclRefExpr(Result, Context->getDeclContext(), + llvm::cast(Var), VarRef); + } else if (const auto *FuncRef = + Result.Nodes.getNodeAs("func_ref")) { + const auto *Func = Result.Nodes.getNodeAs("func_decl"); + assert(Func); + const auto *Context = Result.Nodes.getNodeAs("dc"); + assert(Context && "Empty decl context."); + fixDeclRefExpr(Result, Context->getDeclContext(), + llvm::cast(Func), FuncRef); } else { - const auto *Call = Result.Nodes.getNodeAs("call"); + const auto *Call = Result.Nodes.getNodeAs("call"); assert(Call != nullptr && "Expecting callback for CallExpr."); - const clang::FunctionDecl *Func = Call->getDirectCallee(); + const FunctionDecl *Func = Call->getDirectCallee(); assert(Func != nullptr); // Ignore out-of-line static methods since they will be handled by nested // name specifiers. if (Func->getCanonicalDecl()->getStorageClass() == - clang::StorageClass::SC_Static && + StorageClass::SC_Static && Func->isOutOfLine()) return; - const clang::Decl *Context = Result.Nodes.getNodeAs("dc"); + const auto *Context = Result.Nodes.getNodeAs("dc"); assert(Context && "Empty decl context."); - clang::SourceRange CalleeRange = Call->getCallee()->getSourceRange(); + SourceRange CalleeRange = Call->getCallee()->getSourceRange(); replaceQualifiedSymbolInDeclContext( Result, Context->getDeclContext(), CalleeRange.getBegin(), CalleeRange.getEnd(), llvm::cast(Func)); @@ -698,6 +706,15 @@ llvm_unreachable(llvm::toString(std::move(Err)).c_str()); } +void ChangeNamespaceTool::fixDeclRefExpr( + const ast_matchers::MatchFinder::MatchResult &Result, + const DeclContext *UseContext, const NamedDecl *From, + const DeclRefExpr *Ref) { + SourceRange RefRange = Ref->getSourceRange(); + replaceQualifiedSymbolInDeclContext(Result, UseContext, RefRange.getBegin(), + RefRange.getEnd(), From); +} + void ChangeNamespaceTool::onEndOfTranslationUnit() { // Move namespace blocks and insert forward declaration to old namespace. for (const auto &FileAndNsMoves : MoveNamespaces) { Index: clang-tools-extra/trunk/unittests/change-namespace/ChangeNamespaceTests.cpp =================================================================== --- clang-tools-extra/trunk/unittests/change-namespace/ChangeNamespaceTests.cpp +++ clang-tools-extra/trunk/unittests/change-namespace/ChangeNamespaceTests.cpp @@ -457,6 +457,40 @@ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code)); } +TEST_F(ChangeNamespaceTest, FixNonCallingFunctionReferences) { + std::string Code = "namespace na {\n" + "class A {\n" + "public:\n" + " static void f() {}\n" + "};\n" + "void a_f() {}\n" + "static void s_f() {}\n" + "namespace nb {\n" + "void f() {\n" + "auto *ref1 = A::f; auto *ref2 = a_f; auto *ref3 = s_f;\n" + "}\n" + "} // namespace nb\n" + "} // namespace na\n"; + std::string Expected = + "namespace na {\n" + "class A {\n" + "public:\n" + " static void f() {}\n" + "};\n" + "void a_f() {}\n" + "static void s_f() {}\n" + "\n" + "} // namespace na\n" + "namespace x {\n" + "namespace y {\n" + "void f() {\n" + "auto *ref1 = na::A::f; auto *ref2 = na::a_f; auto *ref3 = na::s_f;\n" + "}\n" + "} // namespace y\n" + "} // namespace x\n"; + EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code)); +} + TEST_F(ChangeNamespaceTest, MoveAndFixGlobalVariables) { std::string Code = "namespace na {\n" "int GlobA;\n"