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