123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289 |
- #pragma once
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wunused-parameter"
- #endif
- //==--- AbstractBasicWriter.h - Abstract basic value serialization --------===//
- //
- // 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_ABSTRACTBASICWRITER_H
- #define LLVM_CLANG_AST_ABSTRACTBASICWRITER_H
- #include "clang/AST/ASTContext.h"
- #include "clang/AST/DeclTemplate.h"
- namespace clang {
- namespace serialization {
- template <class T>
- inline llvm::Optional<T> makeOptionalFromNullable(const T &value) {
- return (value.isNull()
- ? llvm::Optional<T>()
- : llvm::Optional<T>(value));
- }
- template <class T>
- inline llvm::Optional<T*> makeOptionalFromPointer(T *value) {
- return (value ? llvm::Optional<T*>(value) : llvm::Optional<T*>());
- }
- // PropertyWriter is a class concept that requires the following method:
- // BasicWriter find(llvm::StringRef propertyName);
- // where BasicWriter is some class conforming to the BasicWriter concept.
- // An abstract AST-node writer is created with a PropertyWriter and
- // performs a sequence of calls like so:
- // propertyWriter.find(propertyName).write##TypeName(value)
- // to write the properties of the node it is serializing.
- // BasicWriter is a class concept that requires methods like:
- // void write##TypeName(ValueType value);
- // where TypeName is the name of a PropertyType node from PropertiesBase.td
- // and ValueType is the corresponding C++ type name.
- //
- // In addition to the concrete property types, BasicWriter is expected
- // to implement these methods:
- //
- // template <class EnumType>
- // void writeEnum(T value);
- //
- // Writes an enum value as the current property. EnumType will always
- // be an enum type. Only necessary if the BasicWriter doesn't provide
- // type-specific writers for all the enum types.
- //
- // template <class ValueType>
- // void writeOptional(Optional<ValueType> value);
- //
- // Writes an optional value as the current property.
- //
- // template <class ValueType>
- // void writeArray(ArrayRef<ValueType> value);
- //
- // Writes an array of values as the current property.
- //
- // PropertyWriter writeObject();
- //
- // Writes an object as the current property; the returned property
- // writer will be subjected to a sequence of property writes and then
- // discarded before any other properties are written to the "outer"
- // property writer (which need not be the same type). The sub-writer
- // will be used as if with the following code:
- //
- // {
- // auto &&widget = W.find("widget").writeObject();
- // widget.find("kind").writeWidgetKind(...);
- // widget.find("declaration").writeDeclRef(...);
- // }
- // WriteDispatcher is a template which does type-based forwarding to one
- // of the write methods of the BasicWriter passed in:
- //
- // template <class ValueType>
- // struct WriteDispatcher {
- // template <class BasicWriter>
- // static void write(BasicWriter &W, ValueType value);
- // };
- // BasicWriterBase provides convenience implementations of the write
- // methods for EnumPropertyType and SubclassPropertyType types that just
- // defer to the "underlying" implementations (for UInt32 and the base class,
- // respectively).
- //
- // template <class Impl>
- // class BasicWriterBase {
- // protected:
- // Impl &asImpl();
- // public:
- // ...
- // };
- // The actual classes are auto-generated; see ClangASTPropertiesEmitter.cpp.
- #include "clang/AST/AbstractBasicWriter.inc"
- /// DataStreamBasicWriter provides convenience implementations for many
- /// BasicWriter methods based on the assumption that the
- /// ultimate writer implementation is based on a variable-length stream
- /// of unstructured data (like Clang's module files). It is designed
- /// to pair with DataStreamBasicReader.
- ///
- /// This class can also act as a PropertyWriter, implementing find("...")
- /// by simply forwarding to itself.
- ///
- /// Unimplemented methods:
- /// writeBool
- /// writeUInt32
- /// writeUInt64
- /// writeIdentifier
- /// writeSelector
- /// writeSourceLocation
- /// writeQualType
- /// writeStmtRef
- /// writeDeclRef
- template <class Impl>
- class DataStreamBasicWriter : public BasicWriterBase<Impl> {
- protected:
- using BasicWriterBase<Impl>::asImpl;
- DataStreamBasicWriter(ASTContext &ctx) : BasicWriterBase<Impl>(ctx) {}
- public:
- /// 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();
- }
- // Implement object writing by forwarding to this, collapsing the
- // structure into a single data stream.
- Impl &writeObject() { return asImpl(); }
- template <class T>
- void writeEnum(T value) {
- asImpl().writeUInt32(uint32_t(value));
- }
- template <class T>
- void writeArray(llvm::ArrayRef<T> array) {
- asImpl().writeUInt32(array.size());
- for (const T &elt : array) {
- WriteDispatcher<T>::write(asImpl(), elt);
- }
- }
- template <class T>
- void writeOptional(llvm::Optional<T> value) {
- WriteDispatcher<T>::write(asImpl(), PackOptionalValue<T>::pack(value));
- }
- void writeAPSInt(const llvm::APSInt &value) {
- asImpl().writeBool(value.isUnsigned());
- asImpl().writeAPInt(value);
- }
- void writeAPInt(const llvm::APInt &value) {
- asImpl().writeUInt32(value.getBitWidth());
- const uint64_t *words = value.getRawData();
- for (size_t i = 0, e = value.getNumWords(); i != e; ++i)
- asImpl().writeUInt64(words[i]);
- }
- void writeFixedPointSemantics(const llvm::FixedPointSemantics &sema) {
- asImpl().writeUInt32(sema.getWidth());
- asImpl().writeUInt32(sema.getScale());
- asImpl().writeUInt32(sema.isSigned() | sema.isSaturated() << 1 |
- sema.hasUnsignedPadding() << 2);
- }
- void writeLValuePathSerializationHelper(
- APValue::LValuePathSerializationHelper lvaluePath) {
- ArrayRef<APValue::LValuePathEntry> path = lvaluePath.Path;
- QualType elemTy = lvaluePath.getType();
- asImpl().writeQualType(elemTy);
- asImpl().writeUInt32(path.size());
- auto &ctx = ((BasicWriterBase<Impl> *)this)->getASTContext();
- for (auto elem : path) {
- if (elemTy->getAs<RecordType>()) {
- asImpl().writeUInt32(elem.getAsBaseOrMember().getInt());
- const Decl *baseOrMember = elem.getAsBaseOrMember().getPointer();
- if (const auto *recordDecl = dyn_cast<CXXRecordDecl>(baseOrMember)) {
- asImpl().writeDeclRef(recordDecl);
- elemTy = ctx.getRecordType(recordDecl);
- } else {
- const auto *valueDecl = cast<ValueDecl>(baseOrMember);
- asImpl().writeDeclRef(valueDecl);
- elemTy = valueDecl->getType();
- }
- } else {
- asImpl().writeUInt32(elem.getAsArrayIndex());
- elemTy = ctx.getAsArrayType(elemTy)->getElementType();
- }
- }
- }
- void writeQualifiers(Qualifiers value) {
- static_assert(sizeof(value.getAsOpaqueValue()) <= sizeof(uint32_t),
- "update this if the value size changes");
- asImpl().writeUInt32(value.getAsOpaqueValue());
- }
- void writeExceptionSpecInfo(
- const FunctionProtoType::ExceptionSpecInfo &esi) {
- asImpl().writeUInt32(uint32_t(esi.Type));
- if (esi.Type == EST_Dynamic) {
- asImpl().writeArray(esi.Exceptions);
- } else if (isComputedNoexcept(esi.Type)) {
- asImpl().writeExprRef(esi.NoexceptExpr);
- } else if (esi.Type == EST_Uninstantiated) {
- asImpl().writeDeclRef(esi.SourceDecl);
- asImpl().writeDeclRef(esi.SourceTemplate);
- } else if (esi.Type == EST_Unevaluated) {
- asImpl().writeDeclRef(esi.SourceDecl);
- }
- }
- void writeExtParameterInfo(FunctionProtoType::ExtParameterInfo epi) {
- static_assert(sizeof(epi.getOpaqueValue()) <= sizeof(uint32_t),
- "opaque value doesn't fit into uint32_t");
- asImpl().writeUInt32(epi.getOpaqueValue());
- }
- void writeNestedNameSpecifier(NestedNameSpecifier *NNS) {
- // Nested name specifiers usually aren't too long. I think that 8 would
- // typically accommodate the vast majority.
- SmallVector<NestedNameSpecifier *, 8> nestedNames;
- // Push each of the NNS's onto a stack for serialization in reverse order.
- while (NNS) {
- nestedNames.push_back(NNS);
- NNS = NNS->getPrefix();
- }
- asImpl().writeUInt32(nestedNames.size());
- while (!nestedNames.empty()) {
- NNS = nestedNames.pop_back_val();
- NestedNameSpecifier::SpecifierKind kind = NNS->getKind();
- asImpl().writeNestedNameSpecifierKind(kind);
- switch (kind) {
- case NestedNameSpecifier::Identifier:
- asImpl().writeIdentifier(NNS->getAsIdentifier());
- continue;
- case NestedNameSpecifier::Namespace:
- asImpl().writeNamespaceDeclRef(NNS->getAsNamespace());
- continue;
- case NestedNameSpecifier::NamespaceAlias:
- asImpl().writeNamespaceAliasDeclRef(NNS->getAsNamespaceAlias());
- continue;
- case NestedNameSpecifier::TypeSpec:
- case NestedNameSpecifier::TypeSpecWithTemplate:
- asImpl().writeQualType(QualType(NNS->getAsType(), 0));
- continue;
- case NestedNameSpecifier::Global:
- // Don't need to write an associated value.
- continue;
- case NestedNameSpecifier::Super:
- asImpl().writeDeclRef(NNS->getAsRecordDecl());
- continue;
- }
- llvm_unreachable("bad nested name specifier kind");
- }
- }
- };
- } // end namespace serialization
- } // end namespace clang
- #endif
- #ifdef __GNUC__
- #pragma GCC diagnostic pop
- #endif
|