text: //===--- TypeLocBuilder.cpp - Type Source Info collector ------------------===//
  //
  // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  // See https://llvm.org/LICENSE.txt for license information.
  // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  //
  //===----------------------------------------------------------------------===//
  //
  //  This files defines TypeLocBuilder, a class for building TypeLocs
  //  bottom-up.
  //
  //===----------------------------------------------------------------------===//
  
  #include "TypeLocBuilder.h"
  
  using namespace clang;
  
  void TypeLocBuilder::pushFullCopy(TypeLoc L) {
    size_t Size = L.getFullDataSize();
    reserve(Size);
  
    SmallVector<TypeLoc, 4> TypeLocs;
    TypeLoc CurTL = L;
    while (CurTL) {
      TypeLocs.push_back(CurTL);
      CurTL = CurTL.getNextTypeLoc();
    }
  
    for (unsigned i = 0, e = TypeLocs.size(); i < e; ++i) {
      TypeLoc CurTL = TypeLocs[e-i-1];
      switch (CurTL.getTypeLocClass()) {
  #define ABSTRACT_TYPELOC(CLASS, PARENT)
  #define TYPELOC(CLASS, PARENT) \
      case TypeLoc::CLASS: { \
        CLASS##TypeLoc NewTL = push<class CLASS##TypeLoc>(CurTL.getType()); \
        memcpy(NewTL.getOpaqueData(), CurTL.getOpaqueData(), NewTL.getLocalDataSize()); \
        break; \
      }
  #include "clang/AST/TypeLocNodes.def"
      }
    }
  }
  
  void TypeLocBuilder::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 TypeLocBuilder::pushImpl(QualType T, size_t LocalSize, unsigned LocalAlignment) {
  #ifndef NDEBUG
    QualType TLast = TypeLoc(T, nullptr).getNextTypeLoc().getType();
    assert(TLast == LastTy &&
           "mismatch between last type and new type's inner type");
    LastTy = T;
  #endif
  
    assert(LocalAlignment <= BufferMaxAlignment && "Unexpected alignment");
  
    // 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);
    }
  
    // Because we're adding elements to the TypeLoc backwards, we have to
    // do some extra work to keep everything aligned appropriately.
    // FIXME: This algorithm is a absolute mess because every TypeLoc returned
    // needs to be valid.  Partial TypeLocs are a terrible idea.
    // FIXME: 4 and 8 are sufficient at the moment, but it's pretty ugly to
    // hardcode them.
    if (LocalAlignment == 4) {
      if (NumBytesAtAlign8 == 0) {
        NumBytesAtAlign4 += LocalSize;
      } else {
        unsigned Padding = NumBytesAtAlign4 % 8;
        if (Padding == 0) {
          if (LocalSize % 8 == 0) {
            // Everything is set: there's no padding and we don't need to add
            // any.
          } else {
            assert(LocalSize % 8 == 4);
            // No existing padding; add in 4 bytes padding
            memmove(&Buffer[Index - 4], &Buffer[Index], NumBytesAtAlign4);
            Index -= 4;
          }
        } else {
          assert(Padding == 4);
          if (LocalSize % 8 == 0) {
            // Everything is set: there's 4 bytes padding and we don't need
            // to add any.
          } else {
            assert(LocalSize % 8 == 4);
            // There are 4 bytes padding, but we don't need any; remove it.
            memmove(&Buffer[Index + 4], &Buffer[Index], NumBytesAtAlign4);
            Index += 4;
          }
        }
        NumBytesAtAlign4 += LocalSize;
      }
    } else if (LocalAlignment == 8) {
      if (NumBytesAtAlign8 == 0) {
        // We have not seen any 8-byte aligned element yet. We insert a padding
        // only if the new Index is not 8-byte-aligned.
        if ((Index - LocalSize) % 8 != 0) {
          memmove(&Buffer[Index - 4], &Buffer[Index], NumBytesAtAlign4);
          Index -= 4;
        }
      } else {
        unsigned Padding = NumBytesAtAlign4 % 8;
        if (Padding == 0) {
          if (LocalSize % 8 == 0) {
            // Everything is set: there's no padding and we don't need to add
            // any.
          } else {
            assert(LocalSize % 8 == 4);
            // No existing padding; add in 4 bytes padding
            memmove(&Buffer[Index - 4], &Buffer[Index], NumBytesAtAlign4);
            Index -= 4;
          }
        } else {
          assert(Padding == 4);
          if (LocalSize % 8 == 0) {
            // Everything is set: there's 4 bytes padding and we don't need
            // to add any.
          } else {
            assert(LocalSize % 8 == 4);
            // There are 4 bytes padding, but we don't need any; remove it.
            memmove(&Buffer[Index + 4], &Buffer[Index], NumBytesAtAlign4);
            Index += 4;
          }
        }
      }
  
      // Forget about any padding.
      NumBytesAtAlign4 = 0;
      NumBytesAtAlign8 += LocalSize;
    } else {
      assert(LocalSize == 0);
    }
  
    Index -= LocalSize;
  
    assert(Capacity - Index == TypeLoc::getFullDataSizeForType(T) &&
           "incorrect data size provided to CreateTypeSourceInfo!");
  
    return getTemporaryTypeLoc(T);
  }
  