blob: 81d880c61a6375a0a6ea5a2d3a5734736e10870b [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
John McCallefd0dfb2019-12-16 02:10:15 -050083struct CasedTypeInfo {
84 TypeKindRule KindRule;
85 std::vector<TypeCase> Cases;
86};
87
John McCall6404bd22019-12-13 21:52:16 -050088class ASTPropsEmitter {
89 raw_ostream &Out;
90 RecordKeeper &Records;
John McCallefd0dfb2019-12-16 02:10:15 -050091 std::map<HasProperties, NodeInfo> NodeInfos;
John McCall00bc76e2019-12-15 02:39:13 -050092 std::vector<PropertyType> AllPropertyTypes;
John McCallefd0dfb2019-12-16 02:10:15 -050093 std::map<PropertyType, CasedTypeInfo> CasedTypeInfos;
John McCall6404bd22019-12-13 21:52:16 -050094
95public:
96 ASTPropsEmitter(RecordKeeper &records, raw_ostream &out)
97 : Out(out), Records(records) {
98
99 // Find all the properties.
100 for (Property property :
101 records.getAllDerivedDefinitions(PropertyClassName)) {
102 ASTNode node = property.getClass();
103 NodeInfos[node].Properties.push_back(property);
104 }
105
106 // Find all the creation rules.
107 for (CreationRule creationRule :
108 records.getAllDerivedDefinitions(CreationRuleClassName)) {
109 ASTNode node = creationRule.getClass();
110
111 auto &info = NodeInfos[node];
112 if (info.Creator) {
113 PrintFatalError(creationRule.getLoc(),
114 "multiple creator rules for \"" + node.getName()
115 + "\"");
116 }
117 info.Creator = creationRule;
118 }
119
120 // Find all the override rules.
121 for (OverrideRule overrideRule :
122 records.getAllDerivedDefinitions(OverrideRuleClassName)) {
123 ASTNode node = overrideRule.getClass();
124
125 auto &info = NodeInfos[node];
126 if (info.Override) {
127 PrintFatalError(overrideRule.getLoc(),
128 "multiple override rules for \"" + node.getName()
129 + "\"");
130 }
131 info.Override = overrideRule;
132 }
133
John McCallefd0dfb2019-12-16 02:10:15 -0500134 // Find all the concrete property types.
John McCall00bc76e2019-12-15 02:39:13 -0500135 for (PropertyType type :
136 records.getAllDerivedDefinitions(PropertyTypeClassName)) {
137 // Ignore generic specializations; they're generally not useful when
138 // emitting basic emitters etc.
139 if (type.isGenericSpecialization()) continue;
140
141 AllPropertyTypes.push_back(type);
142 }
143
John McCallefd0dfb2019-12-16 02:10:15 -0500144 // Find all the type kind rules.
145 for (TypeKindRule kindRule :
146 records.getAllDerivedDefinitions(TypeKindClassName)) {
147 PropertyType type = kindRule.getParentType();
148 auto &info = CasedTypeInfos[type];
149 if (info.KindRule) {
150 PrintFatalError(kindRule.getLoc(),
151 "multiple kind rules for \""
152 + type.getCXXTypeName() + "\"");
153 }
154 info.KindRule = kindRule;
155 }
156
157 // Find all the type cases.
158 for (TypeCase typeCase :
159 records.getAllDerivedDefinitions(TypeCaseClassName)) {
160 CasedTypeInfos[typeCase.getParentType()].Cases.push_back(typeCase);
161 }
162
John McCall6404bd22019-12-13 21:52:16 -0500163 Validator(*this).validate();
164 }
165
John McCallefd0dfb2019-12-16 02:10:15 -0500166 void visitAllProperties(HasProperties derived, const NodeInfo &derivedInfo,
John McCall6404bd22019-12-13 21:52:16 -0500167 function_ref<void (Property)> visit) {
168 std::set<StringRef> ignoredProperties;
169
170 auto overrideRule = derivedInfo.Override;
171 if (overrideRule) {
172 auto list = overrideRule.getIgnoredProperties();
173 ignoredProperties.insert(list.begin(), list.end());
174 }
175
John McCallefd0dfb2019-12-16 02:10:15 -0500176 visitAllNodesWithInfo(derived, derivedInfo,
177 [&](HasProperties node, const NodeInfo &info) {
John McCall6404bd22019-12-13 21:52:16 -0500178 for (Property prop : info.Properties) {
179 if (ignoredProperties.count(prop.getName()))
180 continue;
181
182 visit(prop);
183 }
John McCallefd0dfb2019-12-16 02:10:15 -0500184 });
185 }
186
187 void visitAllNodesWithInfo(HasProperties derivedNode,
188 const NodeInfo &derivedNodeInfo,
189 llvm::function_ref<void (HasProperties node,
190 const NodeInfo &info)>
191 visit) {
192 visit(derivedNode, derivedNodeInfo);
193
194 // Also walk the bases if appropriate.
195 if (ASTNode base = derivedNode.getAs<ASTNode>()) {
196 for (base = base.getBase(); base; base = base.getBase()) {
197 auto it = NodeInfos.find(base);
198
199 // Ignore intermediate nodes that don't add interesting properties.
200 if (it == NodeInfos.end()) continue;
201 auto &baseInfo = it->second;
202
203 visit(base, baseInfo);
204 }
John McCall6404bd22019-12-13 21:52:16 -0500205 }
206 }
207
208 template <class NodeClass>
John McCallefd0dfb2019-12-16 02:10:15 -0500209 void emitNodeReaderClass() {
John McCall6404bd22019-12-13 21:52:16 -0500210 auto info = ReaderWriterInfo::forReader<NodeClass>();
John McCallefd0dfb2019-12-16 02:10:15 -0500211 emitNodeReaderWriterClass<NodeClass>(info);
John McCall6404bd22019-12-13 21:52:16 -0500212 }
213
214 template <class NodeClass>
John McCallefd0dfb2019-12-16 02:10:15 -0500215 void emitNodeWriterClass() {
John McCall6404bd22019-12-13 21:52:16 -0500216 auto info = ReaderWriterInfo::forWriter<NodeClass>();
John McCallefd0dfb2019-12-16 02:10:15 -0500217 emitNodeReaderWriterClass<NodeClass>(info);
John McCall6404bd22019-12-13 21:52:16 -0500218 }
219
220 template <class NodeClass>
John McCallefd0dfb2019-12-16 02:10:15 -0500221 void emitNodeReaderWriterClass(const ReaderWriterInfo &info);
John McCall6404bd22019-12-13 21:52:16 -0500222
223 template <class NodeClass>
224 void emitNodeReaderWriterMethod(NodeClass node,
225 const ReaderWriterInfo &info);
226
John McCallefd0dfb2019-12-16 02:10:15 -0500227 void emitPropertiedReaderWriterBody(HasProperties node,
228 const ReaderWriterInfo &info);
229
230 void emitReadOfProperty(StringRef readerName, Property property);
231 void emitReadOfProperty(StringRef readerName, StringRef name,
232 PropertyType type);
233
234 void emitWriteOfProperty(StringRef writerName, Property property);
235 void emitWriteOfProperty(StringRef writerName, StringRef name,
236 PropertyType type, StringRef readCode);
John McCall6404bd22019-12-13 21:52:16 -0500237
John McCall00bc76e2019-12-15 02:39:13 -0500238 void emitBasicReaderWriterFile(const ReaderWriterInfo &info);
239 void emitDispatcherTemplate(const ReaderWriterInfo &info);
240 void emitPackUnpackOptionalTemplate(const ReaderWriterInfo &info);
241 void emitBasicReaderWriterTemplate(const ReaderWriterInfo &info);
242
John McCallefd0dfb2019-12-16 02:10:15 -0500243 void emitCasedReaderWriterMethodBody(PropertyType type,
244 const CasedTypeInfo &typeCases,
245 const ReaderWriterInfo &info);
246
John McCall6404bd22019-12-13 21:52:16 -0500247private:
248 class Validator {
John McCallefd0dfb2019-12-16 02:10:15 -0500249 ASTPropsEmitter &Emitter;
250 std::set<HasProperties> ValidatedNodes;
John McCall6404bd22019-12-13 21:52:16 -0500251
252 public:
John McCallefd0dfb2019-12-16 02:10:15 -0500253 Validator(ASTPropsEmitter &emitter) : Emitter(emitter) {}
John McCall6404bd22019-12-13 21:52:16 -0500254 void validate();
255
256 private:
John McCallefd0dfb2019-12-16 02:10:15 -0500257 void validateNode(HasProperties node, const NodeInfo &nodeInfo);
John McCall6404bd22019-12-13 21:52:16 -0500258 void validateType(PropertyType type, WrappedRecord context);
259 };
260};
261
262} // end anonymous namespace
263
264void ASTPropsEmitter::Validator::validate() {
265 for (auto &entry : Emitter.NodeInfos) {
266 validateNode(entry.first, entry.second);
267 }
268
269 if (ErrorsPrinted > 0) {
270 PrintFatalError("property validation failed");
271 }
272}
273
John McCallefd0dfb2019-12-16 02:10:15 -0500274void ASTPropsEmitter::Validator::validateNode(HasProperties derivedNode,
275 const NodeInfo &derivedNodeInfo) {
276 if (!ValidatedNodes.insert(derivedNode).second) return;
John McCall6404bd22019-12-13 21:52:16 -0500277
278 // A map from property name to property.
279 std::map<StringRef, Property> allProperties;
280
John McCallefd0dfb2019-12-16 02:10:15 -0500281 Emitter.visitAllNodesWithInfo(derivedNode, derivedNodeInfo,
282 [&](HasProperties node,
283 const NodeInfo &nodeInfo) {
284 for (Property property : nodeInfo.Properties) {
John McCall6404bd22019-12-13 21:52:16 -0500285 validateType(property.getType(), property);
286
287 auto result = allProperties.insert(
288 std::make_pair(property.getName(), property));
289
290 // Diagnose non-unique properties.
291 if (!result.second) {
292 // The existing property is more likely to be associated with a
293 // derived node, so use it as the error.
294 Property existingProperty = result.first->second;
295 PrintError(existingProperty.getLoc(),
296 "multiple properties named \"" + property.getName()
John McCallefd0dfb2019-12-16 02:10:15 -0500297 + "\" in hierarchy of " + derivedNode.getName());
John McCall6404bd22019-12-13 21:52:16 -0500298 PrintNote(property.getLoc(), "existing property");
299 }
300 }
John McCallefd0dfb2019-12-16 02:10:15 -0500301 });
John McCall6404bd22019-12-13 21:52:16 -0500302}
303
304void ASTPropsEmitter::Validator::validateType(PropertyType type,
305 WrappedRecord context) {
306 if (!type.isGenericSpecialization()) {
307 if (type.getCXXTypeName() == "") {
308 PrintError(type.getLoc(),
309 "type is not generic but has no C++ type name");
310 if (context) PrintNote(context.getLoc(), "type used here");
311 }
312 } else if (auto eltType = type.getArrayElementType()) {
313 validateType(eltType, context);
314 } else if (auto valueType = type.getOptionalElementType()) {
315 validateType(valueType, context);
316
317 if (valueType.getPackOptionalCode().empty()) {
318 PrintError(valueType.getLoc(),
319 "type doesn't provide optional-packing code");
320 if (context) PrintNote(context.getLoc(), "type used here");
321 } else if (valueType.getUnpackOptionalCode().empty()) {
322 PrintError(valueType.getLoc(),
323 "type doesn't provide optional-unpacking code");
324 if (context) PrintNote(context.getLoc(), "type used here");
325 }
326 } else {
327 PrintError(type.getLoc(), "unknown generic property type");
328 if (context) PrintNote(context.getLoc(), "type used here");
329 }
330}
331
332/****************************************************************************/
333/**************************** AST READER/WRITERS ****************************/
334/****************************************************************************/
335
336template <class NodeClass>
John McCallefd0dfb2019-12-16 02:10:15 -0500337void ASTPropsEmitter::emitNodeReaderWriterClass(const ReaderWriterInfo &info) {
John McCall6404bd22019-12-13 21:52:16 -0500338 StringRef suffix = info.ClassSuffix;
339 StringRef var = info.HelperVariable;
340
341 // Enter the class declaration.
342 Out << "template <class Property" << suffix << ">\n"
343 "class Abstract" << info.HierarchyName << suffix << " {\n"
344 "public:\n"
345 " Property" << suffix << " &" << var << ";\n\n";
346
347 // Emit the constructor.
348 Out << " Abstract" << info.HierarchyName << suffix
349 << "(Property" << suffix << " &" << var << ") : "
350 << var << "(" << var << ") {}\n\n";
351
352 // Emit a method that dispatches on a kind to the appropriate node-specific
353 // method.
354 Out << " " << info.ResultType << " " << info.MethodPrefix << "(";
355 if (info.IsReader)
356 Out << NodeClass::getASTIdTypeName() << " kind";
357 else
358 Out << "const " << info.HierarchyName << " *node";
359 Out << ") {\n"
360 " switch (";
361 if (info.IsReader)
362 Out << "kind";
363 else
364 Out << "node->" << NodeClass::getASTIdAccessorName() << "()";
365 Out << ") {\n";
366 visitASTNodeHierarchy<NodeClass>(Records, [&](NodeClass node, NodeClass _) {
367 if (node.isAbstract()) return;
368 Out << " case " << info.HierarchyName << "::" << node.getId() << ":\n"
369 " return " << info.MethodPrefix << node.getClassName() << "(";
370 if (!info.IsReader)
371 Out << "static_cast<const " << node.getClassName()
372 << " *>(node)";
373 Out << ");\n";
374 });
375 Out << " }\n"
376 " llvm_unreachable(\"bad kind\");\n"
377 " }\n\n";
378
379 // Emit node-specific methods for all the concrete nodes.
380 visitASTNodeHierarchy<NodeClass>(Records,
381 [&](NodeClass node, NodeClass base) {
382 if (node.isAbstract()) return;
383 emitNodeReaderWriterMethod(node, info);
384 });
385
386 // Finish the class.
387 Out << "};\n\n";
388}
389
390/// Emit a reader method for the given concrete AST node class.
391template <class NodeClass>
392void ASTPropsEmitter::emitNodeReaderWriterMethod(NodeClass node,
393 const ReaderWriterInfo &info) {
394 // Declare and start the method.
395 Out << " " << info.ResultType << " "
396 << info.MethodPrefix << node.getClassName() << "(";
397 if (!info.IsReader)
398 Out << "const " << node.getClassName() << " *node";
399 Out << ") {\n";
400 if (info.IsReader)
401 Out << " auto &ctx = " << info.HelperVariable << ".getASTContext();\n";
402
John McCallefd0dfb2019-12-16 02:10:15 -0500403 emitPropertiedReaderWriterBody(node, info);
404
405 // Finish the method declaration.
406 Out << " }\n\n";
407}
408
409void ASTPropsEmitter::emitPropertiedReaderWriterBody(HasProperties node,
410 const ReaderWriterInfo &info) {
John McCall6404bd22019-12-13 21:52:16 -0500411 // Find the information for this node.
412 auto it = NodeInfos.find(node);
413 if (it == NodeInfos.end())
414 PrintFatalError(node.getLoc(),
415 "no information about how to deserialize \""
416 + node.getName() + "\"");
417 auto &nodeInfo = it->second;
418
419 StringRef creationCode;
420 if (info.IsReader) {
421 // We should have a creation rule.
422 if (!nodeInfo.Creator)
423 PrintFatalError(node.getLoc(),
424 "no " CreationRuleClassName " for \""
425 + node.getName() + "\"");
426
427 creationCode = nodeInfo.Creator.getCreationCode();
428 }
429
430 // Emit code to read all the properties.
431 visitAllProperties(node, nodeInfo, [&](Property prop) {
432 // Verify that the creation code refers to this property.
433 if (info.IsReader && creationCode.find(prop.getName()) == StringRef::npos)
434 PrintFatalError(nodeInfo.Creator.getLoc(),
435 "creation code for " + node.getName()
436 + " doesn't refer to property \""
437 + prop.getName() + "\"");
438
439 // Emit code to read or write this property.
440 if (info.IsReader)
John McCallefd0dfb2019-12-16 02:10:15 -0500441 emitReadOfProperty(info.HelperVariable, prop);
John McCall6404bd22019-12-13 21:52:16 -0500442 else
John McCallefd0dfb2019-12-16 02:10:15 -0500443 emitWriteOfProperty(info.HelperVariable, prop);
John McCall6404bd22019-12-13 21:52:16 -0500444 });
445
446 // Emit the final creation code.
447 if (info.IsReader)
448 Out << " " << creationCode << "\n";
John McCall6404bd22019-12-13 21:52:16 -0500449}
450
451static void emitBasicReaderWriterMethodSuffix(raw_ostream &out,
452 PropertyType type,
453 bool isForRead) {
454 if (!type.isGenericSpecialization()) {
455 out << type.getAbstractTypeName();
456 } else if (auto eltType = type.getArrayElementType()) {
457 out << "Array";
458 // We only include an explicit template argument for reads so that
459 // we don't cause spurious const mismatches.
460 if (isForRead) {
461 out << "<";
462 eltType.emitCXXValueTypeName(isForRead, out);
463 out << ">";
464 }
465 } else if (auto valueType = type.getOptionalElementType()) {
466 out << "Optional";
467 // We only include an explicit template argument for reads so that
468 // we don't cause spurious const mismatches.
469 if (isForRead) {
470 out << "<";
471 valueType.emitCXXValueTypeName(isForRead, out);
472 out << ">";
473 }
474 } else {
475 PrintFatalError(type.getLoc(), "unexpected generic property type");
476 }
477}
478
479/// Emit code to read the given property in a node-reader method.
John McCallefd0dfb2019-12-16 02:10:15 -0500480void ASTPropsEmitter::emitReadOfProperty(StringRef readerName,
481 Property property) {
482 emitReadOfProperty(readerName, property.getName(), property.getType());
483}
John McCall6404bd22019-12-13 21:52:16 -0500484
John McCallefd0dfb2019-12-16 02:10:15 -0500485void ASTPropsEmitter::emitReadOfProperty(StringRef readerName,
486 StringRef name,
487 PropertyType type) {
John McCall6404bd22019-12-13 21:52:16 -0500488 // Declare all the necessary buffers.
489 auto bufferTypes = type.getBufferElementTypes();
490 for (size_t i = 0, e = bufferTypes.size(); i != e; ++i) {
491 Out << " llvm::SmallVector<";
492 PropertyType(bufferTypes[i]).emitCXXValueTypeName(/*for read*/ true, Out);
493 Out << ", 8> " << name << "_buffer_" << i << ";\n";
494 }
495
496 // T prop = R.find("prop").read##ValueType(buffers...);
497 // We intentionally ignore shouldPassByReference here: we're going to
498 // get a pr-value back from read(), and we should be able to forward
499 // that in the creation rule.
500 Out << " ";
501 type.emitCXXValueTypeName(true, Out);
John McCallefd0dfb2019-12-16 02:10:15 -0500502 Out << " " << name << " = " << readerName << ".find(\"" << name << "\")."
John McCall6404bd22019-12-13 21:52:16 -0500503 << (type.isGenericSpecialization() ? "template " : "") << "read";
504 emitBasicReaderWriterMethodSuffix(Out, type, /*for read*/ true);
505 Out << "(";
506 for (size_t i = 0, e = bufferTypes.size(); i != e; ++i) {
507 Out << (i > 0 ? ", " : "") << name << "_buffer_" << i;
508 }
509 Out << ");\n";
510}
511
512/// Emit code to write the given property in a node-writer method.
John McCallefd0dfb2019-12-16 02:10:15 -0500513void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName,
514 Property property) {
515 emitWriteOfProperty(writerName, property.getName(), property.getType(),
516 property.getReadCode());
517}
518
519void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName,
520 StringRef name,
521 PropertyType type,
522 StringRef readCode) {
John McCall6404bd22019-12-13 21:52:16 -0500523 // Focus down to the property:
524 // W.find("prop").write##ValueType(value);
John McCallefd0dfb2019-12-16 02:10:15 -0500525 Out << " " << writerName << ".find(\"" << name << "\").write";
526 emitBasicReaderWriterMethodSuffix(Out, type, /*for read*/ false);
527 Out << "(" << readCode << ");\n";
John McCall6404bd22019-12-13 21:52:16 -0500528}
529
530/// Emit an .inc file that defines the AbstractFooReader class
531/// for the given AST class hierarchy.
532template <class NodeClass>
533static void emitASTReader(RecordKeeper &records, raw_ostream &out,
534 StringRef description) {
535 emitSourceFileHeader(description, out);
536
John McCallefd0dfb2019-12-16 02:10:15 -0500537 ASTPropsEmitter(records, out).emitNodeReaderClass<NodeClass>();
John McCall6404bd22019-12-13 21:52:16 -0500538}
539
540void clang::EmitClangTypeReader(RecordKeeper &records, raw_ostream &out) {
541 emitASTReader<TypeNode>(records, out, "A CRTP reader for Clang Type nodes");
542}
543
544/// Emit an .inc file that defines the AbstractFooWriter class
545/// for the given AST class hierarchy.
546template <class NodeClass>
547static void emitASTWriter(RecordKeeper &records, raw_ostream &out,
548 StringRef description) {
549 emitSourceFileHeader(description, out);
550
John McCallefd0dfb2019-12-16 02:10:15 -0500551 ASTPropsEmitter(records, out).emitNodeWriterClass<NodeClass>();
John McCall6404bd22019-12-13 21:52:16 -0500552}
553
554void clang::EmitClangTypeWriter(RecordKeeper &records, raw_ostream &out) {
555 emitASTWriter<TypeNode>(records, out, "A CRTP writer for Clang Type nodes");
556}
557
558/****************************************************************************/
559/*************************** BASIC READER/WRITERS ***************************/
560/****************************************************************************/
561
John McCall00bc76e2019-12-15 02:39:13 -0500562void
563ASTPropsEmitter::emitDispatcherTemplate(const ReaderWriterInfo &info) {
John McCall6404bd22019-12-13 21:52:16 -0500564 // Declare the {Read,Write}Dispatcher template.
565 StringRef dispatcherPrefix = (info.IsReader ? "Read" : "Write");
John McCall00bc76e2019-12-15 02:39:13 -0500566 Out << "template <class ValueType>\n"
John McCall6404bd22019-12-13 21:52:16 -0500567 "struct " << dispatcherPrefix << "Dispatcher;\n";
568
569 // Declare a specific specialization of the dispatcher template.
570 auto declareSpecialization =
571 [&](StringRef specializationParameters,
572 const Twine &cxxTypeName,
573 StringRef methodSuffix) {
574 StringRef var = info.HelperVariable;
John McCall00bc76e2019-12-15 02:39:13 -0500575 Out << "template " << specializationParameters << "\n"
John McCall6404bd22019-12-13 21:52:16 -0500576 "struct " << dispatcherPrefix << "Dispatcher<"
577 << cxxTypeName << "> {\n";
John McCall00bc76e2019-12-15 02:39:13 -0500578 Out << " template <class Basic" << info.ClassSuffix << ", class... Args>\n"
John McCall6404bd22019-12-13 21:52:16 -0500579 " static " << (info.IsReader ? cxxTypeName : "void") << " "
580 << info.MethodPrefix
581 << "(Basic" << info.ClassSuffix << " &" << var
582 << ", Args &&... args) {\n"
583 " return " << var << "."
584 << info.MethodPrefix << methodSuffix
585 << "(std::forward<Args>(args)...);\n"
586 " }\n"
587 "};\n";
588 };
589
590 // Declare explicit specializations for each of the concrete types.
John McCall00bc76e2019-12-15 02:39:13 -0500591 for (PropertyType type : AllPropertyTypes) {
John McCall6404bd22019-12-13 21:52:16 -0500592 declareSpecialization("<>",
593 type.getCXXTypeName(),
594 type.getAbstractTypeName());
595 // Also declare a specialization for the const type when appropriate.
596 if (!info.IsReader && type.isConstWhenWriting()) {
597 declareSpecialization("<>",
598 "const " + type.getCXXTypeName(),
599 type.getAbstractTypeName());
600 }
601 }
602 // Declare partial specializations for ArrayRef and Optional.
603 declareSpecialization("<class T>",
604 "llvm::ArrayRef<T>",
605 "Array");
606 declareSpecialization("<class T>",
607 "llvm::Optional<T>",
608 "Optional");
John McCall00bc76e2019-12-15 02:39:13 -0500609 Out << "\n";
John McCall6404bd22019-12-13 21:52:16 -0500610}
611
John McCall00bc76e2019-12-15 02:39:13 -0500612void
613ASTPropsEmitter::emitPackUnpackOptionalTemplate(const ReaderWriterInfo &info) {
John McCall6404bd22019-12-13 21:52:16 -0500614 StringRef classPrefix = (info.IsReader ? "Unpack" : "Pack");
615 StringRef methodName = (info.IsReader ? "unpack" : "pack");
616
617 // Declare the {Pack,Unpack}OptionalValue template.
John McCall00bc76e2019-12-15 02:39:13 -0500618 Out << "template <class ValueType>\n"
John McCall6404bd22019-12-13 21:52:16 -0500619 "struct " << classPrefix << "OptionalValue;\n";
620
621 auto declareSpecialization = [&](const Twine &typeName,
622 StringRef code) {
John McCall00bc76e2019-12-15 02:39:13 -0500623 Out << "template <>\n"
John McCall6404bd22019-12-13 21:52:16 -0500624 "struct " << classPrefix << "OptionalValue<" << typeName << "> {\n"
625 " static " << (info.IsReader ? "Optional<" : "") << typeName
626 << (info.IsReader ? "> " : " ") << methodName << "("
627 << (info.IsReader ? "" : "Optional<") << typeName
628 << (info.IsReader ? "" : ">") << " value) {\n"
629 " return " << code << ";\n"
630 " }\n"
631 "};\n";
632 };
633
John McCall00bc76e2019-12-15 02:39:13 -0500634 for (PropertyType type : AllPropertyTypes) {
John McCall6404bd22019-12-13 21:52:16 -0500635 StringRef code = (info.IsReader ? type.getUnpackOptionalCode()
636 : type.getPackOptionalCode());
637 if (code.empty()) continue;
638
639 StringRef typeName = type.getCXXTypeName();
640 declareSpecialization(typeName, code);
641 if (type.isConstWhenWriting() && !info.IsReader)
642 declareSpecialization("const " + typeName, code);
643 }
John McCall00bc76e2019-12-15 02:39:13 -0500644 Out << "\n";
John McCall6404bd22019-12-13 21:52:16 -0500645}
646
John McCall00bc76e2019-12-15 02:39:13 -0500647void
648ASTPropsEmitter::emitBasicReaderWriterTemplate(const ReaderWriterInfo &info) {
John McCall6404bd22019-12-13 21:52:16 -0500649 // Emit the Basic{Reader,Writer}Base template.
John McCall00bc76e2019-12-15 02:39:13 -0500650 Out << "template <class Impl>\n"
John McCall6404bd22019-12-13 21:52:16 -0500651 "class Basic" << info.ClassSuffix << "Base {\n";
652 if (info.IsReader)
John McCall00bc76e2019-12-15 02:39:13 -0500653 Out << " ASTContext &C;\n";
654 Out << "protected:\n"
John McCall6404bd22019-12-13 21:52:16 -0500655 " Basic" << info.ClassSuffix << "Base"
656 << (info.IsReader ? "(ASTContext &ctx) : C(ctx)" : "()")
657 << " {}\n"
658 "public:\n";
659 if (info.IsReader)
John McCall00bc76e2019-12-15 02:39:13 -0500660 Out << " ASTContext &getASTContext() { return C; }\n";
661 Out << " Impl &asImpl() { return static_cast<Impl&>(*this); }\n";
John McCall6404bd22019-12-13 21:52:16 -0500662
663 auto enterReaderWriterMethod = [&](StringRef cxxTypeName,
664 StringRef abstractTypeName,
665 bool shouldPassByReference,
John McCallefd0dfb2019-12-16 02:10:15 -0500666 bool constWhenWriting,
667 StringRef paramName) {
John McCall00bc76e2019-12-15 02:39:13 -0500668 Out << " " << (info.IsReader ? cxxTypeName : "void")
John McCall6404bd22019-12-13 21:52:16 -0500669 << " " << info.MethodPrefix << abstractTypeName << "(";
670 if (!info.IsReader)
John McCall00bc76e2019-12-15 02:39:13 -0500671 Out << (shouldPassByReference || constWhenWriting ? "const " : "")
John McCall6404bd22019-12-13 21:52:16 -0500672 << cxxTypeName
John McCallefd0dfb2019-12-16 02:10:15 -0500673 << (shouldPassByReference ? " &" : "") << " " << paramName;
John McCall00bc76e2019-12-15 02:39:13 -0500674 Out << ") {\n";
John McCall6404bd22019-12-13 21:52:16 -0500675 };
676
677 // Emit {read,write}ValueType methods for all the enum and subclass types
678 // that default to using the integer/base-class implementations.
John McCall00bc76e2019-12-15 02:39:13 -0500679 for (PropertyType type : AllPropertyTypes) {
John McCallefd0dfb2019-12-16 02:10:15 -0500680 auto enterMethod = [&](StringRef paramName) {
John McCall6404bd22019-12-13 21:52:16 -0500681 enterReaderWriterMethod(type.getCXXTypeName(),
682 type.getAbstractTypeName(),
John McCallefd0dfb2019-12-16 02:10:15 -0500683 type.shouldPassByReference(),
684 type.isConstWhenWriting(),
685 paramName);
686 };
687 auto exitMethod = [&] {
688 Out << " }\n";
689 };
690
691 // Handled cased types.
692 auto casedIter = CasedTypeInfos.find(type);
693 if (casedIter != CasedTypeInfos.end()) {
694 enterMethod("node");
695 emitCasedReaderWriterMethodBody(type, casedIter->second, info);
696 exitMethod();
697
698 } else if (type.isEnum()) {
699 enterMethod("value");
John McCall6404bd22019-12-13 21:52:16 -0500700 if (info.IsReader)
John McCall00bc76e2019-12-15 02:39:13 -0500701 Out << " return " << type.getCXXTypeName()
John McCall6404bd22019-12-13 21:52:16 -0500702 << "(asImpl().readUInt32());\n";
703 else
John McCall00bc76e2019-12-15 02:39:13 -0500704 Out << " asImpl().writeUInt32(uint32_t(value));\n";
John McCallefd0dfb2019-12-16 02:10:15 -0500705 exitMethod();
706
John McCall6404bd22019-12-13 21:52:16 -0500707 } else if (PropertyType superclass = type.getSuperclassType()) {
John McCallefd0dfb2019-12-16 02:10:15 -0500708 enterMethod("value");
John McCall6404bd22019-12-13 21:52:16 -0500709 if (info.IsReader)
John McCall00bc76e2019-12-15 02:39:13 -0500710 Out << " return cast_or_null<" << type.getSubclassClassName()
John McCall6404bd22019-12-13 21:52:16 -0500711 << ">(asImpl().read"
712 << superclass.getAbstractTypeName()
713 << "());\n";
714 else
John McCall00bc76e2019-12-15 02:39:13 -0500715 Out << " asImpl().write" << superclass.getAbstractTypeName()
John McCall6404bd22019-12-13 21:52:16 -0500716 << "(value);\n";
John McCallefd0dfb2019-12-16 02:10:15 -0500717 exitMethod();
718
John McCall6404bd22019-12-13 21:52:16 -0500719 } else {
720 // The other types can't be handled as trivially.
721 }
722 }
John McCall00bc76e2019-12-15 02:39:13 -0500723 Out << "};\n\n";
John McCall6404bd22019-12-13 21:52:16 -0500724}
725
John McCallefd0dfb2019-12-16 02:10:15 -0500726void ASTPropsEmitter::emitCasedReaderWriterMethodBody(PropertyType type,
727 const CasedTypeInfo &typeCases,
728 const ReaderWriterInfo &info) {
729 if (typeCases.Cases.empty()) {
730 assert(typeCases.KindRule);
731 PrintFatalError(typeCases.KindRule.getLoc(),
732 "no cases found for \"" + type.getCXXTypeName() + "\"");
733 }
734 if (!typeCases.KindRule) {
735 assert(!typeCases.Cases.empty());
736 PrintFatalError(typeCases.Cases.front().getLoc(),
737 "no kind rule for \"" + type.getCXXTypeName() + "\"");
738 }
John McCall6404bd22019-12-13 21:52:16 -0500739
John McCallefd0dfb2019-12-16 02:10:15 -0500740 auto var = info.HelperVariable;
741 std::string subvar = ("sub" + var).str();
742
743 // Bind `ctx` for readers.
744 if (info.IsReader)
745 Out << " auto &ctx = asImpl().getASTContext();\n";
746
747 // Start an object.
748 Out << " auto &&" << subvar << " = asImpl()."
749 << info.MethodPrefix << "Object();\n";
750
751 // Read/write the kind property;
752 TypeKindRule kindRule = typeCases.KindRule;
753 StringRef kindProperty = kindRule.getKindPropertyName();
754 PropertyType kindType = kindRule.getKindType();
755 if (info.IsReader) {
756 emitReadOfProperty(subvar, kindProperty, kindType);
757 } else {
758 // Read the kind into a local variable.
759 Out << " ";
760 kindType.emitCXXValueTypeName(/*for read*/ false, Out);
761 Out << " " << kindProperty << " = " << kindRule.getReadCode() << ";\n";
762 emitWriteOfProperty(subvar, kindProperty, kindType, kindProperty);
763 }
764
765 // Prepare a ReaderWriterInfo with a helper variable that will use
766 // the sub-reader/writer.
767 ReaderWriterInfo subInfo = info;
768 subInfo.HelperVariable = subvar;
769
770 // Switch on the kind.
771 Out << " switch (" << kindProperty << ") {\n";
772 for (TypeCase typeCase : typeCases.Cases) {
773 Out << " case " << type.getCXXTypeName() << "::"
774 << typeCase.getCaseName() << ": {\n";
775 emitPropertiedReaderWriterBody(typeCase, subInfo);
776 if (!info.IsReader)
777 Out << " return;\n";
778 Out << " }\n\n";
779 }
780 Out << " }\n"
781 " llvm_unreachable(\"bad " << kindType.getCXXTypeName()
782 << "\");\n";
783}
784
785void ASTPropsEmitter::emitBasicReaderWriterFile(const ReaderWriterInfo &info) {
John McCall00bc76e2019-12-15 02:39:13 -0500786 emitDispatcherTemplate(info);
787 emitPackUnpackOptionalTemplate(info);
788 emitBasicReaderWriterTemplate(info);
John McCall6404bd22019-12-13 21:52:16 -0500789}
790
791/// Emit an .inc file that defines some helper classes for reading
792/// basic values.
793void clang::EmitClangBasicReader(RecordKeeper &records, raw_ostream &out) {
794 emitSourceFileHeader("Helper classes for BasicReaders", out);
795
796 // Use any property, we won't be using those properties.
797 auto info = ReaderWriterInfo::forReader<TypeNode>();
John McCall00bc76e2019-12-15 02:39:13 -0500798 ASTPropsEmitter(records, out).emitBasicReaderWriterFile(info);
John McCall6404bd22019-12-13 21:52:16 -0500799}
800
801/// Emit an .inc file that defines some helper classes for writing
802/// basic values.
803void clang::EmitClangBasicWriter(RecordKeeper &records, raw_ostream &out) {
804 emitSourceFileHeader("Helper classes for BasicWriters", out);
805
806 // Use any property, we won't be using those properties.
807 auto info = ReaderWriterInfo::forWriter<TypeNode>();
John McCall00bc76e2019-12-15 02:39:13 -0500808 ASTPropsEmitter(records, out).emitBasicReaderWriterFile(info);
John McCall6404bd22019-12-13 21:52:16 -0500809}