summaryrefslogtreecommitdiff
path: root/clang/include/clang/AST/AbstractBasicWriter.h
diff options
context:
space:
mode:
Diffstat (limited to 'clang/include/clang/AST/AbstractBasicWriter.h')
-rw-r--r--clang/include/clang/AST/AbstractBasicWriter.h243
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