xref: /llvm-project/clang/lib/Sema/SemaAPINotes.cpp (revision 31a203fa8af47a8b2e8e357857b114cf90638b2e)
1 //===--- SemaAPINotes.cpp - API Notes Handling ----------------------------===//
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 //  This file implements the mapping from API notes to declaration attributes.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "clang/APINotes/APINotesReader.h"
14 #include "clang/AST/Decl.h"
15 #include "clang/AST/DeclObjC.h"
16 #include "clang/Basic/SourceLocation.h"
17 #include "clang/Lex/Lexer.h"
18 #include "clang/Sema/SemaInternal.h"
19 #include "clang/Sema/SemaObjC.h"
20 
21 using namespace clang;
22 
23 namespace {
24 enum class IsActive_t : bool { Inactive, Active };
25 enum class IsSubstitution_t : bool { Original, Replacement };
26 
27 struct VersionedInfoMetadata {
28   /// An empty version refers to unversioned metadata.
29   VersionTuple Version;
30   unsigned IsActive : 1;
31   unsigned IsReplacement : 1;
32 
33   VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
34                         IsSubstitution_t Replacement)
35       : Version(Version), IsActive(Active == IsActive_t::Active),
36         IsReplacement(Replacement == IsSubstitution_t::Replacement) {}
37 };
38 } // end anonymous namespace
39 
40 /// Determine whether this is a multi-level pointer type.
41 static bool isIndirectPointerType(QualType Type) {
42   QualType Pointee = Type->getPointeeType();
43   if (Pointee.isNull())
44     return false;
45 
46   return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
47          Pointee->isMemberPointerType();
48 }
49 
50 /// Apply nullability to the given declaration.
51 static void applyNullability(Sema &S, Decl *D, NullabilityKind Nullability,
52                              VersionedInfoMetadata Metadata) {
53   if (!Metadata.IsActive)
54     return;
55 
56   auto GetModified =
57       [&](Decl *D, QualType QT,
58           NullabilityKind Nullability) -> std::optional<QualType> {
59     QualType Original = QT;
60     S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(),
61                                             isa<ParmVarDecl>(D),
62                                             /*OverrideExisting=*/true);
63     return (QT.getTypePtr() != Original.getTypePtr()) ? std::optional(QT)
64                                                       : std::nullopt;
65   };
66 
67   if (auto Function = dyn_cast<FunctionDecl>(D)) {
68     if (auto Modified =
69             GetModified(D, Function->getReturnType(), Nullability)) {
70       const FunctionType *FnType = Function->getType()->castAs<FunctionType>();
71       if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(FnType))
72         Function->setType(S.Context.getFunctionType(
73             *Modified, proto->getParamTypes(), proto->getExtProtoInfo()));
74       else
75         Function->setType(
76             S.Context.getFunctionNoProtoType(*Modified, FnType->getExtInfo()));
77     }
78   } else if (auto Method = dyn_cast<ObjCMethodDecl>(D)) {
79     if (auto Modified = GetModified(D, Method->getReturnType(), Nullability)) {
80       Method->setReturnType(*Modified);
81 
82       // Make it a context-sensitive keyword if we can.
83       if (!isIndirectPointerType(*Modified))
84         Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
85             Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
86     }
87   } else if (auto Value = dyn_cast<ValueDecl>(D)) {
88     if (auto Modified = GetModified(D, Value->getType(), Nullability)) {
89       Value->setType(*Modified);
90 
91       // Make it a context-sensitive keyword if we can.
92       if (auto Parm = dyn_cast<ParmVarDecl>(D)) {
93         if (Parm->isObjCMethodParameter() && !isIndirectPointerType(*Modified))
94           Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
95               Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
96       }
97     }
98   } else if (auto Property = dyn_cast<ObjCPropertyDecl>(D)) {
99     if (auto Modified = GetModified(D, Property->getType(), Nullability)) {
100       Property->setType(*Modified, Property->getTypeSourceInfo());
101 
102       // Make it a property attribute if we can.
103       if (!isIndirectPointerType(*Modified))
104         Property->setPropertyAttributes(
105             ObjCPropertyAttribute::kind_null_resettable);
106     }
107   }
108 }
109 
110 /// Copy a string into ASTContext-allocated memory.
111 static StringRef ASTAllocateString(ASTContext &Ctx, StringRef String) {
112   void *mem = Ctx.Allocate(String.size(), alignof(char *));
113   memcpy(mem, String.data(), String.size());
114   return StringRef(static_cast<char *>(mem), String.size());
115 }
116 
117 static AttributeCommonInfo getPlaceholderAttrInfo() {
118   return AttributeCommonInfo(SourceRange(),
119                              AttributeCommonInfo::UnknownAttribute,
120                              {AttributeCommonInfo::AS_GNU,
121                               /*Spelling*/ 0, /*IsAlignas*/ false,
122                               /*IsRegularKeywordAttribute*/ false});
123 }
124 
125 namespace {
126 template <typename A> struct AttrKindFor {};
127 
128 #define ATTR(X)                                                                \
129   template <> struct AttrKindFor<X##Attr> {                                    \
130     static const attr::Kind value = attr::X;                                   \
131   };
132 #include "clang/Basic/AttrList.inc"
133 
134 /// Handle an attribute introduced by API notes.
135 ///
136 /// \param IsAddition Whether we should add a new attribute
137 /// (otherwise, we might remove an existing attribute).
138 /// \param CreateAttr Create the new attribute to be added.
139 template <typename A>
140 void handleAPINotedAttribute(
141     Sema &S, Decl *D, bool IsAddition, VersionedInfoMetadata Metadata,
142     llvm::function_ref<A *()> CreateAttr,
143     llvm::function_ref<Decl::attr_iterator(const Decl *)> GetExistingAttr) {
144   if (Metadata.IsActive) {
145     auto Existing = GetExistingAttr(D);
146     if (Existing != D->attr_end()) {
147       // Remove the existing attribute, and treat it as a superseded
148       // non-versioned attribute.
149       auto *Versioned = SwiftVersionedAdditionAttr::CreateImplicit(
150           S.Context, Metadata.Version, *Existing, /*IsReplacedByActive*/ true);
151 
152       D->getAttrs().erase(Existing);
153       D->addAttr(Versioned);
154     }
155 
156     // If we're supposed to add a new attribute, do so.
157     if (IsAddition) {
158       if (auto Attr = CreateAttr())
159         D->addAttr(Attr);
160     }
161 
162     return;
163   }
164   if (IsAddition) {
165     if (auto Attr = CreateAttr()) {
166       auto *Versioned = SwiftVersionedAdditionAttr::CreateImplicit(
167           S.Context, Metadata.Version, Attr,
168           /*IsReplacedByActive*/ Metadata.IsReplacement);
169       D->addAttr(Versioned);
170     }
171   } else {
172     // FIXME: This isn't preserving enough information for things like
173     // availability, where we're trying to remove a /specific/ kind of
174     // attribute.
175     auto *Versioned = SwiftVersionedRemovalAttr::CreateImplicit(
176         S.Context, Metadata.Version, AttrKindFor<A>::value,
177         /*IsReplacedByActive*/ Metadata.IsReplacement);
178     D->addAttr(Versioned);
179   }
180 }
181 
182 template <typename A>
183 void handleAPINotedAttribute(Sema &S, Decl *D, bool ShouldAddAttribute,
184                              VersionedInfoMetadata Metadata,
185                              llvm::function_ref<A *()> CreateAttr) {
186   handleAPINotedAttribute<A>(
187       S, D, ShouldAddAttribute, Metadata, CreateAttr, [](const Decl *D) {
188         return llvm::find_if(D->attrs(),
189                              [](const Attr *Next) { return isa<A>(Next); });
190       });
191 }
192 } // namespace
193 
194 template <typename A>
195 static void handleAPINotedRetainCountAttribute(Sema &S, Decl *D,
196                                                bool ShouldAddAttribute,
197                                                VersionedInfoMetadata Metadata) {
198   // The template argument has a default to make the "removal" case more
199   // concise; it doesn't matter /which/ attribute is being removed.
200   handleAPINotedAttribute<A>(
201       S, D, ShouldAddAttribute, Metadata,
202       [&] { return new (S.Context) A(S.Context, getPlaceholderAttrInfo()); },
203       [](const Decl *D) -> Decl::attr_iterator {
204         return llvm::find_if(D->attrs(), [](const Attr *Next) -> bool {
205           return isa<CFReturnsRetainedAttr>(Next) ||
206                  isa<CFReturnsNotRetainedAttr>(Next) ||
207                  isa<NSReturnsRetainedAttr>(Next) ||
208                  isa<NSReturnsNotRetainedAttr>(Next) ||
209                  isa<CFAuditedTransferAttr>(Next);
210         });
211       });
212 }
213 
214 static void handleAPINotedRetainCountConvention(
215     Sema &S, Decl *D, VersionedInfoMetadata Metadata,
216     std::optional<api_notes::RetainCountConventionKind> Convention) {
217   if (!Convention)
218     return;
219   switch (*Convention) {
220   case api_notes::RetainCountConventionKind::None:
221     if (isa<FunctionDecl>(D)) {
222       handleAPINotedRetainCountAttribute<CFUnknownTransferAttr>(
223           S, D, /*shouldAddAttribute*/ true, Metadata);
224     } else {
225       handleAPINotedRetainCountAttribute<CFReturnsRetainedAttr>(
226           S, D, /*shouldAddAttribute*/ false, Metadata);
227     }
228     break;
229   case api_notes::RetainCountConventionKind::CFReturnsRetained:
230     handleAPINotedRetainCountAttribute<CFReturnsRetainedAttr>(
231         S, D, /*shouldAddAttribute*/ true, Metadata);
232     break;
233   case api_notes::RetainCountConventionKind::CFReturnsNotRetained:
234     handleAPINotedRetainCountAttribute<CFReturnsNotRetainedAttr>(
235         S, D, /*shouldAddAttribute*/ true, Metadata);
236     break;
237   case api_notes::RetainCountConventionKind::NSReturnsRetained:
238     handleAPINotedRetainCountAttribute<NSReturnsRetainedAttr>(
239         S, D, /*shouldAddAttribute*/ true, Metadata);
240     break;
241   case api_notes::RetainCountConventionKind::NSReturnsNotRetained:
242     handleAPINotedRetainCountAttribute<NSReturnsNotRetainedAttr>(
243         S, D, /*shouldAddAttribute*/ true, Metadata);
244     break;
245   }
246 }
247 
248 static void ProcessAPINotes(Sema &S, Decl *D,
249                             const api_notes::CommonEntityInfo &Info,
250                             VersionedInfoMetadata Metadata) {
251   // Availability
252   if (Info.Unavailable) {
253     handleAPINotedAttribute<UnavailableAttr>(S, D, true, Metadata, [&] {
254       return new (S.Context)
255           UnavailableAttr(S.Context, getPlaceholderAttrInfo(),
256                           ASTAllocateString(S.Context, Info.UnavailableMsg));
257     });
258   }
259 
260   if (Info.UnavailableInSwift) {
261     handleAPINotedAttribute<AvailabilityAttr>(
262         S, D, true, Metadata,
263         [&] {
264           return new (S.Context) AvailabilityAttr(
265               S.Context, getPlaceholderAttrInfo(),
266               &S.Context.Idents.get("swift"), VersionTuple(), VersionTuple(),
267               VersionTuple(),
268               /*Unavailable=*/true,
269               ASTAllocateString(S.Context, Info.UnavailableMsg),
270               /*Strict=*/false,
271               /*Replacement=*/StringRef(),
272               /*Priority=*/Sema::AP_Explicit);
273         },
274         [](const Decl *D) {
275           return llvm::find_if(D->attrs(), [](const Attr *next) -> bool {
276             if (const auto *AA = dyn_cast<AvailabilityAttr>(next))
277               if (const auto *II = AA->getPlatform())
278                 return II->isStr("swift");
279             return false;
280           });
281         });
282   }
283 
284   // swift_private
285   if (auto SwiftPrivate = Info.isSwiftPrivate()) {
286     handleAPINotedAttribute<SwiftPrivateAttr>(
287         S, D, *SwiftPrivate, Metadata, [&] {
288           return new (S.Context)
289               SwiftPrivateAttr(S.Context, getPlaceholderAttrInfo());
290         });
291   }
292 
293   // swift_name
294   if (!Info.SwiftName.empty()) {
295     handleAPINotedAttribute<SwiftNameAttr>(
296         S, D, true, Metadata, [&]() -> SwiftNameAttr * {
297           AttributeFactory AF{};
298           AttributePool AP{AF};
299           auto &C = S.getASTContext();
300           ParsedAttr *SNA =
301               AP.create(&C.Idents.get("swift_name"), SourceRange(), nullptr,
302                         SourceLocation(), nullptr, nullptr, nullptr,
303                         ParsedAttr::Form::GNU());
304 
305           if (!S.DiagnoseSwiftName(D, Info.SwiftName, D->getLocation(), *SNA,
306                                    /*IsAsync=*/false))
307             return nullptr;
308 
309           return new (S.Context)
310               SwiftNameAttr(S.Context, getPlaceholderAttrInfo(),
311                             ASTAllocateString(S.Context, Info.SwiftName));
312         });
313   }
314 }
315 
316 static void ProcessAPINotes(Sema &S, Decl *D,
317                             const api_notes::CommonTypeInfo &Info,
318                             VersionedInfoMetadata Metadata) {
319   // swift_bridge
320   if (auto SwiftBridge = Info.getSwiftBridge()) {
321     handleAPINotedAttribute<SwiftBridgeAttr>(
322         S, D, !SwiftBridge->empty(), Metadata, [&] {
323           return new (S.Context)
324               SwiftBridgeAttr(S.Context, getPlaceholderAttrInfo(),
325                               ASTAllocateString(S.Context, *SwiftBridge));
326         });
327   }
328 
329   // ns_error_domain
330   if (auto NSErrorDomain = Info.getNSErrorDomain()) {
331     handleAPINotedAttribute<NSErrorDomainAttr>(
332         S, D, !NSErrorDomain->empty(), Metadata, [&] {
333           return new (S.Context)
334               NSErrorDomainAttr(S.Context, getPlaceholderAttrInfo(),
335                                 &S.Context.Idents.get(*NSErrorDomain));
336         });
337   }
338 
339   ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(Info),
340                   Metadata);
341 }
342 
343 /// Check that the replacement type provided by API notes is reasonable.
344 ///
345 /// This is a very weak form of ABI check.
346 static bool checkAPINotesReplacementType(Sema &S, SourceLocation Loc,
347                                          QualType OrigType,
348                                          QualType ReplacementType) {
349   if (S.Context.getTypeSize(OrigType) !=
350       S.Context.getTypeSize(ReplacementType)) {
351     S.Diag(Loc, diag::err_incompatible_replacement_type)
352         << ReplacementType << OrigType;
353     return true;
354   }
355 
356   return false;
357 }
358 
359 /// Process API notes for a variable or property.
360 static void ProcessAPINotes(Sema &S, Decl *D,
361                             const api_notes::VariableInfo &Info,
362                             VersionedInfoMetadata Metadata) {
363   // Type override.
364   if (Metadata.IsActive && !Info.getType().empty() &&
365       S.ParseTypeFromStringCallback) {
366     auto ParsedType = S.ParseTypeFromStringCallback(
367         Info.getType(), "<API Notes>", D->getLocation());
368     if (ParsedType.isUsable()) {
369       QualType Type = Sema::GetTypeFromParser(ParsedType.get());
370       auto TypeInfo =
371           S.Context.getTrivialTypeSourceInfo(Type, D->getLocation());
372 
373       if (auto Var = dyn_cast<VarDecl>(D)) {
374         // Make adjustments to parameter types.
375         if (isa<ParmVarDecl>(Var)) {
376           Type = S.ObjC().AdjustParameterTypeForObjCAutoRefCount(
377               Type, D->getLocation(), TypeInfo);
378           Type = S.Context.getAdjustedParameterType(Type);
379         }
380 
381         if (!checkAPINotesReplacementType(S, Var->getLocation(), Var->getType(),
382                                           Type)) {
383           Var->setType(Type);
384           Var->setTypeSourceInfo(TypeInfo);
385         }
386       } else if (auto Property = dyn_cast<ObjCPropertyDecl>(D)) {
387         if (!checkAPINotesReplacementType(S, Property->getLocation(),
388                                           Property->getType(), Type))
389           Property->setType(Type, TypeInfo);
390 
391       } else
392         llvm_unreachable("API notes allowed a type on an unknown declaration");
393     }
394   }
395 
396   // Nullability.
397   if (auto Nullability = Info.getNullability())
398     applyNullability(S, D, *Nullability, Metadata);
399 
400   // Handle common entity information.
401   ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(Info),
402                   Metadata);
403 }
404 
405 /// Process API notes for a parameter.
406 static void ProcessAPINotes(Sema &S, ParmVarDecl *D,
407                             const api_notes::ParamInfo &Info,
408                             VersionedInfoMetadata Metadata) {
409   // noescape
410   if (auto NoEscape = Info.isNoEscape())
411     handleAPINotedAttribute<NoEscapeAttr>(S, D, *NoEscape, Metadata, [&] {
412       return new (S.Context) NoEscapeAttr(S.Context, getPlaceholderAttrInfo());
413     });
414 
415   // Retain count convention
416   handleAPINotedRetainCountConvention(S, D, Metadata,
417                                       Info.getRetainCountConvention());
418 
419   // Handle common entity information.
420   ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(Info),
421                   Metadata);
422 }
423 
424 /// Process API notes for a global variable.
425 static void ProcessAPINotes(Sema &S, VarDecl *D,
426                             const api_notes::GlobalVariableInfo &Info,
427                             VersionedInfoMetadata metadata) {
428   // Handle common entity information.
429   ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(Info),
430                   metadata);
431 }
432 
433 /// Process API notes for an Objective-C property.
434 static void ProcessAPINotes(Sema &S, ObjCPropertyDecl *D,
435                             const api_notes::ObjCPropertyInfo &Info,
436                             VersionedInfoMetadata Metadata) {
437   // Handle common entity information.
438   ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(Info),
439                   Metadata);
440 
441   if (auto AsAccessors = Info.getSwiftImportAsAccessors()) {
442     handleAPINotedAttribute<SwiftImportPropertyAsAccessorsAttr>(
443         S, D, *AsAccessors, Metadata, [&] {
444           return new (S.Context) SwiftImportPropertyAsAccessorsAttr(
445               S.Context, getPlaceholderAttrInfo());
446         });
447   }
448 }
449 
450 namespace {
451 typedef llvm::PointerUnion<FunctionDecl *, ObjCMethodDecl *> FunctionOrMethod;
452 }
453 
454 /// Process API notes for a function or method.
455 static void ProcessAPINotes(Sema &S, FunctionOrMethod AnyFunc,
456                             const api_notes::FunctionInfo &Info,
457                             VersionedInfoMetadata Metadata) {
458   // Find the declaration itself.
459   FunctionDecl *FD = AnyFunc.dyn_cast<FunctionDecl *>();
460   Decl *D = FD;
461   ObjCMethodDecl *MD = nullptr;
462   if (!D) {
463     MD = AnyFunc.get<ObjCMethodDecl *>();
464     D = MD;
465   }
466 
467   assert((FD || MD) && "Expecting Function or ObjCMethod");
468 
469   // Nullability of return type.
470   if (Info.NullabilityAudited)
471     applyNullability(S, D, Info.getReturnTypeInfo(), Metadata);
472 
473   // Parameters.
474   unsigned NumParams = FD ? FD->getNumParams() : MD->param_size();
475 
476   bool AnyTypeChanged = false;
477   for (unsigned I = 0; I != NumParams; ++I) {
478     ParmVarDecl *Param = FD ? FD->getParamDecl(I) : MD->param_begin()[I];
479     QualType ParamTypeBefore = Param->getType();
480 
481     if (I < Info.Params.size())
482       ProcessAPINotes(S, Param, Info.Params[I], Metadata);
483 
484     // Nullability.
485     if (Info.NullabilityAudited)
486       applyNullability(S, Param, Info.getParamTypeInfo(I), Metadata);
487 
488     if (ParamTypeBefore.getAsOpaquePtr() != Param->getType().getAsOpaquePtr())
489       AnyTypeChanged = true;
490   }
491 
492   // Result type override.
493   QualType OverriddenResultType;
494   if (Metadata.IsActive && !Info.ResultType.empty() &&
495       S.ParseTypeFromStringCallback) {
496     auto ParsedType = S.ParseTypeFromStringCallback(
497         Info.ResultType, "<API Notes>", D->getLocation());
498     if (ParsedType.isUsable()) {
499       QualType ResultType = Sema::GetTypeFromParser(ParsedType.get());
500 
501       if (MD) {
502         if (!checkAPINotesReplacementType(S, D->getLocation(),
503                                           MD->getReturnType(), ResultType)) {
504           auto ResultTypeInfo =
505               S.Context.getTrivialTypeSourceInfo(ResultType, D->getLocation());
506           MD->setReturnType(ResultType);
507           MD->setReturnTypeSourceInfo(ResultTypeInfo);
508         }
509       } else if (!checkAPINotesReplacementType(
510                      S, FD->getLocation(), FD->getReturnType(), ResultType)) {
511         OverriddenResultType = ResultType;
512         AnyTypeChanged = true;
513       }
514     }
515   }
516 
517   // If the result type or any of the parameter types changed for a function
518   // declaration, we have to rebuild the type.
519   if (FD && AnyTypeChanged) {
520     if (const auto *fnProtoType = FD->getType()->getAs<FunctionProtoType>()) {
521       if (OverriddenResultType.isNull())
522         OverriddenResultType = fnProtoType->getReturnType();
523 
524       SmallVector<QualType, 4> ParamTypes;
525       for (auto Param : FD->parameters())
526         ParamTypes.push_back(Param->getType());
527 
528       FD->setType(S.Context.getFunctionType(OverriddenResultType, ParamTypes,
529                                             fnProtoType->getExtProtoInfo()));
530     } else if (!OverriddenResultType.isNull()) {
531       const auto *FnNoProtoType = FD->getType()->castAs<FunctionNoProtoType>();
532       FD->setType(S.Context.getFunctionNoProtoType(
533           OverriddenResultType, FnNoProtoType->getExtInfo()));
534     }
535   }
536 
537   // Retain count convention
538   handleAPINotedRetainCountConvention(S, D, Metadata,
539                                       Info.getRetainCountConvention());
540 
541   // Handle common entity information.
542   ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(Info),
543                   Metadata);
544 }
545 
546 /// Process API notes for a global function.
547 static void ProcessAPINotes(Sema &S, FunctionDecl *D,
548                             const api_notes::GlobalFunctionInfo &Info,
549                             VersionedInfoMetadata Metadata) {
550   // Handle common function information.
551   ProcessAPINotes(S, FunctionOrMethod(D),
552                   static_cast<const api_notes::FunctionInfo &>(Info), Metadata);
553 }
554 
555 /// Process API notes for an enumerator.
556 static void ProcessAPINotes(Sema &S, EnumConstantDecl *D,
557                             const api_notes::EnumConstantInfo &Info,
558                             VersionedInfoMetadata Metadata) {
559   // Handle common information.
560   ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(Info),
561                   Metadata);
562 }
563 
564 /// Process API notes for an Objective-C method.
565 static void ProcessAPINotes(Sema &S, ObjCMethodDecl *D,
566                             const api_notes::ObjCMethodInfo &Info,
567                             VersionedInfoMetadata Metadata) {
568   // Designated initializers.
569   if (Info.DesignatedInit) {
570     handleAPINotedAttribute<ObjCDesignatedInitializerAttr>(
571         S, D, true, Metadata, [&] {
572           if (ObjCInterfaceDecl *IFace = D->getClassInterface())
573             IFace->setHasDesignatedInitializers();
574 
575           return new (S.Context) ObjCDesignatedInitializerAttr(
576               S.Context, getPlaceholderAttrInfo());
577         });
578   }
579 
580   // Handle common function information.
581   ProcessAPINotes(S, FunctionOrMethod(D),
582                   static_cast<const api_notes::FunctionInfo &>(Info), Metadata);
583 }
584 
585 /// Process API notes for a tag.
586 static void ProcessAPINotes(Sema &S, TagDecl *D, const api_notes::TagInfo &Info,
587                             VersionedInfoMetadata Metadata) {
588   if (auto ImportAs = Info.SwiftImportAs)
589     D->addAttr(SwiftAttrAttr::Create(S.Context, "import_" + ImportAs.value()));
590 
591   if (auto RetainOp = Info.SwiftRetainOp)
592     D->addAttr(SwiftAttrAttr::Create(S.Context, "retain:" + RetainOp.value()));
593 
594   if (auto ReleaseOp = Info.SwiftReleaseOp)
595     D->addAttr(
596         SwiftAttrAttr::Create(S.Context, "release:" + ReleaseOp.value()));
597 
598   if (auto Copyable = Info.isSwiftCopyable()) {
599     if (!*Copyable)
600       D->addAttr(SwiftAttrAttr::Create(S.Context, "~Copyable"));
601   }
602 
603   if (auto Extensibility = Info.EnumExtensibility) {
604     using api_notes::EnumExtensibilityKind;
605     bool ShouldAddAttribute = (*Extensibility != EnumExtensibilityKind::None);
606     handleAPINotedAttribute<EnumExtensibilityAttr>(
607         S, D, ShouldAddAttribute, Metadata, [&] {
608           EnumExtensibilityAttr::Kind kind;
609           switch (*Extensibility) {
610           case EnumExtensibilityKind::None:
611             llvm_unreachable("remove only");
612           case EnumExtensibilityKind::Open:
613             kind = EnumExtensibilityAttr::Open;
614             break;
615           case EnumExtensibilityKind::Closed:
616             kind = EnumExtensibilityAttr::Closed;
617             break;
618           }
619           return new (S.Context)
620               EnumExtensibilityAttr(S.Context, getPlaceholderAttrInfo(), kind);
621         });
622   }
623 
624   if (auto FlagEnum = Info.isFlagEnum()) {
625     handleAPINotedAttribute<FlagEnumAttr>(S, D, *FlagEnum, Metadata, [&] {
626       return new (S.Context) FlagEnumAttr(S.Context, getPlaceholderAttrInfo());
627     });
628   }
629 
630   // Handle common type information.
631   ProcessAPINotes(S, D, static_cast<const api_notes::CommonTypeInfo &>(Info),
632                   Metadata);
633 }
634 
635 /// Process API notes for a typedef.
636 static void ProcessAPINotes(Sema &S, TypedefNameDecl *D,
637                             const api_notes::TypedefInfo &Info,
638                             VersionedInfoMetadata Metadata) {
639   // swift_wrapper
640   using SwiftWrapperKind = api_notes::SwiftNewTypeKind;
641 
642   if (auto SwiftWrapper = Info.SwiftWrapper) {
643     handleAPINotedAttribute<SwiftNewTypeAttr>(
644         S, D, *SwiftWrapper != SwiftWrapperKind::None, Metadata, [&] {
645           SwiftNewTypeAttr::NewtypeKind Kind;
646           switch (*SwiftWrapper) {
647           case SwiftWrapperKind::None:
648             llvm_unreachable("Shouldn't build an attribute");
649 
650           case SwiftWrapperKind::Struct:
651             Kind = SwiftNewTypeAttr::NK_Struct;
652             break;
653 
654           case SwiftWrapperKind::Enum:
655             Kind = SwiftNewTypeAttr::NK_Enum;
656             break;
657           }
658           AttributeCommonInfo SyntaxInfo{
659               SourceRange(),
660               AttributeCommonInfo::AT_SwiftNewType,
661               {AttributeCommonInfo::AS_GNU, SwiftNewTypeAttr::GNU_swift_wrapper,
662                /*IsAlignas*/ false, /*IsRegularKeywordAttribute*/ false}};
663           return new (S.Context) SwiftNewTypeAttr(S.Context, SyntaxInfo, Kind);
664         });
665   }
666 
667   // Handle common type information.
668   ProcessAPINotes(S, D, static_cast<const api_notes::CommonTypeInfo &>(Info),
669                   Metadata);
670 }
671 
672 /// Process API notes for an Objective-C class or protocol.
673 static void ProcessAPINotes(Sema &S, ObjCContainerDecl *D,
674                             const api_notes::ObjCContextInfo &Info,
675                             VersionedInfoMetadata Metadata) {
676   // Handle common type information.
677   ProcessAPINotes(S, D, static_cast<const api_notes::CommonTypeInfo &>(Info),
678                   Metadata);
679 }
680 
681 /// Process API notes for an Objective-C class.
682 static void ProcessAPINotes(Sema &S, ObjCInterfaceDecl *D,
683                             const api_notes::ObjCContextInfo &Info,
684                             VersionedInfoMetadata Metadata) {
685   if (auto AsNonGeneric = Info.getSwiftImportAsNonGeneric()) {
686     handleAPINotedAttribute<SwiftImportAsNonGenericAttr>(
687         S, D, *AsNonGeneric, Metadata, [&] {
688           return new (S.Context)
689               SwiftImportAsNonGenericAttr(S.Context, getPlaceholderAttrInfo());
690         });
691   }
692 
693   if (auto ObjcMembers = Info.getSwiftObjCMembers()) {
694     handleAPINotedAttribute<SwiftObjCMembersAttr>(
695         S, D, *ObjcMembers, Metadata, [&] {
696           return new (S.Context)
697               SwiftObjCMembersAttr(S.Context, getPlaceholderAttrInfo());
698         });
699   }
700 
701   // Handle information common to Objective-C classes and protocols.
702   ProcessAPINotes(S, static_cast<clang::ObjCContainerDecl *>(D), Info,
703                   Metadata);
704 }
705 
706 /// If we're applying API notes with an active, non-default version, and the
707 /// versioned API notes have a SwiftName but the declaration normally wouldn't
708 /// have one, add a removal attribute to make it clear that the new SwiftName
709 /// attribute only applies to the active version of \p D, not to all versions.
710 ///
711 /// This must be run \em before processing API notes for \p D, because otherwise
712 /// any existing SwiftName attribute will have been packaged up in a
713 /// SwiftVersionedAdditionAttr.
714 template <typename SpecificInfo>
715 static void maybeAttachUnversionedSwiftName(
716     Sema &S, Decl *D,
717     const api_notes::APINotesReader::VersionedInfo<SpecificInfo> Info) {
718   if (D->hasAttr<SwiftNameAttr>())
719     return;
720   if (!Info.getSelected())
721     return;
722 
723   // Is the active slice versioned, and does it set a Swift name?
724   VersionTuple SelectedVersion;
725   SpecificInfo SelectedInfoSlice;
726   std::tie(SelectedVersion, SelectedInfoSlice) = Info[*Info.getSelected()];
727   if (SelectedVersion.empty())
728     return;
729   if (SelectedInfoSlice.SwiftName.empty())
730     return;
731 
732   // Does the unversioned slice /not/ set a Swift name?
733   for (const auto &VersionAndInfoSlice : Info) {
734     if (!VersionAndInfoSlice.first.empty())
735       continue;
736     if (!VersionAndInfoSlice.second.SwiftName.empty())
737       return;
738   }
739 
740   // Then explicitly call that out with a removal attribute.
741   VersionedInfoMetadata DummyFutureMetadata(
742       SelectedVersion, IsActive_t::Inactive, IsSubstitution_t::Replacement);
743   handleAPINotedAttribute<SwiftNameAttr>(
744       S, D, /*add*/ false, DummyFutureMetadata, []() -> SwiftNameAttr * {
745         llvm_unreachable("should not try to add an attribute here");
746       });
747 }
748 
749 /// Processes all versions of versioned API notes.
750 ///
751 /// Just dispatches to the various ProcessAPINotes functions in this file.
752 template <typename SpecificDecl, typename SpecificInfo>
753 static void ProcessVersionedAPINotes(
754     Sema &S, SpecificDecl *D,
755     const api_notes::APINotesReader::VersionedInfo<SpecificInfo> Info) {
756 
757   maybeAttachUnversionedSwiftName(S, D, Info);
758 
759   unsigned Selected = Info.getSelected().value_or(Info.size());
760 
761   VersionTuple Version;
762   SpecificInfo InfoSlice;
763   for (unsigned i = 0, e = Info.size(); i != e; ++i) {
764     std::tie(Version, InfoSlice) = Info[i];
765     auto Active = (i == Selected) ? IsActive_t::Active : IsActive_t::Inactive;
766     auto Replacement = IsSubstitution_t::Original;
767     if (Active == IsActive_t::Inactive && Version.empty()) {
768       Replacement = IsSubstitution_t::Replacement;
769       Version = Info[Selected].first;
770     }
771     ProcessAPINotes(S, D, InfoSlice,
772                     VersionedInfoMetadata(Version, Active, Replacement));
773   }
774 }
775 
776 /// Process API notes that are associated with this declaration, mapping them
777 /// to attributes as appropriate.
778 void Sema::ProcessAPINotes(Decl *D) {
779   if (!D)
780     return;
781 
782   // Globals.
783   if (D->getDeclContext()->isFileContext() ||
784       D->getDeclContext()->isNamespace() ||
785       D->getDeclContext()->isExternCContext() ||
786       D->getDeclContext()->isExternCXXContext()) {
787     std::optional<api_notes::Context> APINotesContext;
788     if (auto NamespaceContext = dyn_cast<NamespaceDecl>(D->getDeclContext())) {
789       for (auto Reader :
790            APINotes.findAPINotes(NamespaceContext->getLocation())) {
791         // Retrieve the context ID for the parent namespace of the decl.
792         std::stack<NamespaceDecl *> NamespaceStack;
793         {
794           for (auto CurrentNamespace = NamespaceContext; CurrentNamespace;
795                CurrentNamespace =
796                    dyn_cast<NamespaceDecl>(CurrentNamespace->getParent())) {
797             if (!CurrentNamespace->isInlineNamespace())
798               NamespaceStack.push(CurrentNamespace);
799           }
800         }
801         std::optional<api_notes::ContextID> NamespaceID;
802         while (!NamespaceStack.empty()) {
803           auto CurrentNamespace = NamespaceStack.top();
804           NamespaceStack.pop();
805           NamespaceID = Reader->lookupNamespaceID(CurrentNamespace->getName(),
806                                                   NamespaceID);
807           if (!NamespaceID)
808             break;
809         }
810         if (NamespaceID)
811           APINotesContext = api_notes::Context(
812               *NamespaceID, api_notes::ContextKind::Namespace);
813       }
814     }
815 
816     // Global variables.
817     if (auto VD = dyn_cast<VarDecl>(D)) {
818       for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
819         auto Info =
820             Reader->lookupGlobalVariable(VD->getName(), APINotesContext);
821         ProcessVersionedAPINotes(*this, VD, Info);
822       }
823 
824       return;
825     }
826 
827     // Global functions.
828     if (auto FD = dyn_cast<FunctionDecl>(D)) {
829       if (FD->getDeclName().isIdentifier()) {
830         for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
831           auto Info =
832               Reader->lookupGlobalFunction(FD->getName(), APINotesContext);
833           ProcessVersionedAPINotes(*this, FD, Info);
834         }
835       }
836 
837       return;
838     }
839 
840     // Objective-C classes.
841     if (auto Class = dyn_cast<ObjCInterfaceDecl>(D)) {
842       for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
843         auto Info = Reader->lookupObjCClassInfo(Class->getName());
844         ProcessVersionedAPINotes(*this, Class, Info);
845       }
846 
847       return;
848     }
849 
850     // Objective-C protocols.
851     if (auto Protocol = dyn_cast<ObjCProtocolDecl>(D)) {
852       for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
853         auto Info = Reader->lookupObjCProtocolInfo(Protocol->getName());
854         ProcessVersionedAPINotes(*this, Protocol, Info);
855       }
856 
857       return;
858     }
859 
860     // Tags
861     if (auto Tag = dyn_cast<TagDecl>(D)) {
862       std::string LookupName = Tag->getName().str();
863 
864       // Use the source location to discern if this Tag is an OPTIONS macro.
865       // For now we would like to limit this trick of looking up the APINote tag
866       // using the EnumDecl's QualType in the case where the enum is anonymous.
867       // This is only being used to support APINotes lookup for C++
868       // NS/CF_OPTIONS when C++-Interop is enabled.
869       std::string MacroName =
870           LookupName.empty() && Tag->getOuterLocStart().isMacroID()
871               ? clang::Lexer::getImmediateMacroName(
872                     Tag->getOuterLocStart(),
873                     Tag->getASTContext().getSourceManager(), LangOpts)
874                     .str()
875               : "";
876 
877       if (LookupName.empty() && isa<clang::EnumDecl>(Tag) &&
878           (MacroName == "CF_OPTIONS" || MacroName == "NS_OPTIONS" ||
879            MacroName == "OBJC_OPTIONS" || MacroName == "SWIFT_OPTIONS")) {
880 
881         clang::QualType T = llvm::cast<clang::EnumDecl>(Tag)->getIntegerType();
882         LookupName = clang::QualType::getAsString(
883             T.split(), getASTContext().getPrintingPolicy());
884       }
885 
886       for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
887         auto Info = Reader->lookupTag(LookupName, APINotesContext);
888         ProcessVersionedAPINotes(*this, Tag, Info);
889       }
890 
891       return;
892     }
893 
894     // Typedefs
895     if (auto Typedef = dyn_cast<TypedefNameDecl>(D)) {
896       for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
897         auto Info = Reader->lookupTypedef(Typedef->getName(), APINotesContext);
898         ProcessVersionedAPINotes(*this, Typedef, Info);
899       }
900 
901       return;
902     }
903   }
904 
905   // Enumerators.
906   if (D->getDeclContext()->getRedeclContext()->isFileContext() ||
907       D->getDeclContext()->getRedeclContext()->isExternCContext()) {
908     if (auto EnumConstant = dyn_cast<EnumConstantDecl>(D)) {
909       for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
910         auto Info = Reader->lookupEnumConstant(EnumConstant->getName());
911         ProcessVersionedAPINotes(*this, EnumConstant, Info);
912       }
913 
914       return;
915     }
916   }
917 
918   if (auto ObjCContainer = dyn_cast<ObjCContainerDecl>(D->getDeclContext())) {
919     // Location function that looks up an Objective-C context.
920     auto GetContext = [&](api_notes::APINotesReader *Reader)
921         -> std::optional<api_notes::ContextID> {
922       if (auto Protocol = dyn_cast<ObjCProtocolDecl>(ObjCContainer)) {
923         if (auto Found = Reader->lookupObjCProtocolID(Protocol->getName()))
924           return *Found;
925 
926         return std::nullopt;
927       }
928 
929       if (auto Impl = dyn_cast<ObjCCategoryImplDecl>(ObjCContainer)) {
930         if (auto Cat = Impl->getCategoryDecl())
931           ObjCContainer = Cat->getClassInterface();
932         else
933           return std::nullopt;
934       }
935 
936       if (auto Category = dyn_cast<ObjCCategoryDecl>(ObjCContainer)) {
937         if (Category->getClassInterface())
938           ObjCContainer = Category->getClassInterface();
939         else
940           return std::nullopt;
941       }
942 
943       if (auto Impl = dyn_cast<ObjCImplDecl>(ObjCContainer)) {
944         if (Impl->getClassInterface())
945           ObjCContainer = Impl->getClassInterface();
946         else
947           return std::nullopt;
948       }
949 
950       if (auto Class = dyn_cast<ObjCInterfaceDecl>(ObjCContainer)) {
951         if (auto Found = Reader->lookupObjCClassID(Class->getName()))
952           return *Found;
953 
954         return std::nullopt;
955       }
956 
957       return std::nullopt;
958     };
959 
960     // Objective-C methods.
961     if (auto Method = dyn_cast<ObjCMethodDecl>(D)) {
962       for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
963         if (auto Context = GetContext(Reader)) {
964           // Map the selector.
965           Selector Sel = Method->getSelector();
966           SmallVector<StringRef, 2> SelPieces;
967           if (Sel.isUnarySelector()) {
968             SelPieces.push_back(Sel.getNameForSlot(0));
969           } else {
970             for (unsigned i = 0, n = Sel.getNumArgs(); i != n; ++i)
971               SelPieces.push_back(Sel.getNameForSlot(i));
972           }
973 
974           api_notes::ObjCSelectorRef SelectorRef;
975           SelectorRef.NumArgs = Sel.getNumArgs();
976           SelectorRef.Identifiers = SelPieces;
977 
978           auto Info = Reader->lookupObjCMethod(*Context, SelectorRef,
979                                                Method->isInstanceMethod());
980           ProcessVersionedAPINotes(*this, Method, Info);
981         }
982       }
983     }
984 
985     // Objective-C properties.
986     if (auto Property = dyn_cast<ObjCPropertyDecl>(D)) {
987       for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
988         if (auto Context = GetContext(Reader)) {
989           bool isInstanceProperty =
990               (Property->getPropertyAttributesAsWritten() &
991                ObjCPropertyAttribute::kind_class) == 0;
992           auto Info = Reader->lookupObjCProperty(*Context, Property->getName(),
993                                                  isInstanceProperty);
994           ProcessVersionedAPINotes(*this, Property, Info);
995         }
996       }
997 
998       return;
999     }
1000   }
1001 }
1002