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 "CheckExprLifetime.h"
14 #include "TypeLocBuilder.h"
15 #include "clang/APINotes/APINotesReader.h"
16 #include "clang/AST/Decl.h"
17 #include "clang/AST/DeclCXX.h"
18 #include "clang/AST/DeclObjC.h"
19 #include "clang/AST/TypeLoc.h"
20 #include "clang/Basic/SourceLocation.h"
21 #include "clang/Lex/Lexer.h"
22 #include "clang/Sema/SemaObjC.h"
23 #include "clang/Sema/SemaSwift.h"
24 #include <stack>
25
26 using namespace clang;
27
28 namespace {
29 enum class IsActive_t : bool { Inactive, Active };
30 enum class IsSubstitution_t : bool { Original, Replacement };
31
32 struct VersionedInfoMetadata {
33 /// An empty version refers to unversioned metadata.
34 VersionTuple Version;
35 unsigned IsActive : 1;
36 unsigned IsReplacement : 1;
37
VersionedInfoMetadata__anon3271c6580111::VersionedInfoMetadata38 VersionedInfoMetadata(VersionTuple Version, IsActive_t Active,
39 IsSubstitution_t Replacement)
40 : Version(Version), IsActive(Active == IsActive_t::Active),
41 IsReplacement(Replacement == IsSubstitution_t::Replacement) {}
42 };
43 } // end anonymous namespace
44
45 /// Determine whether this is a multi-level pointer type.
isIndirectPointerType(QualType Type)46 static bool isIndirectPointerType(QualType Type) {
47 QualType Pointee = Type->getPointeeType();
48 if (Pointee.isNull())
49 return false;
50
51 return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() ||
52 Pointee->isMemberPointerType();
53 }
54
applyAPINotesType(Sema & S,Decl * decl,StringRef typeString,VersionedInfoMetadata metadata)55 static void applyAPINotesType(Sema &S, Decl *decl, StringRef typeString,
56 VersionedInfoMetadata metadata) {
57 if (typeString.empty())
58
59 return;
60
61 // Version-independent APINotes add "type" annotations
62 // with a versioned attribute for the client to select and apply.
63 if (S.captureSwiftVersionIndependentAPINotes()) {
64 auto *typeAttr = SwiftTypeAttr::CreateImplicit(S.Context, typeString);
65 auto *versioned = SwiftVersionedAdditionAttr::CreateImplicit(
66 S.Context, metadata.Version, typeAttr, metadata.IsReplacement);
67 decl->addAttr(versioned);
68 } else {
69 if (!metadata.IsActive)
70 return;
71 S.ApplyAPINotesType(decl, typeString);
72 }
73 }
74
75 /// Apply nullability to the given declaration.
applyNullability(Sema & S,Decl * decl,NullabilityKind nullability,VersionedInfoMetadata metadata)76 static void applyNullability(Sema &S, Decl *decl, NullabilityKind nullability,
77 VersionedInfoMetadata metadata) {
78 // Version-independent APINotes add "nullability" annotations
79 // with a versioned attribute for the client to select and apply.
80 if (S.captureSwiftVersionIndependentAPINotes()) {
81 SwiftNullabilityAttr::Kind attrNullabilityKind;
82 switch (nullability) {
83 case NullabilityKind::NonNull:
84 attrNullabilityKind = SwiftNullabilityAttr::Kind::NonNull;
85 break;
86 case NullabilityKind::Nullable:
87 attrNullabilityKind = SwiftNullabilityAttr::Kind::Nullable;
88 break;
89 case NullabilityKind::Unspecified:
90 attrNullabilityKind = SwiftNullabilityAttr::Kind::Unspecified;
91 break;
92 case NullabilityKind::NullableResult:
93 attrNullabilityKind = SwiftNullabilityAttr::Kind::NullableResult;
94 break;
95 }
96 auto *nullabilityAttr =
97 SwiftNullabilityAttr::CreateImplicit(S.Context, attrNullabilityKind);
98 auto *versioned = SwiftVersionedAdditionAttr::CreateImplicit(
99 S.Context, metadata.Version, nullabilityAttr, metadata.IsReplacement);
100 decl->addAttr(versioned);
101 return;
102 } else {
103 if (!metadata.IsActive)
104 return;
105
106 S.ApplyNullability(decl, nullability);
107 }
108 }
109
110 /// Copy a string into ASTContext-allocated memory.
ASTAllocateString(ASTContext & Ctx,StringRef String)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
getPlaceholderAttrInfo()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>
handleAPINotedAttribute(Sema & S,Decl * D,bool IsAddition,VersionedInfoMetadata Metadata,llvm::function_ref<A * ()> CreateAttr,llvm::function_ref<Decl::attr_iterator (const Decl *)> GetExistingAttr)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>
handleAPINotedAttribute(Sema & S,Decl * D,bool ShouldAddAttribute,VersionedInfoMetadata Metadata,llvm::function_ref<A * ()> CreateAttr)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>
handleAPINotedRetainCountAttribute(Sema & S,Decl * D,bool ShouldAddAttribute,VersionedInfoMetadata Metadata)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
handleAPINotedRetainCountConvention(Sema & S,Decl * D,VersionedInfoMetadata Metadata,std::optional<api_notes::RetainCountConventionKind> Convention)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
ProcessAPINotes(Sema & S,Decl * D,const api_notes::CommonEntityInfo & Info,VersionedInfoMetadata Metadata)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 = AP.create(
302 &C.Idents.get("swift_name"), SourceRange(), AttributeScopeInfo(),
303 nullptr, nullptr, nullptr, ParsedAttr::Form::GNU());
304
305 if (!S.Swift().DiagnoseName(D, Info.SwiftName, D->getLocation(), *SNA,
306 /*IsAsync=*/false))
307 return nullptr;
308
309 return new (S.Context)
310 SwiftNameAttr(S.Context, getPlaceholderAttrInfo(),
311 ASTAllocateString(S.Context, Info.SwiftName));
312 });
313 }
314 }
315
ProcessAPINotes(Sema & S,Decl * D,const api_notes::CommonTypeInfo & Info,VersionedInfoMetadata Metadata)316 static void ProcessAPINotes(Sema &S, Decl *D,
317 const api_notes::CommonTypeInfo &Info,
318 VersionedInfoMetadata Metadata) {
319 // swift_bridge
320 if (auto SwiftBridge = Info.getSwiftBridge()) {
321 handleAPINotedAttribute<SwiftBridgeAttr>(
322 S, D, !SwiftBridge->empty(), Metadata, [&] {
323 return new (S.Context)
324 SwiftBridgeAttr(S.Context, getPlaceholderAttrInfo(),
325 ASTAllocateString(S.Context, *SwiftBridge));
326 });
327 }
328
329 // ns_error_domain
330 if (auto NSErrorDomain = Info.getNSErrorDomain()) {
331 handleAPINotedAttribute<NSErrorDomainAttr>(
332 S, D, !NSErrorDomain->empty(), Metadata, [&] {
333 return new (S.Context)
334 NSErrorDomainAttr(S.Context, getPlaceholderAttrInfo(),
335 &S.Context.Idents.get(*NSErrorDomain));
336 });
337 }
338
339 ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(Info),
340 Metadata);
341 }
342
343 /// Check that the replacement type provided by API notes is reasonable.
344 ///
345 /// This is a very weak form of ABI check.
checkAPINotesReplacementType(Sema & S,SourceLocation Loc,QualType OrigType,QualType ReplacementType)346 static bool checkAPINotesReplacementType(Sema &S, SourceLocation Loc,
347 QualType OrigType,
348 QualType ReplacementType) {
349 if (S.Context.getTypeSize(OrigType) !=
350 S.Context.getTypeSize(ReplacementType)) {
351 S.Diag(Loc, diag::err_incompatible_replacement_type)
352 << ReplacementType << OrigType;
353 return true;
354 }
355
356 return false;
357 }
358
ApplyAPINotesType(Decl * D,StringRef TypeString)359 void Sema::ApplyAPINotesType(Decl *D, StringRef TypeString) {
360 if (!TypeString.empty() && ParseTypeFromStringCallback) {
361 auto ParsedType = ParseTypeFromStringCallback(TypeString, "<API Notes>",
362 D->getLocation());
363 if (ParsedType.isUsable()) {
364 QualType Type = Sema::GetTypeFromParser(ParsedType.get());
365 auto TypeInfo = Context.getTrivialTypeSourceInfo(Type, D->getLocation());
366 if (auto Var = dyn_cast<VarDecl>(D)) {
367 // Make adjustments to parameter types.
368 if (isa<ParmVarDecl>(Var)) {
369 Type = ObjC().AdjustParameterTypeForObjCAutoRefCount(
370 Type, D->getLocation(), TypeInfo);
371 Type = Context.getAdjustedParameterType(Type);
372 }
373
374 if (!checkAPINotesReplacementType(*this, Var->getLocation(),
375 Var->getType(), Type)) {
376 Var->setType(Type);
377 Var->setTypeSourceInfo(TypeInfo);
378 }
379 } else if (auto property = dyn_cast<ObjCPropertyDecl>(D)) {
380 if (!checkAPINotesReplacementType(*this, property->getLocation(),
381 property->getType(), Type)) {
382 property->setType(Type, TypeInfo);
383 }
384 } else {
385 llvm_unreachable("API notes allowed a type on an unknown declaration");
386 }
387 }
388 }
389 }
390
ApplyNullability(Decl * D,NullabilityKind Nullability)391 void Sema::ApplyNullability(Decl *D, NullabilityKind Nullability) {
392 auto GetModified =
393 [&](class Decl *D, QualType QT,
394 NullabilityKind Nullability) -> std::optional<QualType> {
395 QualType Original = QT;
396 CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(),
397 isa<ParmVarDecl>(D),
398 /*OverrideExisting=*/true);
399 return (QT.getTypePtr() != Original.getTypePtr()) ? std::optional(QT)
400 : std::nullopt;
401 };
402
403 if (auto Function = dyn_cast<FunctionDecl>(D)) {
404 if (auto Modified =
405 GetModified(D, Function->getReturnType(), Nullability)) {
406 const FunctionType *FnType = Function->getType()->castAs<FunctionType>();
407 if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(FnType))
408 Function->setType(Context.getFunctionType(
409 *Modified, proto->getParamTypes(), proto->getExtProtoInfo()));
410 else
411 Function->setType(
412 Context.getFunctionNoProtoType(*Modified, FnType->getExtInfo()));
413 }
414 } else if (auto Method = dyn_cast<ObjCMethodDecl>(D)) {
415 if (auto Modified = GetModified(D, Method->getReturnType(), Nullability)) {
416 Method->setReturnType(*Modified);
417
418 // Make it a context-sensitive keyword if we can.
419 if (!isIndirectPointerType(*Modified))
420 Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
421 Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
422 }
423 } else if (auto Value = dyn_cast<ValueDecl>(D)) {
424 if (auto Modified = GetModified(D, Value->getType(), Nullability)) {
425 Value->setType(*Modified);
426
427 // Make it a context-sensitive keyword if we can.
428 if (auto Parm = dyn_cast<ParmVarDecl>(D)) {
429 if (Parm->isObjCMethodParameter() && !isIndirectPointerType(*Modified))
430 Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
431 Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
432 }
433 }
434 } else if (auto Property = dyn_cast<ObjCPropertyDecl>(D)) {
435 if (auto Modified = GetModified(D, Property->getType(), Nullability)) {
436 Property->setType(*Modified, Property->getTypeSourceInfo());
437
438 // Make it a property attribute if we can.
439 if (!isIndirectPointerType(*Modified))
440 Property->setPropertyAttributes(
441 ObjCPropertyAttribute::kind_null_resettable);
442 }
443 }
444 }
445
446 /// Process API notes for a variable or property.
ProcessAPINotes(Sema & S,Decl * D,const api_notes::VariableInfo & Info,VersionedInfoMetadata Metadata)447 static void ProcessAPINotes(Sema &S, Decl *D,
448 const api_notes::VariableInfo &Info,
449 VersionedInfoMetadata Metadata) {
450 // Type override.
451 applyAPINotesType(S, D, Info.getType(), Metadata);
452
453 // Nullability.
454 if (auto Nullability = Info.getNullability())
455 applyNullability(S, D, *Nullability, Metadata);
456
457 // Handle common entity information.
458 ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(Info),
459 Metadata);
460 }
461
462 /// Process API notes for a parameter.
ProcessAPINotes(Sema & S,ParmVarDecl * D,const api_notes::ParamInfo & Info,VersionedInfoMetadata Metadata)463 static void ProcessAPINotes(Sema &S, ParmVarDecl *D,
464 const api_notes::ParamInfo &Info,
465 VersionedInfoMetadata Metadata) {
466 // noescape
467 if (auto NoEscape = Info.isNoEscape())
468 handleAPINotedAttribute<NoEscapeAttr>(S, D, *NoEscape, Metadata, [&] {
469 return new (S.Context) NoEscapeAttr(S.Context, getPlaceholderAttrInfo());
470 });
471
472 if (auto Lifetimebound = Info.isLifetimebound())
473 handleAPINotedAttribute<LifetimeBoundAttr>(
474 S, D, *Lifetimebound, Metadata, [&] {
475 return new (S.Context)
476 LifetimeBoundAttr(S.Context, getPlaceholderAttrInfo());
477 });
478
479 // Retain count convention
480 handleAPINotedRetainCountConvention(S, D, Metadata,
481 Info.getRetainCountConvention());
482
483 // Handle common entity information.
484 ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(Info),
485 Metadata);
486 }
487
488 /// Process API notes for a global variable.
ProcessAPINotes(Sema & S,VarDecl * D,const api_notes::GlobalVariableInfo & Info,VersionedInfoMetadata metadata)489 static void ProcessAPINotes(Sema &S, VarDecl *D,
490 const api_notes::GlobalVariableInfo &Info,
491 VersionedInfoMetadata metadata) {
492 // Handle common entity information.
493 ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(Info),
494 metadata);
495 }
496
497 /// Process API notes for a C field.
ProcessAPINotes(Sema & S,FieldDecl * D,const api_notes::FieldInfo & Info,VersionedInfoMetadata metadata)498 static void ProcessAPINotes(Sema &S, FieldDecl *D,
499 const api_notes::FieldInfo &Info,
500 VersionedInfoMetadata metadata) {
501 // Handle common entity information.
502 ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(Info),
503 metadata);
504 }
505
506 /// Process API notes for an Objective-C property.
ProcessAPINotes(Sema & S,ObjCPropertyDecl * D,const api_notes::ObjCPropertyInfo & Info,VersionedInfoMetadata Metadata)507 static void ProcessAPINotes(Sema &S, ObjCPropertyDecl *D,
508 const api_notes::ObjCPropertyInfo &Info,
509 VersionedInfoMetadata Metadata) {
510 // Handle common entity information.
511 ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(Info),
512 Metadata);
513
514 if (auto AsAccessors = Info.getSwiftImportAsAccessors()) {
515 handleAPINotedAttribute<SwiftImportPropertyAsAccessorsAttr>(
516 S, D, *AsAccessors, Metadata, [&] {
517 return new (S.Context) SwiftImportPropertyAsAccessorsAttr(
518 S.Context, getPlaceholderAttrInfo());
519 });
520 }
521 }
522
523 namespace {
524 typedef llvm::PointerUnion<FunctionDecl *, ObjCMethodDecl *> FunctionOrMethod;
525 }
526
527 /// Process API notes for a function or method.
ProcessAPINotes(Sema & S,FunctionOrMethod AnyFunc,const api_notes::FunctionInfo & Info,VersionedInfoMetadata Metadata)528 static void ProcessAPINotes(Sema &S, FunctionOrMethod AnyFunc,
529 const api_notes::FunctionInfo &Info,
530 VersionedInfoMetadata Metadata) {
531 // Find the declaration itself.
532 FunctionDecl *FD = dyn_cast<FunctionDecl *>(AnyFunc);
533 Decl *D = FD;
534 ObjCMethodDecl *MD = nullptr;
535 if (!D) {
536 MD = cast<ObjCMethodDecl *>(AnyFunc);
537 D = MD;
538 }
539
540 assert((FD || MD) && "Expecting Function or ObjCMethod");
541
542 // Nullability of return type.
543 if (Info.NullabilityAudited)
544 applyNullability(S, D, Info.getReturnTypeInfo(), Metadata);
545
546 // Parameters.
547 unsigned NumParams = FD ? FD->getNumParams() : MD->param_size();
548
549 bool AnyTypeChanged = false;
550 for (unsigned I = 0; I != NumParams; ++I) {
551 ParmVarDecl *Param = FD ? FD->getParamDecl(I) : MD->param_begin()[I];
552 QualType ParamTypeBefore = Param->getType();
553
554 if (I < Info.Params.size())
555 ProcessAPINotes(S, Param, Info.Params[I], Metadata);
556
557 // Nullability.
558 if (Info.NullabilityAudited)
559 applyNullability(S, Param, Info.getParamTypeInfo(I), Metadata);
560
561 if (ParamTypeBefore.getAsOpaquePtr() != Param->getType().getAsOpaquePtr())
562 AnyTypeChanged = true;
563 }
564
565 // returns_(un)retained
566 if (!Info.SwiftReturnOwnership.empty())
567 D->addAttr(SwiftAttrAttr::Create(S.Context,
568 "returns_" + Info.SwiftReturnOwnership));
569
570 // Result type override.
571 QualType OverriddenResultType;
572 if (Metadata.IsActive && !Info.ResultType.empty() &&
573 S.ParseTypeFromStringCallback) {
574 auto ParsedType = S.ParseTypeFromStringCallback(
575 Info.ResultType, "<API Notes>", D->getLocation());
576 if (ParsedType.isUsable()) {
577 QualType ResultType = Sema::GetTypeFromParser(ParsedType.get());
578
579 if (MD) {
580 if (!checkAPINotesReplacementType(S, D->getLocation(),
581 MD->getReturnType(), ResultType)) {
582 auto ResultTypeInfo =
583 S.Context.getTrivialTypeSourceInfo(ResultType, D->getLocation());
584 MD->setReturnType(ResultType);
585 MD->setReturnTypeSourceInfo(ResultTypeInfo);
586 }
587 } else if (!checkAPINotesReplacementType(
588 S, FD->getLocation(), FD->getReturnType(), ResultType)) {
589 OverriddenResultType = ResultType;
590 AnyTypeChanged = true;
591 }
592 }
593 }
594
595 // If the result type or any of the parameter types changed for a function
596 // declaration, we have to rebuild the type.
597 if (FD && AnyTypeChanged) {
598 if (const auto *fnProtoType = FD->getType()->getAs<FunctionProtoType>()) {
599 if (OverriddenResultType.isNull())
600 OverriddenResultType = fnProtoType->getReturnType();
601
602 SmallVector<QualType, 4> ParamTypes;
603 for (auto Param : FD->parameters())
604 ParamTypes.push_back(Param->getType());
605
606 FD->setType(S.Context.getFunctionType(OverriddenResultType, ParamTypes,
607 fnProtoType->getExtProtoInfo()));
608 } else if (!OverriddenResultType.isNull()) {
609 const auto *FnNoProtoType = FD->getType()->castAs<FunctionNoProtoType>();
610 FD->setType(S.Context.getFunctionNoProtoType(
611 OverriddenResultType, FnNoProtoType->getExtInfo()));
612 }
613 }
614
615 // Retain count convention
616 handleAPINotedRetainCountConvention(S, D, Metadata,
617 Info.getRetainCountConvention());
618
619 // Handle common entity information.
620 ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(Info),
621 Metadata);
622 }
623
624 /// Process API notes for a C++ method.
ProcessAPINotes(Sema & S,CXXMethodDecl * Method,const api_notes::CXXMethodInfo & Info,VersionedInfoMetadata Metadata)625 static void ProcessAPINotes(Sema &S, CXXMethodDecl *Method,
626 const api_notes::CXXMethodInfo &Info,
627 VersionedInfoMetadata Metadata) {
628 if (Info.This && Info.This->isLifetimebound() &&
629 !sema::implicitObjectParamIsLifetimeBound(Method)) {
630 auto MethodType = Method->getType();
631 auto *attr = ::new (S.Context)
632 LifetimeBoundAttr(S.Context, getPlaceholderAttrInfo());
633 QualType AttributedType =
634 S.Context.getAttributedType(attr, MethodType, MethodType);
635 TypeLocBuilder TLB;
636 TLB.pushFullCopy(Method->getTypeSourceInfo()->getTypeLoc());
637 AttributedTypeLoc TyLoc = TLB.push<AttributedTypeLoc>(AttributedType);
638 TyLoc.setAttr(attr);
639 Method->setType(AttributedType);
640 Method->setTypeSourceInfo(TLB.getTypeSourceInfo(S.Context, AttributedType));
641 }
642
643 ProcessAPINotes(S, (FunctionOrMethod)Method, Info, Metadata);
644 }
645
646 /// Process API notes for a global function.
ProcessAPINotes(Sema & S,FunctionDecl * D,const api_notes::GlobalFunctionInfo & Info,VersionedInfoMetadata Metadata)647 static void ProcessAPINotes(Sema &S, FunctionDecl *D,
648 const api_notes::GlobalFunctionInfo &Info,
649 VersionedInfoMetadata Metadata) {
650 // Handle common function information.
651 ProcessAPINotes(S, FunctionOrMethod(D),
652 static_cast<const api_notes::FunctionInfo &>(Info), Metadata);
653 }
654
655 /// Process API notes for an enumerator.
ProcessAPINotes(Sema & S,EnumConstantDecl * D,const api_notes::EnumConstantInfo & Info,VersionedInfoMetadata Metadata)656 static void ProcessAPINotes(Sema &S, EnumConstantDecl *D,
657 const api_notes::EnumConstantInfo &Info,
658 VersionedInfoMetadata Metadata) {
659 // Handle common information.
660 ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(Info),
661 Metadata);
662 }
663
664 /// Process API notes for an Objective-C method.
ProcessAPINotes(Sema & S,ObjCMethodDecl * D,const api_notes::ObjCMethodInfo & Info,VersionedInfoMetadata Metadata)665 static void ProcessAPINotes(Sema &S, ObjCMethodDecl *D,
666 const api_notes::ObjCMethodInfo &Info,
667 VersionedInfoMetadata Metadata) {
668 // Designated initializers.
669 if (Info.DesignatedInit) {
670 handleAPINotedAttribute<ObjCDesignatedInitializerAttr>(
671 S, D, true, Metadata, [&] {
672 if (ObjCInterfaceDecl *IFace = D->getClassInterface())
673 IFace->setHasDesignatedInitializers();
674
675 return new (S.Context) ObjCDesignatedInitializerAttr(
676 S.Context, getPlaceholderAttrInfo());
677 });
678 }
679
680 // Handle common function information.
681 ProcessAPINotes(S, FunctionOrMethod(D),
682 static_cast<const api_notes::FunctionInfo &>(Info), Metadata);
683 }
684
685 /// Process API notes for a tag.
ProcessAPINotes(Sema & S,TagDecl * D,const api_notes::TagInfo & Info,VersionedInfoMetadata Metadata)686 static void ProcessAPINotes(Sema &S, TagDecl *D, const api_notes::TagInfo &Info,
687 VersionedInfoMetadata Metadata) {
688 if (auto ImportAs = Info.SwiftImportAs)
689 D->addAttr(SwiftAttrAttr::Create(S.Context, "import_" + ImportAs.value()));
690
691 if (auto RetainOp = Info.SwiftRetainOp)
692 D->addAttr(SwiftAttrAttr::Create(S.Context, "retain:" + RetainOp.value()));
693
694 if (auto ReleaseOp = Info.SwiftReleaseOp)
695 D->addAttr(
696 SwiftAttrAttr::Create(S.Context, "release:" + ReleaseOp.value()));
697 if (auto DefaultOwnership = Info.SwiftDefaultOwnership)
698 D->addAttr(SwiftAttrAttr::Create(
699 S.Context, "returned_as_" + DefaultOwnership.value() + "_by_default"));
700
701 if (auto ConformsTo = Info.SwiftConformance)
702 D->addAttr(
703 SwiftAttrAttr::Create(S.Context, "conforms_to:" + ConformsTo.value()));
704
705 if (auto Copyable = Info.isSwiftCopyable()) {
706 if (!*Copyable)
707 D->addAttr(SwiftAttrAttr::Create(S.Context, "~Copyable"));
708 }
709
710 if (auto Escapable = Info.isSwiftEscapable()) {
711 D->addAttr(SwiftAttrAttr::Create(S.Context,
712 *Escapable ? "Escapable" : "~Escapable"));
713 }
714
715 if (auto Extensibility = Info.EnumExtensibility) {
716 using api_notes::EnumExtensibilityKind;
717 bool ShouldAddAttribute = (*Extensibility != EnumExtensibilityKind::None);
718 handleAPINotedAttribute<EnumExtensibilityAttr>(
719 S, D, ShouldAddAttribute, Metadata, [&] {
720 EnumExtensibilityAttr::Kind kind;
721 switch (*Extensibility) {
722 case EnumExtensibilityKind::None:
723 llvm_unreachable("remove only");
724 case EnumExtensibilityKind::Open:
725 kind = EnumExtensibilityAttr::Open;
726 break;
727 case EnumExtensibilityKind::Closed:
728 kind = EnumExtensibilityAttr::Closed;
729 break;
730 }
731 return new (S.Context)
732 EnumExtensibilityAttr(S.Context, getPlaceholderAttrInfo(), kind);
733 });
734 }
735
736 if (auto FlagEnum = Info.isFlagEnum()) {
737 handleAPINotedAttribute<FlagEnumAttr>(S, D, *FlagEnum, Metadata, [&] {
738 return new (S.Context) FlagEnumAttr(S.Context, getPlaceholderAttrInfo());
739 });
740 }
741
742 // Handle common type information.
743 ProcessAPINotes(S, D, static_cast<const api_notes::CommonTypeInfo &>(Info),
744 Metadata);
745 }
746
747 /// Process API notes for a typedef.
ProcessAPINotes(Sema & S,TypedefNameDecl * D,const api_notes::TypedefInfo & Info,VersionedInfoMetadata Metadata)748 static void ProcessAPINotes(Sema &S, TypedefNameDecl *D,
749 const api_notes::TypedefInfo &Info,
750 VersionedInfoMetadata Metadata) {
751 // swift_wrapper
752 using SwiftWrapperKind = api_notes::SwiftNewTypeKind;
753
754 if (auto SwiftWrapper = Info.SwiftWrapper) {
755 handleAPINotedAttribute<SwiftNewTypeAttr>(
756 S, D, *SwiftWrapper != SwiftWrapperKind::None, Metadata, [&] {
757 SwiftNewTypeAttr::NewtypeKind Kind;
758 switch (*SwiftWrapper) {
759 case SwiftWrapperKind::None:
760 llvm_unreachable("Shouldn't build an attribute");
761
762 case SwiftWrapperKind::Struct:
763 Kind = SwiftNewTypeAttr::NK_Struct;
764 break;
765
766 case SwiftWrapperKind::Enum:
767 Kind = SwiftNewTypeAttr::NK_Enum;
768 break;
769 }
770 AttributeCommonInfo SyntaxInfo{
771 SourceRange(),
772 AttributeCommonInfo::AT_SwiftNewType,
773 {AttributeCommonInfo::AS_GNU, SwiftNewTypeAttr::GNU_swift_wrapper,
774 /*IsAlignas*/ false, /*IsRegularKeywordAttribute*/ false}};
775 return new (S.Context) SwiftNewTypeAttr(S.Context, SyntaxInfo, Kind);
776 });
777 }
778
779 // Handle common type information.
780 ProcessAPINotes(S, D, static_cast<const api_notes::CommonTypeInfo &>(Info),
781 Metadata);
782 }
783
784 /// Process API notes for an Objective-C class or protocol.
ProcessAPINotes(Sema & S,ObjCContainerDecl * D,const api_notes::ContextInfo & Info,VersionedInfoMetadata Metadata)785 static void ProcessAPINotes(Sema &S, ObjCContainerDecl *D,
786 const api_notes::ContextInfo &Info,
787 VersionedInfoMetadata Metadata) {
788 // Handle common type information.
789 ProcessAPINotes(S, D, static_cast<const api_notes::CommonTypeInfo &>(Info),
790 Metadata);
791 }
792
793 /// Process API notes for an Objective-C class.
ProcessAPINotes(Sema & S,ObjCInterfaceDecl * D,const api_notes::ContextInfo & Info,VersionedInfoMetadata Metadata)794 static void ProcessAPINotes(Sema &S, ObjCInterfaceDecl *D,
795 const api_notes::ContextInfo &Info,
796 VersionedInfoMetadata Metadata) {
797 if (auto AsNonGeneric = Info.getSwiftImportAsNonGeneric()) {
798 handleAPINotedAttribute<SwiftImportAsNonGenericAttr>(
799 S, D, *AsNonGeneric, Metadata, [&] {
800 return new (S.Context)
801 SwiftImportAsNonGenericAttr(S.Context, getPlaceholderAttrInfo());
802 });
803 }
804
805 if (auto ObjcMembers = Info.getSwiftObjCMembers()) {
806 handleAPINotedAttribute<SwiftObjCMembersAttr>(
807 S, D, *ObjcMembers, Metadata, [&] {
808 return new (S.Context)
809 SwiftObjCMembersAttr(S.Context, getPlaceholderAttrInfo());
810 });
811 }
812
813 // Handle information common to Objective-C classes and protocols.
814 ProcessAPINotes(S, static_cast<clang::ObjCContainerDecl *>(D), Info,
815 Metadata);
816 }
817
818 /// If we're applying API notes with an active, non-default version, and the
819 /// versioned API notes have a SwiftName but the declaration normally wouldn't
820 /// have one, add a removal attribute to make it clear that the new SwiftName
821 /// attribute only applies to the active version of \p D, not to all versions.
822 ///
823 /// This must be run \em before processing API notes for \p D, because otherwise
824 /// any existing SwiftName attribute will have been packaged up in a
825 /// SwiftVersionedAdditionAttr.
826 template <typename SpecificInfo>
maybeAttachUnversionedSwiftName(Sema & S,Decl * D,const api_notes::APINotesReader::VersionedInfo<SpecificInfo> Info)827 static void maybeAttachUnversionedSwiftName(
828 Sema &S, Decl *D,
829 const api_notes::APINotesReader::VersionedInfo<SpecificInfo> Info) {
830 if (D->hasAttr<SwiftNameAttr>())
831 return;
832 if (!Info.getSelected())
833 return;
834
835 // Is the active slice versioned, and does it set a Swift name?
836 VersionTuple SelectedVersion;
837 SpecificInfo SelectedInfoSlice;
838 std::tie(SelectedVersion, SelectedInfoSlice) = Info[*Info.getSelected()];
839 if (SelectedVersion.empty())
840 return;
841 if (SelectedInfoSlice.SwiftName.empty())
842 return;
843
844 // Does the unversioned slice /not/ set a Swift name?
845 for (const auto &VersionAndInfoSlice : Info) {
846 if (!VersionAndInfoSlice.first.empty())
847 continue;
848 if (!VersionAndInfoSlice.second.SwiftName.empty())
849 return;
850 }
851
852 // Then explicitly call that out with a removal attribute.
853 VersionedInfoMetadata DummyFutureMetadata(
854 SelectedVersion, IsActive_t::Inactive, IsSubstitution_t::Replacement);
855 handleAPINotedAttribute<SwiftNameAttr>(
856 S, D, /*add*/ false, DummyFutureMetadata, []() -> SwiftNameAttr * {
857 llvm_unreachable("should not try to add an attribute here");
858 });
859 }
860
861 /// Processes all versions of versioned API notes.
862 ///
863 /// Just dispatches to the various ProcessAPINotes functions in this file.
864 template <typename SpecificDecl, typename SpecificInfo>
ProcessVersionedAPINotes(Sema & S,SpecificDecl * D,const api_notes::APINotesReader::VersionedInfo<SpecificInfo> Info)865 static void ProcessVersionedAPINotes(
866 Sema &S, SpecificDecl *D,
867 const api_notes::APINotesReader::VersionedInfo<SpecificInfo> Info) {
868
869 if (!S.captureSwiftVersionIndependentAPINotes())
870 maybeAttachUnversionedSwiftName(S, D, Info);
871
872 unsigned Selected = Info.getSelected().value_or(Info.size());
873
874 VersionTuple Version;
875 SpecificInfo InfoSlice;
876 for (unsigned i = 0, e = Info.size(); i != e; ++i) {
877 std::tie(Version, InfoSlice) = Info[i];
878 auto Active = (i == Selected) ? IsActive_t::Active : IsActive_t::Inactive;
879 auto Replacement = IsSubstitution_t::Original;
880
881 // When collection all APINotes as version-independent,
882 // capture all as inactive and defer to the client select the
883 // right one.
884 if (S.captureSwiftVersionIndependentAPINotes()) {
885 Active = IsActive_t::Inactive;
886 Replacement = IsSubstitution_t::Original;
887 } else if (Active == IsActive_t::Inactive && Version.empty()) {
888 Replacement = IsSubstitution_t::Replacement;
889 Version = Info[Selected].first;
890 }
891
892 ProcessAPINotes(S, D, InfoSlice,
893 VersionedInfoMetadata(Version, Active, Replacement));
894 }
895 }
896
897 static std::optional<api_notes::Context>
UnwindNamespaceContext(DeclContext * DC,api_notes::APINotesManager & APINotes)898 UnwindNamespaceContext(DeclContext *DC, api_notes::APINotesManager &APINotes) {
899 if (auto NamespaceContext = dyn_cast<NamespaceDecl>(DC)) {
900 for (auto Reader : APINotes.findAPINotes(NamespaceContext->getLocation())) {
901 // Retrieve the context ID for the parent namespace of the decl.
902 std::stack<NamespaceDecl *> NamespaceStack;
903 {
904 for (auto CurrentNamespace = NamespaceContext; CurrentNamespace;
905 CurrentNamespace =
906 dyn_cast<NamespaceDecl>(CurrentNamespace->getParent())) {
907 if (!CurrentNamespace->isInlineNamespace())
908 NamespaceStack.push(CurrentNamespace);
909 }
910 }
911 std::optional<api_notes::ContextID> NamespaceID;
912 while (!NamespaceStack.empty()) {
913 auto CurrentNamespace = NamespaceStack.top();
914 NamespaceStack.pop();
915 NamespaceID =
916 Reader->lookupNamespaceID(CurrentNamespace->getName(), NamespaceID);
917 if (!NamespaceID)
918 return std::nullopt;
919 }
920 if (NamespaceID)
921 return api_notes::Context(*NamespaceID,
922 api_notes::ContextKind::Namespace);
923 }
924 }
925 return std::nullopt;
926 }
927
928 static std::optional<api_notes::Context>
UnwindTagContext(TagDecl * DC,api_notes::APINotesManager & APINotes)929 UnwindTagContext(TagDecl *DC, api_notes::APINotesManager &APINotes) {
930 assert(DC && "tag context must not be null");
931 for (auto Reader : APINotes.findAPINotes(DC->getLocation())) {
932 // Retrieve the context ID for the parent tag of the decl.
933 std::stack<TagDecl *> TagStack;
934 {
935 for (auto CurrentTag = DC; CurrentTag;
936 CurrentTag = dyn_cast<TagDecl>(CurrentTag->getParent()))
937 TagStack.push(CurrentTag);
938 }
939 assert(!TagStack.empty());
940 std::optional<api_notes::Context> Ctx =
941 UnwindNamespaceContext(TagStack.top()->getDeclContext(), APINotes);
942 while (!TagStack.empty()) {
943 auto CurrentTag = TagStack.top();
944 TagStack.pop();
945 auto CtxID = Reader->lookupTagID(CurrentTag->getName(), Ctx);
946 if (!CtxID)
947 return std::nullopt;
948 Ctx = api_notes::Context(*CtxID, api_notes::ContextKind::Tag);
949 }
950 return Ctx;
951 }
952 return std::nullopt;
953 }
954
955 /// Process API notes that are associated with this declaration, mapping them
956 /// to attributes as appropriate.
ProcessAPINotes(Decl * D)957 void Sema::ProcessAPINotes(Decl *D) {
958 if (!D)
959 return;
960
961 auto *DC = D->getDeclContext();
962 // Globals.
963 if (DC->isFileContext() || DC->isNamespace() || DC->isExternCContext() ||
964 DC->isExternCXXContext()) {
965 std::optional<api_notes::Context> APINotesContext =
966 UnwindNamespaceContext(DC, APINotes);
967 // Global variables.
968 if (auto VD = dyn_cast<VarDecl>(D)) {
969 for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
970 auto Info =
971 Reader->lookupGlobalVariable(VD->getName(), APINotesContext);
972 ProcessVersionedAPINotes(*this, VD, Info);
973 }
974
975 return;
976 }
977
978 // Global functions.
979 if (auto FD = dyn_cast<FunctionDecl>(D)) {
980 if (FD->getDeclName().isIdentifier()) {
981 for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
982 auto Info =
983 Reader->lookupGlobalFunction(FD->getName(), APINotesContext);
984 ProcessVersionedAPINotes(*this, FD, Info);
985 }
986 }
987
988 return;
989 }
990
991 // Objective-C classes.
992 if (auto Class = dyn_cast<ObjCInterfaceDecl>(D)) {
993 for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
994 auto Info = Reader->lookupObjCClassInfo(Class->getName());
995 ProcessVersionedAPINotes(*this, Class, Info);
996 }
997
998 return;
999 }
1000
1001 // Objective-C protocols.
1002 if (auto Protocol = dyn_cast<ObjCProtocolDecl>(D)) {
1003 for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
1004 auto Info = Reader->lookupObjCProtocolInfo(Protocol->getName());
1005 ProcessVersionedAPINotes(*this, Protocol, Info);
1006 }
1007
1008 return;
1009 }
1010
1011 // Tags
1012 if (auto Tag = dyn_cast<TagDecl>(D)) {
1013 // Determine the name of the entity to search for. If this is an
1014 // anonymous tag that gets its linked name from a typedef, look for the
1015 // typedef name. This allows tag-specific information to be added
1016 // to the declaration.
1017 std::string LookupName;
1018 if (auto typedefName = Tag->getTypedefNameForAnonDecl())
1019 LookupName = typedefName->getName().str();
1020 else
1021 LookupName = Tag->getName().str();
1022
1023 // Use the source location to discern if this Tag is an OPTIONS macro.
1024 // For now we would like to limit this trick of looking up the APINote tag
1025 // using the EnumDecl's QualType in the case where the enum is anonymous.
1026 // This is only being used to support APINotes lookup for C++
1027 // NS/CF_OPTIONS when C++-Interop is enabled.
1028 std::string MacroName =
1029 LookupName.empty() && Tag->getOuterLocStart().isMacroID()
1030 ? clang::Lexer::getImmediateMacroName(
1031 Tag->getOuterLocStart(),
1032 Tag->getASTContext().getSourceManager(), LangOpts)
1033 .str()
1034 : "";
1035
1036 if (LookupName.empty() && isa<clang::EnumDecl>(Tag) &&
1037 (MacroName == "CF_OPTIONS" || MacroName == "NS_OPTIONS" ||
1038 MacroName == "OBJC_OPTIONS" || MacroName == "SWIFT_OPTIONS")) {
1039
1040 clang::QualType T = llvm::cast<clang::EnumDecl>(Tag)->getIntegerType();
1041 LookupName = clang::QualType::getAsString(
1042 T.split(), getASTContext().getPrintingPolicy());
1043 }
1044
1045 for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
1046 if (auto ParentTag = dyn_cast<TagDecl>(Tag->getDeclContext()))
1047 APINotesContext = UnwindTagContext(ParentTag, APINotes);
1048 auto Info = Reader->lookupTag(LookupName, APINotesContext);
1049 ProcessVersionedAPINotes(*this, Tag, Info);
1050 }
1051
1052 return;
1053 }
1054
1055 // Typedefs
1056 if (auto Typedef = dyn_cast<TypedefNameDecl>(D)) {
1057 for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
1058 auto Info = Reader->lookupTypedef(Typedef->getName(), APINotesContext);
1059 ProcessVersionedAPINotes(*this, Typedef, Info);
1060 }
1061
1062 return;
1063 }
1064 }
1065
1066 // Enumerators.
1067 if (DC->getRedeclContext()->isFileContext() ||
1068 DC->getRedeclContext()->isExternCContext()) {
1069 if (auto EnumConstant = dyn_cast<EnumConstantDecl>(D)) {
1070 for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
1071 auto Info = Reader->lookupEnumConstant(EnumConstant->getName());
1072 ProcessVersionedAPINotes(*this, EnumConstant, Info);
1073 }
1074
1075 return;
1076 }
1077 }
1078
1079 if (auto ObjCContainer = dyn_cast<ObjCContainerDecl>(DC)) {
1080 // Location function that looks up an Objective-C context.
1081 auto GetContext = [&](api_notes::APINotesReader *Reader)
1082 -> std::optional<api_notes::ContextID> {
1083 if (auto Protocol = dyn_cast<ObjCProtocolDecl>(ObjCContainer)) {
1084 if (auto Found = Reader->lookupObjCProtocolID(Protocol->getName()))
1085 return *Found;
1086
1087 return std::nullopt;
1088 }
1089
1090 if (auto Impl = dyn_cast<ObjCCategoryImplDecl>(ObjCContainer)) {
1091 if (auto Cat = Impl->getCategoryDecl())
1092 ObjCContainer = Cat->getClassInterface();
1093 else
1094 return std::nullopt;
1095 }
1096
1097 if (auto Category = dyn_cast<ObjCCategoryDecl>(ObjCContainer)) {
1098 if (Category->getClassInterface())
1099 ObjCContainer = Category->getClassInterface();
1100 else
1101 return std::nullopt;
1102 }
1103
1104 if (auto Impl = dyn_cast<ObjCImplDecl>(ObjCContainer)) {
1105 if (Impl->getClassInterface())
1106 ObjCContainer = Impl->getClassInterface();
1107 else
1108 return std::nullopt;
1109 }
1110
1111 if (auto Class = dyn_cast<ObjCInterfaceDecl>(ObjCContainer)) {
1112 if (auto Found = Reader->lookupObjCClassID(Class->getName()))
1113 return *Found;
1114
1115 return std::nullopt;
1116 }
1117
1118 return std::nullopt;
1119 };
1120
1121 // Objective-C methods.
1122 if (auto Method = dyn_cast<ObjCMethodDecl>(D)) {
1123 for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
1124 if (auto Context = GetContext(Reader)) {
1125 // Map the selector.
1126 Selector Sel = Method->getSelector();
1127 SmallVector<StringRef, 2> SelPieces;
1128 if (Sel.isUnarySelector()) {
1129 SelPieces.push_back(Sel.getNameForSlot(0));
1130 } else {
1131 for (unsigned i = 0, n = Sel.getNumArgs(); i != n; ++i)
1132 SelPieces.push_back(Sel.getNameForSlot(i));
1133 }
1134
1135 api_notes::ObjCSelectorRef SelectorRef;
1136 SelectorRef.NumArgs = Sel.getNumArgs();
1137 SelectorRef.Identifiers = SelPieces;
1138
1139 auto Info = Reader->lookupObjCMethod(*Context, SelectorRef,
1140 Method->isInstanceMethod());
1141 ProcessVersionedAPINotes(*this, Method, Info);
1142 }
1143 }
1144 }
1145
1146 // Objective-C properties.
1147 if (auto Property = dyn_cast<ObjCPropertyDecl>(D)) {
1148 for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
1149 if (auto Context = GetContext(Reader)) {
1150 bool isInstanceProperty =
1151 (Property->getPropertyAttributesAsWritten() &
1152 ObjCPropertyAttribute::kind_class) == 0;
1153 auto Info = Reader->lookupObjCProperty(*Context, Property->getName(),
1154 isInstanceProperty);
1155 ProcessVersionedAPINotes(*this, Property, Info);
1156 }
1157 }
1158
1159 return;
1160 }
1161 }
1162
1163 if (auto TagContext = dyn_cast<TagDecl>(DC)) {
1164 if (auto CXXMethod = dyn_cast<CXXMethodDecl>(D)) {
1165 if (!isa<CXXConstructorDecl>(CXXMethod) &&
1166 !isa<CXXDestructorDecl>(CXXMethod) &&
1167 !isa<CXXConversionDecl>(CXXMethod) &&
1168 !CXXMethod->isOverloadedOperator()) {
1169 for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
1170 if (auto Context = UnwindTagContext(TagContext, APINotes)) {
1171 auto Info =
1172 Reader->lookupCXXMethod(Context->id, CXXMethod->getName());
1173 ProcessVersionedAPINotes(*this, CXXMethod, Info);
1174 }
1175 }
1176 }
1177 }
1178
1179 if (auto Field = dyn_cast<FieldDecl>(D)) {
1180 if (!Field->isUnnamedBitField() && !Field->isAnonymousStructOrUnion()) {
1181 for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
1182 if (auto Context = UnwindTagContext(TagContext, APINotes)) {
1183 auto Info = Reader->lookupField(Context->id, Field->getName());
1184 ProcessVersionedAPINotes(*this, Field, Info);
1185 }
1186 }
1187 }
1188 }
1189
1190 if (auto Tag = dyn_cast<TagDecl>(D)) {
1191 for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
1192 if (auto Context = UnwindTagContext(TagContext, APINotes)) {
1193 auto Info = Reader->lookupTag(Tag->getName(), Context);
1194 ProcessVersionedAPINotes(*this, Tag, Info);
1195 }
1196 }
1197 }
1198 }
1199 }
1200