1 //==--- PropertiesBase.td - Baseline definitions for AST properties -------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
11 /// The type of the property.
12 class PropertyType<string typeName = ""> {
13 /// The C++ type name for the type.
14 string CXXName = !if(!ne(typeName, ""), typeName, NAME);
16 /// Whether the C++ type should generally be passed around by reference.
17 bit PassByReference = 0;
19 /// Whether `const` should be prepended to the type when writing.
20 bit ConstWhenWriting = 0;
22 /// Given a value of type Optional<CXXName> bound as 'value', yield a
23 /// CXXName that can be serialized into a DataStreamTypeWriter.
24 string PackOptional = "";
26 /// Given a value of type CXXName bound as 'value' that was deserialized
27 /// by a DataStreamTypeReader, yield an Optional<CXXName>.
28 string UnpackOptional = "";
30 /// A list of types for which buffeers must be passed to the read
32 list<PropertyType> BufferElementTypes = [];
35 /// Property types that correspond to specific C++ enums.
36 class EnumPropertyType<string typeName = ""> : PropertyType<typeName> {}
38 /// Property types that correspond to a specific C++ class.
39 /// Supports optional values by using the null representation.
40 class RefPropertyType<string className> : PropertyType<className # "*"> {
42 "value ? *value : nullptr";
44 "value ? llvm::Optional<" # CXXName # ">(value) : llvm::None";
47 /// Property types that correspond to a specific subclass of another type.
48 class SubclassPropertyType<string className, PropertyType base>
49 : RefPropertyType<className> {
50 PropertyType Base = base;
51 string SubclassName = className;
52 let ConstWhenWriting = base.ConstWhenWriting;
55 /// Property types that support optional values by using their
57 class DefaultValuePropertyType<string typeName = ""> : PropertyType<typeName> {
59 "value ? *value : " # CXXName # "()";
61 "value.isNull() ? llvm::None : llvm::Optional<" # CXXName # ">(value)";
64 /// Property types that correspond to integer types and support optional
65 /// values by shifting the value over by 1.
66 class CountPropertyType<string typeName = ""> : PropertyType<typeName> {
68 "value ? *value + 1 : 0";
70 "value ? llvm::Optional<" # CXXName # ">(value - 1) : llvm::None";
73 def APInt : PropertyType<"llvm::APInt"> { let PassByReference = 1; }
74 def APSInt : PropertyType<"llvm::APSInt"> { let PassByReference = 1; }
75 def ArraySizeModifier : EnumPropertyType<"ArrayType::ArraySizeModifier">;
76 def AttrKind : EnumPropertyType<"attr::Kind">;
77 def AutoTypeKeyword : EnumPropertyType;
78 def Bool : PropertyType<"bool">;
79 def BuiltinTypeKind : EnumPropertyType<"BuiltinType::Kind">;
80 def CallingConv : EnumPropertyType;
81 def DeclarationName : PropertyType;
82 def DeclarationNameKind : EnumPropertyType<"DeclarationName::NameKind">;
83 def DeclRef : RefPropertyType<"Decl"> { let ConstWhenWriting = 1; }
84 def CXXRecordDeclRef :
85 SubclassPropertyType<"CXXRecordDecl", DeclRef>;
87 SubclassPropertyType<"FunctionDecl", DeclRef>;
89 SubclassPropertyType<"NamedDecl", DeclRef>;
90 def NamespaceDeclRef :
91 SubclassPropertyType<"NamespaceDecl", DeclRef>;
92 def NamespaceAliasDeclRef :
93 SubclassPropertyType<"NamespaceAliasDecl", DeclRef>;
94 def ObjCProtocolDeclRef :
95 SubclassPropertyType<"ObjCProtocolDecl", DeclRef>;
96 def ObjCTypeParamDeclRef :
97 SubclassPropertyType<"ObjCTypeParamDecl", DeclRef>;
99 SubclassPropertyType<"TagDecl", DeclRef>;
100 def TemplateDeclRef :
101 SubclassPropertyType<"TemplateDecl", DeclRef>;
103 SubclassPropertyType<"ConceptDecl", DeclRef>;
104 def TemplateTypeParmDeclRef :
105 SubclassPropertyType<"TemplateTypeParmDecl", DeclRef>;
106 def TemplateTemplateParmDeclRef :
107 SubclassPropertyType<"TemplateTemplateParmDecl", DeclRef>;
109 SubclassPropertyType<"ValueDecl", DeclRef>;
110 def ElaboratedTypeKeyword : EnumPropertyType;
111 def ExtParameterInfo : PropertyType<"FunctionProtoType::ExtParameterInfo">;
112 def Identifier : RefPropertyType<"IdentifierInfo"> { let ConstWhenWriting = 1; }
113 def NestedNameSpecifier : PropertyType<"NestedNameSpecifier *">;
114 def NestedNameSpecifierKind :
115 EnumPropertyType<"NestedNameSpecifier::SpecifierKind">;
116 def OverloadedOperatorKind : EnumPropertyType;
117 def Qualifiers : PropertyType;
118 def QualType : DefaultValuePropertyType;
119 def RefQualifierKind : EnumPropertyType;
120 def Selector : PropertyType;
121 def SourceLocation : PropertyType;
122 def StmtRef : RefPropertyType<"Stmt"> { let ConstWhenWriting = 1; }
123 def ExprRef : SubclassPropertyType<"Expr", StmtRef>;
124 def TemplateArgument : PropertyType;
125 def TemplateArgumentKind : EnumPropertyType<"TemplateArgument::ArgKind">;
126 def TemplateName : DefaultValuePropertyType;
127 def TemplateNameKind : EnumPropertyType<"TemplateName::NameKind">;
128 def UInt32 : CountPropertyType<"uint32_t">;
129 def UInt64 : CountPropertyType<"uint64_t">;
130 def UnaryTypeTransformKind : EnumPropertyType<"UnaryTransformType::UTTKind">;
131 def VectorKind : EnumPropertyType<"VectorType::VectorKind">;
133 def ExceptionSpecInfo : PropertyType<"FunctionProtoType::ExceptionSpecInfo"> {
134 let BufferElementTypes = [ QualType ];
137 /// Arrays. The corresponding C++ type is ArrayRef of the corresponding
138 /// C++ type of the element.
139 class Array<PropertyType element> : PropertyType {
140 PropertyType Element = element;
141 let BufferElementTypes = [ element ];
144 /// llvm::Optional<T>. The corresponding C++ type is generally just the
145 /// corresponding C++ type of the element.
147 /// Optional<Unsigned> may restrict the range of the operand for some
148 /// serialization clients.
149 class Optional<PropertyType element> : PropertyType {
150 PropertyType Element = element;
151 let PassByReference = element.PassByReference;
154 /// A property of an AST node.
155 class Property<string name, PropertyType type> {
158 PropertyType Type = type;
160 /// A function for reading the property, expressed in terms of a variable
164 /// Code specifying when this property is available. Can be defined
165 /// in terms of other properties, in which case this property must be
166 /// read/written after those properties. Using this will make the
167 /// value Optional when deserializing.
169 /// FIXME: the emitter doesn't yet force dependent properties to be
170 /// read/written later; this only works if the properties used in the
171 /// condition happen to be written first.
172 code Conditional = "";
175 /// A rule for declaring helper variables when read properties from a
176 /// value of this type. Note that this means that this code is actually
177 /// run when *writing* values of this type; however, naming this
178 /// `ReadHelper` makes the connection to the `Read` operations on the
179 /// properties much clearer.
180 class ReadHelper<code _code> {
183 /// Code which will be run when writing objects of this type before
184 /// writing any of the properties, specified in terms of a variable
189 /// A rule for creating objects of this type.
190 class Creator<code create> {
193 /// A function for creating values of this kind, expressed in terms of a
194 /// variable `ctx` of type `ASTContext &`. Must also refer to all of the
195 /// properties by name.
196 code Create = create;
199 /// A rule which overrides some of the normal rules.
203 /// Properties from base classes that should be ignored.
204 list<string> IgnoredProperties = [];
207 /// A description of how to break a type into cases. Providing this and
208 /// an exhaustive list of the cases will cause AbstractBasic{Reader,Writer}
209 /// to be generated with a default implementation of how to read the
212 /// Creator rules for the cases can additionally access a variable
213 /// `kind` of the KindType.
214 class PropertyTypeKind<PropertyType type,
215 PropertyType kindType,
217 /// The type for which this describes cases.
218 PropertyType Type = type;
220 /// The type of this type's kind enum.
221 PropertyType KindType = kindType;
223 /// The property name to use for the kind.
224 string KindPropertyName = "kind";
226 /// An expression which reads the kind from a value, expressed in terms
227 /// of a variable `node`.
228 string Read = readCode;
231 /// One of the options for representing a particular type.
232 class PropertyTypeCase<PropertyType type, string name> : HasProperties {
233 /// The type of which this is a case.
234 PropertyType Type = type;
236 /// The name of the case (a value of the type's kind enum).
240 // Type cases for DeclarationName.
241 def : PropertyTypeKind<DeclarationName, DeclarationNameKind,
242 "node.getNameKind()">;
243 let Class = PropertyTypeCase<DeclarationName, "Identifier"> in {
244 def : Property<"identifier", Identifier> {
245 let Read = [{ node.getAsIdentifierInfo() }];
248 return DeclarationName(identifier);
251 foreach count = ["Zero", "One", "Multi"] in {
252 let Class = PropertyTypeCase<DeclarationName, "ObjC"#count#"ArgSelector"> in {
253 def : Property<"selector", Selector> {
254 let Read = [{ node.getObjCSelector() }];
257 return DeclarationName(selector);
261 foreach kind = ["Constructor", "Destructor", "ConversionFunction"] in {
262 let Class = PropertyTypeCase<DeclarationName, "CXX"#kind#"Name"> in {
263 def : Property<"type", QualType> {
264 let Read = [{ node.getCXXNameType() }];
267 return ctx.DeclarationNames.getCXX}]#kind#[{Name(
268 ctx.getCanonicalType(type));
272 let Class = PropertyTypeCase<DeclarationName, "CXXDeductionGuideName"> in {
273 def : Property<"declaration", TemplateDeclRef> {
274 let Read = [{ node.getCXXDeductionGuideTemplate() }];
277 return ctx.DeclarationNames.getCXXDeductionGuideName(declaration);
280 let Class = PropertyTypeCase<DeclarationName, "CXXOperatorName"> in {
281 def : Property<"operatorKind", OverloadedOperatorKind> {
282 let Read = [{ node.getCXXOverloadedOperator() }];
285 return ctx.DeclarationNames.getCXXOperatorName(operatorKind);
288 let Class = PropertyTypeCase<DeclarationName, "CXXLiteralOperatorName"> in {
289 def : Property<"identifier", Identifier> {
290 let Read = [{ node.getCXXLiteralIdentifier() }];
293 return ctx.DeclarationNames.getCXXLiteralOperatorName(identifier);
296 let Class = PropertyTypeCase<DeclarationName, "CXXUsingDirective"> in {
298 return DeclarationName::getUsingDirectiveName();
302 // Type cases for TemplateName.
303 def : PropertyTypeKind<TemplateName, TemplateNameKind, "node.getKind()">;
304 let Class = PropertyTypeCase<TemplateName, "Template"> in {
305 def : Property<"declaration", TemplateDeclRef> {
306 let Read = [{ node.getAsTemplateDecl() }];
309 return TemplateName(declaration);
312 let Class = PropertyTypeCase<TemplateName, "OverloadedTemplate"> in {
313 def : Property<"overloads", Array<NamedDeclRef>> {
314 let Read = [{ node.getAsOverloadedTemplate()->decls() }];
317 // Copy into an UnresolvedSet to satisfy the interface.
318 UnresolvedSet<8> overloadSet;
319 for (auto overload : overloads) {
320 overloadSet.addDecl(overload);
323 return ctx.getOverloadedTemplateName(overloadSet.begin(),
327 let Class = PropertyTypeCase<TemplateName, "AssumedTemplate"> in {
328 def : Property<"name", DeclarationName> {
329 let Read = [{ node.getAsAssumedTemplateName()->getDeclName() }];
332 return ctx.getAssumedTemplateName(name);
335 let Class = PropertyTypeCase<TemplateName, "QualifiedTemplate"> in {
337 auto qtn = node.getAsQualifiedTemplateName();
339 def : Property<"qualifier", NestedNameSpecifier> {
340 let Read = [{ qtn->getQualifier() }];
342 def : Property<"hasTemplateKeyword", Bool> {
343 let Read = [{ qtn->hasTemplateKeyword() }];
345 def : Property<"declaration", TemplateDeclRef> {
346 let Read = [{ qtn->getTemplateDecl() }];
349 return ctx.getQualifiedTemplateName(qualifier, hasTemplateKeyword,
353 let Class = PropertyTypeCase<TemplateName, "DependentTemplate"> in {
355 auto dtn = node.getAsDependentTemplateName();
357 def : Property<"qualifier", NestedNameSpecifier> {
358 let Read = [{ dtn->getQualifier() }];
360 def : Property<"identifier", Optional<Identifier>> {
361 let Read = [{ makeOptionalFromPointer(
363 ? dtn->getIdentifier()
366 def : Property<"operatorKind", OverloadedOperatorKind> {
367 let Conditional = [{ !identifier }];
368 let Read = [{ dtn->getOperator() }];
372 return ctx.getDependentTemplateName(qualifier, *identifier);
374 return ctx.getDependentTemplateName(qualifier, *operatorKind);
378 let Class = PropertyTypeCase<TemplateName, "SubstTemplateTemplateParm"> in {
380 auto parm = node.getAsSubstTemplateTemplateParm();
382 def : Property<"parameter", TemplateTemplateParmDeclRef> {
383 let Read = [{ parm->getParameter() }];
385 def : Property<"replacement", TemplateName> {
386 let Read = [{ parm->getReplacement() }];
389 return ctx.getSubstTemplateTemplateParm(parameter, replacement);
392 let Class = PropertyTypeCase<TemplateName, "SubstTemplateTemplateParmPack"> in {
394 auto parm = node.getAsSubstTemplateTemplateParmPack();
396 def : Property<"parameterPack", TemplateTemplateParmDeclRef> {
397 let Read = [{ parm->getParameterPack() }];
399 def : Property<"argumentPack", TemplateArgument> {
400 let Read = [{ parm->getArgumentPack() }];
403 return ctx.getSubstTemplateTemplateParmPack(parameterPack, argumentPack);
407 // Type cases for TemplateArgument.
408 def : PropertyTypeKind<TemplateArgument, TemplateArgumentKind,
410 let Class = PropertyTypeCase<TemplateArgument, "Null"> in {
412 return TemplateArgument();
415 let Class = PropertyTypeCase<TemplateArgument, "Type"> in {
416 def : Property<"type", QualType> {
417 let Read = [{ node.getAsType() }];
420 return TemplateArgument(type);
423 let Class = PropertyTypeCase<TemplateArgument, "Declaration"> in {
424 def : Property<"declaration", ValueDeclRef> {
425 let Read = [{ node.getAsDecl() }];
427 def : Property<"parameterType", QualType> {
428 let Read = [{ node.getParamTypeForDecl() }];
431 return TemplateArgument(declaration, parameterType);
434 let Class = PropertyTypeCase<TemplateArgument, "NullPtr"> in {
435 def : Property<"type", QualType> {
436 let Read = [{ node.getNullPtrType() }];
439 return TemplateArgument(type, /*nullptr*/ true);
442 let Class = PropertyTypeCase<TemplateArgument, "Integral"> in {
443 def : Property<"value", APSInt> {
444 let Read = [{ node.getAsIntegral() }];
446 def : Property<"type", QualType> {
447 let Read = [{ node.getIntegralType() }];
450 return TemplateArgument(ctx, value, type);
453 let Class = PropertyTypeCase<TemplateArgument, "Template"> in {
454 def : Property<"name", TemplateName> {
455 let Read = [{ node.getAsTemplateOrTemplatePattern() }];
458 return TemplateArgument(name);
461 let Class = PropertyTypeCase<TemplateArgument, "TemplateExpansion"> in {
462 def : Property<"name", TemplateName> {
463 let Read = [{ node.getAsTemplateOrTemplatePattern() }];
465 def : Property<"numExpansions", Optional<UInt32>> {
467 // Translate unsigned -> uint32_t just in case.
468 node.getNumTemplateExpansions().map(
469 [](unsigned i) { return uint32_t(i); })
473 auto numExpansionsUnsigned =
474 numExpansions.map([](uint32_t i) { return unsigned(i); });
475 return TemplateArgument(name, numExpansionsUnsigned);
478 let Class = PropertyTypeCase<TemplateArgument, "Expression"> in {
479 def : Property<"expression", ExprRef> {
480 let Read = [{ node.getAsExpr() }];
483 return TemplateArgument(expression);
486 let Class = PropertyTypeCase<TemplateArgument, "Pack"> in {
487 def : Property<"elements", Array<TemplateArgument>> {
488 let Read = [{ node.pack_elements() }];
491 // Copy the pack into the ASTContext.
492 TemplateArgument *ctxElements = new (ctx) TemplateArgument[elements.size()];
493 for (size_t i = 0, e = elements.size(); i != e; ++i)
494 ctxElements[i] = elements[i];
495 return TemplateArgument(llvm::makeArrayRef(ctxElements, elements.size()));