1 //===-- ClangASTPropsEmitter.cpp - Generate Clang AST properties ----------===//
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/Twine.h"
17 #include "llvm/TableGen/Error.h"
18 #include "llvm/TableGen/Record.h"
19 #include "llvm/TableGen/TableGenBackend.h"
25 using namespace clang
;
26 using namespace clang::tblgen
;
28 static StringRef
getReaderResultType(TypeNode _
) { return "QualType"; }
32 struct ReaderWriterInfo
{
35 /// The name of the node hierarchy. Not actually sensitive to IsReader,
36 /// but useful to cache here anyway.
37 StringRef HierarchyName
;
39 /// The suffix on classes: Reader/Writer
40 StringRef ClassSuffix
;
42 /// The base name of methods: read/write
43 StringRef MethodPrefix
;
45 /// The name of the property helper member: R/W
46 StringRef HelperVariable
;
48 /// The result type of methods on the class.
51 template <class NodeClass
>
52 static ReaderWriterInfo
forReader() {
53 return ReaderWriterInfo
{
55 NodeClass::getASTHierarchyName(),
59 getReaderResultType(NodeClass())
63 template <class NodeClass
>
64 static ReaderWriterInfo
forWriter() {
65 return ReaderWriterInfo
{
67 NodeClass::getASTHierarchyName(),
77 std::vector
<Property
> Properties
;
78 CreationRule Creator
= nullptr;
79 OverrideRule Override
= nullptr;
80 ReadHelperRule ReadHelper
= nullptr;
83 struct CasedTypeInfo
{
84 TypeKindRule KindRule
;
85 std::vector
<TypeCase
> Cases
;
88 class ASTPropsEmitter
{
90 const RecordKeeper
&Records
;
91 std::map
<HasProperties
, NodeInfo
> NodeInfos
;
92 std::vector
<PropertyType
> AllPropertyTypes
;
93 std::map
<PropertyType
, CasedTypeInfo
> CasedTypeInfos
;
96 ASTPropsEmitter(const RecordKeeper
&records
, raw_ostream
&out
)
97 : Out(out
), Records(records
) {
99 // Find all the properties.
100 for (Property property
:
101 records
.getAllDerivedDefinitions(PropertyClassName
)) {
102 HasProperties node
= property
.getClass();
103 NodeInfos
[node
].Properties
.push_back(property
);
106 // Find all the creation rules.
107 for (CreationRule creationRule
:
108 records
.getAllDerivedDefinitions(CreationRuleClassName
)) {
109 HasProperties node
= creationRule
.getClass();
111 auto &info
= NodeInfos
[node
];
113 PrintFatalError(creationRule
.getLoc(), "multiple creator rules for \"" +
114 node
.getName() + "\"");
116 info
.Creator
= creationRule
;
119 // Find all the override rules.
120 for (OverrideRule overrideRule
:
121 records
.getAllDerivedDefinitions(OverrideRuleClassName
)) {
122 HasProperties node
= overrideRule
.getClass();
124 auto &info
= NodeInfos
[node
];
126 PrintFatalError(overrideRule
.getLoc(),
127 "multiple override rules for \"" + node
.getName() +
130 info
.Override
= overrideRule
;
133 // Find all the write helper rules.
134 for (ReadHelperRule helperRule
:
135 records
.getAllDerivedDefinitions(ReadHelperRuleClassName
)) {
136 HasProperties node
= helperRule
.getClass();
138 auto &info
= NodeInfos
[node
];
139 if (info
.ReadHelper
) {
140 PrintFatalError(helperRule
.getLoc(),
141 "multiple write helper rules for \"" + node
.getName() +
144 info
.ReadHelper
= helperRule
;
147 // Find all the concrete property types.
148 for (PropertyType type
:
149 records
.getAllDerivedDefinitions(PropertyTypeClassName
)) {
150 // Ignore generic specializations; they're generally not useful when
151 // emitting basic emitters etc.
152 if (type
.isGenericSpecialization())
155 AllPropertyTypes
.push_back(type
);
158 // Find all the type kind rules.
159 for (TypeKindRule kindRule
:
160 records
.getAllDerivedDefinitions(TypeKindClassName
)) {
161 PropertyType type
= kindRule
.getParentType();
162 auto &info
= CasedTypeInfos
[type
];
164 PrintFatalError(kindRule
.getLoc(), "multiple kind rules for \"" +
165 type
.getCXXTypeName() + "\"");
167 info
.KindRule
= kindRule
;
170 // Find all the type cases.
171 for (TypeCase typeCase
:
172 records
.getAllDerivedDefinitions(TypeCaseClassName
)) {
173 CasedTypeInfos
[typeCase
.getParentType()].Cases
.push_back(typeCase
);
176 Validator(*this).validate();
179 void visitAllProperties(HasProperties derived
, const NodeInfo
&derivedInfo
,
180 function_ref
<void(Property
)> visit
) {
181 std::set
<StringRef
> ignoredProperties
;
183 auto overrideRule
= derivedInfo
.Override
;
185 auto list
= overrideRule
.getIgnoredProperties();
186 ignoredProperties
.insert(list
.begin(), list
.end());
189 // TODO: we should sort the properties in various ways
190 // - put arrays at the end to enable abbreviations
191 // - put conditional properties after properties used in the condition
193 visitAllNodesWithInfo(derived
, derivedInfo
,
194 [&](HasProperties node
, const NodeInfo
&info
) {
195 for (Property prop
: info
.Properties
) {
196 if (ignoredProperties
.count(prop
.getName()))
204 void visitAllNodesWithInfo(
205 HasProperties derivedNode
, const NodeInfo
&derivedNodeInfo
,
206 function_ref
<void(HasProperties node
, const NodeInfo
&info
)> visit
) {
207 visit(derivedNode
, derivedNodeInfo
);
209 // Also walk the bases if appropriate.
210 if (ASTNode base
= derivedNode
.getAs
<ASTNode
>()) {
211 for (base
= base
.getBase(); base
; base
= base
.getBase()) {
212 auto it
= NodeInfos
.find(base
);
214 // Ignore intermediate nodes that don't add interesting properties.
215 if (it
== NodeInfos
.end())
217 auto &baseInfo
= it
->second
;
219 visit(base
, baseInfo
);
224 template <class NodeClass
> void emitNodeReaderClass() {
225 auto info
= ReaderWriterInfo::forReader
<NodeClass
>();
226 emitNodeReaderWriterClass
<NodeClass
>(info
);
229 template <class NodeClass
> void emitNodeWriterClass() {
230 auto info
= ReaderWriterInfo::forWriter
<NodeClass
>();
231 emitNodeReaderWriterClass
<NodeClass
>(info
);
234 template <class NodeClass
>
235 void emitNodeReaderWriterClass(const ReaderWriterInfo
&info
);
237 template <class NodeClass
>
238 void emitNodeReaderWriterMethod(NodeClass node
, const ReaderWriterInfo
&info
);
240 void emitPropertiedReaderWriterBody(HasProperties node
,
241 const ReaderWriterInfo
&info
);
243 void emitReadOfProperty(StringRef readerName
, Property property
);
244 void emitReadOfProperty(StringRef readerName
, StringRef name
,
245 PropertyType type
, StringRef condition
= "");
247 void emitWriteOfProperty(StringRef writerName
, Property property
);
248 void emitWriteOfProperty(StringRef writerName
, StringRef name
,
249 PropertyType type
, StringRef readCode
,
250 StringRef condition
= "");
252 void emitBasicReaderWriterFile(const ReaderWriterInfo
&info
);
253 void emitDispatcherTemplate(const ReaderWriterInfo
&info
);
254 void emitPackUnpackOptionalTemplate(const ReaderWriterInfo
&info
);
255 void emitBasicReaderWriterTemplate(const ReaderWriterInfo
&info
);
257 void emitCasedReaderWriterMethodBody(PropertyType type
,
258 const CasedTypeInfo
&typeCases
,
259 const ReaderWriterInfo
&info
);
263 ASTPropsEmitter
&Emitter
;
264 std::set
<HasProperties
> ValidatedNodes
;
267 Validator(ASTPropsEmitter
&emitter
) : Emitter(emitter
) {}
271 void validateNode(HasProperties node
, const NodeInfo
&nodeInfo
);
272 void validateType(PropertyType type
, WrappedRecord context
);
276 } // end anonymous namespace
278 void ASTPropsEmitter::Validator::validate() {
279 for (auto &entry
: Emitter
.NodeInfos
) {
280 validateNode(entry
.first
, entry
.second
);
283 if (ErrorsPrinted
> 0) {
284 PrintFatalError("property validation failed");
288 void ASTPropsEmitter::Validator::validateNode(HasProperties derivedNode
,
289 const NodeInfo
&derivedNodeInfo
) {
290 if (!ValidatedNodes
.insert(derivedNode
).second
) return;
292 // A map from property name to property.
293 std::map
<StringRef
, Property
> allProperties
;
295 Emitter
.visitAllNodesWithInfo(derivedNode
, derivedNodeInfo
,
296 [&](HasProperties node
,
297 const NodeInfo
&nodeInfo
) {
298 for (Property property
: nodeInfo
.Properties
) {
299 validateType(property
.getType(), property
);
301 auto result
= allProperties
.insert(
302 std::make_pair(property
.getName(), property
));
304 // Diagnose non-unique properties.
305 if (!result
.second
) {
306 // The existing property is more likely to be associated with a
307 // derived node, so use it as the error.
308 Property existingProperty
= result
.first
->second
;
309 PrintError(existingProperty
.getLoc(),
310 "multiple properties named \"" + property
.getName()
311 + "\" in hierarchy of " + derivedNode
.getName());
312 PrintNote(property
.getLoc(), "existing property");
318 void ASTPropsEmitter::Validator::validateType(PropertyType type
,
319 WrappedRecord context
) {
320 if (!type
.isGenericSpecialization()) {
321 if (type
.getCXXTypeName() == "") {
322 PrintError(type
.getLoc(),
323 "type is not generic but has no C++ type name");
324 if (context
) PrintNote(context
.getLoc(), "type used here");
326 } else if (auto eltType
= type
.getArrayElementType()) {
327 validateType(eltType
, context
);
328 } else if (auto valueType
= type
.getOptionalElementType()) {
329 validateType(valueType
, context
);
331 if (valueType
.getPackOptionalCode().empty()) {
332 PrintError(valueType
.getLoc(),
333 "type doesn't provide optional-packing code");
334 if (context
) PrintNote(context
.getLoc(), "type used here");
335 } else if (valueType
.getUnpackOptionalCode().empty()) {
336 PrintError(valueType
.getLoc(),
337 "type doesn't provide optional-unpacking code");
338 if (context
) PrintNote(context
.getLoc(), "type used here");
341 PrintError(type
.getLoc(), "unknown generic property type");
342 if (context
) PrintNote(context
.getLoc(), "type used here");
346 /****************************************************************************/
347 /**************************** AST READER/WRITERS ****************************/
348 /****************************************************************************/
350 template <class NodeClass
>
351 void ASTPropsEmitter::emitNodeReaderWriterClass(const ReaderWriterInfo
&info
) {
352 StringRef suffix
= info
.ClassSuffix
;
353 StringRef var
= info
.HelperVariable
;
355 // Enter the class declaration.
356 Out
<< "template <class Property" << suffix
<< ">\n"
357 "class Abstract" << info
.HierarchyName
<< suffix
<< " {\n"
359 " Property" << suffix
<< " &" << var
<< ";\n\n";
361 // Emit the constructor.
362 Out
<< " Abstract" << info
.HierarchyName
<< suffix
363 << "(Property" << suffix
<< " &" << var
<< ") : "
364 << var
<< "(" << var
<< ") {}\n\n";
366 // Emit a method that dispatches on a kind to the appropriate node-specific
368 Out
<< " " << info
.ResultType
<< " " << info
.MethodPrefix
<< "(";
370 Out
<< NodeClass::getASTIdTypeName() << " kind";
372 Out
<< "const " << info
.HierarchyName
<< " *node";
378 Out
<< "node->" << NodeClass::getASTIdAccessorName() << "()";
380 visitASTNodeHierarchy
<NodeClass
>(Records
, [&](NodeClass node
, NodeClass _
) {
381 if (node
.isAbstract()) return;
382 Out
<< " case " << info
.HierarchyName
<< "::" << node
.getId() << ":\n"
383 " return " << info
.MethodPrefix
<< node
.getClassName() << "(";
385 Out
<< "static_cast<const " << node
.getClassName()
390 " llvm_unreachable(\"bad kind\");\n"
393 // Emit node-specific methods for all the concrete nodes.
394 visitASTNodeHierarchy
<NodeClass
>(Records
,
395 [&](NodeClass node
, NodeClass base
) {
396 if (node
.isAbstract()) return;
397 emitNodeReaderWriterMethod(node
, info
);
404 /// Emit a reader method for the given concrete AST node class.
405 template <class NodeClass
>
406 void ASTPropsEmitter::emitNodeReaderWriterMethod(NodeClass node
,
407 const ReaderWriterInfo
&info
) {
408 // Declare and start the method.
409 Out
<< " " << info
.ResultType
<< " "
410 << info
.MethodPrefix
<< node
.getClassName() << "(";
412 Out
<< "const " << node
.getClassName() << " *node";
415 Out
<< " auto &ctx = " << info
.HelperVariable
<< ".getASTContext();\n";
417 emitPropertiedReaderWriterBody(node
, info
);
419 // Finish the method declaration.
423 void ASTPropsEmitter::emitPropertiedReaderWriterBody(HasProperties node
,
424 const ReaderWriterInfo
&info
) {
425 // Find the information for this node.
426 auto it
= NodeInfos
.find(node
);
427 if (it
== NodeInfos
.end())
428 PrintFatalError(node
.getLoc(),
429 "no information about how to deserialize \""
430 + node
.getName() + "\"");
431 auto &nodeInfo
= it
->second
;
433 StringRef creationCode
;
435 // We should have a creation rule.
436 if (!nodeInfo
.Creator
)
437 PrintFatalError(node
.getLoc(),
438 "no " CreationRuleClassName
" for \""
439 + node
.getName() + "\"");
441 creationCode
= nodeInfo
.Creator
.getCreationCode();
444 // Emit the ReadHelper code, if present.
445 if (!info
.IsReader
&& nodeInfo
.ReadHelper
) {
446 Out
<< " " << nodeInfo
.ReadHelper
.getHelperCode() << "\n";
449 // Emit code to read all the properties.
450 visitAllProperties(node
, nodeInfo
, [&](Property prop
) {
451 // Verify that the creation code refers to this property.
452 if (info
.IsReader
&& !creationCode
.contains(prop
.getName()))
453 PrintFatalError(nodeInfo
.Creator
.getLoc(),
454 "creation code for " + node
.getName()
455 + " doesn't refer to property \""
456 + prop
.getName() + "\"");
458 // Emit code to read or write this property.
460 emitReadOfProperty(info
.HelperVariable
, prop
);
462 emitWriteOfProperty(info
.HelperVariable
, prop
);
465 // Emit the final creation code.
467 Out
<< " " << creationCode
<< "\n";
470 static void emitBasicReaderWriterMethodSuffix(raw_ostream
&out
,
473 if (!type
.isGenericSpecialization()) {
474 out
<< type
.getAbstractTypeName();
475 } else if (auto eltType
= type
.getArrayElementType()) {
477 // We only include an explicit template argument for reads so that
478 // we don't cause spurious const mismatches.
481 eltType
.emitCXXValueTypeName(isForRead
, out
);
484 } else if (auto valueType
= type
.getOptionalElementType()) {
486 // We only include an explicit template argument for reads so that
487 // we don't cause spurious const mismatches.
490 valueType
.emitCXXValueTypeName(isForRead
, out
);
494 PrintFatalError(type
.getLoc(), "unexpected generic property type");
498 /// Emit code to read the given property in a node-reader method.
499 void ASTPropsEmitter::emitReadOfProperty(StringRef readerName
,
501 emitReadOfProperty(readerName
, property
.getName(), property
.getType(),
502 property
.getCondition());
505 void ASTPropsEmitter::emitReadOfProperty(StringRef readerName
,
508 StringRef condition
) {
509 // Declare all the necessary buffers.
510 auto bufferTypes
= type
.getBufferElementTypes();
511 for (size_t i
= 0, e
= bufferTypes
.size(); i
!= e
; ++i
) {
512 Out
<< " llvm::SmallVector<";
513 PropertyType(bufferTypes
[i
]).emitCXXValueTypeName(/*for read*/ true, Out
);
514 Out
<< ", 8> " << name
<< "_buffer_" << i
<< ";\n";
517 // T prop = R.find("prop").read##ValueType(buffers...);
518 // We intentionally ignore shouldPassByReference here: we're going to
519 // get a pr-value back from read(), and we should be able to forward
520 // that in the creation rule.
522 if (!condition
.empty())
523 Out
<< "std::optional<";
524 type
.emitCXXValueTypeName(true, Out
);
525 if (!condition
.empty()) Out
<< ">";
528 if (condition
.empty()) {
532 " if (" << condition
<< ") {\n"
533 " " << name
<< ".emplace(";
536 Out
<< readerName
<< ".find(\"" << name
<< "\")."
537 << (type
.isGenericSpecialization() ? "template " : "") << "read";
538 emitBasicReaderWriterMethodSuffix(Out
, type
, /*for read*/ true);
540 for (size_t i
= 0, e
= bufferTypes
.size(); i
!= e
; ++i
) {
541 Out
<< (i
> 0 ? ", " : "") << name
<< "_buffer_" << i
;
545 if (condition
.empty()) {
553 /// Emit code to write the given property in a node-writer method.
554 void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName
,
556 emitWriteOfProperty(writerName
, property
.getName(), property
.getType(),
557 property
.getReadCode(), property
.getCondition());
560 void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName
,
564 StringRef condition
) {
565 if (!condition
.empty()) {
566 Out
<< " if (" << condition
<< ") {\n";
569 // Focus down to the property:
571 // W.find("prop").write##ValueType(prop);
573 type
.emitCXXValueTypeName(false, Out
);
574 Out
<< " " << name
<< " = (" << readCode
<< ");\n"
575 " " << writerName
<< ".find(\"" << name
<< "\").write";
576 emitBasicReaderWriterMethodSuffix(Out
, type
, /*for read*/ false);
577 Out
<< "(" << name
<< ");\n";
579 if (!condition
.empty()) {
584 /// Emit an .inc file that defines the AbstractFooReader class
585 /// for the given AST class hierarchy.
586 template <class NodeClass
>
587 static void emitASTReader(const RecordKeeper
&records
, raw_ostream
&out
,
588 StringRef description
) {
589 emitSourceFileHeader(description
, out
, records
);
591 ASTPropsEmitter(records
, out
).emitNodeReaderClass
<NodeClass
>();
594 void clang::EmitClangTypeReader(const RecordKeeper
&records
, raw_ostream
&out
) {
595 emitASTReader
<TypeNode
>(records
, out
, "A CRTP reader for Clang Type nodes");
598 /// Emit an .inc file that defines the AbstractFooWriter class
599 /// for the given AST class hierarchy.
600 template <class NodeClass
>
601 static void emitASTWriter(const RecordKeeper
&records
, raw_ostream
&out
,
602 StringRef description
) {
603 emitSourceFileHeader(description
, out
, records
);
605 ASTPropsEmitter(records
, out
).emitNodeWriterClass
<NodeClass
>();
608 void clang::EmitClangTypeWriter(const RecordKeeper
&records
, raw_ostream
&out
) {
609 emitASTWriter
<TypeNode
>(records
, out
, "A CRTP writer for Clang Type nodes");
612 /****************************************************************************/
613 /*************************** BASIC READER/WRITERS ***************************/
614 /****************************************************************************/
617 ASTPropsEmitter::emitDispatcherTemplate(const ReaderWriterInfo
&info
) {
618 // Declare the {Read,Write}Dispatcher template.
619 StringRef dispatcherPrefix
= (info
.IsReader
? "Read" : "Write");
620 Out
<< "template <class ValueType>\n"
621 "struct " << dispatcherPrefix
<< "Dispatcher;\n";
623 // Declare a specific specialization of the dispatcher template.
624 auto declareSpecialization
=
625 [&](StringRef specializationParameters
,
626 const Twine
&cxxTypeName
,
627 StringRef methodSuffix
) {
628 StringRef var
= info
.HelperVariable
;
629 Out
<< "template " << specializationParameters
<< "\n"
630 "struct " << dispatcherPrefix
<< "Dispatcher<"
631 << cxxTypeName
<< "> {\n";
632 Out
<< " template <class Basic" << info
.ClassSuffix
<< ", class... Args>\n"
633 " static " << (info
.IsReader
? cxxTypeName
: "void") << " "
635 << "(Basic" << info
.ClassSuffix
<< " &" << var
636 << ", Args &&... args) {\n"
637 " return " << var
<< "."
638 << info
.MethodPrefix
<< methodSuffix
639 << "(std::forward<Args>(args)...);\n"
644 // Declare explicit specializations for each of the concrete types.
645 for (PropertyType type
: AllPropertyTypes
) {
646 declareSpecialization("<>",
647 type
.getCXXTypeName(),
648 type
.getAbstractTypeName());
649 // Also declare a specialization for the const type when appropriate.
650 if (!info
.IsReader
&& type
.isConstWhenWriting()) {
651 declareSpecialization("<>",
652 "const " + type
.getCXXTypeName(),
653 type
.getAbstractTypeName());
656 // Declare partial specializations for ArrayRef and Optional.
657 declareSpecialization("<class T>",
660 declareSpecialization("<class T>", "std::optional<T>", "Optional");
665 ASTPropsEmitter::emitPackUnpackOptionalTemplate(const ReaderWriterInfo
&info
) {
666 StringRef classPrefix
= (info
.IsReader
? "Unpack" : "Pack");
667 StringRef methodName
= (info
.IsReader
? "unpack" : "pack");
669 // Declare the {Pack,Unpack}OptionalValue template.
670 Out
<< "template <class ValueType>\n"
671 "struct " << classPrefix
<< "OptionalValue;\n";
673 auto declareSpecialization
= [&](const Twine
&typeName
, StringRef code
) {
674 Out
<< "template <>\n"
676 << classPrefix
<< "OptionalValue<" << typeName
679 << (info
.IsReader
? "std::optional<" : "") << typeName
680 << (info
.IsReader
? "> " : " ") << methodName
<< "("
681 << (info
.IsReader
? "" : "std::optional<") << typeName
682 << (info
.IsReader
? "" : ">")
691 for (PropertyType type
: AllPropertyTypes
) {
692 StringRef code
= (info
.IsReader
? type
.getUnpackOptionalCode()
693 : type
.getPackOptionalCode());
694 if (code
.empty()) continue;
696 StringRef typeName
= type
.getCXXTypeName();
697 declareSpecialization(typeName
, code
);
698 if (type
.isConstWhenWriting() && !info
.IsReader
)
699 declareSpecialization("const " + typeName
, code
);
705 ASTPropsEmitter::emitBasicReaderWriterTemplate(const ReaderWriterInfo
&info
) {
706 // Emit the Basic{Reader,Writer}Base template.
707 Out
<< "template <class Impl>\n"
708 "class Basic" << info
.ClassSuffix
<< "Base {\n";
709 Out
<< " ASTContext &C;\n";
710 Out
<< "protected:\n"
712 << info
.ClassSuffix
<< "Base" << ("(ASTContext &ctx) : C(ctx)")
715 Out
<< " ASTContext &getASTContext() { return C; }\n";
716 Out
<< " Impl &asImpl() { return static_cast<Impl&>(*this); }\n";
718 auto enterReaderWriterMethod
= [&](StringRef cxxTypeName
,
719 StringRef abstractTypeName
,
720 bool shouldPassByReference
,
721 bool constWhenWriting
,
722 StringRef paramName
) {
723 Out
<< " " << (info
.IsReader
? cxxTypeName
: "void")
724 << " " << info
.MethodPrefix
<< abstractTypeName
<< "(";
726 Out
<< (shouldPassByReference
|| constWhenWriting
? "const " : "")
728 << (shouldPassByReference
? " &" : "") << " " << paramName
;
732 // Emit {read,write}ValueType methods for all the enum and subclass types
733 // that default to using the integer/base-class implementations.
734 for (PropertyType type
: AllPropertyTypes
) {
735 auto enterMethod
= [&](StringRef paramName
) {
736 enterReaderWriterMethod(type
.getCXXTypeName(),
737 type
.getAbstractTypeName(),
738 type
.shouldPassByReference(),
739 type
.isConstWhenWriting(),
742 auto exitMethod
= [&] {
746 // Handled cased types.
747 auto casedIter
= CasedTypeInfos
.find(type
);
748 if (casedIter
!= CasedTypeInfos
.end()) {
750 emitCasedReaderWriterMethodBody(type
, casedIter
->second
, info
);
753 } else if (type
.isEnum()) {
754 enterMethod("value");
756 Out
<< " return asImpl().template readEnum<"
757 << type
.getCXXTypeName() << ">();\n";
759 Out
<< " asImpl().writeEnum(value);\n";
762 } else if (PropertyType superclass
= type
.getSuperclassType()) {
763 enterMethod("value");
765 Out
<< " return cast_or_null<" << type
.getSubclassClassName()
767 << superclass
.getAbstractTypeName()
770 Out
<< " asImpl().write" << superclass
.getAbstractTypeName()
775 // The other types can't be handled as trivially.
781 void ASTPropsEmitter::emitCasedReaderWriterMethodBody(PropertyType type
,
782 const CasedTypeInfo
&typeCases
,
783 const ReaderWriterInfo
&info
) {
784 if (typeCases
.Cases
.empty()) {
785 assert(typeCases
.KindRule
);
786 PrintFatalError(typeCases
.KindRule
.getLoc(),
787 "no cases found for \"" + type
.getCXXTypeName() + "\"");
789 if (!typeCases
.KindRule
) {
790 assert(!typeCases
.Cases
.empty());
791 PrintFatalError(typeCases
.Cases
.front().getLoc(),
792 "no kind rule for \"" + type
.getCXXTypeName() + "\"");
795 auto var
= info
.HelperVariable
;
796 std::string subvar
= ("sub" + var
).str();
798 // Bind `ctx` for readers.
800 Out
<< " auto &ctx = asImpl().getASTContext();\n";
803 Out
<< " auto &&" << subvar
<< " = asImpl()."
804 << info
.MethodPrefix
<< "Object();\n";
806 // Read/write the kind property;
807 TypeKindRule kindRule
= typeCases
.KindRule
;
808 StringRef kindProperty
= kindRule
.getKindPropertyName();
809 PropertyType kindType
= kindRule
.getKindType();
811 emitReadOfProperty(subvar
, kindProperty
, kindType
);
813 // Write the property. Note that this will implicitly read the
814 // kind into a local variable with the right name.
815 emitWriteOfProperty(subvar
, kindProperty
, kindType
,
816 kindRule
.getReadCode());
819 // Prepare a ReaderWriterInfo with a helper variable that will use
820 // the sub-reader/writer.
821 ReaderWriterInfo subInfo
= info
;
822 subInfo
.HelperVariable
= subvar
;
824 // Switch on the kind.
825 Out
<< " switch (" << kindProperty
<< ") {\n";
826 for (TypeCase typeCase
: typeCases
.Cases
) {
827 Out
<< " case " << type
.getCXXTypeName() << "::"
828 << typeCase
.getCaseName() << ": {\n";
829 emitPropertiedReaderWriterBody(typeCase
, subInfo
);
835 " llvm_unreachable(\"bad " << kindType
.getCXXTypeName()
839 void ASTPropsEmitter::emitBasicReaderWriterFile(const ReaderWriterInfo
&info
) {
840 emitDispatcherTemplate(info
);
841 emitPackUnpackOptionalTemplate(info
);
842 emitBasicReaderWriterTemplate(info
);
845 /// Emit an .inc file that defines some helper classes for reading
847 void clang::EmitClangBasicReader(const RecordKeeper
&records
,
849 emitSourceFileHeader("Helper classes for BasicReaders", out
, records
);
851 // Use any property, we won't be using those properties.
852 auto info
= ReaderWriterInfo::forReader
<TypeNode
>();
853 ASTPropsEmitter(records
, out
).emitBasicReaderWriterFile(info
);
856 /// Emit an .inc file that defines some helper classes for writing
858 void clang::EmitClangBasicWriter(const RecordKeeper
&records
,
860 emitSourceFileHeader("Helper classes for BasicWriters", out
, records
);
862 // Use any property, we won't be using those properties.
863 auto info
= ReaderWriterInfo::forWriter
<TypeNode
>();
864 ASTPropsEmitter(records
, out
).emitBasicReaderWriterFile(info
);