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