[clang-tools-extra] r289799 - [change-namespace] handling templated type aliases correctly.
Eric Liu via cfe-commits
cfe-commits at lists.llvm.org
Thu Dec 15 02:42:35 PST 2016
Author: ioeric
Date: Thu Dec 15 04:42:35 2016
New Revision: 289799
URL: http://llvm.org/viewvc/llvm-project?rev=289799&view=rev
Log:
[change-namespace] handling templated type aliases correctly.
Summary: This fixes templated type aliases and templated type aliases in classes.
Reviewers: hokein
Subscribers: cfe-commits
Differential Revision: https://reviews.llvm.org/D27801
Modified:
clang-tools-extra/trunk/change-namespace/ChangeNamespace.cpp
clang-tools-extra/trunk/unittests/change-namespace/ChangeNamespaceTests.cpp
Modified: clang-tools-extra/trunk/change-namespace/ChangeNamespace.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/change-namespace/ChangeNamespace.cpp?rev=289799&r1=289798&r2=289799&view=diff
==============================================================================
--- clang-tools-extra/trunk/change-namespace/ChangeNamespace.cpp (original)
+++ clang-tools-extra/trunk/change-namespace/ChangeNamespace.cpp Thu Dec 15 04:42:35 2016
@@ -454,6 +454,17 @@ void ChangeNamespaceTool::run(
BaseCtorInitializerTypeLocs.push_back(
BaseInitializer->getTypeSourceInfo()->getTypeLoc());
} else if (const auto *TLoc = Result.Nodes.getNodeAs<TypeLoc>("type")) {
+ // This avoids fixing types with record types as qualifier, which is not
+ // filtered by matchers in some cases, e.g. the type is templated. We should
+ // handle the record type qualifier instead.
+ if (TLoc->getTypeLocClass() == TypeLoc::Elaborated) {
+ NestedNameSpecifierLoc NestedNameSpecifier =
+ TLoc->castAs<ElaboratedTypeLoc>().getQualifierLoc();
+ const Type *SpecifierType =
+ NestedNameSpecifier.getNestedNameSpecifier()->getAsType();
+ if (SpecifierType && SpecifierType->isRecordType())
+ return;
+ }
fixTypeLoc(Result, startLocationForType(*TLoc), endLocationForType(*TLoc),
*TLoc);
} else if (const auto *VarRef =
@@ -705,27 +716,32 @@ 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.
+ 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);
+ return FilePatternRE.match(Filename);
+ };
+ // Make `FromDecl` the immediate declaration that `Type` refers to, i.e. if
+ // `Type` is an alias type, we make `FromDecl` the type alias declaration.
+ // Also, 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 (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);
- return FilePatternRE.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;
+ } else if (auto *TemplateType =
+ Type.getType()->getAs<TemplateSpecializationType>()) {
+ if (TemplateType->isTypeAlias()) {
+ FromDecl = TemplateType->getTemplateName().getAsTemplateDecl();
+ if (IsInMovedNs(FromDecl))
+ return;
+ }
}
-
const auto *DeclCtx = Result.Nodes.getNodeAs<Decl>("dc");
assert(DeclCtx && "Empty decl context.");
replaceQualifiedSymbolInDeclContext(Result, DeclCtx->getDeclContext(), Start,
Modified: clang-tools-extra/trunk/unittests/change-namespace/ChangeNamespaceTests.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/change-namespace/ChangeNamespaceTests.cpp?rev=289799&r1=289798&r2=289799&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/change-namespace/ChangeNamespaceTests.cpp (original)
+++ clang-tools-extra/trunk/unittests/change-namespace/ChangeNamespaceTests.cpp Thu Dec 15 04:42:35 2016
@@ -1317,6 +1317,88 @@ TEST_F(ChangeNamespaceTest, KeepGlobalSp
EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
}
+TEST_F(ChangeNamespaceTest, UsingAliasInTemplate) {
+ NewNamespace = "na::nb::nc";
+ std::string Code = "namespace some_ns {\n"
+ "template <typename T, typename S>\n"
+ "class G {};\n"
+ "} // namespace some_ns\n"
+ "namespace na {\n"
+ "template<typename P>\n"
+ "using GG = some_ns::G<int, P>;\n"
+ "} // namespace na\n"
+ "namespace na {\n"
+ "namespace nb {\n"
+ "void f() {\n"
+ " GG<float> g;\n"
+ "}\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected = "namespace some_ns {\n"
+ "template <typename T, typename S>\n"
+ "class G {};\n"
+ "} // namespace some_ns\n"
+ "namespace na {\n"
+ "template<typename P>\n"
+ "using GG = some_ns::G<int, P>;\n"
+ "} // namespace na\n"
+ "namespace na {\n"
+ "namespace nb {\n"
+ "namespace nc {\n"
+ "void f() {\n"
+ " GG<float> g;\n"
+ "}\n"
+ "} // namespace nc\n\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, TemplateUsingAliasInBaseClass) {
+ NewNamespace = "na::nb::nc";
+ std::string Code = "namespace some_ns {\n"
+ "template <typename T, typename S>\n"
+ "class G {};\n"
+ "} // namespace some_ns\n"
+ "namespace na {\n"
+ "class Base {\n"
+ "public:\n"
+ " template<typename P>\n"
+ " using GG = some_ns::G<int, P>;\n"
+ "};\n"
+ "class Derived : public Base {};\n"
+ "} // namespace na\n"
+ "namespace na {\n"
+ "namespace nb {\n"
+ "void f() {\n"
+ " Derived::GG<float> g;\n"
+ "}\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ std::string Expected = "namespace some_ns {\n"
+ "template <typename T, typename S>\n"
+ "class G {};\n"
+ "} // namespace some_ns\n"
+ "namespace na {\n"
+ "class Base {\n"
+ "public:\n"
+ " template<typename P>\n"
+ " using GG = some_ns::G<int, P>;\n"
+ "};\n"
+ "class Derived : public Base {};\n"
+ "} // namespace na\n"
+ "namespace na {\n"
+ "namespace nb {\n"
+ "namespace nc {\n"
+ "void f() {\n"
+ " Derived::GG<float> g;\n"
+ "}\n"
+ "} // namespace nc\n\n"
+ "} // namespace nb\n"
+ "} // namespace na\n";
+ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
} // anonymous namespace
} // namespace change_namespace
} // namespace clang
More information about the cfe-commits
mailing list