//==--- AbstractBasiceReader.h - Abstract basic value deserialization -----===//
 
//
 
// 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
 
//
 
//===----------------------------------------------------------------------===//
 
 
 
#ifndef LLVM_CLANG_AST_ABSTRACTBASICREADER_H
 
#define LLVM_CLANG_AST_ABSTRACTBASICREADER_H
 
 
 
#include "clang/AST/DeclTemplate.h"
 
#include <optional>
 
 
 
namespace clang {
 
namespace serialization {
 
 
 
template <class T>
 
inline T makeNullableFromOptional(const std::optional<T> &value) {
 
  return (value ? *value : T());
 
}
 
 
 
template <class T> inline T *makePointerFromOptional(std::optional<T *> value) {
 
  return value.value_or(nullptr);
 
}
 
 
 
// PropertyReader is a class concept that requires the following method:
 
//   BasicReader find(llvm::StringRef propertyName);
 
// where BasicReader is some class conforming to the BasicReader concept.
 
// An abstract AST-node reader is created with a PropertyReader and
 
// performs a sequence of calls like so:
 
//   propertyReader.find(propertyName).read##TypeName()
 
// to read the properties of the node it is deserializing.
 
 
 
// BasicReader is a class concept that requires methods like:
 
//   ValueType read##TypeName();
 
// where TypeName is the name of a PropertyType node from PropertiesBase.td
 
// and ValueType is the corresponding C++ type name.  The read method may
 
// require one or more buffer arguments.
 
//
 
// In addition to the concrete type names, BasicReader is expected to
 
// implement these methods:
 
//
 
//   template <class EnumType>
 
//   void writeEnum(T value);
 
//
 
//     Reads an enum value from the current property.  EnumType will always
 
//     be an enum type.  Only necessary if the BasicReader doesn't provide
 
//     type-specific readers for all the enum types.
 
//
 
//   template <class ValueType>
 
//   std::optional<ValueType> writeOptional();
 
//
 
//     Reads an optional value from the current property.
 
//
 
//   template <class ValueType>
 
//   ArrayRef<ValueType> readArray(llvm::SmallVectorImpl<ValueType> &buffer);
 
//
 
//     Reads an array of values from the current property.
 
//
 
//   PropertyReader readObject();
 
//
 
//     Reads an object from the current property; the returned property
 
//     reader will be subjected to a sequence of property reads and then
 
//     discarded before any other properties are reader from the "outer"
 
//     property reader (which need not be the same type).  The sub-reader
 
//     will be used as if with the following code:
 
//
 
//       {
 
//         auto &&widget = W.find("widget").readObject();
 
//         auto kind = widget.find("kind").readWidgetKind();
 
//         auto declaration = widget.find("declaration").readDeclRef();
 
//         return Widget(kind, declaration);
 
//       }
 
 
 
// ReadDispatcher does type-based forwarding to one of the read methods
 
// on the BasicReader passed in:
 
//
 
// template <class ValueType>
 
// struct ReadDispatcher {
 
//   template <class BasicReader, class... BufferTypes>
 
//   static ValueType read(BasicReader &R, BufferTypes &&...);
 
// };
 
 
 
// BasicReaderBase provides convenience implementations of the read methods
 
// for EnumPropertyType and SubclassPropertyType types that just defer to
 
// the "underlying" implementations (for UInt32 and the base class,
 
// respectively).
 
//
 
// template <class Impl>
 
// class BasicReaderBase {
 
// protected:
 
//   BasicReaderBase(ASTContext &ctx);
 
//   Impl &asImpl();
 
// public:
 
//   ASTContext &getASTContext();
 
//   ...
 
// };
 
 
 
// The actual classes are auto-generated; see ClangASTPropertiesEmitter.cpp.
 
#include "clang/AST/AbstractBasicReader.inc"
 
 
 
/// DataStreamBasicReader provides convenience implementations for many
 
/// BasicReader methods based on the assumption that the
 
/// ultimate reader implementation is based on a variable-length stream
 
/// of unstructured data (like Clang's module files).  It is designed
 
/// to pair with DataStreamBasicWriter.
 
///
 
/// This class can also act as a PropertyReader, implementing find("...")
 
/// by simply forwarding to itself.
 
///
 
/// Unimplemented methods:
 
///   readBool
 
///   readUInt32
 
///   readUInt64
 
///   readIdentifier
 
///   readSelector
 
///   readSourceLocation
 
///   readQualType
 
///   readStmtRef
 
///   readDeclRef
 
template <class Impl>
 
class DataStreamBasicReader : public BasicReaderBase<Impl> {
 
protected:
 
