1//==--- PropertiesBase.td - Baseline definitions for AST properties -------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9class HasProperties;
10
11/// The type of the property.
12class PropertyType<string typeName = ""> {
13  /// The C++ type name for the type.
14  string CXXName = !if(!ne(typeName, ""), typeName, NAME);
15
16  /// Whether the C++ type should generally be passed around by reference.
17  bit PassByReference = 0;
18
19  /// Whether `const` should be prepended to the type when writing.
20  bit ConstWhenWriting = 0;
21
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 = "";
25
26  /// Given a value of type CXXName bound as 'value' that was deserialized
27  /// by a DataStreamTypeReader, yield an Optional<CXXName>.
28  string UnpackOptional = "";
29
30  /// A list of types for which buffeers must be passed to the read
31  /// operations.
32  list<PropertyType> BufferElementTypes = [];
33}
34
35/// Property types that correspond to specific C++ enums.
36class EnumPropertyType<string typeName = ""> : PropertyType<typeName> {}
37
38/// Property types that correspond to a specific C++ class.
39/// Supports optional values by using the null representation.
40class RefPropertyType<string className> : PropertyType<className # "*"> {
41  let PackOptional =
42    "value ? *value : nullptr";
43  let UnpackOptional =
44    "value ? llvm::Optional<" # CXXName # ">(value) : llvm::None";
45}
46
47/// Property types that correspond to a specific subclass of another type.
48class SubclassPropertyType<string className, PropertyType base>
49    : RefPropertyType<className> {
50  PropertyType Base = base;
51  string SubclassName = className;
52  let ConstWhenWriting = base.ConstWhenWriting;
53}
54
55/// Property types that support optional values by using their
56/// default value.
57class DefaultValuePropertyType<string typeName = ""> : PropertyType<typeName> {
58  let PackOptional =
59    "value ? *value : " # CXXName # "()";
60  let UnpackOptional =
61    "value.isNull() ? llvm::None : llvm::Optional<" # CXXName # ">(value)";
62}
63
64/// Property types that correspond to integer types and support optional
65/// values by shifting the value over by 1.
66class CountPropertyType<string typeName = ""> : PropertyType<typeName> {
67  let PackOptional =
68    "value ? *value + 1 : 0";
69  let UnpackOptional =
70    "value ? llvm::Optional<" # CXXName # ">(value - 1) : llvm::None";
71}
72
73def APInt : PropertyType<"llvm::APInt"> { let PassByReference = 1; }
74def APSInt : PropertyType<"llvm::APSInt"> { let PassByReference = 1; }
75def ArraySizeModifier : EnumPropertyType<"ArrayType::ArraySizeModifier">;
76def AttrKind : EnumPropertyType<"attr::Kind">;
77def AutoTypeKeyword : EnumPropertyType;
78def Bool : PropertyType<"bool">;
79def BuiltinTypeKind : EnumPropertyType<"BuiltinType::Kind">;
80def CallingConv : EnumPropertyType;
81def DeclarationName : PropertyType;
82def DeclarationNameKind : EnumPropertyType<"DeclarationName::NameKind">;
83def DeclRef : RefPropertyType<"Decl"> { let ConstWhenWriting = 1; }
84  def CXXRecordDeclRef :
85    SubclassPropertyType<"CXXRecordDecl", DeclRef>;
86  def FunctionDeclRef :
87    SubclassPropertyType<"FunctionDecl", DeclRef>;
88  def NamedDeclRef :
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>;
98  def TagDeclRef :
99    SubclassPropertyType<"TagDecl", DeclRef>;
100  def TemplateDeclRef :
101    SubclassPropertyType<"TemplateDecl", DeclRef>;
102  def ConceptDeclRef :
103    SubclassPropertyType<"ConceptDecl", DeclRef>;
104  def TemplateTypeParmDeclRef :
105    SubclassPropertyType<"TemplateTypeParmDecl", DeclRef>;
106  def TemplateTemplateParmDeclRef :
107    SubclassPropertyType<"TemplateTemplateParmDecl", DeclRef>;
108  def ValueDeclRef :
109    SubclassPropertyType<"ValueDecl", DeclRef>;
110def ElaboratedTypeKeyword : EnumPropertyType;
111def ExtParameterInfo : PropertyType<"FunctionProtoType::ExtParameterInfo">;
112def Identifier : RefPropertyType<"IdentifierInfo"> { let ConstWhenWriting = 1; }
113def NestedNameSpecifier : PropertyType<"NestedNameSpecifier *">;
114def NestedNameSpecifierKind :
115  EnumPropertyType<"NestedNameSpecifier::SpecifierKind">;
116def OverloadedOperatorKind : EnumPropertyType;
117def Qualifiers : PropertyType;
118def QualType : DefaultValuePropertyType;
119def RefQualifierKind : EnumPropertyType;
120def Selector : PropertyType;
121def SourceLocation : PropertyType;
122def StmtRef : RefPropertyType<"Stmt"> { let ConstWhenWriting = 1; }
123  def ExprRef : SubclassPropertyType<"Expr", StmtRef>;
124def TemplateArgument : PropertyType;
125def TemplateArgumentKind : EnumPropertyType<"TemplateArgument::ArgKind">;
126def TemplateName : DefaultValuePropertyType;
127def TemplateNameKind : EnumPropertyType<"TemplateName::NameKind">;
128def UInt32 : CountPropertyType<"uint32_t">;
129def UInt64 : CountPropertyType<"uint64_t">;
130def UnaryTypeTransformKind : EnumPropertyType<"UnaryTransformType::UTTKind">;
131def VectorKind : EnumPropertyType<"VectorType::VectorKind">;
132
133def ExceptionSpecInfo : PropertyType<"FunctionProtoType::ExceptionSpecInfo"> {
134  let BufferElementTypes = [ QualType ];
135}
136
137/// Arrays.  The corresponding C++ type is ArrayRef of the corresponding
138/// C++ type of the element.
139class Array<PropertyType element> : PropertyType {
140  PropertyType Element = element;
141  let BufferElementTypes = [ element ];
142}
143
144/// llvm::Optional<T>.  The corresponding C++ type is generally just the
145/// corresponding C++ type of the element.
146///
147/// Optional<Unsigned> may restrict the range of the operand for some
148/// serialization clients.
149class Optional<PropertyType element> : PropertyType {
150  PropertyType Element = element;
151  let PassByReference = element.PassByReference;
152}
153
154/// A property of an AST node.
155class Property<string name, PropertyType type> {
156  HasProperties Class;
157  string Name = name;
158  PropertyType Type = type;
159
160  /// A function for reading the property, expressed in terms of a variable
161  /// "node".
162  code Read;
163
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.
168  ///
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 = "";
173}
174
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.
180class ReadHelper<code _code> {
181  HasProperties Class;
182
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
185  /// `node`.
186  code Code = _code;
187}
188
189/// A rule for creating objects of this type.
190class Creator<code create> {
191  HasProperties Class;
192
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;
197}
198
199/// A rule which overrides some of the normal rules.
200class Override {
201  HasProperties Class;
202
203  /// Properties from base classes that should be ignored.
204  list<string> IgnoredProperties = [];
205}
206
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
210/// type.
211///
212/// Creator rules for the cases can additionally access a variable
213/// `kind` of the KindType.
214class PropertyTypeKind<PropertyType type,
215                       PropertyType kindType,
216                       string readCode> {
217  /// The type for which this describes cases.
218  PropertyType Type = type;
219
220  /// The type of this type's kind enum.
221  PropertyType KindType = kindType;
222
223  /// The property name to use for the kind.
224  string KindPropertyName = "kind";
225
226  /// An expression which reads the kind from a value, expressed in terms
227  /// of a variable `node`.
228  string Read = readCode;
229}
230
231/// One of the options for representing a particular type.
232class PropertyTypeCase<PropertyType type, string name> : HasProperties {
233  /// The type of which this is a case.
234  PropertyType Type = type;
235
236  /// The name of the case (a value of the type's kind enum).
237  string Name = name;
238}
239
240// Type cases for DeclarationName.
241def : PropertyTypeKind<DeclarationName, DeclarationNameKind,
242                       "node.getNameKind()">;
243let Class = PropertyTypeCase<DeclarationName, "Identifier"> in {
244  def : Property<"identifier", Identifier> {
245    let Read = [{ node.getAsIdentifierInfo() }];
246  }
247  def : Creator<[{
248    return DeclarationName(identifier);
249  }]>;
250}
251foreach count = ["Zero", "One", "Multi"] in {
252  let Class = PropertyTypeCase<DeclarationName, "ObjC"#count#"ArgSelector"> in {
253    def : Property<"selector", Selector> {
254      let Read = [{ node.getObjCSelector() }];
255    }
256    def : Creator<[{
257      return DeclarationName(selector);
258    }]>;
259  }
260}
261foreach kind = ["Constructor", "Destructor", "ConversionFunction"] in {
262  let Class = PropertyTypeCase<DeclarationName, "CXX"#kind#"Name"> in {
263    def : Property<"type", QualType> {
264      let Read = [{ node.getCXXNameType() }];
265    }
266    def : Creator<[{
267      return ctx.DeclarationNames.getCXX}]#kind#[{Name(
268               ctx.getCanonicalType(type));
269    }]>;
270  }
271}
272let Class = PropertyTypeCase<DeclarationName, "CXXDeductionGuideName"> in {
273  def : Property<"declaration", TemplateDeclRef> {
274    let Read = [{ node.getCXXDeductionGuideTemplate() }];
275  }
276  def : Creator<[{
277    return ctx.DeclarationNames.getCXXDeductionGuideName(declaration);
278  }]>;
279}
280let Class = PropertyTypeCase<DeclarationName, "CXXOperatorName"> in {
281  def : Property<"operatorKind", OverloadedOperatorKind> {
282    let Read = [{ node.getCXXOverloadedOperator() }];
283  }
284  def : Creator<[{
285    return ctx.DeclarationNames.getCXXOperatorName(operatorKind);
286  }]>;
287}
288let Class = PropertyTypeCase<DeclarationName, "CXXLiteralOperatorName"> in {
289  def : Property<"identifier", Identifier> {
290    let Read = [{ node.getCXXLiteralIdentifier() }];
291  }
292  def : Creator<[{
293    return ctx.DeclarationNames.getCXXLiteralOperatorName(identifier);
294  }]>;
295}
296let Class = PropertyTypeCase<DeclarationName, "CXXUsingDirective"> in {
297  def : Creator<[{
298    return DeclarationName::getUsingDirectiveName();
299  }]>;
300}
301
302// Type cases for TemplateName.
303def : PropertyTypeKind<TemplateName, TemplateNameKind, "node.getKind()">;
304let Class = PropertyTypeCase<TemplateName, "Template"> in {
305  def : Property<"declaration", TemplateDeclRef> {
306    let Read = [{ node.getAsTemplateDecl() }];
307  }
308  def : Creator<[{
309    return TemplateName(declaration);
310  }]>;
311}
312let Class = PropertyTypeCase<TemplateName, "OverloadedTemplate"> in {
313  def : Property<"overloads", Array<NamedDeclRef>> {
314    let Read = [{ node.getAsOverloadedTemplate()->decls() }];
315  }
316  def : Creator<[{
317    // Copy into an UnresolvedSet to satisfy the interface.
318    UnresolvedSet<8> overloadSet;
319    for (auto overload : overloads) {
320      overloadSet.addDecl(overload);
321    }
322
323    return ctx.getOverloadedTemplateName(overloadSet.begin(),
324                                         overloadSet.end());
325  }]>;
326}
327let Class = PropertyTypeCase<TemplateName, "AssumedTemplate"> in {
328  def : Property<"name", DeclarationName> {
329    let Read = [{ node.getAsAssumedTemplateName()->getDeclName() }];
330  }
331  def : Creator<[{
332    return ctx.getAssumedTemplateName(name);
333  }]>;
334}
335let Class = PropertyTypeCase<TemplateName, "QualifiedTemplate"> in {
336  def : ReadHelper<[{
337    auto qtn = node.getAsQualifiedTemplateName();
338  }]>;
339  def : Property<"qualifier", NestedNameSpecifier> {
340    let Read = [{ qtn->getQualifier() }];
341  }
342  def : Property<"hasTemplateKeyword", Bool> {
343    let Read = [{ qtn->hasTemplateKeyword() }];
344  }
345  def : Property<"declaration", TemplateDeclRef> {
346    let Read = [{ qtn->getTemplateDecl() }];
347  }
348  def : Creator<[{
349    return ctx.getQualifiedTemplateName(qualifier, hasTemplateKeyword,
350                                        declaration);
351  }]>;
352}
353let Class = PropertyTypeCase<TemplateName, "DependentTemplate"> in {
354  def : ReadHelper<[{
355    auto dtn = node.getAsDependentTemplateName();
356  }]>;
357  def : Property<"qualifier", NestedNameSpecifier> {
358    let Read = [{ dtn->getQualifier() }];
359  }
360  def : Property<"identifier", Optional<Identifier>> {
361    let Read = [{ makeOptionalFromPointer(
362                    dtn->isIdentifier()
363                      ? dtn->getIdentifier()
364                      : nullptr) }];
365  }
366  def : Property<"operatorKind", OverloadedOperatorKind> {
367    let Conditional = [{ !identifier }];
368    let Read = [{ dtn->getOperator() }];
369  }
370  def : Creator<[{
371    if (identifier) {
372      return ctx.getDependentTemplateName(qualifier, *identifier);
373    } else {
374      return ctx.getDependentTemplateName(qualifier, *operatorKind);
375    }
376  }]>;
377}
378let Class = PropertyTypeCase<TemplateName, "SubstTemplateTemplateParm"> in {
379  def : ReadHelper<[{
380    auto parm = node.getAsSubstTemplateTemplateParm();
381  }]>;
382  def : Property<"parameter", TemplateTemplateParmDeclRef> {
383    let Read = [{ parm->getParameter() }];
384  }
385  def : Property<"replacement", TemplateName> {
386    let Read = [{ parm->getReplacement() }];
387  }
388  def : Creator<[{
389    return ctx.getSubstTemplateTemplateParm(parameter, replacement);
390  }]>;
391}
392let Class = PropertyTypeCase<TemplateName, "SubstTemplateTemplateParmPack"> in {
393  def : ReadHelper<[{
394    auto parm = node.getAsSubstTemplateTemplateParmPack();
395  }]>;
396  def : Property<"parameterPack", TemplateTemplateParmDeclRef> {
397    let Read = [{ parm->getParameterPack() }];
398  }
399  def : Property<"argumentPack", TemplateArgument> {
400    let Read = [{ parm->getArgumentPack() }];
401  }
402  def : Creator<[{
403    return ctx.getSubstTemplateTemplateParmPack(parameterPack, argumentPack);
404  }]>;
405}
406
407// Type cases for TemplateArgument.
408def : PropertyTypeKind<TemplateArgument, TemplateArgumentKind,
409                       "node.getKind()">;
410let Class = PropertyTypeCase<TemplateArgument, "Null"> in {
411  def : Creator<[{
412    return TemplateArgument();
413  }]>;
414}
415let Class = PropertyTypeCase<TemplateArgument, "Type"> in {
416  def : Property<"type", QualType> {
417    let Read = [{ node.getAsType() }];
418  }
419  def : Creator<[{
420    return TemplateArgument(type);
421  }]>;
422}
423let Class = PropertyTypeCase<TemplateArgument, "Declaration"> in {
424  def : Property<"declaration", ValueDeclRef> {
425    let Read = [{ node.getAsDecl() }];
426  }
427  def : Property<"parameterType", QualType> {
428    let Read = [{ node.getParamTypeForDecl() }];
429  }
430  def : Creator<[{
431    return TemplateArgument(declaration, parameterType);
432  }]>;
433}
434let Class = PropertyTypeCase<TemplateArgument, "NullPtr"> in {
435  def : Property<"type", QualType> {
436    let Read = [{ node.getNullPtrType() }];
437  }
438  def : Creator<[{
439    return TemplateArgument(type, /*nullptr*/ true);
440  }]>;
441}
442let Class = PropertyTypeCase<TemplateArgument, "Integral"> in {
443  def : Property<"value", APSInt> {
444    let Read = [{ node.getAsIntegral() }];
445  }
446  def : Property<"type", QualType> {
447    let Read = [{ node.getIntegralType() }];
448  }
449  def : Creator<[{
450    return TemplateArgument(ctx, value, type);
451  }]>;
452}
453let Class = PropertyTypeCase<TemplateArgument, "Template"> in {
454  def : Property<"name", TemplateName> {
455    let Read = [{ node.getAsTemplateOrTemplatePattern() }];
456  }
457  def : Creator<[{
458    return TemplateArgument(name);
459  }]>;
460}
461let Class = PropertyTypeCase<TemplateArgument, "TemplateExpansion"> in {
462  def : Property<"name", TemplateName> {
463    let Read = [{ node.getAsTemplateOrTemplatePattern() }];
464  }
465  def : Property<"numExpansions", Optional<UInt32>> {
466    let Read = [{
467      // Translate unsigned -> uint32_t just in case.
468      node.getNumTemplateExpansions().map(
469        [](unsigned i) { return uint32_t(i); })
470    }];
471  }
472  def : Creator<[{
473    auto numExpansionsUnsigned =
474      numExpansions.map([](uint32_t i) { return unsigned(i); });
475    return TemplateArgument(name, numExpansionsUnsigned);
476  }]>;
477}
478let Class = PropertyTypeCase<TemplateArgument, "Expression"> in {
479  def : Property<"expression", ExprRef> {
480    let Read = [{ node.getAsExpr() }];
481  }
482  def : Creator<[{
483    return TemplateArgument(expression);
484  }]>;
485}
486let Class = PropertyTypeCase<TemplateArgument, "Pack"> in {
487  def : Property<"elements", Array<TemplateArgument>> {
488    let Read = [{ node.pack_elements() }];
489  }
490  def : Creator<[{
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()));
496  }]>;
497}
498