866 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This tablegen backend emits code for working with Clang AST properties.10//11//===----------------------------------------------------------------------===//12 13#include "ASTTableGen.h"14#include "TableGenBackends.h"15 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>24using namespace llvm;25using namespace clang;26using namespace clang::tblgen;27 28static StringRef getReaderResultType(TypeNode _) { return "QualType"; }29 30namespace {31 32struct ReaderWriterInfo {33 bool IsReader;34 35 /// The name of the node hierarchy. Not actually sensitive to IsReader,36 /// but useful to cache here anyway.37 StringRef HierarchyName;38 39 /// The suffix on classes: Reader/Writer40 StringRef ClassSuffix;41 42 /// The base name of methods: read/write43 StringRef MethodPrefix;44 45 /// The name of the property helper member: R/W46 StringRef HelperVariable;47 48 /// The result type of methods on the class.49 StringRef ResultType;50 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())60 };61 }62 63 template <class NodeClass>64 static ReaderWriterInfo forWriter() {65 return ReaderWriterInfo{66 false,67 NodeClass::getASTHierarchyName(),68 "Writer",69 "write",70 "W",71 "void"72 };73 }74};75 76struct NodeInfo {77 std::vector<Property> Properties;78 CreationRule Creator = nullptr;79 OverrideRule Override = nullptr;80 ReadHelperRule ReadHelper = nullptr;81};82 83struct CasedTypeInfo {84 TypeKindRule KindRule;85 std::vector<TypeCase> Cases;86};87 88class 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;94 95public:96 ASTPropsEmitter(const RecordKeeper &records, raw_ostream &out)97 : Out(out), Records(records) {98 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);104 }105 106 // Find all the creation rules.107 for (CreationRule creationRule :108 records.getAllDerivedDefinitions(CreationRuleClassName)) {109 HasProperties node = creationRule.getClass();110 111 auto &info = NodeInfos[node];112 if (info.Creator) {113 PrintFatalError(creationRule.getLoc(), "multiple creator rules for \"" +114 node.getName() + "\"");115 }116 info.Creator = creationRule;117 }118 119 // Find all the override rules.120 for (OverrideRule overrideRule :121 records.getAllDerivedDefinitions(OverrideRuleClassName)) {122 HasProperties node = overrideRule.getClass();123 124 auto &info = NodeInfos[node];125 if (info.Override) {126 PrintFatalError(overrideRule.getLoc(),127 "multiple override rules for \"" + node.getName() +128 "\"");129 }130 info.Override = overrideRule;131 }132 133 // Find all the write helper rules.134 for (ReadHelperRule helperRule :135 records.getAllDerivedDefinitions(ReadHelperRuleClassName)) {136 HasProperties node = helperRule.getClass();137 138 auto &info = NodeInfos[node];139 if (info.ReadHelper) {140 PrintFatalError(helperRule.getLoc(),141 "multiple write helper rules for \"" + node.getName() +142 "\"");143 }144 info.ReadHelper = helperRule;145 }146 147 // Find all the concrete property types.148 for (PropertyType type :149 records.getAllDerivedDefinitions(PropertyTypeClassName)) {150 // Ignore generic specializations; they're generally not useful when151 // emitting basic emitters etc.152 if (type.isGenericSpecialization())153 continue;154 155 AllPropertyTypes.push_back(type);156 }157 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() + "\"");166 }167 info.KindRule = kindRule;168 }169 170 // Find all the type cases.171 for (TypeCase typeCase :172 records.getAllDerivedDefinitions(TypeCaseClassName)) {173 CasedTypeInfos[typeCase.getParentType()].Cases.push_back(typeCase);174 }175 176 Validator(*this).validate();177 }178 179 void visitAllProperties(HasProperties derived, const NodeInfo &derivedInfo,180 function_ref<void(Property)> visit) {181 std::set<StringRef> ignoredProperties;182 183 auto overrideRule = derivedInfo.Override;184 if (overrideRule) {185 auto list = overrideRule.getIgnoredProperties();186 ignoredProperties.insert(list.begin(), list.end());187 }188 189 // TODO: we should sort the properties in various ways190 // - put arrays at the end to enable abbreviations191 // - put conditional properties after properties used in the condition192 193 visitAllNodesWithInfo(derived, derivedInfo,194 [&](HasProperties node, const NodeInfo &info) {195 for (Property prop : info.Properties) {196 if (ignoredProperties.count(prop.getName()))197 continue;198 199 visit(prop);200 }201 });202 }203 204 void visitAllNodesWithInfo(205 HasProperties derivedNode, const NodeInfo &derivedNodeInfo,206 function_ref<void(HasProperties node, const NodeInfo &info)> visit) {207 visit(derivedNode, derivedNodeInfo);208 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);213 214 // Ignore intermediate nodes that don't add interesting properties.215 if (it == NodeInfos.end())216 continue;217 auto &baseInfo = it->second;218 219 visit(base, baseInfo);220 }221 }222 }223 224 template <class NodeClass> void emitNodeReaderClass() {225 auto info = ReaderWriterInfo::forReader<NodeClass>();226 emitNodeReaderWriterClass<NodeClass>(info);227 }228 229 template <class NodeClass> void emitNodeWriterClass() {230 auto info = ReaderWriterInfo::forWriter<NodeClass>();231 emitNodeReaderWriterClass<NodeClass>(info);232 }233 234 template <class NodeClass>235 void emitNodeReaderWriterClass(const ReaderWriterInfo &info);236 237 template <class NodeClass>238 void emitNodeReaderWriterMethod(NodeClass node, const ReaderWriterInfo &info);239 240 void emitPropertiedReaderWriterBody(HasProperties node,241 const ReaderWriterInfo &info);242 243 void emitReadOfProperty(StringRef readerName, Property property);244 void emitReadOfProperty(StringRef readerName, StringRef name,245 PropertyType type, StringRef condition = "");246 247 void emitWriteOfProperty(StringRef writerName, Property property);248 void emitWriteOfProperty(StringRef writerName, StringRef name,249 PropertyType type, StringRef readCode,250 StringRef condition = "");251 252 void emitBasicReaderWriterFile(const ReaderWriterInfo &info);253 void emitDispatcherTemplate(const ReaderWriterInfo &info);254 void emitPackUnpackOptionalTemplate(const ReaderWriterInfo &info);255 void emitBasicReaderWriterTemplate(const ReaderWriterInfo &info);256 257 void emitCasedReaderWriterMethodBody(PropertyType type,258 const CasedTypeInfo &typeCases,259 const ReaderWriterInfo &info);260 261private:262 class Validator {263 ASTPropsEmitter &Emitter;264 std::set<HasProperties> ValidatedNodes;265 266 public:267 Validator(ASTPropsEmitter &emitter) : Emitter(emitter) {}268 void validate();269 270 private:271 void validateNode(HasProperties node, const NodeInfo &nodeInfo);272 void validateType(PropertyType type, WrappedRecord context);273 };274};275 276} // end anonymous namespace277 278void ASTPropsEmitter::Validator::validate() {279 for (auto &entry : Emitter.NodeInfos) {280 validateNode(entry.first, entry.second);281 }282 283 if (ErrorsPrinted > 0) {284 PrintFatalError("property validation failed");285 }286}287 288void ASTPropsEmitter::Validator::validateNode(HasProperties derivedNode,289 const NodeInfo &derivedNodeInfo) {290 if (!ValidatedNodes.insert(derivedNode).second) return;291 292 // A map from property name to property.293 std::map<StringRef, Property> allProperties;294 295 Emitter.visitAllNodesWithInfo(derivedNode, derivedNodeInfo,296 [&](HasProperties node,297 const NodeInfo &nodeInfo) {298 for (Property property : nodeInfo.Properties) {299 validateType(property.getType(), property);300 301 auto result = allProperties.insert(302 std::make_pair(property.getName(), property));303 304 // Diagnose non-unique properties.305 if (!result.second) {306 // The existing property is more likely to be associated with a307 // 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");313 }314 }315 });316}317 318void 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");325 }326 } else if (auto eltType = type.getArrayElementType()) {327 validateType(eltType, context);328 } else if (auto valueType = type.getOptionalElementType()) {329 validateType(valueType, context);330 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");339 }340 } else {341 PrintError(type.getLoc(), "unknown generic property type");342 if (context) PrintNote(context.getLoc(), "type used here");343 }344}345 346/****************************************************************************/347/**************************** AST READER/WRITERS ****************************/348/****************************************************************************/349 350template <class NodeClass>351void ASTPropsEmitter::emitNodeReaderWriterClass(const ReaderWriterInfo &info) {352 StringRef suffix = info.ClassSuffix;353 StringRef var = info.HelperVariable;354 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";360 361 // Emit the constructor.362 Out << " Abstract" << info.HierarchyName << suffix363 << "(Property" << suffix << " &" << var << ") : "364 << var << "(" << var << ") {}\n\n";365 366 // Emit a method that dispatches on a kind to the appropriate node-specific367 // method.368 Out << " " << info.ResultType << " " << info.MethodPrefix << "(";369 if (info.IsReader)370 Out << NodeClass::getASTIdTypeName() << " kind";371 else372 Out << "const " << info.HierarchyName << " *node";373 Out << ") {\n"374 " switch (";375 if (info.IsReader)376 Out << "kind";377 else378 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";388 });389 Out << " }\n"390 " llvm_unreachable(\"bad kind\");\n"391 " }\n\n";392 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);398 });399 400 // Finish the class.401 Out << "};\n\n";402}403 404/// Emit a reader method for the given concrete AST node class.405template <class NodeClass>406void 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";416 417 emitPropertiedReaderWriterBody(node, info);418 419 // Finish the method declaration.420 Out << " }\n\n";421}422 423void 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;432 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() + "\"");440 441 creationCode = nodeInfo.Creator.getCreationCode();442 }443 444 // Emit the ReadHelper code, if present.445 if (!info.IsReader && nodeInfo.ReadHelper) {446 Out << " " << nodeInfo.ReadHelper.getHelperCode() << "\n";447 }448 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() + "\"");457 458 // Emit code to read or write this property.459 if (info.IsReader)460 emitReadOfProperty(info.HelperVariable, prop);461 else462 emitWriteOfProperty(info.HelperVariable, prop);463 });464 465 // Emit the final creation code.466 if (info.IsReader)467 Out << " " << creationCode << "\n";468}469 470static 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 that478 // we don't cause spurious const mismatches.479 if (isForRead) {480 out << "<";481 eltType.emitCXXValueTypeName(isForRead, out);482 out << ">";483 }484 } else if (auto valueType = type.getOptionalElementType()) {485 out << "Optional";486 // We only include an explicit template argument for reads so that487 // we don't cause spurious const mismatches.488 if (isForRead) {489 out << "<";490 valueType.emitCXXValueTypeName(isForRead, out);491 out << ">";492 }493 } else {494 PrintFatalError(type.getLoc(), "unexpected generic property type");495 }496}497 498/// Emit code to read the given property in a node-reader method.499void ASTPropsEmitter::emitReadOfProperty(StringRef readerName,500 Property property) {501 emitReadOfProperty(readerName, property.getName(), property.getType(),502 property.getCondition());503}504 505void 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";515 }516 517 // T prop = R.find("prop").read##ValueType(buffers...);518 // We intentionally ignore shouldPassByReference here: we're going to519 // get a pr-value back from read(), and we should be able to forward520 // 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;527 528 if (condition.empty()) {529 Out << " = ";530 } else {531 Out << ";\n"532 " if (" << condition << ") {\n"533 " " << name << ".emplace(";534 }535 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;542 }543 Out << ")";544 545 if (condition.empty()) {546 Out << ";\n";547 } else {548 Out << ");\n"549 " }\n";550 }551}552 553/// Emit code to write the given property in a node-writer method.554void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName,555 Property property) {556 emitWriteOfProperty(writerName, property.getName(), property.getType(),557 property.getReadCode(), property.getCondition());558}559 560void 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";567 }568 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";578 579 if (!condition.empty()) {580 Out << " }\n";581 }582}583 584/// Emit an .inc file that defines the AbstractFooReader class585/// for the given AST class hierarchy.586template <class NodeClass>587static void emitASTReader(const RecordKeeper &records, raw_ostream &out,588 StringRef description) {589 emitSourceFileHeader(description, out, records);590 591 ASTPropsEmitter(records, out).emitNodeReaderClass<NodeClass>();592}593 594void clang::EmitClangTypeReader(const RecordKeeper &records, raw_ostream &out) {595 emitASTReader<TypeNode>(records, out, "A CRTP reader for Clang Type nodes");596}597 598/// Emit an .inc file that defines the AbstractFooWriter class599/// for the given AST class hierarchy.600template <class NodeClass>601static void emitASTWriter(const RecordKeeper &records, raw_ostream &out,602 StringRef description) {603 emitSourceFileHeader(description, out, records);604 605 ASTPropsEmitter(records, out).emitNodeWriterClass<NodeClass>();606}607 608void clang::EmitClangTypeWriter(const RecordKeeper &records, raw_ostream &out) {609 emitASTWriter<TypeNode>(records, out, "A CRTP writer for Clang Type nodes");610}611 612/****************************************************************************/613/*************************** BASIC READER/WRITERS ***************************/614/****************************************************************************/615 616void617ASTPropsEmitter::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";622 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.MethodPrefix635 << "(Basic" << info.ClassSuffix << " &" << var636 << ", Args &&... args) {\n"637 " return " << var << "."638 << info.MethodPrefix << methodSuffix639 << "(std::forward<Args>(args)...);\n"640 " }\n"641 "};\n";642 };643 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());654 }655 }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";662}663 664void665ASTPropsEmitter::emitPackUnpackOptionalTemplate(const ReaderWriterInfo &info) {666 StringRef classPrefix = (info.IsReader ? "Unpack" : "Pack");667 StringRef methodName = (info.IsReader ? "unpack" : "pack");668 669 // Declare the {Pack,Unpack}OptionalValue template.670 Out << "template <class ValueType>\n"671 "struct " << classPrefix << "OptionalValue;\n";672 673 auto declareSpecialization = [&](const Twine &typeName, StringRef code) {674 Out << "template <>\n"675 "struct "676 << classPrefix << "OptionalValue<" << typeName677 << "> {\n"678 " static "679 << (info.IsReader ? "std::optional<" : "") << typeName680 << (info.IsReader ? "> " : " ") << methodName << "("681 << (info.IsReader ? "" : "std::optional<") << typeName682 << (info.IsReader ? "" : ">")683 << " value) {\n"684 " return "685 << code686 << ";\n"687 " }\n"688 "};\n";689 };690 691 for (PropertyType type : AllPropertyTypes) {692 StringRef code = (info.IsReader ? type.getUnpackOptionalCode()693 : type.getPackOptionalCode());694 if (code.empty()) continue;695 696 StringRef typeName = type.getCXXTypeName();697 declareSpecialization(typeName, code);698 if (type.isConstWhenWriting() && !info.IsReader)699 declareSpecialization("const " + typeName, code);700 }701 Out << "\n";702}703 704void705ASTPropsEmitter::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";717 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 << cxxTypeName728 << (shouldPassByReference ? " &" : "") << " " << paramName;729 Out << ") {\n";730 };731 732 // Emit {read,write}ValueType methods for all the enum and subclass types733 // 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);741 };742 auto exitMethod = [&] {743 Out << " }\n";744 };745 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();752 753 } else if (type.isEnum()) {754 enterMethod("value");755 if (info.IsReader)756 Out << " return asImpl().template readEnum<"757 << type.getCXXTypeName() << ">();\n";758 else759 Out << " asImpl().writeEnum(value);\n";760 exitMethod();761 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 else770 Out << " asImpl().write" << superclass.getAbstractTypeName()771 << "(value);\n";772 exitMethod();773 774 } else {775 // The other types can't be handled as trivially.776 }777 }778 Out << "};\n\n";779}780 781void 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() + "\"");788 }789 if (!typeCases.KindRule) {790 assert(!typeCases.Cases.empty());791 PrintFatalError(typeCases.Cases.front().getLoc(),792 "no kind rule for \"" + type.getCXXTypeName() + "\"");793 }794 795 auto var = info.HelperVariable;796 std::string subvar = ("sub" + var).str();797 798 // Bind `ctx` for readers.799 if (info.IsReader)800 Out << " auto &ctx = asImpl().getASTContext();\n";801 802 // Start an object.803 Out << " auto &&" << subvar << " = asImpl()."804 << info.MethodPrefix << "Object();\n";805 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 the814 // kind into a local variable with the right name.815 emitWriteOfProperty(subvar, kindProperty, kindType,816 kindRule.getReadCode());817 }818 819 // Prepare a ReaderWriterInfo with a helper variable that will use820 // the sub-reader/writer.821 ReaderWriterInfo subInfo = info;822 subInfo.HelperVariable = subvar;823 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";833 }834 Out << " }\n"835 " llvm_unreachable(\"bad " << kindType.getCXXTypeName()836 << "\");\n";837}838 839void ASTPropsEmitter::emitBasicReaderWriterFile(const ReaderWriterInfo &info) {840 emitDispatcherTemplate(info);841 emitPackUnpackOptionalTemplate(info);842 emitBasicReaderWriterTemplate(info);843}844 845/// Emit an .inc file that defines some helper classes for reading846/// basic values.847void clang::EmitClangBasicReader(const RecordKeeper &records,848 raw_ostream &out) {849 emitSourceFileHeader("Helper classes for BasicReaders", out, records);850 851 // Use any property, we won't be using those properties.852 auto info = ReaderWriterInfo::forReader<TypeNode>();853 ASTPropsEmitter(records, out).emitBasicReaderWriterFile(info);854}855 856/// Emit an .inc file that defines some helper classes for writing857/// basic values.858void clang::EmitClangBasicWriter(const RecordKeeper &records,859 raw_ostream &out) {860 emitSourceFileHeader("Helper classes for BasicWriters", out, records);861 862 // Use any property, we won't be using those properties.863 auto info = ReaderWriterInfo::forWriter<TypeNode>();864 ASTPropsEmitter(records, out).emitBasicReaderWriterFile(info);865}866