[clang-tidy][NFC]remove deps of clang in clang tidy test (#116588)
[llvm-project.git] / clang / utils / TableGen / ClangASTPropertiesEmitter.cpp
blobacff6febeb8cfab72fcd7309926463b058b83dcc
1 //===-- ClangASTPropsEmitter.cpp - Generate Clang AST properties ----------===//
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.
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"
20 #include <cctype>
21 #include <map>
22 #include <set>
23 #include <string>
24 using namespace llvm;
25 using namespace clang;
26 using namespace clang::tblgen;
28 static StringRef getReaderResultType(TypeNode _) { return "QualType"; }
30 namespace {
32 struct ReaderWriterInfo {
33 bool IsReader;
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.
49 StringRef ResultType;
51 template <class NodeClass>
52 static ReaderWriterInfo forReader() {
53 return ReaderWriterInfo{
54 true,
55 NodeClass::getASTHierarchyName(),
56 "Reader",
57 "read",
58 "R",
59 getReaderResultType(NodeClass())
63 template <class NodeClass>
64 static ReaderWriterInfo forWriter() {
65 return ReaderWriterInfo{
66 false,
67 NodeClass::getASTHierarchyName(),
68 "Writer",
69 "write",
70 "W",
71 "void"
76 struct NodeInfo {
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 {
89 raw_ostream &Out;
90 const RecordKeeper &Records;
91 std::map<HasProperties, NodeInfo> NodeInfos;
92 std::vector<PropertyType> AllPropertyTypes;
93 std::map<PropertyType, CasedTypeInfo> CasedTypeInfos;
95 public:
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];
112 if (info.Creator) {
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];
125 if (info.Override) {
126 PrintFatalError(overrideRule.getLoc(),
127 "multiple override rules for \"" + node.getName() +
128 "\"");
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() +
142 "\"");
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())
153 continue;
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];
163 if (info.KindRule) {
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;
184 if (overrideRule) {
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()))
197 continue;
199 visit(prop);
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())
216 continue;
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);
261 private:
262 class Validator {
263 ASTPropsEmitter &Emitter;
264 std::set<HasProperties> ValidatedNodes;
266 public:
267 Validator(ASTPropsEmitter &emitter) : Emitter(emitter) {}
268 void validate();
270 private:
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");
340 } else {
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"
358 "public:\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
367 // method.
368 Out << " " << info.ResultType << " " << info.MethodPrefix << "(";
369 if (info.IsReader)
370 Out << NodeClass::getASTIdTypeName() << " kind";
371 else
372 Out << "const " << info.HierarchyName << " *node";
373 Out << ") {\n"
374 " switch (";
375 if (info.IsReader)
376 Out << "kind";
377 else
378 Out << "node->" << NodeClass::getASTIdAccessorName() << "()";
379 Out << ") {\n";
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() << "(";
384 if (!info.IsReader)
385 Out << "static_cast<const " << node.getClassName()
386 << " *>(node)";
387 Out << ");\n";
389 Out << " }\n"
390 " llvm_unreachable(\"bad kind\");\n"
391 " }\n\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);
400 // Finish the class.
401 Out << "};\n\n";
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() << "(";
411 if (!info.IsReader)
412 Out << "const " << node.getClassName() << " *node";
413 Out << ") {\n";
414 if (info.IsReader)
415 Out << " auto &ctx = " << info.HelperVariable << ".getASTContext();\n";
417 emitPropertiedReaderWriterBody(node, info);
419 // Finish the method declaration.
420 Out << " }\n\n";
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;
434 if (info.IsReader) {
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.
459 if (info.IsReader)
460 emitReadOfProperty(info.HelperVariable, prop);
461 else
462 emitWriteOfProperty(info.HelperVariable, prop);
465 // Emit the final creation code.
466 if (info.IsReader)
467 Out << " " << creationCode << "\n";
470 static void emitBasicReaderWriterMethodSuffix(raw_ostream &out,
471 PropertyType type,
472 bool isForRead) {
473 if (!type.isGenericSpecialization()) {
474 out << type.getAbstractTypeName();
475 } else if (auto eltType = type.getArrayElementType()) {
476 out << "Array";
477 // We only include an explicit template argument for reads so that
478 // we don't cause spurious const mismatches.
479 if (isForRead) {
480 out << "<";
481 eltType.emitCXXValueTypeName(isForRead, out);
482 out << ">";
484 } else if (auto valueType = type.getOptionalElementType()) {
485 out << "Optional";
486 // We only include an explicit template argument for reads so that
487 // we don't cause spurious const mismatches.
488 if (isForRead) {
489 out << "<";
490 valueType.emitCXXValueTypeName(isForRead, out);
491 out << ">";
493 } else {
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,
500 Property property) {
501 emitReadOfProperty(readerName, property.getName(), property.getType(),
502 property.getCondition());
505 void ASTPropsEmitter::emitReadOfProperty(StringRef readerName,
506 StringRef name,
507 PropertyType type,
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.
521 Out << " ";
522 if (!condition.empty())
523 Out << "std::optional<";
524 type.emitCXXValueTypeName(true, Out);
525 if (!condition.empty()) Out << ">";
526 Out << " " << name;
528 if (condition.empty()) {
529 Out << " = ";
530 } else {
531 Out << ";\n"
532 " if (" << condition << ") {\n"
533 " " << name << ".emplace(";
536 Out << readerName << ".find(\"" << name << "\")."
537 << (type.isGenericSpecialization() ? "template " : "") << "read";
538 emitBasicReaderWriterMethodSuffix(Out, type, /*for read*/ true);
539 Out << "(";
540 for (size_t i = 0, e = bufferTypes.size(); i != e; ++i) {
541 Out << (i > 0 ? ", " : "") << name << "_buffer_" << i;
543 Out << ")";
545 if (condition.empty()) {
546 Out << ";\n";
547 } else {
548 Out << ");\n"
549 " }\n";
553 /// Emit code to write the given property in a node-writer method.
554 void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName,
555 Property property) {
556 emitWriteOfProperty(writerName, property.getName(), property.getType(),
557 property.getReadCode(), property.getCondition());
560 void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName,
561 StringRef name,
562 PropertyType type,
563 StringRef readCode,
564 StringRef condition) {
565 if (!condition.empty()) {
566 Out << " if (" << condition << ") {\n";
569 // Focus down to the property:
570 // T prop = <READ>;
571 // W.find("prop").write##ValueType(prop);
572 Out << " ";
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()) {
580 Out << " }\n";
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 /****************************************************************************/
616 void
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") << " "
634 << info.MethodPrefix
635 << "(Basic" << info.ClassSuffix << " &" << var
636 << ", Args &&... args) {\n"
637 " return " << var << "."
638 << info.MethodPrefix << methodSuffix
639 << "(std::forward<Args>(args)...);\n"
640 " }\n"
641 "};\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>",
658 "llvm::ArrayRef<T>",
659 "Array");
660 declareSpecialization("<class T>", "std::optional<T>", "Optional");
661 Out << "\n";
664 void
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"
675 "struct "
676 << classPrefix << "OptionalValue<" << typeName
677 << "> {\n"
678 " static "
679 << (info.IsReader ? "std::optional<" : "") << typeName
680 << (info.IsReader ? "> " : " ") << methodName << "("
681 << (info.IsReader ? "" : "std::optional<") << typeName
682 << (info.IsReader ? "" : ">")
683 << " value) {\n"
684 " return "
685 << code
686 << ";\n"
687 " }\n"
688 "};\n";
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);
701 Out << "\n";
704 void
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"
711 " Basic"
712 << info.ClassSuffix << "Base" << ("(ASTContext &ctx) : C(ctx)")
713 << " {}\n"
714 "public:\n";
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 << "(";
725 if (!info.IsReader)
726 Out << (shouldPassByReference || constWhenWriting ? "const " : "")
727 << cxxTypeName
728 << (shouldPassByReference ? " &" : "") << " " << paramName;
729 Out << ") {\n";
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(),
740 paramName);
742 auto exitMethod = [&] {
743 Out << " }\n";
746 // Handled cased types.
747 auto casedIter = CasedTypeInfos.find(type);
748 if (casedIter != CasedTypeInfos.end()) {
749 enterMethod("node");
750 emitCasedReaderWriterMethodBody(type, casedIter->second, info);
751 exitMethod();
753 } else if (type.isEnum()) {
754 enterMethod("value");
755 if (info.IsReader)
756 Out << " return asImpl().template readEnum<"
757 << type.getCXXTypeName() << ">();\n";
758 else
759 Out << " asImpl().writeEnum(value);\n";
760 exitMethod();
762 } else if (PropertyType superclass = type.getSuperclassType()) {
763 enterMethod("value");
764 if (info.IsReader)
765 Out << " return cast_or_null<" << type.getSubclassClassName()
766 << ">(asImpl().read"
767 << superclass.getAbstractTypeName()
768 << "());\n";
769 else
770 Out << " asImpl().write" << superclass.getAbstractTypeName()
771 << "(value);\n";
772 exitMethod();
774 } else {
775 // The other types can't be handled as trivially.
778 Out << "};\n\n";
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.
799 if (info.IsReader)
800 Out << " auto &ctx = asImpl().getASTContext();\n";
802 // Start an object.
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();
810 if (info.IsReader) {
811 emitReadOfProperty(subvar, kindProperty, kindType);
812 } else {
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);
830 if (!info.IsReader)
831 Out << " return;\n";
832 Out << " }\n\n";
834 Out << " }\n"
835 " llvm_unreachable(\"bad " << kindType.getCXXTypeName()
836 << "\");\n";
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
846 /// basic values.
847 void clang::EmitClangBasicReader(const RecordKeeper &records,
848 raw_ostream &out) {
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
857 /// basic values.
858 void clang::EmitClangBasicWriter(const RecordKeeper &records,
859 raw_ostream &out) {
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);