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