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"
27 using namespace clang
;
28 using namespace clang::tblgen
;
30 static StringRef
getReaderResultType(TypeNode _
) { return "QualType"; }
34 struct ReaderWriterInfo
{
37 /// The name of the node hierarchy. Not actually sensitive to IsReader,
38 /// but useful to cache here anyway.
39 StringRef HierarchyName
;
41 /// The suffix on classes: Reader/Writer
42 StringRef ClassSuffix
;
44 /// The base name of methods: read/write
45 StringRef MethodPrefix
;
47 /// The name of the property helper member: R/W
48 StringRef HelperVariable
;
50 /// The result type of methods on the class.
53 template <class NodeClass
>
54 static ReaderWriterInfo
forReader() {
55 return ReaderWriterInfo
{
57 NodeClass::getASTHierarchyName(),
61 getReaderResultType(NodeClass())
65 template <class NodeClass
>
66 static ReaderWriterInfo
forWriter() {
67 return ReaderWriterInfo
{
69 NodeClass::getASTHierarchyName(),
79 std::vector
<Property
> Properties
;
80 CreationRule Creator
= nullptr;
81 OverrideRule Override
= nullptr;
82 ReadHelperRule ReadHelper
= nullptr;
85 struct CasedTypeInfo
{
86 TypeKindRule KindRule
;
87 std::vector
<TypeCase
> Cases
;
90 class ASTPropsEmitter
{
92 RecordKeeper
&Records
;
93 std::map
<HasProperties
, NodeInfo
> NodeInfos
;
94 std::vector
<PropertyType
> AllPropertyTypes
;
95 std::map
<PropertyType
, CasedTypeInfo
> CasedTypeInfos
;
98 ASTPropsEmitter(RecordKeeper
&records
, raw_ostream
&out
)
99 : Out(out
), Records(records
) {
101 // Find all the properties.
102 for (Property property
:
103 records
.getAllDerivedDefinitions(PropertyClassName
)) {
104 HasProperties node
= property
.getClass();
105 NodeInfos
[node
].Properties
.push_back(property
);
108 // Find all the creation rules.
109 for (CreationRule creationRule
:
110 records
.getAllDerivedDefinitions(CreationRuleClassName
)) {
111 HasProperties node
= creationRule
.getClass();
113 auto &info
= NodeInfos
[node
];
115 PrintFatalError(creationRule
.getLoc(),
116 "multiple creator rules for \"" + node
.getName()
119 info
.Creator
= creationRule
;
122 // Find all the override rules.
123 for (OverrideRule overrideRule
:
124 records
.getAllDerivedDefinitions(OverrideRuleClassName
)) {
125 HasProperties node
= overrideRule
.getClass();
127 auto &info
= NodeInfos
[node
];
129 PrintFatalError(overrideRule
.getLoc(),
130 "multiple override rules for \"" + node
.getName()
133 info
.Override
= overrideRule
;
136 // Find all the write helper rules.
137 for (ReadHelperRule helperRule
:
138 records
.getAllDerivedDefinitions(ReadHelperRuleClassName
)) {
139 HasProperties node
= helperRule
.getClass();
141 auto &info
= NodeInfos
[node
];
142 if (info
.ReadHelper
) {
143 PrintFatalError(helperRule
.getLoc(),
144 "multiple write helper rules for \"" + node
.getName()
147 info
.ReadHelper
= helperRule
;
150 // Find all the concrete property types.
151 for (PropertyType type
:
152 records
.getAllDerivedDefinitions(PropertyTypeClassName
)) {
153 // Ignore generic specializations; they're generally not useful when
154 // emitting basic emitters etc.
155 if (type
.isGenericSpecialization()) continue;
157 AllPropertyTypes
.push_back(type
);
160 // Find all the type kind rules.
161 for (TypeKindRule kindRule
:
162 records
.getAllDerivedDefinitions(TypeKindClassName
)) {
163 PropertyType type
= kindRule
.getParentType();
164 auto &info
= CasedTypeInfos
[type
];
166 PrintFatalError(kindRule
.getLoc(),
167 "multiple kind rules for \""
168 + type
.getCXXTypeName() + "\"");
170 info
.KindRule
= kindRule
;
173 // Find all the type cases.
174 for (TypeCase typeCase
:
175 records
.getAllDerivedDefinitions(TypeCaseClassName
)) {
176 CasedTypeInfos
[typeCase
.getParentType()].Cases
.push_back(typeCase
);
179 Validator(*this).validate();
182 void visitAllProperties(HasProperties derived
, const NodeInfo
&derivedInfo
,
183 function_ref
<void (Property
)> visit
) {
184 std::set
<StringRef
> ignoredProperties
;
186 auto overrideRule
= derivedInfo
.Override
;
188 auto list
= overrideRule
.getIgnoredProperties();
189 ignoredProperties
.insert(list
.begin(), list
.end());
192 // TODO: we should sort the properties in various ways
193 // - put arrays at the end to enable abbreviations
194 // - put conditional properties after properties used in the condition
196 visitAllNodesWithInfo(derived
, derivedInfo
,
197 [&](HasProperties node
, const NodeInfo
&info
) {
198 for (Property prop
: info
.Properties
) {
199 if (ignoredProperties
.count(prop
.getName()))
207 void visitAllNodesWithInfo(HasProperties derivedNode
,
208 const NodeInfo
&derivedNodeInfo
,
209 llvm::function_ref
<void (HasProperties node
,
210 const NodeInfo
&info
)>
212 visit(derivedNode
, derivedNodeInfo
);
214 // Also walk the bases if appropriate.
215 if (ASTNode base
= derivedNode
.getAs
<ASTNode
>()) {
216 for (base
= base
.getBase(); base
; base
= base
.getBase()) {
217 auto it
= NodeInfos
.find(base
);
219 // Ignore intermediate nodes that don't add interesting properties.
220 if (it
== NodeInfos
.end()) continue;
221 auto &baseInfo
= it
->second
;
223 visit(base
, baseInfo
);
228 template <class NodeClass
>
229 void emitNodeReaderClass() {
230 auto info
= ReaderWriterInfo::forReader
<NodeClass
>();
231 emitNodeReaderWriterClass
<NodeClass
>(info
);
234 template <class NodeClass
>
235 void emitNodeWriterClass() {
236 auto info
= ReaderWriterInfo::forWriter
<NodeClass
>();
237 emitNodeReaderWriterClass
<NodeClass
>(info
);
240 template <class NodeClass
>
241 void emitNodeReaderWriterClass(const ReaderWriterInfo
&info
);
243 template <class NodeClass
>
244 void emitNodeReaderWriterMethod(NodeClass node
,
245 const ReaderWriterInfo
&info
);
247 void emitPropertiedReaderWriterBody(HasProperties node
,
248 const ReaderWriterInfo
&info
);
250 void emitReadOfProperty(StringRef readerName
, Property property
);
251 void emitReadOfProperty(StringRef readerName
, StringRef name
,
252 PropertyType type
, StringRef condition
= "");
254 void emitWriteOfProperty(StringRef writerName
, Property property
);
255 void emitWriteOfProperty(StringRef writerName
, StringRef name
,
256 PropertyType type
, StringRef readCode
,
257 StringRef condition
= "");
259 void emitBasicReaderWriterFile(const ReaderWriterInfo
&info
);
260 void emitDispatcherTemplate(const ReaderWriterInfo
&info
);
261 void emitPackUnpackOptionalTemplate(const ReaderWriterInfo
&info
);
262 void emitBasicReaderWriterTemplate(const ReaderWriterInfo
&info
);
264 void emitCasedReaderWriterMethodBody(PropertyType type
,
265 const CasedTypeInfo
&typeCases
,
266 const ReaderWriterInfo
&info
);
270 ASTPropsEmitter
&Emitter
;
271 std::set
<HasProperties
> ValidatedNodes
;
274 Validator(ASTPropsEmitter
&emitter
) : Emitter(emitter
) {}
278 void validateNode(HasProperties node
, const NodeInfo
&nodeInfo
);
279 void validateType(PropertyType type
, WrappedRecord context
);
283 } // end anonymous namespace
285 void ASTPropsEmitter::Validator::validate() {
286 for (auto &entry
: Emitter
.NodeInfos
) {
287 validateNode(entry
.first
, entry
.second
);
290 if (ErrorsPrinted
> 0) {
291 PrintFatalError("property validation failed");
295 void ASTPropsEmitter::Validator::validateNode(HasProperties derivedNode
,
296 const NodeInfo
&derivedNodeInfo
) {
297 if (!ValidatedNodes
.insert(derivedNode
).second
) return;
299 // A map from property name to property.
300 std::map
<StringRef
, Property
> allProperties
;
302 Emitter
.visitAllNodesWithInfo(derivedNode
, derivedNodeInfo
,
303 [&](HasProperties node
,
304 const NodeInfo
&nodeInfo
) {
305 for (Property property
: nodeInfo
.Properties
) {
306 validateType(property
.getType(), property
);
308 auto result
= allProperties
.insert(
309 std::make_pair(property
.getName(), property
));
311 // Diagnose non-unique properties.
312 if (!result
.second
) {
313 // The existing property is more likely to be associated with a
314 // derived node, so use it as the error.
315 Property existingProperty
= result
.first
->second
;
316 PrintError(existingProperty
.getLoc(),
317 "multiple properties named \"" + property
.getName()
318 + "\" in hierarchy of " + derivedNode
.getName());
319 PrintNote(property
.getLoc(), "existing property");
325 void ASTPropsEmitter::Validator::validateType(PropertyType type
,
326 WrappedRecord context
) {
327 if (!type
.isGenericSpecialization()) {
328 if (type
.getCXXTypeName() == "") {
329 PrintError(type
.getLoc(),
330 "type is not generic but has no C++ type name");
331 if (context
) PrintNote(context
.getLoc(), "type used here");
333 } else if (auto eltType
= type
.getArrayElementType()) {
334 validateType(eltType
, context
);
335 } else if (auto valueType
= type
.getOptionalElementType()) {
336 validateType(valueType
, context
);
338 if (valueType
.getPackOptionalCode().empty()) {
339 PrintError(valueType
.getLoc(),
340 "type doesn't provide optional-packing code");
341 if (context
) PrintNote(context
.getLoc(), "type used here");
342 } else if (valueType
.getUnpackOptionalCode().empty()) {
343 PrintError(valueType
.getLoc(),
344 "type doesn't provide optional-unpacking code");
345 if (context
) PrintNote(context
.getLoc(), "type used here");
348 PrintError(type
.getLoc(), "unknown generic property type");
349 if (context
) PrintNote(context
.getLoc(), "type used here");
353 /****************************************************************************/
354 /**************************** AST READER/WRITERS ****************************/
355 /****************************************************************************/
357 template <class NodeClass
>
358 void ASTPropsEmitter::emitNodeReaderWriterClass(const ReaderWriterInfo
&info
) {
359 StringRef suffix
= info
.ClassSuffix
;
360 StringRef var
= info
.HelperVariable
;
362 // Enter the class declaration.
363 Out
<< "template <class Property" << suffix
<< ">\n"
364 "class Abstract" << info
.HierarchyName
<< suffix
<< " {\n"
366 " Property" << suffix
<< " &" << var
<< ";\n\n";
368 // Emit the constructor.
369 Out
<< " Abstract" << info
.HierarchyName
<< suffix
370 << "(Property" << suffix
<< " &" << var
<< ") : "
371 << var
<< "(" << var
<< ") {}\n\n";
373 // Emit a method that dispatches on a kind to the appropriate node-specific
375 Out
<< " " << info
.ResultType
<< " " << info
.MethodPrefix
<< "(";
377 Out
<< NodeClass::getASTIdTypeName() << " kind";
379 Out
<< "const " << info
.HierarchyName
<< " *node";
385 Out
<< "node->" << NodeClass::getASTIdAccessorName() << "()";
387 visitASTNodeHierarchy
<NodeClass
>(Records
, [&](NodeClass node
, NodeClass _
) {
388 if (node
.isAbstract()) return;
389 Out
<< " case " << info
.HierarchyName
<< "::" << node
.getId() << ":\n"
390 " return " << info
.MethodPrefix
<< node
.getClassName() << "(";
392 Out
<< "static_cast<const " << node
.getClassName()
397 " llvm_unreachable(\"bad kind\");\n"
400 // Emit node-specific methods for all the concrete nodes.
401 visitASTNodeHierarchy
<NodeClass
>(Records
,
402 [&](NodeClass node
, NodeClass base
) {
403 if (node
.isAbstract()) return;
404 emitNodeReaderWriterMethod(node
, info
);
411 /// Emit a reader method for the given concrete AST node class.
412 template <class NodeClass
>
413 void ASTPropsEmitter::emitNodeReaderWriterMethod(NodeClass node
,
414 const ReaderWriterInfo
&info
) {
415 // Declare and start the method.
416 Out
<< " " << info
.ResultType
<< " "
417 << info
.MethodPrefix
<< node
.getClassName() << "(";
419 Out
<< "const " << node
.getClassName() << " *node";
422 Out
<< " auto &ctx = " << info
.HelperVariable
<< ".getASTContext();\n";
424 emitPropertiedReaderWriterBody(node
, info
);
426 // Finish the method declaration.
430 void ASTPropsEmitter::emitPropertiedReaderWriterBody(HasProperties node
,
431 const ReaderWriterInfo
&info
) {
432 // Find the information for this node.
433 auto it
= NodeInfos
.find(node
);
434 if (it
== NodeInfos
.end())
435 PrintFatalError(node
.getLoc(),
436 "no information about how to deserialize \""
437 + node
.getName() + "\"");
438 auto &nodeInfo
= it
->second
;
440 StringRef creationCode
;
442 // We should have a creation rule.
443 if (!nodeInfo
.Creator
)
444 PrintFatalError(node
.getLoc(),
445 "no " CreationRuleClassName
" for \""
446 + node
.getName() + "\"");
448 creationCode
= nodeInfo
.Creator
.getCreationCode();
451 // Emit the ReadHelper code, if present.
452 if (!info
.IsReader
&& nodeInfo
.ReadHelper
) {
453 Out
<< " " << nodeInfo
.ReadHelper
.getHelperCode() << "\n";
456 // Emit code to read all the properties.
457 visitAllProperties(node
, nodeInfo
, [&](Property prop
) {
458 // Verify that the creation code refers to this property.
459 if (info
.IsReader
&& !creationCode
.contains(prop
.getName()))
460 PrintFatalError(nodeInfo
.Creator
.getLoc(),
461 "creation code for " + node
.getName()
462 + " doesn't refer to property \""
463 + prop
.getName() + "\"");
465 // Emit code to read or write this property.
467 emitReadOfProperty(info
.HelperVariable
, prop
);
469 emitWriteOfProperty(info
.HelperVariable
, prop
);
472 // Emit the final creation code.
474 Out
<< " " << creationCode
<< "\n";
477 static void emitBasicReaderWriterMethodSuffix(raw_ostream
&out
,
480 if (!type
.isGenericSpecialization()) {
481 out
<< type
.getAbstractTypeName();
482 } else if (auto eltType
= type
.getArrayElementType()) {
484 // We only include an explicit template argument for reads so that
485 // we don't cause spurious const mismatches.
488 eltType
.emitCXXValueTypeName(isForRead
, out
);
491 } else if (auto valueType
= type
.getOptionalElementType()) {
493 // We only include an explicit template argument for reads so that
494 // we don't cause spurious const mismatches.
497 valueType
.emitCXXValueTypeName(isForRead
, out
);
501 PrintFatalError(type
.getLoc(), "unexpected generic property type");
505 /// Emit code to read the given property in a node-reader method.
506 void ASTPropsEmitter::emitReadOfProperty(StringRef readerName
,
508 emitReadOfProperty(readerName
, property
.getName(), property
.getType(),
509 property
.getCondition());
512 void ASTPropsEmitter::emitReadOfProperty(StringRef readerName
,
515 StringRef condition
) {
516 // Declare all the necessary buffers.
517 auto bufferTypes
= type
.getBufferElementTypes();
518 for (size_t i
= 0, e
= bufferTypes
.size(); i
!= e
; ++i
) {
519 Out
<< " llvm::SmallVector<";
520 PropertyType(bufferTypes
[i
]).emitCXXValueTypeName(/*for read*/ true, Out
);
521 Out
<< ", 8> " << name
<< "_buffer_" << i
<< ";\n";
524 // T prop = R.find("prop").read##ValueType(buffers...);
525 // We intentionally ignore shouldPassByReference here: we're going to
526 // get a pr-value back from read(), and we should be able to forward
527 // that in the creation rule.
529 if (!condition
.empty())
530 Out
<< "std::optional<";
531 type
.emitCXXValueTypeName(true, Out
);
532 if (!condition
.empty()) Out
<< ">";
535 if (condition
.empty()) {
539 " if (" << condition
<< ") {\n"
540 " " << name
<< ".emplace(";
543 Out
<< readerName
<< ".find(\"" << name
<< "\")."
544 << (type
.isGenericSpecialization() ? "template " : "") << "read";
545 emitBasicReaderWriterMethodSuffix(Out
, type
, /*for read*/ true);
547 for (size_t i
= 0, e
= bufferTypes
.size(); i
!= e
; ++i
) {
548 Out
<< (i
> 0 ? ", " : "") << name
<< "_buffer_" << i
;
552 if (condition
.empty()) {
560 /// Emit code to write the given property in a node-writer method.
561 void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName
,
563 emitWriteOfProperty(writerName
, property
.getName(), property
.getType(),
564 property
.getReadCode(), property
.getCondition());
567 void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName
,
571 StringRef condition
) {
572 if (!condition
.empty()) {
573 Out
<< " if (" << condition
<< ") {\n";
576 // Focus down to the property:
578 // W.find("prop").write##ValueType(prop);
580 type
.emitCXXValueTypeName(false, Out
);
581 Out
<< " " << name
<< " = (" << readCode
<< ");\n"
582 " " << writerName
<< ".find(\"" << name
<< "\").write";
583 emitBasicReaderWriterMethodSuffix(Out
, type
, /*for read*/ false);
584 Out
<< "(" << name
<< ");\n";
586 if (!condition
.empty()) {
591 /// Emit an .inc file that defines the AbstractFooReader class
592 /// for the given AST class hierarchy.
593 template <class NodeClass
>
594 static void emitASTReader(RecordKeeper
&records
, raw_ostream
&out
,
595 StringRef description
) {
596 emitSourceFileHeader(description
, out
);
598 ASTPropsEmitter(records
, out
).emitNodeReaderClass
<NodeClass
>();
601 void clang::EmitClangTypeReader(RecordKeeper
&records
, raw_ostream
&out
) {
602 emitASTReader
<TypeNode
>(records
, out
, "A CRTP reader for Clang Type nodes");
605 /// Emit an .inc file that defines the AbstractFooWriter class
606 /// for the given AST class hierarchy.
607 template <class NodeClass
>
608 static void emitASTWriter(RecordKeeper
&records
, raw_ostream
&out
,
609 StringRef description
) {
610 emitSourceFileHeader(description
, out
);
612 ASTPropsEmitter(records
, out
).emitNodeWriterClass
<NodeClass
>();
615 void clang::EmitClangTypeWriter(RecordKeeper
&records
, raw_ostream
&out
) {
616 emitASTWriter
<TypeNode
>(records
, out
, "A CRTP writer for Clang Type nodes");
619 /****************************************************************************/
620 /*************************** BASIC READER/WRITERS ***************************/
621 /****************************************************************************/
624 ASTPropsEmitter::emitDispatcherTemplate(const ReaderWriterInfo
&info
) {
625 // Declare the {Read,Write}Dispatcher template.
626 StringRef dispatcherPrefix
= (info
.IsReader
? "Read" : "Write");
627 Out
<< "template <class ValueType>\n"
628 "struct " << dispatcherPrefix
<< "Dispatcher;\n";
630 // Declare a specific specialization of the dispatcher template.
631 auto declareSpecialization
=
632 [&](StringRef specializationParameters
,
633 const Twine
&cxxTypeName
,
634 StringRef methodSuffix
) {
635 StringRef var
= info
.HelperVariable
;
636 Out
<< "template " << specializationParameters
<< "\n"
637 "struct " << dispatcherPrefix
<< "Dispatcher<"
638 << cxxTypeName
<< "> {\n";
639 Out
<< " template <class Basic" << info
.ClassSuffix
<< ", class... Args>\n"
640 " static " << (info
.IsReader
? cxxTypeName
: "void") << " "
642 << "(Basic" << info
.ClassSuffix
<< " &" << var
643 << ", Args &&... args) {\n"
644 " return " << var
<< "."
645 << info
.MethodPrefix
<< methodSuffix
646 << "(std::forward<Args>(args)...);\n"
651 // Declare explicit specializations for each of the concrete types.
652 for (PropertyType type
: AllPropertyTypes
) {
653 declareSpecialization("<>",
654 type
.getCXXTypeName(),
655 type
.getAbstractTypeName());
656 // Also declare a specialization for the const type when appropriate.
657 if (!info
.IsReader
&& type
.isConstWhenWriting()) {
658 declareSpecialization("<>",
659 "const " + type
.getCXXTypeName(),
660 type
.getAbstractTypeName());
663 // Declare partial specializations for ArrayRef and Optional.
664 declareSpecialization("<class T>",
667 declareSpecialization("<class T>", "std::optional<T>", "Optional");
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
, StringRef code
) {
681 Out
<< "template <>\n"
683 << classPrefix
<< "OptionalValue<" << typeName
686 << (info
.IsReader
? "std::optional<" : "") << typeName
687 << (info
.IsReader
? "> " : " ") << methodName
<< "("
688 << (info
.IsReader
? "" : "std::optional<") << typeName
689 << (info
.IsReader
? "" : ">")
698 for (PropertyType type
: AllPropertyTypes
) {
699 StringRef code
= (info
.IsReader
? type
.getUnpackOptionalCode()
700 : type
.getPackOptionalCode());
701 if (code
.empty()) continue;
703 StringRef typeName
= type
.getCXXTypeName();
704 declareSpecialization(typeName
, code
);
705 if (type
.isConstWhenWriting() && !info
.IsReader
)
706 declareSpecialization("const " + typeName
, code
);
712 ASTPropsEmitter::emitBasicReaderWriterTemplate(const ReaderWriterInfo
&info
) {
713 // Emit the Basic{Reader,Writer}Base template.
714 Out
<< "template <class Impl>\n"
715 "class Basic" << info
.ClassSuffix
<< "Base {\n";
716 Out
<< " ASTContext &C;\n";
717 Out
<< "protected:\n"
719 << info
.ClassSuffix
<< "Base" << ("(ASTContext &ctx) : C(ctx)")
722 Out
<< " ASTContext &getASTContext() { return C; }\n";
723 Out
<< " Impl &asImpl() { return static_cast<Impl&>(*this); }\n";
725 auto enterReaderWriterMethod
= [&](StringRef cxxTypeName
,
726 StringRef abstractTypeName
,
727 bool shouldPassByReference
,
728 bool constWhenWriting
,
729 StringRef paramName
) {
730 Out
<< " " << (info
.IsReader
? cxxTypeName
: "void")
731 << " " << info
.MethodPrefix
<< abstractTypeName
<< "(";
733 Out
<< (shouldPassByReference
|| constWhenWriting
? "const " : "")
735 << (shouldPassByReference
? " &" : "") << " " << paramName
;
739 // Emit {read,write}ValueType methods for all the enum and subclass types
740 // that default to using the integer/base-class implementations.
741 for (PropertyType type
: AllPropertyTypes
) {
742 auto enterMethod
= [&](StringRef paramName
) {
743 enterReaderWriterMethod(type
.getCXXTypeName(),
744 type
.getAbstractTypeName(),
745 type
.shouldPassByReference(),
746 type
.isConstWhenWriting(),
749 auto exitMethod
= [&] {
753 // Handled cased types.
754 auto casedIter
= CasedTypeInfos
.find(type
);
755 if (casedIter
!= CasedTypeInfos
.end()) {
757 emitCasedReaderWriterMethodBody(type
, casedIter
->second
, info
);
760 } else if (type
.isEnum()) {
761 enterMethod("value");
763 Out
<< " return asImpl().template readEnum<"
764 << type
.getCXXTypeName() << ">();\n";
766 Out
<< " asImpl().writeEnum(value);\n";
769 } else if (PropertyType superclass
= type
.getSuperclassType()) {
770 enterMethod("value");
772 Out
<< " return cast_or_null<" << type
.getSubclassClassName()
774 << superclass
.getAbstractTypeName()
777 Out
<< " asImpl().write" << superclass
.getAbstractTypeName()
782 // The other types can't be handled as trivially.
788 void ASTPropsEmitter::emitCasedReaderWriterMethodBody(PropertyType type
,
789 const CasedTypeInfo
&typeCases
,
790 const ReaderWriterInfo
&info
) {
791 if (typeCases
.Cases
.empty()) {
792 assert(typeCases
.KindRule
);
793 PrintFatalError(typeCases
.KindRule
.getLoc(),
794 "no cases found for \"" + type
.getCXXTypeName() + "\"");
796 if (!typeCases
.KindRule
) {
797 assert(!typeCases
.Cases
.empty());
798 PrintFatalError(typeCases
.Cases
.front().getLoc(),
799 "no kind rule for \"" + type
.getCXXTypeName() + "\"");
802 auto var
= info
.HelperVariable
;
803 std::string subvar
= ("sub" + var
).str();
805 // Bind `ctx` for readers.
807 Out
<< " auto &ctx = asImpl().getASTContext();\n";
810 Out
<< " auto &&" << subvar
<< " = asImpl()."
811 << info
.MethodPrefix
<< "Object();\n";
813 // Read/write the kind property;
814 TypeKindRule kindRule
= typeCases
.KindRule
;
815 StringRef kindProperty
= kindRule
.getKindPropertyName();
816 PropertyType kindType
= kindRule
.getKindType();
818 emitReadOfProperty(subvar
, kindProperty
, kindType
);
820 // Write the property. Note that this will implicitly read the
821 // kind into a local variable with the right name.
822 emitWriteOfProperty(subvar
, kindProperty
, kindType
,
823 kindRule
.getReadCode());
826 // Prepare a ReaderWriterInfo with a helper variable that will use
827 // the sub-reader/writer.
828 ReaderWriterInfo subInfo
= info
;
829 subInfo
.HelperVariable
= subvar
;
831 // Switch on the kind.
832 Out
<< " switch (" << kindProperty
<< ") {\n";
833 for (TypeCase typeCase
: typeCases
.Cases
) {
834 Out
<< " case " << type
.getCXXTypeName() << "::"
835 << typeCase
.getCaseName() << ": {\n";
836 emitPropertiedReaderWriterBody(typeCase
, subInfo
);
842 " llvm_unreachable(\"bad " << kindType
.getCXXTypeName()
846 void ASTPropsEmitter::emitBasicReaderWriterFile(const ReaderWriterInfo
&info
) {
847 emitDispatcherTemplate(info
);
848 emitPackUnpackOptionalTemplate(info
);
849 emitBasicReaderWriterTemplate(info
);
852 /// Emit an .inc file that defines some helper classes for reading
854 void clang::EmitClangBasicReader(RecordKeeper
&records
, raw_ostream
&out
) {
855 emitSourceFileHeader("Helper classes for BasicReaders", out
);
857 // Use any property, we won't be using those properties.
858 auto info
= ReaderWriterInfo::forReader
<TypeNode
>();
859 ASTPropsEmitter(records
, out
).emitBasicReaderWriterFile(info
);
862 /// Emit an .inc file that defines some helper classes for writing
864 void clang::EmitClangBasicWriter(RecordKeeper
&records
, raw_ostream
&out
) {
865 emitSourceFileHeader("Helper classes for BasicWriters", out
);
867 // Use any property, we won't be using those properties.
868 auto info
= ReaderWriterInfo::forWriter
<TypeNode
>();
869 ASTPropsEmitter(records
, out
).emitBasicReaderWriterFile(info
);