]> granicus.if.org Git - clang/commitdiff
Add TypeLocBuilder, an API for incrementally creating TypeLocs. Change
authorJohn McCall <rjmccall@apple.com>
Wed, 21 Oct 2009 00:23:54 +0000 (00:23 +0000)
committerJohn McCall <rjmccall@apple.com>
Wed, 21 Oct 2009 00:23:54 +0000 (00:23 +0000)
the API for creating DeclaratorInfos to allow callers to provide an exact
size.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@84715 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/ASTContext.h
include/clang/AST/TypeLocBuilder.h [new file with mode: 0644]
lib/AST/ASTContext.cpp

index df480e9a36a5936d06c8ef84dd9ede3083d7d6f6..8507cd41754cb677b53bfac9804ddc3e0785fd8e 100644 (file)
@@ -1059,7 +1059,10 @@ public:
   /// \param T the type that will be the basis for type source info. This type
   /// should refer to how the declarator was written in source code, not to
   /// what type semantic analysis resolved the declarator to.
-  DeclaratorInfo *CreateDeclaratorInfo(QualType T);
+  ///
+  /// \param Size the size of the type info to create, or 0 if the size
+  /// should be calculated based on the type.
+  DeclaratorInfo *CreateDeclaratorInfo(QualType T, unsigned Size = 0);
 
 private:
   ASTContext(const ASTContext&); // DO NOT IMPLEMENT
diff --git a/include/clang/AST/TypeLocBuilder.h b/include/clang/AST/TypeLocBuilder.h
new file mode 100644 (file)
index 0000000..4e1fbaa
--- /dev/null
@@ -0,0 +1,122 @@
+//===--- TypeLocBuilder.h - Type Source Info collector ----------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This files defines TypeLocBuilder, a class for building TypeLocs
+//  bottom-up.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_TYPELOCBUILDER_H
+#define LLVM_CLANG_AST_TYPELOCBUILDER_H
+
+#include "clang/AST/TypeLoc.h"
+#include "llvm/ADT/SmallVector.h"
+
+namespace clang {
+
+class TypeLocBuilder {
+  enum { InlineCapacity = 8 * sizeof(SourceLocation) };
+
+  /// The underlying location-data buffer.  Data grows from the end
+  /// of the buffer backwards.
+  char *Buffer;
+
+  /// The capacity of the current buffer.
+  size_t Capacity;
+
+  /// The index of the first occupied byte in the buffer.
+  size_t Index;
+
+#ifndef NDEBUG
+  /// The last type pushed on this builder.
+  QualType LastTy;
+#endif
+    
+  /// The inline buffer.
+  char InlineBuffer[InlineCapacity];
+
+ public:
+  TypeLocBuilder()
+    : Buffer(InlineBuffer), Capacity(InlineCapacity), Index(InlineCapacity)
+  {}
+
+  ~TypeLocBuilder() {
+    if (Buffer != InlineBuffer)
+      delete[] Buffer;
+  }
+
+  /// Ensures that this buffer has at least as much capacity as described.
+  void reserve(size_t Requested) {
+    if (Requested > Capacity)
+      // For now, match the request exactly.
+      grow(Requested);
+  }
+
+  /// Pushes space for a new TypeLoc onto the given type.  Invalidates
+  /// any TypeLocs previously retrieved from this builder.
+  template <class TyLocType> TyLocType push(QualType T) {
+#ifndef NDEBUG
+    QualType TLast = TypeLoc(T, 0).getNextTypeLoc().getType();
+    assert(TLast == LastTy &&
+           "mismatch between last type and new type's inner type");
+    LastTy = T;
+#endif
+
+    size_t LocalSize = cast<TyLocType>(TypeLoc(T, 0)).getLocalDataSize();
+
+    // If we need to grow, grow by a factor of 2.
+    if (LocalSize > Index) {
+      size_t RequiredCapacity = Capacity + (LocalSize - Index);
+      size_t NewCapacity = Capacity * 2;
+      while (RequiredCapacity > NewCapacity)
+        NewCapacity *= 2;
+      grow(NewCapacity);
+    }
+
+    Index -= LocalSize;
+
+    return cast<TyLocType>(TypeLoc(T, &Buffer[Index]));
+  }
+
+  /// Creates a DeclaratorInfo for the given type.
+  DeclaratorInfo *getDeclaratorInfo(ASTContext& Context, QualType T) {
+#ifndef NDEBUG
+    assert(T == LastTy && "type doesn't match last type pushed!");
+#endif
+
+    size_t FullDataSize = Capacity - Index;
+    DeclaratorInfo *DI = Context.CreateDeclaratorInfo(T, FullDataSize);
+    memcpy(DI->getTypeLoc().getOpaqueData(), &Buffer[Index], FullDataSize);
+    return DI;
+  }
+
+ private:
+  /// Grow to the given capacity.
+  void grow(size_t NewCapacity) {
+    assert(NewCapacity > Capacity);
+
+    // Allocate the new buffer and copy the old data into it.
+    char *NewBuffer = new char[NewCapacity];
+    unsigned NewIndex = Index + NewCapacity - Capacity;
+    memcpy(&NewBuffer[NewIndex],
+           &Buffer[Index],
+           Capacity - Index);
+
+    if (Buffer != InlineBuffer)
+      delete[] Buffer;
+
+    Buffer = NewBuffer;
+    Capacity = NewCapacity;
+    Index = NewIndex;
+  }
+};
+
+}
+
+#endif
index 98aef39022fe58ce197ff89fca71173c9ddf33d3..8855cba1594579cb3b4eca52048de0056a5e241b 100644 (file)
@@ -943,8 +943,14 @@ void ASTContext::setObjCImplementation(ObjCCategoryDecl *CatD,
 /// \param T the type that will be the basis for type source info. This type
 /// should refer to how the declarator was written in source code, not to
 /// what type semantic analysis resolved the declarator to.
-DeclaratorInfo *ASTContext::CreateDeclaratorInfo(QualType T) {
-  unsigned DataSize = TypeLoc::getFullDataSizeForType(T);
+DeclaratorInfo *ASTContext::CreateDeclaratorInfo(QualType T,
+                                                 unsigned DataSize) {
+  if (!DataSize)
+    DataSize = TypeLoc::getFullDataSizeForType(T);
+  else
+    assert(DataSize == TypeLoc::getFullDataSizeForType(T) &&
+           "incorrect data size provided to CreateDeclaratorInfo!");
+
   DeclaratorInfo *DInfo =
     (DeclaratorInfo*)BumpAlloc.Allocate(sizeof(DeclaratorInfo) + DataSize, 8);
   new (DInfo) DeclaratorInfo(T);