blob: e14b9eb6e6ff1e61d34251f7a691566dcffe9978 [file] [log] [blame]
John McCall6404bd22019-12-13 21:52:16 -05001//=== ClangASTPropsEmitter.cpp - Generate Clang AST properties --*- C++ -*-===//
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// This tablegen backend emits code for working with Clang AST properties.
10//
11//===----------------------------------------------------------------------===//
12
13#include "ASTTableGen.h"
14#include "TableGenBackends.h"
15
16#include "llvm/ADT/STLExtras.h"
17#include "llvm/ADT/Twine.h"
18#include "llvm/TableGen/Error.h"
19#include "llvm/TableGen/Record.h"
20#include "llvm/TableGen/TableGenBackend.h"
21#include <cctype>
22#include <map>
23#include <set>
24#include <string>
25using namespace llvm;
26using namespace clang;
27using namespace clang::tblgen;
28
29static StringRef getReaderResultType(TypeNode _) { return "QualType"; }
30
31namespace {
32
33struct ReaderWriterInfo {
34 bool IsReader;
35
36 /// The name of the node hierarchy. Not actually sensitive to IsReader,
37 /// but useful to cache here anyway.
38 StringRef HierarchyName;
39
40 /// The suffix on classes: Reader/Writer
41 StringRef ClassSuffix;
42
43 /// The base name of methods: read/write
44 StringRef MethodPrefix;
45
46 /// The name of the property helper member: R/W
47 StringRef HelperVariable;
48
49 /// The result type of methods on the class.
50 StringRef ResultType;
51
52 template <class NodeClass>
53 static ReaderWriterInfo forReader() {
54 return ReaderWriterInfo{
55 true,
56 NodeClass::getASTHierarchyName(),
57 "Reader",
58 "read",
59 "R",
60 getReaderResultType(NodeClass())
61 };
62 }
63
64 template <class NodeClass>
65 static ReaderWriterInfo forWriter() {
66 return ReaderWriterInfo{
67 false,
68 NodeClass::getASTHierarchyName(),
69 "Writer",
70 "write",
71 "W",
72 "void"
73 };
74 }
75};
76
77struct NodeInfo {
78 std::vector<Property> Properties;
79 CreationRule Creator = nullptr;
80 OverrideRule Override = nullptr;
81};
82
83class ASTPropsEmitter {
84 raw_ostream &Out;
85 RecordKeeper &Records;
86 std::map<ASTNode, NodeInfo> NodeInfos;
John McCall00bc76e2019-12-15 02:39:13 -050087 std::vector<PropertyType> AllPropertyTypes;
John McCall6404bd22019-12-13 21:52:16 -050088
89public:
90 ASTPropsEmitter(RecordKeeper &records, raw_ostream &out)
91 : Out(out), Records(records) {
92
93 // Find all the properties.
94 for (Property property :
95 records.getAllDerivedDefinitions(PropertyClassName)) {
96 ASTNode node = property.getClass();
97 NodeInfos[node].Properties.push_back(property);
98 }
99
100 // Find all the creation rules.
101 for (CreationRule creationRule :
102 records.getAllDerivedDefinitions(CreationRuleClassName)) {
103 ASTNode node = creationRule.getClass();
104
105 auto &info = NodeInfos[node];
106 if (info.Creator) {
107 PrintFatalError(creationRule.getLoc(),
108 "multiple creator rules for \"" + node.getName()
109 + "\"");
110 }
111 info.Creator = creationRule;
112 }
113
114 // Find all the override rules.
115 for (OverrideRule overrideRule :
116 records.getAllDerivedDefinitions(OverrideRuleClassName)) {
117 ASTNode node = overrideRule.getClass();
118
119 auto &info = NodeInfos[node];
120 if (info.Override) {
121 PrintFatalError(overrideRule.getLoc(),
122 "multiple override rules for \"" + node.getName()
123 + "\"");
124 }
125 info.Override = overrideRule;
126 }
127
John McCall00bc76e2019-12-15 02:39:13 -0500128 for (PropertyType type :
129 records.getAllDerivedDefinitions(PropertyTypeClassName)) {
130 // Ignore generic specializations; they're generally not useful when
131 // emitting basic emitters etc.
132 if (type.isGenericSpecialization()) continue;
133
134 AllPropertyTypes.push_back(type);
135 }
136
John McCall6404bd22019-12-13 21:52:16 -0500137 Validator(*this).validate();
138 }
139
140 void visitAllProperties(ASTNode derived, const NodeInfo &derivedInfo,
141 function_ref<void (Property)> visit) {
142 std::set<StringRef> ignoredProperties;
143
144 auto overrideRule = derivedInfo.Override;
145 if (overrideRule) {
146 auto list = overrideRule.getIgnoredProperties();
147 ignoredProperties.insert(list.begin(), list.end());
148 }
149
150 for (ASTNode node = derived; node; node = node.getBase()) {
151 auto it = NodeInfos.find(node);
152
153 // Ignore intermediate nodes that don't add interesting properties.
154 if (it == NodeInfos.end()) continue;
155 auto &info = it->second;
156
157 for (Property prop : info.Properties) {
158 if (ignoredProperties.count(prop.getName()))
159 continue;
160
161 visit(prop);
162 }
163 }
164 }
165
166 template <class NodeClass>
167 void emitReaderClass() {
168 auto info = ReaderWriterInfo::forReader<NodeClass>();
169 emitReaderWriterClass<NodeClass>(info);
170 }
171
172 template <class NodeClass>
173 void emitWriterClass() {
174 auto info = ReaderWriterInfo::forWriter<NodeClass>();
175 emitReaderWriterClass<NodeClass>(info);
176 }
177
178 template <class NodeClass>
179 void emitReaderWriterClass(const ReaderWriterInfo &info);
180
181 template <class NodeClass>
182 void emitNodeReaderWriterMethod(NodeClass node,
183 const ReaderWriterInfo &info);
184
185 void emitReadOfProperty(Property property);
186 void emitWriteOfProperty(Property property);
187
John McCall00bc76e2019-12-15 02:39:13 -0500188 void emitBasicReaderWriterFile(const ReaderWriterInfo &info);
189 void emitDispatcherTemplate(const ReaderWriterInfo &info);
190 void emitPackUnpackOptionalTemplate(const ReaderWriterInfo &info);
191 void emitBasicReaderWriterTemplate(const ReaderWriterInfo &info);
192
John McCall6404bd22019-12-13 21:52:16 -0500193private:
194 class Validator {
195 const ASTPropsEmitter &Emitter;
196 std::set<ASTNode> ValidatedNodes;
197
198 public:
199 Validator(const ASTPropsEmitter &emitter) : Emitter(emitter) {}
200 void validate();
201
202 private:
203 void validateNode(ASTNode node, const NodeInfo &nodeInfo);
204 void validateType(PropertyType type, WrappedRecord context);
205 };
206};
207
208} // end anonymous namespace
209
210void ASTPropsEmitter::Validator::validate() {
211 for (auto &entry : Emitter.NodeInfos) {
212 validateNode(entry.first, entry.second);
213 }
214
215 if (ErrorsPrinted > 0) {
216 PrintFatalError("property validation failed");
217 }
218}
219
220void ASTPropsEmitter::Validator::validateNode(ASTNode node,
221 const NodeInfo &nodeInfo) {
222 if (!ValidatedNodes.insert(node).second) return;
223
224 // A map from property name to property.
225 std::map<StringRef, Property> allProperties;
226
227 // Walk the hierarchy, ignoring nodes that don't declare anything
228 // interesting.
229 for (auto base = node; base; base = base.getBase()) {
230 auto it = Emitter.NodeInfos.find(base);
231 if (it == Emitter.NodeInfos.end()) continue;
232
233 auto &baseInfo = it->second;
234 for (Property property : baseInfo.Properties) {
235 validateType(property.getType(), property);
236
237 auto result = allProperties.insert(
238 std::make_pair(property.getName(), property));
239
240 // Diagnose non-unique properties.
241 if (!result.second) {
242 // The existing property is more likely to be associated with a
243 // derived node, so use it as the error.
244 Property existingProperty = result.first->second;
245 PrintError(existingProperty.getLoc(),
246 "multiple properties named \"" + property.getName()
247 + "\" in hierarchy of " + node.getName());
248 PrintNote(property.getLoc(), "existing property");
249 }
250 }
251 }
252}
253
254void ASTPropsEmitter::Validator::validateType(PropertyType type,
255 WrappedRecord context) {
256 if (!type.isGenericSpecialization()) {
257 if (type.getCXXTypeName() == "") {
258 PrintError(type.getLoc(),
259 "type is not generic but has no C++ type name");
260 if (context) PrintNote(context.getLoc(), "type used here");
261 }
262 } else if (auto eltType = type.getArrayElementType()) {
263 validateType(eltType, context);
264 } else if (auto valueType = type.getOptionalElementType()) {
265 validateType(valueType, context);
266
267 if (valueType.getPackOptionalCode().empty()) {
268 PrintError(valueType.getLoc(),
269 "type doesn't provide optional-packing code");
270 if (context) PrintNote(context.getLoc(), "type used here");
271 } else if (valueType.getUnpackOptionalCode().empty()) {
272 PrintError(valueType.getLoc(),
273 "type doesn't provide optional-unpacking code");
274 if (context) PrintNote(context.getLoc(), "type used here");
275 }
276 } else {
277 PrintError(type.getLoc(), "unknown generic property type");
278 if (context) PrintNote(context.getLoc(), "type used here");
279 }
280}
281
282/****************************************************************************/
283/**************************** AST READER/WRITERS ****************************/
284/****************************************************************************/
285
286template <class NodeClass>
287void ASTPropsEmitter::emitReaderWriterClass(const ReaderWriterInfo &info) {
288 StringRef suffix = info.ClassSuffix;
289 StringRef var = info.HelperVariable;
290
291 // Enter the class declaration.
292 Out << "template <class Property" << suffix << ">\n"
293 "class Abstract" << info.HierarchyName << suffix << " {\n"
294 "public:\n"
295 " Property" << suffix << " &" << var << ";\n\n";
296
297 // Emit the constructor.
298 Out << " Abstract" << info.HierarchyName << suffix
299 << "(Property" << suffix << " &" << var << ") : "
300 << var << "(" << var << ") {}\n\n";
301
302 // Emit a method that dispatches on a kind to the appropriate node-specific
303 // method.
304 Out << " " << info.ResultType << " " << info.MethodPrefix << "(";
305 if (info.IsReader)
306 Out << NodeClass::getASTIdTypeName() << " kind";
307 else
308 Out << "const " << info.HierarchyName << " *node";
309 Out << ") {\n"
310 " switch (";
311 if (info.IsReader)
312 Out << "kind";
313 else
314 Out << "node->" << NodeClass::getASTIdAccessorName() << "()";
315 Out << ") {\n";
316 visitASTNodeHierarchy<NodeClass>(Records, [&](NodeClass node, NodeClass _) {
317 if (node.isAbstract()) return;
318 Out << " case " << info.HierarchyName << "::" << node.getId() << ":\n"
319 " return " << info.MethodPrefix << node.getClassName() << "(";
320 if (!info.IsReader)
321 Out << "static_cast<const " << node.getClassName()
322 << " *>(node)";
323 Out << ");\n";
324 });
325 Out << " }\n"
326 " llvm_unreachable(\"bad kind\");\n"
327 " }\n\n";
328
329 // Emit node-specific methods for all the concrete nodes.
330 visitASTNodeHierarchy<NodeClass>(Records,
331 [&](NodeClass node, NodeClass base) {
332 if (node.isAbstract()) return;
333 emitNodeReaderWriterMethod(node, info);
334 });
335
336 // Finish the class.
337 Out << "};\n\n";
338}
339
340/// Emit a reader method for the given concrete AST node class.
341template <class NodeClass>
342void ASTPropsEmitter::emitNodeReaderWriterMethod(NodeClass node,
343 const ReaderWriterInfo &info) {
344 // Declare and start the method.
345 Out << " " << info.ResultType << " "
346 << info.MethodPrefix << node.getClassName() << "(";
347 if (!info.IsReader)
348 Out << "const " << node.getClassName() << " *node";
349 Out << ") {\n";
350 if (info.IsReader)
351 Out << " auto &ctx = " << info.HelperVariable << ".getASTContext();\n";
352
353 // Find the information for this node.
354 auto it = NodeInfos.find(node);
355 if (it == NodeInfos.end())
356 PrintFatalError(node.getLoc(),
357 "no information about how to deserialize \""
358 + node.getName() + "\"");
359 auto &nodeInfo = it->second;
360
361 StringRef creationCode;
362 if (info.IsReader) {
363 // We should have a creation rule.
364 if (!nodeInfo.Creator)
365 PrintFatalError(node.getLoc(),
366 "no " CreationRuleClassName " for \""
367 + node.getName() + "\"");
368
369 creationCode = nodeInfo.Creator.getCreationCode();
370 }
371
372 // Emit code to read all the properties.
373 visitAllProperties(node, nodeInfo, [&](Property prop) {
374 // Verify that the creation code refers to this property.
375 if (info.IsReader && creationCode.find(prop.getName()) == StringRef::npos)
376 PrintFatalError(nodeInfo.Creator.getLoc(),
377 "creation code for " + node.getName()
378 + " doesn't refer to property \""
379 + prop.getName() + "\"");
380
381 // Emit code to read or write this property.
382 if (info.IsReader)
383 emitReadOfProperty(prop);
384 else
385 emitWriteOfProperty(prop);
386 });
387
388 // Emit the final creation code.
389 if (info.IsReader)
390 Out << " " << creationCode << "\n";
391
392 // Finish the method declaration.
393 Out << " }\n\n";
394}
395
396static void emitBasicReaderWriterMethodSuffix(raw_ostream &out,
397 PropertyType type,
398 bool isForRead) {
399 if (!type.isGenericSpecialization()) {
400 out << type.getAbstractTypeName();
401 } else if (auto eltType = type.getArrayElementType()) {
402 out << "Array";
403 // We only include an explicit template argument for reads so that
404 // we don't cause spurious const mismatches.
405 if (isForRead) {
406 out << "<";
407 eltType.emitCXXValueTypeName(isForRead, out);
408 out << ">";
409 }
410 } else if (auto valueType = type.getOptionalElementType()) {
411 out << "Optional";
412 // We only include an explicit template argument for reads so that
413 // we don't cause spurious const mismatches.
414 if (isForRead) {
415 out << "<";
416 valueType.emitCXXValueTypeName(isForRead, out);
417 out << ">";
418 }
419 } else {
420 PrintFatalError(type.getLoc(), "unexpected generic property type");
421 }
422}
423
424/// Emit code to read the given property in a node-reader method.
425void ASTPropsEmitter::emitReadOfProperty(Property property) {
426 PropertyType type = property.getType();
427 auto name = property.getName();
428
429 // Declare all the necessary buffers.
430 auto bufferTypes = type.getBufferElementTypes();
431 for (size_t i = 0, e = bufferTypes.size(); i != e; ++i) {
432 Out << " llvm::SmallVector<";
433 PropertyType(bufferTypes[i]).emitCXXValueTypeName(/*for read*/ true, Out);
434 Out << ", 8> " << name << "_buffer_" << i << ";\n";
435 }
436
437 // T prop = R.find("prop").read##ValueType(buffers...);
438 // We intentionally ignore shouldPassByReference here: we're going to
439 // get a pr-value back from read(), and we should be able to forward
440 // that in the creation rule.
441 Out << " ";
442 type.emitCXXValueTypeName(true, Out);
443 Out << " " << name << " = R.find(\"" << name << "\")."
444 << (type.isGenericSpecialization() ? "template " : "") << "read";
445 emitBasicReaderWriterMethodSuffix(Out, type, /*for read*/ true);
446 Out << "(";
447 for (size_t i = 0, e = bufferTypes.size(); i != e; ++i) {
448 Out << (i > 0 ? ", " : "") << name << "_buffer_" << i;
449 }
450 Out << ");\n";
451}
452
453/// Emit code to write the given property in a node-writer method.
454void ASTPropsEmitter::emitWriteOfProperty(Property property) {
455 // Focus down to the property:
456 // W.find("prop").write##ValueType(value);
457 Out << " W.find(\"" << property.getName() << "\").write";
458 emitBasicReaderWriterMethodSuffix(Out, property.getType(),
459 /*for read*/ false);
460 Out << "(" << property.getReadCode() << ");\n";
461}
462
463/// Emit an .inc file that defines the AbstractFooReader class
464/// for the given AST class hierarchy.
465template <class NodeClass>
466static void emitASTReader(RecordKeeper &records, raw_ostream &out,
467 StringRef description) {
468 emitSourceFileHeader(description, out);
469
470 ASTPropsEmitter(records, out).emitReaderClass<NodeClass>();
471}
472
473void clang::EmitClangTypeReader(RecordKeeper &records, raw_ostream &out) {
474 emitASTReader<TypeNode>(records, out, "A CRTP reader for Clang Type nodes");
475}
476
477/// Emit an .inc file that defines the AbstractFooWriter class
478/// for the given AST class hierarchy.
479template <class NodeClass>
480static void emitASTWriter(RecordKeeper &records, raw_ostream &out,
481 StringRef description) {
482 emitSourceFileHeader(description, out);
483
484 ASTPropsEmitter(records, out).emitWriterClass<NodeClass>();
485}
486
487void clang::EmitClangTypeWriter(RecordKeeper &records, raw_ostream &out) {
488 emitASTWriter<TypeNode>(records, out, "A CRTP writer for Clang Type nodes");
489}
490
491/****************************************************************************/
492/*************************** BASIC READER/WRITERS ***************************/
493/****************************************************************************/
494
John McCall00bc76e2019-12-15 02:39:13 -0500495void
496ASTPropsEmitter::emitDispatcherTemplate(const ReaderWriterInfo &info) {
John McCall6404bd22019-12-13 21:52:16 -0500497 // Declare the {Read,Write}Dispatcher template.
498 StringRef dispatcherPrefix = (info.IsReader ? "Read" : "Write");
John McCall00bc76e2019-12-15 02:39:13 -0500499 Out << "template <class ValueType>\n"
John McCall6404bd22019-12-13 21:52:16 -0500500 "struct " << dispatcherPrefix << "Dispatcher;\n";
501
502 // Declare a specific specialization of the dispatcher template.
503 auto declareSpecialization =
504 [&](StringRef specializationParameters,
505 const Twine &cxxTypeName,
506 StringRef methodSuffix) {
507 StringRef var = info.HelperVariable;
John McCall00bc76e2019-12-15 02:39:13 -0500508 Out << "template " << specializationParameters << "\n"
John McCall6404bd22019-12-13 21:52:16 -0500509 "struct " << dispatcherPrefix << "Dispatcher<"
510 << cxxTypeName << "> {\n";
John McCall00bc76e2019-12-15 02:39:13 -0500511 Out << " template <class Basic" << info.ClassSuffix << ", class... Args>\n"
John McCall6404bd22019-12-13 21:52:16 -0500512 " static " << (info.IsReader ? cxxTypeName : "void") << " "
513 << info.MethodPrefix
514 << "(Basic" << info.ClassSuffix << " &" << var
515 << ", Args &&... args) {\n"
516 " return " << var << "."
517 << info.MethodPrefix << methodSuffix
518 << "(std::forward<Args>(args)...);\n"
519 " }\n"
520 "};\n";
521 };
522
523 // Declare explicit specializations for each of the concrete types.
John McCall00bc76e2019-12-15 02:39:13 -0500524 for (PropertyType type : AllPropertyTypes) {
John McCall6404bd22019-12-13 21:52:16 -0500525 declareSpecialization("<>",
526 type.getCXXTypeName(),
527 type.getAbstractTypeName());
528 // Also declare a specialization for the const type when appropriate.
529 if (!info.IsReader && type.isConstWhenWriting()) {
530 declareSpecialization("<>",
531 "const " + type.getCXXTypeName(),
532 type.getAbstractTypeName());
533 }
534 }
535 // Declare partial specializations for ArrayRef and Optional.
536 declareSpecialization("<class T>",
537 "llvm::ArrayRef<T>",
538 "Array");
539 declareSpecialization("<class T>",
540 "llvm::Optional<T>",
541 "Optional");
John McCall00bc76e2019-12-15 02:39:13 -0500542 Out << "\n";
John McCall6404bd22019-12-13 21:52:16 -0500543}
544
John McCall00bc76e2019-12-15 02:39:13 -0500545void
546ASTPropsEmitter::emitPackUnpackOptionalTemplate(const ReaderWriterInfo &info) {
John McCall6404bd22019-12-13 21:52:16 -0500547 StringRef classPrefix = (info.IsReader ? "Unpack" : "Pack");
548 StringRef methodName = (info.IsReader ? "unpack" : "pack");
549
550 // Declare the {Pack,Unpack}OptionalValue template.
John McCall00bc76e2019-12-15 02:39:13 -0500551 Out << "template <class ValueType>\n"
John McCall6404bd22019-12-13 21:52:16 -0500552 "struct " << classPrefix << "OptionalValue;\n";
553
554 auto declareSpecialization = [&](const Twine &typeName,
555 StringRef code) {
John McCall00bc76e2019-12-15 02:39:13 -0500556 Out << "template <>\n"
John McCall6404bd22019-12-13 21:52:16 -0500557 "struct " << classPrefix << "OptionalValue<" << typeName << "> {\n"
558 " static " << (info.IsReader ? "Optional<" : "") << typeName
559 << (info.IsReader ? "> " : " ") << methodName << "("
560 << (info.IsReader ? "" : "Optional<") << typeName
561 << (info.IsReader ? "" : ">") << " value) {\n"
562 " return " << code << ";\n"
563 " }\n"
564 "};\n";
565 };
566
John McCall00bc76e2019-12-15 02:39:13 -0500567 for (PropertyType type : AllPropertyTypes) {
John McCall6404bd22019-12-13 21:52:16 -0500568 StringRef code = (info.IsReader ? type.getUnpackOptionalCode()
569 : type.getPackOptionalCode());
570 if (code.empty()) continue;
571
572 StringRef typeName = type.getCXXTypeName();
573 declareSpecialization(typeName, code);
574 if (type.isConstWhenWriting() && !info.IsReader)
575 declareSpecialization("const " + typeName, code);
576 }
John McCall00bc76e2019-12-15 02:39:13 -0500577 Out << "\n";
John McCall6404bd22019-12-13 21:52:16 -0500578}
579
John McCall00bc76e2019-12-15 02:39:13 -0500580void
581ASTPropsEmitter::emitBasicReaderWriterTemplate(const ReaderWriterInfo &info) {
John McCall6404bd22019-12-13 21:52:16 -0500582 // Emit the Basic{Reader,Writer}Base template.
John McCall00bc76e2019-12-15 02:39:13 -0500583 Out << "template <class Impl>\n"
John McCall6404bd22019-12-13 21:52:16 -0500584 "class Basic" << info.ClassSuffix << "Base {\n";
585 if (info.IsReader)
John McCall00bc76e2019-12-15 02:39:13 -0500586 Out << " ASTContext &C;\n";
587 Out << "protected:\n"
John McCall6404bd22019-12-13 21:52:16 -0500588 " Basic" << info.ClassSuffix << "Base"
589 << (info.IsReader ? "(ASTContext &ctx) : C(ctx)" : "()")
590 << " {}\n"
591 "public:\n";
592 if (info.IsReader)
John McCall00bc76e2019-12-15 02:39:13 -0500593 Out << " ASTContext &getASTContext() { return C; }\n";
594 Out << " Impl &asImpl() { return static_cast<Impl&>(*this); }\n";
John McCall6404bd22019-12-13 21:52:16 -0500595
596 auto enterReaderWriterMethod = [&](StringRef cxxTypeName,
597 StringRef abstractTypeName,
598 bool shouldPassByReference,
599 bool constWhenWriting) {
John McCall00bc76e2019-12-15 02:39:13 -0500600 Out << " " << (info.IsReader ? cxxTypeName : "void")
John McCall6404bd22019-12-13 21:52:16 -0500601 << " " << info.MethodPrefix << abstractTypeName << "(";
602 if (!info.IsReader)
John McCall00bc76e2019-12-15 02:39:13 -0500603 Out << (shouldPassByReference || constWhenWriting ? "const " : "")
John McCall6404bd22019-12-13 21:52:16 -0500604 << cxxTypeName
605 << (shouldPassByReference ? " &" : "") << " value";
John McCall00bc76e2019-12-15 02:39:13 -0500606 Out << ") {\n";
John McCall6404bd22019-12-13 21:52:16 -0500607 };
608
609 // Emit {read,write}ValueType methods for all the enum and subclass types
610 // that default to using the integer/base-class implementations.
John McCall00bc76e2019-12-15 02:39:13 -0500611 for (PropertyType type : AllPropertyTypes) {
John McCall6404bd22019-12-13 21:52:16 -0500612 if (type.isEnum()) {
613 enterReaderWriterMethod(type.getCXXTypeName(),
614 type.getAbstractTypeName(),
615 /*pass by reference*/ false,
616 /*const when writing*/ false);
617 if (info.IsReader)
John McCall00bc76e2019-12-15 02:39:13 -0500618 Out << " return " << type.getCXXTypeName()
John McCall6404bd22019-12-13 21:52:16 -0500619 << "(asImpl().readUInt32());\n";
620 else
John McCall00bc76e2019-12-15 02:39:13 -0500621 Out << " asImpl().writeUInt32(uint32_t(value));\n";
622 Out << " }\n";
John McCall6404bd22019-12-13 21:52:16 -0500623 } else if (PropertyType superclass = type.getSuperclassType()) {
624 enterReaderWriterMethod(type.getCXXTypeName(),
625 type.getAbstractTypeName(),
626 /*pass by reference*/ false,
627 /*const when writing*/ type.isConstWhenWriting());
628 if (info.IsReader)
John McCall00bc76e2019-12-15 02:39:13 -0500629 Out << " return cast_or_null<" << type.getSubclassClassName()
John McCall6404bd22019-12-13 21:52:16 -0500630 << ">(asImpl().read"
631 << superclass.getAbstractTypeName()
632 << "());\n";
633 else
John McCall00bc76e2019-12-15 02:39:13 -0500634 Out << " asImpl().write" << superclass.getAbstractTypeName()
John McCall6404bd22019-12-13 21:52:16 -0500635 << "(value);\n";
John McCall00bc76e2019-12-15 02:39:13 -0500636 Out << " }\n";
John McCall6404bd22019-12-13 21:52:16 -0500637 } else {
638 // The other types can't be handled as trivially.
639 }
640 }
John McCall00bc76e2019-12-15 02:39:13 -0500641 Out << "};\n\n";
John McCall6404bd22019-12-13 21:52:16 -0500642}
643
John McCall00bc76e2019-12-15 02:39:13 -0500644void ASTPropsEmitter::emitBasicReaderWriterFile(const ReaderWriterInfo &info) {
645 auto types = Records.getAllDerivedDefinitions(PropertyTypeClassName);
John McCall6404bd22019-12-13 21:52:16 -0500646
John McCall00bc76e2019-12-15 02:39:13 -0500647 emitDispatcherTemplate(info);
648 emitPackUnpackOptionalTemplate(info);
649 emitBasicReaderWriterTemplate(info);
John McCall6404bd22019-12-13 21:52:16 -0500650}
651
652/// Emit an .inc file that defines some helper classes for reading
653/// basic values.
654void clang::EmitClangBasicReader(RecordKeeper &records, raw_ostream &out) {
655 emitSourceFileHeader("Helper classes for BasicReaders", out);
656
657 // Use any property, we won't be using those properties.
658 auto info = ReaderWriterInfo::forReader<TypeNode>();
John McCall00bc76e2019-12-15 02:39:13 -0500659 ASTPropsEmitter(records, out).emitBasicReaderWriterFile(info);
John McCall6404bd22019-12-13 21:52:16 -0500660}
661
662/// Emit an .inc file that defines some helper classes for writing
663/// basic values.
664void clang::EmitClangBasicWriter(RecordKeeper &records, raw_ostream &out) {
665 emitSourceFileHeader("Helper classes for BasicWriters", out);
666
667 // Use any property, we won't be using those properties.
668 auto info = ReaderWriterInfo::forWriter<TypeNode>();
John McCall00bc76e2019-12-15 02:39:13 -0500669 ASTPropsEmitter(records, out).emitBasicReaderWriterFile(info);
John McCall6404bd22019-12-13 21:52:16 -0500670}