[change-namespace] consider typedef/using alias decls in the moved namespace.

Summary: If a TypeLoc refers to a type alias defined in the moved namespace, we do not need to update its specifier since the type alias decl will be moved along with the type reference.

Reviewers: hokein

Subscribers: cfe-commits

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

llvm-svn: 286873
This commit is contained in:
Eric Liu 2016-11-14 19:37:55 +00:00
parent 10e59fac3e
commit 3215886b7a
2 changed files with 90 additions and 7 deletions

View File

@ -621,8 +621,27 @@ void ChangeNamespaceTool::fixTypeLoc(
const auto *FromDecl = Result.Nodes.getNodeAs<NamedDecl>("from_decl");
// `hasDeclaration` gives underlying declaration, but if the type is
// a typedef type, we need to use the typedef type instead.
if (auto *Typedef = Type.getType()->getAs<TypedefType>())
if (auto *Typedef = Type.getType()->getAs<TypedefType>()) {
FromDecl = Typedef->getDecl();
auto IsInMovedNs = [&](const NamedDecl *D) {
if (!llvm::StringRef(D->getQualifiedNameAsString())
.startswith(OldNamespace + "::"))
return false;
auto ExpansionLoc =
Result.SourceManager->getExpansionLoc(D->getLocStart());
if (ExpansionLoc.isInvalid())
return false;
llvm::StringRef Filename =
Result.SourceManager->getFilename(ExpansionLoc);
llvm::Regex RE(FilePattern);
return RE.match(Filename);
};
// Don't fix the \p Type if it refers to a type alias decl in the moved
// namespace since the alias decl will be moved along with the type
// reference.
if (IsInMovedNs(FromDecl))
return;
}
const Decl *DeclCtx = Result.Nodes.getNodeAs<Decl>("dc");
assert(DeclCtx && "Empty decl context.");

View File

@ -822,22 +822,22 @@ TEST_F(ChangeNamespaceTest, UsingShadowDeclInFunction) {
}
TEST_F(ChangeNamespaceTest, UsingShadowDeclInClass) {
std::string Code = "namespace na { class C_A {};\n }\n"
std::string Code = "namespace na { class C_A {}; }\n"
"namespace na {\n"
"namespace nb {\n"
"void f() {\n"
" using na::CA;\n"
" CA ca;\n"
" using ::na::C_A;\n"
" C_A ca;\n"
"}\n"
"} // namespace nb\n"
"} // namespace na\n";
std::string Expected = "namespace na { class C_A {};\n }\n"
std::string Expected = "namespace na { class C_A {}; }\n"
"\n"
"namespace x {\n"
"namespace y {\n"
"void f() {\n"
" using na::CA;\n"
" CA ca;\n"
" using ::na::C_A;\n"
" C_A ca;\n"
"}\n"
"} // namespace y\n"
"} // namespace x\n";
@ -941,6 +941,70 @@ TEST_F(ChangeNamespaceTest, UsingDeclInTheParentOfOldNamespace) {
EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
}
TEST_F(ChangeNamespaceTest, UsingAliasDecl) {
std::string Code =
"namespace nx { namespace ny { class X {}; } }\n"
"namespace na {\n"
"namespace nb {\n"
"using Y = nx::ny::X;\n"
"void f() { Y y; }\n"
"} // namespace nb\n"
"} // namespace na\n";
std::string Expected = "namespace nx { namespace ny { class X {}; } }\n"
"\n"
"namespace x {\n"
"namespace y {\n"
"using Y = nx::ny::X;\n"
"void f() { Y y; }\n"
"} // namespace y\n"
"} // namespace x\n";
EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
}
TEST_F(ChangeNamespaceTest, UsingAliasDeclInGlobal) {
std::string Code =
"namespace nx { namespace ny { class X {}; } }\n"
"using Y = nx::ny::X;\n"
"namespace na {\n"
"namespace nb {\n"
"void f() { Y y; }\n"
"} // namespace nb\n"
"} // namespace na\n";
std::string Expected = "namespace nx { namespace ny { class X {}; } }\n"
"using Y = nx::ny::X;\n"
"\n"
"namespace x {\n"
"namespace y {\n"
"void f() { Y y; }\n"
"} // namespace y\n"
"} // namespace x\n";
EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
}
TEST_F(ChangeNamespaceTest, TypedefAliasDecl) {
std::string Code =
"namespace nx { namespace ny { class X {}; } }\n"
"namespace na {\n"
"namespace nb {\n"
"typedef nx::ny::X Y;\n"
"void f() { Y y; }\n"
"} // namespace nb\n"
"} // namespace na\n";
std::string Expected = "namespace nx { namespace ny { class X {}; } }\n"
"\n"
"namespace x {\n"
"namespace y {\n"
"typedef nx::ny::X Y;\n"
"void f() { Y y; }\n"
"} // namespace y\n"
"} // namespace x\n";
EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
}
} // anonymous namespace
} // namespace change_namespace
} // namespace clang