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