1 //=== ClangASTPropsEmitter.cpp - Generate Clang AST properties --*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // This tablegen backend emits code for working with Clang AST properties.
11 //===----------------------------------------------------------------------===//
13 #include "ASTTableGen.h"
14 #include "TableGenBackends.h"
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"
26 using namespace clang;
27 using namespace clang::tblgen;
29 static StringRef getReaderResultType(TypeNode _) { return "QualType"; }
33 struct ReaderWriterInfo {
36 /// The name of the node hierarchy. Not actually sensitive to IsReader,
37 /// but useful to cache here anyway.
38 StringRef HierarchyName;
40 /// The suffix on classes: Reader/Writer
41 StringRef ClassSuffix;
43 /// The base name of methods: read/write
44 StringRef MethodPrefix;
46 /// The name of the property helper member: R/W
47 StringRef HelperVariable;
49 /// The result type of methods on the class.
52 template <class NodeClass>
53 static ReaderWriterInfo forReader() {
54 return ReaderWriterInfo{
56 NodeClass::getASTHierarchyName(),
60 getReaderResultType(NodeClass())
64 template <class NodeClass>
65 static ReaderWriterInfo forWriter() {
66 return ReaderWriterInfo{
68 NodeClass::getASTHierarchyName(),
78 std::vector<Property> Properties;
79 CreationRule Creator = nullptr;
80 OverrideRule Override = nullptr;
81 ReadHelperRule ReadHelper = nullptr;
84 struct CasedTypeInfo {
85 TypeKindRule KindRule;
86 std::vector<TypeCase> Cases;
89 class ASTPropsEmitter {
91 RecordKeeper &Records;
92 std::map<HasProperties, NodeInfo> NodeInfos;
93 std::vector<PropertyType> AllPropertyTypes;
94 std::map<PropertyType, CasedTypeInfo> CasedTypeInfos;
97 ASTPropsEmitter(RecordKeeper &records, raw_ostream &out)
98 : Out(out), Records(records) {
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);
107 // Find all the creation rules.
108 for (CreationRule creationRule :
109 records.getAllDerivedDefinitions(CreationRuleClassName)) {
110 HasProperties node = creationRule.getClass();
112 auto &info = NodeInfos[node];
114 PrintFatalError(creationRule.getLoc(),
115 "multiple creator rules for \"" + node.getName()
118 info.Creator = creationRule;
121 // Find all the override rules.
122 for (OverrideRule overrideRule :
123 records.getAllDerivedDefinitions(OverrideRuleClassName)) {
124 HasProperties node = overrideRule.getClass();
126 auto &info = NodeInfos[node];
128 PrintFatalError(overrideRule.getLoc(),
129 "multiple override rules for \"" + node.getName()
132 info.Override = overrideRule;
135 // Find all the write helper rules.
136 for (ReadHelperRule helperRule :
137 records.getAllDerivedDefinitions(ReadHelperRuleClassName)) {
138 HasProperties node = helperRule.getClass();
140 auto &info = NodeInfos[node];
141 if (info.ReadHelper) {
142 PrintFatalError(helperRule.getLoc(),
143 "multiple write helper rules for \"" + node.getName()
146 info.ReadHelper = helperRule;
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;
156 AllPropertyTypes.push_back(type);
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];
165 PrintFatalError(kindRule.getLoc(),
166 "multiple kind rules for \""
167 + type.getCXXTypeName() + "\"");
169 info.KindRule = kindRule;
172 // Find all the type cases.
173 for (TypeCase typeCase :
174 records.getAllDerivedDefinitions(TypeCaseClassName)) {
175 CasedTypeInfos[typeCase.getParentType()].Cases.push_back(typeCase);
178 Validator(*this).validate();
181 void visitAllProperties(HasProperties derived, const NodeInfo &derivedInfo,
182 function_ref<void (Property)> visit) {
183 std::set<StringRef> ignoredProperties;
185 auto overrideRule = derivedInfo.Override;
187 auto list = overrideRule.getIgnoredProperties();
188 ignoredProperties.insert(list.begin(), list.end());
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
195 visitAllNodesWithInfo(derived, derivedInfo,
196 [&](HasProperties node, const NodeInfo &info) {
197 for (Property prop : info.Properties) {
198 if (ignoredProperties.count(prop.getName()))
206 void visitAllNodesWithInfo(HasProperties derivedNode,
207 const NodeInfo &derivedNodeInfo,
208 llvm::function_ref<void (HasProperties node,
209 const NodeInfo &info)>
211 visit(derivedNode, derivedNodeInfo);
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);
218 // Ignore intermediate nodes that don't add interesting properties.
219 if (it == NodeInfos.end()) continue;
220 auto &baseInfo = it->second;
222 visit(base, baseInfo);
227 template <class NodeClass>
228 void emitNodeReaderClass() {
229 auto info = ReaderWriterInfo::forReader<NodeClass>();
230 emitNodeReaderWriterClass<NodeClass>(info);
233 template <class NodeClass>
234 void emitNodeWriterClass() {
235 auto info = ReaderWriterInfo::forWriter<NodeClass>();
236 emitNodeReaderWriterClass<NodeClass>(info);
239 template <class NodeClass>
240 void emitNodeReaderWriterClass(const ReaderWriterInfo &info);
242 template <class NodeClass>
243 void emitNodeReaderWriterMethod(NodeClass node,
244 const ReaderWriterInfo &info);
246 void emitPropertiedReaderWriterBody(HasProperties node,
247 const ReaderWriterInfo &info);
249 void emitReadOfProperty(StringRef readerName, Property property);
250 void emitReadOfProperty(StringRef readerName, StringRef name,
251 PropertyType type, StringRef condition = "");
253 void emitWriteOfProperty(StringRef writerName, Property property);
254 void emitWriteOfProperty(StringRef writerName, StringRef name,
255 PropertyType type, StringRef readCode,
256 StringRef condition = "");
258 void emitBasicReaderWriterFile(const ReaderWriterInfo &info);
259 void emitDispatcherTemplate(const ReaderWriterInfo &info);
260 void emitPackUnpackOptionalTemplate(const ReaderWriterInfo &info);
261 void emitBasicReaderWriterTemplate(const ReaderWriterInfo &info);
263 void emitCasedReaderWriterMethodBody(PropertyType type,
264 const CasedTypeInfo &typeCases,
265 const ReaderWriterInfo &info);
269 ASTPropsEmitter &Emitter;
270 std::set<HasProperties> ValidatedNodes;
273 Validator(ASTPropsEmitter &emitter) : Emitter(emitter) {}
277 void validateNode(HasProperties node, const NodeInfo &nodeInfo);
278 void validateType(PropertyType type, WrappedRecord context);
282 } // end anonymous namespace
284 void ASTPropsEmitter::Validator::validate() {
285 for (auto &entry : Emitter.NodeInfos) {
286 validateNode(entry.first, entry.second);
289 if (ErrorsPrinted > 0) {
290 PrintFatalError("property validation failed");
294 void ASTPropsEmitter::Validator::validateNode(HasProperties derivedNode,
295 const NodeInfo &derivedNodeInfo) {
296 if (!ValidatedNodes.insert(derivedNode).second) return;
298 // A map from property name to property.
299 std::map<StringRef, Property> allProperties;
301 Emitter.visitAllNodesWithInfo(derivedNode, derivedNodeInfo,
302 [&](HasProperties node,
303 const NodeInfo &nodeInfo) {
304 for (Property property : nodeInfo.Properties) {
305 validateType(property.getType(), property);
307 auto result = allProperties.insert(
308 std::make_pair(property.getName(), property));
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");
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");
332 } else if (auto eltType = type.getArrayElementType()) {
333 validateType(eltType, context);
334 } else if (auto valueType = type.getOptionalElementType()) {
335 validateType(valueType, context);
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");
347 PrintError(type.getLoc(), "unknown generic property type");
348 if (context) PrintNote(context.getLoc(), "type used here");
352 /****************************************************************************/
353 /**************************** AST READER/WRITERS ****************************/
354 /****************************************************************************/
356 template <class NodeClass>
357 void ASTPropsEmitter::emitNodeReaderWriterClass(const ReaderWriterInfo &info) {
358 StringRef suffix = info.ClassSuffix;
359 StringRef var = info.HelperVariable;
361 // Enter the class declaration.
362 Out << "template <class Property" << suffix << ">\n"
363 "class Abstract" << info.HierarchyName << suffix << " {\n"
365 " Property" << suffix << " &" << var << ";\n\n";
367 // Emit the constructor.
368 Out << " Abstract" << info.HierarchyName << suffix
369 << "(Property" << suffix << " &" << var << ") : "
370 << var << "(" << var << ") {}\n\n";
372 // Emit a method that dispatches on a kind to the appropriate node-specific
374 Out << " " << info.ResultType << " " << info.MethodPrefix << "(";
376 Out << NodeClass::getASTIdTypeName() << " kind";
378 Out << "const " << info.HierarchyName << " *node";
384 Out << "node->" << NodeClass::getASTIdAccessorName() << "()";
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() << "(";
391 Out << "static_cast<const " << node.getClassName()
396 " llvm_unreachable(\"bad kind\");\n"
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);
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() << "(";
418 Out << "const " << node.getClassName() << " *node";
421 Out << " auto &ctx = " << info.HelperVariable << ".getASTContext();\n";
423 emitPropertiedReaderWriterBody(node, info);
425 // Finish the method declaration.
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;
439 StringRef creationCode;
441 // We should have a creation rule.
442 if (!nodeInfo.Creator)
443 PrintFatalError(node.getLoc(),
444 "no " CreationRuleClassName " for \""
445 + node.getName() + "\"");
447 creationCode = nodeInfo.Creator.getCreationCode();
450 // Emit the ReadHelper code, if present.
451 if (!info.IsReader && nodeInfo.ReadHelper) {
452 Out << " " << nodeInfo.ReadHelper.getHelperCode() << "\n";
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() + "\"");
464 // Emit code to read or write this property.
466 emitReadOfProperty(info.HelperVariable, prop);
468 emitWriteOfProperty(info.HelperVariable, prop);
471 // Emit the final creation code.
473 Out << " " << creationCode << "\n";
476 static void emitBasicReaderWriterMethodSuffix(raw_ostream &out,
479 if (!type.isGenericSpecialization()) {
480 out << type.getAbstractTypeName();
481 } else if (auto eltType = type.getArrayElementType()) {
483 // We only include an explicit template argument for reads so that
484 // we don't cause spurious const mismatches.
487 eltType.emitCXXValueTypeName(isForRead, out);
490 } else if (auto valueType = type.getOptionalElementType()) {
492 // We only include an explicit template argument for reads so that
493 // we don't cause spurious const mismatches.
496 valueType.emitCXXValueTypeName(isForRead, out);
500 PrintFatalError(type.getLoc(), "unexpected generic property type");
504 /// Emit code to read the given property in a node-reader method.
505 void ASTPropsEmitter::emitReadOfProperty(StringRef readerName,
507 emitReadOfProperty(readerName, property.getName(), property.getType(),
508 property.getCondition());
511 void ASTPropsEmitter::emitReadOfProperty(StringRef readerName,
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";
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.
528 if (!condition.empty()) Out << "llvm::Optional<";
529 type.emitCXXValueTypeName(true, Out);
530 if (!condition.empty()) Out << ">";
533 if (condition.empty()) {
537 " if (" << condition << ") {\n"
538 " " << name << ".emplace(";
541 Out << readerName << ".find(\"" << name << "\")."
542 << (type.isGenericSpecialization() ? "template " : "") << "read";
543 emitBasicReaderWriterMethodSuffix(Out, type, /*for read*/ true);
545 for (size_t i = 0, e = bufferTypes.size(); i != e; ++i) {
546 Out << (i > 0 ? ", " : "") << name << "_buffer_" << i;
550 if (condition.empty()) {
558 /// Emit code to write the given property in a node-writer method.
559 void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName,
561 emitWriteOfProperty(writerName, property.getName(), property.getType(),
562 property.getReadCode(), property.getCondition());
565 void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName,
569 StringRef condition) {
570 if (!condition.empty()) {
571 Out << " if (" << condition << ") {\n";
574 // Focus down to the property:
576 // W.find("prop").write##ValueType(prop);
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";
584 if (!condition.empty()) {
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);
596 ASTPropsEmitter(records, out).emitNodeReaderClass<NodeClass>();
599 void clang::EmitClangTypeReader(RecordKeeper &records, raw_ostream &out) {
600 emitASTReader<TypeNode>(records, out, "A CRTP reader for Clang Type nodes");
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);
610 ASTPropsEmitter(records, out).emitNodeWriterClass<NodeClass>();
613 void clang::EmitClangTypeWriter(RecordKeeper &records, raw_ostream &out) {
614 emitASTWriter<TypeNode>(records, out, "A CRTP writer for Clang Type nodes");
617 /****************************************************************************/
618 /*************************** BASIC READER/WRITERS ***************************/
619 /****************************************************************************/
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";
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") << " "
640 << "(Basic" << info.ClassSuffix << " &" << var
641 << ", Args &&... args) {\n"
642 " return " << var << "."
643 << info.MethodPrefix << methodSuffix
644 << "(std::forward<Args>(args)...);\n"
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());
661 // Declare partial specializations for ArrayRef and Optional.
662 declareSpecialization("<class T>",
665 declareSpecialization("<class T>",
672 ASTPropsEmitter::emitPackUnpackOptionalTemplate(const ReaderWriterInfo &info) {
673 StringRef classPrefix = (info.IsReader ? "Unpack" : "Pack");
674 StringRef methodName = (info.IsReader ? "unpack" : "pack");
676 // Declare the {Pack,Unpack}OptionalValue template.
677 Out << "template <class ValueType>\n"
678 "struct " << classPrefix << "OptionalValue;\n";
680 auto declareSpecialization = [&](const Twine &typeName,
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"
693 for (PropertyType type : AllPropertyTypes) {
694 StringRef code = (info.IsReader ? type.getUnpackOptionalCode()
695 : type.getPackOptionalCode());
696 if (code.empty()) continue;
698 StringRef typeName = type.getCXXTypeName();
699 declareSpecialization(typeName, code);
700 if (type.isConstWhenWriting() && !info.IsReader)
701 declareSpecialization("const " + typeName, code);
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";
712 Out << " ASTContext &C;\n";
713 Out << "protected:\n"
714 " Basic" << info.ClassSuffix << "Base"
715 << (info.IsReader ? "(ASTContext &ctx) : C(ctx)" : "()")
719 Out << " ASTContext &getASTContext() { return C; }\n";
720 Out << " Impl &asImpl() { return static_cast<Impl&>(*this); }\n";
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 << "(";
730 Out << (shouldPassByReference || constWhenWriting ? "const " : "")
732 << (shouldPassByReference ? " &" : "") << " " << paramName;
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(),
746 auto exitMethod = [&] {
750 // Handled cased types.
751 auto casedIter = CasedTypeInfos.find(type);
752 if (casedIter != CasedTypeInfos.end()) {
754 emitCasedReaderWriterMethodBody(type, casedIter->second, info);
757 } else if (type.isEnum()) {
758 enterMethod("value");
760 Out << " return asImpl().template readEnum<"
761 << type.getCXXTypeName() << ">();\n";
763 Out << " asImpl().writeEnum(value);\n";
766 } else if (PropertyType superclass = type.getSuperclassType()) {
767 enterMethod("value");
769 Out << " return cast_or_null<" << type.getSubclassClassName()
771 << superclass.getAbstractTypeName()
774 Out << " asImpl().write" << superclass.getAbstractTypeName()
779 // The other types can't be handled as trivially.
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() + "\"");
793 if (!typeCases.KindRule) {
794 assert(!typeCases.Cases.empty());
795 PrintFatalError(typeCases.Cases.front().getLoc(),
796 "no kind rule for \"" + type.getCXXTypeName() + "\"");
799 auto var = info.HelperVariable;
800 std::string subvar = ("sub" + var).str();
802 // Bind `ctx` for readers.
804 Out << " auto &ctx = asImpl().getASTContext();\n";
807 Out << " auto &&" << subvar << " = asImpl()."
808 << info.MethodPrefix << "Object();\n";
810 // Read/write the kind property;
811 TypeKindRule kindRule = typeCases.KindRule;
812 StringRef kindProperty = kindRule.getKindPropertyName();
813 PropertyType kindType = kindRule.getKindType();
815 emitReadOfProperty(subvar, kindProperty, kindType);
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());
823 // Prepare a ReaderWriterInfo with a helper variable that will use
824 // the sub-reader/writer.
825 ReaderWriterInfo subInfo = info;
826 subInfo.HelperVariable = subvar;
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);
839 " llvm_unreachable(\"bad " << kindType.getCXXTypeName()
843 void ASTPropsEmitter::emitBasicReaderWriterFile(const ReaderWriterInfo &info) {
844 emitDispatcherTemplate(info);
845 emitPackUnpackOptionalTemplate(info);
846 emitBasicReaderWriterTemplate(info);
849 /// Emit an .inc file that defines some helper classes for reading
851 void clang::EmitClangBasicReader(RecordKeeper &records, raw_ostream &out) {
852 emitSourceFileHeader("Helper classes for BasicReaders", out);
854 // Use any property, we won't be using those properties.
855 auto info = ReaderWriterInfo::forReader<TypeNode>();
856 ASTPropsEmitter(records, out).emitBasicReaderWriterFile(info);
859 /// Emit an .inc file that defines some helper classes for writing
861 void clang::EmitClangBasicWriter(RecordKeeper &records, raw_ostream &out) {
862 emitSourceFileHeader("Helper classes for BasicWriters", out);
864 // Use any property, we won't be using those properties.
865 auto info = ReaderWriterInfo::forWriter<TypeNode>();
866 ASTPropsEmitter(records, out).emitBasicReaderWriterFile(info);