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 /*Environment=*/nullptr); 274 }, 275 [](const Decl *D) { 276 return llvm::find_if(D->attrs(), [](const Attr *next) -> bool { 277 if (const auto *AA = dyn_cast<AvailabilityAttr>(next)) 278 if (const auto *II = AA->getPlatform()) 279 return II->isStr("swift"); 280 return false; 281 }); 282 }); 283 } 284 285 // swift_private 286 if (auto SwiftPrivate = Info.isSwiftPrivate()) { 287 handleAPINotedAttribute<SwiftPrivateAttr>( 288 S, D, *SwiftPrivate, Metadata, [&] { 289 return new (S.Context) 290 SwiftPrivateAttr(S.Context, getPlaceholderAttrInfo()); 291 }); 292 } 293 294 // swift_name 295 if (!Info.SwiftName.empty()) { 296 handleAPINotedAttribute<SwiftNameAttr>( 297 S, D, true, Metadata, [&]() -> SwiftNameAttr * { 298 AttributeFactory AF{}; 299 AttributePool AP{AF}; 300 auto &C = S.getASTContext(); 301 ParsedAttr *SNA = 302 AP.create(&C.Idents.get("swift_name"), SourceRange(), nullptr, 303 SourceLocation(), nullptr, nullptr, nullptr, 304 ParsedAttr::Form::GNU()); 305 306 if (!S.DiagnoseSwiftName(D, Info.SwiftName, D->getLocation(), *SNA, 307 /*IsAsync=*/false)) 308 return nullptr; 309 310 return new (S.Context) 311 SwiftNameAttr(S.Context, getPlaceholderAttrInfo(), 312 ASTAllocateString(S.Context, Info.SwiftName)); 313 }); 314 } 315 } 316 317 static void ProcessAPINotes(Sema &S, Decl *D, 318 const api_notes::CommonTypeInfo &Info, 319 VersionedInfoMetadata Metadata) { 320 // swift_bridge 321 if (auto SwiftBridge = Info.getSwiftBridge()) { 322 handleAPINotedAttribute<SwiftBridgeAttr>( 323 S, D, !SwiftBridge->empty(), Metadata, [&] { 324 return new (S.Context) 325 SwiftBridgeAttr(S.Context, getPlaceholderAttrInfo(), 326 ASTAllocateString(S.Context, *SwiftBridge)); 327 }); 328 } 329 330 // ns_error_domain 331 if (auto NSErrorDomain = Info.getNSErrorDomain()) { 332 handleAPINotedAttribute<NSErrorDomainAttr>( 333 S, D, !NSErrorDomain->empty(), Metadata, [&] { 334 return new (S.Context) 335 NSErrorDomainAttr(S.Context, getPlaceholderAttrInfo(), 336 &S.Context.Idents.get(*NSErrorDomain)); 337 }); 338 } 339 340 ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(Info), 341 Metadata); 342 } 343 344 /// Check that the replacement type provided by API notes is reasonable. 345 /// 346 /// This is a very weak form of ABI check. 347 static bool checkAPINotesReplacementType(Sema &S, SourceLocation Loc, 348 QualType OrigType, 349 QualType ReplacementType) { 350 if (S.Context.getTypeSize(OrigType) != 351 S.Context.getTypeSize(ReplacementType)) { 352 S.Diag(Loc, diag::err_incompatible_replacement_type) 353 << ReplacementType << OrigType; 354 return true; 355 } 356 357 return false; 358 } 359 360 /// Process API notes for a variable or property. 361 static void ProcessAPINotes(Sema &S, Decl *D, 362 const api_notes::VariableInfo &Info, 363 VersionedInfoMetadata Metadata) { 364 // Type override. 365 if (Metadata.IsActive && !Info.getType().empty() && 366 S.ParseTypeFromStringCallback) { 367 auto ParsedType = S.ParseTypeFromStringCallback( 368 Info.getType(), "<API Notes>", D->getLocation()); 369 if (ParsedType.isUsable()) { 370 QualType Type = Sema::GetTypeFromParser(ParsedType.get()); 371 auto TypeInfo = 372 S.Context.getTrivialTypeSourceInfo(Type, D->getLocation()); 373 374 if (auto Var = dyn_cast<VarDecl>(D)) { 375 // Make adjustments to parameter types. 376 if (isa<ParmVarDecl>(Var)) { 377 Type = S.ObjC().AdjustParameterTypeForObjCAutoRefCount( 378 Type, D->getLocation(), TypeInfo); 379 Type = S.Context.getAdjustedParameterType(Type); 380 } 381 382 if (!checkAPINotesReplacementType(S, Var->getLocation(), Var->getType(), 383 Type)) { 384 Var->setType(Type); 385 Var->setTypeSourceInfo(TypeInfo); 386 } 387 } else if (auto Property = dyn_cast<ObjCPropertyDecl>(D)) { 388 if (!checkAPINotesReplacementType(S, Property->getLocation(), 389 Property->getType(), Type)) 390 Property->setType(Type, TypeInfo); 391 392 } else 393 llvm_unreachable("API notes allowed a type on an unknown declaration"); 394 } 395 } 396 397 // Nullability. 398 if (auto Nullability = Info.getNullability()) 399 applyNullability(S, D, *Nullability, Metadata); 400 401 // Handle common entity information. 402 ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(Info), 403 Metadata); 404 } 405 406 /// Process API notes for a parameter. 407 static void ProcessAPINotes(Sema &S, ParmVarDecl *D, 408 const api_notes::ParamInfo &Info, 409 VersionedInfoMetadata Metadata) { 410 // noescape 411 if (auto NoEscape = Info.isNoEscape()) 412 handleAPINotedAttribute<NoEscapeAttr>(S, D, *NoEscape, Metadata, [&] { 413 return new (S.Context) NoEscapeAttr(S.Context, getPlaceholderAttrInfo()); 414 }); 415 416 // Retain count convention 417 handleAPINotedRetainCountConvention(S, D, Metadata, 418 Info.getRetainCountConvention()); 419 420 // Handle common entity information. 421 ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(Info), 422 Metadata); 423 } 424 425 /// Process API notes for a global variable. 426 static void ProcessAPINotes(Sema &S, VarDecl *D, 427 const api_notes::GlobalVariableInfo &Info, 428 VersionedInfoMetadata metadata) { 429 // Handle common entity information. 430 ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(Info), 431 metadata); 432 } 433 434 /// Process API notes for an Objective-C property. 435 static void ProcessAPINotes(Sema &S, ObjCPropertyDecl *D, 436 const api_notes::ObjCPropertyInfo &Info, 437 VersionedInfoMetadata Metadata) { 438 // Handle common entity information. 439 ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(Info), 440 Metadata); 441 442 if (auto AsAccessors = Info.getSwiftImportAsAccessors()) { 443 handleAPINotedAttribute<SwiftImportPropertyAsAccessorsAttr>( 444 S, D, *AsAccessors, Metadata, [&] { 445 return new (S.Context) SwiftImportPropertyAsAccessorsAttr( 446 S.Context, getPlaceholderAttrInfo()); 447 }); 448 } 449 } 450 451 namespace { 452 typedef llvm::PointerUnion<FunctionDecl *, ObjCMethodDecl *> FunctionOrMethod; 453 } 454 455 /// Process API notes for a function or method. 456 static void ProcessAPINotes(Sema &S, FunctionOrMethod AnyFunc, 457 const api_notes::FunctionInfo &Info, 458 VersionedInfoMetadata Metadata) { 459 // Find the declaration itself. 460 FunctionDecl *FD = AnyFunc.dyn_cast<FunctionDecl *>(); 461 Decl *D = FD; 462 ObjCMethodDecl *MD = nullptr; 463 if (!D) { 464 MD = AnyFunc.get<ObjCMethodDecl *>(); 465 D = MD; 466 } 467 468 assert((FD || MD) && "Expecting Function or ObjCMethod"); 469 470 // Nullability of return type. 471 if (Info.NullabilityAudited) 472 applyNullability(S, D, Info.getReturnTypeInfo(), Metadata); 473 474 // Parameters. 475 unsigned NumParams = FD ? FD->getNumParams() : MD->param_size(); 476 477 bool AnyTypeChanged = false; 478 for (unsigned I = 0; I != NumParams; ++I) { 479 ParmVarDecl *Param = FD ? FD->getParamDecl(I) : MD->param_begin()[I]; 480 QualType ParamTypeBefore = Param->getType(); 481 482 if (I < Info.Params.size()) 483 ProcessAPINotes(S, Param, Info.Params[I], Metadata); 484 485 // Nullability. 486 if (Info.NullabilityAudited) 487 applyNullability(S, Param, Info.getParamTypeInfo(I), Metadata); 488 489 if (ParamTypeBefore.getAsOpaquePtr() != Param->getType().getAsOpaquePtr()) 490 AnyTypeChanged = true; 491 } 492 493 // Result type override. 494 QualType OverriddenResultType; 495 if (Metadata.IsActive && !Info.ResultType.empty() && 496 S.ParseTypeFromStringCallback) { 497 auto ParsedType = S.ParseTypeFromStringCallback( 498 Info.ResultType, "<API Notes>", D->getLocation()); 499 if (ParsedType.isUsable()) { 500 QualType ResultType = Sema::GetTypeFromParser(ParsedType.get()); 501 502 if (MD) { 503 if (!checkAPINotesReplacementType(S, D->getLocation(), 504 MD->getReturnType(), ResultType)) { 505 auto ResultTypeInfo = 506 S.Context.getTrivialTypeSourceInfo(ResultType, D->getLocation()); 507 MD->setReturnType(ResultType); 508 MD->setReturnTypeSourceInfo(ResultTypeInfo); 509 } 510 } else if (!checkAPINotesReplacementType( 511 S, FD->getLocation(), FD->getReturnType(), ResultType)) { 512 OverriddenResultType = ResultType; 513 AnyTypeChanged = true; 514 } 515 } 516 } 517 518 // If the result type or any of the parameter types changed for a function 519 // declaration, we have to rebuild the type. 520 if (FD && AnyTypeChanged) { 521 if (const auto *fnProtoType = FD->getType()->getAs<FunctionProtoType>()) { 522 if (OverriddenResultType.isNull()) 523 OverriddenResultType = fnProtoType->getReturnType(); 524 525 SmallVector<QualType, 4> ParamTypes; 526 for (auto Param : FD->parameters()) 527 ParamTypes.push_back(Param->getType()); 528 529 FD->setType(S.Context.getFunctionType(OverriddenResultType, ParamTypes, 530 fnProtoType->getExtProtoInfo())); 531 } else if (!OverriddenResultType.isNull()) { 532 const auto *FnNoProtoType = FD->getType()->castAs<FunctionNoProtoType>(); 533 FD->setType(S.Context.getFunctionNoProtoType( 534 OverriddenResultType, FnNoProtoType->getExtInfo())); 535 } 536 } 537 538 // Retain count convention 539 handleAPINotedRetainCountConvention(S, D, Metadata, 540 Info.getRetainCountConvention()); 541 542 // Handle common entity information. 543 ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(Info), 544 Metadata); 545 } 546 547 /// Process API notes for a global function. 548 static void ProcessAPINotes(Sema &S, FunctionDecl *D, 549 const api_notes::GlobalFunctionInfo &Info, 550 VersionedInfoMetadata Metadata) { 551 // Handle common function information. 552 ProcessAPINotes(S, FunctionOrMethod(D), 553 static_cast<const api_notes::FunctionInfo &>(Info), Metadata); 554 } 555 556 /// Process API notes for an enumerator. 557 static void ProcessAPINotes(Sema &S, EnumConstantDecl *D, 558 const api_notes::EnumConstantInfo &Info, 559 VersionedInfoMetadata Metadata) { 560 // Handle common information. 561 ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(Info), 562 Metadata); 563 } 564 565 /// Process API notes for an Objective-C method. 566 static void ProcessAPINotes(Sema &S, ObjCMethodDecl *D, 567 const api_notes::ObjCMethodInfo &Info, 568 VersionedInfoMetadata Metadata) { 569 // Designated initializers. 570 if (Info.DesignatedInit) { 571 handleAPINotedAttribute<ObjCDesignatedInitializerAttr>( 572 S, D, true, Metadata, [&] { 573 if (ObjCInterfaceDecl *IFace = D->getClassInterface()) 574 IFace->setHasDesignatedInitializers(); 575 576 return new (S.Context) ObjCDesignatedInitializerAttr( 577 S.Context, getPlaceholderAttrInfo()); 578 }); 579 } 580 581 // Handle common function information. 582 ProcessAPINotes(S, FunctionOrMethod(D), 583 static_cast<const api_notes::FunctionInfo &>(Info), Metadata); 584 } 585 586 /// Process API notes for a tag. 587 static void ProcessAPINotes(Sema &S, TagDecl *D, const api_notes::TagInfo &Info, 588 VersionedInfoMetadata Metadata) { 589 if (auto ImportAs = Info.SwiftImportAs) 590 D->addAttr(SwiftAttrAttr::Create(S.Context, "import_" + ImportAs.value())); 591 592 if (auto RetainOp = Info.SwiftRetainOp) 593 D->addAttr(SwiftAttrAttr::Create(S.Context, "retain:" + RetainOp.value())); 594 595 if (auto ReleaseOp = Info.SwiftReleaseOp) 596 D->addAttr( 597 SwiftAttrAttr::Create(S.Context, "release:" + ReleaseOp.value())); 598 599 if (auto Copyable = Info.isSwiftCopyable()) { 600 if (!*Copyable) 601 D->addAttr(SwiftAttrAttr::Create(S.Context, "~Copyable")); 602 } 603 604 if (auto Extensibility = Info.EnumExtensibility) { 605 using api_notes::EnumExtensibilityKind; 606 bool ShouldAddAttribute = (*Extensibility != EnumExtensibilityKind::None); 607 handleAPINotedAttribute<EnumExtensibilityAttr>( 608 S, D, ShouldAddAttribute, Metadata, [&] { 609 EnumExtensibilityAttr::Kind kind; 610 switch (*Extensibility) { 611 case EnumExtensibilityKind::None: 612 llvm_unreachable("remove only"); 613 case EnumExtensibilityKind::Open: 614 kind = EnumExtensibilityAttr::Open; 615 break; 616 case EnumExtensibilityKind::Closed: 617 kind = EnumExtensibilityAttr::Closed; 618 break; 619 } 620 return new (S.Context) 621 EnumExtensibilityAttr(S.Context, getPlaceholderAttrInfo(), kind); 622 }); 623 } 624 625 if (auto FlagEnum = Info.isFlagEnum()) { 626 handleAPINotedAttribute<FlagEnumAttr>(S, D, *FlagEnum, Metadata, [&] { 627 return new (S.Context) FlagEnumAttr(S.Context, getPlaceholderAttrInfo()); 628 }); 629 } 630 631 // Handle common type information. 632 ProcessAPINotes(S, D, static_cast<const api_notes::CommonTypeInfo &>(Info), 633 Metadata); 634 } 635 636 /// Process API notes for a typedef. 637 static void ProcessAPINotes(Sema &S, TypedefNameDecl *D, 638 const api_notes::TypedefInfo &Info, 639 VersionedInfoMetadata Metadata) { 640 // swift_wrapper 641 using SwiftWrapperKind = api_notes::SwiftNewTypeKind; 642 643 if (auto SwiftWrapper = Info.SwiftWrapper) { 644 handleAPINotedAttribute<SwiftNewTypeAttr>( 645 S, D, *SwiftWrapper != SwiftWrapperKind::None, Metadata, [&] { 646 SwiftNewTypeAttr::NewtypeKind Kind; 647 switch (*SwiftWrapper) { 648 case SwiftWrapperKind::None: 649 llvm_unreachable("Shouldn't build an attribute"); 650 651 case SwiftWrapperKind::Struct: 652 Kind = SwiftNewTypeAttr::NK_Struct; 653 break; 654 655 case SwiftWrapperKind::Enum: 656 Kind = SwiftNewTypeAttr::NK_Enum; 657 break; 658 } 659 AttributeCommonInfo SyntaxInfo{ 660 SourceRange(), 661 AttributeCommonInfo::AT_SwiftNewType, 662 {AttributeCommonInfo::AS_GNU, SwiftNewTypeAttr::GNU_swift_wrapper, 663 /*IsAlignas*/ false, /*IsRegularKeywordAttribute*/ false}}; 664 return new (S.Context) SwiftNewTypeAttr(S.Context, SyntaxInfo, Kind); 665 }); 666 } 667 668 // Handle common type information. 669 ProcessAPINotes(S, D, static_cast<const api_notes::CommonTypeInfo &>(Info), 670 Metadata); 671 } 672 673 /// Process API notes for an Objective-C class or protocol. 674 static void ProcessAPINotes(Sema &S, ObjCContainerDecl *D, 675 const api_notes::ObjCContextInfo &Info, 676 VersionedInfoMetadata Metadata) { 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. 683 static void ProcessAPINotes(Sema &S, ObjCInterfaceDecl *D, 684 const api_notes::ObjCContextInfo &Info, 685 VersionedInfoMetadata Metadata) { 686 if (auto AsNonGeneric = Info.getSwiftImportAsNonGeneric()) { 687 handleAPINotedAttribute<SwiftImportAsNonGenericAttr>( 688 S, D, *AsNonGeneric, Metadata, [&] { 689 return new (S.Context) 690 SwiftImportAsNonGenericAttr(S.Context, getPlaceholderAttrInfo()); 691 }); 692 } 693 694 if (auto ObjcMembers = Info.getSwiftObjCMembers()) { 695 handleAPINotedAttribute<SwiftObjCMembersAttr>( 696 S, D, *ObjcMembers, Metadata, [&] { 697 return new (S.Context) 698 SwiftObjCMembersAttr(S.Context, getPlaceholderAttrInfo()); 699 }); 700 } 701 702 // Handle information common to Objective-C classes and protocols. 703 ProcessAPINotes(S, static_cast<clang::ObjCContainerDecl *>(D), Info, 704 Metadata); 705 } 706 707 /// If we're applying API notes with an active, non-default version, and the 708 /// versioned API notes have a SwiftName but the declaration normally wouldn't 709 /// have one, add a removal attribute to make it clear that the new SwiftName 710 /// attribute only applies to the active version of \p D, not to all versions. 711 /// 712 /// This must be run \em before processing API notes for \p D, because otherwise 713 /// any existing SwiftName attribute will have been packaged up in a 714 /// SwiftVersionedAdditionAttr. 715 template <typename SpecificInfo> 716 static void maybeAttachUnversionedSwiftName( 717 Sema &S, Decl *D, 718 const api_notes::APINotesReader::VersionedInfo<SpecificInfo> Info) { 719 if (D->hasAttr<SwiftNameAttr>()) 720 return; 721 if (!Info.getSelected()) 722 return; 723 724 // Is the active slice versioned, and does it set a Swift name? 725 VersionTuple SelectedVersion; 726 SpecificInfo SelectedInfoSlice; 727 std::tie(SelectedVersion, SelectedInfoSlice) = Info[*Info.getSelected()]; 728 if (SelectedVersion.empty()) 729 return; 730 if (SelectedInfoSlice.SwiftName.empty()) 731 return; 732 733 // Does the unversioned slice /not/ set a Swift name? 734 for (const auto &VersionAndInfoSlice : Info) { 735 if (!VersionAndInfoSlice.first.empty()) 736 continue; 737 if (!VersionAndInfoSlice.second.SwiftName.empty()) 738 return; 739 } 740 741 // Then explicitly call that out with a removal attribute. 742 VersionedInfoMetadata DummyFutureMetadata( 743 SelectedVersion, IsActive_t::Inactive, IsSubstitution_t::Replacement); 744 handleAPINotedAttribute<SwiftNameAttr>( 745 S, D, /*add*/ false, DummyFutureMetadata, []() -> SwiftNameAttr * { 746 llvm_unreachable("should not try to add an attribute here"); 747 }); 748 } 749 750 /// Processes all versions of versioned API notes. 751 /// 752 /// Just dispatches to the various ProcessAPINotes functions in this file. 753 template <typename SpecificDecl, typename SpecificInfo> 754 static void ProcessVersionedAPINotes( 755 Sema &S, SpecificDecl *D, 756 const api_notes::APINotesReader::VersionedInfo<SpecificInfo> Info) { 757 758 maybeAttachUnversionedSwiftName(S, D, Info); 759 760 unsigned Selected = Info.getSelected().value_or(Info.size()); 761 762 VersionTuple Version; 763 SpecificInfo InfoSlice; 764 for (unsigned i = 0, e = Info.size(); i != e; ++i) { 765 std::tie(Version, InfoSlice) = Info[i]; 766 auto Active = (i == Selected) ? IsActive_t::Active : IsActive_t::Inactive; 767 auto Replacement = IsSubstitution_t::Original; 768 if (Active == IsActive_t::Inactive && Version.empty()) { 769 Replacement = IsSubstitution_t::Replacement; 770 Version = Info[Selected].first; 771 } 772 ProcessAPINotes(S, D, InfoSlice, 773 VersionedInfoMetadata(Version, Active, Replacement)); 774 } 775 } 776 777 /// Process API notes that are associated with this declaration, mapping them 778 /// to attributes as appropriate. 779 void Sema::ProcessAPINotes(Decl *D) { 780 if (!D) 781 return; 782 783 // Globals. 784 if (D->getDeclContext()->isFileContext() || 785 D->getDeclContext()->isNamespace() || 786 D->getDeclContext()->isExternCContext() || 787 D->getDeclContext()->isExternCXXContext()) { 788 std::optional<api_notes::Context> APINotesContext; 789 if (auto NamespaceContext = dyn_cast<NamespaceDecl>(D->getDeclContext())) { 790 for (auto Reader : 791 APINotes.findAPINotes(NamespaceContext->getLocation())) { 792 // Retrieve the context ID for the parent namespace of the decl. 793 std::stack<NamespaceDecl *> NamespaceStack; 794 { 795 for (auto CurrentNamespace = NamespaceContext; CurrentNamespace; 796 CurrentNamespace = 797 dyn_cast<NamespaceDecl>(CurrentNamespace->getParent())) { 798 if (!CurrentNamespace->isInlineNamespace()) 799 NamespaceStack.push(CurrentNamespace); 800 } 801 } 802 std::optional<api_notes::ContextID> NamespaceID; 803 while (!NamespaceStack.empty()) { 804 auto CurrentNamespace = NamespaceStack.top(); 805 NamespaceStack.pop(); 806 NamespaceID = Reader->lookupNamespaceID(CurrentNamespace->getName(), 807 NamespaceID); 808 if (!NamespaceID) 809 break; 810 } 811 if (NamespaceID) 812 APINotesContext = api_notes::Context( 813 *NamespaceID, api_notes::ContextKind::Namespace); 814 } 815 } 816 817 // Global variables. 818 if (auto VD = dyn_cast<VarDecl>(D)) { 819 for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 820 auto Info = 821 Reader->lookupGlobalVariable(VD->getName(), APINotesContext); 822 ProcessVersionedAPINotes(*this, VD, Info); 823 } 824 825 return; 826 } 827 828 // Global functions. 829 if (auto FD = dyn_cast<FunctionDecl>(D)) { 830 if (FD->getDeclName().isIdentifier()) { 831 for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 832 auto Info = 833 Reader->lookupGlobalFunction(FD->getName(), APINotesContext); 834 ProcessVersionedAPINotes(*this, FD, Info); 835 } 836 } 837 838 return; 839 } 840 841 // Objective-C classes. 842 if (auto Class = dyn_cast<ObjCInterfaceDecl>(D)) { 843 for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 844 auto Info = Reader->lookupObjCClassInfo(Class->getName()); 845 ProcessVersionedAPINotes(*this, Class, Info); 846 } 847 848 return; 849 } 850 851 // Objective-C protocols. 852 if (auto Protocol = dyn_cast<ObjCProtocolDecl>(D)) { 853 for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 854 auto Info = Reader->lookupObjCProtocolInfo(Protocol->getName()); 855 ProcessVersionedAPINotes(*this, Protocol, Info); 856 } 857 858 return; 859 } 860 861 // Tags 862 if (auto Tag = dyn_cast<TagDecl>(D)) { 863 std::string LookupName = Tag->getName().str(); 864 865 // Use the source location to discern if this Tag is an OPTIONS macro. 866 // For now we would like to limit this trick of looking up the APINote tag 867 // using the EnumDecl's QualType in the case where the enum is anonymous. 868 // This is only being used to support APINotes lookup for C++ 869 // NS/CF_OPTIONS when C++-Interop is enabled. 870 std::string MacroName = 871 LookupName.empty() && Tag->getOuterLocStart().isMacroID() 872 ? clang::Lexer::getImmediateMacroName( 873 Tag->getOuterLocStart(), 874 Tag->getASTContext().getSourceManager(), LangOpts) 875 .str() 876 : ""; 877 878 if (LookupName.empty() && isa<clang::EnumDecl>(Tag) && 879 (MacroName == "CF_OPTIONS" || MacroName == "NS_OPTIONS" || 880 MacroName == "OBJC_OPTIONS" || MacroName == "SWIFT_OPTIONS")) { 881 882 clang::QualType T = llvm::cast<clang::EnumDecl>(Tag)->getIntegerType(); 883 LookupName = clang::QualType::getAsString( 884 T.split(), getASTContext().getPrintingPolicy()); 885 } 886 887 for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 888 auto Info = Reader->lookupTag(LookupName, APINotesContext); 889 ProcessVersionedAPINotes(*this, Tag, Info); 890 } 891 892 return; 893 } 894 895 // Typedefs 896 if (auto Typedef = dyn_cast<TypedefNameDecl>(D)) { 897 for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 898 auto Info = Reader->lookupTypedef(Typedef->getName(), APINotesContext); 899 ProcessVersionedAPINotes(*this, Typedef, Info); 900 } 901 902 return; 903 } 904 } 905 906 // Enumerators. 907 if (D->getDeclContext()->getRedeclContext()->isFileContext() || 908 D->getDeclContext()->getRedeclContext()->isExternCContext()) { 909 if (auto EnumConstant = dyn_cast<EnumConstantDecl>(D)) { 910 for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 911 auto Info = Reader->lookupEnumConstant(EnumConstant->getName()); 912 ProcessVersionedAPINotes(*this, EnumConstant, Info); 913 } 914 915 return; 916 } 917 } 918 919 if (auto ObjCContainer = dyn_cast<ObjCContainerDecl>(D->getDeclContext())) { 920 // Location function that looks up an Objective-C context. 921 auto GetContext = [&](api_notes::APINotesReader *Reader) 922 -> std::optional<api_notes::ContextID> { 923 if (auto Protocol = dyn_cast<ObjCProtocolDecl>(ObjCContainer)) { 924 if (auto Found = Reader->lookupObjCProtocolID(Protocol->getName())) 925 return *Found; 926 927 return std::nullopt; 928 } 929 930 if (auto Impl = dyn_cast<ObjCCategoryImplDecl>(ObjCContainer)) { 931 if (auto Cat = Impl->getCategoryDecl()) 932 ObjCContainer = Cat->getClassInterface(); 933 else 934 return std::nullopt; 935 } 936 937 if (auto Category = dyn_cast<ObjCCategoryDecl>(ObjCContainer)) { 938 if (Category->getClassInterface()) 939 ObjCContainer = Category->getClassInterface(); 940 else 941 return std::nullopt; 942 } 943 944 if (auto Impl = dyn_cast<ObjCImplDecl>(ObjCContainer)) { 945 if (Impl->getClassInterface()) 946 ObjCContainer = Impl->getClassInterface(); 947 else 948 return std::nullopt; 949 } 950 951 if (auto Class = dyn_cast<ObjCInterfaceDecl>(ObjCContainer)) { 952 if (auto Found = Reader->lookupObjCClassID(Class->getName())) 953 return *Found; 954 955 return std::nullopt; 956 } 957 958 return std::nullopt; 959 }; 960 961 // Objective-C methods. 962 if (auto Method = dyn_cast<ObjCMethodDecl>(D)) { 963 for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 964 if (auto Context = GetContext(Reader)) { 965 // Map the selector. 966 Selector Sel = Method->getSelector(); 967 SmallVector<StringRef, 2> SelPieces; 968 if (Sel.isUnarySelector()) { 969 SelPieces.push_back(Sel.getNameForSlot(0)); 970 } else { 971 for (unsigned i = 0, n = Sel.getNumArgs(); i != n; ++i) 972 SelPieces.push_back(Sel.getNameForSlot(i)); 973 } 974 975 api_notes::ObjCSelectorRef SelectorRef; 976 SelectorRef.NumArgs = Sel.getNumArgs(); 977 SelectorRef.Identifiers = SelPieces; 978 979 auto Info = Reader->lookupObjCMethod(*Context, SelectorRef, 980 Method->isInstanceMethod()); 981 ProcessVersionedAPINotes(*this, Method, Info); 982 } 983 } 984 } 985 986 // Objective-C properties. 987 if (auto Property = dyn_cast<ObjCPropertyDecl>(D)) { 988 for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 989 if (auto Context = GetContext(Reader)) { 990 bool isInstanceProperty = 991 (Property->getPropertyAttributesAsWritten() & 992 ObjCPropertyAttribute::kind_class) == 0; 993 auto Info = Reader->lookupObjCProperty(*Context, Property->getName(), 994 isInstanceProperty); 995 ProcessVersionedAPINotes(*this, Property, Info); 996 } 997 } 998 999 return; 1000 } 1001 } 1002 } 1003