Teach NestedNameSpecifier to keep track of namespace aliases the same
way it keeps track of namespaces. Previously, we would map from the
namespace alias to its underlying namespace when building a
nested-name-specifier, losing source information in the process.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@126358 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 0b3febd..9c24550 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -2981,7 +2981,15 @@
   case NestedNameSpecifier::Namespace:
     // A namespace is canonical; build a nested-name-specifier with
     // this namespace and no prefix.
-    return NestedNameSpecifier::Create(*this, 0, NNS->getAsNamespace());
+    return NestedNameSpecifier::Create(*this, 0, 
+                                 NNS->getAsNamespace()->getOriginalNamespace());
+
+  case NestedNameSpecifier::NamespaceAlias:
+    // A namespace is canonical; build a nested-name-specifier with
+    // this namespace and no prefix.
+    return NestedNameSpecifier::Create(*this, 0, 
+                                    NNS->getAsNamespaceAlias()->getNamespace()
+                                                      ->getOriginalNamespace());
 
   case NestedNameSpecifier::TypeSpec:
   case NestedNameSpecifier::TypeSpecWithTemplate: {
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index e2dbb83..939ca7a 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -606,6 +606,9 @@
   case NestedNameSpecifier::Namespace:
     mangleName(Qualifier->getAsNamespace());
     break;
+  case NestedNameSpecifier::NamespaceAlias:
+    mangleName(Qualifier->getAsNamespaceAlias()->getNamespace());
+    break;
   case NestedNameSpecifier::TypeSpec:
   case NestedNameSpecifier::TypeSpecWithTemplate: {
     const Type *QTy = Qualifier->getAsType();
diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp
index 650321d..1b477d8 100644
--- a/lib/AST/NestedNameSpecifier.cpp
+++ b/lib/AST/NestedNameSpecifier.cpp
@@ -14,6 +14,7 @@
 #include "clang/AST/NestedNameSpecifier.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
 #include "clang/AST/PrettyPrinter.h"
 #include "clang/AST/Type.h"
 #include "llvm/Support/raw_ostream.h"
@@ -46,7 +47,7 @@
 
   NestedNameSpecifier Mockup;
   Mockup.Prefix.setPointer(Prefix);
-  Mockup.Prefix.setInt(Identifier);
+  Mockup.Prefix.setInt(StoredIdentifier);
   Mockup.Specifier = II;
   return FindOrInsert(Context, Mockup);
 }
@@ -60,19 +61,34 @@
          "Broken nested name specifier");
   NestedNameSpecifier Mockup;
   Mockup.Prefix.setPointer(Prefix);
-  Mockup.Prefix.setInt(Namespace);
+  Mockup.Prefix.setInt(StoredNamespaceOrAlias);
   Mockup.Specifier = NS;
   return FindOrInsert(Context, Mockup);
 }
 
 NestedNameSpecifier *
 NestedNameSpecifier::Create(const ASTContext &Context,
+                            NestedNameSpecifier *Prefix, 
+                            NamespaceAliasDecl *Alias) {
+  assert(Alias && "Namespace alias cannot be NULL");
+  assert((!Prefix ||
+          (Prefix->getAsType() == 0 && Prefix->getAsIdentifier() == 0)) &&
+         "Broken nested name specifier");
+  NestedNameSpecifier Mockup;
+  Mockup.Prefix.setPointer(Prefix);
+  Mockup.Prefix.setInt(StoredNamespaceOrAlias);
+  Mockup.Specifier = Alias;
+  return FindOrInsert(Context, Mockup);
+}
+
+NestedNameSpecifier *
+NestedNameSpecifier::Create(const ASTContext &Context,
                             NestedNameSpecifier *Prefix,
                             bool Template, const Type *T) {
   assert(T && "Type cannot be NULL");
   NestedNameSpecifier Mockup;
   Mockup.Prefix.setPointer(Prefix);
-  Mockup.Prefix.setInt(Template? TypeSpecWithTemplate : TypeSpec);
+  Mockup.Prefix.setInt(Template? StoredTypeSpecWithTemplate : StoredTypeSpec);
   Mockup.Specifier = const_cast<Type*>(T);
   return FindOrInsert(Context, Mockup);
 }
@@ -82,7 +98,7 @@
   assert(II && "Identifier cannot be NULL");
   NestedNameSpecifier Mockup;
   Mockup.Prefix.setPointer(0);
-  Mockup.Prefix.setInt(Identifier);
+  Mockup.Prefix.setInt(StoredIdentifier);
   Mockup.Specifier = II;
   return FindOrInsert(Context, Mockup);
 }
@@ -94,6 +110,47 @@
   return Context.GlobalNestedNameSpecifier;
 }
 
