From 26fe7e0b8ad4240bc51127aa9126afdf13aee4ca Mon Sep 17 00:00:00 2001 From: John McCall Date: Wed, 21 Oct 2009 00:23:54 +0000 Subject: [PATCH] Add TypeLocBuilder, an API for incrementally creating TypeLocs. Change the API for creating DeclaratorInfos to allow callers to provide an exact size. llvm-svn: 84715 --- clang/include/clang/AST/ASTContext.h | 5 +- clang/include/clang/AST/TypeLocBuilder.h | 122 +++++++++++++++++++++++ clang/lib/AST/ASTContext.cpp | 10 +- 3 files changed, 134 insertions(+), 3 deletions(-) create mode 100644 clang/include/clang/AST/TypeLocBuilder.h diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index df480e9a36a5..8507cd41754c 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -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/clang/include/clang/AST/TypeLocBuilder.h b/clang/include/clang/AST/TypeLocBuilder.h new file mode 100644 index 000000000000..4e1fbaaf4c5e --- /dev/null +++ b/clang/include/clang/AST/TypeLocBuilder.h @@ -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 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(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(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 diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 98aef39022fe..8855cba15945 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -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);