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