From 4b4b54b247f45639bdab4f571dfc93f929ffc2dd Mon Sep 17 00:00:00 2001
From: Axel Naumann <Axel.Naumann@cern.ch>
Date: Wed, 4 Dec 2013 16:39:43 +0100
Subject: [PATCH] Move several TypeName functions from MetaUtils to
 cling/Utils.

They were once identical but then got bug fixed out of sync.
Moved routines:

GetFullyQualifiedLocalType()
GetFullyQualifiedType()
CreateNestedNameSpecifier()
CreateNestedNameSpecifierForScopeOf()
GetFullyQualifiedTypeNNS()
---
 core/metautils/inc/TMetaUtils.h             |  10 -
 core/metautils/src/TMetaUtils.cxx           | 352 +------------------
 interpreter/cling/include/cling/Utils/AST.h |  41 +++
 interpreter/cling/lib/Utils/AST.cpp         | 362 +++++++++++++++++---
 4 files changed, 354 insertions(+), 411 deletions(-)

diff --git a/core/metautils/inc/TMetaUtils.h b/core/metautils/inc/TMetaUtils.h
index a9689ba6a1a..740a6497af8 100644
--- a/core/metautils/inc/TMetaUtils.h
+++ b/core/metautils/inc/TMetaUtils.h
@@ -454,16 +454,6 @@ std::string GetROOTIncludeDir(bool rootbuild);
 // that can be used in C++ as a variable name.
 void GetCppName(std::string &output, const char *input);
 
-//______________________________________________________________________________
-// Return the type with all parts fully qualified (most typedefs),
-// including template arguments.
-clang::QualType GetFullyQualifiedType(const clang::QualType &type, const cling::Interpreter &interpreter);
-
-//______________________________________________________________________________
-// Return the type with all parts fully qualified (most typedefs),
-// including template arguments, without the interpreter
-clang::QualType GetFullyQualifiedType(const clang::QualType &type, const clang::ASTContext &);
-
 //______________________________________________________________________________
 // Return the type with all parts fully qualified (most typedefs),
 // including template arguments, appended to name.
diff --git a/core/metautils/src/TMetaUtils.cxx b/core/metautils/src/TMetaUtils.cxx
index f5d623a1c3a..0093210d12e 100644
--- a/core/metautils/src/TMetaUtils.cxx
+++ b/core/metautils/src/TMetaUtils.cxx
@@ -158,329 +158,6 @@ static clang::NestedNameSpecifier* ReSubstTemplateArgNNS(const clang::ASTContext
 }
 
 // See also cling's AST.cpp
