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