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
26using namespace clang;
27
28namespace {
29enum class IsActive_t : bool { Inactive, Active };
30enum class IsSubstitution_t : bool { Original, Replacement };
31
32struct VersionedInfoMetadata {
33 /// An empty version refers to unversioned metadata.
34 VersionTuple Version;
35 unsigned IsActive : 1;
36 unsigned IsReplacement : 1;
37
38 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.
46static 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
55static 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(Ctx&: S.Context, TypeString: typeString);
65 auto *versioned = SwiftVersionedAdditionAttr::CreateImplicit(
66 Ctx&: S.Context, Version: metadata.Version, AdditionalAttr: typeAttr, IsReplacedByActive: metadata.IsReplacement);
67 decl->addAttr(A: versioned);
68 } else {
69 if (!metadata.IsActive)
70 return;
71 S.ApplyAPINotesType(D: decl, TypeString: typeString);
72 }
73}
74
75/// Apply nullability to the given declaration.
76static 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(Ctx&: S.Context, Kind: attrNullabilityKind);
98 auto *versioned = SwiftVersionedAdditionAttr::CreateImplicit(
99 Ctx&: S.Context, Version: metadata.Version, AdditionalAttr: nullabilityAttr, IsReplacedByActive: metadata.IsReplacement);
100 decl->addAttr(A: versioned);
101 return;
102 } else {
103 if (!metadata.IsActive)
104 return;
105
106 S.ApplyNullability(D: decl, Nullability: nullability);
107 }
108}
109
110/// Copy a string into ASTContext-allocated memory.
111static StringRef ASTAllocateString(ASTContext &Ctx, StringRef String) {
112 void *mem = Ctx.Allocate(Size: String.size(), Align: alignof(char *));
113 memcpy(dest: mem, src: String.data(), n: String.size());
114 return StringRef(static_cast<char *>(mem), String.size());
115}
116
117static AttributeCommonInfo getPlaceholderAttrInfo() {
118 return AttributeCommonInfo(SourceRange(),
119 AttributeCommonInfo::UnknownAttribute,
120 {AttributeCommonInfo::AS_GNU,
121 /*Spelling*/ 0, /*IsAlignas*/ false,
122 /*IsRegularKeywordAttribute*/ false});
123}
124
125namespace {
126template <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.
139template <typename A>
140void 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 Ctx&: S.Context, Version: Metadata.Version, AdditionalAttr: *Existing, /*IsReplacedByActive*/ true);
151
152 D->getAttrs().erase(CI: Existing);
153 D->addAttr(A: 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(A: 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(A: 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(A: Versioned);
179 }
180}
181
182template <typename A>
183void 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
194template <typename A>
195static 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>(Val: Next) ||
206 isa<CFReturnsNotRetainedAttr>(Val: Next) ||
207 isa<NSReturnsRetainedAttr>(Val: Next) ||
208 isa<NSReturnsNotRetainedAttr>(Val: Next) ||
209 isa<CFAuditedTransferAttr>(Val: Next);
210 });
211 });
212}
213
214static 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>(Val: D)) {
222 handleAPINotedRetainCountAttribute<CFUnknownTransferAttr>(
223 S, D, /*shouldAddAttribute*/ ShouldAddAttribute: true, Metadata);
224 } else {
225 handleAPINotedRetainCountAttribute<CFReturnsRetainedAttr>(
226 S, D, /*shouldAddAttribute*/ ShouldAddAttribute: false, Metadata);
227 }
228 break;
229 case api_notes::RetainCountConventionKind::CFReturnsRetained:
230 handleAPINotedRetainCountAttribute<CFReturnsRetainedAttr>(
231 S, D, /*shouldAddAttribute*/ ShouldAddAttribute: true, Metadata);
232 break;
233 case api_notes::RetainCountConventionKind::CFReturnsNotRetained:
234 handleAPINotedRetainCountAttribute<CFReturnsNotRetainedAttr>(
235 S, D, /*shouldAddAttribute*/ ShouldAddAttribute: true, Metadata);
236 break;
237 case api_notes::RetainCountConventionKind::NSReturnsRetained:
238 handleAPINotedRetainCountAttribute<NSReturnsRetainedAttr>(
239 S, D, /*shouldAddAttribute*/ ShouldAddAttribute: true, Metadata);
240 break;
241 case api_notes::RetainCountConventionKind::NSReturnsNotRetained:
242 handleAPINotedRetainCountAttribute<NSReturnsNotRetainedAttr>(
243 S, D, /*shouldAddAttribute*/ ShouldAddAttribute: true, Metadata);
244 break;
245 }
246}
247
248static 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, ShouldAddAttribute: true, Metadata, CreateAttr: [&] {
254 return new (S.Context)
255 UnavailableAttr(S.Context, getPlaceholderAttrInfo(),
256 ASTAllocateString(Ctx&: S.Context, String: Info.UnavailableMsg));
257 });
258 }
259
260 if (Info.UnavailableInSwift) {
261 handleAPINotedAttribute<AvailabilityAttr>(
262 S, D, IsAddition: true, Metadata,
263 CreateAttr: [&] {
264 return new (S.Context) AvailabilityAttr(
265 S.Context, getPlaceholderAttrInfo(),
266 &S.Context.Idents.get(Name: "swift"), VersionTuple(), VersionTuple(),
267 VersionTuple(),
268 /*Unavailable=*/true,
269 ASTAllocateString(Ctx&: S.Context, String: Info.UnavailableMsg),
270 /*Strict=*/false,
271 /*Replacement=*/StringRef(),
272 /*Priority=*/Sema::AP_Explicit,
273 /*Environment=*/nullptr);
274 },
275 GetExistingAttr: [](const Decl *D) {
276 return llvm::find_if(Range: D->attrs(), P: [](const Attr *next) -> bool {
277 if (const auto *AA = dyn_cast<AvailabilityAttr>(Val: next))
278 if (const auto *II = AA->getPlatform())
279 return II->isStr(Str: "swift");
280 return false;
281 });
282 });
283 }
284
285 // swift_private
286 if (auto SwiftPrivate = Info.isSwiftPrivate()) {
287 handleAPINotedAttribute<SwiftPrivateAttr>(
288 S, D, ShouldAddAttribute: *SwiftPrivate, Metadata, CreateAttr: [&] {
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, ShouldAddAttribute: true, Metadata, CreateAttr: [&]() -> SwiftNameAttr * {
298 AttributeFactory AF{};
299 AttributePool AP{AF};
300 auto &C = S.getASTContext();
301 ParsedAttr *SNA = AP.create(
302 attrName: &C.Idents.get(Name: "swift_name"), attrRange: SourceRange(), scope: AttributeScopeInfo(),
303 Param1: nullptr, Param2: nullptr, Param3: nullptr, form: ParsedAttr::Form::GNU());
304
305 if (!S.Swift().DiagnoseName(D, Name: Info.SwiftName, Loc: D->getLocation(), AL: *SNA,
306 /*IsAsync=*/false))
307 return nullptr;
308
309 return new (S.Context)
310 SwiftNameAttr(S.Context, getPlaceholderAttrInfo(),
311 ASTAllocateString(Ctx&: S.Context, String: Info.SwiftName));
312 });
313 }
314}
315
316static 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, ShouldAddAttribute: !SwiftBridge->empty(), Metadata, CreateAttr: [&] {
323 return new (S.Context)
324 SwiftBridgeAttr(S.Context, getPlaceholderAttrInfo(),
325 ASTAllocateString(Ctx&: S.Context, String: *SwiftBridge));
326 });
327 }
328
329 // ns_error_domain
330 if (auto NSErrorDomain = Info.getNSErrorDomain()) {
331 handleAPINotedAttribute<NSErrorDomainAttr>(
332 S, D, ShouldAddAttribute: !NSErrorDomain->empty(), Metadata, CreateAttr: [&] {
333 return new (S.Context)
334 NSErrorDomainAttr(S.Context, getPlaceholderAttrInfo(),
335 &S.Context.Idents.get(Name: *NSErrorDomain));
336 });
337 }
338
339 ProcessAPINotes(S, D, Info: 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.
346static bool checkAPINotesReplacementType(Sema &S, SourceLocation Loc,
347 QualType OrigType,
348 QualType ReplacementType) {
349 if (S.Context.getTypeSize(T: OrigType) !=
350 S.Context.getTypeSize(T: ReplacementType)) {
351 S.Diag(Loc, DiagID: diag::err_incompatible_replacement_type)
352 << ReplacementType << OrigType;
353 return true;
354 }
355
356 return false;
357}
358
359void 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(Ty: ParsedType.get());
365 auto TypeInfo = Context.getTrivialTypeSourceInfo(T: Type, Loc: D->getLocation());
366 if (auto Var = dyn_cast<VarDecl>(Val: D)) {
367 // Make adjustments to parameter types.
368 if (isa<ParmVarDecl>(Val: Var)) {
369 Type = ObjC().AdjustParameterTypeForObjCAutoRefCount(
370 T: Type, NameLoc: D->getLocation(), TSInfo: TypeInfo);
371 Type = Context.getAdjustedParameterType(T: Type);
372 }
373
374 if (!checkAPINotesReplacementType(S&: *this, Loc: Var->getLocation(),
375 OrigType: Var->getType(), ReplacementType: Type)) {
376 Var->setType(Type);
377 Var->setTypeSourceInfo(TypeInfo);
378 }
379 } else if (auto property = dyn_cast<ObjCPropertyDecl>(Val: D)) {
380 if (!checkAPINotesReplacementType(S&: *this, Loc: property->getLocation(),
381 OrigType: property->getType(), ReplacementType: Type)) {
382 property->setType(T: Type, TSI: TypeInfo);
383 }
384 } else {
385 llvm_unreachable("API notes allowed a type on an unknown declaration");
386 }
387 }
388 }
389}
390
391void 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(Type&: QT, Nullability, DiagLoc: D->getLocation(),
397 AllowArrayTypes: isa<ParmVarDecl>(Val: 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>(Val: 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>(Val: FnType))
408 Function->setType(Context.getFunctionType(
409 ResultTy: *Modified, Args: proto->getParamTypes(), EPI: proto->getExtProtoInfo()));
410 else
411 Function->setType(
412 Context.getFunctionNoProtoType(ResultTy: *Modified, Info: FnType->getExtInfo()));
413 }
414 } else if (auto Method = dyn_cast<ObjCMethodDecl>(Val: 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(Type: *Modified))
420 Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
421 Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
422 }
423 } else if (auto Value = dyn_cast<ValueDecl>(Val: 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>(Val: D)) {
429 if (Parm->isObjCMethodParameter() && !isIndirectPointerType(Type: *Modified))
430 Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier(
431 Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability));
432 }
433 }
434 } else if (auto Property = dyn_cast<ObjCPropertyDecl>(Val: D)) {
435 if (auto Modified = GetModified(D, Property->getType(), Nullability)) {
436 Property->setType(T: *Modified, TSI: Property->getTypeSourceInfo());
437
438 // Make it a property attribute if we can.
439 if (!isIndirectPointerType(Type: *Modified))
440 Property->setPropertyAttributes(
441 ObjCPropertyAttribute::kind_null_resettable);
442 }
443 }
444}
445
446/// Process API notes for a variable or property.
447static void ProcessAPINotes(Sema &S, Decl *D,
448 const api_notes::VariableInfo &Info,
449 VersionedInfoMetadata Metadata) {
450 // Type override.
451 applyAPINotesType(S, decl: D, typeString: Info.getType(), metadata: Metadata);
452
453 // Nullability.
454 if (auto Nullability = Info.getNullability())
455 applyNullability(S, decl: D, nullability: *Nullability, metadata: Metadata);
456
457 // Handle common entity information.
458 ProcessAPINotes(S, D, Info: static_cast<const api_notes::CommonEntityInfo &>(Info),
459 Metadata);
460}
461
462/// Process API notes for a parameter.
463static 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, ShouldAddAttribute: *NoEscape, Metadata, CreateAttr: [&] {
469 return new (S.Context) NoEscapeAttr(S.Context, getPlaceholderAttrInfo());
470 });
471
472 if (auto Lifetimebound = Info.isLifetimebound())
473 handleAPINotedAttribute<LifetimeBoundAttr>(
474 S, D, ShouldAddAttribute: *Lifetimebound, Metadata, CreateAttr: [&] {
475 return new (S.Context)
476 LifetimeBoundAttr(S.Context, getPlaceholderAttrInfo());
477 });
478
479 // Retain count convention
480 handleAPINotedRetainCountConvention(S, D, Metadata,
481 Convention: Info.getRetainCountConvention());
482
483 // Handle common entity information.
484 ProcessAPINotes(S, D, Info: static_cast<const api_notes::VariableInfo &>(Info),
485 Metadata);
486}
487
488/// Process API notes for a global variable.
489static void ProcessAPINotes(Sema &S, VarDecl *D,
490 const api_notes::GlobalVariableInfo &Info,
491 VersionedInfoMetadata metadata) {
492 // Handle common entity information.
493 ProcessAPINotes(S, D, Info: static_cast<const api_notes::VariableInfo &>(Info),
494 Metadata: metadata);
495}
496
497/// Process API notes for a C field.
498static void ProcessAPINotes(Sema &S, FieldDecl *D,
499 const api_notes::FieldInfo &Info,
500 VersionedInfoMetadata metadata) {
501 // Handle common entity information.
502 ProcessAPINotes(S, D, Info: static_cast<const api_notes::VariableInfo &>(Info),
503 Metadata: metadata);
504}
505
506/// Process API notes for an Objective-C property.
507static void ProcessAPINotes(Sema &S, ObjCPropertyDecl *D,
508 const api_notes::ObjCPropertyInfo &Info,
509 VersionedInfoMetadata Metadata) {
510 // Handle common entity information.
511 ProcessAPINotes(S, D, Info: static_cast<const api_notes::VariableInfo &>(Info),
512 Metadata);
513
514 if (auto AsAccessors = Info.getSwiftImportAsAccessors()) {
515 handleAPINotedAttribute<SwiftImportPropertyAsAccessorsAttr>(
516 S, D, ShouldAddAttribute: *AsAccessors, Metadata, CreateAttr: [&] {
517 return new (S.Context) SwiftImportPropertyAsAccessorsAttr(
518 S.Context, getPlaceholderAttrInfo());
519 });
520 }
521}
522
523namespace {
524typedef llvm::PointerUnion<FunctionDecl *, ObjCMethodDecl *> FunctionOrMethod;
525}
526
527/// Process API notes for a function or method.
528static 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 *>(Val&: AnyFunc);
533 Decl *D = FD;
534 ObjCMethodDecl *MD = nullptr;
535 if (!D) {
536 MD = cast<ObjCMethodDecl *>(Val&: 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, decl: D, nullability: Info.getReturnTypeInfo(), metadata: 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: I) : MD->param_begin()[I];
552 QualType ParamTypeBefore = Param->getType();
553
554 if (I < Info.Params.size())
555 ProcessAPINotes(S, D: Param, Info: Info.Params[I], Metadata);
556
557 // Nullability.
558 if (Info.NullabilityAudited)
559 applyNullability(S, decl: Param, nullability: Info.getParamTypeInfo(index: I), metadata: 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(A: SwiftAttrAttr::Create(Ctx&: S.Context,
568 Attribute: "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(Ty: ParsedType.get());
578
579 if (MD) {
580 if (!checkAPINotesReplacementType(S, Loc: D->getLocation(),
581 OrigType: MD->getReturnType(), ReplacementType: ResultType)) {
582 auto ResultTypeInfo =
583 S.Context.getTrivialTypeSourceInfo(T: ResultType, Loc: D->getLocation());
584 MD->setReturnType(ResultType);
585 MD->setReturnTypeSourceInfo(ResultTypeInfo);
586 }
587 } else if (!checkAPINotesReplacementType(
588 S, Loc: FD->getLocation(), OrigType: FD->getReturnType(), ReplacementType: 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(Elt: Param->getType());
605
606 FD->setType(S.Context.getFunctionType(ResultTy: OverriddenResultType, Args: ParamTypes,
607 EPI: fnProtoType->getExtProtoInfo()));
608 } else if (!OverriddenResultType.isNull()) {
609 const auto *FnNoProtoType = FD->getType()->castAs<FunctionNoProtoType>();
610 FD->setType(S.Context.getFunctionNoProtoType(
611 ResultTy: OverriddenResultType, Info: FnNoProtoType->getExtInfo()));
612 }
613 }
614
615 // Retain count convention
616 handleAPINotedRetainCountConvention(S, D, Metadata,
617 Convention: Info.getRetainCountConvention());
618
619 // Handle common entity information.
620 ProcessAPINotes(S, D, Info: static_cast<const api_notes::CommonEntityInfo &>(Info),
621 Metadata);
622}
623
624/// Process API notes for a C++ method.
625static 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(FD: 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, modifiedType: MethodType, equivalentType: MethodType);
635 TypeLocBuilder TLB;
636 TLB.pushFullCopy(L: Method->getTypeSourceInfo()->getTypeLoc());
637 AttributedTypeLoc TyLoc = TLB.push<AttributedTypeLoc>(T: AttributedType);
638 TyLoc.setAttr(attr);
639 Method->setType(AttributedType);
640 Method->setTypeSourceInfo(TLB.getTypeSourceInfo(Context&: S.Context, T: AttributedType));
641 }
642
643 ProcessAPINotes(S, AnyFunc: (FunctionOrMethod)Method, Info, Metadata);
644}
645
646/// Process API notes for a global function.
647static void ProcessAPINotes(Sema &S, FunctionDecl *D,
648 const api_notes::GlobalFunctionInfo &Info,
649 VersionedInfoMetadata Metadata) {
650 // Handle common function information.
651 ProcessAPINotes(S, AnyFunc: FunctionOrMethod(D),
652 Info: static_cast<const api_notes::FunctionInfo &>(Info), Metadata);
653}
654
655/// Process API notes for an enumerator.
656static void ProcessAPINotes(Sema &S, EnumConstantDecl *D,
657 const api_notes::EnumConstantInfo &Info,
658 VersionedInfoMetadata Metadata) {
659 // Handle common information.
660 ProcessAPINotes(S, D, Info: static_cast<const api_notes::CommonEntityInfo &>(Info),
661 Metadata);
662}
663
664/// Process API notes for an Objective-C method.
665static 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, ShouldAddAttribute: true, Metadata, CreateAttr: [&] {
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, AnyFunc: FunctionOrMethod(D),
682 Info: static_cast<const api_notes::FunctionInfo &>(Info), Metadata);
683}
684
685/// Process API notes for a tag.
686static void ProcessAPINotes(Sema &S, TagDecl *D, const api_notes::TagInfo &Info,
687 VersionedInfoMetadata Metadata) {
688 if (auto ImportAs = Info.SwiftImportAs)
689 D->addAttr(A: SwiftAttrAttr::Create(Ctx&: S.Context, Attribute: "import_" + ImportAs.value()));
690
691 if (auto RetainOp = Info.SwiftRetainOp)
692 D->addAttr(A: SwiftAttrAttr::Create(Ctx&: S.Context, Attribute: "retain:" + RetainOp.value()));
693
694 if (auto ReleaseOp = Info.SwiftReleaseOp)
695 D->addAttr(
696 A: SwiftAttrAttr::Create(Ctx&: S.Context, Attribute: "release:" + ReleaseOp.value()));
697 if (auto DefaultOwnership = Info.SwiftDefaultOwnership)
698 D->addAttr(A: SwiftAttrAttr::Create(
699 Ctx&: S.Context, Attribute: "returned_as_" + DefaultOwnership.value() + "_by_default"));
700
701 if (auto ConformsTo = Info.SwiftConformance)
702 D->addAttr(
703 A: SwiftAttrAttr::Create(Ctx&: S.Context, Attribute: "conforms_to:" + ConformsTo.value()));
704
705 if (auto Copyable = Info.isSwiftCopyable()) {
706 if (!*Copyable)
707 D->addAttr(A: SwiftAttrAttr::Create(Ctx&: S.Context, Attribute: "~Copyable"));
708 }
709
710 if (auto Escapable = Info.isSwiftEscapable()) {
711 D->addAttr(A: SwiftAttrAttr::Create(Ctx&: S.Context,
712 Attribute: *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, CreateAttr: [&] {
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, ShouldAddAttribute: *FlagEnum, Metadata, CreateAttr: [&] {
738 return new (S.Context) FlagEnumAttr(S.Context, getPlaceholderAttrInfo());
739 });
740 }
741
742 // Handle common type information.
743 ProcessAPINotes(S, D, Info: static_cast<const api_notes::CommonTypeInfo &>(Info),
744 Metadata);
745}
746
747/// Process API notes for a typedef.
748static 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, ShouldAddAttribute: *SwiftWrapper != SwiftWrapperKind::None, Metadata, CreateAttr: [&] {
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, Info: static_cast<const api_notes::CommonTypeInfo &>(Info),
781 Metadata);
782}
783
784/// Process API notes for an Objective-C class or protocol.
785static void ProcessAPINotes(Sema &S, ObjCContainerDecl *D,
786 const api_notes::ContextInfo &Info,
787 VersionedInfoMetadata Metadata) {
788 // Handle common type information.
789 ProcessAPINotes(S, D, Info: static_cast<const api_notes::CommonTypeInfo &>(Info),
790 Metadata);
791}
792
793/// Process API notes for an Objective-C class.
794static 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, ShouldAddAttribute: *AsNonGeneric, Metadata, CreateAttr: [&] {
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, ShouldAddAttribute: *ObjcMembers, Metadata, CreateAttr: [&] {
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, D: 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.
826template <typename SpecificInfo>
827static 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.
864template <typename SpecificDecl, typename SpecificInfo>
865static 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
897static std::optional<api_notes::Context>
898UnwindNamespaceContext(DeclContext *DC, api_notes::APINotesManager &APINotes) {
899 if (auto NamespaceContext = dyn_cast<NamespaceDecl>(Val: DC)) {
900 for (auto Reader : APINotes.findAPINotes(Loc: 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>(Val: CurrentNamespace->getParent())) {
907 if (!CurrentNamespace->isInlineNamespace())
908 NamespaceStack.push(x: 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(Name: CurrentNamespace->getName(), ParentNamespaceID: 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
928static std::optional<api_notes::Context>
929UnwindTagContext(TagDecl *DC, api_notes::APINotesManager &APINotes) {
930 assert(DC && "tag context must not be null");
931 for (auto Reader : APINotes.findAPINotes(Loc: 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>(Val: CurrentTag->getParent()))
937 TagStack.push(x: CurrentTag);
938 }
939 assert(!TagStack.empty());
940 std::optional<api_notes::Context> Ctx =
941 UnwindNamespaceContext(DC: TagStack.top()->getDeclContext(), APINotes);
942 while (!TagStack.empty()) {
943 auto CurrentTag = TagStack.top();
944 TagStack.pop();
945 auto CtxID = Reader->lookupTagID(Name: CurrentTag->getName(), ParentCtx: 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.
957void 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>(Val: D)) {
969 for (auto Reader : APINotes.findAPINotes(Loc: D->getLocation())) {
970 auto Info =
971 Reader->lookupGlobalVariable(Name: VD->getName(), Ctx: APINotesContext);
972 ProcessVersionedAPINotes(S&: *this, D: VD, Info);
973 }
974
975 return;
976 }
977
978 // Global functions.
979 if (auto FD = dyn_cast<FunctionDecl>(Val: D)) {
980 if (FD->getDeclName().isIdentifier()) {
981 for (auto Reader : APINotes.findAPINotes(Loc: D->getLocation())) {
982 auto Info =
983 Reader->lookupGlobalFunction(Name: FD->getName(), Ctx: APINotesContext);
984 ProcessVersionedAPINotes(S&: *this, D: FD, Info);
985 }
986 }
987
988 return;
989 }
990
991 // Objective-C classes.
992 if (auto Class = dyn_cast<ObjCInterfaceDecl>(Val: D)) {
993 for (auto Reader : APINotes.findAPINotes(Loc: D->getLocation())) {
994 auto Info = Reader->lookupObjCClassInfo(Name: Class->getName());
995 ProcessVersionedAPINotes(S&: *this, D: Class, Info);
996 }
997
998 return;
999 }
1000
1001 // Objective-C protocols.
1002 if (auto Protocol = dyn_cast<ObjCProtocolDecl>(Val: D)) {
1003 for (auto Reader : APINotes.findAPINotes(Loc: D->getLocation())) {
1004 auto Info = Reader->lookupObjCProtocolInfo(Name: Protocol->getName());
1005 ProcessVersionedAPINotes(S&: *this, D: Protocol, Info);
1006 }
1007
1008 return;
1009 }
1010
1011 // Tags
1012 if (auto Tag = dyn_cast<TagDecl>(Val: 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 Loc: Tag->getOuterLocStart(),
1032 SM: Tag->getASTContext().getSourceManager(), LangOpts)
1033 .str()
1034 : "";
1035
1036 if (LookupName.empty() && isa<clang::EnumDecl>(Val: Tag) &&
1037 (MacroName == "CF_OPTIONS" || MacroName == "NS_OPTIONS" ||
1038 MacroName == "OBJC_OPTIONS" || MacroName == "SWIFT_OPTIONS")) {
1039
1040 clang::QualType T = llvm::cast<clang::EnumDecl>(Val: Tag)->getIntegerType();
1041 LookupName = clang::QualType::getAsString(
1042 split: T.split(), Policy: getASTContext().getPrintingPolicy());
1043 }
1044
1045 for (auto Reader : APINotes.findAPINotes(Loc: D->getLocation())) {
1046 if (auto ParentTag = dyn_cast<TagDecl>(Val: Tag->getDeclContext()))
1047 APINotesContext = UnwindTagContext(DC: ParentTag, APINotes);
1048 auto Info = Reader->lookupTag(Name: LookupName, Ctx: APINotesContext);
1049 ProcessVersionedAPINotes(S&: *this, D: Tag, Info);
1050 }
1051
1052 return;
1053 }
1054
1055 // Typedefs
1056 if (auto Typedef = dyn_cast<TypedefNameDecl>(Val: D)) {
1057 for (auto Reader : APINotes.findAPINotes(Loc: D->getLocation())) {
1058 auto Info = Reader->lookupTypedef(Name: Typedef->getName(), Ctx: APINotesContext);
1059 ProcessVersionedAPINotes(S&: *this, D: 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>(Val: D)) {
1070 for (auto Reader : APINotes.findAPINotes(Loc: D->getLocation())) {
1071 auto Info = Reader->lookupEnumConstant(Name: EnumConstant->getName());
1072 ProcessVersionedAPINotes(S&: *this, D: EnumConstant, Info);
1073 }
1074
1075 return;
1076 }
1077 }
1078
1079 if (auto ObjCContainer = dyn_cast<ObjCContainerDecl>(Val: 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>(Val: ObjCContainer)) {
1084 if (auto Found = Reader->lookupObjCProtocolID(Name: Protocol->getName()))
1085 return *Found;
1086
1087 return std::nullopt;
1088 }
1089
1090 if (auto Impl = dyn_cast<ObjCCategoryImplDecl>(Val: 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>(Val: ObjCContainer)) {
1098 if (Category->getClassInterface())
1099 ObjCContainer = Category->getClassInterface();
1100 else
1101 return std::nullopt;
1102 }
1103
1104 if (auto Impl = dyn_cast<ObjCImplDecl>(Val: ObjCContainer)) {
1105 if (Impl->getClassInterface())
1106 ObjCContainer = Impl->getClassInterface();
1107 else
1108 return std::nullopt;
1109 }
1110
1111 if (auto Class = dyn_cast<ObjCInterfaceDecl>(Val: ObjCContainer)) {
1112 if (auto Found = Reader->lookupObjCClassID(Name: 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>(Val: D)) {
1123 for (auto Reader : APINotes.findAPINotes(Loc: 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(Elt: Sel.getNameForSlot(argIndex: 0));
1130 } else {
1131 for (unsigned i = 0, n = Sel.getNumArgs(); i != n; ++i)
1132 SelPieces.push_back(Elt: Sel.getNameForSlot(argIndex: i));
1133 }
1134
1135 api_notes::ObjCSelectorRef SelectorRef;
1136 SelectorRef.NumArgs = Sel.getNumArgs();
1137 SelectorRef.Identifiers = SelPieces;
1138
1139 auto Info = Reader->lookupObjCMethod(CtxID: *Context, Selector: SelectorRef,
1140 IsInstanceMethod: Method->isInstanceMethod());
1141 ProcessVersionedAPINotes(S&: *this, D: Method, Info);
1142 }
1143 }
1144 }
1145
1146 // Objective-C properties.
1147 if (auto Property = dyn_cast<ObjCPropertyDecl>(Val: D)) {
1148 for (auto Reader : APINotes.findAPINotes(Loc: D->getLocation())) {
1149 if (auto Context = GetContext(Reader)) {
1150 bool isInstanceProperty =
1151 (Property->getPropertyAttributesAsWritten() &
1152 ObjCPropertyAttribute::kind_class) == 0;
1153 auto Info = Reader->lookupObjCProperty(CtxID: *Context, Name: Property->getName(),
1154 IsInstance: isInstanceProperty);
1155 ProcessVersionedAPINotes(S&: *this, D: Property, Info);
1156 }
1157 }
1158
1159 return;
1160 }
1161 }
1162
1163 if (auto TagContext = dyn_cast<TagDecl>(Val: DC)) {
1164 if (auto CXXMethod = dyn_cast<CXXMethodDecl>(Val: D)) {
1165 if (!isa<CXXConstructorDecl>(Val: CXXMethod) &&
1166 !isa<CXXDestructorDecl>(Val: CXXMethod) &&
1167 !isa<CXXConversionDecl>(Val: CXXMethod) &&
1168 !CXXMethod->isOverloadedOperator()) {
1169 for (auto Reader : APINotes.findAPINotes(Loc: D->getLocation())) {
1170 if (auto Context = UnwindTagContext(DC: TagContext, APINotes)) {
1171 auto Info =
1172 Reader->lookupCXXMethod(CtxID: Context->id, Name: CXXMethod->getName());
1173 ProcessVersionedAPINotes(S&: *this, D: CXXMethod, Info);
1174 }
1175 }
1176 }
1177 }
1178
1179 if (auto Field = dyn_cast<FieldDecl>(Val: D)) {
1180 if (!Field->isUnnamedBitField() && !Field->isAnonymousStructOrUnion()) {
1181 for (auto Reader : APINotes.findAPINotes(Loc: D->getLocation())) {
1182 if (auto Context = UnwindTagContext(DC: TagContext, APINotes)) {
1183 auto Info = Reader->lookupField(CtxID: Context->id, Name: Field->getName());
1184 ProcessVersionedAPINotes(S&: *this, D: Field, Info);
1185 }
1186 }
1187 }
1188 }
1189
1190 if (auto Tag = dyn_cast<TagDecl>(Val: D)) {
1191 for (auto Reader : APINotes.findAPINotes(Loc: D->getLocation())) {
1192 if (auto Context = UnwindTagContext(DC: TagContext, APINotes)) {
1193 auto Info = Reader->lookupTag(Name: Tag->getName(), Ctx: Context);
1194 ProcessVersionedAPINotes(S&: *this, D: Tag, Info);
1195 }
1196 }
1197 }
1198 }
1199}
1200

source code of clang/lib/Sema/SemaAPINotes.cpp