//==--- 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 HasProperties; /// The type of the property. class PropertyType { /// 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 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. string UnpackOptional = ""; /// A list of types for which buffeers must be passed to the read /// operations. list BufferElementTypes = []; } /// Property types that correspond to specific C++ enums. class EnumPropertyType : PropertyType {} /// Property types that correspond to a specific C++ class. /// Supports optional values by using the null representation. class RefPropertyType : PropertyType { 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 : RefPropertyType { PropertyType Base = base; string SubclassName = className; let ConstWhenWriting = base.ConstWhenWriting; } /// Property types that support optional values by using their /// default value. class DefaultValuePropertyType : PropertyType { 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 : PropertyType { 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 ConceptDeclRef : SubclassPropertyType<"ConceptDecl", 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 : RefPropertyType<"IdentifierInfo"> { let ConstWhenWriting = 1; } 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 { PropertyType Element = element; let BufferElementTypes = [ element ]; } /// llvm::Optional. The corresponding C++ type is generally just the /// corresponding C++ type of the element. /// /// Optional may restrict the range of the operand for some /// serialization clients. class Optional : PropertyType { PropertyType Element = element; let PassByReference = element.PassByReference; } /// A property of an AST node. class Property { HasProperties Class; string Name = name; PropertyType Type = type; /// A function for reading the property, expressed in terms of a variable /// "node". code Read; /// Code specifying when this property is available. Can be defined /// in terms of other properties, in which case this property must be /// read/written after those properties. Using this will make the /// value Optional when deserializing. /// /// FIXME: the emitter doesn't yet force dependent properties to be /// read/written later; this only works if the properties used in the /// condition happen to be written first. code Conditional = ""; } /// A rule for declaring helper variables when read properties from a /// value of this type. Note that this means that this code is actually /// run when *writing* values of this type; however, naming this /// `ReadHelper` makes the connection to the `Read` operations on the /// properties much clearer. class ReadHelper { HasProperties Class; /// Code which will be run when writing objects of this type before /// writing any of the properties, specified in terms of a variable /// `node`. code Code = _code; } /// A rule for creating objects of this type. class Creator { HasProperties 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 { HasProperties Class; /// Properties from base classes that should be ignored. list IgnoredProperties = []; } /// A description of how to break a type into cases. Providing this and /// an exhaustive list of the cases will cause AbstractBasic{Reader,Writer} /// to be generated with a default implementation of how to read the /// type. /// /// Creator rules for the cases can additionally access a variable /// `kind` of the KindType. class PropertyTypeKind { /// The type for which this describes cases. PropertyType Type = type; /// The type of this type's kind enum. PropertyType KindType = kindType; /// The property name to use for the kind. string KindPropertyName = "kind"; /// An expression which reads the kind from a value, expressed in terms /// of a variable `node`. string Read = readCode; } /// One of the options for representing a particular type. class PropertyTypeCase : HasProperties { /// The type of which this is a case. PropertyType Type = type; /// The name of the case (a value of the type's kind enum). string Name = name; } // Type cases for DeclarationName. def : PropertyTypeKind; let Class = PropertyTypeCase in { def : Property<"identifier", Identifier> { let Read = [{ node.getAsIdentifierInfo() }]; } def : Creator<[{ return DeclarationName(identifier); }]>; } foreach count = ["Zero", "One", "Multi"] in { let Class = PropertyTypeCase in { def : Property<"selector", Selector> { let Read = [{ node.getObjCSelector() }]; } def : Creator<[{ return DeclarationName(selector); }]>; } } foreach kind = ["Constructor", "Destructor", "ConversionFunction"] in { let Class = PropertyTypeCase in { def : Property<"type", QualType> { let Read = [{ node.getCXXNameType() }]; } def : Creator<[{ return ctx.DeclarationNames.getCXX}]#kind#[{Name( ctx.getCanonicalType(type)); }]>; } } let Class = PropertyTypeCase in { def : Property<"declaration", TemplateDeclRef> { let Read = [{ node.getCXXDeductionGuideTemplate() }]; } def : Creator<[{ return ctx.DeclarationNames.getCXXDeductionGuideName(declaration); }]>; } let Class = PropertyTypeCase in { def : Property<"operatorKind", OverloadedOperatorKind> { let Read = [{ node.getCXXOverloadedOperator() }]; } def : Creator<[{ return ctx.DeclarationNames.getCXXOperatorName(operatorKind); }]>; } let Class = PropertyTypeCase in { def : Property<"identifier", Identifier> { let Read = [{ node.getCXXLiteralIdentifier() }]; } def : Creator<[{ return ctx.DeclarationNames.getCXXLiteralOperatorName(identifier); }]>; } let Class = PropertyTypeCase in { def : Creator<[{ return DeclarationName::getUsingDirectiveName(); }]>; } // Type cases for TemplateName. def : PropertyTypeKind; let Class = PropertyTypeCase in { def : Property<"declaration", TemplateDeclRef> { let Read = [{ node.getAsTemplateDecl() }]; } def : Creator<[{ return TemplateName(declaration); }]>; } let Class = PropertyTypeCase in { def : Property<"overloads", Array> { let Read = [{ node.getAsOverloadedTemplate()->decls() }]; } def : Creator<[{ // Copy into an UnresolvedSet to satisfy the interface. UnresolvedSet<8> overloadSet; for (auto overload : overloads) { overloadSet.addDecl(overload); } return ctx.getOverloadedTemplateName(overloadSet.begin(), overloadSet.end()); }]>; } let Class = PropertyTypeCase in { def : Property<"name", DeclarationName> { let Read = [{ node.getAsAssumedTemplateName()->getDeclName() }]; } def : Creator<[{ return ctx.getAssumedTemplateName(name); }]>; } let Class = PropertyTypeCase in { def : ReadHelper<[{ auto qtn = node.getAsQualifiedTemplateName(); }]>; def : Property<"qualifier", NestedNameSpecifier> { let Read = [{ qtn->getQualifier() }]; } def : Property<"hasTemplateKeyword", Bool> { let Read = [{ qtn->hasTemplateKeyword() }]; } def : Property<"declaration", TemplateDeclRef> { let Read = [{ qtn->getTemplateDecl() }]; } def : Creator<[{ return ctx.getQualifiedTemplateName(qualifier, hasTemplateKeyword, declaration); }]>; } let Class = PropertyTypeCase in { def : ReadHelper<[{ auto dtn = node.getAsDependentTemplateName(); }]>; def : Property<"qualifier", NestedNameSpecifier> { let Read = [{ dtn->getQualifier() }]; } def : Property<"identifier", Optional> { let Read = [{ makeOptionalFromPointer( dtn->isIdentifier() ? dtn->getIdentifier() : nullptr) }]; } def : Property<"operatorKind", OverloadedOperatorKind> { let Conditional = [{ !identifier }]; let Read = [{ dtn->getOperator() }]; } def : Creator<[{ if (identifier) { return ctx.getDependentTemplateName(qualifier, *identifier); } else { return ctx.getDependentTemplateName(qualifier, *operatorKind); } }]>; } let Class = PropertyTypeCase in { def : ReadHelper<[{ auto parm = node.getAsSubstTemplateTemplateParm(); }]>; def : Property<"parameter", TemplateTemplateParmDeclRef> { let Read = [{ parm->getParameter() }]; } def : Property<"replacement", TemplateName> { let Read = [{ parm->getReplacement() }]; } def : Creator<[{ return ctx.getSubstTemplateTemplateParm(parameter, replacement); }]>; } let Class = PropertyTypeCase in { def : ReadHelper<[{ auto parm = node.getAsSubstTemplateTemplateParmPack(); }]>; def : Property<"parameterPack", TemplateTemplateParmDeclRef> { let Read = [{ parm->getParameterPack() }]; } def : Property<"argumentPack", TemplateArgument> { let Read = [{ parm->getArgumentPack() }]; } def : Creator<[{ return ctx.getSubstTemplateTemplateParmPack(parameterPack, argumentPack); }]>; } // Type cases for TemplateArgument. def : PropertyTypeKind; let Class = PropertyTypeCase in { def : Creator<[{ return TemplateArgument(); }]>; } let Class = PropertyTypeCase in { def : Property<"type", QualType> { let Read = [{ node.getAsType() }]; } def : Creator<[{ return TemplateArgument(type); }]>; } let Class = PropertyTypeCase in { def : Property<"declaration", ValueDeclRef> { let Read = [{ node.getAsDecl() }]; } def : Property<"parameterType", QualType> { let Read = [{ node.getParamTypeForDecl() }]; } def : Creator<[{ return TemplateArgument(declaration, parameterType); }]>; } let Class = PropertyTypeCase in { def : Property<"type", QualType> { let Read = [{ node.getNullPtrType() }]; } def : Creator<[{ return TemplateArgument(type, /*nullptr*/ true); }]>; } let Class = PropertyTypeCase in { def : Property<"value", APSInt> { let Read = [{ node.getAsIntegral() }]; } def : Property<"type", QualType> { let Read = [{ node.getIntegralType() }]; } def : Creator<[{ return TemplateArgument(ctx, value, type); }]>; } let Class = PropertyTypeCase in { def : Property<"name", TemplateName> { let Read = [{ node.getAsTemplateOrTemplatePattern() }]; } def : Creator<[{ return TemplateArgument(name); }]>; } let Class = PropertyTypeCase in { def : Property<"name", TemplateName> { let Read = [{ node.getAsTemplateOrTemplatePattern() }]; } def : Property<"numExpansions", Optional> { let Read = [{ // Translate unsigned -> uint32_t just in case. node.getNumTemplateExpansions().map( [](unsigned i) { return uint32_t(i); }) }]; } def : Creator<[{ auto numExpansionsUnsigned = numExpansions.map([](uint32_t i) { return unsigned(i); }); return TemplateArgument(name, numExpansionsUnsigned); }]>; } let Class = PropertyTypeCase in { def : Property<"expression", ExprRef> { let Read = [{ node.getAsExpr() }]; } def : Creator<[{ return TemplateArgument(expression); }]>; } let Class = PropertyTypeCase in { def : Property<"elements", Array> { let Read = [{ node.pack_elements() }]; } def : Creator<[{ // Copy the pack into the ASTContext. TemplateArgument *ctxElements = new (ctx) TemplateArgument[elements.size()]; for (size_t i = 0, e = elements.size(); i != e; ++i) ctxElements[i] = elements[i]; return TemplateArgument(llvm::makeArrayRef(ctxElements, elements.size())); }]>; }