r274185 - [Tooling] Add optional argument to getFullyQualifiedName to prepend "::".

Siva Chandra via cfe-commits cfe-commits at lists.llvm.org
Wed Jun 29 15:38:59 PDT 2016


Author: sivachandra
Date: Wed Jun 29 17:38:59 2016
New Revision: 274185

URL: http://llvm.org/viewvc/llvm-project?rev=274185&view=rev
Log:
[Tooling] Add optional argument to getFullyQualifiedName to prepend "::".

Reviewers: rsmith, saugustine, rnk

Subscribers: klimek, cfe-commits

Differential Revision: http://reviews.llvm.org/D21666

Modified:
    cfe/trunk/include/clang/Tooling/Core/QualTypeNames.h
    cfe/trunk/lib/Tooling/Core/QualTypeNames.cpp
    cfe/trunk/unittests/Tooling/QualTypeNamesTest.cpp

Modified: cfe/trunk/include/clang/Tooling/Core/QualTypeNames.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Tooling/Core/QualTypeNames.h?rev=274185&r1=274184&r2=274185&view=diff
==============================================================================
--- cfe/trunk/include/clang/Tooling/Core/QualTypeNames.h (original)
+++ cfe/trunk/include/clang/Tooling/Core/QualTypeNames.h Wed Jun 29 17:38:59 2016
@@ -69,8 +69,11 @@ namespace TypeName {
 /// \param[in] QT - the type for which the fully qualified name will be
 /// returned.
 /// \param[in] Ctx - the ASTContext to be used.
+/// \param[in] WithGlobalNsPrefix - If true, then the global namespace
+/// specifier "::" will be prepended to the fully qualified name.
 std::string getFullyQualifiedName(QualType QT,
-                                  const ASTContext &Ctx);
+                                  const ASTContext &Ctx,
+                                  bool WithGlobalNsPrefix = false);
 }  // end namespace TypeName
 }  // end namespace clang
 #endif  // LLVM_CLANG_TOOLING_CORE_QUALTYPENAMES_H

Modified: cfe/trunk/lib/Tooling/Core/QualTypeNames.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/Core/QualTypeNames.cpp?rev=274185&r1=274184&r2=274185&view=diff
==============================================================================
--- cfe/trunk/lib/Tooling/Core/QualTypeNames.cpp (original)
+++ cfe/trunk/lib/Tooling/Core/QualTypeNames.cpp Wed Jun 29 17:38:59 2016
@@ -30,7 +30,10 @@ namespace TypeName {
 /// \param[in] QT - the type for which the fully qualified type will be
 /// returned.
 /// \param[in] Ctx - the ASTContext to be used.
-static QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx);
+/// \param[in] WithGlobalNsPrefix - Indicate whether the global namespace
+/// specifier "::" should be prepended or not.
+static QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx,
+                                      bool WithGlobalNsPrefix);
 
 /// \brief Create a NestedNameSpecifier for Namesp and its enclosing
 /// scopes.
@@ -38,8 +41,12 @@ static QualType getFullyQualifiedType(Qu
 /// \param[in] Ctx - the AST Context to be used.
 /// \param[in] Namesp - the NamespaceDecl for which a NestedNameSpecifier
 /// is requested.
+/// \param[in] WithGlobalNsPrefix - Indicate whether the global namespace
+/// specifier "::" should be prepended or not.
 static NestedNameSpecifier *createNestedNameSpecifier(
-    const ASTContext &Ctx, const NamespaceDecl *Namesp);
+    const ASTContext &Ctx,
+    const NamespaceDecl *Namesp,
+    bool WithGlobalNsPrefix);
 
 /// \brief Create a NestedNameSpecifier for TagDecl and its enclosing
 /// scopes.
@@ -49,17 +56,22 @@ static NestedNameSpecifier *createNested
 /// requested.
 /// \param[in] FullyQualify - Convert all template arguments into fully
 /// qualified names.
