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