  using BasicReaderBase<Impl>::asImpl;
 
  DataStreamBasicReader(ASTContext &ctx) : BasicReaderBase<Impl>(ctx) {}
 
 
 
public:
 
  using BasicReaderBase<Impl>::getASTContext;
 
 
 
  /// Implement property-find by ignoring it.  We rely on properties being
 
  /// serialized and deserialized in a reliable order instead.
 
  Impl &find(const char *propertyName) {
 
    return asImpl();
 
  }
 
 
 
  template <class T>
 
  T readEnum() {
 
    return T(asImpl().readUInt32());
 
  }
 
 
 
  // Implement object reading by forwarding to this, collapsing the
 
  // structure into a single data stream.
 
  Impl &readObject() { return asImpl(); }
 
 
 
  template <class T>
 
  llvm::ArrayRef<T> readArray(llvm::SmallVectorImpl<T> &buffer) {
 
    assert(buffer.empty());
 
 
 
    uint32_t size = asImpl().readUInt32();
 
    buffer.reserve(size);
 
 
 
    for (uint32_t i = 0; i != size; ++i) {
 
      buffer.push_back(ReadDispatcher<T>::read(asImpl()));
 
    }
 
    return buffer;
 
  }
 
 
 
  template <class T, class... Args>
 
  std::optional<T> readOptional(Args &&...args) {
 
    return UnpackOptionalValue<T>::unpack(
 
             ReadDispatcher<T>::read(asImpl(), std::forward<Args>(args)...));
 
  }
 
 
 
  llvm::APSInt readAPSInt() {
 
    bool isUnsigned = asImpl().readBool();
 
    llvm::APInt value = asImpl().readAPInt();
 
    return llvm::APSInt(std::move(value), isUnsigned);
 
  }
 
 
 
  llvm::APInt readAPInt() {
 
    unsigned bitWidth = asImpl().readUInt32();
 
    unsigned numWords = llvm::APInt::getNumWords(bitWidth);
 
    llvm::SmallVector<uint64_t, 4> data;
 
    for (uint32_t i = 0; i != numWords; ++i)
 
      data.push_back(asImpl().readUInt64());
 
    return llvm::APInt(bitWidth, numWords, &data[0]);
 
  }
 
 
 
  llvm::FixedPointSemantics readFixedPointSemantics() {
 
    unsigned width = asImpl().readUInt32();
 
    unsigned scale = asImpl().readUInt32();
 
    unsigned tmp = asImpl().readUInt32();
 
    bool isSigned = tmp & 0x1;
 
    bool isSaturated = tmp & 0x2;
 
    bool hasUnsignedPadding = tmp & 0x4;
 
    return llvm::FixedPointSemantics(width, scale, isSigned, isSaturated,
 
                                     hasUnsignedPadding);
 
  }
 
 
 
  APValue::LValuePathSerializationHelper readLValuePathSerializationHelper(
 
      SmallVectorImpl<APValue::LValuePathEntry> &path) {
 
    auto origTy = asImpl().readQualType();
 
    auto elemTy = origTy;
 
    unsigned pathLength = asImpl().readUInt32();
 
    for (unsigned i = 0; i < pathLength; ++i) {
 
      if (elemTy->template getAs<RecordType>()) {
 
        unsigned int_ = asImpl().readUInt32();
 
        Decl *decl = asImpl().template readDeclAs<Decl>();
 
        if (auto *recordDecl = dyn_cast<CXXRecordDecl>(decl))
 
          elemTy = getASTContext().getRecordType(recordDecl);
 
        else
 
          elemTy = cast<ValueDecl>(decl)->getType();
 
        path.push_back(
 
            APValue::LValuePathEntry(APValue::BaseOrMemberType(decl, int_)));
 
      } else {
 
        elemTy = getASTContext().getAsArrayType(elemTy)->getElementType();
 
        path.push_back(
 
            APValue::LValuePathEntry::ArrayIndex(asImpl().readUInt32()));
 
      }
 
    }
 
    return APValue::LValuePathSerializationHelper(path, origTy);
 
  }
 
 
 
