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