brintos

brintos / llvm-project-archived public Read only

0
0
Text · 30.3 KiB · acff6fe Raw
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