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