Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
14 pmbaty 1
//==--- AbstractBasicWriter.h - Abstract basic value serialization --------===//
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 LLVM_CLANG_AST_ABSTRACTBASICWRITER_H
10
#define LLVM_CLANG_AST_ABSTRACTBASICWRITER_H
11
 
12
#include "clang/AST/ASTContext.h"
13
#include "clang/AST/DeclTemplate.h"
14
#include <optional>
15
 
16
namespace clang {
17
namespace serialization {
18
 
19
template <class T>
20
inline std::optional<T> makeOptionalFromNullable(const T &value) {
21
  return (value.isNull() ? std::optional<T>() : std::optional<T>(value));
22
}
23
 
24
template <class T> inline std::optional<T *> makeOptionalFromPointer(T *value) {
25
  return (value ? std::optional<T *>(value) : std::optional<T *>());
26
}
27
 
28
// PropertyWriter is a class concept that requires the following method:
29
//   BasicWriter find(llvm::StringRef propertyName);
30
// where BasicWriter is some class conforming to the BasicWriter concept.
31
// An abstract AST-node writer is created with a PropertyWriter and
32
// performs a sequence of calls like so:
33
//   propertyWriter.find(propertyName).write##TypeName(value)
34
// to write the properties of the node it is serializing.
35
 
36
// BasicWriter is a class concept that requires methods like:
37
//   void write##TypeName(ValueType value);
38
// where TypeName is the name of a PropertyType node from PropertiesBase.td
39
// and ValueType is the corresponding C++ type name.
40
//
41
// In addition to the concrete property types, BasicWriter is expected
42
// to implement these methods:
43
//
44
//   template <class EnumType>
45
//   void writeEnum(T value);
46
//
47
//     Writes an enum value as the current property.  EnumType will always
48
//     be an enum type.  Only necessary if the BasicWriter doesn't provide
49
//     type-specific writers for all the enum types.
50
//
51
//   template <class ValueType>
52
//   void writeOptional(std::optional<ValueType> value);
53
//
54
//     Writes an optional value as the current property.
55
//
56
//   template <class ValueType>
57
//   void writeArray(ArrayRef<ValueType> value);
58
//
59
//     Writes an array of values as the current property.
60
//
61
//   PropertyWriter writeObject();
62
//
63
//     Writes an object as the current property; the returned property
64
//     writer will be subjected to a sequence of property writes and then
65
//     discarded before any other properties are written to the "outer"
66
//     property writer (which need not be the same type).  The sub-writer
67
//     will be used as if with the following code:
68
//
69
//       {
70
//         auto &&widget = W.find("widget").writeObject();
71
//         widget.find("kind").writeWidgetKind(...);
72
//         widget.find("declaration").writeDeclRef(...);
73
//       }
74
 
75
// WriteDispatcher is a template which does type-based forwarding to one
76
// of the write methods of the BasicWriter passed in:
77
//
78
// template <class ValueType>
79
// struct WriteDispatcher {
80
//   template <class BasicWriter>
81
//   static void write(BasicWriter &W, ValueType value);
82
// };
83
 
84
// BasicWriterBase provides convenience implementations of the write
85
// methods for EnumPropertyType and SubclassPropertyType types that just
86
// defer to the "underlying" implementations (for UInt32 and the base class,
87
// respectively).
88
//
89
// template <class Impl>
90
// class BasicWriterBase {
91
// protected:
92
//   Impl &asImpl();
93
// public:
94
//   ...
95
// };
96
 
97
// The actual classes are auto-generated; see ClangASTPropertiesEmitter.cpp.
98
#include "clang/AST/AbstractBasicWriter.inc"
99
 
100
/// DataStreamBasicWriter provides convenience implementations for many
101
/// BasicWriter methods based on the assumption that the
102
/// ultimate writer implementation is based on a variable-length stream
103
/// of unstructured data (like Clang's module files).  It is designed
104
/// to pair with DataStreamBasicReader.
105
///
106
/// This class can also act as a PropertyWriter, implementing find("...")
107
/// by simply forwarding to itself.
108
///
109
/// Unimplemented methods:
110
///   writeBool
111
///   writeUInt32
112
///   writeUInt64
113
///   writeIdentifier
114
///   writeSelector
115
///   writeSourceLocation
116
///   writeQualType
117
///   writeStmtRef
118
///   writeDeclRef
119
template <class Impl>
120
class DataStreamBasicWriter : public BasicWriterBase<Impl> {
121
protected:
122
  using BasicWriterBase<Impl>::asImpl;
123
  DataStreamBasicWriter(ASTContext &ctx) : BasicWriterBase<Impl>(ctx) {}
124
 
125
public:
126
  /// Implement property-find by ignoring it.  We rely on properties being
127
  /// serialized and deserialized in a reliable order instead.
128
  Impl &find(const char *propertyName) {
129
    return asImpl();
130
  }
131
 
132
  // Implement object writing by forwarding to this, collapsing the
133
  // structure into a single data stream.
134
  Impl &writeObject() { return asImpl(); }
135
 
136
  template <class T>
137
  void writeEnum(T value) {
138
    asImpl().writeUInt32(uint32_t(value));
139
  }
140
 
141
  template <class T>
142
  void writeArray(llvm::ArrayRef<T> array) {
143
    asImpl().writeUInt32(array.size());
144
    for (const T &elt : array) {
145
      WriteDispatcher<T>::write(asImpl(), elt);
146
    }
147
  }
148
 
149
  template <class T> void writeOptional(std::optional<T> value) {
150
    WriteDispatcher<T>::write(asImpl(), PackOptionalValue<T>::pack(value));
151
  }
152
 
153
  void writeAPSInt(const llvm::APSInt &value) {
154
    asImpl().writeBool(value.isUnsigned());
155
    asImpl().writeAPInt(value);
156
  }
157
 
158
  void writeAPInt(const llvm::APInt &value) {
159
    asImpl().writeUInt32(value.getBitWidth());
160
    const uint64_t *words = value.getRawData();
161
    for (size_t i = 0, e = value.getNumWords(); i != e; ++i)
162
      asImpl().writeUInt64(words[i]);
163
  }
164
 
165
  void writeFixedPointSemantics(const llvm::FixedPointSemantics &sema) {
166
    asImpl().writeUInt32(sema.getWidth());
167
    asImpl().writeUInt32(sema.getScale());
168
    asImpl().writeUInt32(sema.isSigned() | sema.isSaturated() << 1 |
169
                         sema.hasUnsignedPadding() << 2);
170
  }
171
 
172
  void writeLValuePathSerializationHelper(
173
      APValue::LValuePathSerializationHelper lvaluePath) {
174
    ArrayRef<APValue::LValuePathEntry> path = lvaluePath.Path;
175
    QualType elemTy = lvaluePath.getType();
176
    asImpl().writeQualType(elemTy);
177
    asImpl().writeUInt32(path.size());
178
    auto &ctx = ((BasicWriterBase<Impl> *)this)->getASTContext();
179
    for (auto elem : path) {
180
      if (elemTy->getAs<RecordType>()) {
181
        asImpl().writeUInt32(elem.getAsBaseOrMember().getInt());
182
        const Decl *baseOrMember = elem.getAsBaseOrMember().getPointer();
183
        if (const auto *recordDecl = dyn_cast<CXXRecordDecl>(baseOrMember)) {
184
          asImpl().writeDeclRef(recordDecl);
185
          elemTy = ctx.getRecordType(recordDecl);
186
        } else {
187
          const auto *valueDecl = cast<ValueDecl>(baseOrMember);
188
          asImpl().writeDeclRef(valueDecl);
189
          elemTy = valueDecl->getType();
190
        }
191
      } else {
192
        asImpl().writeUInt32(elem.getAsArrayIndex());
193
        elemTy = ctx.getAsArrayType(elemTy)->getElementType();
194
      }
195
    }
196
  }
197
 
198
  void writeQualifiers(Qualifiers value) {
199
    static_assert(sizeof(value.getAsOpaqueValue()) <= sizeof(uint32_t),
200
                  "update this if the value size changes");
201
    asImpl().writeUInt32(value.getAsOpaqueValue());
202
  }
203
 
204
  void writeExceptionSpecInfo(
205
                        const FunctionProtoType::ExceptionSpecInfo &esi) {
206
    asImpl().writeUInt32(uint32_t(esi.Type));
207
    if (esi.Type == EST_Dynamic) {
208
      asImpl().writeArray(esi.Exceptions);
209
    } else if (isComputedNoexcept(esi.Type)) {
210
      asImpl().writeExprRef(esi.NoexceptExpr);
211
    } else if (esi.Type == EST_Uninstantiated) {
212
      asImpl().writeDeclRef(esi.SourceDecl);
213
      asImpl().writeDeclRef(esi.SourceTemplate);
214
    } else if (esi.Type == EST_Unevaluated) {
215
      asImpl().writeDeclRef(esi.SourceDecl);
216
    }
217
  }
218
 
219
  void writeExtParameterInfo(FunctionProtoType::ExtParameterInfo epi) {
220
    static_assert(sizeof(epi.getOpaqueValue()) <= sizeof(uint32_t),
221
                  "opaque value doesn't fit into uint32_t");
222
    asImpl().writeUInt32(epi.getOpaqueValue());
223
  }
224
 
225
  void writeNestedNameSpecifier(NestedNameSpecifier *NNS) {
226
    // Nested name specifiers usually aren't too long. I think that 8 would
227
    // typically accommodate the vast majority.
228
    SmallVector<NestedNameSpecifier *, 8> nestedNames;
229
 
230
    // Push each of the NNS's onto a stack for serialization in reverse order.
231
    while (NNS) {
232
      nestedNames.push_back(NNS);
233
      NNS = NNS->getPrefix();
234
    }
235
 
236
    asImpl().writeUInt32(nestedNames.size());
237
    while (!nestedNames.empty()) {
238
      NNS = nestedNames.pop_back_val();
239
      NestedNameSpecifier::SpecifierKind kind = NNS->getKind();
240
      asImpl().writeNestedNameSpecifierKind(kind);
241
      switch (kind) {
242
      case NestedNameSpecifier::Identifier:
243
        asImpl().writeIdentifier(NNS->getAsIdentifier());
244
        continue;
245
 
246
      case NestedNameSpecifier::Namespace:
247
        asImpl().writeNamespaceDeclRef(NNS->getAsNamespace());
248
        continue;
249
 
250
      case NestedNameSpecifier::NamespaceAlias:
251
        asImpl().writeNamespaceAliasDeclRef(NNS->getAsNamespaceAlias());
252
        continue;
253
 
254
      case NestedNameSpecifier::TypeSpec:
255
      case NestedNameSpecifier::TypeSpecWithTemplate:
256
        asImpl().writeQualType(QualType(NNS->getAsType(), 0));
257
        continue;
258
 
259
      case NestedNameSpecifier::Global:
260
        // Don't need to write an associated value.
261
        continue;
262
 
263
      case NestedNameSpecifier::Super:
264
        asImpl().writeDeclRef(NNS->getAsRecordDecl());
265
        continue;
266
      }
267
      llvm_unreachable("bad nested name specifier kind");
268
    }
269
  }
270
};
271
 
272
} // end namespace serialization
273
} // end namespace clang
274
 
275
#endif