AbstractBasicWriter.h revision 360784
1219019Sgabor//==--- AbstractBasicWriter.h - Abstract basic value serialization --------===// 2219019Sgabor// 3219019Sgabor// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4219019Sgabor// See https://llvm.org/LICENSE.txt for license information. 5219019Sgabor// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6219019Sgabor// 7219019Sgabor//===----------------------------------------------------------------------===// 8219019Sgabor 9219019Sgabor#ifndef CLANG_AST_ABSTRACTBASICWRITER_H 10219019Sgabor#define CLANG_AST_ABSTRACTBASICWRITER_H 11219019Sgabor 12219019Sgabor#include "clang/AST/DeclTemplate.h" 13219019Sgabor 14219019Sgabornamespace clang { 15219019Sgabornamespace serialization { 16219019Sgabor 17219019Sgabortemplate <class T> 18219019Sgaborinline llvm::Optional<T> makeOptionalFromNullable(const T &value) { 19219019Sgabor return (value.isNull() 20219019Sgabor ? llvm::Optional<T>() 21219019Sgabor : llvm::Optional<T>(value)); 22219019Sgabor} 23219019Sgabor 24219019Sgabortemplate <class T> 25219019Sgaborinline llvm::Optional<T*> makeOptionalFromPointer(T *value) { 26219019Sgabor return (value ? llvm::Optional<T*>(value) : llvm::Optional<T*>()); 27219019Sgabor} 28219019Sgabor 29219019Sgabor// PropertyWriter is a class concept that requires the following method: 30219019Sgabor// BasicWriter find(llvm::StringRef propertyName); 31219019Sgabor// where BasicWriter is some class conforming to the BasicWriter concept. 32219019Sgabor// An abstract AST-node writer is created with a PropertyWriter and 33219019Sgabor// performs a sequence of calls like so: 34219019Sgabor// propertyWriter.find(propertyName).write##TypeName(value) 35219019Sgabor// to write the properties of the node it is serializing. 36219019Sgabor 37219019Sgabor// BasicWriter is a class concept that requires methods like: 38219019Sgabor// void write##TypeName(ValueType value); 39219019Sgabor// where TypeName is the name of a PropertyType node from PropertiesBase.td 40219019Sgabor// and ValueType is the corresponding C++ type name. 41219019Sgabor// 42219019Sgabor// In addition to the concrete property types, BasicWriter is expected 43219019Sgabor// to implement these methods: 44219019Sgabor// 45219019Sgabor// template <class EnumType> 46219019Sgabor// void writeEnum(T value); 47219019Sgabor// 48219019Sgabor// Writes an enum value as the current property. EnumType will always 49219019Sgabor// be an enum type. Only necessary if the BasicWriter doesn't provide 50219019Sgabor// type-specific writers for all the enum types. 51219019Sgabor// 52219019Sgabor// template <class ValueType> 53219019Sgabor// void writeOptional(Optional<ValueType> value); 54219019Sgabor// 55219019Sgabor// Writes an optional value as the current property. 56219019Sgabor// 57219019Sgabor// template <class ValueType> 58219019Sgabor// void writeArray(ArrayRef<ValueType> value); 59219019Sgabor// 60219019Sgabor// Writes an array of values as the current property. 61219019Sgabor// 62219019Sgabor// PropertyWriter writeObject(); 63219019Sgabor// 64219019Sgabor// Writes an object as the current property; the returned property 65219019Sgabor// writer will be subjected to a sequence of property writes and then 66219019Sgabor// discarded before any other properties are written to the "outer" 67219019Sgabor// property writer (which need not be the same type). The sub-writer 68219019Sgabor// will be used as if with the following code: 69219019Sgabor// 70219019Sgabor// { 71219019Sgabor// auto &&widget = W.find("widget").writeObject(); 72219019Sgabor// widget.find("kind").writeWidgetKind(...); 73219019Sgabor// widget.find("declaration").writeDeclRef(...); 74219019Sgabor// } 75219019Sgabor 76219019Sgabor// WriteDispatcher is a template which does type-based forwarding to one 77219019Sgabor// of the write methods of the BasicWriter passed in: 78219019Sgabor// 79219019Sgabor// template <class ValueType> 80219019Sgabor// struct WriteDispatcher { 81219019Sgabor// template <class BasicWriter> 82219019Sgabor// static void write(BasicWriter &W, ValueType value); 83219019Sgabor// }; 84219019Sgabor 85219019Sgabor// BasicWriterBase provides convenience implementations of the write 86219019Sgabor// methods for EnumPropertyType and SubclassPropertyType types that just 87219019Sgabor// defer to the "underlying" implementations (for UInt32 and the base class, 88219019Sgabor// respectively). 89219019Sgabor// 90219019Sgabor// template <class Impl> 91219019Sgabor// class BasicWriterBase { 92219019Sgabor// protected: 93219019Sgabor// Impl &asImpl(); 94219019Sgabor// public: 95219019Sgabor// ... 96219019Sgabor// }; 97219019Sgabor 98219019Sgabor// The actual classes are auto-generated; see ClangASTPropertiesEmitter.cpp. 99219019Sgabor#include "clang/AST/AbstractBasicWriter.inc" 100219019Sgabor 101219019Sgabor/// DataStreamBasicWriter provides convenience implementations for many 102219019Sgabor/// BasicWriter methods based on the assumption that the 103219019Sgabor/// ultimate writer implementation is based on a variable-length stream 104219019Sgabor/// of unstructured data (like Clang's module files). It is designed 105219019Sgabor/// to pair with DataStreamBasicReader. 106219019Sgabor/// 107219019Sgabor/// This class can also act as a PropertyWriter, implementing find("...") 108219019Sgabor/// by simply forwarding to itself. 109219019Sgabor/// 110219019Sgabor/// Unimplemented methods: 111219019Sgabor/// writeBool 112219019Sgabor/// writeUInt32 113219019Sgabor/// writeUInt64 114219019Sgabor/// writeIdentifier 115219019Sgabor/// writeSelector 116219019Sgabor/// writeSourceLocation 117219019Sgabor/// writeQualType 118219019Sgabor/// writeStmtRef 119219019Sgabor/// writeDeclRef 120219019Sgabortemplate <class Impl> 121219019Sgaborclass DataStreamBasicWriter : public BasicWriterBase<Impl> { 122219019Sgaborprotected: 123219019Sgabor using BasicWriterBase<Impl>::asImpl; 124219019Sgabor 125219019Sgaborpublic: 126219019Sgabor /// Implement property-find by ignoring it. We rely on properties being 127219019Sgabor /// serialized and deserialized in a reliable order instead. 128219019Sgabor Impl &find(const char *propertyName) { 129219019Sgabor return asImpl(); 130219019Sgabor } 131219019Sgabor 132219019Sgabor // Implement object writing by forwarding to this, collapsing the 133219019Sgabor // structure into a single data stream. 134219019Sgabor Impl &writeObject() { return asImpl(); } 135219019Sgabor 136219019Sgabor template <class T> 137219019Sgabor void writeEnum(T value) { 138219019Sgabor asImpl().writeUInt32(uint32_t(value)); 139219019Sgabor } 140219019Sgabor 141219019Sgabor template <class T> 142219019Sgabor void writeArray(llvm::ArrayRef<T> array) { 143219019Sgabor asImpl().writeUInt32(array.size()); 144219019Sgabor for (const T &elt : array) { 145219019Sgabor WriteDispatcher<T>::write(asImpl(), elt); 146219019Sgabor } 147219019Sgabor } 148219019Sgabor 149219019Sgabor template <class T> 150219019Sgabor void writeOptional(llvm::Optional<T> value) { 151219019Sgabor WriteDispatcher<T>::write(asImpl(), PackOptionalValue<T>::pack(value)); 152219019Sgabor } 153219019Sgabor 154219019Sgabor void writeAPSInt(const llvm::APSInt &value) { 155219019Sgabor asImpl().writeBool(value.isUnsigned()); 156219019Sgabor asImpl().writeAPInt(value); 157219019Sgabor } 158219019Sgabor 159219019Sgabor void writeAPInt(const llvm::APInt &value) { 160219019Sgabor asImpl().writeUInt32(value.getBitWidth()); 161219019Sgabor const uint64_t *words = value.getRawData(); 162219019Sgabor for (size_t i = 0, e = value.getNumWords(); i != e; ++i) 163219019Sgabor asImpl().writeUInt64(words[i]); 164219019Sgabor } 165219019Sgabor 166219019Sgabor void writeQualifiers(Qualifiers value) { 167219019Sgabor static_assert(sizeof(value.getAsOpaqueValue()) <= sizeof(uint32_t), 168219019Sgabor "update this if the value size changes"); 169219019Sgabor asImpl().writeUInt32(value.getAsOpaqueValue()); 170219019Sgabor } 171219019Sgabor 172219019Sgabor void writeExceptionSpecInfo( 173219019Sgabor const FunctionProtoType::ExceptionSpecInfo &esi) { 174219019Sgabor asImpl().writeUInt32(uint32_t(esi.Type)); 175219019Sgabor if (esi.Type == EST_Dynamic) { 176219019Sgabor asImpl().writeArray(esi.Exceptions); 177219019Sgabor } else if (isComputedNoexcept(esi.Type)) { 178219019Sgabor asImpl().writeExprRef(esi.NoexceptExpr); 179219019Sgabor } else if (esi.Type == EST_Uninstantiated) { 180219019Sgabor asImpl().writeDeclRef(esi.SourceDecl); 181219019Sgabor asImpl().writeDeclRef(esi.SourceTemplate); 182219019Sgabor } else if (esi.Type == EST_Unevaluated) { 183219019Sgabor asImpl().writeDeclRef(esi.SourceDecl); 184219019Sgabor } 185219019Sgabor } 186219019Sgabor 187219019Sgabor void writeExtParameterInfo(FunctionProtoType::ExtParameterInfo epi) { 188219019Sgabor static_assert(sizeof(epi.getOpaqueValue()) <= sizeof(uint32_t), 189219019Sgabor "opaque value doesn't fit into uint32_t"); 190219019Sgabor asImpl().writeUInt32(epi.getOpaqueValue()); 191219019Sgabor } 192219019Sgabor 193219019Sgabor void writeNestedNameSpecifier(NestedNameSpecifier *NNS) { 194219019Sgabor // Nested name specifiers usually aren't too long. I think that 8 would 195219019Sgabor // typically accommodate the vast majority. 196219019Sgabor SmallVector<NestedNameSpecifier *, 8> nestedNames; 197219019Sgabor 198219019Sgabor // Push each of the NNS's onto a stack for serialization in reverse order. 199219019Sgabor while (NNS) { 200219019Sgabor nestedNames.push_back(NNS); 201219019Sgabor NNS = NNS->getPrefix(); 202219019Sgabor } 203219019Sgabor 204219019Sgabor asImpl().writeUInt32(nestedNames.size()); 205219019Sgabor while (!nestedNames.empty()) { 206219019Sgabor NNS = nestedNames.pop_back_val(); 207219019Sgabor NestedNameSpecifier::SpecifierKind kind = NNS->getKind(); 208219019Sgabor asImpl().writeNestedNameSpecifierKind(kind); 209219019Sgabor switch (kind) { 210219019Sgabor case NestedNameSpecifier::Identifier: 211219019Sgabor asImpl().writeIdentifier(NNS->getAsIdentifier()); 212219019Sgabor continue; 213219019Sgabor 214219019Sgabor case NestedNameSpecifier::Namespace: 215219019Sgabor asImpl().writeNamespaceDeclRef(NNS->getAsNamespace()); 216219019Sgabor continue; 217219019Sgabor 218219019Sgabor case NestedNameSpecifier::NamespaceAlias: 219219019Sgabor asImpl().writeNamespaceAliasDeclRef(NNS->getAsNamespaceAlias()); 220219019Sgabor continue; 221219019Sgabor 222219019Sgabor case NestedNameSpecifier::TypeSpec: 223219019Sgabor case NestedNameSpecifier::TypeSpecWithTemplate: 224219019Sgabor asImpl().writeQualType(QualType(NNS->getAsType(), 0)); 225219019Sgabor continue; 226219019Sgabor 227219019Sgabor case NestedNameSpecifier::Global: 228219019Sgabor // Don't need to write an associated value. 229219019Sgabor continue; 230219019Sgabor 231219019Sgabor case NestedNameSpecifier::Super: 232219019Sgabor asImpl().writeDeclRef(NNS->getAsRecordDecl()); 233219019Sgabor continue; 234219019Sgabor } 235219019Sgabor llvm_unreachable("bad nested name specifier kind"); 236219019Sgabor } 237219019Sgabor } 238219019Sgabor}; 239219019Sgabor 240219019Sgabor} // end namespace serialization 241219019Sgabor} // end namespace clang 242219019Sgabor 243219019Sgabor#endif 244219019Sgabor