+NestedNameSpecifier::SpecifierKind NestedNameSpecifier::getKind() const {
+  if (Specifier == 0)
+    return Global;
+
+  switch (Prefix.getInt()) {
+  case StoredIdentifier:
+    return Identifier;
+
+  case StoredNamespaceOrAlias:
+    return isa<NamespaceDecl>(static_cast<NamedDecl *>(Specifier))? Namespace
+                                                            : NamespaceAlias;
+
+  case StoredTypeSpec:
+    return TypeSpec;
+
+  case StoredTypeSpecWithTemplate:
+    return TypeSpecWithTemplate;
+  }
+
+  return Global;
+}
+
+/// \brief Retrieve the namespace stored in this nested name
+/// specifier.
+NamespaceDecl *NestedNameSpecifier::getAsNamespace() const {
+  if (Prefix.getInt() == StoredNamespaceOrAlias)
+    return dyn_cast<NamespaceDecl>(static_cast<NamedDecl *>(Specifier));
+
+  return 0;
+}
+
+/// \brief Retrieve the namespace alias stored in this nested name
+/// specifier.
+NamespaceAliasDecl *NestedNameSpecifier::getAsNamespaceAlias() const {
+  if (Prefix.getInt() == StoredNamespaceOrAlias)
+    return dyn_cast<NamespaceAliasDecl>(static_cast<NamedDecl *>(Specifier));
+
+  return 0;
+}
+
+
 /// \brief Whether this nested name specifier refers to a dependent
 /// type or not.
 bool NestedNameSpecifier::isDependent() const {
@@ -103,6 +160,7 @@
     return true;
 
   case Namespace:
+  case NamespaceAlias:
   case Global:
     return false;
 
@@ -121,6 +179,7 @@
     return getPrefix() && getPrefix()->containsUnexpandedParameterPack();
 
   case Namespace:
+  case NamespaceAlias:
   case Global:
     return false;
 
@@ -147,7 +206,11 @@
     break;
 
   case Namespace:
-    OS << getAsNamespace()->getIdentifier()->getName();
+    OS << getAsNamespace()->getName();
+    break;
+
+  case NamespaceAlias:
+    OS << getAsNamespaceAlias()->getName();
     break;
 
   case Global:
diff --git a/lib/Frontend/DocumentXML.cpp b/lib/Frontend/DocumentXML.cpp
index b24ece5..a09db0b 100644
--- a/lib/Frontend/DocumentXML.cpp
+++ b/lib/Frontend/DocumentXML.cpp
@@ -14,6 +14,7 @@
 
 #include "clang/Frontend/DocumentXML.h"
 #include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/Basic/SourceManager.h"
 #include "llvm/ADT/StringExtras.h"
@@ -218,6 +219,10 @@
     addPtrAttribute(pAttributeName, pNNS->getAsNamespace());
     break;
   }
+  case NestedNameSpecifier::NamespaceAlias: {
+    addPtrAttribute(pAttributeName, pNNS->getAsNamespaceAlias());
+    break;
+  }
   case NestedNameSpecifier::TypeSpec: {
     addPtrAttribute(pAttributeName, pNNS->getAsType());
     break;
diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp
index 3998497..f21d90f 100644
--- a/lib/Sema/DeclSpec.cpp
+++ b/lib/Sema/DeclSpec.cpp
@@ -74,6 +74,15 @@
   Range.setEnd(ColonColonLoc);
 }
 
