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