-//______________________________________________________________________________
-static const clang::Type *GetFullyQualifiedLocalType(const clang::ASTContext& Ctx,
-                                                     const clang::Type *typeptr);
-
-//______________________________________________________________________________
-static clang::QualType GetFullyQualifiedType(const clang::ASTContext& Ctx,
-                                             const clang::QualType &qtype);
-
-//______________________________________________________________________________
-static clang::NestedNameSpecifier* CreateNestedNameSpecifier(const clang::ASTContext& Ctx,
-                                                             clang::NamespaceDecl* cl)
-{
-   // Create a nested namespecifier for the given namespace and all
-   // its enclosing namespaces.
-
-   clang::NamespaceDecl* outer =
-   llvm::dyn_cast_or_null<clang::NamespaceDecl>(cl->getDeclContext());
-   if (outer && outer->getName().size()) {
-      clang::NestedNameSpecifier* outerNNS = CreateNestedNameSpecifier(Ctx,outer);
-      return clang::NestedNameSpecifier::Create(Ctx,outerNNS,
-                                                cl);
-   } else {
-      return clang::NestedNameSpecifier::Create(Ctx,
-                                                0, /* no starting '::'*/
-                                                cl);
-   }
-}
-
-// See also cling's AST.cpp
-//______________________________________________________________________________
-static clang::NestedNameSpecifier* CreateNestedNameSpecifier(const clang::ASTContext& Ctx,
-                                                             clang::TagDecl *cl)
-{
-   // Create a nested namespecifier for the given class/union or enum and all
-   // its declaring contexts.
-
-   clang::NamedDecl* outer = llvm::dyn_cast_or_null<clang::NamedDecl>(cl->getDeclContext());
-
-   clang::NestedNameSpecifier *outerNNS;
-   if (cl->getDeclContext()->isNamespace()) {
-      if (outer && outer->getName().size()) {
-         outerNNS = CreateNestedNameSpecifier(Ctx,
-                                              llvm::dyn_cast<clang::NamespaceDecl>(outer));
-      } else {
-         outerNNS = 0; // Make sure the name does not start with '::'.
-      }
-   } else if (cl->getDeclContext()->isRecord() ||
-      llvm::isa<clang::EnumDecl>(cl->getDeclContext())) {
-      if (outer && outer->getName().size()) {
-         outerNNS = CreateNestedNameSpecifier(Ctx,
-                                              llvm::dyn_cast<clang::TagDecl>(outer));
-      } else {
-         outerNNS = 0; // record without a name ....
-      }
-      } else {
-         // Function or the like ... no real name to be use in the prefix ...
-         outerNNS = 0;
-      }
-      return clang::NestedNameSpecifier::Create(Ctx,outerNNS,
-                                                false /* template keyword wanted */,
-                                                GetFullyQualifiedLocalType(Ctx, Ctx.getTypeDeclType(cl).getTypePtr()));
-}
-
-//______________________________________________________________________________
-static clang::NestedNameSpecifier *CreateNestedNameSpecifierForScopeOf(const clang::ASTContext& Ctx,
-                                                                       const clang::Type *typeptr)
-{
-   // Create a nested name specifier for the declaring context of the type.
-
-   clang::Decl *decl = 0;
-   const clang::TypedefType* typedeftype = llvm::dyn_cast_or_null<clang::TypedefType>(typeptr);
-   if (typedeftype) {
-      decl = typedeftype->getDecl();
-   } else {
-      // There are probably other cases ...
-      const clang::TagType* tagdecltype = llvm::dyn_cast_or_null<clang::TagType>(typeptr);
-      if (tagdecltype) {
-         decl = tagdecltype->getDecl();
-      } else {
-         decl = typeptr->getAsCXXRecordDecl();
-      }
-   }
-
-   if (decl) {
-
-      clang::NamedDecl* outer  = llvm::dyn_cast_or_null<clang::NamedDecl>(decl->getDeclContext());
-      clang::NamespaceDecl* outer_ns = llvm::dyn_cast_or_null<clang::NamespaceDecl>(decl->getDeclContext());
-      if (outer && !(outer_ns && outer_ns->isAnonymousNamespace())) {
-         clang::CXXRecordDecl *cxxdecl = llvm::dyn_cast_or_null<clang::CXXRecordDecl>(decl->getDeclContext());
-         if (cxxdecl) {
-            clang::ClassTemplateDecl *clTempl = cxxdecl->getDescribedClassTemplate();
-            if (clTempl) {
-               // We are in the case of a type(def) that was declared in a
-               // class template but is *not* type dependent.  In clang, it gets
-               // attached to the class template declaration rather than any
-               // specific class template instantiation.   This result in 'odd'
-               // fully qualified typename:
-               //    vector<_Tp,_Alloc>::size_type
-               // Make the situation is 'useable' but looking a bit odd by
-               // picking a random instance as the declaring context.
-               if (clTempl->spec_begin() != clTempl->spec_end()) {
-                  decl = *(clTempl->spec_begin());
-                  outer  = llvm::dyn_cast<clang::NamedDecl>(decl);
-                  outer_ns = llvm::dyn_cast<clang::NamespaceDecl>(decl);
-               }
-            }
-         }
-
-         if (outer_ns) {
-            return CreateNestedNameSpecifier(Ctx,outer_ns);
-         } else {
-            assert(llvm::isa<clang::TagDecl>(outer)&& "not in namespace of TagDecl");
-            return CreateNestedNameSpecifier(Ctx,
-                                             llvm::dyn_cast<clang::TagDecl>(outer));
-         }
-      }
-   }
-   return 0;
-}
-
-//______________________________________________________________________________
-static const clang::Type *GetFullyQualifiedLocalType(const clang::ASTContext& Ctx,
-                                                     const clang::Type *typeptr)
-{
-   // We really just want to handle the template parameter if any ....
-   // In case of template specializations iterate over the arguments and
-   // fully qualifiy them as well.
-   if(const clang::TemplateSpecializationType* TST
-      = llvm::dyn_cast<const clang::TemplateSpecializationType>(typeptr)) {
-
-      bool mightHaveChanged = false;
-   llvm::SmallVector<clang::TemplateArgument, 4> desArgs;
-   for(clang::TemplateSpecializationType::iterator I = TST->begin(), E = TST->end();
-       I != E; ++I) {
-      if (I->getKind() != clang::TemplateArgument::Type) {
-         desArgs.push_back(*I);
-         continue;
-      }
-
-      clang::QualType SubTy = I->getAsType();
-   // Check if the type needs more desugaring and recurse.
-      mightHaveChanged = true;
-      desArgs.push_back(clang::TemplateArgument(GetFullyQualifiedType(Ctx,SubTy)));
-       }
-
-       // If desugaring happened allocate new type in the AST.
-       if (mightHaveChanged) {
-          clang::QualType QT = Ctx.getTemplateSpecializationType(TST->getTemplateName(),
-                                                                 desArgs.data(),
-                                                                 desArgs.size(),
-                                                                 TST->getCanonicalTypeInternal());
-          return QT.getTypePtr();
-       }
-      } else if (const clang::RecordType *TSTRecord
-         = llvm::dyn_cast<const clang::RecordType>(typeptr)) {
-         // We are asked to fully qualify and we have a Record Type,
-         // which can point to a template instantiation with no sugar in any of
-         // its template argument, however we still need to fully qualify them.
-
-         if (const clang::ClassTemplateSpecializationDecl* TSTdecl =
-            llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(TSTRecord->getDecl()))
-         {
-            const clang::TemplateArgumentList& templateArgs
-            = TSTdecl->getTemplateArgs();
-
-            bool mightHaveChanged = false;
-            llvm::SmallVector<clang::TemplateArgument, 4> desArgs;
-            for(unsigned int I = 0, E = templateArgs.size();
-                I != E; ++I) {
-               if (templateArgs[I].getKind() != clang::TemplateArgument::Type) {
-                  desArgs.push_back(templateArgs[I]);
-                  continue;
-               }
-
-               clang::QualType SubTy = templateArgs[I].getAsType();
-            // Check if the type needs more desugaring and recurse.
-               mightHaveChanged = true;
-               desArgs.push_back(clang::TemplateArgument(GetFullyQualifiedType(Ctx,SubTy)));
-                }
-                // If desugaring happened allocate new type in the AST.
-                if (mightHaveChanged) {
-                   clang::QualType QT = Ctx.getTemplateSpecializationType(clang::TemplateName(TSTdecl->getSpecializedTemplate()),
-                                                                          desArgs.data(),
-                                                                          desArgs.size(),
-                                                                          TSTRecord->getCanonicalTypeInternal());
-                   return QT.getTypePtr();
-                }
-         }
-         }
-         return typeptr;
-}
-
-//______________________________________________________________________________
-static clang::NestedNameSpecifier* GetFullyQualifiedTypeNNS(const clang::ASTContext& Ctx,
-                                                            clang::NestedNameSpecifier* scope)
-{
-   // Make sure that the given namespecifier has a fully qualifying chain
-   // (a name specifier for each of the declaring context) and that each
-   // of the element of the chain, if they are templates, have all they
-   // template argument fully qualified.
-
-   const clang::Type* scope_type = scope->getAsType();
-   if (scope_type) {
-      scope_type = GetFullyQualifiedLocalType(Ctx, scope_type);
-
-      // This is not a namespace, so we might need to also look at its
-      // (potential) template parameter.
-      clang::NestedNameSpecifier* outer_scope = scope->getPrefix();
-      if (outer_scope) {
-         outer_scope = GetFullyQualifiedTypeNNS(Ctx, outer_scope);
-
-         // NOTE: Should check whether the type has changed or not?
-         return clang::NestedNameSpecifier::Create(Ctx,outer_scope,
-                                                   false /* template keyword wanted */,
-                                                   scope_type);
-      } else {
-         // Do we need to make one up?
-
-         // NOTE: Should check whether the type has changed or not.
-         outer_scope = CreateNestedNameSpecifierForScopeOf(Ctx,scope_type);
-         return clang::NestedNameSpecifier::Create(Ctx,outer_scope,
-                                                   false /* template keyword wanted */,
-                                                   scope_type);
-      }
-   }
-   return scope;
-}
-
-//______________________________________________________________________________
-static clang::QualType GetFullyQualifiedType(const clang::ASTContext& Ctx,
-                                             const clang::QualType &qtype)
-{
-   // Return the fully qualified type, if we need to recurse through any template parameter,
-   // this needs to be merged somehow with GetPartialDesugaredType.
-
-   clang::QualType QT(qtype);
-
-   // In case of Int_t* we need to strip the pointer first, fully qualifiy and attach
-   // the pointer once again.
-   if (llvm::isa<clang::PointerType>(QT.getTypePtr())) {
-      // Get the qualifiers.
-      clang::Qualifiers quals = QT.getQualifiers();
-      QT = GetFullyQualifiedType(Ctx, QT->getPointeeType());
-      QT = Ctx.getPointerType(QT);
-      // Add back the qualifiers.
-      QT = Ctx.getQualifiedType(QT, quals);
-      return QT;
-   }
-
-   // In case of Int_t& we need to strip the pointer first, fully qualifiy  and attach
-   // the pointer once again.
-   if (llvm::isa<clang::ReferenceType>(QT.getTypePtr())) {
-      // Get the qualifiers.
-      bool isLValueRefTy = llvm::isa<clang::LValueReferenceType>(QT.getTypePtr());
-      clang::Qualifiers quals = QT.getQualifiers();
-      QT = GetFullyQualifiedType(Ctx, QT->getPointeeType());
-      // Add the r- or l-value reference type back to the desugared one.
-      if (isLValueRefTy)
-         QT = Ctx.getLValueReferenceType(QT);
-      else
-         QT = Ctx.getRValueReferenceType(QT);
-      // Add back the qualifiers.
-         QT = Ctx.getQualifiedType(QT, quals);
-         return QT;
-   }
-
-   clang::NestedNameSpecifier* prefix = 0;
-   clang::Qualifiers prefix_qualifiers;
-   const clang::ElaboratedType* etype_input = llvm::dyn_cast<clang::ElaboratedType>(QT.getTypePtr());
-   if (etype_input) {
-      // Intentionally, we do not care about the other compononent of
-      // the elaborated type (the keyword) as part of the partial
-      // desugaring (and/or name normaliztation) is to remove it.
-      prefix = etype_input->getQualifier();
-      if (prefix) {
-         const clang::NamespaceDecl *ns = prefix->getAsNamespace();
-         if (!(ns && ns->isAnonymousNamespace())) {
-            prefix_qualifiers = QT.getLocalQualifiers();
-            prefix = GetFullyQualifiedTypeNNS(Ctx, prefix);
-            QT = clang::QualType(etype_input->getNamedType().getTypePtr(),0);
-         } else {
-            prefix = 0;
-         }
-      }
-   } else {
-
-      // Create a nested name specifier if needed (i.e. if the decl context
-      // is not the global scope.
-      prefix = CreateNestedNameSpecifierForScopeOf(Ctx,QT.getTypePtr());
-
-      // move the qualifiers on the outer type (avoid 'std::const string'!)
-      if (prefix) {
-         prefix_qualifiers = QT.getLocalQualifiers();
-         QT = clang::QualType(QT.getTypePtr(),0);
-      }
-   }
-
-   // In case of template specializations iterate over the arguments and
-   // fully qualify them as well.
-   if(llvm::isa<const clang::TemplateSpecializationType>(QT.getTypePtr())) {
-
-      clang::Qualifiers qualifiers = QT.getLocalQualifiers();
-      const clang::Type *typeptr = GetFullyQualifiedLocalType(Ctx,QT.getTypePtr());
-      QT = Ctx.getQualifiedType(typeptr, qualifiers);
-
-   } else if (llvm::isa<const clang::RecordType>(QT.getTypePtr())) {
-      // We are asked to fully qualify and we have a Record Type,
-      // which can point to a template instantiation with no sugar in any of
-      // its template argument, however we still need to fully qualify them.
-
-      clang::Qualifiers qualifiers = QT.getLocalQualifiers();
-      const clang::Type *typeptr = GetFullyQualifiedLocalType(Ctx,QT.getTypePtr());
-      QT = Ctx.getQualifiedType(typeptr, qualifiers);
-
-   }
-   if (prefix) {
-      // We intentionally always use ETK_None, we never want
-      // the keyword (humm ... what about anonymous types?)
-      QT = Ctx.getElaboratedType(clang::ETK_None,prefix,QT);
-      QT = Ctx.getQualifiedType(QT, prefix_qualifiers);
-   }
-   return QT;
-}
 
 //______________________________________________________________________________
 static bool IsTypeInt(const clang::Type *type)
