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