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/DeclTemplate.h" 13 14 namespace clang { 15 namespace serialization { 16 17 template <class T> 18 inline llvm::Optional<T> makeOptionalFromNullable(const T &value) { 19 return (value.isNull() 20 ? llvm::Optional<T>() 21 : llvm::Optional<T>(value)); 22 } 23 24 template <class T> 25 inline llvm::Optional<T*> makeOptionalFromPointer(T *value) { 26 return (value ? llvm::Optional<T*>(value) : llvm::Optional<T*>()); 27 } 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 37 // BasicWriter is a class concept that requires methods like: 38 // void write##TypeName(ValueType value); 39 // where TypeName is the name of a PropertyType node from PropertiesBase.td 40 // and ValueType is the corresponding C++ type name. 41 // 42 // In addition to the concrete property types, BasicWriter is expected 43 // to implement these methods: 44 // 45 // template <class EnumType> 46 // void writeEnum(T value); 47 // 48 // Writes an enum value as the current property. EnumType will always 49 // be an enum type. Only necessary if the BasicWriter doesn't provide 50 // type-specific writers for all the enum types. 51 // 52 // template <class ValueType> 53 // void writeOptional(Optional<ValueType> value); 54 // 55 // Writes an optional value as the current property. 56 // 57 // template <class ValueType> 58 // void writeArray(ArrayRef<ValueType> value); 59 // 60 // Writes an array of values as the current property. 61 // 62 // PropertyWriter writeObject(); 63 // 64 // Writes an object as the current property; the returned property 65 // writer will be subjected to a sequence of property writes and then 66 // discarded before any other properties are written to the "outer" 67 // property writer (which need not be the same type). The sub-writer 68 // will be used as if with the following code: 69 // 70 // { 71 // auto &&widget = W.find("widget").writeObject(); 72 // widget.find("kind").writeWidgetKind(...); 73 // widget.find("declaration").writeDeclRef(...); 74 // } 75 76 // WriteDispatcher is a template which does type-based forwarding to one 77 // of the write methods of the BasicWriter passed in: 78 // 79 // template <class ValueType> 80 // struct WriteDispatcher { 81 // template <class BasicWriter> 82 // static void write(BasicWriter &W, ValueType value); 83 // }; 84 85 // BasicWriterBase provides convenience implementations of the write 86 // methods for EnumPropertyType and SubclassPropertyType types that just 87 // defer to the "underlying" implementations (for UInt32 and the base class, 88 // respectively). 89 // 90 // template <class Impl> 91 // class BasicWriterBase { 92 // protected: 93 // Impl &asImpl(); 94 // public: 95 // ... 96 // }; 97 98 // The actual classes are auto-generated; see ClangASTPropertiesEmitter.cpp. 99 #include "clang/AST/AbstractBasicWriter.inc" 100 101 /// DataStreamBasicWriter provides convenience implementations for many 102 /// BasicWriter methods based on the assumption that the 103 /// ultimate writer implementation is based on a variable-length stream 104 /// of unstructured data (like Clang's module files). It is designed 105 /// to pair with DataStreamBasicReader. 106 /// 107 /// This class can also act as a PropertyWriter, implementing find("...") 108 /// by simply forwarding to itself. 109 /// 110 /// Unimplemented methods: 111 /// writeBool 112 /// writeUInt32 113 /// writeUInt64 114 /// writeIdentifier 115 /// writeSelector 116 /// writeSourceLocation 117 /// writeQualType 118 /// writeStmtRef 119 /// writeDeclRef 120 template <class Impl> 121 class DataStreamBasicWriter : public BasicWriterBase<Impl> { 122 protected: 123 using BasicWriterBase<Impl>::asImpl; 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> 150 void writeOptional(llvm::Optional<T> value) { 151 WriteDispatcher<T>::write(asImpl(), PackOptionalValue<T>::pack(value)); 152 } 153 154 void writeAPSInt(const llvm::APSInt &value) { 155 asImpl().writeBool(value.isUnsigned()); 156 asImpl().writeAPInt(value); 157 } 158 159 void writeAPInt(const llvm::APInt &value) { 160 asImpl().writeUInt32(value.getBitWidth()); 161 const uint64_t *words = value.getRawData(); 162 for (size_t i = 0, e = value.getNumWords(); i != e; ++i) 163 asImpl().writeUInt64(words[i]); 164 } 165 166 void writeQualifiers(Qualifiers value) { 167 static_assert(sizeof(value.getAsOpaqueValue()) <= sizeof(uint32_t), 168 "update this if the value size changes"); 169 asImpl().writeUInt32(value.getAsOpaqueValue()); 170 } 171 172 void writeExceptionSpecInfo( 173 const FunctionProtoType::ExceptionSpecInfo &esi) { 174 asImpl().writeUInt32(uint32_t(esi.Type)); 175 if (esi.Type == EST_Dynamic) { 176 asImpl().writeArray(esi.Exceptions); 177 } else if (isComputedNoexcept(esi.Type)) { 178 asImpl().writeExprRef(esi.NoexceptExpr); 179 } else if (esi.Type == EST_Uninstantiated) { 180 asImpl().writeDeclRef(esi.SourceDecl); 181 asImpl().writeDeclRef(esi.SourceTemplate); 182 } else if (esi.Type == EST_Unevaluated) { 183 asImpl().writeDeclRef(esi.SourceDecl); 184 } 185 } 186 187 void writeExtParameterInfo(FunctionProtoType::ExtParameterInfo epi) { 188 static_assert(sizeof(epi.getOpaqueValue()) <= sizeof(uint32_t), 189 "opaque value doesn't fit into uint32_t"); 190 asImpl().writeUInt32(epi.getOpaqueValue()); 191 } 192 193 void writeNestedNameSpecifier(NestedNameSpecifier *NNS) { 194 // Nested name specifiers usually aren't too long. I think that 8 would 195 // typically accommodate the vast majority. 196 SmallVector<NestedNameSpecifier *, 8> nestedNames; 197 198 // Push each of the NNS's onto a stack for serialization in reverse order. 199 while (NNS) { 200 nestedNames.push_back(NNS); 201 NNS = NNS->getPrefix(); 202 } 203 204 asImpl().writeUInt32(nestedNames.size()); 205 while (!nestedNames.empty()) { 206 NNS = nestedNames.pop_back_val(); 207 NestedNameSpecifier::SpecifierKind kind = NNS->getKind(); 208 asImpl().writeNestedNameSpecifierKind(kind); 209 switch (kind) { 210 case NestedNameSpecifier::Identifier: 211 asImpl().writeIdentifier(NNS->getAsIdentifier()); 212 continue; 213 214 case NestedNameSpecifier::Namespace: 215 asImpl().writeNamespaceDeclRef(NNS->getAsNamespace()); 216 continue; 217 218 case NestedNameSpecifier::NamespaceAlias: 219 asImpl().writeNamespaceAliasDeclRef(NNS->getAsNamespaceAlias()); 220 continue; 221 222 case NestedNameSpecifier::TypeSpec: 223 case NestedNameSpecifier::TypeSpecWithTemplate: 224 asImpl().writeQualType(QualType(NNS->getAsType(), 0)); 225 continue; 226 227 case NestedNameSpecifier::Global: 228 // Don't need to write an associated value. 229 continue; 230 231 case NestedNameSpecifier::Super: 232 asImpl().writeDeclRef(NNS->getAsRecordDecl()); 233 continue; 234 } 235 llvm_unreachable("bad nested name specifier kind"); 236 } 237 } 238 }; 239 240 } // end namespace serialization 241 } // end namespace clang 242 243 #endif 244