ClangASTPropertiesEmitter.cpp revision 360784
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.
10//
11//===----------------------------------------------------------------------===//
12
13#include "ASTTableGen.h"
14#include "TableGenBackends.h"
15
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 <set>
24#include <string>
25using namespace llvm;
26using namespace clang;
27using namespace clang::tblgen;
28
29static StringRef getReaderResultType(TypeNode _) { return "QualType"; }
30
31namespace {
32
33struct ReaderWriterInfo {
34  bool IsReader;
35
36  /// The name of the node hierarchy.  Not actually sensitive to IsReader,
37  /// but useful to cache here anyway.
38  StringRef HierarchyName;
39
40  /// The suffix on classes: Reader/Writer
41  StringRef ClassSuffix;
42
43  /// The base name of methods: read/write
44  StringRef MethodPrefix;
45
46  /// The name of the property helper member: R/W
47  StringRef HelperVariable;
48
49  /// The result type of methods on the class.
50  StringRef ResultType;
51
52  template <class NodeClass>
53  static ReaderWriterInfo forReader() {
54    return ReaderWriterInfo{
55      true,
56      NodeClass::getASTHierarchyName(),
57      "Reader",
58      "read",
59      "R",
60      getReaderResultType(NodeClass())
61    };
62  }
63
64  template <class NodeClass>
65  static ReaderWriterInfo forWriter() {
66    return ReaderWriterInfo{
67      false,
68      NodeClass::getASTHierarchyName(),
69      "Writer",
70      "write",
71      "W",
72      "void"
73    };
74  }
75};
76
77struct NodeInfo {
78  std::vector<Property> Properties;
79  CreationRule Creator = nullptr;
80  OverrideRule Override = nullptr;
81  ReadHelperRule ReadHelper = nullptr;
82};
83
84struct CasedTypeInfo {
85  TypeKindRule KindRule;
86  std::vector<TypeCase> Cases;
87};
88
89class ASTPropsEmitter {
90	raw_ostream &Out;
91	RecordKeeper &Records;
92	std::map<HasProperties, NodeInfo> NodeInfos;
93  std::vector<PropertyType> AllPropertyTypes;
94  std::map<PropertyType, CasedTypeInfo> CasedTypeInfos;
95
96public:
97	ASTPropsEmitter(RecordKeeper &records, raw_ostream &out)
98		: Out(out), Records(records) {
99
100		// Find all the properties.
101		for (Property property :
102           records.getAllDerivedDefinitions(PropertyClassName)) {
103			HasProperties node = property.getClass();
104			NodeInfos[node].Properties.push_back(property);
105		}
106
107    // Find all the creation rules.
108    for (CreationRule creationRule :
109           records.getAllDerivedDefinitions(CreationRuleClassName)) {
110      HasProperties node = creationRule.getClass();
111
112      auto &info = NodeInfos[node];
113      if (info.Creator) {
114        PrintFatalError(creationRule.getLoc(),
115                        "multiple creator rules for \"" + node.getName()
116                          + "\"");
117      }
118      info.Creator = creationRule;
119    }
120
121    // Find all the override rules.
122    for (OverrideRule overrideRule :
123           records.getAllDerivedDefinitions(OverrideRuleClassName)) {
124      HasProperties node = overrideRule.getClass();
125
126      auto &info = NodeInfos[node];
127      if (info.Override) {
128        PrintFatalError(overrideRule.getLoc(),
129                        "multiple override rules for \"" + node.getName()
130                          + "\"");
131      }
132      info.Override = overrideRule;
133    }
134
135    // Find all the write helper rules.
136    for (ReadHelperRule helperRule :
137           records.getAllDerivedDefinitions(ReadHelperRuleClassName)) {
138      HasProperties node = helperRule.getClass();
139
140      auto &info = NodeInfos[node];
141      if (info.ReadHelper) {
142        PrintFatalError(helperRule.getLoc(),
143                        "multiple write helper rules for \"" + node.getName()
144                          + "\"");
145      }
146      info.ReadHelper = helperRule;
147    }
148
149    // Find all the concrete property types.
150    for (PropertyType type :
151           records.getAllDerivedDefinitions(PropertyTypeClassName)) {
152      // Ignore generic specializations; they're generally not useful when
153      // emitting basic emitters etc.
154      if (type.isGenericSpecialization()) continue;
155
156      AllPropertyTypes.push_back(type);
157    }
158
159    // Find all the type kind rules.
160    for (TypeKindRule kindRule :
161           records.getAllDerivedDefinitions(TypeKindClassName)) {
162      PropertyType type = kindRule.getParentType();
163      auto &info = CasedTypeInfos[type];
164      if (info.KindRule) {
165        PrintFatalError(kindRule.getLoc(),
166                        "multiple kind rules for \""
167                           + type.getCXXTypeName() + "\"");
168      }
169      info.KindRule = kindRule;
170    }
171
172    // Find all the type cases.
173    for (TypeCase typeCase :
174           records.getAllDerivedDefinitions(TypeCaseClassName)) {
175      CasedTypeInfos[typeCase.getParentType()].Cases.push_back(typeCase);
176    }
177
178    Validator(*this).validate();
179	}
180
181  void visitAllProperties(HasProperties derived, const NodeInfo &derivedInfo,
182                          function_ref<void (Property)> visit) {
183    std::set<StringRef> ignoredProperties;
184
185    auto overrideRule = derivedInfo.Override;
186    if (overrideRule) {
187      auto list = overrideRule.getIgnoredProperties();
188      ignoredProperties.insert(list.begin(), list.end());
189    }
190
191    // TODO: we should sort the properties in various ways
192    //   - put arrays at the end to enable abbreviations
193    //   - put conditional properties after properties used in the condition
194
195    visitAllNodesWithInfo(derived, derivedInfo,
196                          [&](HasProperties node, const NodeInfo &info) {
197      for (Property prop : info.Properties) {
198        if (ignoredProperties.count(prop.getName()))
199          continue;
200
201        visit(prop);
202      }
203    });
204  }
205
206  void visitAllNodesWithInfo(HasProperties derivedNode,
207                             const NodeInfo &derivedNodeInfo,
208                             llvm::function_ref<void (HasProperties node,
209                                                      const NodeInfo &info)>
210                               visit) {
211    visit(derivedNode, derivedNodeInfo);
212
213    // Also walk the bases if appropriate.
214    if (ASTNode base = derivedNode.getAs<ASTNode>()) {
215      for (base = base.getBase(); base; base = base.getBase()) {
216        auto it = NodeInfos.find(base);
217
218        // Ignore intermediate nodes that don't add interesting properties.
219        if (it == NodeInfos.end()) continue;
220        auto &baseInfo = it->second;
221
222        visit(base, baseInfo);
223      }
224    }
225  }
226
227  template <class NodeClass>
228  void emitNodeReaderClass() {
229    auto info = ReaderWriterInfo::forReader<NodeClass>();
230    emitNodeReaderWriterClass<NodeClass>(info);
231  }
232
233  template <class NodeClass>
234  void emitNodeWriterClass() {
235    auto info = ReaderWriterInfo::forWriter<NodeClass>();
236    emitNodeReaderWriterClass<NodeClass>(info);
237  }
238
239  template <class NodeClass>
240  void emitNodeReaderWriterClass(const ReaderWriterInfo &info);
241
242  template <class NodeClass>
243  void emitNodeReaderWriterMethod(NodeClass node,
244                                  const ReaderWriterInfo &info);
245
246  void emitPropertiedReaderWriterBody(HasProperties node,
247                                      const ReaderWriterInfo &info);
248
249  void emitReadOfProperty(StringRef readerName, Property property);
250  void emitReadOfProperty(StringRef readerName, StringRef name,
251                          PropertyType type, StringRef condition = "");
252
253  void emitWriteOfProperty(StringRef writerName, Property property);
254  void emitWriteOfProperty(StringRef writerName, StringRef name,
255                           PropertyType type, StringRef readCode,
256                           StringRef condition = "");
257
258  void emitBasicReaderWriterFile(const ReaderWriterInfo &info);
259  void emitDispatcherTemplate(const ReaderWriterInfo &info);
260  void emitPackUnpackOptionalTemplate(const ReaderWriterInfo &info);
261  void emitBasicReaderWriterTemplate(const ReaderWriterInfo &info);
262
263  void emitCasedReaderWriterMethodBody(PropertyType type,
264                                       const CasedTypeInfo &typeCases,
265                                       const ReaderWriterInfo &info);
266
267private:
268  class Validator {
269    ASTPropsEmitter &Emitter;
270    std::set<HasProperties> ValidatedNodes;
271
272  public:
273    Validator(ASTPropsEmitter &emitter) : Emitter(emitter) {}
274    void validate();
275
276  private:
277    void validateNode(HasProperties node, const NodeInfo &nodeInfo);
278    void validateType(PropertyType type, WrappedRecord context);
279  };
280};
281
282} // end anonymous namespace
283
284void ASTPropsEmitter::Validator::validate() {
285  for (auto &entry : Emitter.NodeInfos) {
286    validateNode(entry.first, entry.second);
287  }
288
289  if (ErrorsPrinted > 0) {
290    PrintFatalError("property validation failed");
291  }
292}
293
294void ASTPropsEmitter::Validator::validateNode(HasProperties derivedNode,
295                                              const NodeInfo &derivedNodeInfo) {
296  if (!ValidatedNodes.insert(derivedNode).second) return;
297
298  // A map from property name to property.
299  std::map<StringRef, Property> allProperties;
300
301  Emitter.visitAllNodesWithInfo(derivedNode, derivedNodeInfo,
302                                [&](HasProperties node,
303                                    const NodeInfo &nodeInfo) {
304    for (Property property : nodeInfo.Properties) {
305      validateType(property.getType(), property);
306
307      auto result = allProperties.insert(
308                      std::make_pair(property.getName(), property));
309
310      // Diagnose non-unique properties.
311      if (!result.second) {
312        // The existing property is more likely to be associated with a
313        // derived node, so use it as the error.
314        Property existingProperty = result.first->second;
315        PrintError(existingProperty.getLoc(),
316                   "multiple properties named \"" + property.getName()
317                      + "\" in hierarchy of " + derivedNode.getName());
318        PrintNote(property.getLoc(), "existing property");
319      }
320    }
321  });
322}
323
324void ASTPropsEmitter::Validator::validateType(PropertyType type,
325                                              WrappedRecord context) {
326  if (!type.isGenericSpecialization()) {
327    if (type.getCXXTypeName() == "") {
328      PrintError(type.getLoc(),
329                 "type is not generic but has no C++ type name");
330      if (context) PrintNote(context.getLoc(), "type used here");
331    }
332  } else if (auto eltType = type.getArrayElementType()) {
333    validateType(eltType, context);
334  } else if (auto valueType = type.getOptionalElementType()) {
335    validateType(valueType, context);
336
337    if (valueType.getPackOptionalCode().empty()) {
338      PrintError(valueType.getLoc(),
339                 "type doesn't provide optional-packing code");
340      if (context) PrintNote(context.getLoc(), "type used here");
341    } else if (valueType.getUnpackOptionalCode().empty()) {
342      PrintError(valueType.getLoc(),
343                 "type doesn't provide optional-unpacking code");
344      if (context) PrintNote(context.getLoc(), "type used here");
345    }
346  } else {
347    PrintError(type.getLoc(), "unknown generic property type");
348    if (context) PrintNote(context.getLoc(), "type used here");
349  }
350}
351
352/****************************************************************************/
353/**************************** AST READER/WRITERS ****************************/
354/****************************************************************************/
355
356template <class NodeClass>
357void ASTPropsEmitter::emitNodeReaderWriterClass(const ReaderWriterInfo &info) {
358  StringRef suffix = info.ClassSuffix;
359  StringRef var = info.HelperVariable;
360
361  // Enter the class declaration.
362  Out << "template <class Property" << suffix << ">\n"
363         "class Abstract" << info.HierarchyName << suffix << " {\n"
364         "public:\n"
365         "  Property" << suffix << " &" << var << ";\n\n";
366
367  // Emit the constructor.
368  Out << "  Abstract" << info.HierarchyName << suffix
369                      << "(Property" << suffix << " &" << var << ") : "
370                      << var << "(" << var << ") {}\n\n";
371
372  // Emit a method that dispatches on a kind to the appropriate node-specific
373  // method.
374  Out << "  " << info.ResultType << " " << info.MethodPrefix << "(";
375  if (info.IsReader)
376    Out       << NodeClass::getASTIdTypeName() << " kind";
377  else
378    Out       << "const " << info.HierarchyName << " *node";
379  Out         << ") {\n"
380         "    switch (";
381  if (info.IsReader)
382    Out         << "kind";
383  else
384    Out         << "node->" << NodeClass::getASTIdAccessorName() << "()";
385  Out           << ") {\n";
386  visitASTNodeHierarchy<NodeClass>(Records, [&](NodeClass node, NodeClass _) {
387    if (node.isAbstract()) return;
388    Out << "    case " << info.HierarchyName << "::" << node.getId() << ":\n"
389           "      return " << info.MethodPrefix << node.getClassName() << "(";
390    if (!info.IsReader)
391      Out                  << "static_cast<const " << node.getClassName()
392                           << " *>(node)";
393    Out                    << ");\n";
394  });
395  Out << "    }\n"
396         "    llvm_unreachable(\"bad kind\");\n"
397         "  }\n\n";
398
399  // Emit node-specific methods for all the concrete nodes.
400  visitASTNodeHierarchy<NodeClass>(Records,
401                                   [&](NodeClass node, NodeClass base) {
402    if (node.isAbstract()) return;
403    emitNodeReaderWriterMethod(node, info);
404  });
405
406  // Finish the class.
407  Out << "};\n\n";
408}
409
410/// Emit a reader method for the given concrete AST node class.
411template <class NodeClass>
412void ASTPropsEmitter::emitNodeReaderWriterMethod(NodeClass node,
413                                           const ReaderWriterInfo &info) {
414  // Declare and start the method.
415  Out << "  " << info.ResultType << " "
416              << info.MethodPrefix << node.getClassName() << "(";
417  if (!info.IsReader)
418    Out <<       "const " << node.getClassName() << " *node";
419  Out <<         ") {\n";
420  if (info.IsReader)
421    Out << "    auto &ctx = " << info.HelperVariable << ".getASTContext();\n";
422
423  emitPropertiedReaderWriterBody(node, info);
424
425  // Finish the method declaration.
426  Out << "  }\n\n";
427}
428
429void ASTPropsEmitter::emitPropertiedReaderWriterBody(HasProperties node,
430                                               const ReaderWriterInfo &info) {
431  // Find the information for this node.
432  auto it = NodeInfos.find(node);
433  if (it == NodeInfos.end())
434    PrintFatalError(node.getLoc(),
435                    "no information about how to deserialize \""
436                      + node.getName() + "\"");
437  auto &nodeInfo = it->second;
438
439  StringRef creationCode;
440  if (info.IsReader) {
441    // We should have a creation rule.
442    if (!nodeInfo.Creator)
443      PrintFatalError(node.getLoc(),
444                      "no " CreationRuleClassName " for \""
445                        + node.getName() + "\"");
446
447    creationCode = nodeInfo.Creator.getCreationCode();
448  }
449
450  // Emit the ReadHelper code, if present.
451  if (!info.IsReader && nodeInfo.ReadHelper) {
452    Out << "    " << nodeInfo.ReadHelper.getHelperCode() << "\n";
453  }
454
455  // Emit code to read all the properties.
456  visitAllProperties(node, nodeInfo, [&](Property prop) {
457    // Verify that the creation code refers to this property.
458    if (info.IsReader && creationCode.find(prop.getName()) == StringRef::npos)
459      PrintFatalError(nodeInfo.Creator.getLoc(),
460                      "creation code for " + node.getName()
461                        + " doesn't refer to property \""
462                        + prop.getName() + "\"");
463
464    // Emit code to read or write this property.
465    if (info.IsReader)
466      emitReadOfProperty(info.HelperVariable, prop);
467    else
468      emitWriteOfProperty(info.HelperVariable, prop);
469  });
470
471  // Emit the final creation code.
472  if (info.IsReader)
473    Out << "    " << creationCode << "\n";
474}
475
476static void emitBasicReaderWriterMethodSuffix(raw_ostream &out,
477                                              PropertyType type,
478                                              bool isForRead) {
479  if (!type.isGenericSpecialization()) {
480    out << type.getAbstractTypeName();
481  } else if (auto eltType = type.getArrayElementType()) {
482    out << "Array";
483    // We only include an explicit template argument for reads so that
484    // we don't cause spurious const mismatches.
485    if (isForRead) {
486      out << "<";
487      eltType.emitCXXValueTypeName(isForRead, out);
488      out << ">";
489    }
490  } else if (auto valueType = type.getOptionalElementType()) {
491    out << "Optional";
492    // We only include an explicit template argument for reads so that
493    // we don't cause spurious const mismatches.
494    if (isForRead) {
495      out << "<";
496      valueType.emitCXXValueTypeName(isForRead, out);
497      out << ">";
498    }
499  } else {
500    PrintFatalError(type.getLoc(), "unexpected generic property type");
501  }
502}
503
504/// Emit code to read the given property in a node-reader method.
505void ASTPropsEmitter::emitReadOfProperty(StringRef readerName,
506                                         Property property) {
507  emitReadOfProperty(readerName, property.getName(), property.getType(),
508                     property.getCondition());
509}
510
511void ASTPropsEmitter::emitReadOfProperty(StringRef readerName,
512                                         StringRef name,
513                                         PropertyType type,
514                                         StringRef condition) {
515  // Declare all the necessary buffers.
516  auto bufferTypes = type.getBufferElementTypes();
517  for (size_t i = 0, e = bufferTypes.size(); i != e; ++i) {
518    Out << "    llvm::SmallVector<";
519    PropertyType(bufferTypes[i]).emitCXXValueTypeName(/*for read*/ true, Out);
520    Out << ", 8> " << name << "_buffer_" << i << ";\n";
521  }
522
523  //   T prop = R.find("prop").read##ValueType(buffers...);
524  // We intentionally ignore shouldPassByReference here: we're going to
525  // get a pr-value back from read(), and we should be able to forward
526  // that in the creation rule.
527  Out << "    ";
528  if (!condition.empty()) Out << "llvm::Optional<";
529  type.emitCXXValueTypeName(true, Out);
530  if (!condition.empty()) Out << ">";
531  Out << " " << name;
532
533  if (condition.empty()) {
534    Out << " = ";
535  } else {
536    Out << ";\n"
537           "    if (" << condition << ") {\n"
538           "      " << name << ".emplace(";
539  }
540
541  Out << readerName << ".find(\"" << name << "\")."
542      << (type.isGenericSpecialization() ? "template " : "") << "read";
543  emitBasicReaderWriterMethodSuffix(Out, type, /*for read*/ true);
544  Out << "(";
545  for (size_t i = 0, e = bufferTypes.size(); i != e; ++i) {
546    Out << (i > 0 ? ", " : "") << name << "_buffer_" << i;
547  }
548  Out << ")";
549
550  if (condition.empty()) {
551    Out << ";\n";
552  } else {
553    Out << ");\n"
554           "    }\n";
555  }
556}
557
558/// Emit code to write the given property in a node-writer method.
559void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName,
560                                          Property property) {
561  emitWriteOfProperty(writerName, property.getName(), property.getType(),
562                      property.getReadCode(), property.getCondition());
563}
564
565void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName,
566                                          StringRef name,
567                                          PropertyType type,
568                                          StringRef readCode,
569                                          StringRef condition) {
570  if (!condition.empty()) {
571    Out << "    if (" << condition << ") {\n";
572  }
573
574  // Focus down to the property:
575  //   T prop = <READ>;
576  //   W.find("prop").write##ValueType(prop);
577  Out << "    ";
578  type.emitCXXValueTypeName(false, Out);
579  Out << " " << name << " = (" << readCode << ");\n"
580         "    " << writerName << ".find(\"" << name << "\").write";
581  emitBasicReaderWriterMethodSuffix(Out, type, /*for read*/ false);
582  Out << "(" << name << ");\n";
583
584  if (!condition.empty()) {
585    Out << "    }\n";
586  }
587}
588
589/// Emit an .inc file that defines the AbstractFooReader class
590/// for the given AST class hierarchy.
591template <class NodeClass>
592static void emitASTReader(RecordKeeper &records, raw_ostream &out,
593                          StringRef description) {
594  emitSourceFileHeader(description, out);
595
596  ASTPropsEmitter(records, out).emitNodeReaderClass<NodeClass>();
597}
598
599void clang::EmitClangTypeReader(RecordKeeper &records, raw_ostream &out) {
600  emitASTReader<TypeNode>(records, out, "A CRTP reader for Clang Type nodes");
601}
602
603/// Emit an .inc file that defines the AbstractFooWriter class
604/// for the given AST class hierarchy.
605template <class NodeClass>
606static void emitASTWriter(RecordKeeper &records, raw_ostream &out,
607                          StringRef description) {
608  emitSourceFileHeader(description, out);
609
610  ASTPropsEmitter(records, out).emitNodeWriterClass<NodeClass>();
611}
612
613void clang::EmitClangTypeWriter(RecordKeeper &records, raw_ostream &out) {
614  emitASTWriter<TypeNode>(records, out, "A CRTP writer for Clang Type nodes");
615}
616
617/****************************************************************************/
618/*************************** BASIC READER/WRITERS ***************************/
619/****************************************************************************/
620
621void
622ASTPropsEmitter::emitDispatcherTemplate(const ReaderWriterInfo &info) {
623  // Declare the {Read,Write}Dispatcher template.
624  StringRef dispatcherPrefix = (info.IsReader ? "Read" : "Write");
625  Out << "template <class ValueType>\n"
626         "struct " << dispatcherPrefix << "Dispatcher;\n";
627
628  // Declare a specific specialization of the dispatcher template.
629  auto declareSpecialization =
630    [&](StringRef specializationParameters,
631        const Twine &cxxTypeName,
632        StringRef methodSuffix) {
633    StringRef var = info.HelperVariable;
634    Out << "template " << specializationParameters << "\n"
635           "struct " << dispatcherPrefix << "Dispatcher<"
636                     << cxxTypeName << "> {\n";
637    Out << "  template <class Basic" << info.ClassSuffix << ", class... Args>\n"
638           "  static " << (info.IsReader ? cxxTypeName : "void") << " "
639                       << info.MethodPrefix
640                       << "(Basic" << info.ClassSuffix << " &" << var
641                       << ", Args &&... args) {\n"
642           "    return " << var << "."
643                         << info.MethodPrefix << methodSuffix
644                         << "(std::forward<Args>(args)...);\n"
645           "  }\n"
646           "};\n";
647  };
648
649  // Declare explicit specializations for each of the concrete types.
650  for (PropertyType type : AllPropertyTypes) {
651    declareSpecialization("<>",
652                          type.getCXXTypeName(),
653                          type.getAbstractTypeName());
654    // Also declare a specialization for the const type when appropriate.
655    if (!info.IsReader && type.isConstWhenWriting()) {
656      declareSpecialization("<>",
657                            "const " + type.getCXXTypeName(),
658                            type.getAbstractTypeName());
659    }
660  }
661  // Declare partial specializations for ArrayRef and Optional.
662  declareSpecialization("<class T>",
663                        "llvm::ArrayRef<T>",
664                        "Array");
665  declareSpecialization("<class T>",
666                        "llvm::Optional<T>",
667                        "Optional");
668  Out << "\n";
669}
670
671void
672ASTPropsEmitter::emitPackUnpackOptionalTemplate(const ReaderWriterInfo &info) {
673  StringRef classPrefix = (info.IsReader ? "Unpack" : "Pack");
674  StringRef methodName = (info.IsReader ? "unpack" : "pack");
675
676  // Declare the {Pack,Unpack}OptionalValue template.
677  Out << "template <class ValueType>\n"
678         "struct " << classPrefix << "OptionalValue;\n";
679
680  auto declareSpecialization = [&](const Twine &typeName,
681                                   StringRef code) {
682    Out << "template <>\n"
683           "struct " << classPrefix << "OptionalValue<" << typeName << "> {\n"
684           "  static " << (info.IsReader ? "Optional<" : "") << typeName
685                       << (info.IsReader ? "> " : " ") << methodName << "("
686                       << (info.IsReader ? "" : "Optional<") << typeName
687                       << (info.IsReader ? "" : ">") << " value) {\n"
688           "    return " << code << ";\n"
689           "  }\n"
690           "};\n";
691  };
692
693  for (PropertyType type : AllPropertyTypes) {
694    StringRef code = (info.IsReader ? type.getUnpackOptionalCode()
695                                    : type.getPackOptionalCode());
696    if (code.empty()) continue;
697
698    StringRef typeName = type.getCXXTypeName();
699    declareSpecialization(typeName, code);
700    if (type.isConstWhenWriting() && !info.IsReader)
701      declareSpecialization("const " + typeName, code);
702  }
703  Out << "\n";
704}
705
706void
707ASTPropsEmitter::emitBasicReaderWriterTemplate(const ReaderWriterInfo &info) {
708  // Emit the Basic{Reader,Writer}Base template.
709  Out << "template <class Impl>\n"
710         "class Basic" << info.ClassSuffix << "Base {\n";
711  if (info.IsReader)
712    Out << "  ASTContext &C;\n";
713  Out << "protected:\n"
714         "  Basic" << info.ClassSuffix << "Base"
715                   << (info.IsReader ? "(ASTContext &ctx) : C(ctx)" : "()")
716                   << " {}\n"
717         "public:\n";
718  if (info.IsReader)
719    Out << "  ASTContext &getASTContext() { return C; }\n";
720  Out << "  Impl &asImpl() { return static_cast<Impl&>(*this); }\n";
721
722  auto enterReaderWriterMethod = [&](StringRef cxxTypeName,
723                                     StringRef abstractTypeName,
724                                     bool shouldPassByReference,
725                                     bool constWhenWriting,
726                                     StringRef paramName) {
727    Out << "  " << (info.IsReader ? cxxTypeName : "void")
728                << " " << info.MethodPrefix << abstractTypeName << "(";
729    if (!info.IsReader)
730      Out       << (shouldPassByReference || constWhenWriting ? "const " : "")
731                << cxxTypeName
732                << (shouldPassByReference ? " &" : "") << " " << paramName;
733    Out         << ") {\n";
734  };
735
736  // Emit {read,write}ValueType methods for all the enum and subclass types
737  // that default to using the integer/base-class implementations.
738  for (PropertyType type : AllPropertyTypes) {
739    auto enterMethod = [&](StringRef paramName) {
740      enterReaderWriterMethod(type.getCXXTypeName(),
741                              type.getAbstractTypeName(),
742                              type.shouldPassByReference(),
743                              type.isConstWhenWriting(),
744                              paramName);
745    };
746    auto exitMethod = [&] {
747      Out << "  }\n";
748    };
749
750    // Handled cased types.
751    auto casedIter = CasedTypeInfos.find(type);
752    if (casedIter != CasedTypeInfos.end()) {
753      enterMethod("node");
754      emitCasedReaderWriterMethodBody(type, casedIter->second, info);
755      exitMethod();
756
757    } else if (type.isEnum()) {
758      enterMethod("value");
759      if (info.IsReader)
760        Out << "    return asImpl().template readEnum<"
761            <<         type.getCXXTypeName() << ">();\n";
762      else
763        Out << "    asImpl().writeEnum(value);\n";
764      exitMethod();
765
766    } else if (PropertyType superclass = type.getSuperclassType()) {
767      enterMethod("value");
768      if (info.IsReader)
769        Out << "    return cast_or_null<" << type.getSubclassClassName()
770                                          << ">(asImpl().read"
771                                          << superclass.getAbstractTypeName()
772                                          << "());\n";
773      else
774        Out << "    asImpl().write" << superclass.getAbstractTypeName()
775                                    << "(value);\n";
776      exitMethod();
777
778    } else {
779      // The other types can't be handled as trivially.
780    }
781  }
782  Out << "};\n\n";
783}
784
785void ASTPropsEmitter::emitCasedReaderWriterMethodBody(PropertyType type,
786                                             const CasedTypeInfo &typeCases,
787                                             const ReaderWriterInfo &info) {
788  if (typeCases.Cases.empty()) {
789    assert(typeCases.KindRule);
790    PrintFatalError(typeCases.KindRule.getLoc(),
791                    "no cases found for \"" + type.getCXXTypeName() + "\"");
792  }
793  if (!typeCases.KindRule) {
794    assert(!typeCases.Cases.empty());
795    PrintFatalError(typeCases.Cases.front().getLoc(),
796                    "no kind rule for \"" + type.getCXXTypeName() + "\"");
797  }
798
799  auto var = info.HelperVariable;
800  std::string subvar = ("sub" + var).str();
801
802  // Bind `ctx` for readers.
803  if (info.IsReader)
804    Out << "    auto &ctx = asImpl().getASTContext();\n";
805
806  // Start an object.
807  Out << "    auto &&" << subvar << " = asImpl()."
808                       << info.MethodPrefix << "Object();\n";
809
810  // Read/write the kind property;
811  TypeKindRule kindRule = typeCases.KindRule;
812  StringRef kindProperty = kindRule.getKindPropertyName();
813  PropertyType kindType = kindRule.getKindType();
814  if (info.IsReader) {
815    emitReadOfProperty(subvar, kindProperty, kindType);
816  } else {
817    // Write the property.  Note that this will implicitly read the
818    // kind into a local variable with the right name.
819    emitWriteOfProperty(subvar, kindProperty, kindType,
820                        kindRule.getReadCode());
821  }
822
823  // Prepare a ReaderWriterInfo with a helper variable that will use
824  // the sub-reader/writer.
825  ReaderWriterInfo subInfo = info;
826  subInfo.HelperVariable = subvar;
827
828  // Switch on the kind.
829  Out << "    switch (" << kindProperty << ") {\n";
830  for (TypeCase typeCase : typeCases.Cases) {
831    Out << "    case " << type.getCXXTypeName() << "::"
832                       << typeCase.getCaseName() << ": {\n";
833    emitPropertiedReaderWriterBody(typeCase, subInfo);
834    if (!info.IsReader)
835      Out << "    return;\n";
836    Out << "    }\n\n";
837  }
838  Out << "    }\n"
839         "    llvm_unreachable(\"bad " << kindType.getCXXTypeName()
840                                       << "\");\n";
841}
842
843void ASTPropsEmitter::emitBasicReaderWriterFile(const ReaderWriterInfo &info) {
844  emitDispatcherTemplate(info);
845  emitPackUnpackOptionalTemplate(info);
846  emitBasicReaderWriterTemplate(info);
847}
848
849/// Emit an .inc file that defines some helper classes for reading
850/// basic values.
851void clang::EmitClangBasicReader(RecordKeeper &records, raw_ostream &out) {
852  emitSourceFileHeader("Helper classes for BasicReaders", out);
853
854  // Use any property, we won't be using those properties.
855  auto info = ReaderWriterInfo::forReader<TypeNode>();
856  ASTPropsEmitter(records, out).emitBasicReaderWriterFile(info);
857}
858
859/// Emit an .inc file that defines some helper classes for writing
860/// basic values.
861void clang::EmitClangBasicWriter(RecordKeeper &records, raw_ostream &out) {
862  emitSourceFileHeader("Helper classes for BasicWriters", out);
863
864  // Use any property, we won't be using those properties.
865  auto info = ReaderWriterInfo::forWriter<TypeNode>();
866  ASTPropsEmitter(records, out).emitBasicReaderWriterFile(info);
867}
868