1 //=== 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>
25 using namespace llvm;
26 using namespace clang;
27 using namespace clang::tblgen;
28
getReaderResultType(TypeNode _)29 static StringRef getReaderResultType(TypeNode _) { return "QualType"; }
30
31 namespace {
32
33 struct 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>
forReader__anonc5b9aba90111::ReaderWriterInfo53 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>
forWriter__anonc5b9aba90111::ReaderWriterInfo65 static ReaderWriterInfo forWriter() {
66 return ReaderWriterInfo{
67 false,
68 NodeClass::getASTHierarchyName(),
69 "Writer",
70 "write",
71 "W",
72 "void"
73 };
74 }
75 };
76
77 struct NodeInfo {
78 std::vector<Property> Properties;
79 CreationRule Creator = nullptr;
80 OverrideRule Override = nullptr;
81 ReadHelperRule ReadHelper = nullptr;
82 };
83
84 struct CasedTypeInfo {
85 TypeKindRule KindRule;
86 std::vector<TypeCase> Cases;
87 };
88
89 class ASTPropsEmitter {
90 raw_ostream &Out;
91 RecordKeeper &Records;
92 std::map<HasProperties, NodeInfo> NodeInfos;
93 std::vector<PropertyType> AllPropertyTypes;
94 std::map<PropertyType, CasedTypeInfo> CasedTypeInfos;
95
96 public:
ASTPropsEmitter(RecordKeeper & records,raw_ostream & out)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)) {
103 HasProperties node = property.getClass();
104 NodeInfos[node].Properties.push_back(property);
105 }
106
107 // Find all the creation rules.
108 for (CreationRule creationRule :
109 records.getAllDerivedDefinitions(CreationRuleClassName)) {
110 HasProperties node = creationRule.getClass();
111
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)) {
124 HasProperties node = overrideRule.getClass();
125
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
135 // 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
149 // Find all the concrete property types.
150 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
159 // 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
178 Validator(*this).validate();
179 }
180
visitAllProperties(HasProperties derived,const NodeInfo & derivedInfo,function_ref<void (Property)> visit)181 void visitAllProperties(HasProperties derived, const NodeInfo &derivedInfo,
182 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
191 // 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
195 visitAllNodesWithInfo(derived, derivedInfo,
196 [&](HasProperties node, const NodeInfo &info) {
197 for (Property prop : info.Properties) {
198 if (ignoredProperties.count(prop.getName()))
199 continue;
200
201 visit(prop);
202 }
203 });
204 }
205
visitAllNodesWithInfo(HasProperties derivedNode,const NodeInfo & derivedNodeInfo,llvm::function_ref<void (HasProperties node,const NodeInfo & info)> visit)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 }
224 }
225 }
226
227 template <class NodeClass>
emitNodeReaderClass()228 void emitNodeReaderClass() {
229 auto info = ReaderWriterInfo::forReader<NodeClass>();
230 emitNodeReaderWriterClass<NodeClass>(info);
231 }
232
233 template <class NodeClass>
emitNodeWriterClass()234 void emitNodeWriterClass() {
235 auto info = ReaderWriterInfo::forWriter<NodeClass>();
236 emitNodeReaderWriterClass<NodeClass>(info);
237 }
238
239 template <class NodeClass>
240 void emitNodeReaderWriterClass(const ReaderWriterInfo &info);
241
242 template <class NodeClass>
243 void emitNodeReaderWriterMethod(NodeClass node,
244 const ReaderWriterInfo &info);
245
246 void emitPropertiedReaderWriterBody(HasProperties node,
247 const ReaderWriterInfo &info);
248
249 void emitReadOfProperty(StringRef readerName, Property property);
250 void emitReadOfProperty(StringRef readerName, StringRef name,
251 PropertyType type, StringRef condition = "");
252
253 void emitWriteOfProperty(StringRef writerName, Property property);
254 void emitWriteOfProperty(StringRef writerName, StringRef name,
255 PropertyType type, StringRef readCode,
256 StringRef condition = "");
257
258 void emitBasicReaderWriterFile(const ReaderWriterInfo &info);
259 void emitDispatcherTemplate(const ReaderWriterInfo &info);
260 void emitPackUnpackOptionalTemplate(const ReaderWriterInfo &info);
261 void emitBasicReaderWriterTemplate(const ReaderWriterInfo &info);
262
263 void emitCasedReaderWriterMethodBody(PropertyType type,
264 const CasedTypeInfo &typeCases,
265 const ReaderWriterInfo &info);
266
267 private:
268 class Validator {
269 ASTPropsEmitter &Emitter;
270 std::set<HasProperties> ValidatedNodes;
271
272 public:
Validator(ASTPropsEmitter & emitter)273 Validator(ASTPropsEmitter &emitter) : Emitter(emitter) {}
274 void validate();
275
276 private:
277 void validateNode(HasProperties node, const NodeInfo &nodeInfo);
278 void validateType(PropertyType type, WrappedRecord context);
279 };
280 };
281
282 } // end anonymous namespace
283
validate()284 void 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
validateNode(HasProperties derivedNode,const NodeInfo & derivedNodeInfo)294 void ASTPropsEmitter::Validator::validateNode(HasProperties derivedNode,
295 const NodeInfo &derivedNodeInfo) {
296 if (!ValidatedNodes.insert(derivedNode).second) return;
297
298 // A map from property name to property.
299 std::map<StringRef, Property> allProperties;
300
301 Emitter.visitAllNodesWithInfo(derivedNode, derivedNodeInfo,
302 [&](HasProperties node,
303 const NodeInfo &nodeInfo) {
304 for (Property property : nodeInfo.Properties) {
305 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()
317 + "\" in hierarchy of " + derivedNode.getName());
318 PrintNote(property.getLoc(), "existing property");
319 }
320 }
321 });
322 }
323
validateType(PropertyType type,WrappedRecord context)324 void 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
356 template <class NodeClass>
emitNodeReaderWriterClass(const ReaderWriterInfo & info)357 void ASTPropsEmitter::emitNodeReaderWriterClass(const ReaderWriterInfo &info) {
358 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.
411 template <class NodeClass>
emitNodeReaderWriterMethod(NodeClass node,const ReaderWriterInfo & info)412 void 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
423 emitPropertiedReaderWriterBody(node, info);
424
425 // Finish the method declaration.
426 Out << " }\n\n";
427 }
428
emitPropertiedReaderWriterBody(HasProperties node,const ReaderWriterInfo & info)429 void ASTPropsEmitter::emitPropertiedReaderWriterBody(HasProperties node,
430 const ReaderWriterInfo &info) {
431 // 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
450 // Emit the ReadHelper code, if present.
451 if (!info.IsReader && nodeInfo.ReadHelper) {
452 Out << " " << nodeInfo.ReadHelper.getHelperCode() << "\n";
453 }
454
455 // 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)
466 emitReadOfProperty(info.HelperVariable, prop);
467 else
468 emitWriteOfProperty(info.HelperVariable, prop);
469 });
470
471 // Emit the final creation code.
472 if (info.IsReader)
473 Out << " " << creationCode << "\n";
474 }
475
emitBasicReaderWriterMethodSuffix(raw_ostream & out,PropertyType type,bool isForRead)476 static 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.
emitReadOfProperty(StringRef readerName,Property property)505 void ASTPropsEmitter::emitReadOfProperty(StringRef readerName,
506 Property property) {
507 emitReadOfProperty(readerName, property.getName(), property.getType(),
508 property.getCondition());
509 }
510
emitReadOfProperty(StringRef readerName,StringRef name,PropertyType type,StringRef condition)511 void ASTPropsEmitter::emitReadOfProperty(StringRef readerName,
512 StringRef name,
513 PropertyType type,
514 StringRef condition) {
515 // 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 << " ";
528 if (!condition.empty()) Out << "llvm::Optional<";
529 type.emitCXXValueTypeName(true, Out);
530 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 << "\")."
542 << (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 }
548 Out << ")";
549
550 if (condition.empty()) {
551 Out << ";\n";
552 } else {
553 Out << ");\n"
554 " }\n";
555 }
556 }
557
558 /// Emit code to write the given property in a node-writer method.
emitWriteOfProperty(StringRef writerName,Property property)559 void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName,
560 Property property) {
561 emitWriteOfProperty(writerName, property.getName(), property.getType(),
562 property.getReadCode(), property.getCondition());
563 }
564
emitWriteOfProperty(StringRef writerName,StringRef name,PropertyType type,StringRef readCode,StringRef condition)565 void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName,
566 StringRef name,
567 PropertyType type,
568 StringRef readCode,
569 StringRef condition) {
570 if (!condition.empty()) {
571 Out << " if (" << condition << ") {\n";
572 }
573
574 // Focus down to the property:
575 // 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";
581 emitBasicReaderWriterMethodSuffix(Out, type, /*for read*/ false);
582 Out << "(" << name << ");\n";
583
584 if (!condition.empty()) {
585 Out << " }\n";
586 }
587 }
588
589 /// Emit an .inc file that defines the AbstractFooReader class
590 /// for the given AST class hierarchy.
591 template <class NodeClass>
emitASTReader(RecordKeeper & records,raw_ostream & out,StringRef description)592 static void emitASTReader(RecordKeeper &records, raw_ostream &out,
593 StringRef description) {
594 emitSourceFileHeader(description, out);
595
596 ASTPropsEmitter(records, out).emitNodeReaderClass<NodeClass>();
597 }
598
EmitClangTypeReader(RecordKeeper & records,raw_ostream & out)599 void 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.
605 template <class NodeClass>
emitASTWriter(RecordKeeper & records,raw_ostream & out,StringRef description)606 static void emitASTWriter(RecordKeeper &records, raw_ostream &out,
607 StringRef description) {
608 emitSourceFileHeader(description, out);
609
610 ASTPropsEmitter(records, out).emitNodeWriterClass<NodeClass>();
611 }
612
EmitClangTypeWriter(RecordKeeper & records,raw_ostream & out)613 void 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
621 void
emitDispatcherTemplate(const ReaderWriterInfo & info)622 ASTPropsEmitter::emitDispatcherTemplate(const ReaderWriterInfo &info) {
623 // Declare the {Read,Write}Dispatcher template.
624 StringRef dispatcherPrefix = (info.IsReader ? "Read" : "Write");
625 Out << "template <class ValueType>\n"
626 "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;
634 Out << "template " << specializationParameters << "\n"
635 "struct " << dispatcherPrefix << "Dispatcher<"
636 << cxxTypeName << "> {\n";
637 Out << " template <class Basic" << info.ClassSuffix << ", class... Args>\n"
638 " 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.
650 for (PropertyType type : AllPropertyTypes) {
651 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");
668 Out << "\n";
669 }
670
671 void
emitPackUnpackOptionalTemplate(const ReaderWriterInfo & info)672 ASTPropsEmitter::emitPackUnpackOptionalTemplate(const ReaderWriterInfo &info) {
673 StringRef classPrefix = (info.IsReader ? "Unpack" : "Pack");
674 StringRef methodName = (info.IsReader ? "unpack" : "pack");
675
676 // Declare the {Pack,Unpack}OptionalValue template.
677 Out << "template <class ValueType>\n"
678 "struct " << classPrefix << "OptionalValue;\n";
679
680 auto declareSpecialization = [&](const Twine &typeName,
681 StringRef code) {
682 Out << "template <>\n"
683 "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
693 for (PropertyType type : AllPropertyTypes) {
694 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 }
703 Out << "\n";
704 }
705
706 void
emitBasicReaderWriterTemplate(const ReaderWriterInfo & info)707 ASTPropsEmitter::emitBasicReaderWriterTemplate(const ReaderWriterInfo &info) {
708 // Emit the Basic{Reader,Writer}Base template.
709 Out << "template <class Impl>\n"
710 "class Basic" << info.ClassSuffix << "Base {\n";
711 if (info.IsReader)
712 Out << " ASTContext &C;\n";
713 Out << "protected:\n"
714 " Basic" << info.ClassSuffix << "Base"
715 << (info.IsReader ? "(ASTContext &ctx) : C(ctx)" : "()")
716 << " {}\n"
717 "public:\n";
718 if (info.IsReader)
719 Out << " ASTContext &getASTContext() { return C; }\n";
720 Out << " Impl &asImpl() { return static_cast<Impl&>(*this); }\n";
721
722 auto enterReaderWriterMethod = [&](StringRef cxxTypeName,
723 StringRef abstractTypeName,
724 bool shouldPassByReference,
725 bool constWhenWriting,
726 StringRef paramName) {
727 Out << " " << (info.IsReader ? cxxTypeName : "void")
728 << " " << info.MethodPrefix << abstractTypeName << "(";
729 if (!info.IsReader)
730 Out << (shouldPassByReference || constWhenWriting ? "const " : "")
731 << cxxTypeName
732 << (shouldPassByReference ? " &" : "") << " " << paramName;
733 Out << ") {\n";
734 };
735
736 // Emit {read,write}ValueType methods for all the enum and subclass types
737 // that default to using the integer/base-class implementations.
738 for (PropertyType type : AllPropertyTypes) {
739 auto enterMethod = [&](StringRef paramName) {
740 enterReaderWriterMethod(type.getCXXTypeName(),
741 type.getAbstractTypeName(),
742 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");
759 if (info.IsReader)
760 Out << " return asImpl().template readEnum<"
761 << type.getCXXTypeName() << ">();\n";
762 else
763 Out << " asImpl().writeEnum(value);\n";
764 exitMethod();
765
766 } else if (PropertyType superclass = type.getSuperclassType()) {
767 enterMethod("value");
768 if (info.IsReader)
769 Out << " return cast_or_null<" << type.getSubclassClassName()
770 << ">(asImpl().read"
771 << superclass.getAbstractTypeName()
772 << "());\n";
773 else
774 Out << " asImpl().write" << superclass.getAbstractTypeName()
775 << "(value);\n";
776 exitMethod();
777
778 } else {
779 // The other types can't be handled as trivially.
780 }
781 }
782 Out << "};\n\n";
783 }
784
emitCasedReaderWriterMethodBody(PropertyType type,const CasedTypeInfo & typeCases,const ReaderWriterInfo & info)785 void 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 }
798
799 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 {
817 // 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());
821 }
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
emitBasicReaderWriterFile(const ReaderWriterInfo & info)843 void ASTPropsEmitter::emitBasicReaderWriterFile(const ReaderWriterInfo &info) {
844 emitDispatcherTemplate(info);
845 emitPackUnpackOptionalTemplate(info);
846 emitBasicReaderWriterTemplate(info);
847 }
848
849 /// Emit an .inc file that defines some helper classes for reading
850 /// basic values.
EmitClangBasicReader(RecordKeeper & records,raw_ostream & out)851 void 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>();
856 ASTPropsEmitter(records, out).emitBasicReaderWriterFile(info);
857 }
858
859 /// Emit an .inc file that defines some helper classes for writing
860 /// basic values.
EmitClangBasicWriter(RecordKeeper & records,raw_ostream & out)861 void 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>();
866 ASTPropsEmitter(records, out).emitBasicReaderWriterFile(info);
867 }
868