blob: 8dc0e8873382bfcf2e26e8e4c5160bccaa65f119 [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 McCall6887ccf2019-12-16 03:51:16 -0500191 // TODO: we should sort the properties in various ways
192 // - put arrays at the end to enable abbreviations
193 // - put conditional properties after properties used in the condition
194
John McCallefd0dfb2019-12-16 02:10:15 -0500195 visitAllNodesWithInfo(derived, derivedInfo,
196 [&](HasProperties node, const NodeInfo &info) {
John McCall6404bd22019-12-13 21:52:16 -0500197 for (Property prop : info.Properties) {
198 if (ignoredProperties.count(prop.getName()))
199 continue;
200
201 visit(prop);
202 }
John McCallefd0dfb2019-12-16 02:10:15 -0500203 });
204 }
205
206 void visitAllNodesWithInfo(HasProperties derivedNode,
207 const NodeInfo &derivedNodeInfo,
208 llvm::function_ref<void (HasProperties node,
209 const NodeInfo &info)>
210 visit) {
211 visit(derivedNode, derivedNodeInfo);
212
213 // Also walk the bases if appropriate.
214 if (ASTNode base = derivedNode.getAs<ASTNode>()) {
215 for (base = base.getBase(); base; base = base.getBase()) {
216 auto it = NodeInfos.find(base);
217
218 // Ignore intermediate nodes that don't add interesting properties.
219 if (it == NodeInfos.end()) continue;
220 auto &baseInfo = it->second;
221
222 visit(base, baseInfo);
223 }
John McCall6404bd22019-12-13 21:52:16 -0500224 }
225 }
226
227 template <class NodeClass>
John McCallefd0dfb2019-12-16 02:10:15 -0500228 void emitNodeReaderClass() {
John McCall6404bd22019-12-13 21:52:16 -0500229 auto info = ReaderWriterInfo::forReader<NodeClass>();
John McCallefd0dfb2019-12-16 02:10:15 -0500230 emitNodeReaderWriterClass<NodeClass>(info);
John McCall6404bd22019-12-13 21:52:16 -0500231 }
232
233 template <class NodeClass>
John McCallefd0dfb2019-12-16 02:10:15 -0500234 void emitNodeWriterClass() {
John McCall6404bd22019-12-13 21:52:16 -0500235 auto info = ReaderWriterInfo::forWriter<NodeClass>();
John McCallefd0dfb2019-12-16 02:10:15 -0500236 emitNodeReaderWriterClass<NodeClass>(info);
John McCall6404bd22019-12-13 21:52:16 -0500237 }
238
239 template <class NodeClass>
John McCallefd0dfb2019-12-16 02:10:15 -0500240 void emitNodeReaderWriterClass(const ReaderWriterInfo &info);
John McCall6404bd22019-12-13 21:52:16 -0500241
242 template <class NodeClass>
243 void emitNodeReaderWriterMethod(NodeClass node,
244 const ReaderWriterInfo &info);
245
John McCallefd0dfb2019-12-16 02:10:15 -0500246 void emitPropertiedReaderWriterBody(HasProperties node,
247 const ReaderWriterInfo &info);
248
249 void emitReadOfProperty(StringRef readerName, Property property);
250 void emitReadOfProperty(StringRef readerName, StringRef name,
John McCall6887ccf2019-12-16 03:51:16 -0500251 PropertyType type, StringRef condition = "");
John McCallefd0dfb2019-12-16 02:10:15 -0500252
253 void emitWriteOfProperty(StringRef writerName, Property property);
254 void emitWriteOfProperty(StringRef writerName, StringRef name,
John McCall6887ccf2019-12-16 03:51:16 -0500255 PropertyType type, StringRef readCode,
256 StringRef condition = "");
John McCall6404bd22019-12-13 21:52:16 -0500257
John McCall00bc76e2019-12-15 02:39:13 -0500258 void emitBasicReaderWriterFile(const ReaderWriterInfo &info);
259 void emitDispatcherTemplate(const ReaderWriterInfo &info);
260 void emitPackUnpackOptionalTemplate(const ReaderWriterInfo &info);
261 void emitBasicReaderWriterTemplate(const ReaderWriterInfo &info);
262
John McCallefd0dfb2019-12-16 02:10:15 -0500263 void emitCasedReaderWriterMethodBody(PropertyType type,
264 const CasedTypeInfo &typeCases,
265 const ReaderWriterInfo &info);
266
John McCall6404bd22019-12-13 21:52:16 -0500267private:
268 class Validator {
John McCallefd0dfb2019-12-16 02:10:15 -0500269 ASTPropsEmitter &Emitter;
270 std::set<HasProperties> ValidatedNodes;
John McCall6404bd22019-12-13 21:52:16 -0500271
272 public:
John McCallefd0dfb2019-12-16 02:10:15 -0500273 Validator(ASTPropsEmitter &emitter) : Emitter(emitter) {}
John McCall6404bd22019-12-13 21:52:16 -0500274 void validate();
275
276 private:
John McCallefd0dfb2019-12-16 02:10:15 -0500277 void validateNode(HasProperties node, const NodeInfo &nodeInfo);
John McCall6404bd22019-12-13 21:52:16 -0500278 void validateType(PropertyType type, WrappedRecord context);
279 };
280};
281
282} // end anonymous namespace
283
284void ASTPropsEmitter::Validator::validate() {
285 for (auto &entry : Emitter.NodeInfos) {
286 validateNode(entry.first, entry.second);
287 }
288
289 if (ErrorsPrinted > 0) {
290 PrintFatalError("property validation failed");
291 }
292}
293
John McCallefd0dfb2019-12-16 02:10:15 -0500294void ASTPropsEmitter::Validator::validateNode(HasProperties derivedNode,
295 const NodeInfo &derivedNodeInfo) {
296 if (!ValidatedNodes.insert(derivedNode).second) return;
John McCall6404bd22019-12-13 21:52:16 -0500297
298 // A map from property name to property.
299 std::map<StringRef, Property> allProperties;
300
John McCallefd0dfb2019-12-16 02:10:15 -0500301 Emitter.visitAllNodesWithInfo(derivedNode, derivedNodeInfo,
302 [&](HasProperties node,
303 const NodeInfo &nodeInfo) {
304 for (Property property : nodeInfo.Properties) {
John McCall6404bd22019-12-13 21:52:16 -0500305 validateType(property.getType(), property);
306
307 auto result = allProperties.insert(
308 std::make_pair(property.getName(), property));
309
310 // Diagnose non-unique properties.
311 if (!result.second) {
312 // The existing property is more likely to be associated with a
313 // derived node, so use it as the error.
314 Property existingProperty = result.first->second;
315 PrintError(existingProperty.getLoc(),
316 "multiple properties named \"" + property.getName()
John McCallefd0dfb2019-12-16 02:10:15 -0500317 + "\" in hierarchy of " + derivedNode.getName());
John McCall6404bd22019-12-13 21:52:16 -0500318 PrintNote(property.getLoc(), "existing property");
319 }
320 }
John McCallefd0dfb2019-12-16 02:10:15 -0500321 });
John McCall6404bd22019-12-13 21:52:16 -0500322}
323
324void ASTPropsEmitter::Validator::validateType(PropertyType type,
325 WrappedRecord context) {
326 if (!type.isGenericSpecialization()) {
327 if (type.getCXXTypeName() == "") {
328 PrintError(type.getLoc(),
329 "type is not generic but has no C++ type name");
330 if (context) PrintNote(context.getLoc(), "type used here");
331 }
332 } else if (auto eltType = type.getArrayElementType()) {
333 validateType(eltType, context);
334 } else if (auto valueType = type.getOptionalElementType()) {
335 validateType(valueType, context);
336
337 if (valueType.getPackOptionalCode().empty()) {
338 PrintError(valueType.getLoc(),
339 "type doesn't provide optional-packing code");
340 if (context) PrintNote(context.getLoc(), "type used here");
341 } else if (valueType.getUnpackOptionalCode().empty()) {
342 PrintError(valueType.getLoc(),
343 "type doesn't provide optional-unpacking code");
344 if (context) PrintNote(context.getLoc(), "type used here");
345 }
346 } else {
347 PrintError(type.getLoc(), "unknown generic property type");
348 if (context) PrintNote(context.getLoc(), "type used here");
349 }
350}
351
352/****************************************************************************/
353/**************************** AST READER/WRITERS ****************************/
354/****************************************************************************/
355
356template <class NodeClass>
John McCallefd0dfb2019-12-16 02:10:15 -0500357void ASTPropsEmitter::emitNodeReaderWriterClass(const ReaderWriterInfo &info) {
John McCall6404bd22019-12-13 21:52:16 -0500358 StringRef suffix = info.ClassSuffix;
359 StringRef var = info.HelperVariable;
360
361 // Enter the class declaration.
362 Out << "template <class Property" << suffix << ">\n"
363 "class Abstract" << info.HierarchyName << suffix << " {\n"
364 "public:\n"
365 " Property" << suffix << " &" << var << ";\n\n";
366
367 // Emit the constructor.
368 Out << " Abstract" << info.HierarchyName << suffix
369 << "(Property" << suffix << " &" << var << ") : "
370 << var << "(" << var << ") {}\n\n";
371
372 // Emit a method that dispatches on a kind to the appropriate node-specific
373 // method.
374 Out << " " << info.ResultType << " " << info.MethodPrefix << "(";
375 if (info.IsReader)
376 Out << NodeClass::getASTIdTypeName() << " kind";
377 else
378 Out << "const " << info.HierarchyName << " *node";
379 Out << ") {\n"
380 " switch (";
381 if (info.IsReader)
382 Out << "kind";
383 else
384 Out << "node->" << NodeClass::getASTIdAccessorName() << "()";
385 Out << ") {\n";
386 visitASTNodeHierarchy<NodeClass>(Records, [&](NodeClass node, NodeClass _) {
387 if (node.isAbstract()) return;
388 Out << " case " << info.HierarchyName << "::" << node.getId() << ":\n"
389 " return " << info.MethodPrefix << node.getClassName() << "(";
390 if (!info.IsReader)
391 Out << "static_cast<const " << node.getClassName()
392 << " *>(node)";
393 Out << ");\n";
394 });
395 Out << " }\n"
396 " llvm_unreachable(\"bad kind\");\n"
397 " }\n\n";
398
399 // Emit node-specific methods for all the concrete nodes.
400 visitASTNodeHierarchy<NodeClass>(Records,
401 [&](NodeClass node, NodeClass base) {
402 if (node.isAbstract()) return;
403 emitNodeReaderWriterMethod(node, info);
404 });
405
406 // Finish the class.
407 Out << "};\n\n";
408}
409
410/// Emit a reader method for the given concrete AST node class.
411template <class NodeClass>
412void ASTPropsEmitter::emitNodeReaderWriterMethod(NodeClass node,
413 const ReaderWriterInfo &info) {
414 // Declare and start the method.
415 Out << " " << info.ResultType << " "
416 << info.MethodPrefix << node.getClassName() << "(";
417 if (!info.IsReader)
418 Out << "const " << node.getClassName() << " *node";
419 Out << ") {\n";
420 if (info.IsReader)
421 Out << " auto &ctx = " << info.HelperVariable << ".getASTContext();\n";
422
John McCallefd0dfb2019-12-16 02:10:15 -0500423 emitPropertiedReaderWriterBody(node, info);
424
425 // Finish the method declaration.
426 Out << " }\n\n";
427}
428
429void ASTPropsEmitter::emitPropertiedReaderWriterBody(HasProperties node,
430 const ReaderWriterInfo &info) {
John McCall6404bd22019-12-13 21:52:16 -0500431 // Find the information for this node.
432 auto it = NodeInfos.find(node);
433 if (it == NodeInfos.end())
434 PrintFatalError(node.getLoc(),
435 "no information about how to deserialize \""
436 + node.getName() + "\"");
437 auto &nodeInfo = it->second;
438
439 StringRef creationCode;
440 if (info.IsReader) {
441 // We should have a creation rule.
442 if (!nodeInfo.Creator)
443 PrintFatalError(node.getLoc(),
444 "no " CreationRuleClassName " for \""
445 + node.getName() + "\"");
446
447 creationCode = nodeInfo.Creator.getCreationCode();
448 }
449
John McCall256ec992019-12-16 02:56:32 -0500450 // Emit the ReadHelper code, if present.
451 if (!info.IsReader && nodeInfo.ReadHelper) {
452 Out << " " << nodeInfo.ReadHelper.getHelperCode() << "\n";
453 }
454
John McCall6404bd22019-12-13 21:52:16 -0500455 // Emit code to read all the properties.
456 visitAllProperties(node, nodeInfo, [&](Property prop) {
457 // Verify that the creation code refers to this property.
458 if (info.IsReader && creationCode.find(prop.getName()) == StringRef::npos)
459 PrintFatalError(nodeInfo.Creator.getLoc(),
460 "creation code for " + node.getName()
461 + " doesn't refer to property \""
462 + prop.getName() + "\"");
463
464 // Emit code to read or write this property.
465 if (info.IsReader)
John McCallefd0dfb2019-12-16 02:10:15 -0500466 emitReadOfProperty(info.HelperVariable, prop);
John McCall6404bd22019-12-13 21:52:16 -0500467 else
John McCallefd0dfb2019-12-16 02:10:15 -0500468 emitWriteOfProperty(info.HelperVariable, prop);
John McCall6404bd22019-12-13 21:52:16 -0500469 });
470
471 // Emit the final creation code.
472 if (info.IsReader)
473 Out << " " << creationCode << "\n";
John McCall6404bd22019-12-13 21:52:16 -0500474}
475
476static void emitBasicReaderWriterMethodSuffix(raw_ostream &out,
477 PropertyType type,
478 bool isForRead) {
479 if (!type.isGenericSpecialization()) {
480 out << type.getAbstractTypeName();
481 } else if (auto eltType = type.getArrayElementType()) {
482 out << "Array";
483 // We only include an explicit template argument for reads so that
484 // we don't cause spurious const mismatches.
485 if (isForRead) {
486 out << "<";
487 eltType.emitCXXValueTypeName(isForRead, out);
488 out << ">";
489 }
490 } else if (auto valueType = type.getOptionalElementType()) {
491 out << "Optional";
492 // We only include an explicit template argument for reads so that
493 // we don't cause spurious const mismatches.
494 if (isForRead) {
495 out << "<";
496 valueType.emitCXXValueTypeName(isForRead, out);
497 out << ">";
498 }
499 } else {
500 PrintFatalError(type.getLoc(), "unexpected generic property type");
501 }
502}
503
504/// Emit code to read the given property in a node-reader method.
John McCallefd0dfb2019-12-16 02:10:15 -0500505void ASTPropsEmitter::emitReadOfProperty(StringRef readerName,
506 Property property) {
John McCall6887ccf2019-12-16 03:51:16 -0500507 emitReadOfProperty(readerName, property.getName(), property.getType(),
508 property.getCondition());
John McCallefd0dfb2019-12-16 02:10:15 -0500509}
John McCall6404bd22019-12-13 21:52:16 -0500510
John McCallefd0dfb2019-12-16 02:10:15 -0500511void ASTPropsEmitter::emitReadOfProperty(StringRef readerName,
512 StringRef name,
John McCall6887ccf2019-12-16 03:51:16 -0500513 PropertyType type,
514 StringRef condition) {
John McCall6404bd22019-12-13 21:52:16 -0500515 // Declare all the necessary buffers.
516 auto bufferTypes = type.getBufferElementTypes();
517 for (size_t i = 0, e = bufferTypes.size(); i != e; ++i) {
518 Out << " llvm::SmallVector<";
519 PropertyType(bufferTypes[i]).emitCXXValueTypeName(/*for read*/ true, Out);
520 Out << ", 8> " << name << "_buffer_" << i << ";\n";
521 }
522
523 // T prop = R.find("prop").read##ValueType(buffers...);
524 // We intentionally ignore shouldPassByReference here: we're going to
525 // get a pr-value back from read(), and we should be able to forward
526 // that in the creation rule.
527 Out << " ";
John McCall6887ccf2019-12-16 03:51:16 -0500528 if (!condition.empty()) Out << "llvm::Optional<";
John McCall6404bd22019-12-13 21:52:16 -0500529 type.emitCXXValueTypeName(true, Out);
John McCall6887ccf2019-12-16 03:51:16 -0500530 if (!condition.empty()) Out << ">";
531 Out << " " << name;
532
533 if (condition.empty()) {
534 Out << " = ";
535 } else {
536 Out << ";\n"
537 " if (" << condition << ") {\n"
538 " " << name << ".emplace(";
539 }
540
541 Out << readerName << ".find(\"" << name << "\")."
John McCall6404bd22019-12-13 21:52:16 -0500542 << (type.isGenericSpecialization() ? "template " : "") << "read";
543 emitBasicReaderWriterMethodSuffix(Out, type, /*for read*/ true);
544 Out << "(";
545 for (size_t i = 0, e = bufferTypes.size(); i != e; ++i) {
546 Out << (i > 0 ? ", " : "") << name << "_buffer_" << i;
547 }
John McCall6887ccf2019-12-16 03:51:16 -0500548 Out << ")";
549
550 if (condition.empty()) {
551 Out << ";\n";
552 } else {
553 Out << ");\n"
554 " }\n";
555 }
John McCall6404bd22019-12-13 21:52:16 -0500556}
557
558/// Emit code to write the given property in a node-writer method.
John McCallefd0dfb2019-12-16 02:10:15 -0500559void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName,
560 Property property) {
561 emitWriteOfProperty(writerName, property.getName(), property.getType(),
John McCall6887ccf2019-12-16 03:51:16 -0500562 property.getReadCode(), property.getCondition());
John McCallefd0dfb2019-12-16 02:10:15 -0500563}
564
565void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName,
566 StringRef name,
567 PropertyType type,
John McCall6887ccf2019-12-16 03:51:16 -0500568 StringRef readCode,
569 StringRef condition) {
570 if (!condition.empty()) {
571 Out << " if (" << condition << ") {\n";
572 }
573
John McCall6404bd22019-12-13 21:52:16 -0500574 // Focus down to the property:
John McCall6887ccf2019-12-16 03:51:16 -0500575 // T prop = <READ>;
576 // W.find("prop").write##ValueType(prop);
577 Out << " ";
578 type.emitCXXValueTypeName(false, Out);
579 Out << " " << name << " = (" << readCode << ");\n"
580 " " << writerName << ".find(\"" << name << "\").write";
John McCallefd0dfb2019-12-16 02:10:15 -0500581 emitBasicReaderWriterMethodSuffix(Out, type, /*for read*/ false);
John McCall6887ccf2019-12-16 03:51:16 -0500582 Out << "(" << name << ");\n";
583
584 if (!condition.empty()) {
585 Out << " }\n";
586 }
John McCall6404bd22019-12-13 21:52:16 -0500587}
588
589/// Emit an .inc file that defines the AbstractFooReader class
590/// for the given AST class hierarchy.
591template <class NodeClass>
592static void emitASTReader(RecordKeeper &records, raw_ostream &out,
593 StringRef description) {
594 emitSourceFileHeader(description, out);
595
John McCallefd0dfb2019-12-16 02:10:15 -0500596 ASTPropsEmitter(records, out).emitNodeReaderClass<NodeClass>();
John McCall6404bd22019-12-13 21:52:16 -0500597}
598
599void clang::EmitClangTypeReader(RecordKeeper &records, raw_ostream &out) {
600 emitASTReader<TypeNode>(records, out, "A CRTP reader for Clang Type nodes");
601}
602
603/// Emit an .inc file that defines the AbstractFooWriter class
604/// for the given AST class hierarchy.
605template <class NodeClass>
606static void emitASTWriter(RecordKeeper &records, raw_ostream &out,
607 StringRef description) {
608 emitSourceFileHeader(description, out);
609
John McCallefd0dfb2019-12-16 02:10:15 -0500610 ASTPropsEmitter(records, out).emitNodeWriterClass<NodeClass>();
John McCall6404bd22019-12-13 21:52:16 -0500611}
612
613void clang::EmitClangTypeWriter(RecordKeeper &records, raw_ostream &out) {
614 emitASTWriter<TypeNode>(records, out, "A CRTP writer for Clang Type nodes");
615}
616
617/****************************************************************************/
618/*************************** BASIC READER/WRITERS ***************************/
619/****************************************************************************/
620
John McCall00bc76e2019-12-15 02:39:13 -0500621void
622ASTPropsEmitter::emitDispatcherTemplate(const ReaderWriterInfo &info) {
John McCall6404bd22019-12-13 21:52:16 -0500623 // Declare the {Read,Write}Dispatcher template.
624 StringRef dispatcherPrefix = (info.IsReader ? "Read" : "Write");
John McCall00bc76e2019-12-15 02:39:13 -0500625 Out << "template <class ValueType>\n"
John McCall6404bd22019-12-13 21:52:16 -0500626 "struct " << dispatcherPrefix << "Dispatcher;\n";
627
628 // Declare a specific specialization of the dispatcher template.
629 auto declareSpecialization =
630 [&](StringRef specializationParameters,
631 const Twine &cxxTypeName,
632 StringRef methodSuffix) {
633 StringRef var = info.HelperVariable;
John McCall00bc76e2019-12-15 02:39:13 -0500634 Out << "template " << specializationParameters << "\n"
John McCall6404bd22019-12-13 21:52:16 -0500635 "struct " << dispatcherPrefix << "Dispatcher<"
636 << cxxTypeName << "> {\n";
John McCall00bc76e2019-12-15 02:39:13 -0500637 Out << " template <class Basic" << info.ClassSuffix << ", class... Args>\n"
John McCall6404bd22019-12-13 21:52:16 -0500638 " static " << (info.IsReader ? cxxTypeName : "void") << " "
639 << info.MethodPrefix
640 << "(Basic" << info.ClassSuffix << " &" << var
641 << ", Args &&... args) {\n"
642 " return " << var << "."
643 << info.MethodPrefix << methodSuffix
644 << "(std::forward<Args>(args)...);\n"
645 " }\n"
646 "};\n";
647 };
648
649 // Declare explicit specializations for each of the concrete types.
John McCall00bc76e2019-12-15 02:39:13 -0500650 for (PropertyType type : AllPropertyTypes) {
John McCall6404bd22019-12-13 21:52:16 -0500651 declareSpecialization("<>",
652 type.getCXXTypeName(),
653 type.getAbstractTypeName());
654 // Also declare a specialization for the const type when appropriate.
655 if (!info.IsReader && type.isConstWhenWriting()) {
656 declareSpecialization("<>",
657 "const " + type.getCXXTypeName(),
658 type.getAbstractTypeName());
659 }
660 }
661 // Declare partial specializations for ArrayRef and Optional.
662 declareSpecialization("<class T>",
663 "llvm::ArrayRef<T>",
664 "Array");
665 declareSpecialization("<class T>",
666 "llvm::Optional<T>",
667 "Optional");
John McCall00bc76e2019-12-15 02:39:13 -0500668 Out << "\n";
John McCall6404bd22019-12-13 21:52:16 -0500669}
670
John McCall00bc76e2019-12-15 02:39:13 -0500671void
672ASTPropsEmitter::emitPackUnpackOptionalTemplate(const ReaderWriterInfo &info) {
John McCall6404bd22019-12-13 21:52:16 -0500673 StringRef classPrefix = (info.IsReader ? "Unpack" : "Pack");
674 StringRef methodName = (info.IsReader ? "unpack" : "pack");
675
676 // Declare the {Pack,Unpack}OptionalValue template.
John McCall00bc76e2019-12-15 02:39:13 -0500677 Out << "template <class ValueType>\n"
John McCall6404bd22019-12-13 21:52:16 -0500678 "struct " << classPrefix << "OptionalValue;\n";
679
680 auto declareSpecialization = [&](const Twine &typeName,
681 StringRef code) {
John McCall00bc76e2019-12-15 02:39:13 -0500682 Out << "template <>\n"
John McCall6404bd22019-12-13 21:52:16 -0500683 "struct " << classPrefix << "OptionalValue<" << typeName << "> {\n"
684 " static " << (info.IsReader ? "Optional<" : "") << typeName
685 << (info.IsReader ? "> " : " ") << methodName << "("
686 << (info.IsReader ? "" : "Optional<") << typeName
687 << (info.IsReader ? "" : ">") << " value) {\n"
688 " return " << code << ";\n"
689 " }\n"
690 "};\n";
691 };
692
John McCall00bc76e2019-12-15 02:39:13 -0500693 for (PropertyType type : AllPropertyTypes) {
John McCall6404bd22019-12-13 21:52:16 -0500694 StringRef code = (info.IsReader ? type.getUnpackOptionalCode()
695 : type.getPackOptionalCode());
696 if (code.empty()) continue;
697
698 StringRef typeName = type.getCXXTypeName();
699 declareSpecialization(typeName, code);
700 if (type.isConstWhenWriting() && !info.IsReader)
701 declareSpecialization("const " + typeName, code);
702 }
John McCall00bc76e2019-12-15 02:39:13 -0500703 Out << "\n";
John McCall6404bd22019-12-13 21:52:16 -0500704}
705
John McCall00bc76e2019-12-15 02:39:13 -0500706void
707ASTPropsEmitter::emitBasicReaderWriterTemplate(const ReaderWriterInfo &info) {
John McCall6404bd22019-12-13 21:52:16 -0500708 // Emit the Basic{Reader,Writer}Base template.
John McCall00bc76e2019-12-15 02:39:13 -0500709 Out << "template <class Impl>\n"
John McCall6404bd22019-12-13 21:52:16 -0500710 "class Basic" << info.ClassSuffix << "Base {\n";
711 if (info.IsReader)
John McCall00bc76e2019-12-15 02:39:13 -0500712 Out << " ASTContext &C;\n";
713 Out << "protected:\n"
John McCall6404bd22019-12-13 21:52:16 -0500714 " Basic" << info.ClassSuffix << "Base"
715 << (info.IsReader ? "(ASTContext &ctx) : C(ctx)" : "()")
716 << " {}\n"
717 "public:\n";
718 if (info.IsReader)
John McCall00bc76e2019-12-15 02:39:13 -0500719 Out << " ASTContext &getASTContext() { return C; }\n";
720 Out << " Impl &asImpl() { return static_cast<Impl&>(*this); }\n";
John McCall6404bd22019-12-13 21:52:16 -0500721
722 auto enterReaderWriterMethod = [&](StringRef cxxTypeName,
723 StringRef abstractTypeName,
724 bool shouldPassByReference,
John McCallefd0dfb2019-12-16 02:10:15 -0500725 bool constWhenWriting,
726 StringRef paramName) {
John McCall00bc76e2019-12-15 02:39:13 -0500727 Out << " " << (info.IsReader ? cxxTypeName : "void")
John McCall6404bd22019-12-13 21:52:16 -0500728 << " " << info.MethodPrefix << abstractTypeName << "(";
729 if (!info.IsReader)
John McCall00bc76e2019-12-15 02:39:13 -0500730 Out << (shouldPassByReference || constWhenWriting ? "const " : "")
John McCall6404bd22019-12-13 21:52:16 -0500731 << cxxTypeName
John McCallefd0dfb2019-12-16 02:10:15 -0500732 << (shouldPassByReference ? " &" : "") << " " << paramName;
John McCall00bc76e2019-12-15 02:39:13 -0500733 Out << ") {\n";
John McCall6404bd22019-12-13 21:52:16 -0500734 };
735
736 // Emit {read,write}ValueType methods for all the enum and subclass types
737 // that default to using the integer/base-class implementations.
John McCall00bc76e2019-12-15 02:39:13 -0500738 for (PropertyType type : AllPropertyTypes) {
John McCallefd0dfb2019-12-16 02:10:15 -0500739 auto enterMethod = [&](StringRef paramName) {
John McCall6404bd22019-12-13 21:52:16 -0500740 enterReaderWriterMethod(type.getCXXTypeName(),
741 type.getAbstractTypeName(),
John McCallefd0dfb2019-12-16 02:10:15 -0500742 type.shouldPassByReference(),
743 type.isConstWhenWriting(),
744 paramName);
745 };
746 auto exitMethod = [&] {
747 Out << " }\n";
748 };
749
750 // Handled cased types.
751 auto casedIter = CasedTypeInfos.find(type);
752 if (casedIter != CasedTypeInfos.end()) {
753 enterMethod("node");
754 emitCasedReaderWriterMethodBody(type, casedIter->second, info);
755 exitMethod();
756
757 } else if (type.isEnum()) {
758 enterMethod("value");
John McCall6404bd22019-12-13 21:52:16 -0500759 if (info.IsReader)
John McCall00bc76e2019-12-15 02:39:13 -0500760 Out << " return " << type.getCXXTypeName()
John McCall6404bd22019-12-13 21:52:16 -0500761 << "(asImpl().readUInt32());\n";
762 else
John McCall00bc76e2019-12-15 02:39:13 -0500763 Out << " asImpl().writeUInt32(uint32_t(value));\n";
John McCallefd0dfb2019-12-16 02:10:15 -0500764 exitMethod();
765
John McCall6404bd22019-12-13 21:52:16 -0500766 } else if (PropertyType superclass = type.getSuperclassType()) {
John McCallefd0dfb2019-12-16 02:10:15 -0500767 enterMethod("value");
John McCall6404bd22019-12-13 21:52:16 -0500768 if (info.IsReader)
John McCall00bc76e2019-12-15 02:39:13 -0500769 Out << " return cast_or_null<" << type.getSubclassClassName()
John McCall6404bd22019-12-13 21:52:16 -0500770 << ">(asImpl().read"
771 << superclass.getAbstractTypeName()
772 << "());\n";
773 else
John McCall00bc76e2019-12-15 02:39:13 -0500774 Out << " asImpl().write" << superclass.getAbstractTypeName()
John McCall6404bd22019-12-13 21:52:16 -0500775 << "(value);\n";
John McCallefd0dfb2019-12-16 02:10:15 -0500776 exitMethod();
777
John McCall6404bd22019-12-13 21:52:16 -0500778 } else {
779 // The other types can't be handled as trivially.
780 }
781 }
John McCall00bc76e2019-12-15 02:39:13 -0500782 Out << "};\n\n";
John McCall6404bd22019-12-13 21:52:16 -0500783}
784
John McCallefd0dfb2019-12-16 02:10:15 -0500785void ASTPropsEmitter::emitCasedReaderWriterMethodBody(PropertyType type,
786 const CasedTypeInfo &typeCases,
787 const ReaderWriterInfo &info) {
788 if (typeCases.Cases.empty()) {
789 assert(typeCases.KindRule);
790 PrintFatalError(typeCases.KindRule.getLoc(),
791 "no cases found for \"" + type.getCXXTypeName() + "\"");
792 }
793 if (!typeCases.KindRule) {
794 assert(!typeCases.Cases.empty());
795 PrintFatalError(typeCases.Cases.front().getLoc(),
796 "no kind rule for \"" + type.getCXXTypeName() + "\"");
797 }
John McCall6404bd22019-12-13 21:52:16 -0500798
John McCallefd0dfb2019-12-16 02:10:15 -0500799 auto var = info.HelperVariable;
800 std::string subvar = ("sub" + var).str();
801
802 // Bind `ctx` for readers.
803 if (info.IsReader)
804 Out << " auto &ctx = asImpl().getASTContext();\n";
805
806 // Start an object.
807 Out << " auto &&" << subvar << " = asImpl()."
808 << info.MethodPrefix << "Object();\n";
809
810 // Read/write the kind property;
811 TypeKindRule kindRule = typeCases.KindRule;
812 StringRef kindProperty = kindRule.getKindPropertyName();
813 PropertyType kindType = kindRule.getKindType();
814 if (info.IsReader) {
815 emitReadOfProperty(subvar, kindProperty, kindType);
816 } else {
John McCall6887ccf2019-12-16 03:51:16 -0500817 // Write the property. Note that this will implicitly read the
818 // kind into a local variable with the right name.
819 emitWriteOfProperty(subvar, kindProperty, kindType,
820 kindRule.getReadCode());
John McCallefd0dfb2019-12-16 02:10:15 -0500821 }
822
823 // Prepare a ReaderWriterInfo with a helper variable that will use
824 // the sub-reader/writer.
825 ReaderWriterInfo subInfo = info;
826 subInfo.HelperVariable = subvar;
827
828 // Switch on the kind.
829 Out << " switch (" << kindProperty << ") {\n";
830 for (TypeCase typeCase : typeCases.Cases) {
831 Out << " case " << type.getCXXTypeName() << "::"
832 << typeCase.getCaseName() << ": {\n";
833 emitPropertiedReaderWriterBody(typeCase, subInfo);
834 if (!info.IsReader)
835 Out << " return;\n";
836 Out << " }\n\n";
837 }
838 Out << " }\n"
839 " llvm_unreachable(\"bad " << kindType.getCXXTypeName()
840 << "\");\n";
841}
842
843void ASTPropsEmitter::emitBasicReaderWriterFile(const ReaderWriterInfo &info) {
John McCall00bc76e2019-12-15 02:39:13 -0500844 emitDispatcherTemplate(info);
845 emitPackUnpackOptionalTemplate(info);
846 emitBasicReaderWriterTemplate(info);
John McCall6404bd22019-12-13 21:52:16 -0500847}
848
849/// Emit an .inc file that defines some helper classes for reading
850/// basic values.
851void clang::EmitClangBasicReader(RecordKeeper &records, raw_ostream &out) {
852 emitSourceFileHeader("Helper classes for BasicReaders", out);
853
854 // Use any property, we won't be using those properties.
855 auto info = ReaderWriterInfo::forReader<TypeNode>();
John McCall00bc76e2019-12-15 02:39:13 -0500856 ASTPropsEmitter(records, out).emitBasicReaderWriterFile(info);
John McCall6404bd22019-12-13 21:52:16 -0500857}
858
859/// Emit an .inc file that defines some helper classes for writing
860/// basic values.
861void clang::EmitClangBasicWriter(RecordKeeper &records, raw_ostream &out) {
862 emitSourceFileHeader("Helper classes for BasicWriters", out);
863
864 // Use any property, we won't be using those properties.
865 auto info = ReaderWriterInfo::forWriter<TypeNode>();
John McCall00bc76e2019-12-15 02:39:13 -0500866 ASTPropsEmitter(records, out).emitBasicReaderWriterFile(info);
John McCall6404bd22019-12-13 21:52:16 -0500867}