diff options
Diffstat (limited to 'clang/include/clang/AST/AbstractBasicWriter.h')
-rw-r--r-- | clang/include/clang/AST/AbstractBasicWriter.h | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/clang/include/clang/AST/AbstractBasicWriter.h b/clang/include/clang/AST/AbstractBasicWriter.h new file mode 100644 index 000000000000..0a6730c86bbf --- /dev/null +++ b/clang/include/clang/AST/AbstractBasicWriter.h @@ -0,0 +1,243 @@ +//==--- AbstractBasicWriter.h - Abstract basic value serialization --------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_AST_ABSTRACTBASICWRITER_H +#define CLANG_AST_ABSTRACTBASICWRITER_H + +#include "clang/AST/DeclTemplate.h" + +namespace clang { +namespace serialization { + +template <class T> +inline llvm::Optional<T> makeOptionalFromNullable(const T &value) { + return (value.isNull() + ? llvm::Optional<T>() + : llvm::Optional<T>(value)); +} + +template <class T> +inline llvm::Optional<T*> makeOptionalFromPointer(T *value) { + return (value ? llvm::Optional<T*>(value) : llvm::Optional<T*>()); +} + +// PropertyWriter is a class concept that requires the following method: +// BasicWriter find(llvm::StringRef propertyName); +// where BasicWriter is some class conforming to the BasicWriter concept. +// An abstract AST-node writer is created with a PropertyWriter and +// performs a sequence of calls like so: +// propertyWriter.find(propertyName).write##TypeName(value) +// to write the properties of the node it is serializing. + +// BasicWriter is a class concept that requires methods like: +// void write##TypeName(ValueType value); +// where TypeName is the name of a PropertyType node from PropertiesBase.td +// and ValueType is the corresponding C++ type name. +// +// In addition to the concrete property types, BasicWriter is expected +// to implement these methods: +// +// template <class EnumType> +// void writeEnum(T value); +// +// Writes an enum value as the current property. EnumType will always +// be an enum type. Only necessary if the BasicWriter doesn't provide +// type-specific writers for all the enum types. +// +// template <class ValueType> +// void writeOptional(Optional<ValueType> value); +// +// Writes an optional value as the current property. +// +// template <class ValueType> +// void writeArray(ArrayRef<ValueType> value); +// +// Writes an array of values as the current property. +// +// PropertyWriter writeObject(); +// +// Writes an object as the current property; the returned property +// writer will be subjected to a sequence of property writes and then +// discarded before any other properties are written to the "outer" +// property writer (which need not be the same type). The sub-writer +// will be used as if with the following code: +// +// { +// auto &&widget = W.find("widget").writeObject(); +// widget.find("kind").writeWidgetKind(...); +// widget.find("declaration").writeDeclRef(...); +// } + +// WriteDispatcher is a template which does type-based forwarding to one +// of the write methods of the BasicWriter passed in: +// +// template <class ValueType> +// struct WriteDispatcher { +// template <class BasicWriter> +// static void write(BasicWriter &W, ValueType value); +// }; + +// BasicWriterBase provides convenience implementations of the write +// methods for EnumPropertyType and SubclassPropertyType types that just +// defer to the "underlying" implementations (for UInt32 and the base class, +// respectively). +// +// template <class Impl> +// class BasicWriterBase { +// protected: +// Impl &asImpl(); +// public: +// ... +// }; + +// The actual classes are auto-generated; see ClangASTPropertiesEmitter.cpp. +#include "clang/AST/AbstractBasicWriter.inc" + +/// DataStreamBasicWriter provides convenience implementations for many +/// BasicWriter methods based on the assumption that the +/// ultimate writer implementation is based on a variable-length stream +/// of unstructured data (like Clang's module files). It is designed +/// to pair with DataStreamBasicReader. +/// +/// This class can also act as a PropertyWriter, implementing find("...") +/// by simply forwarding to itself. +/// +/// Unimplemented methods: +/// writeBool +/// writeUInt32 +/// writeUInt64 +/// writeIdentifier +/// writeSelector +/// writeSourceLocation +/// writeQualType +/// writeStmtRef +/// writeDeclRef +template <class Impl> +class DataStreamBasicWriter : public BasicWriterBase<Impl> { +protected: + using BasicWriterBase<Impl>::asImpl; + +public: + /// Implement property-find by ignoring it. We rely on properties being + /// serialized and deserialized in a reliable order instead. + Impl &find(const char *propertyName) { + return asImpl(); + } + + // Implement object writing by forwarding to this, collapsing the + // structure into a single data stream. + Impl &writeObject() { return asImpl(); } + + template <class T> + void writeEnum(T value) { + asImpl().writeUInt32(uint32_t(value)); + } + + template <class T> + void writeArray(llvm::ArrayRef<T> array) { + asImpl().writeUInt32(array.size()); + for (const T &elt : array) { + WriteDispatcher<T>::write(asImpl(), elt); + } + } + + template <class T> + void writeOptional(llvm::Optional<T> value) { + WriteDispatcher<T>::write(asImpl(), PackOptionalValue<T>::pack(value)); + } + + void writeAPSInt(const llvm::APSInt &value) { + asImpl().writeBool(value.isUnsigned()); + asImpl().writeAPInt(value); + } + + void writeAPInt(const llvm::APInt &value) { + asImpl().writeUInt32(value.getBitWidth()); + const uint64_t *words = value.getRawData(); + for (size_t i = 0, e = value.getNumWords(); i != e; ++i) + asImpl().writeUInt64(words[i]); + } + + void writeQualifiers(Qualifiers value) { + static_assert(sizeof(value.getAsOpaqueValue()) <= sizeof(uint32_t), + "update this if the value size changes"); + asImpl().writeUInt32(value.getAsOpaqueValue()); + } + + void writeExceptionSpecInfo( + const FunctionProtoType::ExceptionSpecInfo &esi) { + asImpl().writeUInt32(uint32_t(esi.Type)); + if (esi.Type == EST_Dynamic) { + asImpl().writeArray(esi.Exceptions); + } else if (isComputedNoexcept(esi.Type)) { + asImpl().writeExprRef(esi.NoexceptExpr); + } else if (esi.Type == EST_Uninstantiated) { + asImpl().writeDeclRef(esi.SourceDecl); + asImpl().writeDeclRef(esi.SourceTemplate); + } else if (esi.Type == EST_Unevaluated) { + asImpl().writeDeclRef(esi.SourceDecl); + } + } + + void writeExtParameterInfo(FunctionProtoType::ExtParameterInfo epi) { + static_assert(sizeof(epi.getOpaqueValue()) <= sizeof(uint32_t), + "opaque value doesn't fit into uint32_t"); + asImpl().writeUInt32(epi.getOpaqueValue()); + } + + void writeNestedNameSpecifier(NestedNameSpecifier *NNS) { + // Nested name specifiers usually aren't too long. I think that 8 would + // typically accommodate the vast majority. + SmallVector<NestedNameSpecifier *, 8> nestedNames; + + // Push each of the NNS's onto a stack for serialization in reverse order. + while (NNS) { + nestedNames.push_back(NNS); + NNS = NNS->getPrefix(); + } + + asImpl().writeUInt32(nestedNames.size()); + while (!nestedNames.empty()) { + NNS = nestedNames.pop_back_val(); + NestedNameSpecifier::SpecifierKind kind = NNS->getKind(); + asImpl().writeNestedNameSpecifierKind(kind); + switch (kind) { + case NestedNameSpecifier::Identifier: + asImpl().writeIdentifier(NNS->getAsIdentifier()); + continue; + + case NestedNameSpecifier::Namespace: + asImpl().writeNamespaceDeclRef(NNS->getAsNamespace()); + continue; + + case NestedNameSpecifier::NamespaceAlias: + asImpl().writeNamespaceAliasDeclRef(NNS->getAsNamespaceAlias()); + continue; + + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: + asImpl().writeQualType(QualType(NNS->getAsType(), 0)); + continue; + + case NestedNameSpecifier::Global: + // Don't need to write an associated value. + continue; + + case NestedNameSpecifier::Super: + asImpl().writeDeclRef(NNS->getAsRecordDecl()); + continue; + } + llvm_unreachable("bad nested name specifier kind"); + } + } +}; + +} // end namespace serialization +} // end namespace clang + +#endif |