+/// \param[in] WithGlobalNsPrefix - Indicate whether the global namespace
+/// specifier "::" should be prepended or not.
 static NestedNameSpecifier *createNestedNameSpecifier(
-    const ASTContext &Ctx, const TypeDecl *TD, bool FullyQualify);
+    const ASTContext &Ctx, const TypeDecl *TD,
+    bool FullyQualify, bool WithGlobalNsPrefix);
 
 static NestedNameSpecifier *createNestedNameSpecifierForScopeOf(
-    const ASTContext &Ctx, const Decl *decl, bool FullyQualified);
+    const ASTContext &Ctx, const Decl *decl,
+    bool FullyQualified, bool WithGlobalNsPrefix);
 
 static NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier(
-    const ASTContext &Ctx, NestedNameSpecifier *scope);
+    const ASTContext &Ctx, NestedNameSpecifier *scope, bool WithGlobalNsPrefix);
 
 static bool getFullyQualifiedTemplateName(const ASTContext &Ctx,
-                                          TemplateName &TName) {
+                                          TemplateName &TName,
+                                          bool WithGlobalNsPrefix) {
   bool Changed = false;
   NestedNameSpecifier *NNS = nullptr;
 
@@ -71,7 +83,8 @@ static bool getFullyQualifiedTemplateNam
 
   if (QTName && !QTName->hasTemplateKeyword()) {
     NNS = QTName->getQualifier();
-    NestedNameSpecifier *QNNS = getFullyQualifiedNestedNameSpecifier(Ctx, NNS);
+    NestedNameSpecifier *QNNS = getFullyQualifiedNestedNameSpecifier(
+        Ctx, NNS, WithGlobalNsPrefix);
     if (QNNS != NNS) {
       Changed = true;
       NNS = QNNS;
@@ -79,7 +92,8 @@ static bool getFullyQualifiedTemplateNam
       NNS = nullptr;
     }
   } else {
-    NNS = createNestedNameSpecifierForScopeOf(Ctx, ArgTDecl, true);
+    NNS = createNestedNameSpecifierForScopeOf(
+        Ctx, ArgTDecl, true, WithGlobalNsPrefix);
   }
   if (NNS) {
     TName = Ctx.getQualifiedTemplateName(NNS,
@@ -90,7 +104,8 @@ static bool getFullyQualifiedTemplateNam
 }
 
 static bool getFullyQualifiedTemplateArgument(const ASTContext &Ctx,
-                                              TemplateArgument &Arg) {
+                                              TemplateArgument &Arg,
+                                              bool WithGlobalNsPrefix) {
   bool Changed = false;
 
   // Note: we do not handle TemplateArgument::Expression, to replace it
@@ -98,14 +113,14 @@ static bool getFullyQualifiedTemplateArg
 
   if (Arg.getKind() == TemplateArgument::Template) {
     TemplateName TName = Arg.getAsTemplate();
-    Changed = getFullyQualifiedTemplateName(Ctx, TName);
+    Changed = getFullyQualifiedTemplateName(Ctx, TName, WithGlobalNsPrefix);
     if (Changed) {
       Arg = TemplateArgument(TName);
     }
   } else if (Arg.getKind() == TemplateArgument::Type) {
     QualType SubTy = Arg.getAsType();
     // Check if the type needs more desugaring and recurse.
-    QualType QTFQ = getFullyQualifiedType(SubTy, Ctx);
+    QualType QTFQ = getFullyQualifiedType(SubTy, Ctx, WithGlobalNsPrefix);
     if (QTFQ != SubTy) {
       Arg = TemplateArgument(QTFQ);
       Changed = true;
@@ -115,7 +130,8 @@ static bool getFullyQualifiedTemplateArg
 }
 
 static const Type *getFullyQualifiedTemplateType(const ASTContext &Ctx,
-                                                 const Type *TypePtr) {
+                                                 const Type *TypePtr,
+                                                 bool WithGlobalNsPrefix) {
   // DependentTemplateTypes exist within template declarations and
   // definitions. Therefore we shouldn't encounter them at the end of
   // a translation unit. If we do, the caller has made an error.
@@ -130,7 +146,8 @@ static const Type *getFullyQualifiedTemp
       // Cheap to copy and potentially modified by
       // getFullyQualifedTemplateArgument.
       TemplateArgument Arg(*I);
-      MightHaveChanged |= getFullyQualifiedTemplateArgument(Ctx, Arg);
+      MightHaveChanged |= getFullyQualifiedTemplateArgument(
+          Ctx, Arg, WithGlobalNsPrefix);
       FQArgs.push_back(Arg);
     }
 
@@ -160,7 +177,8 @@ static const Type *getFullyQualifiedTemp
         // cheap to copy and potentially modified by
         // getFullyQualifedTemplateArgument
         TemplateArgument Arg(TemplateArgs[I]);
-        MightHaveChanged |= getFullyQualifiedTemplateArgument(Ctx, Arg);
+        MightHaveChanged |= getFullyQualifiedTemplateArgument(
+            Ctx, Arg, WithGlobalNsPrefix);
         FQArgs.push_back(Arg);
       }
 
@@ -182,44 +200,55 @@ static const Type *getFullyQualifiedTemp
 }
 
 static NestedNameSpecifier *createOuterNNS(const ASTContext &Ctx, const Decl *D,
-                                           bool FullyQualify) {
+                                           bool FullyQualify,
+                                           bool WithGlobalNsPrefix) {
   const DeclContext *DC = D->getDeclContext();
   if (const auto *NS = dyn_cast<NamespaceDecl>(DC)) {
     while (NS && NS->isInline()) {
       // Ignore inline namespace;
       NS = dyn_cast<NamespaceDecl>(NS->getDeclContext());
     }
-    if (NS->getDeclName()) return createNestedNameSpecifier(Ctx, NS);
+    if (NS->getDeclName()) {
+      return createNestedNameSpecifier(Ctx, NS, WithGlobalNsPrefix);
+    }
     return nullptr;  // no starting '::', no anonymous
   } else if (const auto *TD = dyn_cast<TagDecl>(DC)) {
-    return createNestedNameSpecifier(Ctx, TD, FullyQualify);
+    return createNestedNameSpecifier(Ctx, TD, FullyQualify, WithGlobalNsPrefix);
   } else if (const auto *TDD = dyn_cast<TypedefNameDecl>(DC)) {
-    return createNestedNameSpecifier(Ctx, TDD, FullyQualify);
+    return createNestedNameSpecifier(
+        Ctx, TDD, FullyQualify, WithGlobalNsPrefix);
+  } else if (WithGlobalNsPrefix && DC->isTranslationUnit()) {
+    return NestedNameSpecifier::GlobalSpecifier(Ctx);
   }
-  return nullptr;  // no starting '::'
+  return nullptr;  // no starting '::' if |WithGlobalNsPrefix| is false
 }
 
 /// \brief Return a fully qualified version of this name specifier.
 static NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier(
-    const ASTContext &Ctx, NestedNameSpecifier *Scope) {
+    const ASTContext &Ctx, NestedNameSpecifier *Scope,
+    bool WithGlobalNsPrefix) {
   switch (Scope->getKind()) {
     case NestedNameSpecifier::Global:
       // Already fully qualified
       return Scope;
     case NestedNameSpecifier::Namespace:
-      return TypeName::createNestedNameSpecifier(Ctx, Scope->getAsNamespace());
+      return TypeName::createNestedNameSpecifier(
+          Ctx, Scope->getAsNamespace(), WithGlobalNsPrefix);
     case NestedNameSpecifier::NamespaceAlias:
       // Namespace aliases are only valid for the duration of the
       // scope where they were introduced, and therefore are often
       // invalid at the end of the TU.  So use the namespace name more
       // likely to be valid at the end of the TU.
       return TypeName::createNestedNameSpecifier(
-          Ctx, Scope->getAsNamespaceAlias()->getNamespace()->getCanonicalDecl());
+          Ctx,
+          Scope->getAsNamespaceAlias()->getNamespace()->getCanonicalDecl(),
+          WithGlobalNsPrefix);
     case NestedNameSpecifier::Identifier:
       // A function or some other construct that makes it un-namable
       // at the end of the TU. Skip the current component of the name,
       // but use the name of it's prefix.
-      return getFullyQualifiedNestedNameSpecifier(Ctx, Scope->getPrefix());
+      return getFullyQualifiedNestedNameSpecifier(
+          Ctx, Scope->getPrefix(), WithGlobalNsPrefix);
     case NestedNameSpecifier::Super:
     case NestedNameSpecifier::TypeSpec:
     case NestedNameSpecifier::TypeSpecWithTemplate: {
@@ -233,10 +262,12 @@ static NestedNameSpecifier *getFullyQual
       }
       if (TD) {
         return TypeName::createNestedNameSpecifier(Ctx, TD,
-                                                   true /*FullyQualified*/);
+                                                   true /*FullyQualified*/,
+                                                   WithGlobalNsPrefix);
       } else if (const auto *TDD = dyn_cast<TypedefType>(Type)) {
         return TypeName::createNestedNameSpecifier(Ctx, TDD->getDecl(),
-                                                   true /*FullyQualified*/);
+                                                   true /*FullyQualified*/,
+                                                   WithGlobalNsPrefix);
       }
       return Scope;
     }
