[clang-format] Fix a bug in aligning comments above PPDirective (#72791)
[llvm-project.git] / clang / utils / TableGen / ClangASTPropertiesEmitter.cpp
blobde8dda60681ff872049604d92e073b033b512d2b
1 //=== ClangASTPropsEmitter.cpp - Generate Clang AST properties --*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This tablegen backend emits code for working with Clang AST properties.
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"
21 #include <cctype>
22 #include <map>
23 #include <optional>
24 #include <set>
25 #include <string>
26 using namespace llvm;
27 using namespace clang;
28 using namespace clang::tblgen;
30 static StringRef getReaderResultType(TypeNode _) { return "QualType"; }
32 namespace {
34 struct ReaderWriterInfo {
35 bool IsReader;
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.
51 StringRef ResultType;
53 template <class NodeClass>
54 static ReaderWriterInfo forReader() {
55 return ReaderWriterInfo{
56 true,
57 NodeClass::getASTHierarchyName(),
58 "Reader",
59 "read",
60 "R",
61 getReaderResultType(NodeClass())
65 template <class NodeClass>
66 static ReaderWriterInfo forWriter() {
67 return ReaderWriterInfo{
68 false,
69 NodeClass::getASTHierarchyName(),
70 "Writer",
71 "write",
72 "W",
73 "void"
78 struct NodeInfo {
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 {
91 raw_ostream &Out;
92 RecordKeeper &Records;
93 std::map<HasProperties, NodeInfo> NodeInfos;
94 std::vector<PropertyType> AllPropertyTypes;
95 std::map<PropertyType, CasedTypeInfo> CasedTypeInfos;
97 public:
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];
114 if (info.Creator) {
115 PrintFatalError(creationRule.getLoc(),
116 "multiple creator rules for \"" + node.getName()
117 + "\"");
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];
128 if (info.Override) {
129 PrintFatalError(overrideRule.getLoc(),
130 "multiple override rules for \"" + node.getName()
131 + "\"");
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()
145 + "\"");
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];
165 if (info.KindRule) {
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;
187 if (overrideRule) {
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()))
200 continue;
202 visit(prop);
207 void visitAllNodesWithInfo(HasProperties derivedNode,
208 const NodeInfo &derivedNodeInfo,
209 llvm::function_ref<void (HasProperties node,
210 const NodeInfo &info)>
211 visit) {
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);
268 private:
269 class Validator {
270 ASTPropsEmitter &Emitter;
271 std::set<HasProperties> ValidatedNodes;
273 public:
274 Validator(ASTPropsEmitter &emitter) : Emitter(emitter) {}
275 void validate();
277 private:
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");
347 } else {
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"
365 "public:\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
374 // method.
375 Out << " " << info.ResultType << " " << info.MethodPrefix << "(";
376 if (info.IsReader)
377 Out << NodeClass::getASTIdTypeName() << " kind";
378 else
379 Out << "const " << info.HierarchyName << " *node";
380 Out << ") {\n"
381 " switch (";
382 if (info.IsReader)
383 Out << "kind";
384 else
385 Out << "node->" << NodeClass::getASTIdAccessorName() << "()";
386 Out << ") {\n";
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() << "(";
391 if (!info.IsReader)
392 Out << "static_cast<const " << node.getClassName()
393 << " *>(node)";
394 Out << ");\n";
396 Out << " }\n"
397 " llvm_unreachable(\"bad kind\");\n"
398 " }\n\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);
407 // Finish the class.
408 Out << "};\n\n";
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() << "(";
418 if (!info.IsReader)
419 Out << "const " << node.getClassName() << " *node";
420 Out << ") {\n";
421 if (info.IsReader)
422 Out << " auto &ctx = " << info.HelperVariable << ".getASTContext();\n";
424 emitPropertiedReaderWriterBody(node, info);
426 // Finish the method declaration.
427 Out << " }\n\n";
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;
441 if (info.IsReader) {
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.
466 if (info.IsReader)
467 emitReadOfProperty(info.HelperVariable, prop);
468 else
469 emitWriteOfProperty(info.HelperVariable, prop);
472 // Emit the final creation code.
473 if (info.IsReader)
474 Out << " " << creationCode << "\n";
477 static void emitBasicReaderWriterMethodSuffix(raw_ostream &out,
478 PropertyType type,
479 bool isForRead) {
480 if (!type.isGenericSpecialization()) {
481 out << type.getAbstractTypeName();
482 } else if (auto eltType = type.getArrayElementType()) {
483 out << "Array";
484 // We only include an explicit template argument for reads so that
485 // we don't cause spurious const mismatches.
486 if (isForRead) {
487 out << "<";
488 eltType.emitCXXValueTypeName(isForRead, out);
489 out << ">";
491 } else if (auto valueType = type.getOptionalElementType()) {
492 out << "Optional";
493 // We only include an explicit template argument for reads so that
494 // we don't cause spurious const mismatches.
495 if (isForRead) {
496 out << "<";
497 valueType.emitCXXValueTypeName(isForRead, out);
498 out << ">";
500 } else {
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,
507 Property property) {
508 emitReadOfProperty(readerName, property.getName(), property.getType(),
509 property.getCondition());
512 void ASTPropsEmitter::emitReadOfProperty(StringRef readerName,
513 StringRef name,
514 PropertyType type,
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.
528 Out << " ";
529 if (!condition.empty())
530 Out << "std::optional<";
531 type.emitCXXValueTypeName(true, Out);
532 if (!condition.empty()) Out << ">";
533 Out << " " << name;
535 if (condition.empty()) {
536 Out << " = ";
537 } else {
538 Out << ";\n"
539 " if (" << condition << ") {\n"
540 " " << name << ".emplace(";
543 Out << readerName << ".find(\"" << name << "\")."
544 << (type.isGenericSpecialization() ? "template " : "") << "read";
545 emitBasicReaderWriterMethodSuffix(Out, type, /*for read*/ true);
546 Out << "(";
547 for (size_t i = 0, e = bufferTypes.size(); i != e; ++i) {
548 Out << (i > 0 ? ", " : "") << name << "_buffer_" << i;
550 Out << ")";
552 if (condition.empty()) {
553 Out << ";\n";
554 } else {
555 Out << ");\n"
556 " }\n";
560 /// Emit code to write the given property in a node-writer method.
561 void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName,
562 Property property) {
563 emitWriteOfProperty(writerName, property.getName(), property.getType(),
564 property.getReadCode(), property.getCondition());
567 void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName,
568 StringRef name,
569 PropertyType type,
570 StringRef readCode,
571 StringRef condition) {
572 if (!condition.empty()) {
573 Out << " if (" << condition << ") {\n";
576 // Focus down to the property:
577 // T prop = <READ>;
578 // W.find("prop").write##ValueType(prop);
579 Out << " ";
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()) {
587 Out << " }\n";
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, records);
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, records);
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 /****************************************************************************/
623 void
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") << " "
641 << info.MethodPrefix
642 << "(Basic" << info.ClassSuffix << " &" << var
643 << ", Args &&... args) {\n"
644 " return " << var << "."
645 << info.MethodPrefix << methodSuffix
646 << "(std::forward<Args>(args)...);\n"
647 " }\n"
648 "};\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>",
665 "llvm::ArrayRef<T>",
666 "Array");
667 declareSpecialization("<class T>", "std::optional<T>", "Optional");
668 Out << "\n";
671 void
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"
682 "struct "
683 << classPrefix << "OptionalValue<" << typeName
684 << "> {\n"
685 " static "
686 << (info.IsReader ? "std::optional<" : "") << typeName
687 << (info.IsReader ? "> " : " ") << methodName << "("
688 << (info.IsReader ? "" : "std::optional<") << typeName
689 << (info.IsReader ? "" : ">")
690 << " value) {\n"
691 " return "
692 << code
693 << ";\n"
694 " }\n"
695 "};\n";
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);
708 Out << "\n";
711 void
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"
718 " Basic"
719 << info.ClassSuffix << "Base" << ("(ASTContext &ctx) : C(ctx)")
720 << " {}\n"
721 "public:\n";
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 << "(";
732 if (!info.IsReader)
733 Out << (shouldPassByReference || constWhenWriting ? "const " : "")
734 << cxxTypeName
735 << (shouldPassByReference ? " &" : "") << " " << paramName;
736 Out << ") {\n";
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(),
747 paramName);
749 auto exitMethod = [&] {
750 Out << " }\n";
753 // Handled cased types.
754 auto casedIter = CasedTypeInfos.find(type);
755 if (casedIter != CasedTypeInfos.end()) {
756 enterMethod("node");
757 emitCasedReaderWriterMethodBody(type, casedIter->second, info);
758 exitMethod();
760 } else if (type.isEnum()) {
761 enterMethod("value");
762 if (info.IsReader)
763 Out << " return asImpl().template readEnum<"
764 << type.getCXXTypeName() << ">();\n";
765 else
766 Out << " asImpl().writeEnum(value);\n";
767 exitMethod();
769 } else if (PropertyType superclass = type.getSuperclassType()) {
770 enterMethod("value");
771 if (info.IsReader)
772 Out << " return cast_or_null<" << type.getSubclassClassName()
773 << ">(asImpl().read"
774 << superclass.getAbstractTypeName()
775 << "());\n";
776 else
777 Out << " asImpl().write" << superclass.getAbstractTypeName()
778 << "(value);\n";
779 exitMethod();
781 } else {
782 // The other types can't be handled as trivially.
785 Out << "};\n\n";
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.
806 if (info.IsReader)
807 Out << " auto &ctx = asImpl().getASTContext();\n";
809 // Start an object.
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();
817 if (info.IsReader) {
818 emitReadOfProperty(subvar, kindProperty, kindType);
819 } else {
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);
837 if (!info.IsReader)
838 Out << " return;\n";
839 Out << " }\n\n";
841 Out << " }\n"
842 " llvm_unreachable(\"bad " << kindType.getCXXTypeName()
843 << "\");\n";
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
853 /// basic values.
854 void clang::EmitClangBasicReader(RecordKeeper &records, raw_ostream &out) {
855 emitSourceFileHeader("Helper classes for BasicReaders", out, records);
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
863 /// basic values.
864 void clang::EmitClangBasicWriter(RecordKeeper &records, raw_ostream &out) {
865 emitSourceFileHeader("Helper classes for BasicWriters", out, records);
867 // Use any property, we won't be using those properties.
868 auto info = ReaderWriterInfo::forWriter<TypeNode>();
869 ASTPropsEmitter(records, out).emitBasicReaderWriterFile(info);