| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,335 @@ | ||
| //==--- AbstractBasicWriter.h - Abstract basic value serialization --------===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef CLANG_AST_ABSTRACTBASICWRITER_H | ||
| #define CLANG_AST_ABSTRACTBASICWRITER_H | ||
|
|
||
| #include "clang/AST/DeclTemplate.h" | ||
|
|
||
| namespace clang { | ||
| namespace serialization { | ||
|
|
||
| template <class T> | ||
| inline llvm::Optional<T> makeOptionalFromNullable(const T &value) { | ||
| return (value.isNull() | ||
| ? llvm::Optional<T>() | ||
| : llvm::Optional<T>(value)); | ||
| } | ||
|
|
||
| template <class T> | ||
| inline llvm::Optional<T*> makeOptionalFromPointer(T *value) { | ||
| return (value ? llvm::Optional<T*>(value) : llvm::Optional<T*>()); | ||
| } | ||
|
|
||
| // PropertyWriter is a class concept that requires the following method: | ||
| // BasicWriter find(llvm::StringRef propertyName); | ||
| // where BasicWriter is some class conforming to the BasicWriter concept. | ||
| // An abstract AST-node writer is created with a PropertyWriter and | ||
| // performs a sequence of calls like so: | ||
| // propertyWriter.find(propertyName).write##TypeName(value) | ||
| // to write the properties of the node it is serializing. | ||
|
|
||
| // BasicWriter is a class concept that requires methods like: | ||
| // void write##TypeName(ValueType value); | ||
| // where TypeName is the name of a PropertyType node from PropertiesBase.td | ||
| // and ValueType is the corresponding C++ type name. | ||
|
|
||
| // WriteDispatcher is a template which does type-based forwarding to one | ||
| // of the write methods of the BasicWriter passed in: | ||
| // | ||
| // template <class ValueType> | ||
| // struct WriteDispatcher { | ||
| // template <class BasicWriter> | ||
| // static void write(BasicWriter &W, ValueType value); | ||
| // }; | ||
|
|
||
| // BasicWriterBase provides convenience implementations of the write | ||
| // methods for EnumPropertyType and SubclassPropertyType types that just | ||
| // defer to the "underlying" implementations (for UInt32 and the base class, | ||
| // respectively). | ||
| // | ||
| // template <class Impl> | ||
| // class BasicWriterBase { | ||
| // protected: | ||
| // Impl &asImpl(); | ||
| // public: | ||
| // ... | ||
| // }; | ||
|
|
||
| // The actual classes are auto-generated; see ClangASTPropertiesEmitter.cpp. | ||
| #include "clang/AST/AbstractBasicWriter.inc" | ||
|
|
||
| /// DataStreamBasicWriter provides convenience implementations for many | ||
| /// BasicWriter methods based on the assumption that the | ||
| /// ultimate writer implementation is based on a variable-length stream | ||
| /// of unstructured data (like Clang's module files). It is designed | ||
| /// to pair with DataStreamBasicReader. | ||
| /// | ||
| /// This class can also act as a PropertyWriter, implementing find("...") | ||
| /// by simply forwarding to itself. | ||
| /// | ||
| /// Unimplemented methods: | ||
| /// writeBool | ||
| /// writeUInt32 | ||
| /// writeUInt64 | ||
| /// writeIdentifier | ||
| /// writeSelector | ||
| /// writeSourceLocation | ||
| /// writeQualType | ||
| /// writeStmtRef | ||
| /// writeDeclRef | ||
| template <class Impl> | ||
| class DataStreamBasicWriter : public BasicWriterBase<Impl> { | ||
| protected: | ||
| using BasicWriterBase<Impl>::asImpl; | ||
|
|
||
| public: | ||
| /// Implement property-find by ignoring it. We rely on properties being | ||
| /// serialized and deserialized in a reliable order instead. | ||
| Impl &find(const char *propertyName) { | ||
| return asImpl(); | ||
| } | ||
|
|
||
| template <class T> | ||
| void writeArray(llvm::ArrayRef<T> array) { | ||
| asImpl().writeUInt32(array.size()); | ||
| for (const T &elt : array) { | ||
| WriteDispatcher<T>::write(asImpl(), elt); | ||
| } | ||
| } | ||
|
|
||
| template <class T> | ||
| void writeOptional(llvm::Optional<T> value) { | ||
| WriteDispatcher<T>::write(asImpl(), PackOptionalValue<T>::pack(value)); | ||
| } | ||
|
|
||
| void writeAPSInt(const llvm::APSInt &value) { | ||
| asImpl().writeBool(value.isUnsigned()); | ||
| asImpl().writeAPInt(value); | ||
| } | ||
|
|
||
| void writeAPInt(const llvm::APInt &value) { | ||
| asImpl().writeUInt32(value.getBitWidth()); | ||
| const uint64_t *words = value.getRawData(); | ||
| for (size_t i = 0, e = value.getNumWords(); i != e; ++i) | ||
| asImpl().writeUInt64(words[i]); | ||
| } | ||
|
|
||
| void writeQualifiers(Qualifiers value) { | ||
| static_assert(sizeof(value.getAsOpaqueValue()) <= sizeof(uint32_t), | ||
| "update this if the value size changes"); | ||
| asImpl().writeUInt32(value.getAsOpaqueValue()); | ||
| } | ||
|
|
||
| void writeExceptionSpecInfo( | ||
| const FunctionProtoType::ExceptionSpecInfo &esi) { | ||
| asImpl().writeUInt32(uint32_t(esi.Type)); | ||
| if (esi.Type == EST_Dynamic) { | ||
| asImpl().writeArray(esi.Exceptions); | ||
| } else if (isComputedNoexcept(esi.Type)) { | ||
| asImpl().writeExprRef(esi.NoexceptExpr); | ||
| } else if (esi.Type == EST_Uninstantiated) { | ||
| asImpl().writeDeclRef(esi.SourceDecl); | ||
| asImpl().writeDeclRef(esi.SourceTemplate); | ||
| } else if (esi.Type == EST_Unevaluated) { | ||
| asImpl().writeDeclRef(esi.SourceDecl); | ||
| } | ||
| } | ||
|
|
||
| void writeExtParameterInfo(FunctionProtoType::ExtParameterInfo epi) { | ||
| static_assert(sizeof(epi.getOpaqueValue()) <= sizeof(uint32_t), | ||
| "opaque value doesn't fit into uint32_t"); | ||
| asImpl().writeUInt32(epi.getOpaqueValue()); | ||
| } | ||
|
|
||
| void writeDeclarationName(DeclarationName name) { | ||
| asImpl().writeDeclarationNameKind(name.getNameKind()); | ||
| switch (name.getNameKind()) { | ||
| case DeclarationName::Identifier: | ||
| asImpl().writeIdentifier(name.getAsIdentifierInfo()); | ||
| return; | ||
|
|
||
| case DeclarationName::ObjCZeroArgSelector: | ||
| case DeclarationName::ObjCOneArgSelector: | ||
| case DeclarationName::ObjCMultiArgSelector: | ||
| asImpl().writeSelector(name.getObjCSelector()); | ||
| return; | ||
|
|
||
| case DeclarationName::CXXConstructorName: | ||
| case DeclarationName::CXXDestructorName: | ||
| case DeclarationName::CXXConversionFunctionName: | ||
| asImpl().writeQualType(name.getCXXNameType()); | ||
| return; | ||
|
|
||
| case DeclarationName::CXXDeductionGuideName: | ||
| asImpl().writeDeclRef(name.getCXXDeductionGuideTemplate()); | ||
| return; | ||
|
|
||
| case DeclarationName::CXXOperatorName: | ||
| asImpl().writeOverloadedOperatorKind(name.getCXXOverloadedOperator()); | ||
| return; | ||
|
|
||
| case DeclarationName::CXXLiteralOperatorName: | ||
| asImpl().writeIdentifier(name.getCXXLiteralIdentifier()); | ||
| return; | ||
|
|
||
| case DeclarationName::CXXUsingDirective: | ||
| // No extra data to emit | ||
| return; | ||
| } | ||
| llvm_unreachable("bad name kind"); | ||
| } | ||
|
|
||
| void writeTemplateName(TemplateName name) { | ||
| asImpl().writeTemplateNameKind(name.getKind()); | ||
| switch (name.getKind()) { | ||
| case TemplateName::Template: | ||
| asImpl().writeDeclRef(name.getAsTemplateDecl()); | ||
| return; | ||
|
|
||
| case TemplateName::OverloadedTemplate: { | ||
| OverloadedTemplateStorage *overload = name.getAsOverloadedTemplate(); | ||
| asImpl().writeArray(llvm::makeArrayRef(overload->begin(), | ||
| overload->end())); | ||
| return; | ||
| } | ||
|
|
||
| case TemplateName::AssumedTemplate: { | ||
| AssumedTemplateStorage *assumed = name.getAsAssumedTemplateName(); | ||
| asImpl().writeDeclarationName(assumed->getDeclName()); | ||
| return; | ||
| } | ||
|
|
||
| case TemplateName::QualifiedTemplate: { | ||
| QualifiedTemplateName *qual = name.getAsQualifiedTemplateName(); | ||
| asImpl().writeNestedNameSpecifier(qual->getQualifier()); | ||
| asImpl().writeBool(qual->hasTemplateKeyword()); | ||
| asImpl().writeDeclRef(qual->getTemplateDecl()); | ||
| return; | ||
| } | ||
|
|
||
| case TemplateName::DependentTemplate: { | ||
| DependentTemplateName *dep = name.getAsDependentTemplateName(); | ||
| asImpl().writeNestedNameSpecifier(dep->getQualifier()); | ||
| asImpl().writeBool(dep->isIdentifier()); | ||
| if (dep->isIdentifier()) | ||
| asImpl().writeIdentifier(dep->getIdentifier()); | ||
| else | ||
| asImpl().writeOverloadedOperatorKind(dep->getOperator()); | ||
| return; | ||
| } | ||
|
|
||
| case TemplateName::SubstTemplateTemplateParm: { | ||
| auto subst = name.getAsSubstTemplateTemplateParm(); | ||
| asImpl().writeDeclRef(subst->getParameter()); | ||
| asImpl().writeTemplateName(subst->getReplacement()); | ||
| return; | ||
| } | ||
|
|
||
| case TemplateName::SubstTemplateTemplateParmPack: { | ||
| auto substPack = name.getAsSubstTemplateTemplateParmPack(); | ||
| asImpl().writeDeclRef(substPack->getParameterPack()); | ||
| asImpl().writeTemplateArgument(substPack->getArgumentPack()); | ||
| return; | ||
| } | ||
| } | ||
| llvm_unreachable("bad template name kind"); | ||
| } | ||
|
|
||
| void writeTemplateArgument(const TemplateArgument &arg) { | ||
| asImpl().writeTemplateArgumentKind(arg.getKind()); | ||
| switch (arg.getKind()) { | ||
| case TemplateArgument::Null: | ||
| return; | ||
| case TemplateArgument::Type: | ||
| asImpl().writeQualType(arg.getAsType()); | ||
| return; | ||
| case TemplateArgument::Declaration: | ||
| asImpl().writeValueDeclRef(arg.getAsDecl()); | ||
| asImpl().writeQualType(arg.getParamTypeForDecl()); | ||
| return; | ||
| case TemplateArgument::NullPtr: | ||
| asImpl().writeQualType(arg.getNullPtrType()); | ||
| return; | ||
| case TemplateArgument::Integral: | ||
| asImpl().writeAPSInt(arg.getAsIntegral()); | ||
| asImpl().writeQualType(arg.getIntegralType()); | ||
| return; | ||
| case TemplateArgument::Template: | ||
| asImpl().writeTemplateName(arg.getAsTemplateOrTemplatePattern()); | ||
| return; | ||
| case TemplateArgument::TemplateExpansion: { | ||
| asImpl().writeTemplateName(arg.getAsTemplateOrTemplatePattern()); | ||
| // Convert Optional<unsigned> to Optional<uint32>, just in case. | ||
| Optional<unsigned> numExpansions = arg.getNumTemplateExpansions(); | ||
| Optional<uint32_t> numExpansions32; | ||
| if (numExpansions) numExpansions32 = *numExpansions; | ||
| asImpl().template writeOptional<uint32_t>(numExpansions32); | ||
| return; | ||
| } | ||
| case TemplateArgument::Expression: | ||
| asImpl().writeExprRef(arg.getAsExpr()); | ||
| return; | ||
| case TemplateArgument::Pack: | ||
| asImpl().template writeArray<TemplateArgument>(arg.pack_elements()); | ||
| return; | ||
| } | ||
| llvm_unreachable("bad template argument kind"); | ||
| } | ||
|
|
||
| void writeNestedNameSpecifier(NestedNameSpecifier *NNS) { | ||
| // Nested name specifiers usually aren't too long. I think that 8 would | ||
| // typically accommodate the vast majority. | ||
| SmallVector<NestedNameSpecifier *, 8> nestedNames; | ||
|
|
||
| // Push each of the NNS's onto a stack for serialization in reverse order. | ||
| while (NNS) { | ||
| nestedNames.push_back(NNS); | ||
| NNS = NNS->getPrefix(); | ||
| } | ||
|
|
||
| asImpl().writeUInt32(nestedNames.size()); | ||
| while (!nestedNames.empty()) { | ||
| NNS = nestedNames.pop_back_val(); | ||
| NestedNameSpecifier::SpecifierKind kind = NNS->getKind(); | ||
| asImpl().writeNestedNameSpecifierKind(kind); | ||
| switch (kind) { | ||
| case NestedNameSpecifier::Identifier: | ||
| asImpl().writeIdentifier(NNS->getAsIdentifier()); | ||
| continue; | ||
|
|
||
| case NestedNameSpecifier::Namespace: | ||
| asImpl().writeNamespaceDeclRef(NNS->getAsNamespace()); | ||
| continue; | ||
|
|
||
| case NestedNameSpecifier::NamespaceAlias: | ||
| asImpl().writeNamespaceAliasDeclRef(NNS->getAsNamespaceAlias()); | ||
| continue; | ||
|
|
||
| case NestedNameSpecifier::TypeSpec: | ||
| case NestedNameSpecifier::TypeSpecWithTemplate: | ||
| asImpl().writeQualType(QualType(NNS->getAsType(), 0)); | ||
| continue; | ||
|
|
||
| case NestedNameSpecifier::Global: | ||
| // Don't need to write an associated value. | ||
| continue; | ||
|
|
||
| case NestedNameSpecifier::Super: | ||
| asImpl().writeDeclRef(NNS->getAsRecordDecl()); | ||
| continue; | ||
| } | ||
| llvm_unreachable("bad nested name specifier kind"); | ||
| } | ||
| } | ||
| }; | ||
|
|
||
| } // end namespace serialization | ||
| } // end namespace clang | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| //==--- AbstractTypeReader.h - Abstract deserialization for types ---------===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef CLANG_AST_ABSTRACTTYPEREADER_H | ||
| #define CLANG_AST_ABSTRACTTYPEREADER_H | ||
|
|
||
| #include "clang/AST/Type.h" | ||
| #include "clang/AST/AbstractBasicReader.h" | ||
|
|
||
| namespace clang { | ||
| namespace serialization { | ||
|
|
||
| // template <class PropertyReader> | ||
| // class AbstractTypeReader { | ||
| // public: | ||
| // AbstractTypeReader(PropertyReader &W); | ||
| // QualType read(Type::TypeClass kind); | ||
| // }; | ||
| // | ||
| // The actual class is auto-generated; see ClangASTPropertiesEmitter.cpp. | ||
| #include "clang/AST/AbstractTypeReader.inc" | ||
|
|
||
| } // end namespace serialization | ||
| } // end namespace clang | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| //==--- AbstractTypeWriter.h - Abstract serialization for types -----------===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef CLANG_AST_ABSTRACTTYPEWRITER_H | ||
| #define CLANG_AST_ABSTRACTTYPEWRITER_H | ||
|
|
||
| #include "clang/AST/Type.h" | ||
| #include "clang/AST/AbstractBasicWriter.h" | ||
| #include "clang/AST/DeclObjC.h" | ||
|
|
||
| namespace clang { | ||
| namespace serialization { | ||
|
|
||
| // template <class PropertyWriter> | ||
| // class AbstractTypeWriter { | ||
| // public: | ||
| // AbstractTypeWriter(PropertyWriter &W); | ||
| // void write(QualType type); | ||
| // }; | ||
| // | ||
| // The actual class is auto-generated; see ClangASTPropertiesEmitter.cpp. | ||
| #include "clang/AST/AbstractTypeWriter.inc" | ||
|
|
||
| } // end namespace serialization | ||
| } // end namespace clang | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,179 @@ | ||
| //==--- 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 = []; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| //===--- TypeNodeBitCodes.def - Type to bitcode correspondance --*- 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 file provides an x-macro link between AST Type IDs and | ||
| // their stable serialized bit-code record type IDs. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| TYPE_BIT_CODE(Complex, COMPLEX, 3) | ||
| TYPE_BIT_CODE(Pointer, POINTER, 4) | ||
| TYPE_BIT_CODE(BlockPointer, BLOCK_POINTER, 5) | ||
| TYPE_BIT_CODE(LValueReference, LVALUE_REFERENCE, 6) | ||
| TYPE_BIT_CODE(RValueReference, RVALUE_REFERENCE, 7) | ||
| TYPE_BIT_CODE(MemberPointer, MEMBER_POINTER, 8) | ||
| TYPE_BIT_CODE(ConstantArray, CONSTANT_ARRAY, 9) | ||
| TYPE_BIT_CODE(IncompleteArray, INCOMPLETE_ARRAY, 10) | ||
| TYPE_BIT_CODE(VariableArray, VARIABLE_ARRAY, 11) | ||
| TYPE_BIT_CODE(Vector, VECTOR, 12) | ||
| TYPE_BIT_CODE(ExtVector, EXT_VECTOR, 13) | ||
| TYPE_BIT_CODE(FunctionNoProto, FUNCTION_NO_PROTO, 14) | ||
| TYPE_BIT_CODE(FunctionProto, FUNCTION_PROTO, 15) | ||
| TYPE_BIT_CODE(Typedef, TYPEDEF, 16) | ||
| TYPE_BIT_CODE(TypeOfExpr, TYPEOF_EXPR, 17) | ||
| TYPE_BIT_CODE(TypeOf, TYPEOF, 18) | ||
| TYPE_BIT_CODE(Record, RECORD, 19) | ||
| TYPE_BIT_CODE(Enum, ENUM, 20) | ||
| TYPE_BIT_CODE(ObjCInterface, OBJC_INTERFACE, 21) | ||
| TYPE_BIT_CODE(ObjCObjectPointer, OBJC_OBJECT_POINTER, 22) | ||
| TYPE_BIT_CODE(Decltype, DECLTYPE, 23) | ||
| TYPE_BIT_CODE(Elaborated, ELABORATED, 24) | ||
| TYPE_BIT_CODE(SubstTemplateTypeParm, SUBST_TEMPLATE_TYPE_PARM, 25) | ||
| TYPE_BIT_CODE(UnresolvedUsing, UNRESOLVED_USING, 26) | ||
| TYPE_BIT_CODE(InjectedClassName, INJECTED_CLASS_NAME, 27) | ||
| TYPE_BIT_CODE(ObjCObject, OBJC_OBJECT, 28) | ||
| TYPE_BIT_CODE(TemplateTypeParm, TEMPLATE_TYPE_PARM, 29) | ||
| TYPE_BIT_CODE(TemplateSpecialization, TEMPLATE_SPECIALIZATION, 30) | ||
| TYPE_BIT_CODE(DependentName, DEPENDENT_NAME, 31) | ||
| TYPE_BIT_CODE(DependentTemplateSpecialization, DEPENDENT_TEMPLATE_SPECIALIZATION, 32) | ||
| TYPE_BIT_CODE(DependentSizedArray, DEPENDENT_SIZED_ARRAY, 33) | ||
| TYPE_BIT_CODE(Paren, PAREN, 34) | ||
| TYPE_BIT_CODE(PackExpansion, PACK_EXPANSION, 35) | ||
| TYPE_BIT_CODE(Attributed, ATTRIBUTED, 36) | ||
| TYPE_BIT_CODE(SubstTemplateTypeParmPack, SUBST_TEMPLATE_TYPE_PARM_PACK, 37) | ||
| TYPE_BIT_CODE(Auto, AUTO, 38) | ||
| TYPE_BIT_CODE(UnaryTransform, UNARY_TRANSFORM, 39) | ||
| TYPE_BIT_CODE(Atomic, ATOMIC, 40) | ||
| TYPE_BIT_CODE(Decayed, DECAYED, 41) | ||
| TYPE_BIT_CODE(Adjusted, ADJUSTED, 42) | ||
| TYPE_BIT_CODE(Pipe, PIPE, 43) | ||
| TYPE_BIT_CODE(ObjCTypeParam, OBJC_TYPE_PARAM, 44) | ||
| TYPE_BIT_CODE(DeducedTemplateSpecialization, DEDUCED_TEMPLATE_SPECIALIZATION, 45) | ||
| TYPE_BIT_CODE(DependentSizedExtVector, DEPENDENT_SIZED_EXT_VECTOR, 46) | ||
| TYPE_BIT_CODE(DependentAddressSpace, DEPENDENT_ADDRESS_SPACE, 47) | ||
| TYPE_BIT_CODE(DependentVector, DEPENDENT_SIZED_VECTOR, 48) | ||
| TYPE_BIT_CODE(MacroQualified, MACRO_QUALIFIED, 49) | ||
|
|
||
| #undef TYPE_BIT_CODE |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,132 @@ | ||
| //=== ASTTableGen.cpp - Helper functions for working with AST records -----===// | ||
| // | ||
| // 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 file defines some helper functions for working with tblegen reocrds | ||
| // for the Clang AST: that is, the contents of files such as DeclNodes.td, | ||
| // StmtNodes.td, and TypeNodes.td. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "ASTTableGen.h" | ||
| #include "llvm/TableGen/Record.h" | ||
| #include "llvm/TableGen/Error.h" | ||
|
|
||
| using namespace llvm; | ||
| using namespace clang; | ||
| using namespace clang::tblgen; | ||
|
|
||
| static StringRef removeExpectedNodeNameSuffix(Record *node, StringRef suffix) { | ||
| StringRef nodeName = node->getName(); | ||
| if (!nodeName.endswith(suffix)) { | ||
| PrintFatalError(node->getLoc(), | ||
| Twine("name of node doesn't end in ") + suffix); | ||
| } | ||
| return nodeName.drop_back(suffix.size()); | ||
| } | ||
|
|
||
| // Decl node names don't end in Decl for historical reasons, and it would | ||
| // be somewhat annoying to fix now. Conveniently, this means the ID matches | ||
| // is exactly the node name, and the class name is simply that plus Decl. | ||
| std::string clang::tblgen::DeclNode::getClassName() const { | ||
| return (Twine(getName()) + "Decl").str(); | ||
| } | ||
| StringRef clang::tblgen::DeclNode::getId() const { | ||
| return getName(); | ||
| } | ||
|
|
||
| // Type nodes are all named ending in Type, just like the corresponding | ||
| // C++ class, and the ID just strips this suffix. | ||
| StringRef clang::tblgen::TypeNode::getClassName() const { | ||
| return getName(); | ||
| } | ||
| StringRef clang::tblgen::TypeNode::getId() const { | ||
| return removeExpectedNodeNameSuffix(getRecord(), "Type"); | ||
| } | ||
|
|
||
| // Stmt nodes are named the same as the C++ class, which has no regular | ||
| // naming convention (all the non-expression statements end in Stmt, | ||
| // and *many* expressions end in Expr, but there are also several | ||
| // core expression classes like IntegerLiteral and BinaryOperator with | ||
| // no standard suffix). The ID adds "Class" for historical reasons. | ||
| StringRef clang::tblgen::StmtNode::getClassName() const { | ||
| return getName(); | ||
| } | ||
| std::string clang::tblgen::StmtNode::getId() const { | ||
| return (Twine(getName()) + "Class").str(); | ||
| } | ||
|
|
||
| /// Emit a string spelling out the C++ value type. | ||
| void PropertyType::emitCXXValueTypeName(bool forRead, raw_ostream &out) const { | ||
| if (!isGenericSpecialization()) { | ||
| if (!forRead && isConstWhenWriting()) | ||
| out << "const "; | ||
| out << getCXXTypeName(); | ||
| } else if (auto elementType = getArrayElementType()) { | ||
| out << "llvm::ArrayRef<"; | ||
| elementType.emitCXXValueTypeName(forRead, out); | ||
| out << ">"; | ||
| } else if (auto valueType = getOptionalElementType()) { | ||
| out << "llvm::Optional<"; | ||
| valueType.emitCXXValueTypeName(forRead, out); | ||
| out << ">"; | ||
| } else { | ||
| //PrintFatalError(getLoc(), "unexpected generic property type"); | ||
| abort(); | ||
| } | ||
| } | ||
|
|
||
| // A map from a node to each of its child nodes. | ||
| using ChildMap = std::multimap<ASTNode, ASTNode>; | ||
|
|
||
| static void visitASTNodeRecursive(ASTNode node, ASTNode base, | ||
| const ChildMap &map, | ||
| ASTNodeHierarchyVisitor<ASTNode> visit) { | ||
| visit(node, base); | ||
|
|
||
| auto i = map.lower_bound(node), e = map.upper_bound(node); | ||
| for (; i != e; ++i) { | ||
| visitASTNodeRecursive(i->second, node, map, visit); | ||
| } | ||
| } | ||
|
|
||
| static void visitHierarchy(RecordKeeper &records, | ||
| StringRef nodeClassName, | ||
| ASTNodeHierarchyVisitor<ASTNode> visit) { | ||
| // Check for the node class, just as a sanity check. | ||
| if (!records.getClass(nodeClassName)) { | ||
| PrintFatalError(Twine("cannot find definition for node class ") | ||
| + nodeClassName); | ||
| } | ||
|
|
||
| // Find all the nodes in the hierarchy. | ||
| auto nodes = records.getAllDerivedDefinitions(nodeClassName); | ||
|
|
||
| // Derive the child map. | ||
| ChildMap hierarchy; | ||
| ASTNode root; | ||
| for (ASTNode node : nodes) { | ||
| if (auto base = node.getBase()) | ||
| hierarchy.insert(std::make_pair(base, node)); | ||
| else if (root) | ||
| PrintFatalError(node.getLoc(), | ||
| "multiple root nodes in " + nodeClassName + " hierarchy"); | ||
| else | ||
| root = node; | ||
| } | ||
| if (!root) | ||
| PrintFatalError(Twine("no root node in ") + nodeClassName + " hierarchy"); | ||
|
|
||
| // Now visit the map recursively, starting at the root node. | ||
| visitASTNodeRecursive(root, ASTNode(), hierarchy, visit); | ||
| } | ||
|
|
||
| void clang::tblgen::visitASTNodeHierarchyImpl(RecordKeeper &records, | ||
| StringRef nodeClassName, | ||
| ASTNodeHierarchyVisitor<ASTNode> visit) { | ||
| visitHierarchy(records, nodeClassName, visit); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,364 @@ | ||
| //=== ASTTableGen.h - Common definitions for AST node tablegen --*- 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef CLANG_AST_TABLEGEN_H | ||
| #define CLANG_AST_TABLEGEN_H | ||
|
|
||
| #include "llvm/TableGen/Record.h" | ||
| #include "llvm/ADT/STLExtras.h" | ||
|
|
||
| // These are spellings in the tblgen files. | ||
|
|
||
| // Field names that are fortunately common across the hierarchies. | ||
| #define BaseFieldName "Base" | ||
| #define AbstractFieldName "Abstract" | ||
|
|
||
| // Comment node hierarchy. | ||
| #define CommentNodeClassName "CommentNode" | ||
|
|
||
| // Decl node hierarchy. | ||
| #define DeclNodeClassName "DeclNode" | ||
| #define DeclContextNodeClassName "DeclContext" | ||
|
|
||
| // Stmt node hierarchy. | ||
| #define StmtNodeClassName "StmtNode" | ||
|
|
||
| // Type node hierarchy. | ||
| #define TypeNodeClassName "TypeNode" | ||
| #define AlwaysDependentClassName "AlwaysDependent" | ||
| #define NeverCanonicalClassName "NeverCanonical" | ||
| #define NeverCanonicalUnlessDependentClassName "NeverCanonicalUnlessDependent" | ||
| #define LeafTypeClassName "LeafType" | ||
|
|
||
| // 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 { | ||
|
|
||
| class WrappedRecord { | ||
| llvm::Record *Record; | ||
|
|
||
| protected: | ||
| WrappedRecord(llvm::Record *record = nullptr) : Record(record) {} | ||
|
|
||
| llvm::Record *get() const { | ||
| assert(Record && "accessing null record"); | ||
| return Record; | ||
| } | ||
|
|
||
| public: | ||
| llvm::Record *getRecord() const { return Record; } | ||
|
|
||
| explicit operator bool() const { return Record != nullptr; } | ||
|
|
||
| llvm::ArrayRef<llvm::SMLoc> getLoc() const { | ||
| return get()->getLoc(); | ||
| } | ||
|
|
||
| /// Does the node inherit from the given TableGen class? | ||
| bool isSubClassOf(llvm::StringRef className) const { | ||
| return get()->isSubClassOf(className); | ||
| } | ||
| }; | ||
|
|
||
| /// An (optional) reference to a TableGen node representing a class | ||
| /// in one of Clang's AST hierarchies. | ||
| class ASTNode : public WrappedRecord { | ||
| public: | ||
| ASTNode(llvm::Record *record = nullptr) : WrappedRecord(record) {} | ||
|
|
||
| llvm::StringRef getName() const { | ||
| return get()->getName(); | ||
| } | ||
|
|
||
| /// Return the node for the base, if there is one. | ||
| ASTNode getBase() const { | ||
| return get()->getValueAsOptionalDef(BaseFieldName); | ||
| } | ||
|
|
||
| /// Is the corresponding class abstract? | ||
| bool isAbstract() const { | ||
| return get()->getValueAsBit(AbstractFieldName); | ||
| } | ||
|
|
||
| friend bool operator<(ASTNode lhs, ASTNode rhs) { | ||
| assert(lhs && rhs && "sorting null nodes"); | ||
| return lhs.getName() < rhs.getName(); | ||
| } | ||
| friend bool operator>(ASTNode lhs, ASTNode rhs) { return rhs < lhs; } | ||
| friend bool operator<=(ASTNode lhs, ASTNode rhs) { return !(rhs < lhs); } | ||
| friend bool operator>=(ASTNode lhs, ASTNode rhs) { return !(lhs < rhs); } | ||
|
|
||
| friend bool operator==(ASTNode lhs, ASTNode rhs) { | ||
| // This should handle null nodes. | ||
| return lhs.getRecord() == rhs.getRecord(); | ||
| } | ||
| friend bool operator!=(ASTNode lhs, ASTNode rhs) { return !(lhs == rhs); } | ||
| }; | ||
|
|
||
| class DeclNode : public ASTNode { | ||
| public: | ||
| DeclNode(llvm::Record *record = nullptr) : ASTNode(record) {} | ||
|
|
||
| llvm::StringRef getId() const; | ||
| std::string getClassName() const; | ||
| DeclNode getBase() const { return DeclNode(ASTNode::getBase().getRecord()); } | ||
|
|
||
| static llvm::StringRef getASTHierarchyName() { | ||
| return "Decl"; | ||
| } | ||
| static llvm::StringRef getASTIdTypeName() { | ||
| return "Decl::Kind"; | ||
| } | ||
| static llvm::StringRef getASTIdAccessorName() { | ||
| return "getKind"; | ||
| } | ||
| static llvm::StringRef getTableGenNodeClassName() { | ||
| return DeclNodeClassName; | ||
| } | ||
| }; | ||
|
|
||
| class TypeNode : public ASTNode { | ||
| public: | ||
| TypeNode(llvm::Record *record = nullptr) : ASTNode(record) {} | ||
|
|
||
| llvm::StringRef getId() const; | ||
| llvm::StringRef getClassName() const; | ||
| TypeNode getBase() const { return TypeNode(ASTNode::getBase().getRecord()); } | ||
|
|
||
| static llvm::StringRef getASTHierarchyName() { | ||
| return "Type"; | ||
| } | ||
| static llvm::StringRef getASTIdTypeName() { | ||
| return "Type::TypeClass"; | ||
| } | ||
| static llvm::StringRef getASTIdAccessorName() { | ||
| return "getTypeClass"; | ||
| } | ||
| static llvm::StringRef getTableGenNodeClassName() { | ||
| return TypeNodeClassName; | ||
| } | ||
| }; | ||
|
|
||
| class StmtNode : public ASTNode { | ||
| public: | ||
| StmtNode(llvm::Record *record = nullptr) : ASTNode(record) {} | ||
|
|
||
| std::string getId() const; | ||
| llvm::StringRef getClassName() const; | ||
| StmtNode getBase() const { return StmtNode(ASTNode::getBase().getRecord()); } | ||
|
|
||
| static llvm::StringRef getASTHierarchyName() { | ||
| return "Stmt"; | ||
| } | ||
| static llvm::StringRef getASTIdTypeName() { | ||
| return "Stmt::StmtClass"; | ||
| } | ||
| static llvm::StringRef getASTIdAccessorName() { | ||
| return "getStmtClass"; | ||
| } | ||
| static llvm::StringRef getTableGenNodeClassName() { | ||
| return StmtNodeClassName; | ||
| } | ||
| }; | ||
|
|
||
| /// 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> | ||
| using ASTNodeHierarchyVisitor = | ||
| llvm::function_ref<void(NodeClass node, NodeClass base)>; | ||
|
|
||
| void visitASTNodeHierarchyImpl(llvm::RecordKeeper &records, | ||
| llvm::StringRef nodeClassName, | ||
| ASTNodeHierarchyVisitor<ASTNode> visit); | ||
|
|
||
| template <class NodeClass> | ||
| void visitASTNodeHierarchy(llvm::RecordKeeper &records, | ||
| ASTNodeHierarchyVisitor<NodeClass> visit) { | ||
| visitASTNodeHierarchyImpl(records, NodeClass::getTableGenNodeClassName(), | ||
| [visit](ASTNode node, ASTNode base) { | ||
| visit(NodeClass(node.getRecord()), | ||
| NodeClass(base.getRecord())); | ||
| }); | ||
| } | ||
|
|
||
| } // end namespace clang::tblgen | ||
| } // end namespace clang | ||
|
|
||
| #endif |