@@ -247,7 +278,8 @@ static NestedNameSpecifier *getFullyQual
 /// \brief Create a nested name specifier for the declaring context of
 /// the type.
 static NestedNameSpecifier *createNestedNameSpecifierForScopeOf(
-    const ASTContext &Ctx, const Decl *Decl, bool FullyQualified) {
+    const ASTContext &Ctx, const Decl *Decl,
+    bool FullyQualified, bool WithGlobalNsPrefix) {
   assert(Decl);
 
   const DeclContext *DC = Decl->getDeclContext()->getRedeclContext();
@@ -276,9 +308,10 @@ static NestedNameSpecifier *createNested
     }
 
     if (OuterNS) {
-      return createNestedNameSpecifier(Ctx, OuterNS);
+      return createNestedNameSpecifier(Ctx, OuterNS, WithGlobalNsPrefix);
     } else if (const auto *TD = dyn_cast<TagDecl>(Outer)) {
-      return createNestedNameSpecifier(Ctx, TD, FullyQualified);
+      return createNestedNameSpecifier(
+          Ctx, TD, FullyQualified, WithGlobalNsPrefix);
     } else if (dyn_cast<TranslationUnitDecl>(Outer)) {
       // Context is the TU. Nothing needs to be done.
       return nullptr;
@@ -288,6 +321,8 @@ static NestedNameSpecifier *createNested
       // accessible at the end of the TU.
       return nullptr;
     }
