Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:36:27

0001 //==--- AbstractBasicWriter.h - Abstract basic value serialization --------===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 
0009 #ifndef LLVM_CLANG_AST_ABSTRACTBASICWRITER_H
0010 #define LLVM_CLANG_AST_ABSTRACTBASICWRITER_H
0011 
0012 #include "clang/AST/ASTContext.h"
0013 #include "clang/AST/DeclTemplate.h"
0014 #include <optional>
0015 
0016 namespace clang {
0017 namespace serialization {
0018 
0019 template <class T>
0020 inline std::optional<T> makeOptionalFromNullable(const T &value) {
0021   return (value.isNull() ? std::optional<T>() : std::optional<T>(value));
0022 }
0023 
0024 template <class T> inline std::optional<T *> makeOptionalFromPointer(T *value) {
0025   return (value ? std::optional<T *>(value) : std::optional<T *>());
0026 }
0027 
0028 // PropertyWriter is a class concept that requires the following method:
0029 //   BasicWriter find(llvm::StringRef propertyName);
0030 // where BasicWriter is some class conforming to the BasicWriter concept.
0031 // An abstract AST-node writer is created with a PropertyWriter and
0032 // performs a sequence of calls like so:
0033 //   propertyWriter.find(propertyName).write##TypeName(value)
0034 // to write the properties of the node it is serializing.
0035 
0036 // BasicWriter is a class concept that requires methods like:
0037 //   void write##TypeName(ValueType value);
0038 // where TypeName is the name of a PropertyType node from PropertiesBase.td
0039 // and ValueType is the corresponding C++ type name.
0040 //
0041 // In addition to the concrete property types, BasicWriter is expected
0042 // to implement these methods:
0043 //
0044 //   template <class EnumType>
0045 //   void writeEnum(T value);
0046 //
0047 //     Writes an enum value as the current property.  EnumType will always
0048 //     be an enum type.  Only necessary if the BasicWriter doesn't provide
0049 //     type-specific writers for all the enum types.
0050 //
0051 //   template <class ValueType>
0052 //   void writeOptional(std::optional<ValueType> value);
0053 //
0054 //     Writes an optional value as the current property.
0055 //
0056 //   template <class ValueType>
0057 //   void writeArray(ArrayRef<ValueType> value);
0058 //
0059 //     Writes an array of values as the current property.
0060 //
0061 //   PropertyWriter writeObject();
0062 //
0063 //     Writes an object as the current property; the returned property
0064 //     writer will be subjected to a sequence of property writes and then
0065 //     discarded before any other properties are written to the "outer"
0066 //     property writer (which need not be the same type).  The sub-writer
0067 //     will be used as if with the following code:
0068 //
0069 //       {
0070 //         auto &&widget = W.find("widget").writeObject();
0071 //         widget.find("kind").writeWidgetKind(...);
0072 //         widget.find("declaration").writeDeclRef(...);
0073 //       }
0074 
0075 // WriteDispatcher is a template which does type-based forwarding to one
0076 // of the write methods of the BasicWriter passed in:
0077 //
0078 // template <class ValueType>
0079 // struct WriteDispatcher {
0080 //   template <class BasicWriter>
0081 //   static void write(BasicWriter &W, ValueType value);
0082 // };
0083 
0084 // BasicWriterBase provides convenience implementations of the write
0085 // methods for EnumPropertyType and SubclassPropertyType types that just
0086 // defer to the "underlying" implementations (for UInt32 and the base class,
0087 // respectively).
0088 //
0089 // template <class Impl>
0090 // class BasicWriterBase {
0091 // protected:
0092 //   Impl &asImpl();
0093 // public:
0094 //   ...
0095 // };
0096 
0097 // The actual classes are auto-generated; see ClangASTPropertiesEmitter.cpp.
0098 #include "clang/AST/AbstractBasicWriter.inc"
0099 
0100 /// DataStreamBasicWriter provides convenience implementations for many
0101 /// BasicWriter methods based on the assumption that the
0102 /// ultimate writer implementation is based on a variable-length stream
0103 /// of unstructured data (like Clang's module files).  It is designed
0104 /// to pair with DataStreamBasicReader.
0105 ///
0106 /// This class can also act as a PropertyWriter, implementing find("...")
0107 /// by simply forwarding to itself.
0108 ///
0109 /// Unimplemented methods:
0110 ///   writeBool
0111 ///   writeUInt32
0112 ///   writeUInt64
0113 ///   writeIdentifier
0114 ///   writeSelector
0115 ///   writeSourceLocation
0116 ///   writeQualType
0117 ///   writeStmtRef
0118 ///   writeDeclRef
0119 template <class Impl>
0120 class DataStreamBasicWriter : public BasicWriterBase<Impl> {
0121 protected:
0122   using BasicWriterBase<Impl>::asImpl;
0123   DataStreamBasicWriter(ASTContext &ctx) : BasicWriterBase<Impl>(ctx) {}
0124 
0125 public:
0126   /// Implement property-find by ignoring it.  We rely on properties being
0127   /// serialized and deserialized in a reliable order instead.
0128   Impl &find(const char *propertyName) {
0129     return asImpl();
0130   }
0131 
0132   // Implement object writing by forwarding to this, collapsing the
0133   // structure into a single data stream.
0134   Impl &writeObject() { return asImpl(); }
0135 
0136   template <class T>
0137   void writeEnum(T value) {
0138     asImpl().writeUInt32(uint32_t(value));
0139   }
0140 
0141   template <class T>
0142   void writeArray(llvm::ArrayRef<T> array) {
0143     asImpl().writeUInt32(array.size());
0144     for (const T &elt : array) {
0145       WriteDispatcher<T>::write(asImpl(), elt);
0146     }
0147   }
0148 
0149   template <class T> void writeOptional(std::optional<T> value) {
0150     WriteDispatcher<T>::write(asImpl(), PackOptionalValue<T>::pack(value));
0151   }
0152 
0153   void writeAPSInt(const llvm::APSInt &value) {
0154     asImpl().writeBool(value.isUnsigned());
0155     asImpl().writeAPInt(value);
0156   }
0157 
0158   void writeAPInt(const llvm::APInt &value) {
0159     asImpl().writeUInt32(value.getBitWidth());
0160     const uint64_t *words = value.getRawData();
0161     for (size_t i = 0, e = value.getNumWords(); i != e; ++i)
0162       asImpl().writeUInt64(words[i]);
0163   }
0164 
0165   void writeFixedPointSemantics(const llvm::FixedPointSemantics &sema) {
0166     asImpl().writeUInt32(sema.getWidth());
0167     asImpl().writeUInt32(sema.getScale());
0168     asImpl().writeUInt32(sema.isSigned() | sema.isSaturated() << 1 |
0169                          sema.hasUnsignedPadding() << 2);
0170   }
0171 
0172   void writeLValuePathSerializationHelper(
0173       APValue::LValuePathSerializationHelper lvaluePath) {
0174     ArrayRef<APValue::LValuePathEntry> path = lvaluePath.Path;
0175     QualType elemTy = lvaluePath.getType();
0176     asImpl().writeQualType(elemTy);
0177     asImpl().writeUInt32(path.size());
0178     auto &ctx = ((BasicWriterBase<Impl> *)this)->getASTContext();
0179     for (auto elem : path) {
0180       if (elemTy->getAs<RecordType>()) {
0181         asImpl().writeUInt32(elem.getAsBaseOrMember().getInt());
0182         const Decl *baseOrMember = elem.getAsBaseOrMember().getPointer();
0183         if (const auto *recordDecl = dyn_cast<CXXRecordDecl>(baseOrMember)) {
0184           asImpl().writeDeclRef(recordDecl);
0185           elemTy = ctx.getRecordType(recordDecl);
0186         } else {
0187           const auto *valueDecl = cast<ValueDecl>(baseOrMember);
0188           asImpl().writeDeclRef(valueDecl);
0189           elemTy = valueDecl->getType();
0190         }
0191       } else {
0192         asImpl().writeUInt32(elem.getAsArrayIndex());
0193         elemTy = ctx.getAsArrayType(elemTy)->getElementType();
0194       }
0195     }
0196   }
0197 
0198   void writeQualifiers(Qualifiers value) {
0199     static_assert(sizeof(value.getAsOpaqueValue()) <= sizeof(uint64_t),
0200                   "update this if the value size changes");
0201     asImpl().writeUInt64(value.getAsOpaqueValue());
0202   }
0203 
0204   void writeExceptionSpecInfo(
0205                         const FunctionProtoType::ExceptionSpecInfo &esi) {
0206     asImpl().writeUInt32(uint32_t(esi.Type));
0207     if (esi.Type == EST_Dynamic) {
0208       asImpl().writeArray(esi.Exceptions);
0209     } else if (isComputedNoexcept(esi.Type)) {
0210       asImpl().writeExprRef(esi.NoexceptExpr);
0211     } else if (esi.Type == EST_Uninstantiated) {
0212       asImpl().writeDeclRef(esi.SourceDecl);
0213       asImpl().writeDeclRef(esi.SourceTemplate);
0214     } else if (esi.Type == EST_Unevaluated) {
0215       asImpl().writeDeclRef(esi.SourceDecl);
0216     }
0217   }
0218 
0219   void writeExtParameterInfo(FunctionProtoType::ExtParameterInfo epi) {
0220     static_assert(sizeof(epi.getOpaqueValue()) <= sizeof(uint32_t),
0221                   "opaque value doesn't fit into uint32_t");
0222     asImpl().writeUInt32(epi.getOpaqueValue());
0223   }
0224 
0225   void writeFunctionEffect(FunctionEffect E) {
0226     asImpl().writeUInt32(E.toOpaqueInt32());
0227   }
0228 
0229   void writeEffectConditionExpr(EffectConditionExpr CE) {
0230     asImpl().writeExprRef(CE.getCondition());
0231   }
0232 
0233   void writeNestedNameSpecifier(NestedNameSpecifier *NNS) {
0234     // Nested name specifiers usually aren't too long. I think that 8 would
0235     // typically accommodate the vast majority.
0236     SmallVector<NestedNameSpecifier *, 8> nestedNames;
0237 
0238     // Push each of the NNS's onto a stack for serialization in reverse order.
0239     while (NNS) {
0240       nestedNames.push_back(NNS);
0241       NNS = NNS->getPrefix();
0242     }
0243 
0244     asImpl().writeUInt32(nestedNames.size());
0245     while (!nestedNames.empty()) {
0246       NNS = nestedNames.pop_back_val();
0247       NestedNameSpecifier::SpecifierKind kind = NNS->getKind();
0248       asImpl().writeNestedNameSpecifierKind(kind);
0249       switch (kind) {
0250       case NestedNameSpecifier::Identifier:
0251         asImpl().writeIdentifier(NNS->getAsIdentifier());
0252         continue;
0253 
0254       case NestedNameSpecifier::Namespace:
0255         asImpl().writeNamespaceDeclRef(NNS->getAsNamespace());
0256         continue;
0257 
0258       case NestedNameSpecifier::NamespaceAlias:
0259         asImpl().writeNamespaceAliasDeclRef(NNS->getAsNamespaceAlias());
0260         continue;
0261 
0262       case NestedNameSpecifier::TypeSpec:
0263       case NestedNameSpecifier::TypeSpecWithTemplate:
0264         asImpl().writeQualType(QualType(NNS->getAsType(), 0));
0265         continue;
0266 
0267       case NestedNameSpecifier::Global:
0268         // Don't need to write an associated value.
0269         continue;
0270 
0271       case NestedNameSpecifier::Super:
0272         asImpl().writeDeclRef(NNS->getAsRecordDecl());
0273         continue;
0274       }
0275       llvm_unreachable("bad nested name specifier kind");
0276     }
0277   }
0278 };
0279 
0280 } // end namespace serialization
0281 } // end namespace clang
0282 
0283 #endif