@@ -2884,8 +2561,8 @@ clang::QualType ROOT::TMetaUtils::AddDefaultParameters(clang::QualType instanceT
                   if (declCtxt && !templateName.getAsQualifiedTemplateName()){
                      clang::NamespaceDecl* ns = clang::dyn_cast<clang::NamespaceDecl>(declCtxt);
                      clang::NestedNameSpecifier* nns;
-                     if (ns) nns = ::CreateNestedNameSpecifier(Ctx, ns);
-                     else nns = ::CreateNestedNameSpecifier(Ctx,llvm::dyn_cast<clang::TagDecl>(declCtxt));
+                     if (ns) nns = cling::utils::TypeName::CreateNestedNameSpecifier(Ctx, ns);
+                     else nns = cling::utils::TypeName::CreateNestedNameSpecifier(Ctx,llvm::dyn_cast<clang::TagDecl>(declCtxt));
                      clang::TemplateName templateNameWithNSS ( Ctx.getQualifiedTemplateName(nns, false, templateDecl) );
                      desArgs.push_back(clang::TemplateArgument(templateNameWithNSS));
                      mightHaveChanged = true;
@@ -3315,36 +2992,15 @@ llvm::StringRef ROOT::TMetaUtils::GetFileName(const clang::Decl *decl,
    return invalidFilename;
 }
 
-//______________________________________________________________________________
-clang::QualType ROOT::TMetaUtils::GetFullyQualifiedType(const clang::QualType &qtype,
-                                                        const clang::ASTContext &astContext)
-{
-   return ::GetFullyQualifiedType(astContext,qtype);
-}
-
-//______________________________________________________________________________
-clang::QualType ROOT::TMetaUtils::GetFullyQualifiedType(const clang::QualType &qtype,
-                                                        const cling::Interpreter &interpreter)
-{
-   const clang::ASTContext& Ctx = interpreter.getCI()->getASTContext();
-   return GetFullyQualifiedType(qtype,Ctx);
-}
-
 //______________________________________________________________________________
 void ROOT::TMetaUtils::GetFullyQualifiedTypeName(std::string &typenamestr,
                                                  const clang::QualType &qtype,
                                                  const clang::ASTContext &astContext)
 {
-
-   clang::QualType typeForName = ::GetFullyQualifiedType(astContext,qtype);
-   clang::PrintingPolicy policy(astContext.getPrintingPolicy());
-   policy.SuppressScope = false;
-   policy.AnonymousTagLocations = false;
-
-   TClassEdit::TSplitType splitname(typeForName.getAsString(policy).c_str(),
+   std::string fqname = cling::utils::TypeName::GetFullyQualifiedName(qtype, astContext);
+   TClassEdit::TSplitType splitname(fqname.c_str(),
                                     (TClassEdit::EModType)(TClassEdit::kLong64 | TClassEdit::kDropStd | TClassEdit::kDropStlDefault | TClassEdit::kKeepOuterConst));
    splitname.ShortType(typenamestr,TClassEdit::kDropStd | TClassEdit::kDropStlDefault | TClassEdit::kKeepOuterConst);
-
 }
 
 //______________________________________________________________________________
diff --git a/interpreter/cling/include/cling/Utils/AST.h b/interpreter/cling/include/cling/Utils/AST.h
index f52766d0caa..ecf5adc909d 100644
--- a/interpreter/cling/include/cling/Utils/AST.h
+++ b/interpreter/cling/include/cling/Utils/AST.h
@@ -20,8 +20,10 @@ namespace clang {
   class IntegerLiteral;
   class NamedDecl;
   class NamespaceDecl;
+  class NestedNameSpecifier;
   class QualType;
   class Sema;
+  class TagDecl;
   class Type;
 }
 
@@ -190,6 +192,45 @@ namespace utils {
                                    const clang::DeclContext* Within = 0);
 
   };
+
+  namespace TypeName {
+    ///\brief Convert the type into one with fully qualified template
+    /// arguments.
+    ///\param[in] QT - the type for which the fully qualified type will be
+    /// returned.
+    ///\param[in] Ctx - the ASTContext to be used.
+    clang::QualType GetFullyQualifiedType(clang::QualType QT,
+                                          const clang::ASTContext& Ctx);
+
+    ///\brief Get the fully qualified name for a type. This includes full
+    /// qualification of all template parameters etc.
+    ///
+    ///\param[in] QT - the type for which the fully qualified name will be
+    /// returned.
+    ///\param[in] Ctx - the ASTContext to be used.
+    std::string GetFullyQualifiedName(clang::QualType QT,
+                                      const clang::ASTContext &Ctx);
+
+    ///\brief Create a NestedNameSpecifier for Namesp and its enclosing
+    /// scopes.
+    ///
+    ///\param[in] Ctx - the AST Context to be used.
+    ///\param[in] Namesp - the NamespaceDecl for which a NestedNameSpecifier
+    /// is requested.
+    clang::NestedNameSpecifier*
+    CreateNestedNameSpecifier(const clang::ASTContext& Ctx,
+                              const clang::NamespaceDecl* Namesp);
+
+    ///\brief Create a NestedNameSpecifier for TagDecl and its enclosing
+    /// scopes.
+    ///
+    ///\param[in] Ctx - the AST Context to be used.
+    ///\param[in] TD - the TagDecl for which a NestedNameSpecifier is
+    /// requested.
+    clang::NestedNameSpecifier*
+    CreateNestedNameSpecifier(const clang::ASTContext& Ctx,
+                              const clang::TagDecl *TD);
+  }; // end namespace TypeName
 } // end namespace utils
 } // end namespace cling
 #endif // CLING_UTILS_AST_H
