[change-namespace] fix namespace specifier of global variables.

Reviewers: hokein

Subscribers: cfe-commits

Differential Revision: https://reviews.llvm.org/D24963

llvm-svn: 282837
This commit is contained in:
Eric Liu 2016-09-30 04:32:39 +00:00
parent de03ff7063
commit 159f0135b1
2 changed files with 86 additions and 3 deletions

View File

@ -230,8 +230,6 @@ ChangeNamespaceTool::ChangeNamespaceTool(
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 @@ void ChangeNamespaceTool::registerMatchers(ast_matchers::MatchFinder *Finder) {
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 @@ void ChangeNamespaceTool::run(
} else if (const auto *TLoc = Result.Nodes.getNodeAs<TypeLoc>("type")) {
fixTypeLoc(Result, startLocationForType(*TLoc), EndLocationForType(*TLoc),
*TLoc);
} else if (const auto *VarRef = Result.Nodes.getNodeAs<DeclRefExpr>("var_ref")){
const auto *Var = Result.Nodes.getNodeAs<VarDecl>("var_decl");
assert(Var);
if (Var->getCanonicalDecl()->isStaticDataMember())
return;
std::string Name = Var->getQualifiedNameAsString();
const clang::Decl *Context = Result.Nodes.getNodeAs<clang::Decl>("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<clang::CallExpr>("call");
const auto *Call = Result.Nodes.getNodeAs<clang::CallExpr>("call");
assert(Call != nullptr &&"Expecting callback for CallExpr.");
const clang::FunctionDecl* Func = Call->getDirectCallee();
assert(Func != nullptr);

View File

@ -447,6 +447,72 @@ TEST_F(ChangeNamespaceTest, FixFunctionNameSpecifiers) {
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