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