Retain complete source-location information for C++
nested-name-specifiers throughout the parser, and provide a new class
(NestedNameSpecifierLoc) that contains a nested-name-specifier along
with its type-source information.

Right now, this information is completely useless, because we don't
actually store the source-location information anywhere in the
AST. Call this Step 1/N.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@126391 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp
index f21d90f..2d85374 100644
--- a/lib/Sema/DeclSpec.cpp
+++ b/lib/Sema/DeclSpec.cpp
@@ -14,6 +14,7 @@
 #include "clang/Parse/ParseDiagnostic.h" // FIXME: remove this back-dependency!
 #include "clang/Sema/DeclSpec.h"
 #include "clang/Sema/ParsedTemplate.h"
+#include "clang/AST/ASTContext.h"
 #include "clang/AST/NestedNameSpecifier.h"
 #include "clang/AST/TypeLoc.h"
 #include "clang/Lex/Preprocessor.h"
@@ -46,6 +47,85 @@
   EndLocation = TemplateId->RAngleLoc;
 }
 
+CXXScopeSpec::CXXScopeSpec(const CXXScopeSpec &Other)
+  : Range(Other.Range), ScopeRep(Other.ScopeRep), Buffer(0), 
+    BufferSize(Other.BufferSize), BufferCapacity(Other.BufferSize) 
+{
+  if (BufferSize) {
+    Buffer = static_cast<char *>(malloc(BufferSize));
+    memcpy(Buffer, Other.Buffer, BufferSize);
+  }
+}
+
+CXXScopeSpec &CXXScopeSpec::operator=(const CXXScopeSpec &Other) {
+  Range = Other.Range;
+  ScopeRep = Other.ScopeRep;
+  if (Buffer && Other.Buffer && BufferCapacity >= Other.BufferSize) {
+    // Re-use our storage.
+    BufferSize = Other.BufferSize;
+    memcpy(Buffer, Other.Buffer, BufferSize);
+    return *this;
+  }
+  
+  if (BufferCapacity)
+    free(Buffer);
+  if (Other.Buffer) {
+    BufferSize = Other.BufferSize;
+    BufferCapacity = BufferSize;
+    Buffer = static_cast<char *>(malloc(BufferSize));
+    memcpy(Buffer, Other.Buffer, BufferSize);
+  } else {
+    Buffer = 0;
+    BufferSize = 0;
+    BufferCapacity = 0;
+  }
+  return *this;
+}
+
+CXXScopeSpec::~CXXScopeSpec() {
+  if (BufferCapacity)
+    free(Buffer);
+}
+
+namespace {
+  void Append(char *Start, char *End, char *&Buffer, unsigned &BufferSize,
+              unsigned &BufferCapacity) {
+    if (BufferSize + (End - Start) > BufferCapacity) {
+      // Reallocate the buffer.
+      unsigned NewCapacity 
+        = std::max((unsigned)(BufferCapacity? BufferCapacity * 2 
+                                            : sizeof(void*) * 2),
+                   (unsigned)(BufferSize + (End - Start)));
+      char *NewBuffer = static_cast<char *>(malloc(NewCapacity));
+      memcpy(NewBuffer, Buffer, BufferSize);
+      
+      if (BufferCapacity)
+        free(Buffer);
+      Buffer = NewBuffer;
+      BufferCapacity = NewCapacity;
+    }
+    
+    memcpy(Buffer + BufferSize, Start, End - Start);
+    BufferSize += End-Start;
+  }
+  
+  /// \brief Save a source location to the given buffer.
+  void SaveSourceLocation(SourceLocation Loc, char *&Buffer,
+                          unsigned &BufferSize, unsigned &BufferCapacity) {
+    unsigned Raw = Loc.getRawEncoding();
+    Append(reinterpret_cast<char *>(&Raw),
+           reinterpret_cast<char *>(&Raw) + sizeof(unsigned),
+           Buffer, BufferSize, BufferCapacity);
+  }
+  
+  /// \brief Save a pointer to the given buffer.
+  void SavePointer(void *Ptr, char *&Buffer, unsigned &BufferSize,
+                   unsigned &BufferCapacity) {
+    Append(reinterpret_cast<char *>(&Ptr),
+           reinterpret_cast<char *>(&Ptr) + sizeof(void *),
+           Buffer, BufferSize, BufferCapacity);
+  }
+}
 void CXXScopeSpec::Extend(ASTContext &Context, SourceLocation TemplateKWLoc, 
                           TypeLoc TL, SourceLocation ColonColonLoc) {
   ScopeRep = NestedNameSpecifier::Create(Context, ScopeRep, 
@@ -54,6 +134,13 @@
   if (Range.getBegin().isInvalid())
     Range.setBegin(TL.getBeginLoc());
   Range.setEnd(ColonColonLoc);
+
+  // Push source-location info into the buffer.
+  SavePointer(TL.getOpaqueData(), Buffer, BufferSize, BufferCapacity);
+  SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
+
+  assert(Range == NestedNameSpecifierLoc(ScopeRep, Buffer).getSourceRange() &&
+         "NestedNameSpecifierLoc range computation incorrect");
 }
 
 void CXXScopeSpec::Extend(ASTContext &Context, IdentifierInfo *Identifier,
@@ -63,6 +150,13 @@
   if (Range.getBegin().isInvalid())
     Range.setBegin(IdentifierLoc);
   Range.setEnd(ColonColonLoc);
+  
+  // Push source-location info into the buffer.
+  SaveSourceLocation(IdentifierLoc, Buffer, BufferSize, BufferCapacity);
+  SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
+  
+  assert(Range == NestedNameSpecifierLoc(ScopeRep, Buffer).getSourceRange() &&
+         "NestedNameSpecifierLoc range computation incorrect");
 }
 
 void CXXScopeSpec::Extend(ASTContext &Context, NamespaceDecl *Namespace,
@@ -72,6 +166,13 @@
   if (Range.getBegin().isInvalid())
     Range.setBegin(NamespaceLoc);
   Range.setEnd(ColonColonLoc);
+
+  // Push source-location info into the buffer.
+  SaveSourceLocation(NamespaceLoc, Buffer, BufferSize, BufferCapacity);
+  SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
+  
+  assert(Range == NestedNameSpecifierLoc(ScopeRep, Buffer).getSourceRange() &&
+         "NestedNameSpecifierLoc range computation incorrect");
 }
 
 void CXXScopeSpec::Extend(ASTContext &Context, NamespaceAliasDecl *Alias,
@@ -81,6 +182,13 @@
   if (Range.getBegin().isInvalid())
     Range.setBegin(AliasLoc);
   Range.setEnd(ColonColonLoc);
+
+  // Push source-location info into the buffer.
+  SaveSourceLocation(AliasLoc, Buffer, BufferSize, BufferCapacity);
+  SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
+  
+  assert(Range == NestedNameSpecifierLoc(ScopeRep, Buffer).getSourceRange() &&
+         "NestedNameSpecifierLoc range computation incorrect");
 }
 
 void CXXScopeSpec::MakeGlobal(ASTContext &Context, 
@@ -88,6 +196,87 @@
   assert(!ScopeRep && "Already have a nested-name-specifier!?");
   ScopeRep = NestedNameSpecifier::GlobalSpecifier(Context);
   Range = SourceRange(ColonColonLoc);
+  
+  // Push source-location info into the buffer.
+  SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
+  
+  assert(Range == NestedNameSpecifierLoc(ScopeRep, Buffer).getSourceRange() &&
+         "NestedNameSpecifierLoc range computation incorrect");
+}
+
+void CXXScopeSpec::MakeTrivial(ASTContext &Context, 
+                               NestedNameSpecifier *Qualifier, SourceRange R) {
+  ScopeRep = Qualifier;
+  Range = R;
+
+  // Construct bogus (but well-formed) source information for the 
+  // nested-name-specifier.
+  BufferSize = 0;
+  llvm::SmallVector<NestedNameSpecifier *, 4> Stack;
+  for (NestedNameSpecifier *NNS = Qualifier; NNS; NNS = NNS->getPrefix())
+    Stack.push_back(NNS);
+  while (!Stack.empty()) {
+    NestedNameSpecifier *NNS = Stack.back();
+    Stack.pop_back();
+    switch (NNS->getKind()) {
+    case NestedNameSpecifier::Identifier:
+    case NestedNameSpecifier::Namespace:
+    case NestedNameSpecifier::NamespaceAlias:
+      SaveSourceLocation(R.getBegin(), Buffer, BufferSize, BufferCapacity);
+      break;
+
+    case NestedNameSpecifier::TypeSpec:
+    case NestedNameSpecifier::TypeSpecWithTemplate: {
+      TypeSourceInfo *TSInfo
+        = Context.getTrivialTypeSourceInfo(QualType(NNS->getAsType(), 0),
+                                           R.getBegin());
+      SavePointer(TSInfo->getTypeLoc().getOpaqueData(), Buffer, BufferSize, 
+                  BufferCapacity);
+      break;
+    }
+        
+    case NestedNameSpecifier::Global:
+      break;
+    }
+
+    // Save the location of the '::'.
+    SaveSourceLocation(Stack.empty()? R.getEnd() : R.getBegin(), 
+                       Buffer, BufferSize, BufferCapacity);
+  }
+}
+
+void CXXScopeSpec::Adopt(NestedNameSpecifierLoc Other) {
+  if (!Other) {
+    Range = SourceRange();
+    ScopeRep = 0;
+    return;
+  }
+    
+  if (BufferCapacity)
+    free(Buffer);
+  
+  // Rather than copying the data (which is wasteful), "adopt" the 
+  // pointer (which points into the ASTContext) but set the capacity to zero to
+  // indicate that we don't own it.
+  Range = Other.getSourceRange();
+  ScopeRep = Other.getNestedNameSpecifier();
+  Buffer = static_cast<char *>(Other.getOpaqueData());
+  BufferSize = Other.getDataLength();
+  BufferCapacity = 0;
+}
+
+NestedNameSpecifierLoc CXXScopeSpec::getWithLocInContext(ASTContext &Context) {
+  if (isEmpty() || isInvalid())
+    return NestedNameSpecifierLoc();
+  
+  // If we adopted our data pointer from elsewhere in the AST context, there's
+  // no need to copy the memory.
+  if (BufferCapacity == 0)
+    return NestedNameSpecifierLoc(ScopeRep, Buffer);
+  
+  void *Mem = Context.Allocate(BufferSize, llvm::alignOf<void *>());
+  memcpy(Mem, Buffer, BufferSize);
+  return NestedNameSpecifierLoc(ScopeRep, Mem);
 }
 
 /// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function.