xref: /llvm-project/clang/lib/Sema/SemaAPINotes.cpp (revision 3f33c4c14e79e68007cf1460e4a0e606eb199da5)
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               /*Environment=*/nullptr);
274         },
275         [](const Decl *D) {
276           return llvm::find_if(D->attrs(), [](const Attr *next) -> bool {
277             if (const auto *AA = dyn_cast<AvailabilityAttr>(next))
278               if (const auto *II = AA->getPlatform())
279                 return II->isStr("swift");
280             return false;
281           });
282         });
283   }
284 
285   // swift_private
286   if (auto SwiftPrivate = Info.isSwiftPrivate()) {
287     handleAPINotedAttribute<SwiftPrivateAttr>(
288         S, D, *SwiftPrivate, Metadata, [&] {
289           return new (S.Context)
290               SwiftPrivateAttr(S.Context, getPlaceholderAttrInfo());
291         });
292   }
293 
294   // swift_name
295   if (!Info.SwiftName.empty()) {
296     handleAPINotedAttribute<SwiftNameAttr>(
297         S, D, true, Metadata, [&]() -> SwiftNameAttr * {
298           AttributeFactory AF{};
299           AttributePool AP{AF};
300           auto &C = S.getASTContext();
301           ParsedAttr *SNA =
302               AP.create(&C.Idents.get("swift_name"), SourceRange(), nullptr,
303                         SourceLocation(), nullptr, nullptr, nullptr,
304                         ParsedAttr::Form::GNU());
305 
306           if (!S.DiagnoseSwiftName(D, Info.SwiftName, D->getLocation(), *SNA,
307                                    /*IsAsync=*/false))
308             return nullptr;
309 
310           return new (S.Context)
311               SwiftNameAttr(S.Context, getPlaceholderAttrInfo(),
312                             ASTAllocateString(S.Context, Info.SwiftName));
313         });
314   }
315 }
316 
317 static void ProcessAPINotes(Sema &S, Decl *D,
318                             const api_notes::CommonTypeInfo &Info,
319                             VersionedInfoMetadata Metadata) {
320   // swift_bridge
321   if (auto SwiftBridge = Info.getSwiftBridge()) {
322     handleAPINotedAttribute<SwiftBridgeAttr>(
323         S, D, !SwiftBridge->empty(), Metadata, [&] {
324           return new (S.Context)
325               SwiftBridgeAttr(S.Context, getPlaceholderAttrInfo(),
326                               ASTAllocateString(S.Context, *SwiftBridge));
327         });
328   }
329 
330   // ns_error_domain
331   if (auto NSErrorDomain = Info.getNSErrorDomain()) {
332     handleAPINotedAttribute<NSErrorDomainAttr>(
333         S, D, !NSErrorDomain->empty(), Metadata, [&] {
334           return new (S.Context)
335               NSErrorDomainAttr(S.Context, getPlaceholderAttrInfo(),
336                                 &S.Context.Idents.get(*NSErrorDomain));
337         });
338   }
339 
340   ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(Info),
341                   Metadata);
342 }
343 
344 /// Check that the replacement type provided by API notes is reasonable.
345 ///
346 /// This is a very weak form of ABI check.
347 static bool checkAPINotesReplacementType(Sema &S, SourceLocation Loc,
348                                          QualType OrigType,
349                                          QualType ReplacementType) {
350   if (S.Context.getTypeSize(OrigType) !=
351       S.Context.getTypeSize(ReplacementType)) {
352     S.Diag(Loc, diag::err_incompatible_replacement_type)
353         << ReplacementType << OrigType;
354     return true;
355   }
356 
357   return false;
358 }
359 
360 /// Process API notes for a variable or property.
361 static void ProcessAPINotes(Sema &S, Decl *D,
362                             const api_notes::VariableInfo &Info,
363                             VersionedInfoMetadata Metadata) {
364   // Type override.
365   if (Metadata.IsActive && !Info.getType().empty() &&
366       S.ParseTypeFromStringCallback) {
367     auto ParsedType = S.ParseTypeFromStringCallback(
368         Info.getType(), "<API Notes>", D->getLocation());
369     if (ParsedType.isUsable()) {
370       QualType Type = Sema::GetTypeFromParser(ParsedType.get());
371       auto TypeInfo =
372           S.Context.getTrivialTypeSourceInfo(Type, D->getLocation());
373 
374       if (auto Var = dyn_cast<VarDecl>(D)) {
375         // Make adjustments to parameter types.
376         if (isa<ParmVarDecl>(Var)) {
377           Type = S.ObjC().AdjustParameterTypeForObjCAutoRefCount(
378               Type, D->getLocation(), TypeInfo);
379           Type = S.Context.getAdjustedParameterType(Type);
380         }
381 
382         if (!checkAPINotesReplacementType(S, Var->getLocation(), Var->getType(),
383                                           Type)) {
384           Var->setType(Type);
385           Var->setTypeSourceInfo(TypeInfo);
386         }
387       } else if (auto Property = dyn_cast<ObjCPropertyDecl>(D)) {
388         if (!checkAPINotesReplacementType(S, Property->getLocation(),
389                                           Property->getType(), Type))
390           Property->setType(Type, TypeInfo);
391 
392       } else
393         llvm_unreachable("API notes allowed a type on an unknown declaration");
394     }
395   }
396 
397   // Nullability.
398   if (auto Nullability = Info.getNullability())
399     applyNullability(S, D, *Nullability, Metadata);
400 
401   // Handle common entity information.
402   ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(Info),
403                   Metadata);
404 }
405 
406 /// Process API notes for a parameter.
407 static void ProcessAPINotes(Sema &S, ParmVarDecl *D,
408                             const api_notes::ParamInfo &Info,
409                             VersionedInfoMetadata Metadata) {
410   // noescape
411   if (auto NoEscape = Info.isNoEscape())
412     handleAPINotedAttribute<NoEscapeAttr>(S, D, *NoEscape, Metadata, [&] {
413       return new (S.Context) NoEscapeAttr(S.Context, getPlaceholderAttrInfo());
414     });
415 
416   // Retain count convention
417   handleAPINotedRetainCountConvention(S, D, Metadata,
418                                       Info.getRetainCountConvention());
419 
420   // Handle common entity information.
421   ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(Info),
422                   Metadata);
423 }
424 
425 /// Process API notes for a global variable.
426 static void ProcessAPINotes(Sema &S, VarDecl *D,
427                             const api_notes::GlobalVariableInfo &Info,
428                             VersionedInfoMetadata metadata) {
429   // Handle common entity information.
430   ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(Info),
431                   metadata);
432 }
433 
434 /// Process API notes for an Objective-C property.
435 static void ProcessAPINotes(Sema &S, ObjCPropertyDecl *D,
436                             const api_notes::ObjCPropertyInfo &Info,
437                             VersionedInfoMetadata Metadata) {
438   // Handle common entity information.
439   ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(Info),
440                   Metadata);
441 
442   if (auto AsAccessors = Info.getSwiftImportAsAccessors()) {
443     handleAPINotedAttribute<SwiftImportPropertyAsAccessorsAttr>(
444         S, D, *AsAccessors, Metadata, [&] {
445           return new (S.Context) SwiftImportPropertyAsAccessorsAttr(
446               S.Context, getPlaceholderAttrInfo());
447         });
448   }
449 }
450 
451 namespace {
452 typedef llvm::PointerUnion<FunctionDecl *, ObjCMethodDecl *> FunctionOrMethod;
453 }
454 
455 /// Process API notes for a function or method.
456 static void ProcessAPINotes(Sema &S, FunctionOrMethod AnyFunc,
457                             const api_notes::FunctionInfo &Info,
458                             VersionedInfoMetadata Metadata) {
459   // Find the declaration itself.
460   FunctionDecl *FD = AnyFunc.dyn_cast<FunctionDecl *>();
461   Decl *D = FD;
462   ObjCMethodDecl *MD = nullptr;
463   if (!D) {
464     MD = AnyFunc.get<ObjCMethodDecl *>();
465     D = MD;
466   }
467 
468   assert((FD || MD) && "Expecting Function or ObjCMethod");
469 
470   // Nullability of return type.
471   if (Info.NullabilityAudited)
472     applyNullability(S, D, Info.getReturnTypeInfo(), Metadata);
473 
474   // Parameters.
475   unsigned NumParams = FD ? FD->getNumParams() : MD->param_size();
476 
477   bool AnyTypeChanged = false;
478   for (unsigned I = 0; I != NumParams; ++I) {
479     ParmVarDecl *Param = FD ? FD->getParamDecl(I) : MD->param_begin()[I];
480     QualType ParamTypeBefore = Param->getType();
481 
482     if (I < Info.Params.size())
483       ProcessAPINotes(S, Param, Info.Params[I], Metadata);
484 
485     // Nullability.
486     if (Info.NullabilityAudited)
487       applyNullability(S, Param, Info.getParamTypeInfo(I), Metadata);
488 
489     if (ParamTypeBefore.getAsOpaquePtr() != Param->getType().getAsOpaquePtr())
490       AnyTypeChanged = true;
491   }
492 
493   // Result type override.
494   QualType OverriddenResultType;
495   if (Metadata.IsActive && !Info.ResultType.empty() &&
496       S.ParseTypeFromStringCallback) {
497     auto ParsedType = S.ParseTypeFromStringCallback(
498         Info.ResultType, "<API Notes>", D->getLocation());
499     if (ParsedType.isUsable()) {
500       QualType ResultType = Sema::GetTypeFromParser(ParsedType.get());
501 
502       if (MD) {
503         if (!checkAPINotesReplacementType(S, D->getLocation(),
504                                           MD->getReturnType(), ResultType)) {
505           auto ResultTypeInfo =
506               S.Context.getTrivialTypeSourceInfo(ResultType, D->getLocation());
507           MD->setReturnType(ResultType);
508           MD->setReturnTypeSourceInfo(ResultTypeInfo);
509         }
510       } else if (!checkAPINotesReplacementType(
511                      S, FD->getLocation(), FD->getReturnType(), ResultType)) {
512         OverriddenResultType = ResultType;
513         AnyTypeChanged = true;
514       }
515     }
516   }
517 
518   // If the result type or any of the parameter types changed for a function
519   // declaration, we have to rebuild the type.
520   if (FD && AnyTypeChanged) {
521     if (const auto *fnProtoType = FD->getType()->getAs<FunctionProtoType>()) {
522       if (OverriddenResultType.isNull())
523         OverriddenResultType = fnProtoType->getReturnType();
524 
525       SmallVector<QualType, 4> ParamTypes;
526       for (auto Param : FD->parameters())
527         ParamTypes.push_back(Param->getType());
528 
529       FD->setType(S.Context.getFunctionType(OverriddenResultType, ParamTypes,
530                                             fnProtoType->getExtProtoInfo()));
531     } else if (!OverriddenResultType.isNull()) {
532       const auto *FnNoProtoType = FD->getType()->castAs<FunctionNoProtoType>();
533       FD->setType(S.Context.getFunctionNoProtoType(
534           OverriddenResultType, FnNoProtoType->getExtInfo()));
535     }
536   }
537 
538   // Retain count convention
539   handleAPINotedRetainCountConvention(S, D, Metadata,
540                                       Info.getRetainCountConvention());
541 
542   // Handle common entity information.
543   ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(Info),
544                   Metadata);
545 }
546 
547 /// Process API notes for a global function.
548 static void ProcessAPINotes(Sema &S, FunctionDecl *D,
549                             const api_notes::GlobalFunctionInfo &Info,
550                             VersionedInfoMetadata Metadata) {
551   // Handle common function information.
552   ProcessAPINotes(S, FunctionOrMethod(D),
553                   static_cast<const api_notes::FunctionInfo &>(Info), Metadata);
554 }
555 
556 /// Process API notes for an enumerator.
557 static void ProcessAPINotes(Sema &S, EnumConstantDecl *D,
558                             const api_notes::EnumConstantInfo &Info,
559                             VersionedInfoMetadata Metadata) {
560   // Handle common information.
561   ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(Info),
562                   Metadata);
563 }
564 
565 /// Process API notes for an Objective-C method.
566 static void ProcessAPINotes(Sema &S, ObjCMethodDecl *D,
567                             const api_notes::ObjCMethodInfo &Info,
568                             VersionedInfoMetadata Metadata) {
569   // Designated initializers.
570   if (Info.DesignatedInit) {
571     handleAPINotedAttribute<ObjCDesignatedInitializerAttr>(
572         S, D, true, Metadata, [&] {
573           if (ObjCInterfaceDecl *IFace = D->getClassInterface())
574             IFace->setHasDesignatedInitializers();
575 
576           return new (S.Context) ObjCDesignatedInitializerAttr(
577               S.Context, getPlaceholderAttrInfo());
578         });
579   }
580 
581   // Handle common function information.
582   ProcessAPINotes(S, FunctionOrMethod(D),
583                   static_cast<const api_notes::FunctionInfo &>(Info), Metadata);
584 }
585 
586 /// Process API notes for a tag.
587 static void ProcessAPINotes(Sema &S, TagDecl *D, const api_notes::TagInfo &Info,
588                             VersionedInfoMetadata Metadata) {
589   if (auto ImportAs = Info.SwiftImportAs)
590     D->addAttr(SwiftAttrAttr::Create(S.Context, "import_" + ImportAs.value()));
591 
592   if (auto RetainOp = Info.SwiftRetainOp)
593     D->addAttr(SwiftAttrAttr::Create(S.Context, "retain:" + RetainOp.value()));
594 
595   if (auto ReleaseOp = Info.SwiftReleaseOp)
596     D->addAttr(
597         SwiftAttrAttr::Create(S.Context, "release:" + ReleaseOp.value()));
598 
599   if (auto Copyable = Info.isSwiftCopyable()) {
600     if (!*Copyable)
601       D->addAttr(SwiftAttrAttr::Create(S.Context, "~Copyable"));
602   }
603 
604   if (auto Extensibility = Info.EnumExtensibility) {
605     using api_notes::EnumExtensibilityKind;
606     bool ShouldAddAttribute = (*Extensibility != EnumExtensibilityKind::None);
607     handleAPINotedAttribute<EnumExtensibilityAttr>(
608         S, D, ShouldAddAttribute, Metadata, [&] {
609           EnumExtensibilityAttr::Kind kind;
610           switch (*Extensibility) {
611           case EnumExtensibilityKind::None:
612             llvm_unreachable("remove only");
613           case EnumExtensibilityKind::Open:
614             kind = EnumExtensibilityAttr::Open;
615             break;
616           case EnumExtensibilityKind::Closed:
617             kind = EnumExtensibilityAttr::Closed;
618             break;
619           }
620           return new (S.Context)
621               EnumExtensibilityAttr(S.Context, getPlaceholderAttrInfo(), kind);
622         });
623   }
624 
625   if (auto FlagEnum = Info.isFlagEnum()) {
626     handleAPINotedAttribute<FlagEnumAttr>(S, D, *FlagEnum, Metadata, [&] {
627       return new (S.Context) FlagEnumAttr(S.Context, getPlaceholderAttrInfo());
628     });
629   }
630 
631   // Handle common type information.
632   ProcessAPINotes(S, D, static_cast<const api_notes::CommonTypeInfo &>(Info),
633                   Metadata);
634 }
635 
636 /// Process API notes for a typedef.
637 static void ProcessAPINotes(Sema &S, TypedefNameDecl *D,
638                             const api_notes::TypedefInfo &Info,
639                             VersionedInfoMetadata Metadata) {
640   // swift_wrapper
641   using SwiftWrapperKind = api_notes::SwiftNewTypeKind;
642 
643   if (auto SwiftWrapper = Info.SwiftWrapper) {
644     handleAPINotedAttribute<SwiftNewTypeAttr>(
645         S, D, *SwiftWrapper != SwiftWrapperKind::None, Metadata, [&] {
646           SwiftNewTypeAttr::NewtypeKind Kind;
647           switch (*SwiftWrapper) {
648           case SwiftWrapperKind::None:
649             llvm_unreachable("Shouldn't build an attribute");
650 
651           case SwiftWrapperKind::Struct:
652             Kind = SwiftNewTypeAttr::NK_Struct;
653             break;
654 
655           case SwiftWrapperKind::Enum:
656             Kind = SwiftNewTypeAttr::NK_Enum;
657             break;
658           }
659           AttributeCommonInfo SyntaxInfo{
660               SourceRange(),
661               AttributeCommonInfo::AT_SwiftNewType,
662               {AttributeCommonInfo::AS_GNU, SwiftNewTypeAttr::GNU_swift_wrapper,
663                /*IsAlignas*/ false, /*IsRegularKeywordAttribute*/ false}};
664           return new (S.Context) SwiftNewTypeAttr(S.Context, SyntaxInfo, Kind);
665         });
666   }
667 
668   // Handle common type information.
669   ProcessAPINotes(S, D, static_cast<const api_notes::CommonTypeInfo &>(Info),
670                   Metadata);
671 }
672 
673 /// Process API notes for an Objective-C class or protocol.
674 static void ProcessAPINotes(Sema &S, ObjCContainerDecl *D,
675                             const api_notes::ObjCContextInfo &Info,
676                             VersionedInfoMetadata Metadata) {
677   // Handle common type information.
678   ProcessAPINotes(S, D, static_cast<const api_notes::CommonTypeInfo &>(Info),
679                   Metadata);
680 }
681 
682 /// Process API notes for an Objective-C class.
683 static void ProcessAPINotes(Sema &S, ObjCInterfaceDecl *D,
684                             const api_notes::ObjCContextInfo &Info,
685                             VersionedInfoMetadata Metadata) {
686   if (auto AsNonGeneric = Info.getSwiftImportAsNonGeneric()) {
687     handleAPINotedAttribute<SwiftImportAsNonGenericAttr>(
688         S, D, *AsNonGeneric, Metadata, [&] {
689           return new (S.Context)
690               SwiftImportAsNonGenericAttr(S.Context, getPlaceholderAttrInfo());
691         });
692   }
693 
694   if (auto ObjcMembers = Info.getSwiftObjCMembers()) {
695     handleAPINotedAttribute<SwiftObjCMembersAttr>(
696         S, D, *ObjcMembers, Metadata, [&] {
697           return new (S.Context)
698               SwiftObjCMembersAttr(S.Context, getPlaceholderAttrInfo());
699         });
700   }
701 
702   // Handle information common to Objective-C classes and protocols.
703   ProcessAPINotes(S, static_cast<clang::ObjCContainerDecl *>(D), Info,
704                   Metadata);
705 }
706 
707 /// If we're applying API notes with an active, non-default version, and the
708 /// versioned API notes have a SwiftName but the declaration normally wouldn't
709 /// have one, add a removal attribute to make it clear that the new SwiftName
710 /// attribute only applies to the active version of \p D, not to all versions.
711 ///
712 /// This must be run \em before processing API notes for \p D, because otherwise
713 /// any existing SwiftName attribute will have been packaged up in a
714 /// SwiftVersionedAdditionAttr.
715 template <typename SpecificInfo>
716 static void maybeAttachUnversionedSwiftName(
717     Sema &S, Decl *D,
718     const api_notes::APINotesReader::VersionedInfo<SpecificInfo> Info) {
719   if (D->hasAttr<SwiftNameAttr>())
720     return;
721   if (!Info.getSelected())
722     return;
723 
724   // Is the active slice versioned, and does it set a Swift name?
725   VersionTuple SelectedVersion;
726   SpecificInfo SelectedInfoSlice;
727   std::tie(SelectedVersion, SelectedInfoSlice) = Info[*Info.getSelected()];
728   if (SelectedVersion.empty())
729     return;
730   if (SelectedInfoSlice.SwiftName.empty())
731     return;
732 
733   // Does the unversioned slice /not/ set a Swift name?
734   for (const auto &VersionAndInfoSlice : Info) {
735     if (!VersionAndInfoSlice.first.empty())
736       continue;
737     if (!VersionAndInfoSlice.second.SwiftName.empty())
738       return;
739   }
740 
741   // Then explicitly call that out with a removal attribute.
742   VersionedInfoMetadata DummyFutureMetadata(
743       SelectedVersion, IsActive_t::Inactive, IsSubstitution_t::Replacement);
744   handleAPINotedAttribute<SwiftNameAttr>(
745       S, D, /*add*/ false, DummyFutureMetadata, []() -> SwiftNameAttr * {
746         llvm_unreachable("should not try to add an attribute here");
747       });
748 }
749 
750 /// Processes all versions of versioned API notes.
751 ///
752 /// Just dispatches to the various ProcessAPINotes functions in this file.
753 template <typename SpecificDecl, typename SpecificInfo>
754 static void ProcessVersionedAPINotes(
755     Sema &S, SpecificDecl *D,
756     const api_notes::APINotesReader::VersionedInfo<SpecificInfo> Info) {
757 
758   maybeAttachUnversionedSwiftName(S, D, Info);
759 
760   unsigned Selected = Info.getSelected().value_or(Info.size());
761 
762   VersionTuple Version;
763   SpecificInfo InfoSlice;
764   for (unsigned i = 0, e = Info.size(); i != e; ++i) {
765     std::tie(Version, InfoSlice) = Info[i];
766     auto Active = (i == Selected) ? IsActive_t::Active : IsActive_t::Inactive;
767     auto Replacement = IsSubstitution_t::Original;
768     if (Active == IsActive_t::Inactive && Version.empty()) {
769       Replacement = IsSubstitution_t::Replacement;
770       Version = Info[Selected].first;
771     }
772     ProcessAPINotes(S, D, InfoSlice,
773                     VersionedInfoMetadata(Version, Active, Replacement));
774   }
775 }
776 
777 /// Process API notes that are associated with this declaration, mapping them
778 /// to attributes as appropriate.
779 void Sema::ProcessAPINotes(Decl *D) {
780   if (!D)
781     return;
782 
783   // Globals.
784   if (D->getDeclContext()->isFileContext() ||
785       D->getDeclContext()->isNamespace() ||
786       D->getDeclContext()->isExternCContext() ||
787       D->getDeclContext()->isExternCXXContext()) {
788     std::optional<api_notes::Context> APINotesContext;
789     if (auto NamespaceContext = dyn_cast<NamespaceDecl>(D->getDeclContext())) {
790       for (auto Reader :
791            APINotes.findAPINotes(NamespaceContext->getLocation())) {
792         // Retrieve the context ID for the parent namespace of the decl.
793         std::stack<NamespaceDecl *> NamespaceStack;
794         {
795           for (auto CurrentNamespace = NamespaceContext; CurrentNamespace;
796                CurrentNamespace =
797                    dyn_cast<NamespaceDecl>(CurrentNamespace->getParent())) {
798             if (!CurrentNamespace->isInlineNamespace())
799               NamespaceStack.push(CurrentNamespace);
800           }
801         }
802         std::optional<api_notes::ContextID> NamespaceID;
803         while (!NamespaceStack.empty()) {
804           auto CurrentNamespace = NamespaceStack.top();
805           NamespaceStack.pop();
806           NamespaceID = Reader->lookupNamespaceID(CurrentNamespace->getName(),
807                                                   NamespaceID);
808           if (!NamespaceID)
809             break;
810         }
811         if (NamespaceID)
812           APINotesContext = api_notes::Context(
813               *NamespaceID, api_notes::ContextKind::Namespace);
814       }
815     }
816 
817     // Global variables.
818     if (auto VD = dyn_cast<VarDecl>(D)) {
819       for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
820         auto Info =
821             Reader->lookupGlobalVariable(VD->getName(), APINotesContext);
822         ProcessVersionedAPINotes(*this, VD, Info);
823       }
824 
825       return;
826     }
827 
828     // Global functions.
829     if (auto FD = dyn_cast<FunctionDecl>(D)) {
830       if (FD->getDeclName().isIdentifier()) {
831         for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
832           auto Info =
833               Reader->lookupGlobalFunction(FD->getName(), APINotesContext);
834           ProcessVersionedAPINotes(*this, FD, Info);
835         }
836       }
837 
838       return;
839     }
840 
841     // Objective-C classes.
842     if (auto Class = dyn_cast<ObjCInterfaceDecl>(D)) {
843       for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
844         auto Info = Reader->lookupObjCClassInfo(Class->getName());
845         ProcessVersionedAPINotes(*this, Class, Info);
846       }
847 
848       return;
849     }
850 
851     // Objective-C protocols.
852     if (auto Protocol = dyn_cast<ObjCProtocolDecl>(D)) {
853       for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
854         auto Info = Reader->lookupObjCProtocolInfo(Protocol->getName());
855         ProcessVersionedAPINotes(*this, Protocol, Info);
856       }
857 
858       return;
859     }
860 
861     // Tags
862     if (auto Tag = dyn_cast<TagDecl>(D)) {
863       std::string LookupName = Tag->getName().str();
864 
865       // Use the source location to discern if this Tag is an OPTIONS macro.
866       // For now we would like to limit this trick of looking up the APINote tag
867       // using the EnumDecl's QualType in the case where the enum is anonymous.
868       // This is only being used to support APINotes lookup for C++
869       // NS/CF_OPTIONS when C++-Interop is enabled.
870       std::string MacroName =
871           LookupName.empty() && Tag->getOuterLocStart().isMacroID()
872               ? clang::Lexer::getImmediateMacroName(
873                     Tag->getOuterLocStart(),
874                     Tag->getASTContext().getSourceManager(), LangOpts)
875                     .str()
876               : "";
877 
878       if (LookupName.empty() && isa<clang::EnumDecl>(Tag) &&
879           (MacroName == "CF_OPTIONS" || MacroName == "NS_OPTIONS" ||
880            MacroName == "OBJC_OPTIONS" || MacroName == "SWIFT_OPTIONS")) {
881 
882         clang::QualType T = llvm::cast<clang::EnumDecl>(Tag)->getIntegerType();
883         LookupName = clang::QualType::getAsString(
884             T.split(), getASTContext().getPrintingPolicy());
885       }
886 
887       for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
888         auto Info = Reader->lookupTag(LookupName, APINotesContext);
889         ProcessVersionedAPINotes(*this, Tag, Info);
890       }
891 
892       return;
893     }
894 
895     // Typedefs
896     if (auto Typedef = dyn_cast<TypedefNameDecl>(D)) {
897       for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
898         auto Info = Reader->lookupTypedef(Typedef->getName(), APINotesContext);
899         ProcessVersionedAPINotes(*this, Typedef, Info);
900       }
901 
902       return;
903     }
904   }
905 
906   // Enumerators.
907   if (D->getDeclContext()->getRedeclContext()->isFileContext() ||
908       D->getDeclContext()->getRedeclContext()->isExternCContext()) {
909     if (auto EnumConstant = dyn_cast<EnumConstantDecl>(D)) {
910       for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
911         auto Info = Reader->lookupEnumConstant(EnumConstant->getName());
912         ProcessVersionedAPINotes(*this, EnumConstant, Info);
913       }
914 
915       return;
916     }
917   }
918 
919   if (auto ObjCContainer = dyn_cast<ObjCContainerDecl>(D->getDeclContext())) {
920     // Location function that looks up an Objective-C context.
921     auto GetContext = [&](api_notes::APINotesReader *Reader)
922         -> std::optional<api_notes::ContextID> {
923       if (auto Protocol = dyn_cast<ObjCProtocolDecl>(ObjCContainer)) {
924         if (auto Found = Reader->lookupObjCProtocolID(Protocol->getName()))
925           return *Found;
926 
927         return std::nullopt;
928       }
929 
930       if (auto Impl = dyn_cast<ObjCCategoryImplDecl>(ObjCContainer)) {
931         if (auto Cat = Impl->getCategoryDecl())
932           ObjCContainer = Cat->getClassInterface();
933         else
934           return std::nullopt;
935       }
936 
937       if (auto Category = dyn_cast<ObjCCategoryDecl>(ObjCContainer)) {
938         if (Category->getClassInterface())
939           ObjCContainer = Category->getClassInterface();
940         else
941           return std::nullopt;
942       }
943 
944       if (auto Impl = dyn_cast<ObjCImplDecl>(ObjCContainer)) {
945         if (Impl->getClassInterface())
946           ObjCContainer = Impl->getClassInterface();
947         else
948           return std::nullopt;
949       }
950 
951       if (auto Class = dyn_cast<ObjCInterfaceDecl>(ObjCContainer)) {
952         if (auto Found = Reader->lookupObjCClassID(Class->getName()))
953           return *Found;
954 
955         return std::nullopt;
956       }
957 
958       return std::nullopt;
959     };
960 
961     // Objective-C methods.
962     if (auto Method = dyn_cast<ObjCMethodDecl>(D)) {
963       for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
964         if (auto Context = GetContext(Reader)) {
965           // Map the selector.
966           Selector Sel = Method->getSelector();
967           SmallVector<StringRef, 2> SelPieces;
968           if (Sel.isUnarySelector()) {
969             SelPieces.push_back(Sel.getNameForSlot(0));
970           } else {
971             for (unsigned i = 0, n = Sel.getNumArgs(); i != n; ++i)
972               SelPieces.push_back(Sel.getNameForSlot(i));
973           }
974 
975           api_notes::ObjCSelectorRef SelectorRef;
976           SelectorRef.NumArgs = Sel.getNumArgs();
977           SelectorRef.Identifiers = SelPieces;
978 
979           auto Info = Reader->lookupObjCMethod(*Context, SelectorRef,
980                                                Method->isInstanceMethod());
981           ProcessVersionedAPINotes(*this, Method, Info);
982         }
983       }
984     }
985 
986     // Objective-C properties.
987     if (auto Property = dyn_cast<ObjCPropertyDecl>(D)) {
988       for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
989         if (auto Context = GetContext(Reader)) {
990           bool isInstanceProperty =
991               (Property->getPropertyAttributesAsWritten() &
992                ObjCPropertyAttribute::kind_class) == 0;
993           auto Info = Reader->lookupObjCProperty(*Context, Property->getName(),
994                                                  isInstanceProperty);
995           ProcessVersionedAPINotes(*this, Property, Info);
996         }
997       }
998 
999       return;
1000     }
1001   }
1002 }
1003