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 @@ -230,8 +230,6 @@ DiffNewNamespace = joinNamespaces(NewNsSplitted); } -// FIXME: handle the following symbols: -// - Variable references. void ChangeNamespaceTool::registerMatchers(ast_matchers::MatchFinder *Finder) { // Match old namespace blocks. std::string FullOldNs = "::" + OldNamespace; @@ -303,6 +301,14 @@ IsInMovedNs, unless(isImplicit())) .bind("dc"), this); + + auto GlobalVarMatcher = varDecl( + hasGlobalStorage(), hasParent(namespaceDecl()), + unless(anyOf(IsInMovedNs, hasAncestor(namespaceDecl(isAnonymous()))))); + Finder->addMatcher(declRefExpr(IsInMovedNs, hasAncestor(decl().bind("dc")), + to(GlobalVarMatcher.bind("var_decl"))) + .bind("var_ref"), + this); } void ChangeNamespaceTool::run( @@ -324,8 +330,19 @@ } else if (const auto *TLoc = Result.Nodes.getNodeAs("type")) { fixTypeLoc(Result, startLocationForType(*TLoc), EndLocationForType(*TLoc), *TLoc); + } else if (const auto *VarRef = Result.Nodes.getNodeAs("var_ref")){ + const auto *Var = Result.Nodes.getNodeAs("var_decl"); + assert(Var); + if (Var->getCanonicalDecl()->isStaticDataMember()) + return; + std::string Name = Var->getQualifiedNameAsString(); + const clang::Decl *Context = Result.Nodes.getNodeAs("dc"); + assert(Context && "Empty decl context."); + clang::SourceRange VarRefRange = VarRef->getSourceRange(); + replaceQualifiedSymbolInDeclContext(Result, Context, VarRefRange.getBegin(), + VarRefRange.getEnd(), Name); } 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(); assert(Func != nullptr); 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 @@ -447,6 +447,72 @@ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code)); } +TEST_F(ChangeNamespaceTest, MoveAndFixGlobalVariables) { + std::string Code = "namespace na {\n" + "int GlobA;\n" + "static int GlobAStatic = 0;\n" + "namespace nc { int GlobC; }\n" + "namespace nb {\n" + "int GlobB;\n" + "void f() {\n" + " int a = GlobA;\n" + " int b = GlobAStatic;\n" + " int c = nc::GlobC;\n" + "}\n" + "} // namespace nb\n" + "} // namespace na\n"; + + std::string Expected = "namespace na {\n" + "int GlobA;\n" + "static int GlobAStatic = 0;\n" + "namespace nc { int GlobC; }\n" + "\n" + "} // namespace na\n" + "namespace x {\n" + "namespace y {\n" + "int GlobB;\n" + "void f() {\n" + " int a = na::GlobA;\n" + " int b = na::GlobAStatic;\n" + " int c = na::nc::GlobC;\n" + "}\n" + "} // namespace y\n" + "} // namespace x\n"; + + EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code)); +} + +TEST_F(ChangeNamespaceTest, DoNotFixStaticVariableOfClass) { + std::string Code = "namespace na {\n" + "class A {\n" + "public:\n" + "static int A1;\n" + "static int A2;\n" + "}\n" + "static int A::A1 = 0;\n" + "namespace nb {\n" + "void f() { int a = A::A1; int b = A::A2; }" + "} // namespace nb\n" + "} // namespace na\n"; + + std::string Expected = "namespace na {\n" + "class A {\n" + "public:\n" + "static int A1;\n" + "static int A2;\n" + "}\n" + "static int A::A1 = 0;\n" + "\n" + "} // namespace na\n" + "namespace x {\n" + "namespace y {\n" + "void f() { int a = na::A::A1; int b = na::A::A2; }" + "} // namespace y\n" + "} // namespace x\n"; + + EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code)); +} + } // anonymous namespace } // namespace change_namespace } // namespace clang