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.find(prop.getName()) == StringRef::npos) 459 PrintFatalError(nodeInfo.Creator.getLoc(), 460 "creation code for " + node.getName() 461 + " doesn't refer to property \"" 462 + prop.getName() + "\""); 463 464 // Emit code to read or write this property. 465 if (info.IsReader) 466 emitReadOfProperty(info.HelperVariable, prop); 467 else 468 emitWriteOfProperty(info.HelperVariable, prop); 469 }); 470 471 // Emit the final creation code. 472 if (info.IsReader) 473 Out << " " << creationCode << "\n"; 474 } 475 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 if (info.IsReader) 712 Out << " ASTContext &C;\n"; 713 Out << "protected:\n" 714 " Basic" << info.ClassSuffix << "Base" 715 << (info.IsReader ? "(ASTContext &ctx) : C(ctx)" : "()") 716 << " {}\n" 717 "public:\n"; 718 if (info.IsReader) 719 Out << " ASTContext &getASTContext() { return C; }\n"; 720 Out << " Impl &asImpl() { return static_cast<Impl&>(*this); }\n"; 721 722 auto enterReaderWriterMethod = [&](StringRef cxxTypeName, 723 StringRef abstractTypeName, 724 bool shouldPassByReference, 725 bool constWhenWriting, 726 StringRef paramName) { 727 Out << " " << (info.IsReader ? cxxTypeName : "void") 728 << " " << info.MethodPrefix << abstractTypeName << "("; 729 if (!info.IsReader) 730 Out << (shouldPassByReference || constWhenWriting ? "const " : "") 731 << cxxTypeName 732 << (shouldPassByReference ? " &" : "") << " " << paramName; 733 Out << ") {\n"; 734 }; 735 736 // Emit {read,write}ValueType methods for all the enum and subclass types 737 // that default to using the integer/base-class implementations. 738 for (PropertyType type : AllPropertyTypes) { 739 auto enterMethod = [&](StringRef paramName) { 740 enterReaderWriterMethod(type.getCXXTypeName(), 741 type.getAbstractTypeName(), 742 type.shouldPassByReference(), 743 type.isConstWhenWriting(), 744 paramName); 745 }; 746 auto exitMethod = [&] { 747 Out << " }\n"; 748 }; 749 750 // Handled cased types. 751 auto casedIter = CasedTypeInfos.find(type); 752 if (casedIter != CasedTypeInfos.end()) { 753 enterMethod("node"); 754 emitCasedReaderWriterMethodBody(type, casedIter->second, info); 755 exitMethod(); 756 757 } else if (type.isEnum()) { 758 enterMethod("value"); 759 if (info.IsReader) 760 Out << " return asImpl().template readEnum<" 761 << type.getCXXTypeName() << ">();\n"; 762 else 763 Out << " asImpl().writeEnum(value);\n"; 764 exitMethod(); 765 766 } else if (PropertyType superclass = type.getSuperclassType()) { 767 enterMethod("value"); 768 if (info.IsReader) 769 Out << " return cast_or_null<" << type.getSubclassClassName() 770 << ">(asImpl().read" 771 << superclass.getAbstractTypeName() 772 << "());\n"; 773 else 774 Out << " asImpl().write" << superclass.getAbstractTypeName() 775 << "(value);\n"; 776 exitMethod(); 777 778 } else { 779 // The other types can't be handled as trivially. 780 } 781 } 782 Out << "};\n\n"; 783 } 784 785 void ASTPropsEmitter::emitCasedReaderWriterMethodBody(PropertyType type, 786 const CasedTypeInfo &typeCases, 787 const ReaderWriterInfo &info) { 788 if (typeCases.Cases.empty()) { 789 assert(typeCases.KindRule); 790 PrintFatalError(typeCases.KindRule.getLoc(), 791 "no cases found for \"" + type.getCXXTypeName() + "\""); 792 } 793 if (!typeCases.KindRule) { 794 assert(!typeCases.Cases.empty()); 795 PrintFatalError(typeCases.Cases.front().getLoc(), 796 "no kind rule for \"" + type.getCXXTypeName() + "\""); 797 } 798 799 auto var = info.HelperVariable; 800 std::string subvar = ("sub" + var).str(); 801 802 // Bind `ctx` for readers. 803 if (info.IsReader) 804 Out << " auto &ctx = asImpl().getASTContext();\n"; 805 806 // Start an object. 807 Out << " auto &&" << subvar << " = asImpl()." 808 << info.MethodPrefix << "Object();\n"; 809 810 // Read/write the kind property; 811 TypeKindRule kindRule = typeCases.KindRule; 812 StringRef kindProperty = kindRule.getKindPropertyName(); 813 PropertyType kindType = kindRule.getKindType(); 814 if (info.IsReader) { 815 emitReadOfProperty(subvar, kindProperty, kindType); 816 } else { 817 // Write the property. Note that this will implicitly read the 818 // kind into a local variable with the right name. 819 emitWriteOfProperty(subvar, kindProperty, kindType, 820 kindRule.getReadCode()); 821 } 822 823 // Prepare a ReaderWriterInfo with a helper variable that will use 824 // the sub-reader/writer. 825 ReaderWriterInfo subInfo = info; 826 subInfo.HelperVariable = subvar; 827 828 // Switch on the kind. 829 Out << " switch (" << kindProperty << ") {\n"; 830 for (TypeCase typeCase : typeCases.Cases) { 831 Out << " case " << type.getCXXTypeName() << "::" 832 << typeCase.getCaseName() << ": {\n"; 833 emitPropertiedReaderWriterBody(typeCase, subInfo); 834 if (!info.IsReader) 835 Out << " return;\n"; 836 Out << " }\n\n"; 837 } 838 Out << " }\n" 839 " llvm_unreachable(\"bad " << kindType.getCXXTypeName() 840 << "\");\n"; 841 } 842 843 void ASTPropsEmitter::emitBasicReaderWriterFile(const ReaderWriterInfo &info) { 844 emitDispatcherTemplate(info); 845 emitPackUnpackOptionalTemplate(info); 846 emitBasicReaderWriterTemplate(info); 847 } 848 849 /// Emit an .inc file that defines some helper classes for reading 850 /// basic values. 851 void clang::EmitClangBasicReader(RecordKeeper &records, raw_ostream &out) { 852 emitSourceFileHeader("Helper classes for BasicReaders", out); 853 854 // Use any property, we won't be using those properties. 855 auto info = ReaderWriterInfo::forReader<TypeNode>(); 856 ASTPropsEmitter(records, out).emitBasicReaderWriterFile(info); 857 } 858 859 /// Emit an .inc file that defines some helper classes for writing 860 /// basic values. 861 void clang::EmitClangBasicWriter(RecordKeeper &records, raw_ostream &out) { 862 emitSourceFileHeader("Helper classes for BasicWriters", out); 863 864 // Use any property, we won't be using those properties. 865 auto info = ReaderWriterInfo::forWriter<TypeNode>(); 866 ASTPropsEmitter(records, out).emitBasicReaderWriterFile(info); 867 } 868