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 @@ -231,7 +231,6 @@ } // FIXME: handle the following symbols: -// - Function references. // - Variable references. void ChangeNamespaceTool::registerMatchers(ast_matchers::MatchFinder *Finder) { // Match old namespace blocks. @@ -283,6 +282,22 @@ hasDeclaration(DeclMatcher.bind("from_decl")))))) .bind("nested_specifier_loc"), this); + + // Handle function. + // Only handle functions that are defined in a namespace excluding static + // methods (qualified by nested specifier) and functions defined in the global + // namespace. + // Note that the matcher does not exclude calls to out-of-line static method + // definitions, so we need to exclude them in the callback handler. + auto FuncMatcher = functionDecl( + hasParent(namespaceDecl()), + unless(anyOf(IsInMovedNs, hasAncestor(namespaceDecl(isAnonymous())), + hasAncestor(cxxRecordDecl())))); + Finder->addMatcher( + decl(forEachDescendant(callExpr(callee(FuncMatcher)).bind("call")), + IsInMovedNs) + .bind("dc"), + this); } void ChangeNamespaceTool::run( @@ -301,11 +316,26 @@ SourceLocation Start = Specifier->getBeginLoc(); SourceLocation End = EndLocationForType(Specifier->getTypeLoc()); fixTypeLoc(Result, Start, End, Specifier->getTypeLoc()); - } else { - const auto *TLoc = Result.Nodes.getNodeAs("type"); - assert(TLoc != nullptr && "Expecting callback for TypeLoc"); + } else if (const auto *TLoc = Result.Nodes.getNodeAs("type")) { fixTypeLoc(Result, startLocationForType(*TLoc), EndLocationForType(*TLoc), *TLoc); + } else { + const auto* Call = Result.Nodes.getNodeAs("call"); + assert(Call != nullptr &&"Expecting callback for CallExpr."); + const clang::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 && + Func->isOutOfLine()) + return; + std::string Name = Func->getQualifiedNameAsString(); + const clang::Decl *Context = Result.Nodes.getNodeAs("dc"); + assert(Context && "Empty decl context."); + clang::SourceRange CalleeRange = Call->getCallee()->getSourceRange(); + replaceQualifiedSymbolInDeclContext(Result, Context, CalleeRange.getBegin(), + CalleeRange.getEnd(), Name); } } 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 @@ -314,6 +314,43 @@ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code)); } +TEST_F(ChangeNamespaceTest, FixFunctionNameSpecifiers) { + std::string Code = + "namespace na {\n" + "class A {\n" + "public:\n" + " static void f() {}\n" + " static void g();\n" + "};\n" + "void A::g() {}" + "void a_f() {}\n" + "static void static_f() {}\n" + "namespace nb {\n" + "void f() { a_f(); static_f(); A::f(); }\n" + "void g() { f(); A::g(); }\n" + "} // namespace nb\n" + "} // namespace na\n"; + std::string Expected = + "namespace na {\n" + "class A {\n" + "public:\n" + " static void f() {}\n" + " static void g();\n" + "};\n" + "void A::g() {}" + "void a_f() {}\n" + "static void static_f() {}\n" + "\n" + "} // namespace na\n" + "namespace x {\n" + "namespace y {\n" + "void f() { na::a_f(); na::static_f(); na::A::f(); }\n" + "void g() { f(); na::A::g(); }\n" + "} // namespace y\n" + "} // namespace x\n"; + EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code)); +} + } // anonymous namespace } // namespace change_namespace } // namespace clang