sivachandra updated this revision to Diff 61821.
sivachandra added a comment.

A little adjustment.


http://reviews.llvm.org/D21666

Files:
  include/clang/AST/NestedNameSpecifier.h
  include/clang/Tooling/Core/QualTypeNames.h
  lib/AST/NestedNameSpecifier.cpp
  lib/Tooling/Core/QualTypeNames.cpp
  unittests/Tooling/QualTypeNamesTest.cpp

Index: unittests/Tooling/QualTypeNamesTest.cpp
===================================================================
--- unittests/Tooling/QualTypeNamesTest.cpp
+++ unittests/Tooling/QualTypeNamesTest.cpp
@@ -14,6 +14,7 @@
 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 @@
         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,30 @@
       "  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.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"
+      "  }"
+      "}"
+  );
 }
 
 }  // end anonymous namespace
Index: lib/Tooling/Core/QualTypeNames.cpp
===================================================================
--- lib/Tooling/Core/QualTypeNames.cpp
+++ lib/Tooling/Core/QualTypeNames.cpp
@@ -30,7 +30,8 @@
 /// \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);
+static QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx,
+                                      bool WithGlobalNsPrefix);
 
 /// \brief Create a NestedNameSpecifier for Namesp and its enclosing
 /// scopes.
@@ -90,7 +91,8 @@
 }
 
 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
@@ -105,7 +107,7 @@
   } 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 +117,8 @@
 }
 
 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 +133,8 @@
       // 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 +164,8 @@
         // 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);
       }
 
@@ -337,13 +342,14 @@
 
 /// \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 +362,7 @@
     // 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)
@@ -398,6 +404,13 @@
   // is not the global scope.
   Prefix = createNestedNameSpecifierForScopeOf(Ctx, QT.getTypePtr(),
                                                true /*FullyQualified*/);
+  if (WithGlobalNsPrefix && !QT->isBuiltinType()) {
+    if (Prefix == nullptr) {
+      Prefix = NestedNameSpecifier::GlobalSpecifier(Ctx);
+    } else {
+      Prefix = NestedNameSpecifier::PrependGlobalSpecifier(Ctx, Prefix);
+    }
+  }
 
   // In case of template specializations iterate over the arguments and
   // fully qualify them as well.
@@ -407,7 +420,8 @@
     // 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 +432,14 @@
 }
 
 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);
 }
 
Index: lib/AST/NestedNameSpecifier.cpp
===================================================================
--- lib/AST/NestedNameSpecifier.cpp
+++ lib/AST/NestedNameSpecifier.cpp
@@ -43,6 +43,46 @@
 }
 
 NestedNameSpecifier *
+NestedNameSpecifier::PrependGlobalSpecifier(
+    const ASTContext &Context, const NestedNameSpecifier *Specifier) {
+  assert(Specifier && "Input nested name specifier cannot be NULL");
+
+  NestedNameSpecifier Mockup(*Specifier);
+  NestedNameSpecifier *P = &Mockup;
+  while (P->getPrefix() != nullptr) {
+    P = P->getPrefix();
+  }
+
+  SpecifierKind Kind = P->getKind();
+  if (Kind == Global) {
+    return const_cast<NestedNameSpecifier *>(Specifier);
+  }
+
+  P->Prefix.setPointer(GlobalSpecifier(Context));
+  switch (Kind) {
+    case Namespace:
+    case NamespaceAlias:
+      P->Prefix.setInt(StoredDecl);
+      break;
+    case Identifier:
+      P->Prefix.setInt(StoredIdentifier);
+      break;
+    case TypeSpec:
+    case Super:
+      P->Prefix.setInt(StoredTypeSpec);
+      break;
+    case TypeSpecWithTemplate:
+      P->Prefix.setInt(StoredTypeSpecWithTemplate);
+      break;
+    default:
+      // Global is handled as a special case above.
+      assert(false && "Invalid NNS Kind!");
+   }
+
+  return FindOrInsert(Context, Mockup);
+}
+
+NestedNameSpecifier *
 NestedNameSpecifier::Create(const ASTContext &Context,
                             NestedNameSpecifier *Prefix, IdentifierInfo *II) {
   assert(II && "Identifier cannot be NULL");
Index: include/clang/Tooling/Core/QualTypeNames.h
===================================================================
--- include/clang/Tooling/Core/QualTypeNames.h
+++ include/clang/Tooling/Core/QualTypeNames.h
@@ -69,8 +69,11 @@
 /// \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
Index: include/clang/AST/NestedNameSpecifier.h
===================================================================
--- include/clang/AST/NestedNameSpecifier.h
+++ include/clang/AST/NestedNameSpecifier.h
@@ -143,6 +143,13 @@
   static NestedNameSpecifier *Create(const ASTContext &Context,
                                      IdentifierInfo *II);
 
+  /// \brief Builds a specifier with the global specifier ("::") prepended.
+  /// If the input specifier already has the global specifier, then the input
+  /// specifier itself is returned.
+  static NestedNameSpecifier *PrependGlobalSpecifier(
+      const ASTContext &Context, const NestedNameSpecifier *Specifier);
+  
+
   /// \brief Returns the nested name specifier representing the global
   /// scope.
   static NestedNameSpecifier *GlobalSpecifier(const ASTContext &Context);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to