1 //===-- Types.h - API Notes Data Types --------------------------*- C++ -*-===//
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 
9 #ifndef LLVM_CLANG_APINOTES_TYPES_H
10 #define LLVM_CLANG_APINOTES_TYPES_H
11 
12 #include "clang/Basic/Specifiers.h"
13 #include "llvm/ADT/StringRef.h"
14 #include <climits>
15 #include <optional>
16 #include <vector>
17 
18 namespace llvm {
19 class raw_ostream;
20 } // namespace llvm
21 
22 namespace clang {
23 namespace api_notes {
24 enum class RetainCountConventionKind {
25   None,
26   CFReturnsRetained,
27   CFReturnsNotRetained,
28   NSReturnsRetained,
29   NSReturnsNotRetained,
30 };
31 
32 /// The payload for an enum_extensibility attribute. This is a tri-state rather
33 /// than just a boolean because the presence of the attribute indicates
34 /// auditing.
35 enum class EnumExtensibilityKind {
36   None,
37   Open,
38   Closed,
39 };
40 
41 /// The kind of a swift_wrapper/swift_newtype.
42 enum class SwiftNewTypeKind {
43   None,
44   Struct,
45   Enum,
46 };
47 
48 /// Describes API notes data for any entity.
49 ///
50 /// This is used as the base of all API notes.
51 class CommonEntityInfo {
52 public:
53   /// Message to use when this entity is unavailable.
54   std::string UnavailableMsg;
55 
56   /// Whether this entity is marked unavailable.
57   unsigned Unavailable : 1;
58 
59   /// Whether this entity is marked unavailable in Swift.
60   unsigned UnavailableInSwift : 1;
61 
62 private:
63   /// Whether SwiftPrivate was specified.
64   unsigned SwiftPrivateSpecified : 1;
65 
66   /// Whether this entity is considered "private" to a Swift overlay.
67   unsigned SwiftPrivate : 1;
68 
69 public:
70   /// Swift name of this entity.
71   std::string SwiftName;
72 
73   CommonEntityInfo()
74       : Unavailable(0), UnavailableInSwift(0), SwiftPrivateSpecified(0),
75         SwiftPrivate(0) {}
76 
77   std::optional<bool> isSwiftPrivate() const {
78     return SwiftPrivateSpecified ? std::optional<bool>(SwiftPrivate)
79                                  : std::nullopt;
80   }
81 
82   void setSwiftPrivate(std::optional<bool> Private) {
83     SwiftPrivateSpecified = Private.has_value();
84     SwiftPrivate = Private.value_or(0);
85   }
86 
87   friend bool operator==(const CommonEntityInfo &, const CommonEntityInfo &);
88 
89   CommonEntityInfo &operator|=(const CommonEntityInfo &RHS) {
90     // Merge unavailability.
91     if (RHS.Unavailable) {
92       Unavailable = true;
93       if (UnavailableMsg.empty())
94         UnavailableMsg = RHS.UnavailableMsg;
95     }
96 
97     if (RHS.UnavailableInSwift) {
98       UnavailableInSwift = true;
99       if (UnavailableMsg.empty())
100         UnavailableMsg = RHS.UnavailableMsg;
101     }
102 
103     if (!SwiftPrivateSpecified)
104       setSwiftPrivate(RHS.isSwiftPrivate());
105 
106     if (SwiftName.empty())
107       SwiftName = RHS.SwiftName;
108 
109     return *this;
110   }
111 
112   LLVM_DUMP_METHOD void dump(llvm::raw_ostream &OS) const;
113 };
114 
115 inline bool operator==(const CommonEntityInfo &LHS,
116                        const CommonEntityInfo &RHS) {
117   return LHS.UnavailableMsg == RHS.UnavailableMsg &&
118          LHS.Unavailable == RHS.Unavailable &&
119          LHS.UnavailableInSwift == RHS.UnavailableInSwift &&
120          LHS.SwiftPrivateSpecified == RHS.SwiftPrivateSpecified &&
121          LHS.SwiftPrivate == RHS.SwiftPrivate && LHS.SwiftName == RHS.SwiftName;
122 }
123 
124 inline bool operator!=(const CommonEntityInfo &LHS,
125                        const CommonEntityInfo &RHS) {
126   return !(LHS == RHS);
127 }
128 
129 /// Describes API notes for types.
130 class CommonTypeInfo : public CommonEntityInfo {
131   /// The Swift type to which a given type is bridged.
132   ///
133   /// Reflects the swift_bridge attribute.
134   std::optional<std::string> SwiftBridge;
135 
136   /// The NS error domain for this type.
137   std::optional<std::string> NSErrorDomain;
138 
139 public:
140   CommonTypeInfo() {}
141 
142   const std::optional<std::string> &getSwiftBridge() const {
143     return SwiftBridge;
144   }
145 
146   void setSwiftBridge(const std::optional<std::string> &SwiftType) {
147     SwiftBridge = SwiftType;
148   }
149 
150   void setSwiftBridge(const std::optional<llvm::StringRef> &SwiftType) {
151     SwiftBridge = SwiftType
152                       ? std::optional<std::string>(std::string(*SwiftType))
153                       : std::nullopt;
154   }
155 
156   const std::optional<std::string> &getNSErrorDomain() const {
157     return NSErrorDomain;
158   }
159 
160   void setNSErrorDomain(const std::optional<std::string> &Domain) {
161     NSErrorDomain = Domain;
162   }
163 
164   void setNSErrorDomain(const std::optional<llvm::StringRef> &Domain) {
165     NSErrorDomain = Domain ? std::optional<std::string>(std::string(*Domain))
166                            : std::nullopt;
167   }
168 
169   friend bool operator==(const CommonTypeInfo &, const CommonTypeInfo &);
170 
171   CommonTypeInfo &operator|=(const CommonTypeInfo &RHS) {
172     // Merge inherited info.
173     static_cast<CommonEntityInfo &>(*this) |= RHS;
174 
175     if (!SwiftBridge)
176       setSwiftBridge(RHS.getSwiftBridge());
177     if (!NSErrorDomain)
178       setNSErrorDomain(RHS.getNSErrorDomain());
179 
180     return *this;
181   }
182 
183   LLVM_DUMP_METHOD void dump(llvm::raw_ostream &OS) const;
184 };
185 
186 inline bool operator==(const CommonTypeInfo &LHS, const CommonTypeInfo &RHS) {
187   return static_cast<const CommonEntityInfo &>(LHS) == RHS &&
188          LHS.SwiftBridge == RHS.SwiftBridge &&
189          LHS.NSErrorDomain == RHS.NSErrorDomain;
190 }
191 
192 inline bool operator!=(const CommonTypeInfo &LHS, const CommonTypeInfo &RHS) {
193   return !(LHS == RHS);
194 }
195 
196 /// Describes API notes data for an Objective-C class or protocol.
197 class ObjCContextInfo : public CommonTypeInfo {
198   /// Whether this class has a default nullability.
199   unsigned HasDefaultNullability : 1;
200 
201   /// The default nullability.
202   unsigned DefaultNullability : 2;
203 
204   /// Whether this class has designated initializers recorded.
205   unsigned HasDesignatedInits : 1;
206 
207   unsigned SwiftImportAsNonGenericSpecified : 1;
208   unsigned SwiftImportAsNonGeneric : 1;
209 
210   unsigned SwiftObjCMembersSpecified : 1;
211   unsigned SwiftObjCMembers : 1;
212 
213 public:
214   ObjCContextInfo()
215       : HasDefaultNullability(0), DefaultNullability(0), HasDesignatedInits(0),
216         SwiftImportAsNonGenericSpecified(false), SwiftImportAsNonGeneric(false),
217         SwiftObjCMembersSpecified(false), SwiftObjCMembers(false) {}
218 
219   /// Determine the default nullability for properties and methods of this
220   /// class.
221   ///
222   /// Returns the default nullability, if implied, or std::nullopt if there is
223   /// none.
224   std::optional<NullabilityKind> getDefaultNullability() const {
225     return HasDefaultNullability
226                ? std::optional<NullabilityKind>(
227                      static_cast<NullabilityKind>(DefaultNullability))
228                : std::nullopt;
229   }
230 
231   /// Set the default nullability for properties and methods of this class.
232   void setDefaultNullability(NullabilityKind Kind) {
233     HasDefaultNullability = true;
234     DefaultNullability = static_cast<unsigned>(Kind);
235   }
236 
237   bool hasDesignatedInits() const { return HasDesignatedInits; }
238   void setHasDesignatedInits(bool Value) { HasDesignatedInits = Value; }
239 
240   std::optional<bool> getSwiftImportAsNonGeneric() const {
241     return SwiftImportAsNonGenericSpecified
242                ? std::optional<bool>(SwiftImportAsNonGeneric)
243                : std::nullopt;
244   }
245   void setSwiftImportAsNonGeneric(std::optional<bool> Value) {
246     SwiftImportAsNonGenericSpecified = Value.has_value();
247     SwiftImportAsNonGeneric = Value.value_or(false);
248   }
249 
250   std::optional<bool> getSwiftObjCMembers() const {
251     return SwiftObjCMembersSpecified ? std::optional<bool>(SwiftObjCMembers)
252                                      : std::nullopt;
253   }
254   void setSwiftObjCMembers(std::optional<bool> Value) {
255     SwiftObjCMembersSpecified = Value.has_value();
256     SwiftObjCMembers = Value.value_or(false);
257   }
258 
259   /// Strip off any information within the class information structure that is
260   /// module-local, such as 'audited' flags.
261   void stripModuleLocalInfo() {
262     HasDefaultNullability = false;
263     DefaultNullability = 0;
264   }
265 
266   friend bool operator==(const ObjCContextInfo &, const ObjCContextInfo &);
267 
268   ObjCContextInfo &operator|=(const ObjCContextInfo &RHS) {
269     // Merge inherited info.
270     static_cast<CommonTypeInfo &>(*this) |= RHS;
271 
272     // Merge nullability.
273     if (!getDefaultNullability())
274       if (auto Nullability = RHS.getDefaultNullability())
275         setDefaultNullability(*Nullability);
276 
277     if (!SwiftImportAsNonGenericSpecified)
278       setSwiftImportAsNonGeneric(RHS.getSwiftImportAsNonGeneric());
279 
280     if (!SwiftObjCMembersSpecified)
281       setSwiftObjCMembers(RHS.getSwiftObjCMembers());
282 
283     HasDesignatedInits |= RHS.HasDesignatedInits;
284 
285     return *this;
286   }
287 
288   LLVM_DUMP_METHOD void dump(llvm::raw_ostream &OS);
289 };
290 
291 inline bool operator==(const ObjCContextInfo &LHS, const ObjCContextInfo &RHS) {
292   return static_cast<const CommonTypeInfo &>(LHS) == RHS &&
293          LHS.getDefaultNullability() == RHS.getDefaultNullability() &&
294          LHS.HasDesignatedInits == RHS.HasDesignatedInits &&
295          LHS.getSwiftImportAsNonGeneric() == RHS.getSwiftImportAsNonGeneric() &&
296          LHS.getSwiftObjCMembers() == RHS.getSwiftObjCMembers();
297 }
298 
299 inline bool operator!=(const ObjCContextInfo &LHS, const ObjCContextInfo &RHS) {
300   return !(LHS == RHS);
301 }
302 
303 /// API notes for a variable/property.
304 class VariableInfo : public CommonEntityInfo {
305   /// Whether this property has been audited for nullability.
306   unsigned NullabilityAudited : 1;
307 
308   /// The kind of nullability for this property. Only valid if the nullability
309   /// has been audited.
310   unsigned Nullable : 2;
311 
312   /// The C type of the variable, as a string.
313   std::string Type;
314 
315 public:
316   VariableInfo() : NullabilityAudited(false), Nullable(0) {}
317 
318   std::optional<NullabilityKind> getNullability() const {
319     return NullabilityAudited ? std::optional<NullabilityKind>(
320                                     static_cast<NullabilityKind>(Nullable))
321                               : std::nullopt;
322   }
323 
324   void setNullabilityAudited(NullabilityKind kind) {
325     NullabilityAudited = true;
326     Nullable = static_cast<unsigned>(kind);
327   }
328 
329   const std::string &getType() const { return Type; }
330   void setType(const std::string &type) { Type = type; }
331 
332   friend bool operator==(const VariableInfo &, const VariableInfo &);
333 
334   VariableInfo &operator|=(const VariableInfo &RHS) {
335     static_cast<CommonEntityInfo &>(*this) |= RHS;
336 
337     if (!NullabilityAudited && RHS.NullabilityAudited)
338       setNullabilityAudited(*RHS.getNullability());
339     if (Type.empty())
340       Type = RHS.Type;
341 
342     return *this;
343   }
344 
345   LLVM_DUMP_METHOD void dump(llvm::raw_ostream &OS) const;
346 };
347 
348 inline bool operator==(const VariableInfo &LHS, const VariableInfo &RHS) {
349   return static_cast<const CommonEntityInfo &>(LHS) == RHS &&
350          LHS.NullabilityAudited == RHS.NullabilityAudited &&
351          LHS.Nullable == RHS.Nullable && LHS.Type == RHS.Type;
352 }
353 
354 inline bool operator!=(const VariableInfo &LHS, const VariableInfo &RHS) {
355   return !(LHS == RHS);
356 }
357 
358 /// Describes API notes data for an Objective-C property.
359 class ObjCPropertyInfo : public VariableInfo {
360   unsigned SwiftImportAsAccessorsSpecified : 1;
361   unsigned SwiftImportAsAccessors : 1;
362 
363 public:
364   ObjCPropertyInfo()
365       : SwiftImportAsAccessorsSpecified(false), SwiftImportAsAccessors(false) {}
366 
367   std::optional<bool> getSwiftImportAsAccessors() const {
368     return SwiftImportAsAccessorsSpecified
369                ? std::optional<bool>(SwiftImportAsAccessors)
370                : std::nullopt;
371   }
372   void setSwiftImportAsAccessors(std::optional<bool> Value) {
373     SwiftImportAsAccessorsSpecified = Value.has_value();
374     SwiftImportAsAccessors = Value.value_or(false);
375   }
376 
377   friend bool operator==(const ObjCPropertyInfo &, const ObjCPropertyInfo &);
378 
379   /// Merge class-wide information into the given property.
380   ObjCPropertyInfo &operator|=(const ObjCContextInfo &RHS) {
381     static_cast<CommonEntityInfo &>(*this) |= RHS;
382 
383     // Merge nullability.
384     if (!getNullability())
385       if (auto Nullable = RHS.getDefaultNullability())
386         setNullabilityAudited(*Nullable);
387 
388     return *this;
389   }
390 
391   ObjCPropertyInfo &operator|=(const ObjCPropertyInfo &RHS) {
392     static_cast<VariableInfo &>(*this) |= RHS;
393 
394     if (!SwiftImportAsAccessorsSpecified)
395       setSwiftImportAsAccessors(RHS.getSwiftImportAsAccessors());
396 
397     return *this;
398   }
399 
400   LLVM_DUMP_METHOD void dump(llvm::raw_ostream &OS) const;
401 };
402 
403 inline bool operator==(const ObjCPropertyInfo &LHS,
404                        const ObjCPropertyInfo &RHS) {
405   return static_cast<const VariableInfo &>(LHS) == RHS &&
406          LHS.getSwiftImportAsAccessors() == RHS.getSwiftImportAsAccessors();
407 }
408 
409 inline bool operator!=(const ObjCPropertyInfo &LHS,
410                        const ObjCPropertyInfo &RHS) {
411   return !(LHS == RHS);
412 }
413 
414 /// Describes a function or method parameter.
415 class ParamInfo : public VariableInfo {
416   /// Whether noescape was specified.
417   unsigned NoEscapeSpecified : 1;
418 
419   /// Whether the this parameter has the 'noescape' attribute.
420   unsigned NoEscape : 1;
421 
422   /// A biased RetainCountConventionKind, where 0 means "unspecified".
423   ///
424   /// Only relevant for out-parameters.
425   unsigned RawRetainCountConvention : 3;
426 
427 public:
428   ParamInfo()
429       : NoEscapeSpecified(false), NoEscape(false), RawRetainCountConvention() {}
430 
431   std::optional<bool> isNoEscape() const {
432     if (!NoEscapeSpecified)
433       return std::nullopt;
434     return NoEscape;
435   }
436   void setNoEscape(std::optional<bool> Value) {
437     NoEscapeSpecified = Value.has_value();
438     NoEscape = Value.value_or(false);
439   }
440 
441   std::optional<RetainCountConventionKind> getRetainCountConvention() const {
442     if (!RawRetainCountConvention)
443       return std::nullopt;
444     return static_cast<RetainCountConventionKind>(RawRetainCountConvention - 1);
445   }
446   void
447   setRetainCountConvention(std::optional<RetainCountConventionKind> Value) {
448     RawRetainCountConvention = Value ? static_cast<unsigned>(*Value) + 1 : 0;
449     assert(getRetainCountConvention() == Value && "bitfield too small");
450   }
451 
452   ParamInfo &operator|=(const ParamInfo &RHS) {
453     static_cast<VariableInfo &>(*this) |= RHS;
454 
455     if (!NoEscapeSpecified && RHS.NoEscapeSpecified) {
456       NoEscapeSpecified = true;
457       NoEscape = RHS.NoEscape;
458     }
459 
460     if (!RawRetainCountConvention)
461       RawRetainCountConvention = RHS.RawRetainCountConvention;
462 
463     return *this;
464   }
465 
466   friend bool operator==(const ParamInfo &, const ParamInfo &);
467 
468   LLVM_DUMP_METHOD void dump(llvm::raw_ostream &OS) const;
469 };
470 
471 inline bool operator==(const ParamInfo &LHS, const ParamInfo &RHS) {
472   return static_cast<const VariableInfo &>(LHS) == RHS &&
473          LHS.NoEscapeSpecified == RHS.NoEscapeSpecified &&
474          LHS.NoEscape == RHS.NoEscape &&
475          LHS.RawRetainCountConvention == RHS.RawRetainCountConvention;
476 }
477 
478 inline bool operator!=(const ParamInfo &LHS, const ParamInfo &RHS) {
479   return !(LHS == RHS);
480 }
481 
482 /// API notes for a function or method.
483 class FunctionInfo : public CommonEntityInfo {
484 private:
485   static constexpr const uint64_t NullabilityKindMask = 0x3;
486   static constexpr const unsigned NullabilityKindSize = 2;
487 
488   static constexpr const unsigned ReturnInfoIndex = 0;
489 
490 public:
491   // If yes, we consider all types to be non-nullable unless otherwise noted.
492   // If this flag is not set, the pointer types are considered to have
493   // unknown nullability.
494 
495   /// Whether the signature has been audited with respect to nullability.
496   unsigned NullabilityAudited : 1;
497 
498   /// Number of types whose nullability is encoded with the NullabilityPayload.
499   unsigned NumAdjustedNullable : 8;
500 
501   /// A biased RetainCountConventionKind, where 0 means "unspecified".
502   unsigned RawRetainCountConvention : 3;
503 
504   // NullabilityKindSize bits are used to encode the nullability. The info
505   // about the return type is stored at position 0, followed by the nullability
506   // of the parameters.
507 
508   /// Stores the nullability of the return type and the parameters.
509   uint64_t NullabilityPayload = 0;
510 
511   /// The result type of this function, as a C type.
512   std::string ResultType;
513 
514   /// The function parameters.
515   std::vector<ParamInfo> Params;
516 
517   FunctionInfo()
518       : NullabilityAudited(false), NumAdjustedNullable(0),
519         RawRetainCountConvention() {}
520 
521   static unsigned getMaxNullabilityIndex() {
522     return ((sizeof(NullabilityPayload) * CHAR_BIT) / NullabilityKindSize);
523   }
524 
525   void addTypeInfo(unsigned index, NullabilityKind kind) {
526     assert(index <= getMaxNullabilityIndex());
527     assert(static_cast<unsigned>(kind) < NullabilityKindMask);
528 
529     NullabilityAudited = true;
530     if (NumAdjustedNullable < index + 1)
531       NumAdjustedNullable = index + 1;
532 
533     // Mask the bits.
534     NullabilityPayload &=
535         ~(NullabilityKindMask << (index * NullabilityKindSize));
536 
537     // Set the value.
538     unsigned kindValue = (static_cast<unsigned>(kind))
539                          << (index * NullabilityKindSize);
540     NullabilityPayload |= kindValue;
541   }
542 
543   /// Adds the return type info.
544   void addReturnTypeInfo(NullabilityKind kind) {
545     addTypeInfo(ReturnInfoIndex, kind);
546   }
547 
548   /// Adds the parameter type info.
549   void addParamTypeInfo(unsigned index, NullabilityKind kind) {
550     addTypeInfo(index + 1, kind);
551   }
552 
553   NullabilityKind getParamTypeInfo(unsigned index) const {
554     return getTypeInfo(index + 1);
555   }
556 
557   NullabilityKind getReturnTypeInfo() const { return getTypeInfo(0); }
558 
559   std::optional<RetainCountConventionKind> getRetainCountConvention() const {
560     if (!RawRetainCountConvention)
561       return std::nullopt;
562     return static_cast<RetainCountConventionKind>(RawRetainCountConvention - 1);
563   }
564   void
565   setRetainCountConvention(std::optional<RetainCountConventionKind> Value) {
566     RawRetainCountConvention = Value ? static_cast<unsigned>(*Value) + 1 : 0;
567     assert(getRetainCountConvention() == Value && "bitfield too small");
568   }
569 
570   friend bool operator==(const FunctionInfo &, const FunctionInfo &);
571 
572 private:
573   NullabilityKind getTypeInfo(unsigned index) const {
574     assert(NullabilityAudited &&
575            "Checking the type adjustment on non-audited method.");
576 
577     // If we don't have info about this parameter, return the default.
578     if (index > NumAdjustedNullable)
579       return NullabilityKind::NonNull;
580     auto nullability = NullabilityPayload >> (index * NullabilityKindSize);
581     return static_cast<NullabilityKind>(nullability & NullabilityKindMask);
582   }
583 
584 public:
585   LLVM_DUMP_METHOD void dump(llvm::raw_ostream &OS) const;
586 };
587 
588 inline bool operator==(const FunctionInfo &LHS, const FunctionInfo &RHS) {
589   return static_cast<const CommonEntityInfo &>(LHS) == RHS &&
590          LHS.NullabilityAudited == RHS.NullabilityAudited &&
591          LHS.NumAdjustedNullable == RHS.NumAdjustedNullable &&
592          LHS.NullabilityPayload == RHS.NullabilityPayload &&
593          LHS.ResultType == RHS.ResultType && LHS.Params == RHS.Params &&
594          LHS.RawRetainCountConvention == RHS.RawRetainCountConvention;
595 }
596 
597 inline bool operator!=(const FunctionInfo &LHS, const FunctionInfo &RHS) {
598   return !(LHS == RHS);
599 }
600 
601 /// Describes API notes data for an Objective-C method.
602 class ObjCMethodInfo : public FunctionInfo {
603 public:
604   /// Whether this is a designated initializer of its class.
605   unsigned DesignatedInit : 1;
606 
607   /// Whether this is a required initializer.
608   unsigned RequiredInit : 1;
609 
610   ObjCMethodInfo() : DesignatedInit(false), RequiredInit(false) {}
611 
612   friend bool operator==(const ObjCMethodInfo &, const ObjCMethodInfo &);
613 
614   ObjCMethodInfo &operator|=(const ObjCContextInfo &RHS) {
615     // Merge Nullability.
616     if (!NullabilityAudited) {
617       if (auto Nullable = RHS.getDefaultNullability()) {
618         NullabilityAudited = true;
619         addTypeInfo(0, *Nullable);
620       }
621     }
622     return *this;
623   }
624 
625   LLVM_DUMP_METHOD void dump(llvm::raw_ostream &OS);
626 };
627 
628 inline bool operator==(const ObjCMethodInfo &LHS, const ObjCMethodInfo &RHS) {
629   return static_cast<const FunctionInfo &>(LHS) == RHS &&
630          LHS.DesignatedInit == RHS.DesignatedInit &&
631          LHS.RequiredInit == RHS.RequiredInit;
632 }
633 
634 inline bool operator!=(const ObjCMethodInfo &LHS, const ObjCMethodInfo &RHS) {
635   return !(LHS == RHS);
636 }
637 
638 /// Describes API notes data for a global variable.
639 class GlobalVariableInfo : public VariableInfo {
640 public:
641   GlobalVariableInfo() {}
642 };
643 
644 /// Describes API notes data for a global function.
645 class GlobalFunctionInfo : public FunctionInfo {
646 public:
647   GlobalFunctionInfo() {}
648 };
649 
650 /// Describes API notes data for an enumerator.
651 class EnumConstantInfo : public CommonEntityInfo {
652 public:
653   EnumConstantInfo() {}
654 };
655 
656 /// Describes API notes data for a tag.
657 class TagInfo : public CommonTypeInfo {
658   unsigned HasFlagEnum : 1;
659   unsigned IsFlagEnum : 1;
660 
661 public:
662   std::optional<EnumExtensibilityKind> EnumExtensibility;
663 
664   TagInfo() : HasFlagEnum(0), IsFlagEnum(0) {}
665 
666   std::optional<bool> isFlagEnum() const {
667     if (HasFlagEnum)
668       return IsFlagEnum;
669     return std::nullopt;
670   }
671   void setFlagEnum(std::optional<bool> Value) {
672     HasFlagEnum = Value.has_value();
673     IsFlagEnum = Value.value_or(false);
674   }
675 
676   TagInfo &operator|=(const TagInfo &RHS) {
677     static_cast<CommonTypeInfo &>(*this) |= RHS;
678 
679     if (!HasFlagEnum)
680       setFlagEnum(RHS.isFlagEnum());
681 
682     if (!EnumExtensibility)
683       EnumExtensibility = RHS.EnumExtensibility;
684 
685     return *this;
686   }
687 
688   friend bool operator==(const TagInfo &, const TagInfo &);
689 
690   LLVM_DUMP_METHOD void dump(llvm::raw_ostream &OS);
691 };
692 
693 inline bool operator==(const TagInfo &LHS, const TagInfo &RHS) {
694   return static_cast<const CommonTypeInfo &>(LHS) == RHS &&
695          LHS.isFlagEnum() == RHS.isFlagEnum() &&
696          LHS.EnumExtensibility == RHS.EnumExtensibility;
697 }
698 
699 inline bool operator!=(const TagInfo &LHS, const TagInfo &RHS) {
700   return !(LHS == RHS);
701 }
702 
703 /// Describes API notes data for a typedef.
704 class TypedefInfo : public CommonTypeInfo {
705 public:
706   std::optional<SwiftNewTypeKind> SwiftWrapper;
707 
708   TypedefInfo() {}
709 
710   TypedefInfo &operator|=(const TypedefInfo &RHS) {
711     static_cast<CommonTypeInfo &>(*this) |= RHS;
712     if (!SwiftWrapper)
713       SwiftWrapper = RHS.SwiftWrapper;
714     return *this;
715   }
716 
717   friend bool operator==(const TypedefInfo &, const TypedefInfo &);
718 
719   LLVM_DUMP_METHOD void dump(llvm::raw_ostream &OS) const;
720 };
721 
722 inline bool operator==(const TypedefInfo &LHS, const TypedefInfo &RHS) {
723   return static_cast<const CommonTypeInfo &>(LHS) == RHS &&
724          LHS.SwiftWrapper == RHS.SwiftWrapper;
725 }
726 
727 inline bool operator!=(const TypedefInfo &LHS, const TypedefInfo &RHS) {
728   return !(LHS == RHS);
729 }
730 } // namespace api_notes
731 } // namespace clang
732 
733 #endif
734