Coverage Report

Created: 2020-09-22 08:39

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