1440b1743SEgor Zhdan //===--- SemaAPINotes.cpp - API Notes Handling ----------------------------===// 2440b1743SEgor Zhdan // 3440b1743SEgor Zhdan // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4440b1743SEgor Zhdan // See https://llvm.org/LICENSE.txt for license information. 5440b1743SEgor Zhdan // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6440b1743SEgor Zhdan // 7440b1743SEgor Zhdan //===----------------------------------------------------------------------===// 8440b1743SEgor Zhdan // 9440b1743SEgor Zhdan // This file implements the mapping from API notes to declaration attributes. 10440b1743SEgor Zhdan // 11440b1743SEgor Zhdan //===----------------------------------------------------------------------===// 12440b1743SEgor Zhdan 134862febdSGábor Horváth #include "CheckExprLifetime.h" 145f4e3a3cSGábor Horváth #include "TypeLocBuilder.h" 15440b1743SEgor Zhdan #include "clang/APINotes/APINotesReader.h" 16440b1743SEgor Zhdan #include "clang/AST/Decl.h" 177ac78f13SGábor Horváth #include "clang/AST/DeclCXX.h" 18440b1743SEgor Zhdan #include "clang/AST/DeclObjC.h" 195f4e3a3cSGábor Horváth #include "clang/AST/TypeLoc.h" 20440b1743SEgor Zhdan #include "clang/Basic/SourceLocation.h" 21440b1743SEgor Zhdan #include "clang/Lex/Lexer.h" 2231a203faSVlad Serebrennikov #include "clang/Sema/SemaObjC.h" 236b755b0cSVlad Serebrennikov #include "clang/Sema/SemaSwift.h" 2448ef912eSNikita Popov #include <stack> 25440b1743SEgor Zhdan 26440b1743SEgor Zhdan using namespace clang; 27440b1743SEgor Zhdan 28440b1743SEgor Zhdan namespace { 29440b1743SEgor Zhdan enum class IsActive_t : bool { Inactive, Active }; 30440b1743SEgor Zhdan enum class IsSubstitution_t : bool { Original, Replacement }; 31440b1743SEgor Zhdan 32440b1743SEgor Zhdan struct VersionedInfoMetadata { 33440b1743SEgor Zhdan /// An empty version refers to unversioned metadata. 34440b1743SEgor Zhdan VersionTuple Version; 35440b1743SEgor Zhdan unsigned IsActive : 1; 36440b1743SEgor Zhdan unsigned IsReplacement : 1; 37440b1743SEgor Zhdan 38440b1743SEgor Zhdan VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, 39440b1743SEgor Zhdan IsSubstitution_t Replacement) 40440b1743SEgor Zhdan : Version(Version), IsActive(Active == IsActive_t::Active), 41440b1743SEgor Zhdan IsReplacement(Replacement == IsSubstitution_t::Replacement) {} 42440b1743SEgor Zhdan }; 43440b1743SEgor Zhdan } // end anonymous namespace 44440b1743SEgor Zhdan 45440b1743SEgor Zhdan /// Determine whether this is a multi-level pointer type. 46440b1743SEgor Zhdan static bool isIndirectPointerType(QualType Type) { 47440b1743SEgor Zhdan QualType Pointee = Type->getPointeeType(); 48440b1743SEgor Zhdan if (Pointee.isNull()) 49440b1743SEgor Zhdan return false; 50440b1743SEgor Zhdan 51440b1743SEgor Zhdan return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || 52440b1743SEgor Zhdan Pointee->isMemberPointerType(); 53440b1743SEgor Zhdan } 54440b1743SEgor Zhdan 55440b1743SEgor Zhdan /// Apply nullability to the given declaration. 56440b1743SEgor Zhdan static void applyNullability(Sema &S, Decl *D, NullabilityKind Nullability, 57440b1743SEgor Zhdan VersionedInfoMetadata Metadata) { 58440b1743SEgor Zhdan if (!Metadata.IsActive) 59440b1743SEgor Zhdan return; 60440b1743SEgor Zhdan 61932949dbSEgor Zhdan auto GetModified = 62932949dbSEgor Zhdan [&](Decl *D, QualType QT, 63932949dbSEgor Zhdan NullabilityKind Nullability) -> std::optional<QualType> { 64440b1743SEgor Zhdan QualType Original = QT; 65440b1743SEgor Zhdan S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(), 66440b1743SEgor Zhdan isa<ParmVarDecl>(D), 67440b1743SEgor Zhdan /*OverrideExisting=*/true); 68932949dbSEgor Zhdan return (QT.getTypePtr() != Original.getTypePtr()) ? std::optional(QT) 69932949dbSEgor Zhdan : std::nullopt; 70440b1743SEgor Zhdan }; 71440b1743SEgor Zhdan 72440b1743SEgor Zhdan if (auto Function = dyn_cast<FunctionDecl>(D)) { 73932949dbSEgor Zhdan if (auto Modified = 74932949dbSEgor Zhdan GetModified(D, Function->getReturnType(), Nullability)) { 75932949dbSEgor Zhdan const FunctionType *FnType = Function->getType()->castAs<FunctionType>(); 76932949dbSEgor Zhdan if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(FnType)) 77932949dbSEgor Zhdan Function->setType(S.Context.getFunctionType( 78932949dbSEgor Zhdan *Modified, proto->getParamTypes(), proto->getExtProtoInfo())); 79932949dbSEgor Zhdan else 80932949dbSEgor Zhdan Function->setType( 81932949dbSEgor Zhdan S.Context.getFunctionNoProtoType(*Modified, FnType->getExtInfo())); 82440b1743SEgor Zhdan } 83440b1743SEgor Zhdan } else if (auto Method = dyn_cast<ObjCMethodDecl>(D)) { 84932949dbSEgor Zhdan if (auto Modified = GetModified(D, Method->getReturnType(), Nullability)) { 85932949dbSEgor Zhdan Method->setReturnType(*Modified); 86440b1743SEgor Zhdan 87440b1743SEgor Zhdan // Make it a context-sensitive keyword if we can. 88932949dbSEgor Zhdan if (!isIndirectPointerType(*Modified)) 89440b1743SEgor Zhdan Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( 90440b1743SEgor Zhdan Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); 91440b1743SEgor Zhdan } 92440b1743SEgor Zhdan } else if (auto Value = dyn_cast<ValueDecl>(D)) { 93932949dbSEgor Zhdan if (auto Modified = GetModified(D, Value->getType(), Nullability)) { 94932949dbSEgor Zhdan Value->setType(*Modified); 95440b1743SEgor Zhdan 96440b1743SEgor Zhdan // Make it a context-sensitive keyword if we can. 97440b1743SEgor Zhdan if (auto Parm = dyn_cast<ParmVarDecl>(D)) { 98932949dbSEgor Zhdan if (Parm->isObjCMethodParameter() && !isIndirectPointerType(*Modified)) 99440b1743SEgor Zhdan Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( 100440b1743SEgor Zhdan Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); 101440b1743SEgor Zhdan } 102440b1743SEgor Zhdan } 103440b1743SEgor Zhdan } else if (auto Property = dyn_cast<ObjCPropertyDecl>(D)) { 104932949dbSEgor Zhdan if (auto Modified = GetModified(D, Property->getType(), Nullability)) { 105932949dbSEgor Zhdan Property->setType(*Modified, Property->getTypeSourceInfo()); 106440b1743SEgor Zhdan 107440b1743SEgor Zhdan // Make it a property attribute if we can. 108932949dbSEgor Zhdan if (!isIndirectPointerType(*Modified)) 109440b1743SEgor Zhdan Property->setPropertyAttributes( 110440b1743SEgor Zhdan ObjCPropertyAttribute::kind_null_resettable); 111440b1743SEgor Zhdan } 112440b1743SEgor Zhdan } 113440b1743SEgor Zhdan } 114440b1743SEgor Zhdan 115440b1743SEgor Zhdan /// Copy a string into ASTContext-allocated memory. 116440b1743SEgor Zhdan static StringRef ASTAllocateString(ASTContext &Ctx, StringRef String) { 117440b1743SEgor Zhdan void *mem = Ctx.Allocate(String.size(), alignof(char *)); 118440b1743SEgor Zhdan memcpy(mem, String.data(), String.size()); 119440b1743SEgor Zhdan return StringRef(static_cast<char *>(mem), String.size()); 120440b1743SEgor Zhdan } 121440b1743SEgor Zhdan 122440b1743SEgor Zhdan static AttributeCommonInfo getPlaceholderAttrInfo() { 123440b1743SEgor Zhdan return AttributeCommonInfo(SourceRange(), 124440b1743SEgor Zhdan AttributeCommonInfo::UnknownAttribute, 125440b1743SEgor Zhdan {AttributeCommonInfo::AS_GNU, 126440b1743SEgor Zhdan /*Spelling*/ 0, /*IsAlignas*/ false, 127440b1743SEgor Zhdan /*IsRegularKeywordAttribute*/ false}); 128440b1743SEgor Zhdan } 129440b1743SEgor Zhdan 130440b1743SEgor Zhdan namespace { 131440b1743SEgor Zhdan template <typename A> struct AttrKindFor {}; 132440b1743SEgor Zhdan 133440b1743SEgor Zhdan #define ATTR(X) \ 134440b1743SEgor Zhdan template <> struct AttrKindFor<X##Attr> { \ 135440b1743SEgor Zhdan static const attr::Kind value = attr::X; \ 136440b1743SEgor Zhdan }; 137440b1743SEgor Zhdan #include "clang/Basic/AttrList.inc" 138440b1743SEgor Zhdan 139440b1743SEgor Zhdan /// Handle an attribute introduced by API notes. 140440b1743SEgor Zhdan /// 141440b1743SEgor Zhdan /// \param IsAddition Whether we should add a new attribute 142440b1743SEgor Zhdan /// (otherwise, we might remove an existing attribute). 143440b1743SEgor Zhdan /// \param CreateAttr Create the new attribute to be added. 144440b1743SEgor Zhdan template <typename A> 145440b1743SEgor Zhdan void handleAPINotedAttribute( 146440b1743SEgor Zhdan Sema &S, Decl *D, bool IsAddition, VersionedInfoMetadata Metadata, 147440b1743SEgor Zhdan llvm::function_ref<A *()> CreateAttr, 148440b1743SEgor Zhdan llvm::function_ref<Decl::attr_iterator(const Decl *)> GetExistingAttr) { 149440b1743SEgor Zhdan if (Metadata.IsActive) { 150440b1743SEgor Zhdan auto Existing = GetExistingAttr(D); 151440b1743SEgor Zhdan if (Existing != D->attr_end()) { 152440b1743SEgor Zhdan // Remove the existing attribute, and treat it as a superseded 153440b1743SEgor Zhdan // non-versioned attribute. 154440b1743SEgor Zhdan auto *Versioned = SwiftVersionedAdditionAttr::CreateImplicit( 155440b1743SEgor Zhdan S.Context, Metadata.Version, *Existing, /*IsReplacedByActive*/ true); 156440b1743SEgor Zhdan 157440b1743SEgor Zhdan D->getAttrs().erase(Existing); 158440b1743SEgor Zhdan D->addAttr(Versioned); 159440b1743SEgor Zhdan } 160440b1743SEgor Zhdan 161440b1743SEgor Zhdan // If we're supposed to add a new attribute, do so. 162440b1743SEgor Zhdan if (IsAddition) { 163440b1743SEgor Zhdan if (auto Attr = CreateAttr()) 164440b1743SEgor Zhdan D->addAttr(Attr); 165440b1743SEgor Zhdan } 166440b1743SEgor Zhdan 167440b1743SEgor Zhdan return; 168440b1743SEgor Zhdan } 169440b1743SEgor Zhdan if (IsAddition) { 170440b1743SEgor Zhdan if (auto Attr = CreateAttr()) { 171440b1743SEgor Zhdan auto *Versioned = SwiftVersionedAdditionAttr::CreateImplicit( 172440b1743SEgor Zhdan S.Context, Metadata.Version, Attr, 173440b1743SEgor Zhdan /*IsReplacedByActive*/ Metadata.IsReplacement); 174440b1743SEgor Zhdan D->addAttr(Versioned); 175440b1743SEgor Zhdan } 176440b1743SEgor Zhdan } else { 177440b1743SEgor Zhdan // FIXME: This isn't preserving enough information for things like 178440b1743SEgor Zhdan // availability, where we're trying to remove a /specific/ kind of 179440b1743SEgor Zhdan // attribute. 180440b1743SEgor Zhdan auto *Versioned = SwiftVersionedRemovalAttr::CreateImplicit( 181440b1743SEgor Zhdan S.Context, Metadata.Version, AttrKindFor<A>::value, 182440b1743SEgor Zhdan /*IsReplacedByActive*/ Metadata.IsReplacement); 183440b1743SEgor Zhdan D->addAttr(Versioned); 184440b1743SEgor Zhdan } 185440b1743SEgor Zhdan } 186440b1743SEgor Zhdan 187440b1743SEgor Zhdan template <typename A> 188440b1743SEgor Zhdan void handleAPINotedAttribute(Sema &S, Decl *D, bool ShouldAddAttribute, 189440b1743SEgor Zhdan VersionedInfoMetadata Metadata, 190440b1743SEgor Zhdan llvm::function_ref<A *()> CreateAttr) { 191440b1743SEgor Zhdan handleAPINotedAttribute<A>( 192440b1743SEgor Zhdan S, D, ShouldAddAttribute, Metadata, CreateAttr, [](const Decl *D) { 193440b1743SEgor Zhdan return llvm::find_if(D->attrs(), 194440b1743SEgor Zhdan [](const Attr *Next) { return isa<A>(Next); }); 195440b1743SEgor Zhdan }); 196440b1743SEgor Zhdan } 197440b1743SEgor Zhdan } // namespace 198440b1743SEgor Zhdan 199440b1743SEgor Zhdan template <typename A> 200440b1743SEgor Zhdan static void handleAPINotedRetainCountAttribute(Sema &S, Decl *D, 201440b1743SEgor Zhdan bool ShouldAddAttribute, 202440b1743SEgor Zhdan VersionedInfoMetadata Metadata) { 203440b1743SEgor Zhdan // The template argument has a default to make the "removal" case more 204440b1743SEgor Zhdan // concise; it doesn't matter /which/ attribute is being removed. 205440b1743SEgor Zhdan handleAPINotedAttribute<A>( 206440b1743SEgor Zhdan S, D, ShouldAddAttribute, Metadata, 207440b1743SEgor Zhdan [&] { return new (S.Context) A(S.Context, getPlaceholderAttrInfo()); }, 208440b1743SEgor Zhdan [](const Decl *D) -> Decl::attr_iterator { 209440b1743SEgor Zhdan return llvm::find_if(D->attrs(), [](const Attr *Next) -> bool { 210440b1743SEgor Zhdan return isa<CFReturnsRetainedAttr>(Next) || 211440b1743SEgor Zhdan isa<CFReturnsNotRetainedAttr>(Next) || 212440b1743SEgor Zhdan isa<NSReturnsRetainedAttr>(Next) || 213440b1743SEgor Zhdan isa<NSReturnsNotRetainedAttr>(Next) || 214440b1743SEgor Zhdan isa<CFAuditedTransferAttr>(Next); 215440b1743SEgor Zhdan }); 216440b1743SEgor Zhdan }); 217440b1743SEgor Zhdan } 218440b1743SEgor Zhdan 219440b1743SEgor Zhdan static void handleAPINotedRetainCountConvention( 220440b1743SEgor Zhdan Sema &S, Decl *D, VersionedInfoMetadata Metadata, 221440b1743SEgor Zhdan std::optional<api_notes::RetainCountConventionKind> Convention) { 222440b1743SEgor Zhdan if (!Convention) 223440b1743SEgor Zhdan return; 224440b1743SEgor Zhdan switch (*Convention) { 225440b1743SEgor Zhdan case api_notes::RetainCountConventionKind::None: 226440b1743SEgor Zhdan if (isa<FunctionDecl>(D)) { 227440b1743SEgor Zhdan handleAPINotedRetainCountAttribute<CFUnknownTransferAttr>( 228440b1743SEgor Zhdan S, D, /*shouldAddAttribute*/ true, Metadata); 229440b1743SEgor Zhdan } else { 230440b1743SEgor Zhdan handleAPINotedRetainCountAttribute<CFReturnsRetainedAttr>( 231440b1743SEgor Zhdan S, D, /*shouldAddAttribute*/ false, Metadata); 232440b1743SEgor Zhdan } 233440b1743SEgor Zhdan break; 234440b1743SEgor Zhdan case api_notes::RetainCountConventionKind::CFReturnsRetained: 235440b1743SEgor Zhdan handleAPINotedRetainCountAttribute<CFReturnsRetainedAttr>( 236440b1743SEgor Zhdan S, D, /*shouldAddAttribute*/ true, Metadata); 237440b1743SEgor Zhdan break; 238440b1743SEgor Zhdan case api_notes::RetainCountConventionKind::CFReturnsNotRetained: 239440b1743SEgor Zhdan handleAPINotedRetainCountAttribute<CFReturnsNotRetainedAttr>( 240440b1743SEgor Zhdan S, D, /*shouldAddAttribute*/ true, Metadata); 241440b1743SEgor Zhdan break; 242440b1743SEgor Zhdan case api_notes::RetainCountConventionKind::NSReturnsRetained: 243440b1743SEgor Zhdan handleAPINotedRetainCountAttribute<NSReturnsRetainedAttr>( 244440b1743SEgor Zhdan S, D, /*shouldAddAttribute*/ true, Metadata); 245440b1743SEgor Zhdan break; 246440b1743SEgor Zhdan case api_notes::RetainCountConventionKind::NSReturnsNotRetained: 247440b1743SEgor Zhdan handleAPINotedRetainCountAttribute<NSReturnsNotRetainedAttr>( 248440b1743SEgor Zhdan S, D, /*shouldAddAttribute*/ true, Metadata); 249440b1743SEgor Zhdan break; 250440b1743SEgor Zhdan } 251440b1743SEgor Zhdan } 252440b1743SEgor Zhdan 253440b1743SEgor Zhdan static void ProcessAPINotes(Sema &S, Decl *D, 254440b1743SEgor Zhdan const api_notes::CommonEntityInfo &Info, 255440b1743SEgor Zhdan VersionedInfoMetadata Metadata) { 256440b1743SEgor Zhdan // Availability 257440b1743SEgor Zhdan if (Info.Unavailable) { 258440b1743SEgor Zhdan handleAPINotedAttribute<UnavailableAttr>(S, D, true, Metadata, [&] { 259440b1743SEgor Zhdan return new (S.Context) 260440b1743SEgor Zhdan UnavailableAttr(S.Context, getPlaceholderAttrInfo(), 261440b1743SEgor Zhdan ASTAllocateString(S.Context, Info.UnavailableMsg)); 262440b1743SEgor Zhdan }); 263440b1743SEgor Zhdan } 264440b1743SEgor Zhdan 265440b1743SEgor Zhdan if (Info.UnavailableInSwift) { 266440b1743SEgor Zhdan handleAPINotedAttribute<AvailabilityAttr>( 267440b1743SEgor Zhdan S, D, true, Metadata, 268440b1743SEgor Zhdan [&] { 269440b1743SEgor Zhdan return new (S.Context) AvailabilityAttr( 270440b1743SEgor Zhdan S.Context, getPlaceholderAttrInfo(), 271440b1743SEgor Zhdan &S.Context.Idents.get("swift"), VersionTuple(), VersionTuple(), 272440b1743SEgor Zhdan VersionTuple(), 273440b1743SEgor Zhdan /*Unavailable=*/true, 274440b1743SEgor Zhdan ASTAllocateString(S.Context, Info.UnavailableMsg), 275440b1743SEgor Zhdan /*Strict=*/false, 276440b1743SEgor Zhdan /*Replacement=*/StringRef(), 2773f33c4c1SHelena Kotas /*Priority=*/Sema::AP_Explicit, 2783f33c4c1SHelena Kotas /*Environment=*/nullptr); 279440b1743SEgor Zhdan }, 280440b1743SEgor Zhdan [](const Decl *D) { 281440b1743SEgor Zhdan return llvm::find_if(D->attrs(), [](const Attr *next) -> bool { 282440b1743SEgor Zhdan if (const auto *AA = dyn_cast<AvailabilityAttr>(next)) 283440b1743SEgor Zhdan if (const auto *II = AA->getPlatform()) 284440b1743SEgor Zhdan return II->isStr("swift"); 285440b1743SEgor Zhdan return false; 286440b1743SEgor Zhdan }); 287440b1743SEgor Zhdan }); 288440b1743SEgor Zhdan } 289440b1743SEgor Zhdan 290440b1743SEgor Zhdan // swift_private 291440b1743SEgor Zhdan if (auto SwiftPrivate = Info.isSwiftPrivate()) { 292440b1743SEgor Zhdan handleAPINotedAttribute<SwiftPrivateAttr>( 293440b1743SEgor Zhdan S, D, *SwiftPrivate, Metadata, [&] { 294440b1743SEgor Zhdan return new (S.Context) 295440b1743SEgor Zhdan SwiftPrivateAttr(S.Context, getPlaceholderAttrInfo()); 296440b1743SEgor Zhdan }); 297440b1743SEgor Zhdan } 298440b1743SEgor Zhdan 299440b1743SEgor Zhdan // swift_name 300440b1743SEgor Zhdan if (!Info.SwiftName.empty()) { 301440b1743SEgor Zhdan handleAPINotedAttribute<SwiftNameAttr>( 302440b1743SEgor Zhdan S, D, true, Metadata, [&]() -> SwiftNameAttr * { 303440b1743SEgor Zhdan AttributeFactory AF{}; 304440b1743SEgor Zhdan AttributePool AP{AF}; 305440b1743SEgor Zhdan auto &C = S.getASTContext(); 306440b1743SEgor Zhdan ParsedAttr *SNA = 307440b1743SEgor Zhdan AP.create(&C.Idents.get("swift_name"), SourceRange(), nullptr, 308440b1743SEgor Zhdan SourceLocation(), nullptr, nullptr, nullptr, 309440b1743SEgor Zhdan ParsedAttr::Form::GNU()); 310440b1743SEgor Zhdan 3116b755b0cSVlad Serebrennikov if (!S.Swift().DiagnoseName(D, Info.SwiftName, D->getLocation(), *SNA, 312440b1743SEgor Zhdan /*IsAsync=*/false)) 313440b1743SEgor Zhdan return nullptr; 314440b1743SEgor Zhdan 315440b1743SEgor Zhdan return new (S.Context) 316440b1743SEgor Zhdan SwiftNameAttr(S.Context, getPlaceholderAttrInfo(), 317440b1743SEgor Zhdan ASTAllocateString(S.Context, Info.SwiftName)); 318440b1743SEgor Zhdan }); 319440b1743SEgor Zhdan } 320440b1743SEgor Zhdan } 321440b1743SEgor Zhdan 322440b1743SEgor Zhdan static void ProcessAPINotes(Sema &S, Decl *D, 323440b1743SEgor Zhdan const api_notes::CommonTypeInfo &Info, 324440b1743SEgor Zhdan VersionedInfoMetadata Metadata) { 325440b1743SEgor Zhdan // swift_bridge 326440b1743SEgor Zhdan if (auto SwiftBridge = Info.getSwiftBridge()) { 327440b1743SEgor Zhdan handleAPINotedAttribute<SwiftBridgeAttr>( 328440b1743SEgor Zhdan S, D, !SwiftBridge->empty(), Metadata, [&] { 329440b1743SEgor Zhdan return new (S.Context) 330440b1743SEgor Zhdan SwiftBridgeAttr(S.Context, getPlaceholderAttrInfo(), 331440b1743SEgor Zhdan ASTAllocateString(S.Context, *SwiftBridge)); 332440b1743SEgor Zhdan }); 333440b1743SEgor Zhdan } 334440b1743SEgor Zhdan 335440b1743SEgor Zhdan // ns_error_domain 336440b1743SEgor Zhdan if (auto NSErrorDomain = Info.getNSErrorDomain()) { 337440b1743SEgor Zhdan handleAPINotedAttribute<NSErrorDomainAttr>( 338440b1743SEgor Zhdan S, D, !NSErrorDomain->empty(), Metadata, [&] { 339440b1743SEgor Zhdan return new (S.Context) 340440b1743SEgor Zhdan NSErrorDomainAttr(S.Context, getPlaceholderAttrInfo(), 341440b1743SEgor Zhdan &S.Context.Idents.get(*NSErrorDomain)); 342440b1743SEgor Zhdan }); 343440b1743SEgor Zhdan } 344440b1743SEgor Zhdan 345440b1743SEgor Zhdan ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(Info), 346440b1743SEgor Zhdan Metadata); 347440b1743SEgor Zhdan } 348440b1743SEgor Zhdan 349440b1743SEgor Zhdan /// Check that the replacement type provided by API notes is reasonable. 350440b1743SEgor Zhdan /// 351440b1743SEgor Zhdan /// This is a very weak form of ABI check. 352440b1743SEgor Zhdan static bool checkAPINotesReplacementType(Sema &S, SourceLocation Loc, 353440b1743SEgor Zhdan QualType OrigType, 354440b1743SEgor Zhdan QualType ReplacementType) { 355440b1743SEgor Zhdan if (S.Context.getTypeSize(OrigType) != 356440b1743SEgor Zhdan S.Context.getTypeSize(ReplacementType)) { 357440b1743SEgor Zhdan S.Diag(Loc, diag::err_incompatible_replacement_type) 358440b1743SEgor Zhdan << ReplacementType << OrigType; 359440b1743SEgor Zhdan return true; 360440b1743SEgor Zhdan } 361440b1743SEgor Zhdan 362440b1743SEgor Zhdan return false; 363440b1743SEgor Zhdan } 364440b1743SEgor Zhdan 365440b1743SEgor Zhdan /// Process API notes for a variable or property. 366440b1743SEgor Zhdan static void ProcessAPINotes(Sema &S, Decl *D, 367440b1743SEgor Zhdan const api_notes::VariableInfo &Info, 368440b1743SEgor Zhdan VersionedInfoMetadata Metadata) { 369440b1743SEgor Zhdan // Type override. 370440b1743SEgor Zhdan if (Metadata.IsActive && !Info.getType().empty() && 371440b1743SEgor Zhdan S.ParseTypeFromStringCallback) { 372440b1743SEgor Zhdan auto ParsedType = S.ParseTypeFromStringCallback( 373440b1743SEgor Zhdan Info.getType(), "<API Notes>", D->getLocation()); 374440b1743SEgor Zhdan if (ParsedType.isUsable()) { 375440b1743SEgor Zhdan QualType Type = Sema::GetTypeFromParser(ParsedType.get()); 376440b1743SEgor Zhdan auto TypeInfo = 377440b1743SEgor Zhdan S.Context.getTrivialTypeSourceInfo(Type, D->getLocation()); 378440b1743SEgor Zhdan 379440b1743SEgor Zhdan if (auto Var = dyn_cast<VarDecl>(D)) { 380440b1743SEgor Zhdan // Make adjustments to parameter types. 381440b1743SEgor Zhdan if (isa<ParmVarDecl>(Var)) { 38231a203faSVlad Serebrennikov Type = S.ObjC().AdjustParameterTypeForObjCAutoRefCount( 383440b1743SEgor Zhdan Type, D->getLocation(), TypeInfo); 384440b1743SEgor Zhdan Type = S.Context.getAdjustedParameterType(Type); 385440b1743SEgor Zhdan } 386440b1743SEgor Zhdan 387440b1743SEgor Zhdan if (!checkAPINotesReplacementType(S, Var->getLocation(), Var->getType(), 388440b1743SEgor Zhdan Type)) { 389440b1743SEgor Zhdan Var->setType(Type); 390440b1743SEgor Zhdan Var->setTypeSourceInfo(TypeInfo); 391440b1743SEgor Zhdan } 392440b1743SEgor Zhdan } else if (auto Property = dyn_cast<ObjCPropertyDecl>(D)) { 393440b1743SEgor Zhdan if (!checkAPINotesReplacementType(S, Property->getLocation(), 394440b1743SEgor Zhdan Property->getType(), Type)) 395440b1743SEgor Zhdan Property->setType(Type, TypeInfo); 396440b1743SEgor Zhdan 397440b1743SEgor Zhdan } else 398440b1743SEgor Zhdan llvm_unreachable("API notes allowed a type on an unknown declaration"); 399440b1743SEgor Zhdan } 400440b1743SEgor Zhdan } 401440b1743SEgor Zhdan 402440b1743SEgor Zhdan // Nullability. 403440b1743SEgor Zhdan if (auto Nullability = Info.getNullability()) 404440b1743SEgor Zhdan applyNullability(S, D, *Nullability, Metadata); 405440b1743SEgor Zhdan 406440b1743SEgor Zhdan // Handle common entity information. 407440b1743SEgor Zhdan ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(Info), 408440b1743SEgor Zhdan Metadata); 409440b1743SEgor Zhdan } 410440b1743SEgor Zhdan 411440b1743SEgor Zhdan /// Process API notes for a parameter. 412440b1743SEgor Zhdan static void ProcessAPINotes(Sema &S, ParmVarDecl *D, 413440b1743SEgor Zhdan const api_notes::ParamInfo &Info, 414440b1743SEgor Zhdan VersionedInfoMetadata Metadata) { 415440b1743SEgor Zhdan // noescape 416440b1743SEgor Zhdan if (auto NoEscape = Info.isNoEscape()) 417440b1743SEgor Zhdan handleAPINotedAttribute<NoEscapeAttr>(S, D, *NoEscape, Metadata, [&] { 418440b1743SEgor Zhdan return new (S.Context) NoEscapeAttr(S.Context, getPlaceholderAttrInfo()); 419440b1743SEgor Zhdan }); 420440b1743SEgor Zhdan 4217ac78f13SGábor Horváth if (auto Lifetimebound = Info.isLifetimebound()) 4227ac78f13SGábor Horváth handleAPINotedAttribute<LifetimeBoundAttr>( 4237ac78f13SGábor Horváth S, D, *Lifetimebound, Metadata, [&] { 4247ac78f13SGábor Horváth return new (S.Context) 4257ac78f13SGábor Horváth LifetimeBoundAttr(S.Context, getPlaceholderAttrInfo()); 4267ac78f13SGábor Horváth }); 4277ac78f13SGábor Horváth 428440b1743SEgor Zhdan // Retain count convention 429440b1743SEgor Zhdan handleAPINotedRetainCountConvention(S, D, Metadata, 430440b1743SEgor Zhdan Info.getRetainCountConvention()); 431440b1743SEgor Zhdan 432440b1743SEgor Zhdan // Handle common entity information. 433440b1743SEgor Zhdan ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(Info), 434440b1743SEgor Zhdan Metadata); 435440b1743SEgor Zhdan } 436440b1743SEgor Zhdan 437440b1743SEgor Zhdan /// Process API notes for a global variable. 438440b1743SEgor Zhdan static void ProcessAPINotes(Sema &S, VarDecl *D, 439440b1743SEgor Zhdan const api_notes::GlobalVariableInfo &Info, 440440b1743SEgor Zhdan VersionedInfoMetadata metadata) { 441440b1743SEgor Zhdan // Handle common entity information. 442440b1743SEgor Zhdan ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(Info), 443440b1743SEgor Zhdan metadata); 444440b1743SEgor Zhdan } 445440b1743SEgor Zhdan 446b8169771SEgor Zhdan /// Process API notes for a C field. 447b8169771SEgor Zhdan static void ProcessAPINotes(Sema &S, FieldDecl *D, 448b8169771SEgor Zhdan const api_notes::FieldInfo &Info, 449b8169771SEgor Zhdan VersionedInfoMetadata metadata) { 450b8169771SEgor Zhdan // Handle common entity information. 451b8169771SEgor Zhdan ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(Info), 452b8169771SEgor Zhdan metadata); 453b8169771SEgor Zhdan } 454b8169771SEgor Zhdan 455440b1743SEgor Zhdan /// Process API notes for an Objective-C property. 456440b1743SEgor Zhdan static void ProcessAPINotes(Sema &S, ObjCPropertyDecl *D, 457440b1743SEgor Zhdan const api_notes::ObjCPropertyInfo &Info, 458440b1743SEgor Zhdan VersionedInfoMetadata Metadata) { 459440b1743SEgor Zhdan // Handle common entity information. 460440b1743SEgor Zhdan ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(Info), 461440b1743SEgor Zhdan Metadata); 462440b1743SEgor Zhdan 463440b1743SEgor Zhdan if (auto AsAccessors = Info.getSwiftImportAsAccessors()) { 464440b1743SEgor Zhdan handleAPINotedAttribute<SwiftImportPropertyAsAccessorsAttr>( 465440b1743SEgor Zhdan S, D, *AsAccessors, Metadata, [&] { 466440b1743SEgor Zhdan return new (S.Context) SwiftImportPropertyAsAccessorsAttr( 467440b1743SEgor Zhdan S.Context, getPlaceholderAttrInfo()); 468440b1743SEgor Zhdan }); 469440b1743SEgor Zhdan } 470440b1743SEgor Zhdan } 471440b1743SEgor Zhdan 472440b1743SEgor Zhdan namespace { 473440b1743SEgor Zhdan typedef llvm::PointerUnion<FunctionDecl *, ObjCMethodDecl *> FunctionOrMethod; 474440b1743SEgor Zhdan } 475440b1743SEgor Zhdan 476440b1743SEgor Zhdan /// Process API notes for a function or method. 477440b1743SEgor Zhdan static void ProcessAPINotes(Sema &S, FunctionOrMethod AnyFunc, 478440b1743SEgor Zhdan const api_notes::FunctionInfo &Info, 479440b1743SEgor Zhdan VersionedInfoMetadata Metadata) { 480440b1743SEgor Zhdan // Find the declaration itself. 481*f09a6f63SKazu Hirata FunctionDecl *FD = dyn_cast<FunctionDecl *>(AnyFunc); 482440b1743SEgor Zhdan Decl *D = FD; 483440b1743SEgor Zhdan ObjCMethodDecl *MD = nullptr; 484440b1743SEgor Zhdan if (!D) { 4851e3e199eSKazu Hirata MD = cast<ObjCMethodDecl *>(AnyFunc); 486440b1743SEgor Zhdan D = MD; 487440b1743SEgor Zhdan } 488440b1743SEgor Zhdan 489b074f253Selizabethandrews assert((FD || MD) && "Expecting Function or ObjCMethod"); 490b074f253Selizabethandrews 491440b1743SEgor Zhdan // Nullability of return type. 492440b1743SEgor Zhdan if (Info.NullabilityAudited) 493440b1743SEgor Zhdan applyNullability(S, D, Info.getReturnTypeInfo(), Metadata); 494440b1743SEgor Zhdan 495440b1743SEgor Zhdan // Parameters. 496440b1743SEgor Zhdan unsigned NumParams = FD ? FD->getNumParams() : MD->param_size(); 497440b1743SEgor Zhdan 498440b1743SEgor Zhdan bool AnyTypeChanged = false; 499440b1743SEgor Zhdan for (unsigned I = 0; I != NumParams; ++I) { 500440b1743SEgor Zhdan ParmVarDecl *Param = FD ? FD->getParamDecl(I) : MD->param_begin()[I]; 501440b1743SEgor Zhdan QualType ParamTypeBefore = Param->getType(); 502440b1743SEgor Zhdan 503440b1743SEgor Zhdan if (I < Info.Params.size()) 504440b1743SEgor Zhdan ProcessAPINotes(S, Param, Info.Params[I], Metadata); 505440b1743SEgor Zhdan 506440b1743SEgor Zhdan // Nullability. 507440b1743SEgor Zhdan if (Info.NullabilityAudited) 508440b1743SEgor Zhdan applyNullability(S, Param, Info.getParamTypeInfo(I), Metadata); 509440b1743SEgor Zhdan 510440b1743SEgor Zhdan if (ParamTypeBefore.getAsOpaquePtr() != Param->getType().getAsOpaquePtr()) 511440b1743SEgor Zhdan AnyTypeChanged = true; 512440b1743SEgor Zhdan } 513440b1743SEgor Zhdan 51448f7f63aSfahadnayyar // returns_(un)retained 51548f7f63aSfahadnayyar if (!Info.SwiftReturnOwnership.empty()) 51648f7f63aSfahadnayyar D->addAttr(SwiftAttrAttr::Create(S.Context, 51748f7f63aSfahadnayyar "returns_" + Info.SwiftReturnOwnership)); 51848f7f63aSfahadnayyar 519440b1743SEgor Zhdan // Result type override. 520440b1743SEgor Zhdan QualType OverriddenResultType; 521440b1743SEgor Zhdan if (Metadata.IsActive && !Info.ResultType.empty() && 522440b1743SEgor Zhdan S.ParseTypeFromStringCallback) { 523440b1743SEgor Zhdan auto ParsedType = S.ParseTypeFromStringCallback( 524440b1743SEgor Zhdan Info.ResultType, "<API Notes>", D->getLocation()); 525440b1743SEgor Zhdan if (ParsedType.isUsable()) { 526440b1743SEgor Zhdan QualType ResultType = Sema::GetTypeFromParser(ParsedType.get()); 527440b1743SEgor Zhdan 528440b1743SEgor Zhdan if (MD) { 529440b1743SEgor Zhdan if (!checkAPINotesReplacementType(S, D->getLocation(), 530440b1743SEgor Zhdan MD->getReturnType(), ResultType)) { 531440b1743SEgor Zhdan auto ResultTypeInfo = 532440b1743SEgor Zhdan S.Context.getTrivialTypeSourceInfo(ResultType, D->getLocation()); 533440b1743SEgor Zhdan MD->setReturnType(ResultType); 534440b1743SEgor Zhdan MD->setReturnTypeSourceInfo(ResultTypeInfo); 535440b1743SEgor Zhdan } 536440b1743SEgor Zhdan } else if (!checkAPINotesReplacementType( 537440b1743SEgor Zhdan S, FD->getLocation(), FD->getReturnType(), ResultType)) { 538440b1743SEgor Zhdan OverriddenResultType = ResultType; 539440b1743SEgor Zhdan AnyTypeChanged = true; 540440b1743SEgor Zhdan } 541440b1743SEgor Zhdan } 542440b1743SEgor Zhdan } 543440b1743SEgor Zhdan 544440b1743SEgor Zhdan // If the result type or any of the parameter types changed for a function 545440b1743SEgor Zhdan // declaration, we have to rebuild the type. 546440b1743SEgor Zhdan if (FD && AnyTypeChanged) { 547440b1743SEgor Zhdan if (const auto *fnProtoType = FD->getType()->getAs<FunctionProtoType>()) { 548440b1743SEgor Zhdan if (OverriddenResultType.isNull()) 549440b1743SEgor Zhdan OverriddenResultType = fnProtoType->getReturnType(); 550440b1743SEgor Zhdan 551440b1743SEgor Zhdan SmallVector<QualType, 4> ParamTypes; 552440b1743SEgor Zhdan for (auto Param : FD->parameters()) 553440b1743SEgor Zhdan ParamTypes.push_back(Param->getType()); 554440b1743SEgor Zhdan 555440b1743SEgor Zhdan FD->setType(S.Context.getFunctionType(OverriddenResultType, ParamTypes, 556440b1743SEgor Zhdan fnProtoType->getExtProtoInfo())); 557440b1743SEgor Zhdan } else if (!OverriddenResultType.isNull()) { 558440b1743SEgor Zhdan const auto *FnNoProtoType = FD->getType()->castAs<FunctionNoProtoType>(); 559440b1743SEgor Zhdan FD->setType(S.Context.getFunctionNoProtoType( 560440b1743SEgor Zhdan OverriddenResultType, FnNoProtoType->getExtInfo())); 561440b1743SEgor Zhdan } 562440b1743SEgor Zhdan } 563440b1743SEgor Zhdan 564440b1743SEgor Zhdan // Retain count convention 565440b1743SEgor Zhdan handleAPINotedRetainCountConvention(S, D, Metadata, 566440b1743SEgor Zhdan Info.getRetainCountConvention()); 567440b1743SEgor Zhdan 568440b1743SEgor Zhdan // Handle common entity information. 569440b1743SEgor Zhdan ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(Info), 570440b1743SEgor Zhdan Metadata); 571440b1743SEgor Zhdan } 572440b1743SEgor Zhdan 5738a79dc7eSEgor Zhdan /// Process API notes for a C++ method. 5748a79dc7eSEgor Zhdan static void ProcessAPINotes(Sema &S, CXXMethodDecl *Method, 5758a79dc7eSEgor Zhdan const api_notes::CXXMethodInfo &Info, 5768a79dc7eSEgor Zhdan VersionedInfoMetadata Metadata) { 5774862febdSGábor Horváth if (Info.This && Info.This->isLifetimebound() && 5784862febdSGábor Horváth !sema::implicitObjectParamIsLifetimeBound(Method)) { 5795f4e3a3cSGábor Horváth auto MethodType = Method->getType(); 5805f4e3a3cSGábor Horváth auto *attr = ::new (S.Context) 5815f4e3a3cSGábor Horváth LifetimeBoundAttr(S.Context, getPlaceholderAttrInfo()); 5825f4e3a3cSGábor Horváth QualType AttributedType = 5835f4e3a3cSGábor Horváth S.Context.getAttributedType(attr, MethodType, MethodType); 5845f4e3a3cSGábor Horváth TypeLocBuilder TLB; 5855f4e3a3cSGábor Horváth TLB.pushFullCopy(Method->getTypeSourceInfo()->getTypeLoc()); 5865f4e3a3cSGábor Horváth AttributedTypeLoc TyLoc = TLB.push<AttributedTypeLoc>(AttributedType); 5875f4e3a3cSGábor Horváth TyLoc.setAttr(attr); 5885f4e3a3cSGábor Horváth Method->setType(AttributedType); 5895f4e3a3cSGábor Horváth Method->setTypeSourceInfo(TLB.getTypeSourceInfo(S.Context, AttributedType)); 5905f4e3a3cSGábor Horváth } 5915f4e3a3cSGábor Horváth 5928a79dc7eSEgor Zhdan ProcessAPINotes(S, (FunctionOrMethod)Method, Info, Metadata); 5938a79dc7eSEgor Zhdan } 5948a79dc7eSEgor Zhdan 595440b1743SEgor Zhdan /// Process API notes for a global function. 596440b1743SEgor Zhdan static void ProcessAPINotes(Sema &S, FunctionDecl *D, 597440b1743SEgor Zhdan const api_notes::GlobalFunctionInfo &Info, 598440b1743SEgor Zhdan VersionedInfoMetadata Metadata) { 599440b1743SEgor Zhdan // Handle common function information. 600440b1743SEgor Zhdan ProcessAPINotes(S, FunctionOrMethod(D), 601440b1743SEgor Zhdan static_cast<const api_notes::FunctionInfo &>(Info), Metadata); 602440b1743SEgor Zhdan } 603440b1743SEgor Zhdan 604440b1743SEgor Zhdan /// Process API notes for an enumerator. 605440b1743SEgor Zhdan static void ProcessAPINotes(Sema &S, EnumConstantDecl *D, 606440b1743SEgor Zhdan const api_notes::EnumConstantInfo &Info, 607440b1743SEgor Zhdan VersionedInfoMetadata Metadata) { 608440b1743SEgor Zhdan // Handle common information. 609440b1743SEgor Zhdan ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(Info), 610440b1743SEgor Zhdan Metadata); 611440b1743SEgor Zhdan } 612440b1743SEgor Zhdan 613440b1743SEgor Zhdan /// Process API notes for an Objective-C method. 614440b1743SEgor Zhdan static void ProcessAPINotes(Sema &S, ObjCMethodDecl *D, 615440b1743SEgor Zhdan const api_notes::ObjCMethodInfo &Info, 616440b1743SEgor Zhdan VersionedInfoMetadata Metadata) { 617440b1743SEgor Zhdan // Designated initializers. 618440b1743SEgor Zhdan if (Info.DesignatedInit) { 619440b1743SEgor Zhdan handleAPINotedAttribute<ObjCDesignatedInitializerAttr>( 620440b1743SEgor Zhdan S, D, true, Metadata, [&] { 621440b1743SEgor Zhdan if (ObjCInterfaceDecl *IFace = D->getClassInterface()) 622440b1743SEgor Zhdan IFace->setHasDesignatedInitializers(); 623440b1743SEgor Zhdan 624440b1743SEgor Zhdan return new (S.Context) ObjCDesignatedInitializerAttr( 625440b1743SEgor Zhdan S.Context, getPlaceholderAttrInfo()); 626440b1743SEgor Zhdan }); 627440b1743SEgor Zhdan } 628440b1743SEgor Zhdan 629440b1743SEgor Zhdan // Handle common function information. 630440b1743SEgor Zhdan ProcessAPINotes(S, FunctionOrMethod(D), 631440b1743SEgor Zhdan static_cast<const api_notes::FunctionInfo &>(Info), Metadata); 632440b1743SEgor Zhdan } 633440b1743SEgor Zhdan 634440b1743SEgor Zhdan /// Process API notes for a tag. 635440b1743SEgor Zhdan static void ProcessAPINotes(Sema &S, TagDecl *D, const api_notes::TagInfo &Info, 636440b1743SEgor Zhdan VersionedInfoMetadata Metadata) { 637440b1743SEgor Zhdan if (auto ImportAs = Info.SwiftImportAs) 638440b1743SEgor Zhdan D->addAttr(SwiftAttrAttr::Create(S.Context, "import_" + ImportAs.value())); 639440b1743SEgor Zhdan 640440b1743SEgor Zhdan if (auto RetainOp = Info.SwiftRetainOp) 641440b1743SEgor Zhdan D->addAttr(SwiftAttrAttr::Create(S.Context, "retain:" + RetainOp.value())); 642440b1743SEgor Zhdan 643440b1743SEgor Zhdan if (auto ReleaseOp = Info.SwiftReleaseOp) 644440b1743SEgor Zhdan D->addAttr( 645440b1743SEgor Zhdan SwiftAttrAttr::Create(S.Context, "release:" + ReleaseOp.value())); 646440b1743SEgor Zhdan 647dc8c217dSEgor Zhdan if (auto ConformsTo = Info.SwiftConformance) 648dc8c217dSEgor Zhdan D->addAttr( 649dc8c217dSEgor Zhdan SwiftAttrAttr::Create(S.Context, "conforms_to:" + ConformsTo.value())); 650dc8c217dSEgor Zhdan 651b2098db2SEgor Zhdan if (auto Copyable = Info.isSwiftCopyable()) { 652b2098db2SEgor Zhdan if (!*Copyable) 653b2098db2SEgor Zhdan D->addAttr(SwiftAttrAttr::Create(S.Context, "~Copyable")); 654b2098db2SEgor Zhdan } 655b2098db2SEgor Zhdan 656d2db9bd7SGábor Horváth if (auto Escapable = Info.isSwiftEscapable()) { 657d2db9bd7SGábor Horváth D->addAttr(SwiftAttrAttr::Create(S.Context, 658d2db9bd7SGábor Horváth *Escapable ? "Escapable" : "~Escapable")); 659d2db9bd7SGábor Horváth } 660d2db9bd7SGábor Horváth 661440b1743SEgor Zhdan if (auto Extensibility = Info.EnumExtensibility) { 662440b1743SEgor Zhdan using api_notes::EnumExtensibilityKind; 663440b1743SEgor Zhdan bool ShouldAddAttribute = (*Extensibility != EnumExtensibilityKind::None); 664440b1743SEgor Zhdan handleAPINotedAttribute<EnumExtensibilityAttr>( 665440b1743SEgor Zhdan S, D, ShouldAddAttribute, Metadata, [&] { 666440b1743SEgor Zhdan EnumExtensibilityAttr::Kind kind; 667440b1743SEgor Zhdan switch (*Extensibility) { 668440b1743SEgor Zhdan case EnumExtensibilityKind::None: 669440b1743SEgor Zhdan llvm_unreachable("remove only"); 670440b1743SEgor Zhdan case EnumExtensibilityKind::Open: 671440b1743SEgor Zhdan kind = EnumExtensibilityAttr::Open; 672440b1743SEgor Zhdan break; 673440b1743SEgor Zhdan case EnumExtensibilityKind::Closed: 674440b1743SEgor Zhdan kind = EnumExtensibilityAttr::Closed; 675440b1743SEgor Zhdan break; 676440b1743SEgor Zhdan } 677440b1743SEgor Zhdan return new (S.Context) 678440b1743SEgor Zhdan EnumExtensibilityAttr(S.Context, getPlaceholderAttrInfo(), kind); 679440b1743SEgor Zhdan }); 680440b1743SEgor Zhdan } 681440b1743SEgor Zhdan 682440b1743SEgor Zhdan if (auto FlagEnum = Info.isFlagEnum()) { 683440b1743SEgor Zhdan handleAPINotedAttribute<FlagEnumAttr>(S, D, *FlagEnum, Metadata, [&] { 684440b1743SEgor Zhdan return new (S.Context) FlagEnumAttr(S.Context, getPlaceholderAttrInfo()); 685440b1743SEgor Zhdan }); 686440b1743SEgor Zhdan } 687440b1743SEgor Zhdan 688440b1743SEgor Zhdan // Handle common type information. 689440b1743SEgor Zhdan ProcessAPINotes(S, D, static_cast<const api_notes::CommonTypeInfo &>(Info), 690440b1743SEgor Zhdan Metadata); 691440b1743SEgor Zhdan } 692440b1743SEgor Zhdan 693440b1743SEgor Zhdan /// Process API notes for a typedef. 694440b1743SEgor Zhdan static void ProcessAPINotes(Sema &S, TypedefNameDecl *D, 695440b1743SEgor Zhdan const api_notes::TypedefInfo &Info, 696440b1743SEgor Zhdan VersionedInfoMetadata Metadata) { 697440b1743SEgor Zhdan // swift_wrapper 698440b1743SEgor Zhdan using SwiftWrapperKind = api_notes::SwiftNewTypeKind; 699440b1743SEgor Zhdan 700440b1743SEgor Zhdan if (auto SwiftWrapper = Info.SwiftWrapper) { 701440b1743SEgor Zhdan handleAPINotedAttribute<SwiftNewTypeAttr>( 702440b1743SEgor Zhdan S, D, *SwiftWrapper != SwiftWrapperKind::None, Metadata, [&] { 703440b1743SEgor Zhdan SwiftNewTypeAttr::NewtypeKind Kind; 704440b1743SEgor Zhdan switch (*SwiftWrapper) { 705440b1743SEgor Zhdan case SwiftWrapperKind::None: 706440b1743SEgor Zhdan llvm_unreachable("Shouldn't build an attribute"); 707440b1743SEgor Zhdan 708440b1743SEgor Zhdan case SwiftWrapperKind::Struct: 709440b1743SEgor Zhdan Kind = SwiftNewTypeAttr::NK_Struct; 710440b1743SEgor Zhdan break; 711440b1743SEgor Zhdan 712440b1743SEgor Zhdan case SwiftWrapperKind::Enum: 713440b1743SEgor Zhdan Kind = SwiftNewTypeAttr::NK_Enum; 714440b1743SEgor Zhdan break; 715440b1743SEgor Zhdan } 716440b1743SEgor Zhdan AttributeCommonInfo SyntaxInfo{ 717440b1743SEgor Zhdan SourceRange(), 718440b1743SEgor Zhdan AttributeCommonInfo::AT_SwiftNewType, 719440b1743SEgor Zhdan {AttributeCommonInfo::AS_GNU, SwiftNewTypeAttr::GNU_swift_wrapper, 720440b1743SEgor Zhdan /*IsAlignas*/ false, /*IsRegularKeywordAttribute*/ false}}; 721440b1743SEgor Zhdan return new (S.Context) SwiftNewTypeAttr(S.Context, SyntaxInfo, Kind); 722440b1743SEgor Zhdan }); 723440b1743SEgor Zhdan } 724440b1743SEgor Zhdan 725440b1743SEgor Zhdan // Handle common type information. 726440b1743SEgor Zhdan ProcessAPINotes(S, D, static_cast<const api_notes::CommonTypeInfo &>(Info), 727440b1743SEgor Zhdan Metadata); 728440b1743SEgor Zhdan } 729440b1743SEgor Zhdan 730440b1743SEgor Zhdan /// Process API notes for an Objective-C class or protocol. 731440b1743SEgor Zhdan static void ProcessAPINotes(Sema &S, ObjCContainerDecl *D, 73282ee7ae3SEgor Zhdan const api_notes::ContextInfo &Info, 733440b1743SEgor Zhdan VersionedInfoMetadata Metadata) { 734440b1743SEgor Zhdan // Handle common type information. 735440b1743SEgor Zhdan ProcessAPINotes(S, D, static_cast<const api_notes::CommonTypeInfo &>(Info), 736440b1743SEgor Zhdan Metadata); 737440b1743SEgor Zhdan } 738440b1743SEgor Zhdan 739440b1743SEgor Zhdan /// Process API notes for an Objective-C class. 740440b1743SEgor Zhdan static void ProcessAPINotes(Sema &S, ObjCInterfaceDecl *D, 74182ee7ae3SEgor Zhdan const api_notes::ContextInfo &Info, 742440b1743SEgor Zhdan VersionedInfoMetadata Metadata) { 743440b1743SEgor Zhdan if (auto AsNonGeneric = Info.getSwiftImportAsNonGeneric()) { 744440b1743SEgor Zhdan handleAPINotedAttribute<SwiftImportAsNonGenericAttr>( 745440b1743SEgor Zhdan S, D, *AsNonGeneric, Metadata, [&] { 746440b1743SEgor Zhdan return new (S.Context) 747440b1743SEgor Zhdan SwiftImportAsNonGenericAttr(S.Context, getPlaceholderAttrInfo()); 748440b1743SEgor Zhdan }); 749440b1743SEgor Zhdan } 750440b1743SEgor Zhdan 751440b1743SEgor Zhdan if (auto ObjcMembers = Info.getSwiftObjCMembers()) { 752440b1743SEgor Zhdan handleAPINotedAttribute<SwiftObjCMembersAttr>( 753440b1743SEgor Zhdan S, D, *ObjcMembers, Metadata, [&] { 754440b1743SEgor Zhdan return new (S.Context) 755440b1743SEgor Zhdan SwiftObjCMembersAttr(S.Context, getPlaceholderAttrInfo()); 756440b1743SEgor Zhdan }); 757440b1743SEgor Zhdan } 758440b1743SEgor Zhdan 759440b1743SEgor Zhdan // Handle information common to Objective-C classes and protocols. 760440b1743SEgor Zhdan ProcessAPINotes(S, static_cast<clang::ObjCContainerDecl *>(D), Info, 761440b1743SEgor Zhdan Metadata); 762440b1743SEgor Zhdan } 763440b1743SEgor Zhdan 764440b1743SEgor Zhdan /// If we're applying API notes with an active, non-default version, and the 765440b1743SEgor Zhdan /// versioned API notes have a SwiftName but the declaration normally wouldn't 766440b1743SEgor Zhdan /// have one, add a removal attribute to make it clear that the new SwiftName 767440b1743SEgor Zhdan /// attribute only applies to the active version of \p D, not to all versions. 768440b1743SEgor Zhdan /// 769440b1743SEgor Zhdan /// This must be run \em before processing API notes for \p D, because otherwise 770440b1743SEgor Zhdan /// any existing SwiftName attribute will have been packaged up in a 771440b1743SEgor Zhdan /// SwiftVersionedAdditionAttr. 772440b1743SEgor Zhdan template <typename SpecificInfo> 773440b1743SEgor Zhdan static void maybeAttachUnversionedSwiftName( 774440b1743SEgor Zhdan Sema &S, Decl *D, 775440b1743SEgor Zhdan const api_notes::APINotesReader::VersionedInfo<SpecificInfo> Info) { 776440b1743SEgor Zhdan if (D->hasAttr<SwiftNameAttr>()) 777440b1743SEgor Zhdan return; 778440b1743SEgor Zhdan if (!Info.getSelected()) 779440b1743SEgor Zhdan return; 780440b1743SEgor Zhdan 781440b1743SEgor Zhdan // Is the active slice versioned, and does it set a Swift name? 782440b1743SEgor Zhdan VersionTuple SelectedVersion; 783440b1743SEgor Zhdan SpecificInfo SelectedInfoSlice; 784440b1743SEgor Zhdan std::tie(SelectedVersion, SelectedInfoSlice) = Info[*Info.getSelected()]; 785440b1743SEgor Zhdan if (SelectedVersion.empty()) 786440b1743SEgor Zhdan return; 787440b1743SEgor Zhdan if (SelectedInfoSlice.SwiftName.empty()) 788440b1743SEgor Zhdan return; 789440b1743SEgor Zhdan 790440b1743SEgor Zhdan // Does the unversioned slice /not/ set a Swift name? 791440b1743SEgor Zhdan for (const auto &VersionAndInfoSlice : Info) { 792440b1743SEgor Zhdan if (!VersionAndInfoSlice.first.empty()) 793440b1743SEgor Zhdan continue; 794440b1743SEgor Zhdan if (!VersionAndInfoSlice.second.SwiftName.empty()) 795440b1743SEgor Zhdan return; 796440b1743SEgor Zhdan } 797440b1743SEgor Zhdan 798440b1743SEgor Zhdan // Then explicitly call that out with a removal attribute. 799440b1743SEgor Zhdan VersionedInfoMetadata DummyFutureMetadata( 800440b1743SEgor Zhdan SelectedVersion, IsActive_t::Inactive, IsSubstitution_t::Replacement); 801440b1743SEgor Zhdan handleAPINotedAttribute<SwiftNameAttr>( 802440b1743SEgor Zhdan S, D, /*add*/ false, DummyFutureMetadata, []() -> SwiftNameAttr * { 803440b1743SEgor Zhdan llvm_unreachable("should not try to add an attribute here"); 804440b1743SEgor Zhdan }); 805440b1743SEgor Zhdan } 806440b1743SEgor Zhdan 807440b1743SEgor Zhdan /// Processes all versions of versioned API notes. 808440b1743SEgor Zhdan /// 809440b1743SEgor Zhdan /// Just dispatches to the various ProcessAPINotes functions in this file. 810440b1743SEgor Zhdan template <typename SpecificDecl, typename SpecificInfo> 811440b1743SEgor Zhdan static void ProcessVersionedAPINotes( 812440b1743SEgor Zhdan Sema &S, SpecificDecl *D, 813440b1743SEgor Zhdan const api_notes::APINotesReader::VersionedInfo<SpecificInfo> Info) { 814440b1743SEgor Zhdan 815440b1743SEgor Zhdan maybeAttachUnversionedSwiftName(S, D, Info); 816440b1743SEgor Zhdan 817440b1743SEgor Zhdan unsigned Selected = Info.getSelected().value_or(Info.size()); 818440b1743SEgor Zhdan 819440b1743SEgor Zhdan VersionTuple Version; 820440b1743SEgor Zhdan SpecificInfo InfoSlice; 821440b1743SEgor Zhdan for (unsigned i = 0, e = Info.size(); i != e; ++i) { 822440b1743SEgor Zhdan std::tie(Version, InfoSlice) = Info[i]; 823440b1743SEgor Zhdan auto Active = (i == Selected) ? IsActive_t::Active : IsActive_t::Inactive; 824440b1743SEgor Zhdan auto Replacement = IsSubstitution_t::Original; 825440b1743SEgor Zhdan if (Active == IsActive_t::Inactive && Version.empty()) { 826440b1743SEgor Zhdan Replacement = IsSubstitution_t::Replacement; 827440b1743SEgor Zhdan Version = Info[Selected].first; 828440b1743SEgor Zhdan } 829440b1743SEgor Zhdan ProcessAPINotes(S, D, InfoSlice, 830440b1743SEgor Zhdan VersionedInfoMetadata(Version, Active, Replacement)); 831440b1743SEgor Zhdan } 832440b1743SEgor Zhdan } 833440b1743SEgor Zhdan 8344d5f81caSEgor Zhdan static std::optional<api_notes::Context> 8354d5f81caSEgor Zhdan UnwindNamespaceContext(DeclContext *DC, api_notes::APINotesManager &APINotes) { 8368a79dc7eSEgor Zhdan if (auto NamespaceContext = dyn_cast<NamespaceDecl>(DC)) { 8374d5f81caSEgor Zhdan for (auto Reader : APINotes.findAPINotes(NamespaceContext->getLocation())) { 838440b1743SEgor Zhdan // Retrieve the context ID for the parent namespace of the decl. 839440b1743SEgor Zhdan std::stack<NamespaceDecl *> NamespaceStack; 840440b1743SEgor Zhdan { 841440b1743SEgor Zhdan for (auto CurrentNamespace = NamespaceContext; CurrentNamespace; 842440b1743SEgor Zhdan CurrentNamespace = 843440b1743SEgor Zhdan dyn_cast<NamespaceDecl>(CurrentNamespace->getParent())) { 844440b1743SEgor Zhdan if (!CurrentNamespace->isInlineNamespace()) 845440b1743SEgor Zhdan NamespaceStack.push(CurrentNamespace); 846440b1743SEgor Zhdan } 847440b1743SEgor Zhdan } 848440b1743SEgor Zhdan std::optional<api_notes::ContextID> NamespaceID; 849440b1743SEgor Zhdan while (!NamespaceStack.empty()) { 850440b1743SEgor Zhdan auto CurrentNamespace = NamespaceStack.top(); 851440b1743SEgor Zhdan NamespaceStack.pop(); 8524d5f81caSEgor Zhdan NamespaceID = 8534d5f81caSEgor Zhdan Reader->lookupNamespaceID(CurrentNamespace->getName(), NamespaceID); 854440b1743SEgor Zhdan if (!NamespaceID) 8554d5f81caSEgor Zhdan return std::nullopt; 856440b1743SEgor Zhdan } 857440b1743SEgor Zhdan if (NamespaceID) 8588a79dc7eSEgor Zhdan return api_notes::Context(*NamespaceID, 8598a79dc7eSEgor Zhdan api_notes::ContextKind::Namespace); 860440b1743SEgor Zhdan } 861440b1743SEgor Zhdan } 8628a79dc7eSEgor Zhdan return std::nullopt; 8634d5f81caSEgor Zhdan } 8644d5f81caSEgor Zhdan 8654d5f81caSEgor Zhdan static std::optional<api_notes::Context> 8664d5f81caSEgor Zhdan UnwindTagContext(TagDecl *DC, api_notes::APINotesManager &APINotes) { 8674d5f81caSEgor Zhdan assert(DC && "tag context must not be null"); 8684d5f81caSEgor Zhdan for (auto Reader : APINotes.findAPINotes(DC->getLocation())) { 8694d5f81caSEgor Zhdan // Retrieve the context ID for the parent tag of the decl. 8704d5f81caSEgor Zhdan std::stack<TagDecl *> TagStack; 8714d5f81caSEgor Zhdan { 8724d5f81caSEgor Zhdan for (auto CurrentTag = DC; CurrentTag; 8734d5f81caSEgor Zhdan CurrentTag = dyn_cast<TagDecl>(CurrentTag->getParent())) 8744d5f81caSEgor Zhdan TagStack.push(CurrentTag); 8754d5f81caSEgor Zhdan } 8764d5f81caSEgor Zhdan assert(!TagStack.empty()); 8774d5f81caSEgor Zhdan std::optional<api_notes::Context> Ctx = 8784d5f81caSEgor Zhdan UnwindNamespaceContext(TagStack.top()->getDeclContext(), APINotes); 8794d5f81caSEgor Zhdan while (!TagStack.empty()) { 8804d5f81caSEgor Zhdan auto CurrentTag = TagStack.top(); 8814d5f81caSEgor Zhdan TagStack.pop(); 8824d5f81caSEgor Zhdan auto CtxID = Reader->lookupTagID(CurrentTag->getName(), Ctx); 8834d5f81caSEgor Zhdan if (!CtxID) 8844d5f81caSEgor Zhdan return std::nullopt; 8854d5f81caSEgor Zhdan Ctx = api_notes::Context(*CtxID, api_notes::ContextKind::Tag); 8864d5f81caSEgor Zhdan } 8874d5f81caSEgor Zhdan return Ctx; 8884d5f81caSEgor Zhdan } 8894d5f81caSEgor Zhdan return std::nullopt; 8904d5f81caSEgor Zhdan } 8914d5f81caSEgor Zhdan 8924d5f81caSEgor Zhdan /// Process API notes that are associated with this declaration, mapping them 8934d5f81caSEgor Zhdan /// to attributes as appropriate. 8944d5f81caSEgor Zhdan void Sema::ProcessAPINotes(Decl *D) { 8954d5f81caSEgor Zhdan if (!D) 8964d5f81caSEgor Zhdan return; 897440b1743SEgor Zhdan 8987ac78f13SGábor Horváth auto *DC = D->getDeclContext(); 8998a79dc7eSEgor Zhdan // Globals. 9007ac78f13SGábor Horváth if (DC->isFileContext() || DC->isNamespace() || DC->isExternCContext() || 9017ac78f13SGábor Horváth DC->isExternCXXContext()) { 9028a79dc7eSEgor Zhdan std::optional<api_notes::Context> APINotesContext = 9037ac78f13SGábor Horváth UnwindNamespaceContext(DC, APINotes); 904440b1743SEgor Zhdan // Global variables. 905440b1743SEgor Zhdan if (auto VD = dyn_cast<VarDecl>(D)) { 906440b1743SEgor Zhdan for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 907440b1743SEgor Zhdan auto Info = 908440b1743SEgor Zhdan Reader->lookupGlobalVariable(VD->getName(), APINotesContext); 909440b1743SEgor Zhdan ProcessVersionedAPINotes(*this, VD, Info); 910440b1743SEgor Zhdan } 911440b1743SEgor Zhdan 912440b1743SEgor Zhdan return; 913440b1743SEgor Zhdan } 914440b1743SEgor Zhdan 915440b1743SEgor Zhdan // Global functions. 916440b1743SEgor Zhdan if (auto FD = dyn_cast<FunctionDecl>(D)) { 917440b1743SEgor Zhdan if (FD->getDeclName().isIdentifier()) { 918440b1743SEgor Zhdan for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 919440b1743SEgor Zhdan auto Info = 920440b1743SEgor Zhdan Reader->lookupGlobalFunction(FD->getName(), APINotesContext); 921440b1743SEgor Zhdan ProcessVersionedAPINotes(*this, FD, Info); 922440b1743SEgor Zhdan } 923440b1743SEgor Zhdan } 924440b1743SEgor Zhdan 925440b1743SEgor Zhdan return; 926440b1743SEgor Zhdan } 927440b1743SEgor Zhdan 928440b1743SEgor Zhdan // Objective-C classes. 929440b1743SEgor Zhdan if (auto Class = dyn_cast<ObjCInterfaceDecl>(D)) { 930440b1743SEgor Zhdan for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 931440b1743SEgor Zhdan auto Info = Reader->lookupObjCClassInfo(Class->getName()); 932440b1743SEgor Zhdan ProcessVersionedAPINotes(*this, Class, Info); 933440b1743SEgor Zhdan } 934440b1743SEgor Zhdan 935440b1743SEgor Zhdan return; 936440b1743SEgor Zhdan } 937440b1743SEgor Zhdan 938440b1743SEgor Zhdan // Objective-C protocols. 939440b1743SEgor Zhdan if (auto Protocol = dyn_cast<ObjCProtocolDecl>(D)) { 940440b1743SEgor Zhdan for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 941440b1743SEgor Zhdan auto Info = Reader->lookupObjCProtocolInfo(Protocol->getName()); 942440b1743SEgor Zhdan ProcessVersionedAPINotes(*this, Protocol, Info); 943440b1743SEgor Zhdan } 944440b1743SEgor Zhdan 945440b1743SEgor Zhdan return; 946440b1743SEgor Zhdan } 947440b1743SEgor Zhdan 948440b1743SEgor Zhdan // Tags 949440b1743SEgor Zhdan if (auto Tag = dyn_cast<TagDecl>(D)) { 950694fd1f2SDoug Gregor // Determine the name of the entity to search for. If this is an 951694fd1f2SDoug Gregor // anonymous tag that gets its linked name from a typedef, look for the 952694fd1f2SDoug Gregor // typedef name. This allows tag-specific information to be added 953694fd1f2SDoug Gregor // to the declaration. 954694fd1f2SDoug Gregor std::string LookupName; 955694fd1f2SDoug Gregor if (auto typedefName = Tag->getTypedefNameForAnonDecl()) 956694fd1f2SDoug Gregor LookupName = typedefName->getName().str(); 957694fd1f2SDoug Gregor else 958694fd1f2SDoug Gregor LookupName = Tag->getName().str(); 959440b1743SEgor Zhdan 960440b1743SEgor Zhdan // Use the source location to discern if this Tag is an OPTIONS macro. 961440b1743SEgor Zhdan // For now we would like to limit this trick of looking up the APINote tag 962440b1743SEgor Zhdan // using the EnumDecl's QualType in the case where the enum is anonymous. 963440b1743SEgor Zhdan // This is only being used to support APINotes lookup for C++ 964440b1743SEgor Zhdan // NS/CF_OPTIONS when C++-Interop is enabled. 965440b1743SEgor Zhdan std::string MacroName = 966440b1743SEgor Zhdan LookupName.empty() && Tag->getOuterLocStart().isMacroID() 967440b1743SEgor Zhdan ? clang::Lexer::getImmediateMacroName( 968440b1743SEgor Zhdan Tag->getOuterLocStart(), 969440b1743SEgor Zhdan Tag->getASTContext().getSourceManager(), LangOpts) 970440b1743SEgor Zhdan .str() 971440b1743SEgor Zhdan : ""; 972440b1743SEgor Zhdan 973440b1743SEgor Zhdan if (LookupName.empty() && isa<clang::EnumDecl>(Tag) && 974440b1743SEgor Zhdan (MacroName == "CF_OPTIONS" || MacroName == "NS_OPTIONS" || 975440b1743SEgor Zhdan MacroName == "OBJC_OPTIONS" || MacroName == "SWIFT_OPTIONS")) { 976440b1743SEgor Zhdan 977440b1743SEgor Zhdan clang::QualType T = llvm::cast<clang::EnumDecl>(Tag)->getIntegerType(); 978440b1743SEgor Zhdan LookupName = clang::QualType::getAsString( 979440b1743SEgor Zhdan T.split(), getASTContext().getPrintingPolicy()); 980440b1743SEgor Zhdan } 981440b1743SEgor Zhdan 982440b1743SEgor Zhdan for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 9834d5f81caSEgor Zhdan if (auto ParentTag = dyn_cast<TagDecl>(Tag->getDeclContext())) 9844d5f81caSEgor Zhdan APINotesContext = UnwindTagContext(ParentTag, APINotes); 985440b1743SEgor Zhdan auto Info = Reader->lookupTag(LookupName, APINotesContext); 986440b1743SEgor Zhdan ProcessVersionedAPINotes(*this, Tag, Info); 987440b1743SEgor Zhdan } 988440b1743SEgor Zhdan 989440b1743SEgor Zhdan return; 990440b1743SEgor Zhdan } 991440b1743SEgor Zhdan 992440b1743SEgor Zhdan // Typedefs 993440b1743SEgor Zhdan if (auto Typedef = dyn_cast<TypedefNameDecl>(D)) { 994440b1743SEgor Zhdan for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 995440b1743SEgor Zhdan auto Info = Reader->lookupTypedef(Typedef->getName(), APINotesContext); 996440b1743SEgor Zhdan ProcessVersionedAPINotes(*this, Typedef, Info); 997440b1743SEgor Zhdan } 998440b1743SEgor Zhdan 999440b1743SEgor Zhdan return; 1000440b1743SEgor Zhdan } 1001440b1743SEgor Zhdan } 1002440b1743SEgor Zhdan 1003440b1743SEgor Zhdan // Enumerators. 10047ac78f13SGábor Horváth if (DC->getRedeclContext()->isFileContext() || 10057ac78f13SGábor Horváth DC->getRedeclContext()->isExternCContext()) { 1006440b1743SEgor Zhdan if (auto EnumConstant = dyn_cast<EnumConstantDecl>(D)) { 1007440b1743SEgor Zhdan for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 1008440b1743SEgor Zhdan auto Info = Reader->lookupEnumConstant(EnumConstant->getName()); 1009440b1743SEgor Zhdan ProcessVersionedAPINotes(*this, EnumConstant, Info); 1010440b1743SEgor Zhdan } 1011440b1743SEgor Zhdan 1012440b1743SEgor Zhdan return; 1013440b1743SEgor Zhdan } 1014440b1743SEgor Zhdan } 1015440b1743SEgor Zhdan 10167ac78f13SGábor Horváth if (auto ObjCContainer = dyn_cast<ObjCContainerDecl>(DC)) { 1017440b1743SEgor Zhdan // Location function that looks up an Objective-C context. 1018440b1743SEgor Zhdan auto GetContext = [&](api_notes::APINotesReader *Reader) 1019440b1743SEgor Zhdan -> std::optional<api_notes::ContextID> { 1020440b1743SEgor Zhdan if (auto Protocol = dyn_cast<ObjCProtocolDecl>(ObjCContainer)) { 1021440b1743SEgor Zhdan if (auto Found = Reader->lookupObjCProtocolID(Protocol->getName())) 1022440b1743SEgor Zhdan return *Found; 1023440b1743SEgor Zhdan 1024440b1743SEgor Zhdan return std::nullopt; 1025440b1743SEgor Zhdan } 1026440b1743SEgor Zhdan 1027440b1743SEgor Zhdan if (auto Impl = dyn_cast<ObjCCategoryImplDecl>(ObjCContainer)) { 1028440b1743SEgor Zhdan if (auto Cat = Impl->getCategoryDecl()) 1029440b1743SEgor Zhdan ObjCContainer = Cat->getClassInterface(); 1030440b1743SEgor Zhdan else 1031440b1743SEgor Zhdan return std::nullopt; 1032440b1743SEgor Zhdan } 1033440b1743SEgor Zhdan 1034440b1743SEgor Zhdan if (auto Category = dyn_cast<ObjCCategoryDecl>(ObjCContainer)) { 1035440b1743SEgor Zhdan if (Category->getClassInterface()) 1036440b1743SEgor Zhdan ObjCContainer = Category->getClassInterface(); 1037440b1743SEgor Zhdan else 1038440b1743SEgor Zhdan return std::nullopt; 1039440b1743SEgor Zhdan } 1040440b1743SEgor Zhdan 1041440b1743SEgor Zhdan if (auto Impl = dyn_cast<ObjCImplDecl>(ObjCContainer)) { 1042440b1743SEgor Zhdan if (Impl->getClassInterface()) 1043440b1743SEgor Zhdan ObjCContainer = Impl->getClassInterface(); 1044440b1743SEgor Zhdan else 1045440b1743SEgor Zhdan return std::nullopt; 1046440b1743SEgor Zhdan } 1047440b1743SEgor Zhdan 1048440b1743SEgor Zhdan if (auto Class = dyn_cast<ObjCInterfaceDecl>(ObjCContainer)) { 1049440b1743SEgor Zhdan if (auto Found = Reader->lookupObjCClassID(Class->getName())) 1050440b1743SEgor Zhdan return *Found; 1051440b1743SEgor Zhdan 1052440b1743SEgor Zhdan return std::nullopt; 1053440b1743SEgor Zhdan } 1054440b1743SEgor Zhdan 1055440b1743SEgor Zhdan return std::nullopt; 1056440b1743SEgor Zhdan }; 1057440b1743SEgor Zhdan 1058440b1743SEgor Zhdan // Objective-C methods. 1059440b1743SEgor Zhdan if (auto Method = dyn_cast<ObjCMethodDecl>(D)) { 1060440b1743SEgor Zhdan for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 1061440b1743SEgor Zhdan if (auto Context = GetContext(Reader)) { 1062440b1743SEgor Zhdan // Map the selector. 1063440b1743SEgor Zhdan Selector Sel = Method->getSelector(); 1064440b1743SEgor Zhdan SmallVector<StringRef, 2> SelPieces; 1065440b1743SEgor Zhdan if (Sel.isUnarySelector()) { 1066440b1743SEgor Zhdan SelPieces.push_back(Sel.getNameForSlot(0)); 1067440b1743SEgor Zhdan } else { 1068440b1743SEgor Zhdan for (unsigned i = 0, n = Sel.getNumArgs(); i != n; ++i) 1069440b1743SEgor Zhdan SelPieces.push_back(Sel.getNameForSlot(i)); 1070440b1743SEgor Zhdan } 1071440b1743SEgor Zhdan 1072440b1743SEgor Zhdan api_notes::ObjCSelectorRef SelectorRef; 1073440b1743SEgor Zhdan SelectorRef.NumArgs = Sel.getNumArgs(); 1074440b1743SEgor Zhdan SelectorRef.Identifiers = SelPieces; 1075440b1743SEgor Zhdan 1076440b1743SEgor Zhdan auto Info = Reader->lookupObjCMethod(*Context, SelectorRef, 1077440b1743SEgor Zhdan Method->isInstanceMethod()); 1078440b1743SEgor Zhdan ProcessVersionedAPINotes(*this, Method, Info); 1079440b1743SEgor Zhdan } 1080440b1743SEgor Zhdan } 1081440b1743SEgor Zhdan } 1082440b1743SEgor Zhdan 1083440b1743SEgor Zhdan // Objective-C properties. 1084440b1743SEgor Zhdan if (auto Property = dyn_cast<ObjCPropertyDecl>(D)) { 1085440b1743SEgor Zhdan for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 1086440b1743SEgor Zhdan if (auto Context = GetContext(Reader)) { 1087440b1743SEgor Zhdan bool isInstanceProperty = 1088440b1743SEgor Zhdan (Property->getPropertyAttributesAsWritten() & 1089440b1743SEgor Zhdan ObjCPropertyAttribute::kind_class) == 0; 1090440b1743SEgor Zhdan auto Info = Reader->lookupObjCProperty(*Context, Property->getName(), 1091440b1743SEgor Zhdan isInstanceProperty); 1092440b1743SEgor Zhdan ProcessVersionedAPINotes(*this, Property, Info); 1093440b1743SEgor Zhdan } 1094440b1743SEgor Zhdan } 1095440b1743SEgor Zhdan 1096440b1743SEgor Zhdan return; 1097440b1743SEgor Zhdan } 1098440b1743SEgor Zhdan } 10998a79dc7eSEgor Zhdan 11007ac78f13SGábor Horváth if (auto TagContext = dyn_cast<TagDecl>(DC)) { 11018a79dc7eSEgor Zhdan if (auto CXXMethod = dyn_cast<CXXMethodDecl>(D)) { 1102c66d25d1SEgor Zhdan if (!isa<CXXConstructorDecl>(CXXMethod) && 1103c66d25d1SEgor Zhdan !isa<CXXDestructorDecl>(CXXMethod) && 1104c66d25d1SEgor Zhdan !isa<CXXConversionDecl>(CXXMethod) && 1105c66d25d1SEgor Zhdan !CXXMethod->isOverloadedOperator()) { 11068a79dc7eSEgor Zhdan for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 11074d5f81caSEgor Zhdan if (auto Context = UnwindTagContext(TagContext, APINotes)) { 11084d5f81caSEgor Zhdan auto Info = 11094d5f81caSEgor Zhdan Reader->lookupCXXMethod(Context->id, CXXMethod->getName()); 11108a79dc7eSEgor Zhdan ProcessVersionedAPINotes(*this, CXXMethod, Info); 11118a79dc7eSEgor Zhdan } 11128a79dc7eSEgor Zhdan } 11138a79dc7eSEgor Zhdan } 1114c66d25d1SEgor Zhdan } 11154d5f81caSEgor Zhdan 1116b8169771SEgor Zhdan if (auto Field = dyn_cast<FieldDecl>(D)) { 1117b8169771SEgor Zhdan if (!Field->isUnnamedBitField() && !Field->isAnonymousStructOrUnion()) { 1118b8169771SEgor Zhdan for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 1119b8169771SEgor Zhdan if (auto Context = UnwindTagContext(TagContext, APINotes)) { 1120b8169771SEgor Zhdan auto Info = Reader->lookupField(Context->id, Field->getName()); 1121b8169771SEgor Zhdan ProcessVersionedAPINotes(*this, Field, Info); 1122b8169771SEgor Zhdan } 1123b8169771SEgor Zhdan } 1124b8169771SEgor Zhdan } 1125b8169771SEgor Zhdan } 1126b8169771SEgor Zhdan 11274d5f81caSEgor Zhdan if (auto Tag = dyn_cast<TagDecl>(D)) { 11284d5f81caSEgor Zhdan for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 11294d5f81caSEgor Zhdan if (auto Context = UnwindTagContext(TagContext, APINotes)) { 11304d5f81caSEgor Zhdan auto Info = Reader->lookupTag(Tag->getName(), Context); 11314d5f81caSEgor Zhdan ProcessVersionedAPINotes(*this, Tag, Info); 11324d5f81caSEgor Zhdan } 11334d5f81caSEgor Zhdan } 11344d5f81caSEgor Zhdan } 11358a79dc7eSEgor Zhdan } 1136440b1743SEgor Zhdan } 1137