1//==--- AbstractBasiceReader.h - Abstract basic value deserialization -----===// 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_ABSTRACTBASICREADER_H 10#define CLANG_AST_ABSTRACTBASICREADER_H 11 12#include "clang/AST/DeclTemplate.h" 13 14namespace clang { 15namespace serialization { 16 17template <class T> 18inline T makeNullableFromOptional(const Optional<T> &value) { 19 return (value ? *value : T()); 20} 21 22template <class T> 23inline T *makePointerFromOptional(Optional<T *> value) { 24 return (value ? *value : nullptr); 25} 26 27// PropertyReader is a class concept that requires the following method: 28// BasicReader find(llvm::StringRef propertyName); 29// where BasicReader is some class conforming to the BasicReader concept. 30// An abstract AST-node reader is created with a PropertyReader and 31// performs a sequence of calls like so: 32// propertyReader.find(propertyName).read##TypeName() 33// to read the properties of the node it is deserializing. 34 35// BasicReader is a class concept that requires methods like: 36// ValueType read##TypeName(); 37// where TypeName is the name of a PropertyType node from PropertiesBase.td 38// and ValueType is the corresponding C++ type name. The read method may 39// require one or more buffer arguments. 40// 41// In addition to the concrete type names, BasicReader is expected to 42// implement these methods: 43// 44// template <class EnumType> 45// void writeEnum(T value); 46// 47// Reads an enum value from the current property. EnumType will always 48// be an enum type. Only necessary if the BasicReader doesn't provide 49// type-specific readers for all the enum types. 50// 51// template <class ValueType> 52// Optional<ValueType> writeOptional(); 53// 54// Reads an optional value from the current property. 55// 56// template <class ValueType> 57// ArrayRef<ValueType> readArray(llvm::SmallVectorImpl<ValueType> &buffer); 58// 59// Reads an array of values from the current property. 60// 61// PropertyReader readObject(); 62// 63// Reads an object from the current property; the returned property 64// reader will be subjected to a sequence of property reads and then 65// discarded before any other properties are reader from the "outer" 66// property reader (which need not be the same type). The sub-reader 67// will be used as if with the following code: 68// 69// { 70// auto &&widget = W.find("widget").readObject(); 71// auto kind = widget.find("kind").readWidgetKind(); 72// auto declaration = widget.find("declaration").readDeclRef(); 73// return Widget(kind, declaration); 74// } 75 76// ReadDispatcher does type-based forwarding to one of the read methods 77// on the BasicReader passed in: 78// 79// template <class ValueType> 80// struct ReadDispatcher { 81// template <class BasicReader, class... BufferTypes> 82// static ValueType read(BasicReader &R, BufferTypes &&...); 83// }; 84 85// BasicReaderBase provides convenience implementations of the read methods 86// for EnumPropertyType and SubclassPropertyType types that just defer to 87// the "underlying" implementations (for UInt32 and the base class, 88// respectively). 89// 90// template <class Impl> 91// class BasicReaderBase { 92// protected: 93// BasicReaderBase(ASTContext &ctx); 94// Impl &asImpl(); 95// public: 96// ASTContext &getASTContext(); 97// ... 98// }; 99 100// The actual classes are auto-generated; see ClangASTPropertiesEmitter.cpp. 101#include "clang/AST/AbstractBasicReader.inc" 102 103/// DataStreamBasicReader provides convenience implementations for many 104/// BasicReader methods based on the assumption that the 105/// ultimate reader implementation is based on a variable-length stream 106/// of unstructured data (like Clang's module files). It is designed 107/// to pair with DataStreamBasicWriter. 108/// 109/// This class can also act as a PropertyReader, implementing find("...") 110/// by simply forwarding to itself. 111/// 112/// Unimplemented methods: 113/// readBool 114/// readUInt32 115/// readUInt64 116/// readIdentifier 117/// readSelector 118/// readSourceLocation 119/// readQualType 120/// readStmtRef 121/// readDeclRef 122template <class Impl> 123class DataStreamBasicReader : public BasicReaderBase<Impl> { 124protected: 125 using BasicReaderBase<Impl>::asImpl; 126 DataStreamBasicReader(ASTContext &ctx) : BasicReaderBase<Impl>(ctx) {} 127 128public: 129 using BasicReaderBase<Impl>::getASTContext; 130 131 /// Implement property-find by ignoring it. We rely on properties being 132 /// serialized and deserialized in a reliable order instead. 133 Impl &find(const char *propertyName) { 134 return asImpl(); 135 } 136 137 template <class T> 138 T readEnum() { 139 return T(asImpl().readUInt32()); 140 } 141 142 // Implement object reading by forwarding to this, collapsing the 143 // structure into a single data stream. 144 Impl &readObject() { return asImpl(); } 145 146 template <class T> 147 llvm::ArrayRef<T> readArray(llvm::SmallVectorImpl<T> &buffer) { 148 assert(buffer.empty()); 149 150 uint32_t size = asImpl().readUInt32(); 151 buffer.reserve(size); 152 153 for (uint32_t i = 0; i != size; ++i) { 154 buffer.push_back(ReadDispatcher<T>::read(asImpl())); 155 } 156 return buffer; 157 } 158 159 template <class T, class... Args> 160 llvm::Optional<T> readOptional(Args &&...args) { 161 return UnpackOptionalValue<T>::unpack( 162 ReadDispatcher<T>::read(asImpl(), std::forward<Args>(args)...)); 163 } 164 165 llvm::APSInt readAPSInt() { 166 bool isUnsigned = asImpl().readBool(); 167 llvm::APInt value = asImpl().readAPInt(); 168 return llvm::APSInt(std::move(value), isUnsigned); 169 } 170 171 llvm::APInt readAPInt() { 172 unsigned bitWidth = asImpl().readUInt32(); 173 unsigned numWords = llvm::APInt::getNumWords(bitWidth); 174 llvm::SmallVector<uint64_t, 4> data; 175 for (uint32_t i = 0; i != numWords; ++i) 176 data.push_back(asImpl().readUInt64()); 177 return llvm::APInt(bitWidth, numWords, &data[0]); 178 } 179 180 Qualifiers readQualifiers() { 181 static_assert(sizeof(Qualifiers().getAsOpaqueValue()) <= sizeof(uint32_t), 182 "update this if the value size changes"); 183 uint32_t value = asImpl().readUInt32(); 184 return Qualifiers::fromOpaqueValue(value); 185 } 186 187 FunctionProtoType::ExceptionSpecInfo 188 readExceptionSpecInfo(llvm::SmallVectorImpl<QualType> &buffer) { 189 FunctionProtoType::ExceptionSpecInfo esi; 190 esi.Type = ExceptionSpecificationType(asImpl().readUInt32()); 191 if (esi.Type == EST_Dynamic) { 192 esi.Exceptions = asImpl().template readArray<QualType>(buffer); 193 } else if (isComputedNoexcept(esi.Type)) { 194 esi.NoexceptExpr = asImpl().readExprRef(); 195 } else if (esi.Type == EST_Uninstantiated) { 196 esi.SourceDecl = asImpl().readFunctionDeclRef(); 197 esi.SourceTemplate = asImpl().readFunctionDeclRef(); 198 } else if (esi.Type == EST_Unevaluated) { 199 esi.SourceDecl = asImpl().readFunctionDeclRef(); 200 } 201 return esi; 202 } 203 204 FunctionProtoType::ExtParameterInfo readExtParameterInfo() { 205 static_assert(sizeof(FunctionProtoType::ExtParameterInfo().getOpaqueValue()) 206 <= sizeof(uint32_t), 207 "opaque value doesn't fit into uint32_t"); 208 uint32_t value = asImpl().readUInt32(); 209 return FunctionProtoType::ExtParameterInfo::getFromOpaqueValue(value); 210 } 211 212 NestedNameSpecifier *readNestedNameSpecifier() { 213 auto &ctx = getASTContext(); 214 215 // We build this up iteratively. 216 NestedNameSpecifier *cur = nullptr; 217 218 uint32_t depth = asImpl().readUInt32(); 219 for (uint32_t i = 0; i != depth; ++i) { 220 auto kind = asImpl().readNestedNameSpecifierKind(); 221 switch (kind) { 222 case NestedNameSpecifier::Identifier: 223 cur = NestedNameSpecifier::Create(ctx, cur, 224 asImpl().readIdentifier()); 225 continue; 226 227 case NestedNameSpecifier::Namespace: 228 cur = NestedNameSpecifier::Create(ctx, cur, 229 asImpl().readNamespaceDeclRef()); 230 continue; 231 232 case NestedNameSpecifier::NamespaceAlias: 233 cur = NestedNameSpecifier::Create(ctx, cur, 234 asImpl().readNamespaceAliasDeclRef()); 235 continue; 236 237 case NestedNameSpecifier::TypeSpec: 238 case NestedNameSpecifier::TypeSpecWithTemplate: 239 cur = NestedNameSpecifier::Create(ctx, cur, 240 kind == NestedNameSpecifier::TypeSpecWithTemplate, 241 asImpl().readQualType().getTypePtr()); 242 continue; 243 244 case NestedNameSpecifier::Global: 245 cur = NestedNameSpecifier::GlobalSpecifier(ctx); 246 continue; 247 248 case NestedNameSpecifier::Super: 249 cur = NestedNameSpecifier::SuperSpecifier(ctx, 250 asImpl().readCXXRecordDeclRef()); 251 continue; 252 } 253 llvm_unreachable("bad nested name specifier kind"); 254 } 255 256 return cur; 257 } 258}; 259 260} // end namespace serialization 261} // end namespace clang 262 263#endif 264