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