AbstractBasicWriter.h 9.6 KB

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