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 Copyable = Info.isSwiftCopyable()) { 609 if (!*Copyable) 610 D->addAttr(SwiftAttrAttr::Create(S.Context, "~Copyable")); 611 } 612 613 if (auto Extensibility = Info.EnumExtensibility) { 614 using api_notes::EnumExtensibilityKind; 615 bool ShouldAddAttribute = (*Extensibility != EnumExtensibilityKind::None); 616 handleAPINotedAttribute<EnumExtensibilityAttr>( 617 S, D, ShouldAddAttribute, Metadata, [&] { 618 EnumExtensibilityAttr::Kind kind; 619 switch (*Extensibility) { 620 case EnumExtensibilityKind::None: 621 llvm_unreachable("remove only"); 622 case EnumExtensibilityKind::Open: 623 kind = EnumExtensibilityAttr::Open; 624 break; 625 case EnumExtensibilityKind::Closed: 626 kind = EnumExtensibilityAttr::Closed; 627 break; 628 } 629 return new (S.Context) 630 EnumExtensibilityAttr(S.Context, getPlaceholderAttrInfo(), kind); 631 }); 632 } 633 634 if (auto FlagEnum = Info.isFlagEnum()) { 635 handleAPINotedAttribute<FlagEnumAttr>(S, D, *FlagEnum, Metadata, [&] { 636 return new (S.Context) FlagEnumAttr(S.Context, getPlaceholderAttrInfo()); 637 }); 638 } 639 640 // Handle common type information. 641 ProcessAPINotes(S, D, static_cast<const api_notes::CommonTypeInfo &>(Info), 642 Metadata); 643 } 644 645 /// Process API notes for a typedef. 646 static void ProcessAPINotes(Sema &S, TypedefNameDecl *D, 647 const api_notes::TypedefInfo &Info, 648 VersionedInfoMetadata Metadata) { 649 // swift_wrapper 650 using SwiftWrapperKind = api_notes::SwiftNewTypeKind; 651 652 if (auto SwiftWrapper = Info.SwiftWrapper) { 653 handleAPINotedAttribute<SwiftNewTypeAttr>( 654 S, D, *SwiftWrapper != SwiftWrapperKind::None, Metadata, [&] { 655 SwiftNewTypeAttr::NewtypeKind Kind; 656 switch (*SwiftWrapper) { 657 case SwiftWrapperKind::None: 658 llvm_unreachable("Shouldn't build an attribute"); 659 660 case SwiftWrapperKind::Struct: 661 Kind = SwiftNewTypeAttr::NK_Struct; 662 break; 663 664 case SwiftWrapperKind::Enum: 665 Kind = SwiftNewTypeAttr::NK_Enum; 666 break; 667 } 668 AttributeCommonInfo SyntaxInfo{ 669 SourceRange(), 670 AttributeCommonInfo::AT_SwiftNewType, 671 {AttributeCommonInfo::AS_GNU, SwiftNewTypeAttr::GNU_swift_wrapper, 672 /*IsAlignas*/ false, /*IsRegularKeywordAttribute*/ false}}; 673 return new (S.Context) SwiftNewTypeAttr(S.Context, SyntaxInfo, Kind); 674 }); 675 } 676 677 // Handle common type information. 678 ProcessAPINotes(S, D, static_cast<const api_notes::CommonTypeInfo &>(Info), 679 Metadata); 680 } 681 682 /// Process API notes for an Objective-C class or protocol. 683 static void ProcessAPINotes(Sema &S, ObjCContainerDecl *D, 684 const api_notes::ContextInfo &Info, 685 VersionedInfoMetadata Metadata) { 686 // Handle common type information. 687 ProcessAPINotes(S, D, static_cast<const api_notes::CommonTypeInfo &>(Info), 688 Metadata); 689 } 690 691 /// Process API notes for an Objective-C class. 692 static void ProcessAPINotes(Sema &S, ObjCInterfaceDecl *D, 693 const api_notes::ContextInfo &Info, 694 VersionedInfoMetadata Metadata) { 695 if (auto AsNonGeneric = Info.getSwiftImportAsNonGeneric()) { 696 handleAPINotedAttribute<SwiftImportAsNonGenericAttr>( 697 S, D, *AsNonGeneric, Metadata, [&] { 698 return new (S.Context) 699 SwiftImportAsNonGenericAttr(S.Context, getPlaceholderAttrInfo()); 700 }); 701 } 702 703 if (auto ObjcMembers = Info.getSwiftObjCMembers()) { 704 handleAPINotedAttribute<SwiftObjCMembersAttr>( 705 S, D, *ObjcMembers, Metadata, [&] { 706 return new (S.Context) 707 SwiftObjCMembersAttr(S.Context, getPlaceholderAttrInfo()); 708 }); 709 } 710 711 // Handle information common to Objective-C classes and protocols. 712 ProcessAPINotes(S, static_cast<clang::ObjCContainerDecl *>(D), Info, 713 Metadata); 714 } 715 716 /// If we're applying API notes with an active, non-default version, and the 717 /// versioned API notes have a SwiftName but the declaration normally wouldn't 718 /// have one, add a removal attribute to make it clear that the new SwiftName 719 /// attribute only applies to the active version of \p D, not to all versions. 720 /// 721 /// This must be run \em before processing API notes for \p D, because otherwise 722 /// any existing SwiftName attribute will have been packaged up in a 723 /// SwiftVersionedAdditionAttr. 724 template <typename SpecificInfo> 725 static void maybeAttachUnversionedSwiftName( 726 Sema &S, Decl *D, 727 const api_notes::APINotesReader::VersionedInfo<SpecificInfo> Info) { 728 if (D->hasAttr<SwiftNameAttr>()) 729 return; 730 if (!Info.getSelected()) 731 return; 732 733 // Is the active slice versioned, and does it set a Swift name? 734 VersionTuple SelectedVersion; 735 SpecificInfo SelectedInfoSlice; 736 std::tie(SelectedVersion, SelectedInfoSlice) = Info[*Info.getSelected()]; 737 if (SelectedVersion.empty()) 738 return; 739 if (SelectedInfoSlice.SwiftName.empty()) 740 return; 741 742 // Does the unversioned slice /not/ set a Swift name? 743 for (const auto &VersionAndInfoSlice : Info) { 744 if (!VersionAndInfoSlice.first.empty()) 745 continue; 746 if (!VersionAndInfoSlice.second.SwiftName.empty()) 747 return; 748 } 749 750 // Then explicitly call that out with a removal attribute. 751 VersionedInfoMetadata DummyFutureMetadata( 752 SelectedVersion, IsActive_t::Inactive, IsSubstitution_t::Replacement); 753 handleAPINotedAttribute<SwiftNameAttr>( 754 S, D, /*add*/ false, DummyFutureMetadata, []() -> SwiftNameAttr * { 755 llvm_unreachable("should not try to add an attribute here"); 756 }); 757 } 758 759 /// Processes all versions of versioned API notes. 760 /// 761 /// Just dispatches to the various ProcessAPINotes functions in this file. 762 template <typename SpecificDecl, typename SpecificInfo> 763 static void ProcessVersionedAPINotes( 764 Sema &S, SpecificDecl *D, 765 const api_notes::APINotesReader::VersionedInfo<SpecificInfo> Info) { 766 767 maybeAttachUnversionedSwiftName(S, D, Info); 768 769 unsigned Selected = Info.getSelected().value_or(Info.size()); 770 771 VersionTuple Version; 772 SpecificInfo InfoSlice; 773 for (unsigned i = 0, e = Info.size(); i != e; ++i) { 774 std::tie(Version, InfoSlice) = Info[i]; 775 auto Active = (i == Selected) ? IsActive_t::Active : IsActive_t::Inactive; 776 auto Replacement = IsSubstitution_t::Original; 777 if (Active == IsActive_t::Inactive && Version.empty()) { 778 Replacement = IsSubstitution_t::Replacement; 779 Version = Info[Selected].first; 780 } 781 ProcessAPINotes(S, D, InfoSlice, 782 VersionedInfoMetadata(Version, Active, Replacement)); 783 } 784 } 785 786 /// Process API notes that are associated with this declaration, mapping them 787 /// to attributes as appropriate. 788 void Sema::ProcessAPINotes(Decl *D) { 789 if (!D) 790 return; 791 792 auto GetNamespaceContext = 793 [&](DeclContext *DC) -> std::optional<api_notes::Context> { 794 if (auto NamespaceContext = dyn_cast<NamespaceDecl>(DC)) { 795 for (auto Reader : 796 APINotes.findAPINotes(NamespaceContext->getLocation())) { 797 // Retrieve the context ID for the parent namespace of the decl. 798 std::stack<NamespaceDecl *> NamespaceStack; 799 { 800 for (auto CurrentNamespace = NamespaceContext; CurrentNamespace; 801 CurrentNamespace = 802 dyn_cast<NamespaceDecl>(CurrentNamespace->getParent())) { 803 if (!CurrentNamespace->isInlineNamespace()) 804 NamespaceStack.push(CurrentNamespace); 805 } 806 } 807 std::optional<api_notes::ContextID> NamespaceID; 808 while (!NamespaceStack.empty()) { 809 auto CurrentNamespace = NamespaceStack.top(); 810 NamespaceStack.pop(); 811 NamespaceID = Reader->lookupNamespaceID(CurrentNamespace->getName(), 812 NamespaceID); 813 if (!NamespaceID) 814 break; 815 } 816 if (NamespaceID) 817 return api_notes::Context(*NamespaceID, 818 api_notes::ContextKind::Namespace); 819 } 820 } 821 return std::nullopt; 822 }; 823 824 // Globals. 825 if (D->getDeclContext()->isFileContext() || 826 D->getDeclContext()->isNamespace() || 827 D->getDeclContext()->isExternCContext() || 828 D->getDeclContext()->isExternCXXContext()) { 829 std::optional<api_notes::Context> APINotesContext = 830 GetNamespaceContext(D->getDeclContext()); 831 // Global variables. 832 if (auto VD = dyn_cast<VarDecl>(D)) { 833 for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 834 auto Info = 835 Reader->lookupGlobalVariable(VD->getName(), APINotesContext); 836 ProcessVersionedAPINotes(*this, VD, Info); 837 } 838 839 return; 840 } 841 842 // Global functions. 843 if (auto FD = dyn_cast<FunctionDecl>(D)) { 844 if (FD->getDeclName().isIdentifier()) { 845 for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 846 auto Info = 847 Reader->lookupGlobalFunction(FD->getName(), APINotesContext); 848 ProcessVersionedAPINotes(*this, FD, Info); 849 } 850 } 851 852 return; 853 } 854 855 // Objective-C classes. 856 if (auto Class = dyn_cast<ObjCInterfaceDecl>(D)) { 857 for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 858 auto Info = Reader->lookupObjCClassInfo(Class->getName()); 859 ProcessVersionedAPINotes(*this, Class, Info); 860 } 861 862 return; 863 } 864 865 // Objective-C protocols. 866 if (auto Protocol = dyn_cast<ObjCProtocolDecl>(D)) { 867 for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 868 auto Info = Reader->lookupObjCProtocolInfo(Protocol->getName()); 869 ProcessVersionedAPINotes(*this, Protocol, Info); 870 } 871 872 return; 873 } 874 875 // Tags 876 if (auto Tag = dyn_cast<TagDecl>(D)) { 877 std::string LookupName = Tag->getName().str(); 878 879 // Use the source location to discern if this Tag is an OPTIONS macro. 880 // For now we would like to limit this trick of looking up the APINote tag 881 // using the EnumDecl's QualType in the case where the enum is anonymous. 882 // This is only being used to support APINotes lookup for C++ 883 // NS/CF_OPTIONS when C++-Interop is enabled. 884 std::string MacroName = 885 LookupName.empty() && Tag->getOuterLocStart().isMacroID() 886 ? clang::Lexer::getImmediateMacroName( 887 Tag->getOuterLocStart(), 888 Tag->getASTContext().getSourceManager(), LangOpts) 889 .str() 890 : ""; 891 892 if (LookupName.empty() && isa<clang::EnumDecl>(Tag) && 893 (MacroName == "CF_OPTIONS" || MacroName == "NS_OPTIONS" || 894 MacroName == "OBJC_OPTIONS" || MacroName == "SWIFT_OPTIONS")) { 895 896 clang::QualType T = llvm::cast<clang::EnumDecl>(Tag)->getIntegerType(); 897 LookupName = clang::QualType::getAsString( 898 T.split(), getASTContext().getPrintingPolicy()); 899 } 900 901 for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 902 auto Info = Reader->lookupTag(LookupName, APINotesContext); 903 ProcessVersionedAPINotes(*this, Tag, Info); 904 } 905 906 return; 907 } 908 909 // Typedefs 910 if (auto Typedef = dyn_cast<TypedefNameDecl>(D)) { 911 for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 912 auto Info = Reader->lookupTypedef(Typedef->getName(), APINotesContext); 913 ProcessVersionedAPINotes(*this, Typedef, Info); 914 } 915 916 return; 917 } 918 } 919 920 // Enumerators. 921 if (D->getDeclContext()->getRedeclContext()->isFileContext() || 922 D->getDeclContext()->getRedeclContext()->isExternCContext()) { 923 if (auto EnumConstant = dyn_cast<EnumConstantDecl>(D)) { 924 for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 925 auto Info = Reader->lookupEnumConstant(EnumConstant->getName()); 926 ProcessVersionedAPINotes(*this, EnumConstant, Info); 927 } 928 929 return; 930 } 931 } 932 933 if (auto ObjCContainer = dyn_cast<ObjCContainerDecl>(D->getDeclContext())) { 934 // Location function that looks up an Objective-C context. 935 auto GetContext = [&](api_notes::APINotesReader *Reader) 936 -> std::optional<api_notes::ContextID> { 937 if (auto Protocol = dyn_cast<ObjCProtocolDecl>(ObjCContainer)) { 938 if (auto Found = Reader->lookupObjCProtocolID(Protocol->getName())) 939 return *Found; 940 941 return std::nullopt; 942 } 943 944 if (auto Impl = dyn_cast<ObjCCategoryImplDecl>(ObjCContainer)) { 945 if (auto Cat = Impl->getCategoryDecl()) 946 ObjCContainer = Cat->getClassInterface(); 947 else 948 return std::nullopt; 949 } 950 951 if (auto Category = dyn_cast<ObjCCategoryDecl>(ObjCContainer)) { 952 if (Category->getClassInterface()) 953 ObjCContainer = Category->getClassInterface(); 954 else 955 return std::nullopt; 956 } 957 958 if (auto Impl = dyn_cast<ObjCImplDecl>(ObjCContainer)) { 959 if (Impl->getClassInterface()) 960 ObjCContainer = Impl->getClassInterface(); 961 else 962 return std::nullopt; 963 } 964 965 if (auto Class = dyn_cast<ObjCInterfaceDecl>(ObjCContainer)) { 966 if (auto Found = Reader->lookupObjCClassID(Class->getName())) 967 return *Found; 968 969 return std::nullopt; 970 } 971 972 return std::nullopt; 973 }; 974 975 // Objective-C methods. 976 if (auto Method = dyn_cast<ObjCMethodDecl>(D)) { 977 for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 978 if (auto Context = GetContext(Reader)) { 979 // Map the selector. 980 Selector Sel = Method->getSelector(); 981 SmallVector<StringRef, 2> SelPieces; 982 if (Sel.isUnarySelector()) { 983 SelPieces.push_back(Sel.getNameForSlot(0)); 984 } else { 985 for (unsigned i = 0, n = Sel.getNumArgs(); i != n; ++i) 986 SelPieces.push_back(Sel.getNameForSlot(i)); 987 } 988 989 api_notes::ObjCSelectorRef SelectorRef; 990 SelectorRef.NumArgs = Sel.getNumArgs(); 991 SelectorRef.Identifiers = SelPieces; 992 993 auto Info = Reader->lookupObjCMethod(*Context, SelectorRef, 994 Method->isInstanceMethod()); 995 ProcessVersionedAPINotes(*this, Method, Info); 996 } 997 } 998 } 999 1000 // Objective-C properties. 1001 if (auto Property = dyn_cast<ObjCPropertyDecl>(D)) { 1002 for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 1003 if (auto Context = GetContext(Reader)) { 1004 bool isInstanceProperty = 1005 (Property->getPropertyAttributesAsWritten() & 1006 ObjCPropertyAttribute::kind_class) == 0; 1007 auto Info = Reader->lookupObjCProperty(*Context, Property->getName(), 1008 isInstanceProperty); 1009 ProcessVersionedAPINotes(*this, Property, Info); 1010 } 1011 } 1012 1013 return; 1014 } 1015 } 1016 1017 if (auto CXXRecord = dyn_cast<CXXRecordDecl>(D->getDeclContext())) { 1018 auto GetRecordContext = [&](api_notes::APINotesReader *Reader) 1019 -> std::optional<api_notes::ContextID> { 1020 auto ParentContext = GetNamespaceContext(CXXRecord->getDeclContext()); 1021 if (auto Found = Reader->lookupTagID(CXXRecord->getName(), ParentContext)) 1022 return *Found; 1023 1024 return std::nullopt; 1025 }; 1026 1027 if (auto CXXMethod = dyn_cast<CXXMethodDecl>(D)) { 1028 for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 1029 if (auto Context = GetRecordContext(Reader)) { 1030 auto Info = Reader->lookupCXXMethod(*Context, CXXMethod->getName()); 1031 ProcessVersionedAPINotes(*this, CXXMethod, Info); 1032 } 1033 } 1034 } 1035 } 1036 } 1037