--- /dev/null
+//==--- PropertiesBase.td - Baseline definitions for AST properties -------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+class ASTNode;
+
+/// The type of the property.
+class PropertyType<string typeName = ""> {
+ /// The C++ type name for the type.
+ string CXXName = !if(!ne(typeName, ""), typeName, NAME);
+
+ /// Whether the C++ type should generally be passed around by reference.
+ bit PassByReference = 0;
+
+ /// Whether `const` should be prepended to the type when writing.
+ bit ConstWhenWriting = 0;
+
+ /// Given a value of type Optional<CXXName> bound as 'value', yield a
+ /// CXXName that can be serialized into a DataStreamTypeWriter.
+ string PackOptional = "";
+
+ /// Given a value of type CXXName bound as 'value' that was deserialized
+ /// by a DataStreamTypeReader, yield an Optional<CXXName>.
+ string UnpackOptional = "";
+
+ /// A list of types for which buffeers must be passed to the read
+ /// operations.
+ list<PropertyType> BufferElementTypes = [];
+}
+
+/// Property types that correspond to specific C++ enums.
+class EnumPropertyType<string typeName = ""> : PropertyType<typeName> {}
+
+/// Property types that correspond to a specific C++ class.
+/// Supports optional values by using the null representation.
+class RefPropertyType<string className> : PropertyType<className # "*"> {
+ let PackOptional =
+ "value ? *value : nullptr";
+ let UnpackOptional =
+ "value ? llvm::Optional<" # CXXName # ">(value) : llvm::None";
+}
+
+/// Property types that correspond to a specific subclass of another type.
+class SubclassPropertyType<string className, PropertyType base>
+ : RefPropertyType<className> {
+ PropertyType Base = base;
+ string SubclassName = className;
+ let ConstWhenWriting = base.ConstWhenWriting;
+}
+
+/// Property types that support optional values by using their
+/// default value.
+class DefaultValuePropertyType<string typeName = ""> : PropertyType<typeName> {
+ let PackOptional =
+ "value ? *value : " # CXXName # "()";
+ let UnpackOptional =
+ "value.isNull() ? llvm::None : llvm::Optional<" # CXXName # ">(value)";
+}
+
+/// Property types that correspond to integer types and support optional
+/// values by shifting the value over by 1.
+class CountPropertyType<string typeName = ""> : PropertyType<typeName> {
+ let PackOptional =
+ "value ? *value + 1 : 0";
+ let UnpackOptional =
+ "value ? llvm::Optional<" # CXXName # ">(value - 1) : llvm::None";
+}
+
+def APInt : PropertyType<"llvm::APInt"> { let PassByReference = 1; }
+def APSInt : PropertyType<"llvm::APSInt"> { let PassByReference = 1; }
+def ArraySizeModifier : EnumPropertyType<"ArrayType::ArraySizeModifier">;
+def AttrKind : EnumPropertyType<"attr::Kind">;
+def AutoTypeKeyword : EnumPropertyType;
+def Bool : PropertyType<"bool">;
+def BuiltinTypeKind : EnumPropertyType<"BuiltinType::Kind">;
+def CallingConv : EnumPropertyType;
+def DeclarationName : PropertyType;
+def DeclarationNameKind : EnumPropertyType<"DeclarationName::NameKind">;
+def DeclRef : RefPropertyType<"Decl"> { let ConstWhenWriting = 1; }
+ def CXXRecordDeclRef :
+ SubclassPropertyType<"CXXRecordDecl", DeclRef>;
+ def FunctionDeclRef :
+ SubclassPropertyType<"FunctionDecl", DeclRef>;
+ def NamedDeclRef :
+ SubclassPropertyType<"NamedDecl", DeclRef>;
+ def NamespaceDeclRef :
+ SubclassPropertyType<"NamespaceDecl", DeclRef>;
+ def NamespaceAliasDeclRef :
+ SubclassPropertyType<"NamespaceAliasDecl", DeclRef>;
+ def ObjCProtocolDeclRef :
+ SubclassPropertyType<"ObjCProtocolDecl", DeclRef>;
+ def ObjCTypeParamDeclRef :
+ SubclassPropertyType<"ObjCTypeParamDecl", DeclRef>;
+ def TagDeclRef :
+ SubclassPropertyType<"TagDecl", DeclRef>;
+ def TemplateDeclRef :
+ SubclassPropertyType<"TemplateDecl", DeclRef>;
+ def TemplateTypeParmDeclRef :
+ SubclassPropertyType<"TemplateTypeParmDecl", DeclRef>;
+ def TemplateTemplateParmDeclRef :
+ SubclassPropertyType<"TemplateTemplateParmDecl", DeclRef>;
+ def ValueDeclRef :
+ SubclassPropertyType<"ValueDecl", DeclRef>;
+def ElaboratedTypeKeyword : EnumPropertyType;
+def ExtParameterInfo : PropertyType<"FunctionProtoType::ExtParameterInfo">;
+def Identifier : PropertyType<"IdentifierInfo*">;
+def NestedNameSpecifier : PropertyType<"NestedNameSpecifier *">;
+def NestedNameSpecifierKind :
+ EnumPropertyType<"NestedNameSpecifier::SpecifierKind">;
+def OverloadedOperatorKind : EnumPropertyType;
+def Qualifiers : PropertyType;
+def QualType : DefaultValuePropertyType;
+def RefQualifierKind : EnumPropertyType;
+def Selector : PropertyType;
+def SourceLocation : PropertyType;
+def StmtRef : RefPropertyType<"Stmt"> { let ConstWhenWriting = 1; }
+ def ExprRef : SubclassPropertyType<"Expr", StmtRef>;
+def TemplateArgument : PropertyType;
+def TemplateArgumentKind : EnumPropertyType<"TemplateArgument::ArgKind">;
+def TemplateName : DefaultValuePropertyType;
+def TemplateNameKind : EnumPropertyType<"TemplateName::NameKind">;
+def UInt32 : CountPropertyType<"uint32_t">;
+def UInt64 : CountPropertyType<"uint64_t">;
+def UnaryTypeTransformKind : EnumPropertyType<"UnaryTransformType::UTTKind">;
+def VectorKind : EnumPropertyType<"VectorType::VectorKind">;
+
+def ExceptionSpecInfo : PropertyType<"FunctionProtoType::ExceptionSpecInfo"> {
+ let BufferElementTypes = [ QualType ];
+}
+
+/// Arrays. The corresponding C++ type is ArrayRef of the corresponding
+/// C++ type of the element.
+class Array<PropertyType element> : PropertyType {
+ PropertyType Element = element;
+ let BufferElementTypes = [ element ];
+}
+
+/// llvm::Optional<T>. The corresponding C++ type is generally just the
+/// corresponding C++ type of the element.
+///
+/// Optional<Unsigned> may restrict the range of the operand for some
+/// serialization clients.
+class Optional<PropertyType element> : PropertyType {
+ PropertyType Element = element;
+ let PassByReference = element.PassByReference;
+}
+
+/// A property of an AST node.
+class Property<string name, PropertyType type> {
+ ASTNode Class;
+ string Name = name;
+ PropertyType Type = type;
+
+ /// A function for reading the property, expressed in terms of a variable
+ /// "node".
+ code Read;
+}
+
+/// A rule for creating objects of this type.
+class Creator<code create> {
+ ASTNode Class;
+
+ /// A function for creating values of this kind, expressed in terms of a
+ /// variable `ctx` of type `ASTContext &`. Must also refer to all of the
+ /// properties by name.
+ code Create = create;
+}
+
+/// A rule which overrides some of the normal rules.
+class Override {
+ ASTNode Class;
+
+ /// Properties from base classes that should be ignored.
+ list<string> IgnoredProperties = [];
+}
#define NeverCanonicalUnlessDependentClassName "NeverCanonicalUnlessDependent"
#define LeafTypeClassName "LeafType"
-// Property node hierarchy.
+// Properties of AST nodes.
#define PropertyClassName "Property"
#define ClassFieldName "Class"
+#define NameFieldName "Name"
+#define TypeFieldName "Type"
+#define ReadFieldName "Read"
+
+// Types of properties.
+#define PropertyTypeClassName "PropertyType"
+#define CXXTypeNameFieldName "CXXName"
+#define PassByReferenceFieldName "PassByReference"
+#define ConstWhenWritingFieldName "ConstWhenWriting"
+#define PackOptionalCodeFieldName "PackOptional"
+#define UnpackOptionalCodeFieldName "UnpackOptional"
+#define BufferElementTypesFieldName "BufferElementTypes"
+#define ArrayTypeClassName "Array"
+#define ArrayElementTypeFieldName "Element"
+#define OptionalTypeClassName "Optional"
+#define OptionalElementTypeFieldName "Element"
+#define SubclassPropertyTypeClassName "SubclassPropertyType"
+#define SubclassBaseTypeFieldName "Base"
+#define SubclassClassNameFieldName "SubclassName"
+#define EnumPropertyTypeClassName "EnumPropertyType"
+
+// Creation rules.
+#define CreationRuleClassName "Creator"
+#define CreateFieldName "Create"
+
+// Override rules.
+#define OverrideRuleClassName "Override"
+#define IgnoredPropertiesFieldName "IgnoredProperties"
namespace clang {
namespace tblgen {
}
};
+/// The type of a property.
+class PropertyType : public WrappedRecord {
+public:
+ PropertyType(llvm::Record *record = nullptr) : WrappedRecord(record) {}
+
+ /// Is this a generic specialization (i.e. `Array<T>` or `Optional<T>`)?
+ bool isGenericSpecialization() const {
+ return get()->isAnonymous();
+ }
+
+ /// The abstract type name of the property. Doesn't work for generic
+ /// specializations.
+ llvm::StringRef getAbstractTypeName() const {
+ return get()->getName();
+ }
+
+ /// The C++ type name of the property. Doesn't work for generic
+ /// specializations.
+ llvm::StringRef getCXXTypeName() const {
+ return get()->getValueAsString(CXXTypeNameFieldName);
+ }
+ void emitCXXValueTypeName(bool forRead, llvm::raw_ostream &out) const;
+
+ /// Whether the C++ type should be passed around by reference.
+ bool shouldPassByReference() const {
+ return get()->getValueAsBit(PassByReferenceFieldName);
+ }
+
+ /// Whether the C++ type should have 'const' prepended when working with
+ /// a value of the type being written.
+ bool isConstWhenWriting() const {
+ return get()->getValueAsBit(ConstWhenWritingFieldName);
+ }
+
+ /// If this is `Array<T>`, return `T`; otherwise return null.
+ PropertyType getArrayElementType() const {
+ if (isSubClassOf(ArrayTypeClassName))
+ return get()->getValueAsDef(ArrayElementTypeFieldName);
+ return nullptr;
+ }
+
+ /// If this is `Optional<T>`, return `T`; otherwise return null.
+ PropertyType getOptionalElementType() const {
+ if (isSubClassOf(OptionalTypeClassName))
+ return get()->getValueAsDef(OptionalElementTypeFieldName);
+ return nullptr;
+ }
+
+ /// If this is a subclass type, return its superclass type.
+ PropertyType getSuperclassType() const {
+ if (isSubClassOf(SubclassPropertyTypeClassName))
+ return get()->getValueAsDef(SubclassBaseTypeFieldName);
+ return nullptr;
+ }
+
+ // Given that this is a subclass type, return the C++ name of its
+ // subclass type. This is just the bare class name, suitable for
+ // use in `cast<>`.
+ llvm::StringRef getSubclassClassName() const {
+ return get()->getValueAsString(SubclassClassNameFieldName);
+ }
+
+ /// Does this represent an enum type?
+ bool isEnum() const {
+ return isSubClassOf(EnumPropertyTypeClassName);
+ }
+
+ llvm::StringRef getPackOptionalCode() const {
+ return get()->getValueAsString(PackOptionalCodeFieldName);
+ }
+
+ llvm::StringRef getUnpackOptionalCode() const {
+ return get()->getValueAsString(UnpackOptionalCodeFieldName);
+ }
+
+ std::vector<llvm::Record*> getBufferElementTypes() const {
+ return get()->getValueAsListOfDefs(BufferElementTypesFieldName);
+ }
+};
+
+/// A property of an AST node.
+class Property : public WrappedRecord {
+public:
+ Property(llvm::Record *record = nullptr) : WrappedRecord(record) {}
+
+ /// Return the name of this property.
+ llvm::StringRef getName() const {
+ return get()->getValueAsString(NameFieldName);
+ }
+
+ /// Return the type of this property.
+ PropertyType getType() const {
+ return get()->getValueAsDef(TypeFieldName);
+ }
+
+ /// Return the class of which this is a property.
+ ASTNode getClass() const {
+ return get()->getValueAsDef(ClassFieldName);
+ }
+
+ /// Return the code for reading this property.
+ llvm::StringRef getReadCode() const {
+ return get()->getValueAsString(ReadFieldName);
+ }
+};
+
+/// A rule for how to create an AST node from its properties.
+class CreationRule : public WrappedRecord {
+public:
+ CreationRule(llvm::Record *record = nullptr) : WrappedRecord(record) {}
+
+ /// Return the class for which this is a creation rule.
+ /// Should never be abstract.
+ ASTNode getClass() const {
+ return get()->getValueAsDef(ClassFieldName);
+ }
+
+ llvm::StringRef getCreationCode() const {
+ return get()->getValueAsString(CreateFieldName);
+ }
+};
+
+/// A rule which overrides the standard rules for serializing an AST node.
+class OverrideRule : public WrappedRecord {
+public:
+ OverrideRule(llvm::Record *record = nullptr) : WrappedRecord(record) {}
+
+ /// Return the class for which this is an override rule.
+ /// Should never be abstract.
+ ASTNode getClass() const {
+ return get()->getValueAsDef(ClassFieldName);
+ }
+
+ /// Return a set of properties that are unnecessary when serializing
+ /// this AST node. Generally this is used for inherited properties
+ /// that are derived for this subclass.
+ std::vector<llvm::StringRef> getIgnoredProperties() const {
+ return get()->getValueAsListOfStrings(IgnoredPropertiesFieldName);
+ }
+};
+
/// A visitor for an AST node hierarchy. Note that `base` can be null for
/// the root class.
template <class NodeClass>
--- /dev/null
+//=== ClangASTPropsEmitter.cpp - Generate Clang AST properties --*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This tablegen backend emits code for working with Clang AST properties.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ASTTableGen.h"
+#include "TableGenBackends.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/TableGen/Error.h"
+#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/TableGenBackend.h"
+#include <cctype>
+#include <map>
+#include <set>
+#include <string>
+using namespace llvm;
+using namespace clang;
+using namespace clang::tblgen;
+
+static StringRef getReaderResultType(TypeNode _) { return "QualType"; }
+
+namespace {
+
+struct ReaderWriterInfo {
+ bool IsReader;
+
+ /// The name of the node hierarchy. Not actually sensitive to IsReader,
+ /// but useful to cache here anyway.
+ StringRef HierarchyName;
+
+ /// The suffix on classes: Reader/Writer
+ StringRef ClassSuffix;
+
+ /// The base name of methods: read/write
+ StringRef MethodPrefix;
+
+ /// The name of the property helper member: R/W
+ StringRef HelperVariable;
+
+ /// The result type of methods on the class.
+ StringRef ResultType;
+
+ template <class NodeClass>
+ static ReaderWriterInfo forReader() {
+ return ReaderWriterInfo{
+ true,
+ NodeClass::getASTHierarchyName(),
+ "Reader",
+ "read",
+ "R",
+ getReaderResultType(NodeClass())
+ };
+ }
+
+ template <class NodeClass>
+ static ReaderWriterInfo forWriter() {
+ return ReaderWriterInfo{
+ false,
+ NodeClass::getASTHierarchyName(),
+ "Writer",
+ "write",
+ "W",
+ "void"
+ };
+ }
+};
+
+struct NodeInfo {
+ std::vector<Property> Properties;
+ CreationRule Creator = nullptr;
+ OverrideRule Override = nullptr;
+};
+
+class ASTPropsEmitter {
+ raw_ostream &Out;
+ RecordKeeper &Records;
+ std::map<ASTNode, NodeInfo> NodeInfos;
+
+public:
+ ASTPropsEmitter(RecordKeeper &records, raw_ostream &out)
+ : Out(out), Records(records) {
+
+ // Find all the properties.
+ for (Property property :
+ records.getAllDerivedDefinitions(PropertyClassName)) {
+ ASTNode node = property.getClass();
+ NodeInfos[node].Properties.push_back(property);
+ }
+
+ // Find all the creation rules.
+ for (CreationRule creationRule :
+ records.getAllDerivedDefinitions(CreationRuleClassName)) {
+ ASTNode node = creationRule.getClass();
+
+ auto &info = NodeInfos[node];
+ if (info.Creator) {
+ PrintFatalError(creationRule.getLoc(),
+ "multiple creator rules for \"" + node.getName()
+ + "\"");
+ }
+ info.Creator = creationRule;
+ }
+
+ // Find all the override rules.
+ for (OverrideRule overrideRule :
+ records.getAllDerivedDefinitions(OverrideRuleClassName)) {
+ ASTNode node = overrideRule.getClass();
+
+ auto &info = NodeInfos[node];
+ if (info.Override) {
+ PrintFatalError(overrideRule.getLoc(),
+ "multiple override rules for \"" + node.getName()
+ + "\"");
+ }
+ info.Override = overrideRule;
+ }
+
+ Validator(*this).validate();
+ }
+
+ void visitAllProperties(ASTNode derived, const NodeInfo &derivedInfo,
+ function_ref<void (Property)> visit) {
+ std::set<StringRef> ignoredProperties;
+
+ auto overrideRule = derivedInfo.Override;
+ if (overrideRule) {
+ auto list = overrideRule.getIgnoredProperties();
+ ignoredProperties.insert(list.begin(), list.end());
+ }
+
+ for (ASTNode node = derived; node; node = node.getBase()) {
+ auto it = NodeInfos.find(node);
+
+ // Ignore intermediate nodes that don't add interesting properties.
+ if (it == NodeInfos.end()) continue;
+ auto &info = it->second;
+
+ for (Property prop : info.Properties) {
+ if (ignoredProperties.count(prop.getName()))
+ continue;
+
+ visit(prop);
+ }
+ }
+ }
+
+ template <class NodeClass>
+ void emitReaderClass() {
+ auto info = ReaderWriterInfo::forReader<NodeClass>();
+ emitReaderWriterClass<NodeClass>(info);
+ }
+
+ template <class NodeClass>
+ void emitWriterClass() {
+ auto info = ReaderWriterInfo::forWriter<NodeClass>();
+ emitReaderWriterClass<NodeClass>(info);
+ }
+
+ template <class NodeClass>
+ void emitReaderWriterClass(const ReaderWriterInfo &info);
+
+ template <class NodeClass>
+ void emitNodeReaderWriterMethod(NodeClass node,
+ const ReaderWriterInfo &info);
+
+ void emitReadOfProperty(Property property);
+ void emitWriteOfProperty(Property property);
+
+private:
+ class Validator {
+ const ASTPropsEmitter &Emitter;
+ std::set<ASTNode> ValidatedNodes;
+
+ public:
+ Validator(const ASTPropsEmitter &emitter) : Emitter(emitter) {}
+ void validate();
+
+ private:
+ void validateNode(ASTNode node, const NodeInfo &nodeInfo);
+ void validateType(PropertyType type, WrappedRecord context);
+ };
+};
+
+} // end anonymous namespace
+
+void ASTPropsEmitter::Validator::validate() {
+ for (auto &entry : Emitter.NodeInfos) {
+ validateNode(entry.first, entry.second);
+ }
+
+ if (ErrorsPrinted > 0) {
+ PrintFatalError("property validation failed");
+ }
+}
+
+void ASTPropsEmitter::Validator::validateNode(ASTNode node,
+ const NodeInfo &nodeInfo) {
+ if (!ValidatedNodes.insert(node).second) return;
+
+ // A map from property name to property.
+ std::map<StringRef, Property> allProperties;
+
+ // Walk the hierarchy, ignoring nodes that don't declare anything
+ // interesting.
+ for (auto base = node; base; base = base.getBase()) {
+ auto it = Emitter.NodeInfos.find(base);
+ if (it == Emitter.NodeInfos.end()) continue;
+
+ auto &baseInfo = it->second;
+ for (Property property : baseInfo.Properties) {
+ validateType(property.getType(), property);
+
+ auto result = allProperties.insert(
+ std::make_pair(property.getName(), property));
+
+ // Diagnose non-unique properties.
+ if (!result.second) {
+ // The existing property is more likely to be associated with a
+ // derived node, so use it as the error.
+ Property existingProperty = result.first->second;
+ PrintError(existingProperty.getLoc(),
+ "multiple properties named \"" + property.getName()
+ + "\" in hierarchy of " + node.getName());
+ PrintNote(property.getLoc(), "existing property");
+ }
+ }
+ }
+}
+
+void ASTPropsEmitter::Validator::validateType(PropertyType type,
+ WrappedRecord context) {
+ if (!type.isGenericSpecialization()) {
+ if (type.getCXXTypeName() == "") {
+ PrintError(type.getLoc(),
+ "type is not generic but has no C++ type name");
+ if (context) PrintNote(context.getLoc(), "type used here");
+ }
+ } else if (auto eltType = type.getArrayElementType()) {
+ validateType(eltType, context);
+ } else if (auto valueType = type.getOptionalElementType()) {
+ validateType(valueType, context);
+
+ if (valueType.getPackOptionalCode().empty()) {
+ PrintError(valueType.getLoc(),
+ "type doesn't provide optional-packing code");
+ if (context) PrintNote(context.getLoc(), "type used here");
+ } else if (valueType.getUnpackOptionalCode().empty()) {
+ PrintError(valueType.getLoc(),
+ "type doesn't provide optional-unpacking code");
+ if (context) PrintNote(context.getLoc(), "type used here");
+ }
+ } else {
+ PrintError(type.getLoc(), "unknown generic property type");
+ if (context) PrintNote(context.getLoc(), "type used here");
+ }
+}
+
+/****************************************************************************/
+/**************************** AST READER/WRITERS ****************************/
+/****************************************************************************/
+
+template <class NodeClass>
+void ASTPropsEmitter::emitReaderWriterClass(const ReaderWriterInfo &info) {
+ StringRef suffix = info.ClassSuffix;
+ StringRef var = info.HelperVariable;
+
+ // Enter the class declaration.
+ Out << "template <class Property" << suffix << ">\n"
+ "class Abstract" << info.HierarchyName << suffix << " {\n"
+ "public:\n"
+ " Property" << suffix << " &" << var << ";\n\n";
+
+ // Emit the constructor.
+ Out << " Abstract" << info.HierarchyName << suffix
+ << "(Property" << suffix << " &" << var << ") : "
+ << var << "(" << var << ") {}\n\n";
+
+ // Emit a method that dispatches on a kind to the appropriate node-specific
+ // method.
+ Out << " " << info.ResultType << " " << info.MethodPrefix << "(";
+ if (info.IsReader)
+ Out << NodeClass::getASTIdTypeName() << " kind";
+ else
+ Out << "const " << info.HierarchyName << " *node";
+ Out << ") {\n"
+ " switch (";
+ if (info.IsReader)
+ Out << "kind";
+ else
+ Out << "node->" << NodeClass::getASTIdAccessorName() << "()";
+ Out << ") {\n";
+ visitASTNodeHierarchy<NodeClass>(Records, [&](NodeClass node, NodeClass _) {
+ if (node.isAbstract()) return;
+ Out << " case " << info.HierarchyName << "::" << node.getId() << ":\n"
+ " return " << info.MethodPrefix << node.getClassName() << "(";
+ if (!info.IsReader)
+ Out << "static_cast<const " << node.getClassName()
+ << " *>(node)";
+ Out << ");\n";
+ });
+ Out << " }\n"
+ " llvm_unreachable(\"bad kind\");\n"
+ " }\n\n";
+
+ // Emit node-specific methods for all the concrete nodes.
+ visitASTNodeHierarchy<NodeClass>(Records,
+ [&](NodeClass node, NodeClass base) {
+ if (node.isAbstract()) return;
+ emitNodeReaderWriterMethod(node, info);
+ });
+
+ // Finish the class.
+ Out << "};\n\n";
+}
+
+/// Emit a reader method for the given concrete AST node class.
+template <class NodeClass>
+void ASTPropsEmitter::emitNodeReaderWriterMethod(NodeClass node,
+ const ReaderWriterInfo &info) {
+ // Declare and start the method.
+ Out << " " << info.ResultType << " "
+ << info.MethodPrefix << node.getClassName() << "(";
+ if (!info.IsReader)
+ Out << "const " << node.getClassName() << " *node";
+ Out << ") {\n";
+ if (info.IsReader)
+ Out << " auto &ctx = " << info.HelperVariable << ".getASTContext();\n";
+
+ // Find the information for this node.
+ auto it = NodeInfos.find(node);
+ if (it == NodeInfos.end())
+ PrintFatalError(node.getLoc(),
+ "no information about how to deserialize \""
+ + node.getName() + "\"");
+ auto &nodeInfo = it->second;
+
+ StringRef creationCode;
+ if (info.IsReader) {
+ // We should have a creation rule.
+ if (!nodeInfo.Creator)
+ PrintFatalError(node.getLoc(),
+ "no " CreationRuleClassName " for \""
+ + node.getName() + "\"");
+
+ creationCode = nodeInfo.Creator.getCreationCode();
+ }
+
+ // Emit code to read all the properties.
+ visitAllProperties(node, nodeInfo, [&](Property prop) {
+ // Verify that the creation code refers to this property.
+ if (info.IsReader && creationCode.find(prop.getName()) == StringRef::npos)
+ PrintFatalError(nodeInfo.Creator.getLoc(),
+ "creation code for " + node.getName()
+ + " doesn't refer to property \""
+ + prop.getName() + "\"");
+
+ // Emit code to read or write this property.
+ if (info.IsReader)
+ emitReadOfProperty(prop);
+ else
+ emitWriteOfProperty(prop);
+ });
+
+ // Emit the final creation code.
+ if (info.IsReader)
+ Out << " " << creationCode << "\n";
+
+ // Finish the method declaration.
+ Out << " }\n\n";
+}
+
+static void emitBasicReaderWriterMethodSuffix(raw_ostream &out,
+ PropertyType type,
+ bool isForRead) {
+ if (!type.isGenericSpecialization()) {
+ out << type.getAbstractTypeName();
+ } else if (auto eltType = type.getArrayElementType()) {
+ out << "Array";
+ // We only include an explicit template argument for reads so that
+ // we don't cause spurious const mismatches.
+ if (isForRead) {
+ out << "<";
+ eltType.emitCXXValueTypeName(isForRead, out);
+ out << ">";
+ }
+ } else if (auto valueType = type.getOptionalElementType()) {
+ out << "Optional";
+ // We only include an explicit template argument for reads so that
+ // we don't cause spurious const mismatches.
+ if (isForRead) {
+ out << "<";
+ valueType.emitCXXValueTypeName(isForRead, out);
+ out << ">";
+ }
+ } else {
+ PrintFatalError(type.getLoc(), "unexpected generic property type");
+ }
+}
+
+/// Emit code to read the given property in a node-reader method.
+void ASTPropsEmitter::emitReadOfProperty(Property property) {
+ PropertyType type = property.getType();
+ auto name = property.getName();
+
+ // Declare all the necessary buffers.
+ auto bufferTypes = type.getBufferElementTypes();
+ for (size_t i = 0, e = bufferTypes.size(); i != e; ++i) {
+ Out << " llvm::SmallVector<";
+ PropertyType(bufferTypes[i]).emitCXXValueTypeName(/*for read*/ true, Out);
+ Out << ", 8> " << name << "_buffer_" << i << ";\n";
+ }
+
+ // T prop = R.find("prop").read##ValueType(buffers...);
+ // We intentionally ignore shouldPassByReference here: we're going to
+ // get a pr-value back from read(), and we should be able to forward
+ // that in the creation rule.
+ Out << " ";
+ type.emitCXXValueTypeName(true, Out);
+ Out << " " << name << " = R.find(\"" << name << "\")."
+ << (type.isGenericSpecialization() ? "template " : "") << "read";
+ emitBasicReaderWriterMethodSuffix(Out, type, /*for read*/ true);
+ Out << "(";
+ for (size_t i = 0, e = bufferTypes.size(); i != e; ++i) {
+ Out << (i > 0 ? ", " : "") << name << "_buffer_" << i;
+ }
+ Out << ");\n";
+}
+
+/// Emit code to write the given property in a node-writer method.
+void ASTPropsEmitter::emitWriteOfProperty(Property property) {
+ // Focus down to the property:
+ // W.find("prop").write##ValueType(value);
+ Out << " W.find(\"" << property.getName() << "\").write";
+ emitBasicReaderWriterMethodSuffix(Out, property.getType(),
+ /*for read*/ false);
+ Out << "(" << property.getReadCode() << ");\n";
+}
+
+/// Emit an .inc file that defines the AbstractFooReader class
+/// for the given AST class hierarchy.
+template <class NodeClass>
+static void emitASTReader(RecordKeeper &records, raw_ostream &out,
+ StringRef description) {
+ emitSourceFileHeader(description, out);
+
+ ASTPropsEmitter(records, out).emitReaderClass<NodeClass>();
+}
+
+void clang::EmitClangTypeReader(RecordKeeper &records, raw_ostream &out) {
+ emitASTReader<TypeNode>(records, out, "A CRTP reader for Clang Type nodes");
+}
+
+/// Emit an .inc file that defines the AbstractFooWriter class
+/// for the given AST class hierarchy.
+template <class NodeClass>
+static void emitASTWriter(RecordKeeper &records, raw_ostream &out,
+ StringRef description) {
+ emitSourceFileHeader(description, out);
+
+ ASTPropsEmitter(records, out).emitWriterClass<NodeClass>();
+}
+
+void clang::EmitClangTypeWriter(RecordKeeper &records, raw_ostream &out) {
+ emitASTWriter<TypeNode>(records, out, "A CRTP writer for Clang Type nodes");
+}
+
+/****************************************************************************/
+/*************************** BASIC READER/WRITERS ***************************/
+/****************************************************************************/
+
+static void emitDispatcherTemplate(ArrayRef<Record*> types, raw_ostream &out,
+ const ReaderWriterInfo &info) {
+ // Declare the {Read,Write}Dispatcher template.
+ StringRef dispatcherPrefix = (info.IsReader ? "Read" : "Write");
+ out << "template <class ValueType>\n"
+ "struct " << dispatcherPrefix << "Dispatcher;\n";
+
+ // Declare a specific specialization of the dispatcher template.
+ auto declareSpecialization =
+ [&](StringRef specializationParameters,
+ const Twine &cxxTypeName,
+ StringRef methodSuffix) {
+ StringRef var = info.HelperVariable;
+ out << "template " << specializationParameters << "\n"
+ "struct " << dispatcherPrefix << "Dispatcher<"
+ << cxxTypeName << "> {\n";
+ out << " template <class Basic" << info.ClassSuffix << ", class... Args>\n"
+ " static " << (info.IsReader ? cxxTypeName : "void") << " "
+ << info.MethodPrefix
+ << "(Basic" << info.ClassSuffix << " &" << var
+ << ", Args &&... args) {\n"
+ " return " << var << "."
+ << info.MethodPrefix << methodSuffix
+ << "(std::forward<Args>(args)...);\n"
+ " }\n"
+ "};\n";
+ };
+
+ // Declare explicit specializations for each of the concrete types.
+ for (PropertyType type : types) {
+ declareSpecialization("<>",
+ type.getCXXTypeName(),
+ type.getAbstractTypeName());
+ // Also declare a specialization for the const type when appropriate.
+ if (!info.IsReader && type.isConstWhenWriting()) {
+ declareSpecialization("<>",
+ "const " + type.getCXXTypeName(),
+ type.getAbstractTypeName());
+ }
+ }
+ // Declare partial specializations for ArrayRef and Optional.
+ declareSpecialization("<class T>",
+ "llvm::ArrayRef<T>",
+ "Array");
+ declareSpecialization("<class T>",
+ "llvm::Optional<T>",
+ "Optional");
+ out << "\n";
+}
+
+static void emitPackUnpackOptionalTemplate(ArrayRef<Record*> types,
+ raw_ostream &out,
+ const ReaderWriterInfo &info) {
+ StringRef classPrefix = (info.IsReader ? "Unpack" : "Pack");
+ StringRef methodName = (info.IsReader ? "unpack" : "pack");
+
+ // Declare the {Pack,Unpack}OptionalValue template.
+ out << "template <class ValueType>\n"
+ "struct " << classPrefix << "OptionalValue;\n";
+
+ auto declareSpecialization = [&](const Twine &typeName,
+ StringRef code) {
+ out << "template <>\n"
+ "struct " << classPrefix << "OptionalValue<" << typeName << "> {\n"
+ " static " << (info.IsReader ? "Optional<" : "") << typeName
+ << (info.IsReader ? "> " : " ") << methodName << "("
+ << (info.IsReader ? "" : "Optional<") << typeName
+ << (info.IsReader ? "" : ">") << " value) {\n"
+ " return " << code << ";\n"
+ " }\n"
+ "};\n";
+ };
+
+ for (PropertyType type : types) {
+ StringRef code = (info.IsReader ? type.getUnpackOptionalCode()
+ : type.getPackOptionalCode());
+ if (code.empty()) continue;
+
+ StringRef typeName = type.getCXXTypeName();
+ declareSpecialization(typeName, code);
+ if (type.isConstWhenWriting() && !info.IsReader)
+ declareSpecialization("const " + typeName, code);
+ }
+ out << "\n";
+}
+
+static void emitBasicReaderWriterTemplate(ArrayRef<Record*> types,
+ raw_ostream &out,
+ const ReaderWriterInfo &info) {
+ // Emit the Basic{Reader,Writer}Base template.
+ out << "template <class Impl>\n"
+ "class Basic" << info.ClassSuffix << "Base {\n";
+ if (info.IsReader)
+ out << " ASTContext &C;\n";
+ out << "protected:\n"
+ " Basic" << info.ClassSuffix << "Base"
+ << (info.IsReader ? "(ASTContext &ctx) : C(ctx)" : "()")
+ << " {}\n"
+ "public:\n";
+ if (info.IsReader)
+ out << " ASTContext &getASTContext() { return C; }\n";
+ out << " Impl &asImpl() { return static_cast<Impl&>(*this); }\n";
+
+ auto enterReaderWriterMethod = [&](StringRef cxxTypeName,
+ StringRef abstractTypeName,
+ bool shouldPassByReference,
+ bool constWhenWriting) {
+ out << " " << (info.IsReader ? cxxTypeName : "void")
+ << " " << info.MethodPrefix << abstractTypeName << "(";
+ if (!info.IsReader)
+ out << (shouldPassByReference || constWhenWriting ? "const " : "")
+ << cxxTypeName
+ << (shouldPassByReference ? " &" : "") << " value";
+ out << ") {\n";
+ };
+
+ // Emit {read,write}ValueType methods for all the enum and subclass types
+ // that default to using the integer/base-class implementations.
+ for (PropertyType type : types) {
+ if (type.isEnum()) {
+ enterReaderWriterMethod(type.getCXXTypeName(),
+ type.getAbstractTypeName(),
+ /*pass by reference*/ false,
+ /*const when writing*/ false);
+ if (info.IsReader)
+ out << " return " << type.getCXXTypeName()
+ << "(asImpl().readUInt32());\n";
+ else
+ out << " asImpl().writeUInt32(uint32_t(value));\n";
+ out << " }\n";
+ } else if (PropertyType superclass = type.getSuperclassType()) {
+ enterReaderWriterMethod(type.getCXXTypeName(),
+ type.getAbstractTypeName(),
+ /*pass by reference*/ false,
+ /*const when writing*/ type.isConstWhenWriting());
+ if (info.IsReader)
+ out << " return cast_or_null<" << type.getSubclassClassName()
+ << ">(asImpl().read"
+ << superclass.getAbstractTypeName()
+ << "());\n";
+ else
+ out << " asImpl().write" << superclass.getAbstractTypeName()
+ << "(value);\n";
+ out << " }\n";
+ } else {
+ // The other types can't be handled as trivially.
+ }
+ }
+ out << "};\n\n";
+}
+
+static void emitBasicReaderWriterFile(RecordKeeper &records, raw_ostream &out,
+ const ReaderWriterInfo &info) {
+ auto types = records.getAllDerivedDefinitions(PropertyTypeClassName);
+
+ emitDispatcherTemplate(types, out, info);
+ emitPackUnpackOptionalTemplate(types, out, info);
+ emitBasicReaderWriterTemplate(types, out, info);
+}
+
+/// Emit an .inc file that defines some helper classes for reading
+/// basic values.
+void clang::EmitClangBasicReader(RecordKeeper &records, raw_ostream &out) {
+ emitSourceFileHeader("Helper classes for BasicReaders", out);
+
+ // Use any property, we won't be using those properties.
+ auto info = ReaderWriterInfo::forReader<TypeNode>();
+ emitBasicReaderWriterFile(records, out, info);
+}
+
+/// Emit an .inc file that defines some helper classes for writing
+/// basic values.
+void clang::EmitClangBasicWriter(RecordKeeper &records, raw_ostream &out) {
+ emitSourceFileHeader("Helper classes for BasicWriters", out);
+
+ // Use any property, we won't be using those properties.
+ auto info = ReaderWriterInfo::forWriter<TypeNode>();
+ emitBasicReaderWriterFile(records, out, info);
+}