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