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