Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/Sema/SemaAPINotes.cpp
35234 views
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
35
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.
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.
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.
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
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>
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>
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>
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
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
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
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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>
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>
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.
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
1038