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-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/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> 24 using namespace llvm; 25 using namespace clang; 26 using namespace clang::tblgen; 27 28 static StringRef getReaderResultType(TypeNode _) { return "QualType"; } 29 30 namespace { 31 32 struct 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/Writer 40 StringRef ClassSuffix; 41 42 /// The base name of methods: read/write 43 StringRef MethodPrefix; 44 45 /// The name of the property helper member: R/W 46 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 76 struct NodeInfo { 77 std::vector<Property> Properties; 78 CreationRule Creator = nullptr; 79 OverrideRule Override = nullptr; 80 ReadHelperRule ReadHelper = nullptr; 81 }; 82 83 struct CasedTypeInfo { 84 TypeKindRule KindRule; 85 std::vector<TypeCase> Cases; 86 }; 87 88 class 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 95 public: 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 when 151 // 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 ways 190 // - put arrays at the end to enable abbreviations 191 // - put conditional properties after properties used in the condition 192 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 261 private: 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 namespace 277 278 void 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 288 void 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 a 307 // 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 318 void 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 350 template <class NodeClass> 351 void 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 << suffix 363 << "(Property" << suffix << " &" << var << ") : " 364 << var << "(" << var << ") {}\n\n"; 365 366 // Emit a method that dispatches on a kind to the appropriate node-specific 367 // method. 368 Out << " " << info.ResultType << " " << info.MethodPrefix << "("; 369 if (info.IsReader) 370 Out << NodeClass::getASTIdTypeName() << " kind"; 371 else 372 Out << "const " << info.HierarchyName << " *node"; 373 Out << ") {\n" 374 " switch ("; 375 if (info.IsReader) 376 Out << "kind"; 377 else 378 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. 405 template <class NodeClass> 406 void 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 423 void 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 else 462 emitWriteOfProperty(info.HelperVariable, prop); 463 }); 464 465 // Emit the final creation code. 466 if (info.IsReader) 467 Out << " " << creationCode << "\n"; 468 } 469 470 static 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 that 478 // 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 that 487 // 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. 499 void ASTPropsEmitter::emitReadOfProperty(StringRef readerName, 500 Property property) { 501 emitReadOfProperty(readerName, property.getName(), property.getType(), 502 property.getCondition()); 503 } 504 505 void 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 to 519 // get a pr-value back from read(), and we should be able to forward 520 // 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. 554 void ASTPropsEmitter::emitWriteOfProperty(StringRef writerName, 555 Property property) { 556 emitWriteOfProperty(writerName, property.getName(), property.getType(), 557 property.getReadCode(), property.getCondition()); 558 } 559 560 void 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 class 585 /// for the given AST class hierarchy. 586 template <class NodeClass> 587 static 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 594 void 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 class 599 /// for the given AST class hierarchy. 600 template <class NodeClass> 601 static 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 608 void 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 616 void 617 ASTPropsEmitter::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.MethodPrefix 635 << "(Basic" << info.ClassSuffix << " &" << var 636 << ", Args &&... args) {\n" 637 " return " << var << "." 638 << info.MethodPrefix << methodSuffix 639 << "(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 664 void 665 ASTPropsEmitter::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<" << typeName 677 << "> {\n" 678 " static " 679 << (info.IsReader ? "std::optional<" : "") << typeName 680 << (info.IsReader ? "> " : " ") << methodName << "(" 681 << (info.IsReader ? "" : "std::optional<") << typeName 682 << (info.IsReader ? "" : ">") 683 << " value) {\n" 684 " return " 685 << code 686 << ";\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 704 void 705 ASTPropsEmitter::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 << cxxTypeName 728 << (shouldPassByReference ? " &" : "") << " " << paramName; 729 Out << ") {\n"; 730 }; 731 732 // Emit {read,write}ValueType methods for all the enum and subclass types 733 // 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 else 759 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 else 770 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 781 void 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 the 814 // 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 use 820 // 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 839 void 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 reading 846 /// basic values. 847 void 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 writing 857 /// basic values. 858 void 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