From 57443fce3f7fc4cdc0408add716145448b760e3b Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Mon, 9 May 2016 23:06:14 +0000 Subject: [PATCH] When forming a fully-qualified type name, put any qualifiers outside/before the nested-name-specifier. Patch by Sterling Augustine! llvm-svn: 268988 --- clang/lib/Tooling/Core/QualTypeNames.cpp | 20 +++++++++---------- clang/unittests/Tooling/QualTypeNamesTest.cpp | 5 +++++ 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/clang/lib/Tooling/Core/QualTypeNames.cpp b/clang/lib/Tooling/Core/QualTypeNames.cpp index cfb9e9a19d24..8fc1a654b977 100644 --- a/clang/lib/Tooling/Core/QualTypeNames.cpp +++ b/clang/lib/Tooling/Core/QualTypeNames.cpp @@ -383,10 +383,15 @@ QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx) { } NestedNameSpecifier *Prefix = nullptr; - Qualifiers PrefixQualifiers; + // Local qualifiers are attached to the QualType outside of the + // elaborated type. Retrieve them before descending into the + // elaborated type. + Qualifiers PrefixQualifiers = QT.getLocalQualifiers(); + QT = QualType(QT.getTypePtr(), 0); ElaboratedTypeKeyword Keyword = ETK_None; if (const auto *ETypeInput = dyn_cast(QT.getTypePtr())) { QT = ETypeInput->getNamedType(); + assert(!QT.hasLocalQualifiers()); Keyword = ETypeInput->getKeyword(); } // Create a nested name specifier if needed (i.e. if the decl context @@ -394,28 +399,21 @@ QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx) { Prefix = createNestedNameSpecifierForScopeOf(Ctx, QT.getTypePtr(), true /*FullyQualified*/); - // move the qualifiers on the outer type (avoid 'std::const string'!) - if (Prefix) { - PrefixQualifiers = QT.getLocalQualifiers(); - QT = QualType(QT.getTypePtr(), 0); - } - // In case of template specializations iterate over the arguments and // fully qualify them as well. if (isa(QT.getTypePtr()) || isa(QT.getTypePtr())) { // We are asked to fully qualify and we have a Record Type (which - // may pont to a template specialization) or Template + // may point to a template specialization) or Template // Specialization Type. We need to fully qualify their arguments. - Qualifiers Quals = QT.getLocalQualifiers(); const Type *TypePtr = getFullyQualifiedTemplateType(Ctx, QT.getTypePtr()); - QT = Ctx.getQualifiedType(TypePtr, Quals); + QT = QualType(TypePtr, 0); } if (Prefix || Keyword != ETK_None) { QT = Ctx.getElaboratedType(Keyword, Prefix, QT); - QT = Ctx.getQualifiedType(QT, PrefixQualifiers); } + QT = Ctx.getQualifiedType(QT, PrefixQualifiers); return QT; } diff --git a/clang/unittests/Tooling/QualTypeNamesTest.cpp b/clang/unittests/Tooling/QualTypeNamesTest.cpp index 2015c6863c4d..812be23b7a69 100644 --- a/clang/unittests/Tooling/QualTypeNamesTest.cpp +++ b/clang/unittests/Tooling/QualTypeNamesTest.cpp @@ -88,6 +88,8 @@ TEST(QualTypeNameTest, getFullyQualifiedName) { "Foo::non_dependent_type"; Visitor.ExpectedQualTypeNames["AnEnumVar"] = "EnumScopeClass::AnEnum"; Visitor.ExpectedQualTypeNames["AliasTypeVal"] = "A::B::C::InnerAlias"; + Visitor.ExpectedQualTypeNames["CheckM"] = "const A::B::Class0 *"; + Visitor.ExpectedQualTypeNames["CheckN"] = "const X *"; Visitor.runOver( "int CheckInt;\n" "template \n" @@ -108,6 +110,7 @@ TEST(QualTypeNameTest, getFullyQualifiedName) { " AnotherClass> CheckC);\n" " void Function2(Template0,\n" " Template0 > CheckD);\n" + " void Function3(const B::Class0* CheckM);\n" " }\n" "template class Variadic {};\n" "Variadic, " @@ -123,6 +126,8 @@ TEST(QualTypeNameTest, getFullyQualifiedName) { "void f() {\n" " struct X {} CheckH;\n" "}\n" + "struct X;\n" + "void f(const ::X* CheckN) {}\n" "namespace {\n" " class aClass {};\n" " aClass CheckI;\n"