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