+  } else if (WithGlobalNsPrefix && DC->isTranslationUnit()) {
+    return NestedNameSpecifier::GlobalSpecifier(Ctx);
   }
   return nullptr;
 }
@@ -295,7 +330,8 @@ static NestedNameSpecifier *createNested
 /// \brief Create a nested name specifier for the declaring context of
 /// the type.
 static NestedNameSpecifier *createNestedNameSpecifierForScopeOf(
-    const ASTContext &Ctx, const Type *TypePtr, bool FullyQualified) {
+    const ASTContext &Ctx, const Type *TypePtr,
+    bool FullyQualified, bool WithGlobalNsPrefix) {
   if (!TypePtr) return nullptr;
 
   Decl *Decl = nullptr;
@@ -312,11 +348,13 @@ static NestedNameSpecifier *createNested
 
   if (!Decl) return nullptr;
 
-  return createNestedNameSpecifierForScopeOf(Ctx, Decl, FullyQualified);
+  return createNestedNameSpecifierForScopeOf(
+      Ctx, Decl, FullyQualified, WithGlobalNsPrefix);
 }
 
-NestedNameSpecifier *createNestedNameSpecifier(
-    const ASTContext &Ctx, const NamespaceDecl *Namespace) {
+NestedNameSpecifier *createNestedNameSpecifier(const ASTContext &Ctx,
+                                               const NamespaceDecl *Namespace,
+                                               bool WithGlobalNsPrefix) {
   while (Namespace && Namespace->isInline()) {
     // Ignore inline namespace;
     Namespace = dyn_cast<NamespaceDecl>(Namespace->getDeclContext());
@@ -325,25 +363,32 @@ NestedNameSpecifier *createNestedNameSpe
 
   bool FullyQualified = true;  // doesn't matter, DeclContexts are namespaces
   return NestedNameSpecifier::Create(
-      Ctx, createOuterNNS(Ctx, Namespace, FullyQualified), Namespace);
+      Ctx,
+      createOuterNNS(Ctx, Namespace, FullyQualified, WithGlobalNsPrefix),
+      Namespace);
 }
 
-NestedNameSpecifier *createNestedNameSpecifier(
-    const ASTContext &Ctx, const TypeDecl *TD, bool FullyQualify) {
-  return NestedNameSpecifier::Create(Ctx, createOuterNNS(Ctx, TD, FullyQualify),
-                                     false /*No TemplateKeyword*/,
-                                     TD->getTypeForDecl());
+NestedNameSpecifier *createNestedNameSpecifier(const ASTContext &Ctx,
+                                               const TypeDecl *TD,
+                                               bool FullyQualify,
+                                               bool WithGlobalNsPrefix) {
+  return NestedNameSpecifier::Create(
+      Ctx,
+      createOuterNNS(Ctx, TD, FullyQualify, WithGlobalNsPrefix),
+      false /*No TemplateKeyword*/,
+      TD->getTypeForDecl());
 }
 
 /// \brief Return the fully qualified type, including fully-qualified
 /// versions of any template parameters.
-QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx) {
+QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx,
+                               bool WithGlobalNsPrefix) {
   // In case of myType* we need to strip the pointer first, fully
   // qualify and attach the pointer once again.
   if (isa<PointerType>(QT.getTypePtr())) {
     // Get the qualifiers.
     Qualifiers Quals = QT.getQualifiers();
-    QT = getFullyQualifiedType(QT->getPointeeType(), Ctx);
+    QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix);
     QT = Ctx.getPointerType(QT);
     // Add back the qualifiers.
     QT = Ctx.getQualifiedType(QT, Quals);
@@ -356,7 +401,7 @@ QualType getFullyQualifiedType(QualType
     // Get the qualifiers.
     bool IsLValueRefTy = isa<LValueReferenceType>(QT.getTypePtr());
     Qualifiers Quals = QT.getQualifiers();
-    QT = getFullyQualifiedType(QT->getPointeeType(), Ctx);
+    QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix);
     // Add the r- or l-value reference type back to the fully
     // qualified one.
     if (IsLValueRefTy)
@@ -394,10 +439,10 @@ QualType getFullyQualifiedType(QualType
     assert(!QT.hasLocalQualifiers());
     Keyword = ETypeInput->getKeyword();
   }
-  // Create a nested name specifier if needed (i.e. if the decl context
-  // is not the global scope.
+  // Create a nested name specifier if needed.
   Prefix = createNestedNameSpecifierForScopeOf(Ctx, QT.getTypePtr(),
-                                               true /*FullyQualified*/);
+                                               true /*FullyQualified*/,
+                                               WithGlobalNsPrefix);
 
   // In case of template specializations iterate over the arguments and
   // fully qualify them as well.
@@ -407,7 +452,8 @@ QualType getFullyQualifiedType(QualType
     // may point to a template specialization) or Template
     // Specialization Type. We need to fully qualify their arguments.
 
-    const Type *TypePtr = getFullyQualifiedTemplateType(Ctx, QT.getTypePtr());
+    const Type *TypePtr = getFullyQualifiedTemplateType(
+        Ctx, QT.getTypePtr(), WithGlobalNsPrefix);
     QT = QualType(TypePtr, 0);
   }
   if (Prefix || Keyword != ETK_None) {
@@ -418,13 +464,14 @@ QualType getFullyQualifiedType(QualType
 }
 
 std::string getFullyQualifiedName(QualType QT,
-                                  const ASTContext &Ctx) {
+                                  const ASTContext &Ctx,
+                                  bool WithGlobalNsPrefix) {
   PrintingPolicy Policy(Ctx.getPrintingPolicy());
   Policy.SuppressScope = false;
   Policy.AnonymousTagLocations = false;
   Policy.PolishForDeclaration = true;
   Policy.SuppressUnwrittenScope = true;
-  QualType FQQT = getFullyQualifiedType(QT, Ctx);
+  QualType FQQT = getFullyQualifiedType(QT, Ctx, WithGlobalNsPrefix);
   return FQQT.getAsString(Policy);
 }
 

Modified: cfe/trunk/unittests/Tooling/QualTypeNamesTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Tooling/QualTypeNamesTest.cpp?rev=274185&r1=274184&r2=274185&view=diff
==============================================================================
--- cfe/trunk/unittests/Tooling/QualTypeNamesTest.cpp (original)
+++ cfe/trunk/unittests/Tooling/QualTypeNamesTest.cpp Wed Jun 29 17:38:59 2016
@@ -14,6 +14,7 @@ using namespace clang;
 namespace {
 struct TypeNameVisitor : TestVisitor<TypeNameVisitor> {
   llvm::StringMap<std::string> ExpectedQualTypeNames;
+  bool WithGlobalNsPrefix = false;
 
   // ValueDecls are the least-derived decl with both a qualtype and a
   // name.
@@ -26,7 +27,8 @@ struct TypeNameVisitor : TestVisitor<Typ
         ExpectedQualTypeNames.lookup(VD->getNameAsString());
     if (ExpectedName != "") {
       std::string ActualName =
-          TypeName::getFullyQualifiedName(VD->getType(), *Context);
+          TypeName::getFullyQualifiedName(VD->getType(), *Context,
+                                          WithGlobalNsPrefix);
       if (ExpectedName != ActualName) {
         // A custom message makes it much easier to see what declaration
         // failed compared to EXPECT_EQ.
@@ -179,6 +181,42 @@ TEST(QualTypeNameTest, getFullyQualified
       "  TX CheckTX;"
       "  struct A { typedef int X; };"
       "}");
+
+  TypeNameVisitor GlobalNsPrefix;
+  GlobalNsPrefix.WithGlobalNsPrefix = true;
+  GlobalNsPrefix.ExpectedQualTypeNames["IntVal"] = "int";
+  GlobalNsPrefix.ExpectedQualTypeNames["BoolVal"] = "bool";
+  GlobalNsPrefix.ExpectedQualTypeNames["XVal"] = "::A::B::X";
+  GlobalNsPrefix.ExpectedQualTypeNames["IntAliasVal"] = "::A::B::Alias<int>";
+  GlobalNsPrefix.ExpectedQualTypeNames["ZVal"] = "::A::B::Y::Z";
+  GlobalNsPrefix.ExpectedQualTypeNames["GlobalZVal"] = "::Z";
+  GlobalNsPrefix.ExpectedQualTypeNames["CheckK"] = "D::aStruct";
+  GlobalNsPrefix.runOver(
+      "namespace A {\n"
+      "  namespace B {\n"
+      "    int IntVal;\n"
+      "    bool BoolVal;\n"
+      "    struct X {};\n"
+      "    X XVal;\n"
+      "    template <typename T> class CCC { };\n"
+      "    template <typename T>\n"
+      "    using Alias = CCC<T>;\n"
+      "    Alias<int> IntAliasVal;\n"
+      "    struct Y { struct Z {}; };\n"
+      "    Y::Z ZVal;\n"
+      "  }\n"
+      "}\n"
+      "struct Z {};\n"
+      "Z GlobalZVal;\n"
+      "namespace {\n"
+      "  namespace D {\n"
+      "    namespace {\n"
+      "      class aStruct {};\n"
+      "      aStruct CheckK;\n"
+      "    }\n"
+      "  }\n"
+      "}\n"
+  );
 }
 
 }  // end anonymous namespace




More information about the cfe-commits mailing list