+void CXXScopeSpec::Extend(ASTContext &Context, NamespaceAliasDecl *Alias,
+                          SourceLocation AliasLoc, 
+                          SourceLocation ColonColonLoc) {
+  ScopeRep = NestedNameSpecifier::Create(Context, ScopeRep, Alias);
+  if (Range.getBegin().isInvalid())
+    Range.setBegin(AliasLoc);
+  Range.setEnd(ColonColonLoc);
+}
+
 void CXXScopeSpec::MakeGlobal(ASTContext &Context, 
                               SourceLocation ColonColonLoc) {
   assert(!ScopeRep && "Already have a nested-name-specifier!?");
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 754c52c..9daec58 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -139,6 +139,9 @@
   case NestedNameSpecifier::Namespace:
     return NNS->getAsNamespace();
 
+  case NestedNameSpecifier::NamespaceAlias:
+    return NNS->getAsNamespaceAlias()->getNamespace();
+
   case NestedNameSpecifier::TypeSpec:
   case NestedNameSpecifier::TypeSpecWithTemplate: {
     const TagType *Tag = NNS->getAsType()->getAs<TagType>();
@@ -532,11 +535,8 @@
       return false;
     }
 
-    // FIXME: It would be nice to maintain the namespace alias name, then
-    // see through that alias when resolving the nested-name-specifier down to
-    // a declaration context.
     if (NamespaceAliasDecl *Alias = dyn_cast<NamespaceAliasDecl>(SD)) {
-      SS.Extend(Context, Alias->getNamespace(), IdentifierLoc, CCLoc);
+      SS.Extend(Context, Alias, IdentifierLoc, CCLoc);
       return false;
     }
 
@@ -681,6 +681,7 @@
   switch (Qualifier->getKind()) {
   case NestedNameSpecifier::Global:
   case NestedNameSpecifier::Namespace:
+  case NestedNameSpecifier::NamespaceAlias:
     // These are always namespace scopes.  We never want to enter a
     // namespace scope from anything but a file context.
     return CurContext->getRedeclContext()->isFileContext();
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index ab6dde5..d75a1f1 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -2868,6 +2868,7 @@
   switch (NNS->getKind()) {
   case NestedNameSpecifier::Identifier:
   case NestedNameSpecifier::Namespace:
+  case NestedNameSpecifier::NamespaceAlias:
   case NestedNameSpecifier::Global:
     return false;
 
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index d30ed74..ba80076 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -1895,6 +1895,7 @@
           break;
 
         case NestedNameSpecifier::Namespace:
+        case NestedNameSpecifier::NamespaceAlias:
         case NestedNameSpecifier::Global:
           llvm_unreachable("Nested-name-specifier must name a type");
           break;
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 7a0754f..1b2822e 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -877,6 +877,16 @@
                                                   NamespaceDecl *NS);
 
   /// \brief Build a new nested-name-specifier given the prefix and the
+  /// namespace alias named in the next step in the nested-name-specifier.
+  ///
+  /// By default, performs semantic analysis when building the new
+  /// nested-name-specifier. Subclasses may override this routine to provide
+  /// different behavior.
+  NestedNameSpecifier *RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
+                                                  SourceRange Range,
+                                                  NamespaceAliasDecl *Alias);
+
+  /// \brief Build a new nested-name-specifier given the prefix and the
   /// type named in the next step in the nested-name-specifier.
   ///
   /// By default, performs semantic analysis when building the new
@@ -2450,6 +2460,19 @@
     return getDerived().RebuildNestedNameSpecifier(Prefix, Range, NS);
   }
 
+  case NestedNameSpecifier::NamespaceAlias: {
+    NamespaceAliasDecl *Alias
+      = cast_or_null<NamespaceAliasDecl>(
+                                    getDerived().TransformDecl(Range.getBegin(),
+                                                    NNS->getAsNamespaceAlias()));
+    if (!getDerived().AlwaysRebuild() &&
+        Prefix == NNS->getPrefix() &&
+        Alias == NNS->getAsNamespaceAlias())
+      return NNS;
+
+    return getDerived().RebuildNestedNameSpecifier(Prefix, Range, Alias);
+  }
+
   case NestedNameSpecifier::Global:
     // There is no meaningful transformation that one could perform on the
     // global scope.
@@ -7571,6 +7594,14 @@
 NestedNameSpecifier *
 TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
                                                    SourceRange Range,
+                                                   NamespaceAliasDecl *Alias) {
+  return NestedNameSpecifier::Create(SemaRef.Context, Prefix, Alias);
+}
+
+template<typename Derived>
+NestedNameSpecifier *
+TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
+                                                   SourceRange Range,
                                                    bool TemplateKW,
                                                    QualType T) {
   if (T->isDependentType() || T->isRecordType() ||
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 2e8e8ca..6f8856c 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -4730,6 +4730,13 @@
       break;
     }
 
+    case NestedNameSpecifier::NamespaceAlias: {
+      NamespaceAliasDecl *Alias
+        = cast<NamespaceAliasDecl>(GetDecl(Record[Idx++]));
+      NNS = NestedNameSpecifier::Create(*Context, Prev, Alias);
+      break;
+    }
+
     case NestedNameSpecifier::TypeSpec:
     case NestedNameSpecifier::TypeSpecWithTemplate: {
       const Type *T = GetType(Record[Idx++]).getTypePtrOrNull();
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index b1edf95..42ca293 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -3470,6 +3470,10 @@
       AddDeclRef(NNS->getAsNamespace(), Record);
       break;
 
+    case NestedNameSpecifier::NamespaceAlias:
+      AddDeclRef(NNS->getAsNamespaceAlias(), Record);
+      break;
+
     case NestedNameSpecifier::TypeSpec:
     case NestedNameSpecifier::TypeSpecWithTemplate:
       AddTypeRef(QualType(NNS->getAsType(), 0), Record);