xref: /freebsd/contrib/llvm-project/clang/utils/TableGen/ClangASTPropertiesEmitter.cpp (revision 6be3386466ab79a84b48429ae66244f21526d3df)
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 
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>
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 
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:
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 
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 
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>
228   void emitNodeReaderClass() {
229     auto info = ReaderWriterInfo::forReader<NodeClass>();
230     emitNodeReaderWriterClass<NodeClass>(info);
231   }
232 
233   template <class NodeClass>
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:
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 
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 
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 
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>
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>
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 
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 
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.
505 void ASTPropsEmitter::emitReadOfProperty(StringRef readerName,
506                                          Property property) {
507   emitReadOfProperty(readerName, property.getName(), property.getType(),
508                      property.getCondition());
509 }
510 
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.
559 void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName,
560                                           Property property) {
561   emitWriteOfProperty(writerName, property.getName(), property.getType(),
562                       property.getReadCode(), property.getCondition());
563 }
564 
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>
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 
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>
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 
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
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
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
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 
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 
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.
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.
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