blob: db756ceebca17bb0f5021952dfae2c4e2820fdb9 [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;
John McCall256ec992019-12-16 02:56:32 -050081 ReadHelperRule ReadHelper = nullptr;
John McCall6404bd22019-12-13 21:52:16 -050082};
83
John McCallefd0dfb2019-12-16 02:10:15 -050084struct CasedTypeInfo {
85 TypeKindRule KindRule;
86 std::vector<TypeCase> Cases;
87};
88
John McCall6404bd22019-12-13 21:52:16 -050089class ASTPropsEmitter {
90 raw_ostream &Out;
91 RecordKeeper &Records;
John McCallefd0dfb2019-12-16 02:10:15 -050092 std::map<HasProperties, NodeInfo> NodeInfos;
John McCall00bc76e2019-12-15 02:39:13 -050093 std::vector<PropertyType> AllPropertyTypes;
John McCallefd0dfb2019-12-16 02:10:15 -050094 std::map<PropertyType, CasedTypeInfo> CasedTypeInfos;
John McCall6404bd22019-12-13 21:52:16 -050095
96public:
97 ASTPropsEmitter(RecordKeeper &records, raw_ostream &out)
98 : Out(out), Records(records) {
99
100 // Find all the properties.
101 for (Property property :
102 records.getAllDerivedDefinitions(PropertyClassName)) {
John McCall256ec992019-12-16 02:56:32 -0500103 HasProperties node = property.getClass();
John McCall6404bd22019-12-13 21:52:16 -0500104 NodeInfos[node].Properties.push_back(property);
105 }
106
107 // Find all the creation rules.
108 for (CreationRule creationRule :
109 records.getAllDerivedDefinitions(CreationRuleClassName)) {
John McCall256ec992019-12-16 02:56:32 -0500110 HasProperties node = creationRule.getClass();
John McCall6404bd22019-12-13 21:52:16 -0500111
112 auto &info = NodeInfos[node];
113 if (info.Creator) {
114 PrintFatalError(creationRule.getLoc(),
115 "multiple creator rules for \"" + node.getName()
116 + "\"");
117 }
118 info.Creator = creationRule;
119 }
120
121 // Find all the override rules.
122 for (OverrideRule overrideRule :
123 records.getAllDerivedDefinitions(OverrideRuleClassName)) {
John McCall256ec992019-12-16 02:56:32 -0500124 HasProperties node = overrideRule.getClass();
John McCall6404bd22019-12-13 21:52:16 -0500125
126 auto &info = NodeInfos[node];
127 if (info.Override) {
128 PrintFatalError(overrideRule.getLoc(),
129 "multiple override rules for \"" + node.getName()
130 + "\"");
131 }
132 info.Override = overrideRule;
133 }
134
John McCall256ec992019-12-16 02:56:32 -0500135 // Find all the write helper rules.
136 for (ReadHelperRule helperRule :
137 records.getAllDerivedDefinitions(ReadHelperRuleClassName)) {
138 HasProperties node = helperRule.getClass();
139
140 auto &info = NodeInfos[node];
141 if (info.ReadHelper) {
142 PrintFatalError(helperRule.getLoc(),
143 "multiple write helper rules for \"" + node.getName()
144 + "\"");
145 }
146 info.ReadHelper = helperRule;
147 }
148
John McCallefd0dfb2019-12-16 02:10:15 -0500149 // Find all the concrete property types.
John McCall00bc76e2019-12-15 02:39:13 -0500150 for (PropertyType type :
151 records.getAllDerivedDefinitions(PropertyTypeClassName)) {
152 // Ignore generic specializations; they're generally not useful when
153 // emitting basic emitters etc.
154 if (type.isGenericSpecialization()) continue;
155
156 AllPropertyTypes.push_back(type);
157 }
158
John McCallefd0dfb2019-12-16 02:10:15 -0500159 // Find all the type kind rules.
160 for (TypeKindRule kindRule :
161 records.getAllDerivedDefinitions(TypeKindClassName)) {
162 PropertyType type = kindRule.getParentType();
163 auto &info = CasedTypeInfos[type];
164 if (info.KindRule) {
165 PrintFatalError(kindRule.getLoc(),
166 "multiple kind rules for \""
167 + type.getCXXTypeName() + "\"");
168 }
169 info.KindRule = kindRule;
170 }
171
172 // Find all the type cases.
173 for (TypeCase typeCase :
174 records.getAllDerivedDefinitions(TypeCaseClassName)) {
175 CasedTypeInfos[typeCase.getParentType()].Cases.push_back(typeCase);
176 }
177
John McCall6404bd22019-12-13 21:52:16 -0500178 Validator(*this).validate();
179 }
180
John McCallefd0dfb2019-12-16 02:10:15 -0500181 void visitAllProperties(HasProperties derived, const NodeInfo &derivedInfo,
John McCall6404bd22019-12-13 21:52:16 -0500182 function_ref<void (Property)> visit) {
183 std::set<StringRef> ignoredProperties;
184
185 auto overrideRule = derivedInfo.Override;
186 if (overrideRule) {
187 auto list = overrideRule.getIgnoredProperties();
188 ignoredProperties.insert(list.begin(), list.end());
189 }
190
John McCallefd0dfb2019-12-16 02:10:15 -0500191 visitAllNodesWithInfo(derived, derivedInfo,
192 [&](HasProperties node, const NodeInfo &info) {
John McCall6404bd22019-12-13 21:52:16 -0500193 for (Property prop : info.Properties) {
194 if (ignoredProperties.count(prop.getName()))
195 continue;
196
197 visit(prop);
198 }
John McCallefd0dfb2019-12-16 02:10:15 -0500199 });
200 }
201
202 void visitAllNodesWithInfo(HasProperties derivedNode,
203 const NodeInfo &derivedNodeInfo,
204 llvm::function_ref<void (HasProperties node,
205 const NodeInfo &info)>
206 visit) {
207 visit(derivedNode, derivedNodeInfo);
208
209 // Also walk the bases if appropriate.
210 if (ASTNode base = derivedNode.getAs<ASTNode>()) {
211 for (base = base.getBase(); base; base = base.getBase()) {
212 auto it = NodeInfos.find(base);
213
214 // Ignore intermediate nodes that don't add interesting properties.
215 if (it == NodeInfos.end()) continue;
216 auto &baseInfo = it->second;
217
218 visit(base, baseInfo);
219 }
John McCall6404bd22019-12-13 21:52:16 -0500220 }
221 }
222
223 template <class NodeClass>
John McCallefd0dfb2019-12-16 02:10:15 -0500224 void emitNodeReaderClass() {
John McCall6404bd22019-12-13 21:52:16 -0500225 auto info = ReaderWriterInfo::forReader<NodeClass>();
John McCallefd0dfb2019-12-16 02:10:15 -0500226 emitNodeReaderWriterClass<NodeClass>(info);
John McCall6404bd22019-12-13 21:52:16 -0500227 }
228
229 template <class NodeClass>
John McCallefd0dfb2019-12-16 02:10:15 -0500230 void emitNodeWriterClass() {
John McCall6404bd22019-12-13 21:52:16 -0500231 auto info = ReaderWriterInfo::forWriter<NodeClass>();
John McCallefd0dfb2019-12-16 02:10:15 -0500232 emitNodeReaderWriterClass<NodeClass>(info);
John McCall6404bd22019-12-13 21:52:16 -0500233 }
234
235 template <class NodeClass>
John McCallefd0dfb2019-12-16 02:10:15 -0500236 void emitNodeReaderWriterClass(const ReaderWriterInfo &info);
John McCall6404bd22019-12-13 21:52:16 -0500237
238 template <class NodeClass>
239 void emitNodeReaderWriterMethod(NodeClass node,
240 const ReaderWriterInfo &info);
241
John McCallefd0dfb2019-12-16 02:10:15 -0500242 void emitPropertiedReaderWriterBody(HasProperties node,
243 const ReaderWriterInfo &info);
244
245 void emitReadOfProperty(StringRef readerName, Property property);
246 void emitReadOfProperty(StringRef readerName, StringRef name,
247 PropertyType type);
248
249 void emitWriteOfProperty(StringRef writerName, Property property);
250 void emitWriteOfProperty(StringRef writerName, StringRef name,
251 PropertyType type, StringRef readCode);
John McCall6404bd22019-12-13 21:52:16 -0500252
John McCall00bc76e2019-12-15 02:39:13 -0500253 void emitBasicReaderWriterFile(const ReaderWriterInfo &info);
254 void emitDispatcherTemplate(const ReaderWriterInfo &info);
255 void emitPackUnpackOptionalTemplate(const ReaderWriterInfo &info);
256 void emitBasicReaderWriterTemplate(const ReaderWriterInfo &info);
257
John McCallefd0dfb2019-12-16 02:10:15 -0500258 void emitCasedReaderWriterMethodBody(PropertyType type,
259 const CasedTypeInfo &typeCases,
260 const ReaderWriterInfo &info);
261
John McCall6404bd22019-12-13 21:52:16 -0500262private:
263 class Validator {
John McCallefd0dfb2019-12-16 02:10:15 -0500264 ASTPropsEmitter &Emitter;
265 std::set<HasProperties> ValidatedNodes;
John McCall6404bd22019-12-13 21:52:16 -0500266
267 public:
John McCallefd0dfb2019-12-16 02:10:15 -0500268 Validator(ASTPropsEmitter &emitter) : Emitter(emitter) {}
John McCall6404bd22019-12-13 21:52:16 -0500269 void validate();
270
271 private:
John McCallefd0dfb2019-12-16 02:10:15 -0500272 void validateNode(HasProperties node, const NodeInfo &nodeInfo);
John McCall6404bd22019-12-13 21:52:16 -0500273 void validateType(PropertyType type, WrappedRecord context);
274 };
275};
276
277} // end anonymous namespace
278
279void ASTPropsEmitter::Validator::validate() {
280 for (auto &entry : Emitter.NodeInfos) {
281 validateNode(entry.first, entry.second);
282 }
283
284 if (ErrorsPrinted > 0) {
285 PrintFatalError("property validation failed");
286 }
287}
288
John McCallefd0dfb2019-12-16 02:10:15 -0500289void ASTPropsEmitter::Validator::validateNode(HasProperties derivedNode,
290 const NodeInfo &derivedNodeInfo) {
291 if (!ValidatedNodes.insert(derivedNode).second) return;
John McCall6404bd22019-12-13 21:52:16 -0500292
293 // A map from property name to property.
294 std::map<StringRef, Property> allProperties;
295
John McCallefd0dfb2019-12-16 02:10:15 -0500296 Emitter.visitAllNodesWithInfo(derivedNode, derivedNodeInfo,
297 [&](HasProperties node,
298 const NodeInfo &nodeInfo) {
299 for (Property property : nodeInfo.Properties) {
John McCall6404bd22019-12-13 21:52:16 -0500300 validateType(property.getType(), property);
301
302 auto result = allProperties.insert(
303 std::make_pair(property.getName(), property));
304
305 // Diagnose non-unique properties.
306 if (!result.second) {
307 // The existing property is more likely to be associated with a
308 // derived node, so use it as the error.
309 Property existingProperty = result.first->second;
310 PrintError(existingProperty.getLoc(),
311 "multiple properties named \"" + property.getName()
John McCallefd0dfb2019-12-16 02:10:15 -0500312 + "\" in hierarchy of " + derivedNode.getName());
John McCall6404bd22019-12-13 21:52:16 -0500313 PrintNote(property.getLoc(), "existing property");
314 }
315 }
John McCallefd0dfb2019-12-16 02:10:15 -0500316 });
John McCall6404bd22019-12-13 21:52:16 -0500317}
318
319void ASTPropsEmitter::Validator::validateType(PropertyType type,
320 WrappedRecord context) {
321 if (!type.isGenericSpecialization()) {
322 if (type.getCXXTypeName() == "") {
323 PrintError(type.getLoc(),
324 "type is not generic but has no C++ type name");
325 if (context) PrintNote(context.getLoc(), "type used here");
326 }
327 } else if (auto eltType = type.getArrayElementType()) {
328 validateType(eltType, context);
329 } else if (auto valueType = type.getOptionalElementType()) {
330 validateType(valueType, context);
331
332 if (valueType.getPackOptionalCode().empty()) {
333 PrintError(valueType.getLoc(),
334 "type doesn't provide optional-packing code");
335 if (context) PrintNote(context.getLoc(), "type used here");
336 } else if (valueType.getUnpackOptionalCode().empty()) {
337 PrintError(valueType.getLoc(),
338 "type doesn't provide optional-unpacking code");
339 if (context) PrintNote(context.getLoc(), "type used here");
340 }
341 } else {
342 PrintError(type.getLoc(), "unknown generic property type");
343 if (context) PrintNote(context.getLoc(), "type used here");
344 }
345}
346
347/****************************************************************************/
348/**************************** AST READER/WRITERS ****************************/
349/****************************************************************************/
350
351template <class NodeClass>
John McCallefd0dfb2019-12-16 02:10:15 -0500352void ASTPropsEmitter::emitNodeReaderWriterClass(const ReaderWriterInfo &info) {
John McCall6404bd22019-12-13 21:52:16 -0500353 StringRef suffix = info.ClassSuffix;
354 StringRef var = info.HelperVariable;
355
356 // Enter the class declaration.
357 Out << "template <class Property" << suffix << ">\n"
358 "class Abstract" << info.HierarchyName << suffix << " {\n"
359 "public:\n"
360 " Property" << suffix << " &" << var << ";\n\n";
361
362 // Emit the constructor.
363 Out << " Abstract" << info.HierarchyName << suffix
364 << "(Property" << suffix << " &" << var << ") : "
365 << var << "(" << var << ") {}\n\n";
366
367 // Emit a method that dispatches on a kind to the appropriate node-specific
368 // method.
369 Out << " " << info.ResultType << " " << info.MethodPrefix << "(";
370 if (info.IsReader)
371 Out << NodeClass::getASTIdTypeName() << " kind";
372 else
373 Out << "const " << info.HierarchyName << " *node";
374 Out << ") {\n"
375 " switch (";
376 if (info.IsReader)
377 Out << "kind";
378 else
379 Out << "node->" << NodeClass::getASTIdAccessorName() << "()";
380 Out << ") {\n";
381 visitASTNodeHierarchy<NodeClass>(Records, [&](NodeClass node, NodeClass _) {
382 if (node.isAbstract()) return;
383 Out << " case " << info.HierarchyName << "::" << node.getId() << ":\n"
384 " return " << info.MethodPrefix << node.getClassName() << "(";
385 if (!info.IsReader)
386 Out << "static_cast<const " << node.getClassName()
387 << " *>(node)";
388 Out << ");\n";
389 });
390 Out << " }\n"
391 " llvm_unreachable(\"bad kind\");\n"
392 " }\n\n";
393
394 // Emit node-specific methods for all the concrete nodes.
395 visitASTNodeHierarchy<NodeClass>(Records,
396 [&](NodeClass node, NodeClass base) {
397 if (node.isAbstract()) return;
398 emitNodeReaderWriterMethod(node, info);
399 });
400
401 // Finish the class.
402 Out << "};\n\n";
403}
404
405/// Emit a reader method for the given concrete AST node class.
406template <class NodeClass>
407void ASTPropsEmitter::emitNodeReaderWriterMethod(NodeClass node,
408 const ReaderWriterInfo &info) {
409 // Declare and start the method.
410 Out << " " << info.ResultType << " "
411 << info.MethodPrefix << node.getClassName() << "(";
412 if (!info.IsReader)
413 Out << "const " << node.getClassName() << " *node";
414 Out << ") {\n";
415 if (info.IsReader)
416 Out << " auto &ctx = " << info.HelperVariable << ".getASTContext();\n";
417
John McCallefd0dfb2019-12-16 02:10:15 -0500418 emitPropertiedReaderWriterBody(node, info);
419
420 // Finish the method declaration.
421 Out << " }\n\n";
422}
423
424void ASTPropsEmitter::emitPropertiedReaderWriterBody(HasProperties node,
425 const ReaderWriterInfo &info) {
John McCall6404bd22019-12-13 21:52:16 -0500426 // Find the information for this node.
427 auto it = NodeInfos.find(node);
428 if (it == NodeInfos.end())
429 PrintFatalError(node.getLoc(),
430 "no information about how to deserialize \""
431 + node.getName() + "\"");
432 auto &nodeInfo = it->second;
433
434 StringRef creationCode;
435 if (info.IsReader) {
436 // We should have a creation rule.
437 if (!nodeInfo.Creator)
438 PrintFatalError(node.getLoc(),
439 "no " CreationRuleClassName " for \""
440 + node.getName() + "\"");
441
442 creationCode = nodeInfo.Creator.getCreationCode();
443 }
444
John McCall256ec992019-12-16 02:56:32 -0500445 // Emit the ReadHelper code, if present.
446 if (!info.IsReader && nodeInfo.ReadHelper) {
447 Out << " " << nodeInfo.ReadHelper.getHelperCode() << "\n";
448 }
449
John McCall6404bd22019-12-13 21:52:16 -0500450 // Emit code to read all the properties.
451 visitAllProperties(node, nodeInfo, [&](Property prop) {
452 // Verify that the creation code refers to this property.
453 if (info.IsReader && creationCode.find(prop.getName()) == StringRef::npos)
454 PrintFatalError(nodeInfo.Creator.getLoc(),
455 "creation code for " + node.getName()
456 + " doesn't refer to property \""
457 + prop.getName() + "\"");
458
459 // Emit code to read or write this property.
460 if (info.IsReader)
John McCallefd0dfb2019-12-16 02:10:15 -0500461 emitReadOfProperty(info.HelperVariable, prop);
John McCall6404bd22019-12-13 21:52:16 -0500462 else
John McCallefd0dfb2019-12-16 02:10:15 -0500463 emitWriteOfProperty(info.HelperVariable, prop);
John McCall6404bd22019-12-13 21:52:16 -0500464 });
465
466 // Emit the final creation code.
467 if (info.IsReader)
468 Out << " " << creationCode << "\n";
John McCall6404bd22019-12-13 21:52:16 -0500469}
470
471static void emitBasicReaderWriterMethodSuffix(raw_ostream &out,
472 PropertyType type,
473 bool isForRead) {
474 if (!type.isGenericSpecialization()) {
475 out << type.getAbstractTypeName();
476 } else if (auto eltType = type.getArrayElementType()) {
477 out << "Array";
478 // We only include an explicit template argument for reads so that
479 // we don't cause spurious const mismatches.
480 if (isForRead) {
481 out << "<";
482 eltType.emitCXXValueTypeName(isForRead, out);
483 out << ">";
484 }
485 } else if (auto valueType = type.getOptionalElementType()) {
486 out << "Optional";
487 // We only include an explicit template argument for reads so that
488 // we don't cause spurious const mismatches.
489 if (isForRead) {
490 out << "<";
491 valueType.emitCXXValueTypeName(isForRead, out);
492 out << ">";
493 }
494 } else {
495 PrintFatalError(type.getLoc(), "unexpected generic property type");
496 }
497}
498
499/// Emit code to read the given property in a node-reader method.
John McCallefd0dfb2019-12-16 02:10:15 -0500500void ASTPropsEmitter::emitReadOfProperty(StringRef readerName,
501 Property property) {
502 emitReadOfProperty(readerName, property.getName(), property.getType());
503}
John McCall6404bd22019-12-13 21:52:16 -0500504
John McCallefd0dfb2019-12-16 02:10:15 -0500505void ASTPropsEmitter::emitReadOfProperty(StringRef readerName,
506 StringRef name,
507 PropertyType type) {
John McCall6404bd22019-12-13 21:52:16 -0500508 // Declare all the necessary buffers.
509 auto bufferTypes = type.getBufferElementTypes();
510 for (size_t i = 0, e = bufferTypes.size(); i != e; ++i) {
511 Out << " llvm::SmallVector<";
512 PropertyType(bufferTypes[i]).emitCXXValueTypeName(/*for read*/ true, Out);
513 Out << ", 8> " << name << "_buffer_" << i << ";\n";
514 }
515
516 // T prop = R.find("prop").read##ValueType(buffers...);
517 // We intentionally ignore shouldPassByReference here: we're going to
518 // get a pr-value back from read(), and we should be able to forward
519 // that in the creation rule.
520 Out << " ";
521 type.emitCXXValueTypeName(true, Out);
John McCallefd0dfb2019-12-16 02:10:15 -0500522 Out << " " << name << " = " << readerName << ".find(\"" << name << "\")."
John McCall6404bd22019-12-13 21:52:16 -0500523 << (type.isGenericSpecialization() ? "template " : "") << "read";
524 emitBasicReaderWriterMethodSuffix(Out, type, /*for read*/ true);
525 Out << "(";
526 for (size_t i = 0, e = bufferTypes.size(); i != e; ++i) {
527 Out << (i > 0 ? ", " : "") << name << "_buffer_" << i;
528 }
529 Out << ");\n";
530}
531
532/// Emit code to write the given property in a node-writer method.
John McCallefd0dfb2019-12-16 02:10:15 -0500533void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName,
534 Property property) {
535 emitWriteOfProperty(writerName, property.getName(), property.getType(),
536 property.getReadCode());
537}
538
539void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName,
540 StringRef name,
541 PropertyType type,
542 StringRef readCode) {
John McCall6404bd22019-12-13 21:52:16 -0500543 // Focus down to the property:
544 // W.find("prop").write##ValueType(value);
John McCallefd0dfb2019-12-16 02:10:15 -0500545 Out << " " << writerName << ".find(\"" << name << "\").write";
546 emitBasicReaderWriterMethodSuffix(Out, type, /*for read*/ false);
547 Out << "(" << readCode << ");\n";
John McCall6404bd22019-12-13 21:52:16 -0500548}
549
550/// Emit an .inc file that defines the AbstractFooReader class
551/// for the given AST class hierarchy.
552template <class NodeClass>
553static void emitASTReader(RecordKeeper &records, raw_ostream &out,
554 StringRef description) {
555 emitSourceFileHeader(description, out);
556
John McCallefd0dfb2019-12-16 02:10:15 -0500557 ASTPropsEmitter(records, out).emitNodeReaderClass<NodeClass>();
John McCall6404bd22019-12-13 21:52:16 -0500558}
559
560void clang::EmitClangTypeReader(RecordKeeper &records, raw_ostream &out) {
561 emitASTReader<TypeNode>(records, out, "A CRTP reader for Clang Type nodes");
562}
563
564/// Emit an .inc file that defines the AbstractFooWriter class
565/// for the given AST class hierarchy.
566template <class NodeClass>
567static void emitASTWriter(RecordKeeper &records, raw_ostream &out,
568 StringRef description) {
569 emitSourceFileHeader(description, out);
570
John McCallefd0dfb2019-12-16 02:10:15 -0500571 ASTPropsEmitter(records, out).emitNodeWriterClass<NodeClass>();
John McCall6404bd22019-12-13 21:52:16 -0500572}
573
574void clang::EmitClangTypeWriter(RecordKeeper &records, raw_ostream &out) {
575 emitASTWriter<TypeNode>(records, out, "A CRTP writer for Clang Type nodes");
576}
577
578/****************************************************************************/
579/*************************** BASIC READER/WRITERS ***************************/
580/****************************************************************************/
581
John McCall00bc76e2019-12-15 02:39:13 -0500582void
583ASTPropsEmitter::emitDispatcherTemplate(const ReaderWriterInfo &info) {
John McCall6404bd22019-12-13 21:52:16 -0500584 // Declare the {Read,Write}Dispatcher template.
585 StringRef dispatcherPrefix = (info.IsReader ? "Read" : "Write");
John McCall00bc76e2019-12-15 02:39:13 -0500586 Out << "template <class ValueType>\n"
John McCall6404bd22019-12-13 21:52:16 -0500587 "struct " << dispatcherPrefix << "Dispatcher;\n";
588
589 // Declare a specific specialization of the dispatcher template.
590 auto declareSpecialization =
591 [&](StringRef specializationParameters,
592 const Twine &cxxTypeName,
593 StringRef methodSuffix) {
594 StringRef var = info.HelperVariable;
John McCall00bc76e2019-12-15 02:39:13 -0500595 Out << "template " << specializationParameters << "\n"
John McCall6404bd22019-12-13 21:52:16 -0500596 "struct " << dispatcherPrefix << "Dispatcher<"
597 << cxxTypeName << "> {\n";
John McCall00bc76e2019-12-15 02:39:13 -0500598 Out << " template <class Basic" << info.ClassSuffix << ", class... Args>\n"
John McCall6404bd22019-12-13 21:52:16 -0500599 " static " << (info.IsReader ? cxxTypeName : "void") << " "
600 << info.MethodPrefix
601 << "(Basic" << info.ClassSuffix << " &" << var
602 << ", Args &&... args) {\n"
603 " return " << var << "."
604 << info.MethodPrefix << methodSuffix
605 << "(std::forward<Args>(args)...);\n"
606 " }\n"
607 "};\n";
608 };
609
610 // Declare explicit specializations for each of the concrete types.
John McCall00bc76e2019-12-15 02:39:13 -0500611 for (PropertyType type : AllPropertyTypes) {
John McCall6404bd22019-12-13 21:52:16 -0500612 declareSpecialization("<>",
613 type.getCXXTypeName(),
614 type.getAbstractTypeName());
615 // Also declare a specialization for the const type when appropriate.
616 if (!info.IsReader && type.isConstWhenWriting()) {
617 declareSpecialization("<>",
618 "const " + type.getCXXTypeName(),
619 type.getAbstractTypeName());
620 }
621 }
622 // Declare partial specializations for ArrayRef and Optional.
623 declareSpecialization("<class T>",
624 "llvm::ArrayRef<T>",
625 "Array");
626 declareSpecialization("<class T>",
627 "llvm::Optional<T>",
628 "Optional");
John McCall00bc76e2019-12-15 02:39:13 -0500629 Out << "\n";
John McCall6404bd22019-12-13 21:52:16 -0500630}
631
John McCall00bc76e2019-12-15 02:39:13 -0500632void
633ASTPropsEmitter::emitPackUnpackOptionalTemplate(const ReaderWriterInfo &info) {
John McCall6404bd22019-12-13 21:52:16 -0500634 StringRef classPrefix = (info.IsReader ? "Unpack" : "Pack");
635 StringRef methodName = (info.IsReader ? "unpack" : "pack");
636
637 // Declare the {Pack,Unpack}OptionalValue template.
John McCall00bc76e2019-12-15 02:39:13 -0500638 Out << "template <class ValueType>\n"
John McCall6404bd22019-12-13 21:52:16 -0500639 "struct " << classPrefix << "OptionalValue;\n";
640
641 auto declareSpecialization = [&](const Twine &typeName,
642 StringRef code) {
John McCall00bc76e2019-12-15 02:39:13 -0500643 Out << "template <>\n"
John McCall6404bd22019-12-13 21:52:16 -0500644 "struct " << classPrefix << "OptionalValue<" << typeName << "> {\n"
645 " static " << (info.IsReader ? "Optional<" : "") << typeName
646 << (info.IsReader ? "> " : " ") << methodName << "("
647 << (info.IsReader ? "" : "Optional<") << typeName
648 << (info.IsReader ? "" : ">") << " value) {\n"
649 " return " << code << ";\n"
650 " }\n"
651 "};\n";
652 };
653
John McCall00bc76e2019-12-15 02:39:13 -0500654 for (PropertyType type : AllPropertyTypes) {
John McCall6404bd22019-12-13 21:52:16 -0500655 StringRef code = (info.IsReader ? type.getUnpackOptionalCode()
656 : type.getPackOptionalCode());
657 if (code.empty()) continue;
658
659 StringRef typeName = type.getCXXTypeName();
660 declareSpecialization(typeName, code);
661 if (type.isConstWhenWriting() && !info.IsReader)
662 declareSpecialization("const " + typeName, code);
663 }
John McCall00bc76e2019-12-15 02:39:13 -0500664 Out << "\n";
John McCall6404bd22019-12-13 21:52:16 -0500665}
666
John McCall00bc76e2019-12-15 02:39:13 -0500667void
668ASTPropsEmitter::emitBasicReaderWriterTemplate(const ReaderWriterInfo &info) {
John McCall6404bd22019-12-13 21:52:16 -0500669 // Emit the Basic{Reader,Writer}Base template.
John McCall00bc76e2019-12-15 02:39:13 -0500670 Out << "template <class Impl>\n"
John McCall6404bd22019-12-13 21:52:16 -0500671 "class Basic" << info.ClassSuffix << "Base {\n";
672 if (info.IsReader)
John McCall00bc76e2019-12-15 02:39:13 -0500673 Out << " ASTContext &C;\n";
674 Out << "protected:\n"
John McCall6404bd22019-12-13 21:52:16 -0500675 " Basic" << info.ClassSuffix << "Base"
676 << (info.IsReader ? "(ASTContext &ctx) : C(ctx)" : "()")
677 << " {}\n"
678 "public:\n";
679 if (info.IsReader)
John McCall00bc76e2019-12-15 02:39:13 -0500680 Out << " ASTContext &getASTContext() { return C; }\n";
681 Out << " Impl &asImpl() { return static_cast<Impl&>(*this); }\n";
John McCall6404bd22019-12-13 21:52:16 -0500682
683 auto enterReaderWriterMethod = [&](StringRef cxxTypeName,
684 StringRef abstractTypeName,
685 bool shouldPassByReference,
John McCallefd0dfb2019-12-16 02:10:15 -0500686 bool constWhenWriting,
687 StringRef paramName) {
John McCall00bc76e2019-12-15 02:39:13 -0500688 Out << " " << (info.IsReader ? cxxTypeName : "void")
John McCall6404bd22019-12-13 21:52:16 -0500689 << " " << info.MethodPrefix << abstractTypeName << "(";
690 if (!info.IsReader)
John McCall00bc76e2019-12-15 02:39:13 -0500691 Out << (shouldPassByReference || constWhenWriting ? "const " : "")
John McCall6404bd22019-12-13 21:52:16 -0500692 << cxxTypeName
John McCallefd0dfb2019-12-16 02:10:15 -0500693 << (shouldPassByReference ? " &" : "") << " " << paramName;
John McCall00bc76e2019-12-15 02:39:13 -0500694 Out << ") {\n";
John McCall6404bd22019-12-13 21:52:16 -0500695 };
696
697 // Emit {read,write}ValueType methods for all the enum and subclass types
698 // that default to using the integer/base-class implementations.
John McCall00bc76e2019-12-15 02:39:13 -0500699 for (PropertyType type : AllPropertyTypes) {
John McCallefd0dfb2019-12-16 02:10:15 -0500700 auto enterMethod = [&](StringRef paramName) {
John McCall6404bd22019-12-13 21:52:16 -0500701 enterReaderWriterMethod(type.getCXXTypeName(),
702 type.getAbstractTypeName(),
John McCallefd0dfb2019-12-16 02:10:15 -0500703 type.shouldPassByReference(),
704 type.isConstWhenWriting(),
705 paramName);
706 };
707 auto exitMethod = [&] {
708 Out << " }\n";
709 };
710
711 // Handled cased types.
712 auto casedIter = CasedTypeInfos.find(type);
713 if (casedIter != CasedTypeInfos.end()) {
714 enterMethod("node");
715 emitCasedReaderWriterMethodBody(type, casedIter->second, info);
716 exitMethod();
717
718 } else if (type.isEnum()) {
719 enterMethod("value");
John McCall6404bd22019-12-13 21:52:16 -0500720 if (info.IsReader)
John McCall00bc76e2019-12-15 02:39:13 -0500721 Out << " return " << type.getCXXTypeName()
John McCall6404bd22019-12-13 21:52:16 -0500722 << "(asImpl().readUInt32());\n";
723 else
John McCall00bc76e2019-12-15 02:39:13 -0500724 Out << " asImpl().writeUInt32(uint32_t(value));\n";
John McCallefd0dfb2019-12-16 02:10:15 -0500725 exitMethod();
726
John McCall6404bd22019-12-13 21:52:16 -0500727 } else if (PropertyType superclass = type.getSuperclassType()) {
John McCallefd0dfb2019-12-16 02:10:15 -0500728 enterMethod("value");
John McCall6404bd22019-12-13 21:52:16 -0500729 if (info.IsReader)
John McCall00bc76e2019-12-15 02:39:13 -0500730 Out << " return cast_or_null<" << type.getSubclassClassName()
John McCall6404bd22019-12-13 21:52:16 -0500731 << ">(asImpl().read"
732 << superclass.getAbstractTypeName()
733 << "());\n";
734 else
John McCall00bc76e2019-12-15 02:39:13 -0500735 Out << " asImpl().write" << superclass.getAbstractTypeName()
John McCall6404bd22019-12-13 21:52:16 -0500736 << "(value);\n";
John McCallefd0dfb2019-12-16 02:10:15 -0500737 exitMethod();
738
John McCall6404bd22019-12-13 21:52:16 -0500739 } else {
740 // The other types can't be handled as trivially.
741 }
742 }
John McCall00bc76e2019-12-15 02:39:13 -0500743 Out << "};\n\n";
John McCall6404bd22019-12-13 21:52:16 -0500744}
745
John McCallefd0dfb2019-12-16 02:10:15 -0500746void ASTPropsEmitter::emitCasedReaderWriterMethodBody(PropertyType type,
747 const CasedTypeInfo &typeCases,
748 const ReaderWriterInfo &info) {
749 if (typeCases.Cases.empty()) {
750 assert(typeCases.KindRule);
751 PrintFatalError(typeCases.KindRule.getLoc(),
752 "no cases found for \"" + type.getCXXTypeName() + "\"");
753 }
754 if (!typeCases.KindRule) {
755 assert(!typeCases.Cases.empty());
756 PrintFatalError(typeCases.Cases.front().getLoc(),
757 "no kind rule for \"" + type.getCXXTypeName() + "\"");
758 }
John McCall6404bd22019-12-13 21:52:16 -0500759
John McCallefd0dfb2019-12-16 02:10:15 -0500760 auto var = info.HelperVariable;
761 std::string subvar = ("sub" + var).str();
762
763 // Bind `ctx` for readers.
764 if (info.IsReader)
765 Out << " auto &ctx = asImpl().getASTContext();\n";
766
767 // Start an object.
768 Out << " auto &&" << subvar << " = asImpl()."
769 << info.MethodPrefix << "Object();\n";
770
771 // Read/write the kind property;
772 TypeKindRule kindRule = typeCases.KindRule;
773 StringRef kindProperty = kindRule.getKindPropertyName();
774 PropertyType kindType = kindRule.getKindType();
775 if (info.IsReader) {
776 emitReadOfProperty(subvar, kindProperty, kindType);
777 } else {
778 // Read the kind into a local variable.
779 Out << " ";
780 kindType.emitCXXValueTypeName(/*for read*/ false, Out);
781 Out << " " << kindProperty << " = " << kindRule.getReadCode() << ";\n";
782 emitWriteOfProperty(subvar, kindProperty, kindType, kindProperty);
783 }
784
785 // Prepare a ReaderWriterInfo with a helper variable that will use
786 // the sub-reader/writer.
787 ReaderWriterInfo subInfo = info;
788 subInfo.HelperVariable = subvar;
789
790 // Switch on the kind.
791 Out << " switch (" << kindProperty << ") {\n";
792 for (TypeCase typeCase : typeCases.Cases) {
793 Out << " case " << type.getCXXTypeName() << "::"
794 << typeCase.getCaseName() << ": {\n";
795 emitPropertiedReaderWriterBody(typeCase, subInfo);
796 if (!info.IsReader)
797 Out << " return;\n";
798 Out << " }\n\n";
799 }
800 Out << " }\n"
801 " llvm_unreachable(\"bad " << kindType.getCXXTypeName()
802 << "\");\n";
803}
804
805void ASTPropsEmitter::emitBasicReaderWriterFile(const ReaderWriterInfo &info) {
John McCall00bc76e2019-12-15 02:39:13 -0500806 emitDispatcherTemplate(info);
807 emitPackUnpackOptionalTemplate(info);
808 emitBasicReaderWriterTemplate(info);
John McCall6404bd22019-12-13 21:52:16 -0500809}
810
811/// Emit an .inc file that defines some helper classes for reading
812/// basic values.
813void clang::EmitClangBasicReader(RecordKeeper &records, raw_ostream &out) {
814 emitSourceFileHeader("Helper classes for BasicReaders", out);
815
816 // Use any property, we won't be using those properties.
817 auto info = ReaderWriterInfo::forReader<TypeNode>();
John McCall00bc76e2019-12-15 02:39:13 -0500818 ASTPropsEmitter(records, out).emitBasicReaderWriterFile(info);
John McCall6404bd22019-12-13 21:52:16 -0500819}
820
821/// Emit an .inc file that defines some helper classes for writing
822/// basic values.
823void clang::EmitClangBasicWriter(RecordKeeper &records, raw_ostream &out) {
824 emitSourceFileHeader("Helper classes for BasicWriters", out);
825
826 // Use any property, we won't be using those properties.
827 auto info = ReaderWriterInfo::forWriter<TypeNode>();
John McCall00bc76e2019-12-15 02:39:13 -0500828 ASTPropsEmitter(records, out).emitBasicReaderWriterFile(info);
John McCall6404bd22019-12-13 21:52:16 -0500829}