Path: blob/main/contrib/llvm-project/clang/utils/TableGen/ClangASTPropertiesEmitter.cpp
35230 views
//=== ClangASTPropsEmitter.cpp - Generate Clang AST properties --*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This tablegen backend emits code for working with Clang AST properties.9//10//===----------------------------------------------------------------------===//1112#include "ASTTableGen.h"13#include "TableGenBackends.h"1415#include "llvm/ADT/STLExtras.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 <optional>23#include <set>24#include <string>25using namespace llvm;26using namespace clang;27using namespace clang::tblgen;2829static StringRef getReaderResultType(TypeNode _) { return "QualType"; }3031namespace {3233struct ReaderWriterInfo {34bool IsReader;3536/// The name of the node hierarchy. Not actually sensitive to IsReader,37/// but useful to cache here anyway.38StringRef HierarchyName;3940/// The suffix on classes: Reader/Writer41StringRef ClassSuffix;4243/// The base name of methods: read/write44StringRef MethodPrefix;4546/// The name of the property helper member: R/W47StringRef HelperVariable;4849/// The result type of methods on the class.50StringRef ResultType;5152template <class NodeClass>53static ReaderWriterInfo forReader() {54return ReaderWriterInfo{55true,56NodeClass::getASTHierarchyName(),57"Reader",58"read",59"R",60getReaderResultType(NodeClass())61};62}6364template <class NodeClass>65static ReaderWriterInfo forWriter() {66return ReaderWriterInfo{67false,68NodeClass::getASTHierarchyName(),69"Writer",70"write",71"W",72"void"73};74}75};7677struct NodeInfo {78std::vector<Property> Properties;79CreationRule Creator = nullptr;80OverrideRule Override = nullptr;81ReadHelperRule ReadHelper = nullptr;82};8384struct CasedTypeInfo {85TypeKindRule KindRule;86std::vector<TypeCase> Cases;87};8889class ASTPropsEmitter {90raw_ostream &Out;91RecordKeeper &Records;92std::map<HasProperties, NodeInfo> NodeInfos;93std::vector<PropertyType> AllPropertyTypes;94std::map<PropertyType, CasedTypeInfo> CasedTypeInfos;9596public:97ASTPropsEmitter(RecordKeeper &records, raw_ostream &out)98: Out(out), Records(records) {99100// Find all the properties.101for (Property property :102records.getAllDerivedDefinitions(PropertyClassName)) {103HasProperties node = property.getClass();104NodeInfos[node].Properties.push_back(property);105}106107// Find all the creation rules.108for (CreationRule creationRule :109records.getAllDerivedDefinitions(CreationRuleClassName)) {110HasProperties node = creationRule.getClass();111112auto &info = NodeInfos[node];113if (info.Creator) {114PrintFatalError(creationRule.getLoc(),115"multiple creator rules for \"" + node.getName()116+ "\"");117}118info.Creator = creationRule;119}120121// Find all the override rules.122for (OverrideRule overrideRule :123records.getAllDerivedDefinitions(OverrideRuleClassName)) {124HasProperties node = overrideRule.getClass();125126auto &info = NodeInfos[node];127if (info.Override) {128PrintFatalError(overrideRule.getLoc(),129"multiple override rules for \"" + node.getName()130+ "\"");131}132info.Override = overrideRule;133}134135// Find all the write helper rules.136for (ReadHelperRule helperRule :137records.getAllDerivedDefinitions(ReadHelperRuleClassName)) {138HasProperties node = helperRule.getClass();139140auto &info = NodeInfos[node];141if (info.ReadHelper) {142PrintFatalError(helperRule.getLoc(),143"multiple write helper rules for \"" + node.getName()144+ "\"");145}146info.ReadHelper = helperRule;147}148149// Find all the concrete property types.150for (PropertyType type :151records.getAllDerivedDefinitions(PropertyTypeClassName)) {152// Ignore generic specializations; they're generally not useful when153// emitting basic emitters etc.154if (type.isGenericSpecialization()) continue;155156AllPropertyTypes.push_back(type);157}158159// Find all the type kind rules.160for (TypeKindRule kindRule :161records.getAllDerivedDefinitions(TypeKindClassName)) {162PropertyType type = kindRule.getParentType();163auto &info = CasedTypeInfos[type];164if (info.KindRule) {165PrintFatalError(kindRule.getLoc(),166"multiple kind rules for \""167+ type.getCXXTypeName() + "\"");168}169info.KindRule = kindRule;170}171172// Find all the type cases.173for (TypeCase typeCase :174records.getAllDerivedDefinitions(TypeCaseClassName)) {175CasedTypeInfos[typeCase.getParentType()].Cases.push_back(typeCase);176}177178Validator(*this).validate();179}180181void visitAllProperties(HasProperties derived, const NodeInfo &derivedInfo,182function_ref<void (Property)> visit) {183std::set<StringRef> ignoredProperties;184185auto overrideRule = derivedInfo.Override;186if (overrideRule) {187auto list = overrideRule.getIgnoredProperties();188ignoredProperties.insert(list.begin(), list.end());189}190191// TODO: we should sort the properties in various ways192// - put arrays at the end to enable abbreviations193// - put conditional properties after properties used in the condition194195visitAllNodesWithInfo(derived, derivedInfo,196[&](HasProperties node, const NodeInfo &info) {197for (Property prop : info.Properties) {198if (ignoredProperties.count(prop.getName()))199continue;200201visit(prop);202}203});204}205206void visitAllNodesWithInfo(HasProperties derivedNode,207const NodeInfo &derivedNodeInfo,208llvm::function_ref<void (HasProperties node,209const NodeInfo &info)>210visit) {211visit(derivedNode, derivedNodeInfo);212213// Also walk the bases if appropriate.214if (ASTNode base = derivedNode.getAs<ASTNode>()) {215for (base = base.getBase(); base; base = base.getBase()) {216auto it = NodeInfos.find(base);217218// Ignore intermediate nodes that don't add interesting properties.219if (it == NodeInfos.end()) continue;220auto &baseInfo = it->second;221222visit(base, baseInfo);223}224}225}226227template <class NodeClass>228void emitNodeReaderClass() {229auto info = ReaderWriterInfo::forReader<NodeClass>();230emitNodeReaderWriterClass<NodeClass>(info);231}232233template <class NodeClass>234void emitNodeWriterClass() {235auto info = ReaderWriterInfo::forWriter<NodeClass>();236emitNodeReaderWriterClass<NodeClass>(info);237}238239template <class NodeClass>240void emitNodeReaderWriterClass(const ReaderWriterInfo &info);241242template <class NodeClass>243void emitNodeReaderWriterMethod(NodeClass node,244const ReaderWriterInfo &info);245246void emitPropertiedReaderWriterBody(HasProperties node,247const ReaderWriterInfo &info);248249void emitReadOfProperty(StringRef readerName, Property property);250void emitReadOfProperty(StringRef readerName, StringRef name,251PropertyType type, StringRef condition = "");252253void emitWriteOfProperty(StringRef writerName, Property property);254void emitWriteOfProperty(StringRef writerName, StringRef name,255PropertyType type, StringRef readCode,256StringRef condition = "");257258void emitBasicReaderWriterFile(const ReaderWriterInfo &info);259void emitDispatcherTemplate(const ReaderWriterInfo &info);260void emitPackUnpackOptionalTemplate(const ReaderWriterInfo &info);261void emitBasicReaderWriterTemplate(const ReaderWriterInfo &info);262263void emitCasedReaderWriterMethodBody(PropertyType type,264const CasedTypeInfo &typeCases,265const ReaderWriterInfo &info);266267private:268class Validator {269ASTPropsEmitter &Emitter;270std::set<HasProperties> ValidatedNodes;271272public:273Validator(ASTPropsEmitter &emitter) : Emitter(emitter) {}274void validate();275276private:277void validateNode(HasProperties node, const NodeInfo &nodeInfo);278void validateType(PropertyType type, WrappedRecord context);279};280};281282} // end anonymous namespace283284void ASTPropsEmitter::Validator::validate() {285for (auto &entry : Emitter.NodeInfos) {286validateNode(entry.first, entry.second);287}288289if (ErrorsPrinted > 0) {290PrintFatalError("property validation failed");291}292}293294void ASTPropsEmitter::Validator::validateNode(HasProperties derivedNode,295const NodeInfo &derivedNodeInfo) {296if (!ValidatedNodes.insert(derivedNode).second) return;297298// A map from property name to property.299std::map<StringRef, Property> allProperties;300301Emitter.visitAllNodesWithInfo(derivedNode, derivedNodeInfo,302[&](HasProperties node,303const NodeInfo &nodeInfo) {304for (Property property : nodeInfo.Properties) {305validateType(property.getType(), property);306307auto result = allProperties.insert(308std::make_pair(property.getName(), property));309310// Diagnose non-unique properties.311if (!result.second) {312// The existing property is more likely to be associated with a313// derived node, so use it as the error.314Property existingProperty = result.first->second;315PrintError(existingProperty.getLoc(),316"multiple properties named \"" + property.getName()317+ "\" in hierarchy of " + derivedNode.getName());318PrintNote(property.getLoc(), "existing property");319}320}321});322}323324void ASTPropsEmitter::Validator::validateType(PropertyType type,325WrappedRecord context) {326if (!type.isGenericSpecialization()) {327if (type.getCXXTypeName() == "") {328PrintError(type.getLoc(),329"type is not generic but has no C++ type name");330if (context) PrintNote(context.getLoc(), "type used here");331}332} else if (auto eltType = type.getArrayElementType()) {333validateType(eltType, context);334} else if (auto valueType = type.getOptionalElementType()) {335validateType(valueType, context);336337if (valueType.getPackOptionalCode().empty()) {338PrintError(valueType.getLoc(),339"type doesn't provide optional-packing code");340if (context) PrintNote(context.getLoc(), "type used here");341} else if (valueType.getUnpackOptionalCode().empty()) {342PrintError(valueType.getLoc(),343"type doesn't provide optional-unpacking code");344if (context) PrintNote(context.getLoc(), "type used here");345}346} else {347PrintError(type.getLoc(), "unknown generic property type");348if (context) PrintNote(context.getLoc(), "type used here");349}350}351352/****************************************************************************/353/**************************** AST READER/WRITERS ****************************/354/****************************************************************************/355356template <class NodeClass>357void ASTPropsEmitter::emitNodeReaderWriterClass(const ReaderWriterInfo &info) {358StringRef suffix = info.ClassSuffix;359StringRef var = info.HelperVariable;360361// Enter the class declaration.362Out << "template <class Property" << suffix << ">\n"363"class Abstract" << info.HierarchyName << suffix << " {\n"364"public:\n"365" Property" << suffix << " &" << var << ";\n\n";366367// Emit the constructor.368Out << " Abstract" << info.HierarchyName << suffix369<< "(Property" << suffix << " &" << var << ") : "370<< var << "(" << var << ") {}\n\n";371372// Emit a method that dispatches on a kind to the appropriate node-specific373// method.374Out << " " << info.ResultType << " " << info.MethodPrefix << "(";375if (info.IsReader)376Out << NodeClass::getASTIdTypeName() << " kind";377else378Out << "const " << info.HierarchyName << " *node";379Out << ") {\n"380" switch (";381if (info.IsReader)382Out << "kind";383else384Out << "node->" << NodeClass::getASTIdAccessorName() << "()";385Out << ") {\n";386visitASTNodeHierarchy<NodeClass>(Records, [&](NodeClass node, NodeClass _) {387if (node.isAbstract()) return;388Out << " case " << info.HierarchyName << "::" << node.getId() << ":\n"389" return " << info.MethodPrefix << node.getClassName() << "(";390if (!info.IsReader)391Out << "static_cast<const " << node.getClassName()392<< " *>(node)";393Out << ");\n";394});395Out << " }\n"396" llvm_unreachable(\"bad kind\");\n"397" }\n\n";398399// Emit node-specific methods for all the concrete nodes.400visitASTNodeHierarchy<NodeClass>(Records,401[&](NodeClass node, NodeClass base) {402if (node.isAbstract()) return;403emitNodeReaderWriterMethod(node, info);404});405406// Finish the class.407Out << "};\n\n";408}409410/// Emit a reader method for the given concrete AST node class.411template <class NodeClass>412void ASTPropsEmitter::emitNodeReaderWriterMethod(NodeClass node,413const ReaderWriterInfo &info) {414// Declare and start the method.415Out << " " << info.ResultType << " "416<< info.MethodPrefix << node.getClassName() << "(";417if (!info.IsReader)418Out << "const " << node.getClassName() << " *node";419Out << ") {\n";420if (info.IsReader)421Out << " auto &ctx = " << info.HelperVariable << ".getASTContext();\n";422423emitPropertiedReaderWriterBody(node, info);424425// Finish the method declaration.426Out << " }\n\n";427}428429void ASTPropsEmitter::emitPropertiedReaderWriterBody(HasProperties node,430const ReaderWriterInfo &info) {431// Find the information for this node.432auto it = NodeInfos.find(node);433if (it == NodeInfos.end())434PrintFatalError(node.getLoc(),435"no information about how to deserialize \""436+ node.getName() + "\"");437auto &nodeInfo = it->second;438439StringRef creationCode;440if (info.IsReader) {441// We should have a creation rule.442if (!nodeInfo.Creator)443PrintFatalError(node.getLoc(),444"no " CreationRuleClassName " for \""445+ node.getName() + "\"");446447creationCode = nodeInfo.Creator.getCreationCode();448}449450// Emit the ReadHelper code, if present.451if (!info.IsReader && nodeInfo.ReadHelper) {452Out << " " << nodeInfo.ReadHelper.getHelperCode() << "\n";453}454455// Emit code to read all the properties.456visitAllProperties(node, nodeInfo, [&](Property prop) {457// Verify that the creation code refers to this property.458if (info.IsReader && !creationCode.contains(prop.getName()))459PrintFatalError(nodeInfo.Creator.getLoc(),460"creation code for " + node.getName()461+ " doesn't refer to property \""462+ prop.getName() + "\"");463464// Emit code to read or write this property.465if (info.IsReader)466emitReadOfProperty(info.HelperVariable, prop);467else468emitWriteOfProperty(info.HelperVariable, prop);469});470471// Emit the final creation code.472if (info.IsReader)473Out << " " << creationCode << "\n";474}475476static void emitBasicReaderWriterMethodSuffix(raw_ostream &out,477PropertyType type,478bool isForRead) {479if (!type.isGenericSpecialization()) {480out << type.getAbstractTypeName();481} else if (auto eltType = type.getArrayElementType()) {482out << "Array";483// We only include an explicit template argument for reads so that484// we don't cause spurious const mismatches.485if (isForRead) {486out << "<";487eltType.emitCXXValueTypeName(isForRead, out);488out << ">";489}490} else if (auto valueType = type.getOptionalElementType()) {491out << "Optional";492// We only include an explicit template argument for reads so that493// we don't cause spurious const mismatches.494if (isForRead) {495out << "<";496valueType.emitCXXValueTypeName(isForRead, out);497out << ">";498}499} else {500PrintFatalError(type.getLoc(), "unexpected generic property type");501}502}503504/// Emit code to read the given property in a node-reader method.505void ASTPropsEmitter::emitReadOfProperty(StringRef readerName,506Property property) {507emitReadOfProperty(readerName, property.getName(), property.getType(),508property.getCondition());509}510511void ASTPropsEmitter::emitReadOfProperty(StringRef readerName,512StringRef name,513PropertyType type,514StringRef condition) {515// Declare all the necessary buffers.516auto bufferTypes = type.getBufferElementTypes();517for (size_t i = 0, e = bufferTypes.size(); i != e; ++i) {518Out << " llvm::SmallVector<";519PropertyType(bufferTypes[i]).emitCXXValueTypeName(/*for read*/ true, Out);520Out << ", 8> " << name << "_buffer_" << i << ";\n";521}522523// T prop = R.find("prop").read##ValueType(buffers...);524// We intentionally ignore shouldPassByReference here: we're going to525// get a pr-value back from read(), and we should be able to forward526// that in the creation rule.527Out << " ";528if (!condition.empty())529Out << "std::optional<";530type.emitCXXValueTypeName(true, Out);531if (!condition.empty()) Out << ">";532Out << " " << name;533534if (condition.empty()) {535Out << " = ";536} else {537Out << ";\n"538" if (" << condition << ") {\n"539" " << name << ".emplace(";540}541542Out << readerName << ".find(\"" << name << "\")."543<< (type.isGenericSpecialization() ? "template " : "") << "read";544emitBasicReaderWriterMethodSuffix(Out, type, /*for read*/ true);545Out << "(";546for (size_t i = 0, e = bufferTypes.size(); i != e; ++i) {547Out << (i > 0 ? ", " : "") << name << "_buffer_" << i;548}549Out << ")";550551if (condition.empty()) {552Out << ";\n";553} else {554Out << ");\n"555" }\n";556}557}558559/// Emit code to write the given property in a node-writer method.560void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName,561Property property) {562emitWriteOfProperty(writerName, property.getName(), property.getType(),563property.getReadCode(), property.getCondition());564}565566void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName,567StringRef name,568PropertyType type,569StringRef readCode,570StringRef condition) {571if (!condition.empty()) {572Out << " if (" << condition << ") {\n";573}574575// Focus down to the property:576// T prop = <READ>;577// W.find("prop").write##ValueType(prop);578Out << " ";579type.emitCXXValueTypeName(false, Out);580Out << " " << name << " = (" << readCode << ");\n"581" " << writerName << ".find(\"" << name << "\").write";582emitBasicReaderWriterMethodSuffix(Out, type, /*for read*/ false);583Out << "(" << name << ");\n";584585if (!condition.empty()) {586Out << " }\n";587}588}589590/// Emit an .inc file that defines the AbstractFooReader class591/// for the given AST class hierarchy.592template <class NodeClass>593static void emitASTReader(RecordKeeper &records, raw_ostream &out,594StringRef description) {595emitSourceFileHeader(description, out, records);596597ASTPropsEmitter(records, out).emitNodeReaderClass<NodeClass>();598}599600void clang::EmitClangTypeReader(RecordKeeper &records, raw_ostream &out) {601emitASTReader<TypeNode>(records, out, "A CRTP reader for Clang Type nodes");602}603604/// Emit an .inc file that defines the AbstractFooWriter class605/// for the given AST class hierarchy.606template <class NodeClass>607static void emitASTWriter(RecordKeeper &records, raw_ostream &out,608StringRef description) {609emitSourceFileHeader(description, out, records);610611ASTPropsEmitter(records, out).emitNodeWriterClass<NodeClass>();612}613614void clang::EmitClangTypeWriter(RecordKeeper &records, raw_ostream &out) {615emitASTWriter<TypeNode>(records, out, "A CRTP writer for Clang Type nodes");616}617618/****************************************************************************/619/*************************** BASIC READER/WRITERS ***************************/620/****************************************************************************/621622void623ASTPropsEmitter::emitDispatcherTemplate(const ReaderWriterInfo &info) {624// Declare the {Read,Write}Dispatcher template.625StringRef dispatcherPrefix = (info.IsReader ? "Read" : "Write");626Out << "template <class ValueType>\n"627"struct " << dispatcherPrefix << "Dispatcher;\n";628629// Declare a specific specialization of the dispatcher template.630auto declareSpecialization =631[&](StringRef specializationParameters,632const Twine &cxxTypeName,633StringRef methodSuffix) {634StringRef var = info.HelperVariable;635Out << "template " << specializationParameters << "\n"636"struct " << dispatcherPrefix << "Dispatcher<"637<< cxxTypeName << "> {\n";638Out << " template <class Basic" << info.ClassSuffix << ", class... Args>\n"639" static " << (info.IsReader ? cxxTypeName : "void") << " "640<< info.MethodPrefix641<< "(Basic" << info.ClassSuffix << " &" << var642<< ", Args &&... args) {\n"643" return " << var << "."644<< info.MethodPrefix << methodSuffix645<< "(std::forward<Args>(args)...);\n"646" }\n"647"};\n";648};649650// Declare explicit specializations for each of the concrete types.651for (PropertyType type : AllPropertyTypes) {652declareSpecialization("<>",653type.getCXXTypeName(),654type.getAbstractTypeName());655// Also declare a specialization for the const type when appropriate.656if (!info.IsReader && type.isConstWhenWriting()) {657declareSpecialization("<>",658"const " + type.getCXXTypeName(),659type.getAbstractTypeName());660}661}662// Declare partial specializations for ArrayRef and Optional.663declareSpecialization("<class T>",664"llvm::ArrayRef<T>",665"Array");666declareSpecialization("<class T>", "std::optional<T>", "Optional");667Out << "\n";668}669670void671ASTPropsEmitter::emitPackUnpackOptionalTemplate(const ReaderWriterInfo &info) {672StringRef classPrefix = (info.IsReader ? "Unpack" : "Pack");673StringRef methodName = (info.IsReader ? "unpack" : "pack");674675// Declare the {Pack,Unpack}OptionalValue template.676Out << "template <class ValueType>\n"677"struct " << classPrefix << "OptionalValue;\n";678679auto declareSpecialization = [&](const Twine &typeName, StringRef code) {680Out << "template <>\n"681"struct "682<< classPrefix << "OptionalValue<" << typeName683<< "> {\n"684" static "685<< (info.IsReader ? "std::optional<" : "") << typeName686<< (info.IsReader ? "> " : " ") << methodName << "("687<< (info.IsReader ? "" : "std::optional<") << typeName688<< (info.IsReader ? "" : ">")689<< " value) {\n"690" return "691<< code692<< ";\n"693" }\n"694"};\n";695};696697for (PropertyType type : AllPropertyTypes) {698StringRef code = (info.IsReader ? type.getUnpackOptionalCode()699: type.getPackOptionalCode());700if (code.empty()) continue;701702StringRef typeName = type.getCXXTypeName();703declareSpecialization(typeName, code);704if (type.isConstWhenWriting() && !info.IsReader)705declareSpecialization("const " + typeName, code);706}707Out << "\n";708}709710void711ASTPropsEmitter::emitBasicReaderWriterTemplate(const ReaderWriterInfo &info) {712// Emit the Basic{Reader,Writer}Base template.713Out << "template <class Impl>\n"714"class Basic" << info.ClassSuffix << "Base {\n";715Out << " ASTContext &C;\n";716Out << "protected:\n"717" Basic"718<< info.ClassSuffix << "Base" << ("(ASTContext &ctx) : C(ctx)")719<< " {}\n"720"public:\n";721Out << " ASTContext &getASTContext() { return C; }\n";722Out << " Impl &asImpl() { return static_cast<Impl&>(*this); }\n";723724auto enterReaderWriterMethod = [&](StringRef cxxTypeName,725StringRef abstractTypeName,726bool shouldPassByReference,727bool constWhenWriting,728StringRef paramName) {729Out << " " << (info.IsReader ? cxxTypeName : "void")730<< " " << info.MethodPrefix << abstractTypeName << "(";731if (!info.IsReader)732Out << (shouldPassByReference || constWhenWriting ? "const " : "")733<< cxxTypeName734<< (shouldPassByReference ? " &" : "") << " " << paramName;735Out << ") {\n";736};737738// Emit {read,write}ValueType methods for all the enum and subclass types739// that default to using the integer/base-class implementations.740for (PropertyType type : AllPropertyTypes) {741auto enterMethod = [&](StringRef paramName) {742enterReaderWriterMethod(type.getCXXTypeName(),743type.getAbstractTypeName(),744type.shouldPassByReference(),745type.isConstWhenWriting(),746paramName);747};748auto exitMethod = [&] {749Out << " }\n";750};751752// Handled cased types.753auto casedIter = CasedTypeInfos.find(type);754if (casedIter != CasedTypeInfos.end()) {755enterMethod("node");756emitCasedReaderWriterMethodBody(type, casedIter->second, info);757exitMethod();758759} else if (type.isEnum()) {760enterMethod("value");761if (info.IsReader)762Out << " return asImpl().template readEnum<"763<< type.getCXXTypeName() << ">();\n";764else765Out << " asImpl().writeEnum(value);\n";766exitMethod();767768} else if (PropertyType superclass = type.getSuperclassType()) {769enterMethod("value");770if (info.IsReader)771Out << " return cast_or_null<" << type.getSubclassClassName()772<< ">(asImpl().read"773<< superclass.getAbstractTypeName()774<< "());\n";775else776Out << " asImpl().write" << superclass.getAbstractTypeName()777<< "(value);\n";778exitMethod();779780} else {781// The other types can't be handled as trivially.782}783}784Out << "};\n\n";785}786787void ASTPropsEmitter::emitCasedReaderWriterMethodBody(PropertyType type,788const CasedTypeInfo &typeCases,789const ReaderWriterInfo &info) {790if (typeCases.Cases.empty()) {791assert(typeCases.KindRule);792PrintFatalError(typeCases.KindRule.getLoc(),793"no cases found for \"" + type.getCXXTypeName() + "\"");794}795if (!typeCases.KindRule) {796assert(!typeCases.Cases.empty());797PrintFatalError(typeCases.Cases.front().getLoc(),798"no kind rule for \"" + type.getCXXTypeName() + "\"");799}800801auto var = info.HelperVariable;802std::string subvar = ("sub" + var).str();803804// Bind `ctx` for readers.805if (info.IsReader)806Out << " auto &ctx = asImpl().getASTContext();\n";807808// Start an object.809Out << " auto &&" << subvar << " = asImpl()."810<< info.MethodPrefix << "Object();\n";811812// Read/write the kind property;813TypeKindRule kindRule = typeCases.KindRule;814StringRef kindProperty = kindRule.getKindPropertyName();815PropertyType kindType = kindRule.getKindType();816if (info.IsReader) {817emitReadOfProperty(subvar, kindProperty, kindType);818} else {819// Write the property. Note that this will implicitly read the820// kind into a local variable with the right name.821emitWriteOfProperty(subvar, kindProperty, kindType,822kindRule.getReadCode());823}824825// Prepare a ReaderWriterInfo with a helper variable that will use826// the sub-reader/writer.827ReaderWriterInfo subInfo = info;828subInfo.HelperVariable = subvar;829830// Switch on the kind.831Out << " switch (" << kindProperty << ") {\n";832for (TypeCase typeCase : typeCases.Cases) {833Out << " case " << type.getCXXTypeName() << "::"834<< typeCase.getCaseName() << ": {\n";835emitPropertiedReaderWriterBody(typeCase, subInfo);836if (!info.IsReader)837Out << " return;\n";838Out << " }\n\n";839}840Out << " }\n"841" llvm_unreachable(\"bad " << kindType.getCXXTypeName()842<< "\");\n";843}844845void ASTPropsEmitter::emitBasicReaderWriterFile(const ReaderWriterInfo &info) {846emitDispatcherTemplate(info);847emitPackUnpackOptionalTemplate(info);848emitBasicReaderWriterTemplate(info);849}850851/// Emit an .inc file that defines some helper classes for reading852/// basic values.853void clang::EmitClangBasicReader(RecordKeeper &records, raw_ostream &out) {854emitSourceFileHeader("Helper classes for BasicReaders", out, records);855856// Use any property, we won't be using those properties.857auto info = ReaderWriterInfo::forReader<TypeNode>();858ASTPropsEmitter(records, out).emitBasicReaderWriterFile(info);859}860861/// Emit an .inc file that defines some helper classes for writing862/// basic values.863void clang::EmitClangBasicWriter(RecordKeeper &records, raw_ostream &out) {864emitSourceFileHeader("Helper classes for BasicWriters", out, records);865866// Use any property, we won't be using those properties.867auto info = ReaderWriterInfo::forWriter<TypeNode>();868ASTPropsEmitter(records, out).emitBasicReaderWriterFile(info);869}870871872