diff --git a/interpreter/cling/lib/Utils/AST.cpp b/interpreter/cling/lib/Utils/AST.cpp
index dfe6a9654a9..ab8525f725f 100644
--- a/interpreter/cling/lib/Utils/AST.cpp
+++ b/interpreter/cling/lib/Utils/AST.cpp
@@ -44,12 +44,12 @@ namespace utils {
       .startswith(Synthesize::UniquePrefix);
   }
 
-  void Analyze::maybeMangleDeclName(const clang::GlobalDecl& GD,
+  void Analyze::maybeMangleDeclName(const GlobalDecl& GD,
                                     std::string& mangledName) {
-    // copied and adapted from clang::CodeGen::CodeGenModule::getMangledName
+    // copied and adapted from CodeGen::CodeGenModule::getMangledName
 
-    clang::NamedDecl* D
-      = cast<NamedDecl>(const_cast<clang::Decl*>(GD.getDecl()));
+    NamedDecl* D
+      = cast<NamedDecl>(const_cast<Decl*>(GD.getDecl()));
     llvm::OwningPtr<MangleContext> mangleCtx;
     mangleCtx.reset(D->getASTContext().createMangleContext());
     if (!mangleCtx->shouldMangleDeclName(D)) {
@@ -170,50 +170,90 @@ namespace utils {
     return IntegerLiteral::Create(C, Addr, C.UnsignedLongTy, SourceLocation());
   }
 
-  static
-  NestedNameSpecifier* CreateNestedNameSpecifier(const ASTContext& Ctx,
-                                                 const NamespaceDecl* cl) {
-    
-    const NamespaceDecl* outer
-      = dyn_cast_or_null<NamespaceDecl>(cl->getDeclContext());
-    if (outer && outer->getName().size()) {
-      NestedNameSpecifier* outerNNS = CreateNestedNameSpecifier(Ctx,outer);
-      return NestedNameSpecifier::Create(Ctx,outerNNS,
-                        // Newer version of clang do not require this const_cast
-                                         const_cast<NamespaceDecl*>(cl));
-    } else {
-      return NestedNameSpecifier::Create(Ctx, 
-                                         0, /* no starting '::'*/
-                       // Newer version of clang do not require this const_cast
-                                         const_cast<NamespaceDecl*>(cl));
+  static const clang::Type*
+  GetFullyQualifiedLocalType(const clang::ASTContext& Ctx,
+                             const clang::Type *typeptr) {
+    // We really just want to handle the template parameter if any ....
+    // In case of template specializations iterate over the arguments and
+    // fully qualify them as well.
+    if (const clang::TemplateSpecializationType* TST
+        = llvm::dyn_cast<const clang::TemplateSpecializationType>(typeptr)) {
+
+      bool mightHaveChanged = false;
+      llvm::SmallVector<clang::TemplateArgument, 4> desArgs;
+      for (clang::TemplateSpecializationType::iterator I = TST->begin(), E = TST->end();
+          I != E; ++I) {
+        if (I->getKind() != clang::TemplateArgument::Type) {
+          desArgs.push_back(*I);
+          continue;
+        }
+
+        clang::QualType SubTy = I->getAsType();
+        // Check if the type needs more desugaring and recurse.
+        mightHaveChanged = true;
+        desArgs.push_back(clang::TemplateArgument(TypeName::GetFullyQualifiedType(SubTy, Ctx)));
+      }
+
+      // If desugaring happened allocate new type in the AST.
+      if (mightHaveChanged) {
+        clang::QualType QT = Ctx.getTemplateSpecializationType(TST->getTemplateName(),
+                                                               desArgs.data(),
+                                                               desArgs.size(),
+                                                               TST->getCanonicalTypeInternal());
+        return QT.getTypePtr();
+      }
+    } else if (const clang::RecordType *TSTRecord
+               = llvm::dyn_cast<const clang::RecordType>(typeptr)) {
+      // We are asked to fully qualify and we have a Record Type,
+      // which can point to a template instantiation with no sugar in any of
+      // its template argument, however we still need to fully qualify them.
+
+      if (const clang::ClassTemplateSpecializationDecl* TSTdecl =
+          llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(TSTRecord->getDecl()))
+        {
+          const clang::TemplateArgumentList& templateArgs
+            = TSTdecl->getTemplateArgs();
+
+          bool mightHaveChanged = false;
+          llvm::SmallVector<clang::TemplateArgument, 4> desArgs;
+          for(unsigned int I = 0, E = templateArgs.size();
+              I != E; ++I) {
+            if (templateArgs[I].getKind() != clang::TemplateArgument::Type) {
+              desArgs.push_back(templateArgs[I]);
+              continue;
+            }
+
+            clang::QualType SubTy = templateArgs[I].getAsType();
+            // Check if the type needs more desugaring and recurse.
+            mightHaveChanged = true;
+            desArgs.push_back(clang::TemplateArgument(TypeName::GetFullyQualifiedType(SubTy, Ctx)));
+          }
+          // If desugaring happened allocate new type in the AST.
+          if (mightHaveChanged) {
+            clang::QualType QT = Ctx.getTemplateSpecializationType(clang::TemplateName(TSTdecl->getSpecializedTemplate()),
+                                                                   desArgs.data(),
+                                                                   desArgs.size(),
+                                                                   TSTRecord->getCanonicalTypeInternal());
+            return QT.getTypePtr();
+          }
+        }
     }
+    return typeptr;
   }
-  
-  static
-  NestedNameSpecifier* CreateNestedNameSpecifier(const ASTContext& Ctx,
-                                                 const TagDecl *cl) {
-    
-    const NamedDecl* outer = dyn_cast_or_null<NamedDecl>(cl->getDeclContext());
-    if (outer && outer->getName().size()) {
-      NestedNameSpecifier *outerNNS;
-      if (cl->getDeclContext()->isNamespace()) {
-        outerNNS = CreateNestedNameSpecifier(Ctx,
-                                             dyn_cast<NamespaceDecl>(outer));
-      } else {
-        outerNNS = CreateNestedNameSpecifier(Ctx,
-                                             dyn_cast<TagDecl>(outer));
-      }
-      return NestedNameSpecifier::Create(Ctx,outerNNS,
-                                         false /* template keyword wanted */,
-                                         Ctx.getTypeDeclType(cl).getTypePtr());
-    } else {
-      return NestedNameSpecifier::Create(Ctx, 
-                                         0, /* no starting '::'*/
-                                         false /* template keyword wanted */,
-                                         Ctx.getTypeDeclType(cl).getTypePtr());        
+
+  static NestedNameSpecifier* CreateOuterNNS(const ASTContext& Ctx,
+                                             const Decl* D) {
+    const DeclContext* DC = D->getDeclContext();
+    if (const NamespaceDecl* NS = dyn_cast<NamespaceDecl>(DC)) {
+      if (NS->getDeclName())
+        return TypeName::CreateNestedNameSpecifier(Ctx, NS);
+      return 0; // no starting '::'
+    } else if (const TagDecl* TD = dyn_cast<TagDecl>(DC)) {
+      return TypeName::CreateNestedNameSpecifier(Ctx, TD);
     }
+    return 0; // no starting '::'    
   }
-  
+
   static
   NestedNameSpecifier* GetFullyQualifiedNameSpecifier(const ASTContext& Ctx,
                                                   NestedNameSpecifier* scope) {
@@ -262,10 +302,10 @@ namespace utils {
     }
     if (needCreate) {
       if (NamespaceDecl *ns = scope->getAsNamespace()) {
-        return CreateNestedNameSpecifier(Ctx,ns);
+        return TypeName::CreateNestedNameSpecifier(Ctx,ns);
       } else if (NamespaceAliasDecl *alias = scope->getAsNamespaceAlias())
       {
-        return CreateNestedNameSpecifier(Ctx,
+        return TypeName::CreateNestedNameSpecifier(Ctx,
                                      alias->getNamespace()->getCanonicalDecl());
 
       } else {
@@ -288,7 +328,7 @@ namespace utils {
         }
         TagDecl *tdecl = dyn_cast<TagDecl>(idecl);
         if (tdecl) {
-          return CreateNestedNameSpecifier(Ctx,tdecl);
+          return TypeName::CreateNestedNameSpecifier(Ctx,tdecl);
         }
       }
     }
@@ -328,7 +368,7 @@ namespace utils {
             // as a starting point.
             prefix = GetFullyQualifiedNameSpecifier(Ctx,original_prefix);
           } else {
-            prefix = CreateNestedNameSpecifier(Ctx,
+            prefix = TypeName::CreateNestedNameSpecifier(Ctx,
                                                dyn_cast<NamespaceDecl>(new_ns));
           }
         }
@@ -347,7 +387,7 @@ namespace utils {
           } else {
             const TagDecl *tdecl = dyn_cast<TagDecl>(declContext);
             if (tdecl) {
-              prefix = CreateNestedNameSpecifier(Ctx,tdecl);
+              prefix = TypeName::CreateNestedNameSpecifier(Ctx,tdecl);
             }
           }
         } else {
@@ -356,7 +396,7 @@ namespace utils {
           // It could also be a CXXMethod for example.
           const TagDecl *tdecl = dyn_cast<TagDecl>(declContext);
           if (tdecl) {
-            prefix = CreateNestedNameSpecifier(Ctx,tdecl);
+            prefix = TypeName::CreateNestedNameSpecifier(Ctx,tdecl);
           }
         }
       }
@@ -786,7 +826,7 @@ namespace utils {
       iter = TypeConfig.m_toReplace.find(QT.getTypePtr());
       if (iter != TypeConfig.m_toReplace.end()) {
         Qualifiers quals = QT.getQualifiers();
-        QT = clang::QualType( iter->second, 0);
+        QT = QualType( iter->second, 0);
         QT = Ctx.getQualifiedType(QT,quals);
         break;
       }
@@ -877,7 +917,7 @@ namespace utils {
           }
           if (outer) {
             if (decl->getDeclContext()->isNamespace()) {
-              prefix = CreateNestedNameSpecifier(Ctx,
+              prefix = TypeName::CreateNestedNameSpecifier(Ctx,
                                                 dyn_cast<NamespaceDecl>(outer));
             } else {
               // We should only create the nested name specifier
@@ -885,7 +925,7 @@ namespace utils {
               // It could also be a CXXMethod for example.
               TagDecl *tdecl = dyn_cast<TagDecl>(outer);
               if (tdecl) {
-                prefix = CreateNestedNameSpecifier(Ctx,tdecl);
+                prefix = TypeName::CreateNestedNameSpecifier(Ctx,tdecl);
                 prefix = GetPartiallyDesugaredNNS(Ctx,prefix,TypeConfig);
               }
             }
@@ -1074,5 +1114,221 @@ namespace utils {
     return R.getFoundDecl();
 
   }
+
+  static NestedNameSpecifier*
+  CreateNestedNameSpecifierForScopeOf(const ASTContext& Ctx,
+                                      const Type *TypePtr)
+  {
+    // Create a nested name specifier for the declaring context of the type.
+
+    if (!TypePtr)
+      return 0;
+
+    Decl *decl = 0;
+    if (const TypedefType* typedeftype = llvm::dyn_cast<TypedefType>(TypePtr)) {
+      decl = typedeftype->getDecl();
+    } else {
+      // There are probably other cases ...
+      if (const TagType* tagdecltype = llvm::dyn_cast_or_null<TagType>(TypePtr))
+        decl = tagdecltype->getDecl();
+      else
+        decl = TypePtr->getAsCXXRecordDecl();
+    }
+
+    if (!decl)
+      return 0;
+
+    NamedDecl* outer
+      = llvm::dyn_cast_or_null<NamedDecl>(decl->getDeclContext());
+    NamespaceDecl* outer_ns
+      = llvm::dyn_cast_or_null<NamespaceDecl>(decl->getDeclContext());
+    if (outer && !(outer_ns && outer_ns->isAnonymousNamespace())) {
+      
+      if (CXXRecordDecl *cxxdecl
+          = llvm::dyn_cast<CXXRecordDecl>(decl->getDeclContext())) {
+        
+        if (ClassTemplateDecl *clTempl = cxxdecl->getDescribedClassTemplate()) {
+          // We are in the case of a type(def) that was declared in a
+          // class template but is *not* type dependent.  In clang, it gets
+          // attached to the class template declaration rather than any
+          // specific class template instantiation.   This result in 'odd'
+          // fully qualified typename:
+          //    vector<_Tp,_Alloc>::size_type
+          // Make the situation is 'useable' but looking a bit odd by
+          // picking a random instance as the declaring context.
+          if (clTempl->spec_begin() != clTempl->spec_end()) {
+            decl = *(clTempl->spec_begin());
+            outer  = llvm::dyn_cast<NamedDecl>(decl);
+            outer_ns = llvm::dyn_cast<NamespaceDecl>(decl);
+          }
+        }
+      }
+
+      if (outer_ns) {
+        return TypeName::CreateNestedNameSpecifier(Ctx,outer_ns);
+      } else {
+        assert(llvm::isa<TagDecl>(outer) && "not in namespace of TagDecl");
+        return TypeName::CreateNestedNameSpecifier(Ctx, llvm::dyn_cast<TagDecl>(outer));
+      }
+    }
+    return 0;
+  }
+
+
+  static clang::NestedNameSpecifier*
+  GetFullyQualifiedTypeNNS(const clang::ASTContext& Ctx,
+                           clang::NestedNameSpecifier* scope) {
+    // Make sure that the given namespecifier has a fully qualifying chain
+    // (a name specifier for each of the declaring context) and that each
+    // of the element of the chain, if they are templates, have all they
+    // template argument fully qualified.
+
+    const clang::Type* scope_type = scope->getAsType();
+    if (scope_type) {
+      scope_type = GetFullyQualifiedLocalType(Ctx, scope_type);
+
+      // This is not a namespace, so we might need to also look at its
+      // (potential) template parameter.
+      clang::NestedNameSpecifier* outer_scope = scope->getPrefix();
+      if (outer_scope) {
+        outer_scope = GetFullyQualifiedTypeNNS(Ctx, outer_scope);
+
+        // NOTE: Should check whether the type has changed or not?
+        return clang::NestedNameSpecifier::Create(Ctx,outer_scope,
+                                                  false /* template keyword wanted */,
+                                                  scope_type);
+      } else {
+        // Do we need to make one up?
+
+        // NOTE: Should check whether the type has changed or not.
+        outer_scope = CreateNestedNameSpecifierForScopeOf(Ctx,scope_type);
+        return clang::NestedNameSpecifier::Create(Ctx,outer_scope,
+                                                  false /* template keyword wanted */,
+                                                  scope_type);
+      }
+    }
+    return scope;
+  }
+
+
+  NestedNameSpecifier*
+  TypeName::CreateNestedNameSpecifier(const ASTContext& Ctx,
+                                      const NamespaceDecl* Namesp) {
+    return NestedNameSpecifier::Create(Ctx, CreateOuterNNS(Ctx, Namesp), Namesp);
+  }
+  
+  NestedNameSpecifier*
+  TypeName::CreateNestedNameSpecifier(const ASTContext& Ctx,
+                                      const TagDecl *TD) {
+    const Type* QT
+      = GetFullyQualifiedLocalType(Ctx, Ctx.getTypeDeclType(TD).getTypePtr());
+    return NestedNameSpecifier::Create(Ctx, CreateOuterNNS(Ctx, TD),
+                                       false /* template keyword wanted */,
+                                       QT);
+  }
+  
+
+  QualType
+  TypeName::GetFullyQualifiedType(QualType QT, const ASTContext& Ctx) {
+    // Return the fully qualified type, if we need to recurse through any
+    // template parameter, this needs to be merged somehow with
+    // GetPartialDesugaredType.
+
+    // In case of myType* we need to strip the pointer first, fully qualifiy
+    // and attach the pointer once again.
+    if (llvm::isa<PointerType>(QT.getTypePtr())) {
+      // Get the qualifiers.
+      Qualifiers quals = QT.getQualifiers();
+      QT = GetFullyQualifiedType(QT->getPointeeType(), Ctx);
+      QT = Ctx.getPointerType(QT);
+      // Add back the qualifiers.
+      QT = Ctx.getQualifiedType(QT, quals);
+      return QT;
+    }
+
+    // In case of myType& we need to strip the pointer first, fully qualifiy
+    // and attach the pointer once again.
+    if (llvm::isa<ReferenceType>(QT.getTypePtr())) {
+      // Get the qualifiers.
+      bool isLValueRefTy = llvm::isa<LValueReferenceType>(QT.getTypePtr());
+      Qualifiers quals = QT.getQualifiers();
+      QT = GetFullyQualifiedType(QT->getPointeeType(), Ctx);
+      // Add the r- or l-value reference type back to the desugared one.
+      if (isLValueRefTy)
+        QT = Ctx.getLValueReferenceType(QT);
+      else
+        QT = Ctx.getRValueReferenceType(QT);
+      // Add back the qualifiers.
+      QT = Ctx.getQualifiedType(QT, quals);
+      return QT;
+    }
+
+    NestedNameSpecifier* prefix = 0;
+    Qualifiers prefix_qualifiers;
+    if (const ElaboratedType* etype_input
+        = llvm::dyn_cast<ElaboratedType>(QT.getTypePtr())) {
+      // Intentionally, we do not care about the other compononent of
+      // the elaborated type (the keyword) as part of the partial
+      // desugaring (and/or name normalization) is to remove it.
+      prefix = etype_input->getQualifier();
+      if (prefix) {
+        const NamespaceDecl *ns = prefix->getAsNamespace();
+        if (!(ns && ns->isAnonymousNamespace())) {
+          prefix_qualifiers = QT.getLocalQualifiers();
+          prefix = GetFullyQualifiedTypeNNS(Ctx, prefix);
+          QT = QualType(etype_input->getNamedType().getTypePtr(),0);
+        } else {
+          prefix = 0;
+        }
+      }
+    } else {
+
+      // Create a nested name specifier if needed (i.e. if the decl context
+      // is not the global scope.
+      prefix = CreateNestedNameSpecifierForScopeOf(Ctx,QT.getTypePtr());
+
+      // move the qualifiers on the outer type (avoid 'std::const string'!)
+      if (prefix) {
+        prefix_qualifiers = QT.getLocalQualifiers();
+        QT = QualType(QT.getTypePtr(),0);
+      }
+    }
+
+    // In case of template specializations iterate over the arguments and
+    // fully qualify them as well.
+    if(llvm::isa<const TemplateSpecializationType>(QT.getTypePtr())) {
+
+      Qualifiers qualifiers = QT.getLocalQualifiers();
+      const Type *TypePtr = GetFullyQualifiedLocalType(Ctx,QT.getTypePtr());
+      QT = Ctx.getQualifiedType(TypePtr, qualifiers);
+
+    } else if (llvm::isa<const RecordType>(QT.getTypePtr())) {
+      // We are asked to fully qualify and we have a Record Type,
+      // which can point to a template instantiation with no sugar in any of
+      // its template argument, however we still need to fully qualify them.
+
+      Qualifiers qualifiers = QT.getLocalQualifiers();
+      const Type *TypePtr = GetFullyQualifiedLocalType(Ctx,QT.getTypePtr());
+      QT = Ctx.getQualifiedType(TypePtr, qualifiers);
+
+    }
+    if (prefix) {
+      // We intentionally always use ETK_None, we never want
+      // the keyword (humm ... what about anonymous types?)
+      QT = Ctx.getElaboratedType(ETK_None,prefix,QT);
+      QT = Ctx.getQualifiedType(QT, prefix_qualifiers);
+    }
+    return QT; 
+  }
+
+  std::string TypeName::GetFullyQualifiedName(clang::QualType QT,
+                                              const clang::ASTContext &Ctx) {
+    QualType FQQT = GetFullyQualifiedType(QT, Ctx);
+    clang::PrintingPolicy Policy(Ctx.getPrintingPolicy());
+    Policy.SuppressScope = false;
+    Policy.AnonymousTagLocations = false;
+    return FQQT.getAsString(Policy);
+  }
+
 } // end namespace utils
 } // end namespace cling
-- 
GitLab