  Qualifiers readQualifiers() {
 
    static_assert(sizeof(Qualifiers().getAsOpaqueValue()) <= sizeof(uint32_t),
 
                  "update this if the value size changes");
 
    uint32_t value = asImpl().readUInt32();
 
    return Qualifiers::fromOpaqueValue(value);
 
  }
 
 
 
  FunctionProtoType::ExceptionSpecInfo
 
  readExceptionSpecInfo(llvm::SmallVectorImpl<QualType> &buffer) {
 
    FunctionProtoType::ExceptionSpecInfo esi;
 
    esi.Type = ExceptionSpecificationType(asImpl().readUInt32());
 
    if (esi.Type == EST_Dynamic) {
 
      esi.Exceptions = asImpl().template readArray<QualType>(buffer);
 
    } else if (isComputedNoexcept(esi.Type)) {
 
      esi.NoexceptExpr = asImpl().readExprRef();
 
    } else if (esi.Type == EST_Uninstantiated) {
 
      esi.SourceDecl = asImpl().readFunctionDeclRef();
 
      esi.SourceTemplate = asImpl().readFunctionDeclRef();
 
    } else if (esi.Type == EST_Unevaluated) {
 
      esi.SourceDecl = asImpl().readFunctionDeclRef();
 
    }
 
    return esi;
 
  }
 
 
 
  FunctionProtoType::ExtParameterInfo readExtParameterInfo() {
 
    static_assert(sizeof(FunctionProtoType::ExtParameterInfo().getOpaqueValue())
 
                    <= sizeof(uint32_t),
 
                  "opaque value doesn't fit into uint32_t");
 
    uint32_t value = asImpl().readUInt32();
 
    return FunctionProtoType::ExtParameterInfo::getFromOpaqueValue(value);
 
  }
 
 
 
  NestedNameSpecifier *readNestedNameSpecifier() {
 
    auto &ctx = getASTContext();
 
 
 
    // We build this up iteratively.
 
    NestedNameSpecifier *cur = nullptr;
 
 
 
    uint32_t depth = asImpl().readUInt32();
 
    for (uint32_t i = 0; i != depth; ++i) {
 
      auto kind = asImpl().readNestedNameSpecifierKind();
 
      switch (kind) {
 
      case NestedNameSpecifier::Identifier:
 
        cur = NestedNameSpecifier::Create(ctx, cur,
 
                                          asImpl().readIdentifier());
 
        continue;
 
 
 
      case NestedNameSpecifier::Namespace:
 
        cur = NestedNameSpecifier::Create(ctx, cur,
 
                                          asImpl().readNamespaceDeclRef());
 
        continue;
 
 
 
      case NestedNameSpecifier::NamespaceAlias:
 
        cur = NestedNameSpecifier::Create(ctx, cur,
 
                                     asImpl().readNamespaceAliasDeclRef());
 
        continue;
 
 
 
      case NestedNameSpecifier::TypeSpec:
 
      case NestedNameSpecifier::TypeSpecWithTemplate:
 
        cur = NestedNameSpecifier::Create(ctx, cur,
 
                          kind == NestedNameSpecifier::TypeSpecWithTemplate,
 
                          asImpl().readQualType().getTypePtr());
 
        continue;
 
 
 
      case NestedNameSpecifier::Global:
 
        cur = NestedNameSpecifier::GlobalSpecifier(ctx);
 
        continue;
 
 
 
      case NestedNameSpecifier::Super:
 
        cur = NestedNameSpecifier::SuperSpecifier(ctx,
 
                                            asImpl().readCXXRecordDeclRef());
 
        continue;
 
      }
 
      llvm_unreachable("bad nested name specifier kind");
 
    }
 
 
 
    return cur;
 
  }
 
};
 
 
 
} // end namespace serialization
 
} // end namespace clang
 
 
 
#endif