blob: f36ec9f3e2093dbfb022e84b9073ad5ef046d738 [file] [log] [blame]
//===--- 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_SEMA_TYPELOCBUILDER_H
#define LLVM_CLANG_SEMA_TYPELOCBUILDER_H
#include "clang/AST/ASTContext.h"
#include "clang/AST/TypeLoc.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 a copy of the given TypeLoc onto this builder. The builder
/// must be empty for this to work.
void pushFullCopy(TypeLoc L) {
size_t Size = L.getFullDataSize();
TypeLoc Copy = pushFullUninitializedImpl(L.getType(), Size);
memcpy(Copy.getOpaqueData(), L.getOpaqueData(), Size);
}
/// Pushes uninitialized space for the given type. The builder must
/// be empty.
TypeLoc pushFullUninitialized(QualType T) {
return pushFullUninitializedImpl(T, TypeLoc::getFullDataSizeForType(T));
}
/// Pushes space for a typespec TypeLoc. Invalidates any TypeLocs
/// previously retrieved from this builder.
TypeSpecTypeLoc pushTypeSpec(QualType T) {
size_t LocalSize = TypeSpecTypeLoc::LocalDataSize;
return pushImpl(T, LocalSize).castAs<TypeSpecTypeLoc>();
}
/// Resets this builder to the newly-initialized state.
void clear() {
#ifndef NDEBUG
LastTy = QualType();
#endif
Index = Capacity;
}
/// \brief Tell the TypeLocBuilder that the type it is storing has been
/// modified in some safe way that doesn't affect type-location information.
void TypeWasModifiedSafely(QualType T) {
#ifndef NDEBUG
LastTy = T;
#endif
}
/// Pushes space for a new TypeLoc of the given type. Invalidates
/// any TypeLocs previously retrieved from this builder.
template <class TyLocType> TyLocType push(QualType T) {
size_t LocalSize = TypeLoc(T, 0).castAs<TyLocType>().getLocalDataSize();
return pushImpl(T, LocalSize).castAs<TyLocType>();
}
/// Creates a TypeSourceInfo for the given type.
TypeSourceInfo *getTypeSourceInfo(ASTContext& Context, QualType T) {
#ifndef NDEBUG
assert(T == LastTy && "type doesn't match last type pushed!");
#endif
size_t FullDataSize = Capacity - Index;
TypeSourceInfo *DI = Context.CreateTypeSourceInfo(T, FullDataSize);
memcpy(DI->getTypeLoc().getOpaqueData(), &Buffer[Index], FullDataSize);
return DI;
}
/// \brief Copies the type-location information to the given AST context and
/// returns a \c TypeLoc referring into the AST context.
TypeLoc getTypeLocInContext(ASTContext &Context, QualType T) {
#ifndef NDEBUG
assert(T == LastTy && "type doesn't match last type pushed!");
#endif
size_t FullDataSize = Capacity - Index;
void *Mem = Context.Allocate(FullDataSize);
memcpy(Mem, &Buffer[Index], FullDataSize);
return TypeLoc(T, Mem);
}
private:
TypeLoc pushImpl(QualType T, size_t LocalSize) {
#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
// 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 getTemporaryTypeLoc(T);
}
/// 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;
}
TypeLoc pushFullUninitializedImpl(QualType T, size_t Size) {
#ifndef NDEBUG
assert(LastTy.isNull() && "pushing full on non-empty TypeLocBuilder");
LastTy = T;
#endif
assert(Index == Capacity && "pushing full on non-empty TypeLocBuilder");
reserve(Size);
Index -= Size;
return getTemporaryTypeLoc(T);
}
public:
/// \brief Retrieve a temporary TypeLoc that refers into this \c TypeLocBuilder
/// object.
///
/// The resulting \c TypeLoc should only be used so long as the
/// \c TypeLocBuilder is active and has not had more type information
/// pushed into it.
TypeLoc getTemporaryTypeLoc(QualType T) {
#ifndef NDEBUG
assert(LastTy == T && "type doesn't match last type pushed!");
#endif
return TypeLoc(T, &Buffer[Index]);
}
};
}
#endif