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