Home | History | Annotate | Line # | Download | only in AST
      1 //==--- AbstractBasicWriter.h - Abstract basic value serialization --------===//
      2 //
      3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4 // See https://llvm.org/LICENSE.txt for license information.
      5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 
      9 #ifndef CLANG_AST_ABSTRACTBASICWRITER_H
     10 #define CLANG_AST_ABSTRACTBASICWRITER_H
     11 
     12 #include "clang/AST/ASTContext.h"
     13 #include "clang/AST/DeclTemplate.h"
     14 
     15 namespace clang {
     16 namespace serialization {
     17 
     18 template <class T>
     19 inline llvm::Optional<T> makeOptionalFromNullable(const T &value) {
     20   return (value.isNull()
     21             ? llvm::Optional<T>()
     22             : llvm::Optional<T>(value));
     23 }
     24 
     25 template <class T>
     26 inline llvm::Optional<T*> makeOptionalFromPointer(T *value) {
     27   return (value ? llvm::Optional<T*>(value) : llvm::Optional<T*>());
     28 }
     29 
     30 // PropertyWriter is a class concept that requires the following method:
     31 //   BasicWriter find(llvm::StringRef propertyName);
     32 // where BasicWriter is some class conforming to the BasicWriter concept.
     33 // An abstract AST-node writer is created with a PropertyWriter and
     34 // performs a sequence of calls like so:
     35 //   propertyWriter.find(propertyName).write##TypeName(value)
     36 // to write the properties of the node it is serializing.
     37 
     38 // BasicWriter is a class concept that requires methods like:
     39 //   void write##TypeName(ValueType value);
     40 // where TypeName is the name of a PropertyType node from PropertiesBase.td
     41 // and ValueType is the corresponding C++ type name.
     42 //
     43 // In addition to the concrete property types, BasicWriter is expected
     44 // to implement these methods:
     45 //
     46 //   template <class EnumType>
     47 //   void writeEnum(T value);
     48 //
     49 //     Writes an enum value as the current property.  EnumType will always
     50 //     be an enum type.  Only necessary if the BasicWriter doesn't provide
     51 //     type-specific writers for all the enum types.
     52 //
     53 //   template <class ValueType>
     54 //   void writeOptional(Optional<ValueType> value);
     55 //
     56 //     Writes an optional value as the current property.
     57 //
     58 //   template <class ValueType>
     59 //   void writeArray(ArrayRef<ValueType> value);
     60 //
     61 //     Writes an array of values as the current property.
     62 //
     63 //   PropertyWriter writeObject();
     64 //
     65 //     Writes an object as the current property; the returned property
     66 //     writer will be subjected to a sequence of property writes and then
     67 //     discarded before any other properties are written to the "outer"
     68 //     property writer (which need not be the same type).  The sub-writer
     69 //     will be used as if with the following code:
     70 //
     71 //       {
     72 //         auto &&widget = W.find("widget").writeObject();
     73 //         widget.find("kind").writeWidgetKind(...);
     74 //         widget.find("declaration").writeDeclRef(...);
     75 //       }
     76 
     77 // WriteDispatcher is a template which does type-based forwarding to one
     78 // of the write methods of the BasicWriter passed in:
     79 //
     80 // template <class ValueType>
     81 // struct WriteDispatcher {
     82 //   template <class BasicWriter>
     83 //   static void write(BasicWriter &W, ValueType value);
     84 // };
     85 
     86 // BasicWriterBase provides convenience implementations of the write
     87 // methods for EnumPropertyType and SubclassPropertyType types that just
     88 // defer to the "underlying" implementations (for UInt32 and the base class,
     89 // respectively).
     90 //
     91 // template <class Impl>
     92 // class BasicWriterBase {
     93 // protected:
     94 //   Impl &asImpl();
     95 // public:
     96 //   ...
     97 // };
     98 
     99 // The actual classes are auto-generated; see ClangASTPropertiesEmitter.cpp.
    100 #include "clang/AST/AbstractBasicWriter.inc"
    101 
    102 /// DataStreamBasicWriter provides convenience implementations for many
    103 /// BasicWriter methods based on the assumption that the
    104 /// ultimate writer implementation is based on a variable-length stream
    105 /// of unstructured data (like Clang's module files).  It is designed
    106 /// to pair with DataStreamBasicReader.
    107 ///
    108 /// This class can also act as a PropertyWriter, implementing find("...")
    109 /// by simply forwarding to itself.
    110 ///
    111 /// Unimplemented methods:
    112 ///   writeBool
    113 ///   writeUInt32
    114 ///   writeUInt64
    115 ///   writeIdentifier
    116 ///   writeSelector
    117 ///   writeSourceLocation
    118 ///   writeQualType
    119 ///   writeStmtRef
    120 ///   writeDeclRef
    121 template <class Impl>
    122 class DataStreamBasicWriter : public BasicWriterBase<Impl> {
    123 protected:
    124   using BasicWriterBase<Impl>::asImpl;
    125   DataStreamBasicWriter(ASTContext &ctx) : BasicWriterBase<Impl>(ctx) {}
    126 
    127 public:
    128   /// Implement property-find by ignoring it.  We rely on properties being
    129   /// serialized and deserialized in a reliable order instead.
    130   Impl &find(const char *propertyName) {
    131     return asImpl();
    132   }
    133 
    134   // Implement object writing by forwarding to this, collapsing the
    135   // structure into a single data stream.
    136   Impl &writeObject() { return asImpl(); }
    137 
    138   template <class T>
    139   void writeEnum(T value) {
    140     asImpl().writeUInt32(uint32_t(value));
    141   }
    142 
    143   template <class T>
    144   void writeArray(llvm::ArrayRef<T> array) {
    145     asImpl().writeUInt32(array.size());
    146     for (const T &elt : array) {
    147       WriteDispatcher<T>::write(asImpl(), elt);
    148     }
    149   }
    150 
    151   template <class T>
    152   void writeOptional(llvm::Optional<T> value) {
    153     WriteDispatcher<T>::write(asImpl(), PackOptionalValue<T>::pack(value));
    154   }
    155 
    156   void writeAPSInt(const llvm::APSInt &value) {
    157     asImpl().writeBool(value.isUnsigned());
    158     asImpl().writeAPInt(value);
    159   }
    160 
    161   void writeAPInt(const llvm::APInt &value) {
    162     asImpl().writeUInt32(value.getBitWidth());
    163     const uint64_t *words = value.getRawData();
    164     for (size_t i = 0, e = value.getNumWords(); i != e; ++i)
    165       asImpl().writeUInt64(words[i]);
    166   }
    167 
    168   void writeFixedPointSemantics(const llvm::FixedPointSemantics &sema) {
    169     asImpl().writeUInt32(sema.getWidth());
    170     asImpl().writeUInt32(sema.getScale());
    171     asImpl().writeUInt32(sema.isSigned() | sema.isSaturated() << 1 |
    172                          sema.hasUnsignedPadding() << 2);
    173   }
    174 
    175   void writeLValuePathSerializationHelper(
    176       APValue::LValuePathSerializationHelper lvaluePath) {
    177     ArrayRef<APValue::LValuePathEntry> path = lvaluePath.Path;
    178     QualType elemTy = lvaluePath.getType();
    179     asImpl().writeQualType(elemTy);
    180     asImpl().writeUInt32(path.size());
    181     auto &ctx = ((BasicWriterBase<Impl> *)this)->getASTContext();
    182     for (auto elem : path) {
    183       if (elemTy->getAs<RecordType>()) {
    184         asImpl().writeUInt32(elem.getAsBaseOrMember().getInt());
    185         const Decl *baseOrMember = elem.getAsBaseOrMember().getPointer();
    186         if (const auto *recordDecl = dyn_cast<CXXRecordDecl>(baseOrMember)) {
    187           asImpl().writeDeclRef(recordDecl);
    188           elemTy = ctx.getRecordType(recordDecl);
    189         } else {
    190           const auto *valueDecl = cast<ValueDecl>(baseOrMember);
    191           asImpl().writeDeclRef(valueDecl);
    192           elemTy = valueDecl->getType();
    193         }
    194       } else {
    195         asImpl().writeUInt32(elem.getAsArrayIndex());
    196         elemTy = ctx.getAsArrayType(elemTy)->getElementType();
    197       }
    198     }
    199   }
    200 
    201   void writeQualifiers(Qualifiers value) {
    202     static_assert(sizeof(value.getAsOpaqueValue()) <= sizeof(uint32_t),
    203                   "update this if the value size changes");
    204     asImpl().writeUInt32(value.getAsOpaqueValue());
    205   }
    206 
    207   void writeExceptionSpecInfo(
    208                         const FunctionProtoType::ExceptionSpecInfo &esi) {
    209     asImpl().writeUInt32(uint32_t(esi.Type));
    210     if (esi.Type == EST_Dynamic) {
    211       asImpl().writeArray(esi.Exceptions);
    212     } else if (isComputedNoexcept(esi.Type)) {
    213       asImpl().writeExprRef(esi.NoexceptExpr);
    214     } else if (esi.Type == EST_Uninstantiated) {
    215       asImpl().writeDeclRef(esi.SourceDecl);
    216       asImpl().writeDeclRef(esi.SourceTemplate);
    217     } else if (esi.Type == EST_Unevaluated) {
    218       asImpl().writeDeclRef(esi.SourceDecl);
    219     }
    220   }
    221 
    222   void writeExtParameterInfo(FunctionProtoType::ExtParameterInfo epi) {
    223     static_assert(sizeof(epi.getOpaqueValue()) <= sizeof(uint32_t),
    224                   "opaque value doesn't fit into uint32_t");
    225     asImpl().writeUInt32(epi.getOpaqueValue());
    226   }
    227 
    228   void writeNestedNameSpecifier(NestedNameSpecifier *NNS) {
    229     // Nested name specifiers usually aren't too long. I think that 8 would
    230     // typically accommodate the vast majority.
    231     SmallVector<NestedNameSpecifier *, 8> nestedNames;
    232 
    233     // Push each of the NNS's onto a stack for serialization in reverse order.
    234     while (NNS) {
    235       nestedNames.push_back(NNS);
    236       NNS = NNS->getPrefix();
    237     }
    238 
    239     asImpl().writeUInt32(nestedNames.size());
    240     while (!nestedNames.empty()) {
    241       NNS = nestedNames.pop_back_val();
    242       NestedNameSpecifier::SpecifierKind kind = NNS->getKind();
    243       asImpl().writeNestedNameSpecifierKind(kind);
    244       switch (kind) {
    245       case NestedNameSpecifier::Identifier:
    246         asImpl().writeIdentifier(NNS->getAsIdentifier());
    247         continue;
    248 
    249       case NestedNameSpecifier::Namespace:
    250         asImpl().writeNamespaceDeclRef(NNS->getAsNamespace());
    251         continue;
    252 
    253       case NestedNameSpecifier::NamespaceAlias:
    254         asImpl().writeNamespaceAliasDeclRef(NNS->getAsNamespaceAlias());
    255         continue;
    256 
    257       case NestedNameSpecifier::TypeSpec:
    258       case NestedNameSpecifier::TypeSpecWithTemplate:
    259         asImpl().writeQualType(QualType(NNS->getAsType(), 0));
    260         continue;
    261 
    262       case NestedNameSpecifier::Global:
    263         // Don't need to write an associated value.
    264         continue;
    265 
    266       case NestedNameSpecifier::Super:
    267         asImpl().writeDeclRef(NNS->getAsRecordDecl());
    268         continue;
    269       }
    270       llvm_unreachable("bad nested name specifier kind");
    271     }
    272   }
    273 };
    274 
    275 } // end namespace serialization
    276 } // end namespace clang
    277 
    278 #endif
    279