1 //===--- SemaAPINotes.cpp - API Notes Handling ----------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file implements the mapping from API notes to declaration attributes. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "CheckExprLifetime.h" 14 #include "TypeLocBuilder.h" 15 #include "clang/APINotes/APINotesReader.h" 16 #include "clang/AST/Decl.h" 17 #include "clang/AST/DeclCXX.h" 18 #include "clang/AST/DeclObjC.h" 19 #include "clang/AST/TypeLoc.h" 20 #include "clang/Basic/SourceLocation.h" 21 #include "clang/Lex/Lexer.h" 22 #include "clang/Sema/SemaObjC.h" 23 #include "clang/Sema/SemaSwift.h" 24 #include <stack> 25 26 using namespace clang; 27 28 namespace { 29 enum class IsActive_t : bool { Inactive, Active }; 30 enum class IsSubstitution_t : bool { Original, Replacement }; 31 32 struct VersionedInfoMetadata { 33 /// An empty version refers to unversioned metadata. 34 VersionTuple Version; 35 unsigned IsActive : 1; 36 unsigned IsReplacement : 1; 37 38 VersionedInfoMetadata(VersionTuple Version, IsActive_t Active, 39 IsSubstitution_t Replacement) 40 : Version(Version), IsActive(Active == IsActive_t::Active), 41 IsReplacement(Replacement == IsSubstitution_t::Replacement) {} 42 }; 43 } // end anonymous namespace 44 45 /// Determine whether this is a multi-level pointer type. 46 static bool isIndirectPointerType(QualType Type) { 47 QualType Pointee = Type->getPointeeType(); 48 if (Pointee.isNull()) 49 return false; 50 51 return Pointee->isAnyPointerType() || Pointee->isObjCObjectPointerType() || 52 Pointee->isMemberPointerType(); 53 } 54 55 static void applyAPINotesType(Sema &S, Decl *decl, StringRef typeString, 56 VersionedInfoMetadata metadata) { 57 if (typeString.empty()) 58 59 return; 60 61 // Version-independent APINotes add "type" annotations 62 // with a versioned attribute for the client to select and apply. 63 if (S.captureSwiftVersionIndependentAPINotes()) { 64 auto *typeAttr = SwiftTypeAttr::CreateImplicit(S.Context, typeString); 65 auto *versioned = SwiftVersionedAdditionAttr::CreateImplicit( 66 S.Context, metadata.Version, typeAttr, metadata.IsReplacement); 67 decl->addAttr(versioned); 68 } else { 69 if (!metadata.IsActive) 70 return; 71 S.ApplyAPINotesType(decl, typeString); 72 } 73 } 74 75 /// Apply nullability to the given declaration. 76 static void applyNullability(Sema &S, Decl *decl, NullabilityKind nullability, 77 VersionedInfoMetadata metadata) { 78 // Version-independent APINotes add "nullability" annotations 79 // with a versioned attribute for the client to select and apply. 80 if (S.captureSwiftVersionIndependentAPINotes()) { 81 SwiftNullabilityAttr::Kind attrNullabilityKind; 82 switch (nullability) { 83 case NullabilityKind::NonNull: 84 attrNullabilityKind = SwiftNullabilityAttr::Kind::NonNull; 85 break; 86 case NullabilityKind::Nullable: 87 attrNullabilityKind = SwiftNullabilityAttr::Kind::Nullable; 88 break; 89 case NullabilityKind::Unspecified: 90 attrNullabilityKind = SwiftNullabilityAttr::Kind::Unspecified; 91 break; 92 case NullabilityKind::NullableResult: 93 attrNullabilityKind = SwiftNullabilityAttr::Kind::NullableResult; 94 break; 95 } 96 auto *nullabilityAttr = 97 SwiftNullabilityAttr::CreateImplicit(S.Context, attrNullabilityKind); 98 auto *versioned = SwiftVersionedAdditionAttr::CreateImplicit( 99 S.Context, metadata.Version, nullabilityAttr, metadata.IsReplacement); 100 decl->addAttr(versioned); 101 return; 102 } else { 103 if (!metadata.IsActive) 104 return; 105 106 S.ApplyNullability(decl, nullability); 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 = AP.create( 302 &C.Idents.get("swift_name"), SourceRange(), AttributeScopeInfo(), 303 nullptr, nullptr, nullptr, ParsedAttr::Form::GNU()); 304 305 if (!S.Swift().DiagnoseName(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 void Sema::ApplyAPINotesType(Decl *D, StringRef TypeString) { 360 if (!TypeString.empty() && ParseTypeFromStringCallback) { 361 auto ParsedType = ParseTypeFromStringCallback(TypeString, "<API Notes>", 362 D->getLocation()); 363 if (ParsedType.isUsable()) { 364 QualType Type = Sema::GetTypeFromParser(ParsedType.get()); 365 auto TypeInfo = Context.getTrivialTypeSourceInfo(Type, D->getLocation()); 366 if (auto Var = dyn_cast<VarDecl>(D)) { 367 // Make adjustments to parameter types. 368 if (isa<ParmVarDecl>(Var)) { 369 Type = ObjC().AdjustParameterTypeForObjCAutoRefCount( 370 Type, D->getLocation(), TypeInfo); 371 Type = Context.getAdjustedParameterType(Type); 372 } 373 374 if (!checkAPINotesReplacementType(*this, Var->getLocation(), 375 Var->getType(), Type)) { 376 Var->setType(Type); 377 Var->setTypeSourceInfo(TypeInfo); 378 } 379 } else if (auto property = dyn_cast<ObjCPropertyDecl>(D)) { 380 if (!checkAPINotesReplacementType(*this, property->getLocation(), 381 property->getType(), Type)) { 382 property->setType(Type, TypeInfo); 383 } 384 } else { 385 llvm_unreachable("API notes allowed a type on an unknown declaration"); 386 } 387 } 388 } 389 } 390 391 void Sema::ApplyNullability(Decl *D, NullabilityKind Nullability) { 392 auto GetModified = 393 [&](class Decl *D, QualType QT, 394 NullabilityKind Nullability) -> std::optional<QualType> { 395 QualType Original = QT; 396 CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(), 397 isa<ParmVarDecl>(D), 398 /*OverrideExisting=*/true); 399 return (QT.getTypePtr() != Original.getTypePtr()) ? std::optional(QT) 400 : std::nullopt; 401 }; 402 403 if (auto Function = dyn_cast<FunctionDecl>(D)) { 404 if (auto Modified = 405 GetModified(D, Function->getReturnType(), Nullability)) { 406 const FunctionType *FnType = Function->getType()->castAs<FunctionType>(); 407 if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(FnType)) 408 Function->setType(Context.getFunctionType( 409 *Modified, proto->getParamTypes(), proto->getExtProtoInfo())); 410 else 411 Function->setType( 412 Context.getFunctionNoProtoType(*Modified, FnType->getExtInfo())); 413 } 414 } else if (auto Method = dyn_cast<ObjCMethodDecl>(D)) { 415 if (auto Modified = GetModified(D, Method->getReturnType(), Nullability)) { 416 Method->setReturnType(*Modified); 417 418 // Make it a context-sensitive keyword if we can. 419 if (!isIndirectPointerType(*Modified)) 420 Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( 421 Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); 422 } 423 } else if (auto Value = dyn_cast<ValueDecl>(D)) { 424 if (auto Modified = GetModified(D, Value->getType(), Nullability)) { 425 Value->setType(*Modified); 426 427 // Make it a context-sensitive keyword if we can. 428 if (auto Parm = dyn_cast<ParmVarDecl>(D)) { 429 if (Parm->isObjCMethodParameter() && !isIndirectPointerType(*Modified)) 430 Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( 431 Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); 432 } 433 } 434 } else if (auto Property = dyn_cast<ObjCPropertyDecl>(D)) { 435 if (auto Modified = GetModified(D, Property->getType(), Nullability)) { 436 Property->setType(*Modified, Property->getTypeSourceInfo()); 437 438 // Make it a property attribute if we can. 439 if (!isIndirectPointerType(*Modified)) 440 Property->setPropertyAttributes( 441 ObjCPropertyAttribute::kind_null_resettable); 442 } 443 } 444 } 445 446 /// Process API notes for a variable or property. 447 static void ProcessAPINotes(Sema &S, Decl *D, 448 const api_notes::VariableInfo &Info, 449 VersionedInfoMetadata Metadata) { 450 // Type override. 451 applyAPINotesType(S, D, Info.getType(), Metadata); 452 453 // Nullability. 454 if (auto Nullability = Info.getNullability()) 455 applyNullability(S, D, *Nullability, Metadata); 456 457 // Handle common entity information. 458 ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(Info), 459 Metadata); 460 } 461 462 /// Process API notes for a parameter. 463 static void ProcessAPINotes(Sema &S, ParmVarDecl *D, 464 const api_notes::ParamInfo &Info, 465 VersionedInfoMetadata Metadata) { 466 // noescape 467 if (auto NoEscape = Info.isNoEscape()) 468 handleAPINotedAttribute<NoEscapeAttr>(S, D, *NoEscape, Metadata, [&] { 469 return new (S.Context) NoEscapeAttr(S.Context, getPlaceholderAttrInfo()); 470 }); 471 472 if (auto Lifetimebound = Info.isLifetimebound()) 473 handleAPINotedAttribute<LifetimeBoundAttr>( 474 S, D, *Lifetimebound, Metadata, [&] { 475 return new (S.Context) 476 LifetimeBoundAttr(S.Context, getPlaceholderAttrInfo()); 477 }); 478 479 // Retain count convention 480 handleAPINotedRetainCountConvention(S, D, Metadata, 481 Info.getRetainCountConvention()); 482 483 // Handle common entity information. 484 ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(Info), 485 Metadata); 486 } 487 488 /// Process API notes for a global variable. 489 static void ProcessAPINotes(Sema &S, VarDecl *D, 490 const api_notes::GlobalVariableInfo &Info, 491 VersionedInfoMetadata metadata) { 492 // Handle common entity information. 493 ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(Info), 494 metadata); 495 } 496 497 /// Process API notes for a C field. 498 static void ProcessAPINotes(Sema &S, FieldDecl *D, 499 const api_notes::FieldInfo &Info, 500 VersionedInfoMetadata metadata) { 501 // Handle common entity information. 502 ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(Info), 503 metadata); 504 } 505 506 /// Process API notes for an Objective-C property. 507 static void ProcessAPINotes(Sema &S, ObjCPropertyDecl *D, 508 const api_notes::ObjCPropertyInfo &Info, 509 VersionedInfoMetadata Metadata) { 510 // Handle common entity information. 511 ProcessAPINotes(S, D, static_cast<const api_notes::VariableInfo &>(Info), 512 Metadata); 513 514 if (auto AsAccessors = Info.getSwiftImportAsAccessors()) { 515 handleAPINotedAttribute<SwiftImportPropertyAsAccessorsAttr>( 516 S, D, *AsAccessors, Metadata, [&] { 517 return new (S.Context) SwiftImportPropertyAsAccessorsAttr( 518 S.Context, getPlaceholderAttrInfo()); 519 }); 520 } 521 } 522 523 namespace { 524 typedef llvm::PointerUnion<FunctionDecl *, ObjCMethodDecl *> FunctionOrMethod; 525 } 526 527 /// Process API notes for a function or method. 528 static void ProcessAPINotes(Sema &S, FunctionOrMethod AnyFunc, 529 const api_notes::FunctionInfo &Info, 530 VersionedInfoMetadata Metadata) { 531 // Find the declaration itself. 532 FunctionDecl *FD = dyn_cast<FunctionDecl *>(AnyFunc); 533 Decl *D = FD; 534 ObjCMethodDecl *MD = nullptr; 535 if (!D) { 536 MD = cast<ObjCMethodDecl *>(AnyFunc); 537 D = MD; 538 } 539 540 assert((FD || MD) && "Expecting Function or ObjCMethod"); 541 542 // Nullability of return type. 543 if (Info.NullabilityAudited) 544 applyNullability(S, D, Info.getReturnTypeInfo(), Metadata); 545 546 // Parameters. 547 unsigned NumParams = FD ? FD->getNumParams() : MD->param_size(); 548 549 bool AnyTypeChanged = false; 550 for (unsigned I = 0; I != NumParams; ++I) { 551 ParmVarDecl *Param = FD ? FD->getParamDecl(I) : MD->param_begin()[I]; 552 QualType ParamTypeBefore = Param->getType(); 553 554 if (I < Info.Params.size()) 555 ProcessAPINotes(S, Param, Info.Params[I], Metadata); 556 557 // Nullability. 558 if (Info.NullabilityAudited) 559 applyNullability(S, Param, Info.getParamTypeInfo(I), Metadata); 560 561 if (ParamTypeBefore.getAsOpaquePtr() != Param->getType().getAsOpaquePtr()) 562 AnyTypeChanged = true; 563 } 564 565 // returns_(un)retained 566 if (!Info.SwiftReturnOwnership.empty()) 567 D->addAttr(SwiftAttrAttr::Create(S.Context, 568 "returns_" + Info.SwiftReturnOwnership)); 569 570 // Result type override. 571 QualType OverriddenResultType; 572 if (Metadata.IsActive && !Info.ResultType.empty() && 573 S.ParseTypeFromStringCallback) { 574 auto ParsedType = S.ParseTypeFromStringCallback( 575 Info.ResultType, "<API Notes>", D->getLocation()); 576 if (ParsedType.isUsable()) { 577 QualType ResultType = Sema::GetTypeFromParser(ParsedType.get()); 578 579 if (MD) { 580 if (!checkAPINotesReplacementType(S, D->getLocation(), 581 MD->getReturnType(), ResultType)) { 582 auto ResultTypeInfo = 583 S.Context.getTrivialTypeSourceInfo(ResultType, D->getLocation()); 584 MD->setReturnType(ResultType); 585 MD->setReturnTypeSourceInfo(ResultTypeInfo); 586 } 587 } else if (!checkAPINotesReplacementType( 588 S, FD->getLocation(), FD->getReturnType(), ResultType)) { 589 OverriddenResultType = ResultType; 590 AnyTypeChanged = true; 591 } 592 } 593 } 594 595 // If the result type or any of the parameter types changed for a function 596 // declaration, we have to rebuild the type. 597 if (FD && AnyTypeChanged) { 598 if (const auto *fnProtoType = FD->getType()->getAs<FunctionProtoType>()) { 599 if (OverriddenResultType.isNull()) 600 OverriddenResultType = fnProtoType->getReturnType(); 601 602 SmallVector<QualType, 4> ParamTypes; 603 for (auto Param : FD->parameters()) 604 ParamTypes.push_back(Param->getType()); 605 606 FD->setType(S.Context.getFunctionType(OverriddenResultType, ParamTypes, 607 fnProtoType->getExtProtoInfo())); 608 } else if (!OverriddenResultType.isNull()) { 609 const auto *FnNoProtoType = FD->getType()->castAs<FunctionNoProtoType>(); 610 FD->setType(S.Context.getFunctionNoProtoType( 611 OverriddenResultType, FnNoProtoType->getExtInfo())); 612 } 613 } 614 615 // Retain count convention 616 handleAPINotedRetainCountConvention(S, D, Metadata, 617 Info.getRetainCountConvention()); 618 619 // Handle common entity information. 620 ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(Info), 621 Metadata); 622 } 623 624 /// Process API notes for a C++ method. 625 static void ProcessAPINotes(Sema &S, CXXMethodDecl *Method, 626 const api_notes::CXXMethodInfo &Info, 627 VersionedInfoMetadata Metadata) { 628 if (Info.This && Info.This->isLifetimebound() && 629 !sema::implicitObjectParamIsLifetimeBound(Method)) { 630 auto MethodType = Method->getType(); 631 auto *attr = ::new (S.Context) 632 LifetimeBoundAttr(S.Context, getPlaceholderAttrInfo()); 633 QualType AttributedType = 634 S.Context.getAttributedType(attr, MethodType, MethodType); 635 TypeLocBuilder TLB; 636 TLB.pushFullCopy(Method->getTypeSourceInfo()->getTypeLoc()); 637 AttributedTypeLoc TyLoc = TLB.push<AttributedTypeLoc>(AttributedType); 638 TyLoc.setAttr(attr); 639 Method->setType(AttributedType); 640 Method->setTypeSourceInfo(TLB.getTypeSourceInfo(S.Context, AttributedType)); 641 } 642 643 ProcessAPINotes(S, (FunctionOrMethod)Method, Info, Metadata); 644 } 645 646 /// Process API notes for a global function. 647 static void ProcessAPINotes(Sema &S, FunctionDecl *D, 648 const api_notes::GlobalFunctionInfo &Info, 649 VersionedInfoMetadata Metadata) { 650 // Handle common function information. 651 ProcessAPINotes(S, FunctionOrMethod(D), 652 static_cast<const api_notes::FunctionInfo &>(Info), Metadata); 653 } 654 655 /// Process API notes for an enumerator. 656 static void ProcessAPINotes(Sema &S, EnumConstantDecl *D, 657 const api_notes::EnumConstantInfo &Info, 658 VersionedInfoMetadata Metadata) { 659 // Handle common information. 660 ProcessAPINotes(S, D, static_cast<const api_notes::CommonEntityInfo &>(Info), 661 Metadata); 662 } 663 664 /// Process API notes for an Objective-C method. 665 static void ProcessAPINotes(Sema &S, ObjCMethodDecl *D, 666 const api_notes::ObjCMethodInfo &Info, 667 VersionedInfoMetadata Metadata) { 668 // Designated initializers. 669 if (Info.DesignatedInit) { 670 handleAPINotedAttribute<ObjCDesignatedInitializerAttr>( 671 S, D, true, Metadata, [&] { 672 if (ObjCInterfaceDecl *IFace = D->getClassInterface()) 673 IFace->setHasDesignatedInitializers(); 674 675 return new (S.Context) ObjCDesignatedInitializerAttr( 676 S.Context, getPlaceholderAttrInfo()); 677 }); 678 } 679 680 // Handle common function information. 681 ProcessAPINotes(S, FunctionOrMethod(D), 682 static_cast<const api_notes::FunctionInfo &>(Info), Metadata); 683 } 684 685 /// Process API notes for a tag. 686 static void ProcessAPINotes(Sema &S, TagDecl *D, const api_notes::TagInfo &Info, 687 VersionedInfoMetadata Metadata) { 688 if (auto ImportAs = Info.SwiftImportAs) 689 D->addAttr(SwiftAttrAttr::Create(S.Context, "import_" + ImportAs.value())); 690 691 if (auto RetainOp = Info.SwiftRetainOp) 692 D->addAttr(SwiftAttrAttr::Create(S.Context, "retain:" + RetainOp.value())); 693 694 if (auto ReleaseOp = Info.SwiftReleaseOp) 695 D->addAttr( 696 SwiftAttrAttr::Create(S.Context, "release:" + ReleaseOp.value())); 697 if (auto DefaultOwnership = Info.SwiftDefaultOwnership) 698 D->addAttr(SwiftAttrAttr::Create( 699 S.Context, "returned_as_" + DefaultOwnership.value() + "_by_default")); 700 701 if (auto ConformsTo = Info.SwiftConformance) 702 D->addAttr( 703 SwiftAttrAttr::Create(S.Context, "conforms_to:" + ConformsTo.value())); 704 705 if (auto Copyable = Info.isSwiftCopyable()) { 706 if (!*Copyable) 707 D->addAttr(SwiftAttrAttr::Create(S.Context, "~Copyable")); 708 } 709 710 if (auto Escapable = Info.isSwiftEscapable()) { 711 D->addAttr(SwiftAttrAttr::Create(S.Context, 712 *Escapable ? "Escapable" : "~Escapable")); 713 } 714 715 if (auto Extensibility = Info.EnumExtensibility) { 716 using api_notes::EnumExtensibilityKind; 717 bool ShouldAddAttribute = (*Extensibility != EnumExtensibilityKind::None); 718 handleAPINotedAttribute<EnumExtensibilityAttr>( 719 S, D, ShouldAddAttribute, Metadata, [&] { 720 EnumExtensibilityAttr::Kind kind; 721 switch (*Extensibility) { 722 case EnumExtensibilityKind::None: 723 llvm_unreachable("remove only"); 724 case EnumExtensibilityKind::Open: 725 kind = EnumExtensibilityAttr::Open; 726 break; 727 case EnumExtensibilityKind::Closed: 728 kind = EnumExtensibilityAttr::Closed; 729 break; 730 } 731 return new (S.Context) 732 EnumExtensibilityAttr(S.Context, getPlaceholderAttrInfo(), kind); 733 }); 734 } 735 736 if (auto FlagEnum = Info.isFlagEnum()) { 737 handleAPINotedAttribute<FlagEnumAttr>(S, D, *FlagEnum, Metadata, [&] { 738 return new (S.Context) FlagEnumAttr(S.Context, getPlaceholderAttrInfo()); 739 }); 740 } 741 742 // Handle common type information. 743 ProcessAPINotes(S, D, static_cast<const api_notes::CommonTypeInfo &>(Info), 744 Metadata); 745 } 746 747 /// Process API notes for a typedef. 748 static void ProcessAPINotes(Sema &S, TypedefNameDecl *D, 749 const api_notes::TypedefInfo &Info, 750 VersionedInfoMetadata Metadata) { 751 // swift_wrapper 752 using SwiftWrapperKind = api_notes::SwiftNewTypeKind; 753 754 if (auto SwiftWrapper = Info.SwiftWrapper) { 755 handleAPINotedAttribute<SwiftNewTypeAttr>( 756 S, D, *SwiftWrapper != SwiftWrapperKind::None, Metadata, [&] { 757 SwiftNewTypeAttr::NewtypeKind Kind; 758 switch (*SwiftWrapper) { 759 case SwiftWrapperKind::None: 760 llvm_unreachable("Shouldn't build an attribute"); 761 762 case SwiftWrapperKind::Struct: 763 Kind = SwiftNewTypeAttr::NK_Struct; 764 break; 765 766 case SwiftWrapperKind::Enum: 767 Kind = SwiftNewTypeAttr::NK_Enum; 768 break; 769 } 770 AttributeCommonInfo SyntaxInfo{ 771 SourceRange(), 772 AttributeCommonInfo::AT_SwiftNewType, 773 {AttributeCommonInfo::AS_GNU, SwiftNewTypeAttr::GNU_swift_wrapper, 774 /*IsAlignas*/ false, /*IsRegularKeywordAttribute*/ false}}; 775 return new (S.Context) SwiftNewTypeAttr(S.Context, SyntaxInfo, Kind); 776 }); 777 } 778 779 // Handle common type information. 780 ProcessAPINotes(S, D, static_cast<const api_notes::CommonTypeInfo &>(Info), 781 Metadata); 782 } 783 784 /// Process API notes for an Objective-C class or protocol. 785 static void ProcessAPINotes(Sema &S, ObjCContainerDecl *D, 786 const api_notes::ContextInfo &Info, 787 VersionedInfoMetadata Metadata) { 788 // Handle common type information. 789 ProcessAPINotes(S, D, static_cast<const api_notes::CommonTypeInfo &>(Info), 790 Metadata); 791 } 792 793 /// Process API notes for an Objective-C class. 794 static void ProcessAPINotes(Sema &S, ObjCInterfaceDecl *D, 795 const api_notes::ContextInfo &Info, 796 VersionedInfoMetadata Metadata) { 797 if (auto AsNonGeneric = Info.getSwiftImportAsNonGeneric()) { 798 handleAPINotedAttribute<SwiftImportAsNonGenericAttr>( 799 S, D, *AsNonGeneric, Metadata, [&] { 800 return new (S.Context) 801 SwiftImportAsNonGenericAttr(S.Context, getPlaceholderAttrInfo()); 802 }); 803 } 804 805 if (auto ObjcMembers = Info.getSwiftObjCMembers()) { 806 handleAPINotedAttribute<SwiftObjCMembersAttr>( 807 S, D, *ObjcMembers, Metadata, [&] { 808 return new (S.Context) 809 SwiftObjCMembersAttr(S.Context, getPlaceholderAttrInfo()); 810 }); 811 } 812 813 // Handle information common to Objective-C classes and protocols. 814 ProcessAPINotes(S, static_cast<clang::ObjCContainerDecl *>(D), Info, 815 Metadata); 816 } 817 818 /// If we're applying API notes with an active, non-default version, and the 819 /// versioned API notes have a SwiftName but the declaration normally wouldn't 820 /// have one, add a removal attribute to make it clear that the new SwiftName 821 /// attribute only applies to the active version of \p D, not to all versions. 822 /// 823 /// This must be run \em before processing API notes for \p D, because otherwise 824 /// any existing SwiftName attribute will have been packaged up in a 825 /// SwiftVersionedAdditionAttr. 826 template <typename SpecificInfo> 827 static void maybeAttachUnversionedSwiftName( 828 Sema &S, Decl *D, 829 const api_notes::APINotesReader::VersionedInfo<SpecificInfo> Info) { 830 if (D->hasAttr<SwiftNameAttr>()) 831 return; 832 if (!Info.getSelected()) 833 return; 834 835 // Is the active slice versioned, and does it set a Swift name? 836 VersionTuple SelectedVersion; 837 SpecificInfo SelectedInfoSlice; 838 std::tie(SelectedVersion, SelectedInfoSlice) = Info[*Info.getSelected()]; 839 if (SelectedVersion.empty()) 840 return; 841 if (SelectedInfoSlice.SwiftName.empty()) 842 return; 843 844 // Does the unversioned slice /not/ set a Swift name? 845 for (const auto &VersionAndInfoSlice : Info) { 846 if (!VersionAndInfoSlice.first.empty()) 847 continue; 848 if (!VersionAndInfoSlice.second.SwiftName.empty()) 849 return; 850 } 851 852 // Then explicitly call that out with a removal attribute. 853 VersionedInfoMetadata DummyFutureMetadata( 854 SelectedVersion, IsActive_t::Inactive, IsSubstitution_t::Replacement); 855 handleAPINotedAttribute<SwiftNameAttr>( 856 S, D, /*add*/ false, DummyFutureMetadata, []() -> SwiftNameAttr * { 857 llvm_unreachable("should not try to add an attribute here"); 858 }); 859 } 860 861 /// Processes all versions of versioned API notes. 862 /// 863 /// Just dispatches to the various ProcessAPINotes functions in this file. 864 template <typename SpecificDecl, typename SpecificInfo> 865 static void ProcessVersionedAPINotes( 866 Sema &S, SpecificDecl *D, 867 const api_notes::APINotesReader::VersionedInfo<SpecificInfo> Info) { 868 869 if (!S.captureSwiftVersionIndependentAPINotes()) 870 maybeAttachUnversionedSwiftName(S, D, Info); 871 872 unsigned Selected = Info.getSelected().value_or(Info.size()); 873 874 VersionTuple Version; 875 SpecificInfo InfoSlice; 876 for (unsigned i = 0, e = Info.size(); i != e; ++i) { 877 std::tie(Version, InfoSlice) = Info[i]; 878 auto Active = (i == Selected) ? IsActive_t::Active : IsActive_t::Inactive; 879 auto Replacement = IsSubstitution_t::Original; 880 881 // When collection all APINotes as version-independent, 882 // capture all as inactive and defer to the client select the 883 // right one. 884 if (S.captureSwiftVersionIndependentAPINotes()) { 885 Active = IsActive_t::Inactive; 886 Replacement = IsSubstitution_t::Original; 887 } else if (Active == IsActive_t::Inactive && Version.empty()) { 888 Replacement = IsSubstitution_t::Replacement; 889 Version = Info[Selected].first; 890 } 891 892 ProcessAPINotes(S, D, InfoSlice, 893 VersionedInfoMetadata(Version, Active, Replacement)); 894 } 895 } 896 897 static std::optional<api_notes::Context> 898 UnwindNamespaceContext(DeclContext *DC, api_notes::APINotesManager &APINotes) { 899 if (auto NamespaceContext = dyn_cast<NamespaceDecl>(DC)) { 900 for (auto Reader : APINotes.findAPINotes(NamespaceContext->getLocation())) { 901 // Retrieve the context ID for the parent namespace of the decl. 902 std::stack<NamespaceDecl *> NamespaceStack; 903 { 904 for (auto CurrentNamespace = NamespaceContext; CurrentNamespace; 905 CurrentNamespace = 906 dyn_cast<NamespaceDecl>(CurrentNamespace->getParent())) { 907 if (!CurrentNamespace->isInlineNamespace()) 908 NamespaceStack.push(CurrentNamespace); 909 } 910 } 911 std::optional<api_notes::ContextID> NamespaceID; 912 while (!NamespaceStack.empty()) { 913 auto CurrentNamespace = NamespaceStack.top(); 914 NamespaceStack.pop(); 915 NamespaceID = 916 Reader->lookupNamespaceID(CurrentNamespace->getName(), NamespaceID); 917 if (!NamespaceID) 918 return std::nullopt; 919 } 920 if (NamespaceID) 921 return api_notes::Context(*NamespaceID, 922 api_notes::ContextKind::Namespace); 923 } 924 } 925 return std::nullopt; 926 } 927 928 static std::optional<api_notes::Context> 929 UnwindTagContext(TagDecl *DC, api_notes::APINotesManager &APINotes) { 930 assert(DC && "tag context must not be null"); 931 for (auto Reader : APINotes.findAPINotes(DC->getLocation())) { 932 // Retrieve the context ID for the parent tag of the decl. 933 std::stack<TagDecl *> TagStack; 934 { 935 for (auto CurrentTag = DC; CurrentTag; 936 CurrentTag = dyn_cast<TagDecl>(CurrentTag->getParent())) 937 TagStack.push(CurrentTag); 938 } 939 assert(!TagStack.empty()); 940 std::optional<api_notes::Context> Ctx = 941 UnwindNamespaceContext(TagStack.top()->getDeclContext(), APINotes); 942 while (!TagStack.empty()) { 943 auto CurrentTag = TagStack.top(); 944 TagStack.pop(); 945 auto CtxID = Reader->lookupTagID(CurrentTag->getName(), Ctx); 946 if (!CtxID) 947 return std::nullopt; 948 Ctx = api_notes::Context(*CtxID, api_notes::ContextKind::Tag); 949 } 950 return Ctx; 951 } 952 return std::nullopt; 953 } 954 955 /// Process API notes that are associated with this declaration, mapping them 956 /// to attributes as appropriate. 957 void Sema::ProcessAPINotes(Decl *D) { 958 if (!D) 959 return; 960 961 auto *DC = D->getDeclContext(); 962 // Globals. 963 if (DC->isFileContext() || DC->isNamespace() || DC->isExternCContext() || 964 DC->isExternCXXContext()) { 965 std::optional<api_notes::Context> APINotesContext = 966 UnwindNamespaceContext(DC, APINotes); 967 // Global variables. 968 if (auto VD = dyn_cast<VarDecl>(D)) { 969 for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 970 auto Info = 971 Reader->lookupGlobalVariable(VD->getName(), APINotesContext); 972 ProcessVersionedAPINotes(*this, VD, Info); 973 } 974 975 return; 976 } 977 978 // Global functions. 979 if (auto FD = dyn_cast<FunctionDecl>(D)) { 980 if (FD->getDeclName().isIdentifier()) { 981 for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 982 auto Info = 983 Reader->lookupGlobalFunction(FD->getName(), APINotesContext); 984 ProcessVersionedAPINotes(*this, FD, Info); 985 } 986 } 987 988 return; 989 } 990 991 // Objective-C classes. 992 if (auto Class = dyn_cast<ObjCInterfaceDecl>(D)) { 993 for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 994 auto Info = Reader->lookupObjCClassInfo(Class->getName()); 995 ProcessVersionedAPINotes(*this, Class, Info); 996 } 997 998 return; 999 } 1000 1001 // Objective-C protocols. 1002 if (auto Protocol = dyn_cast<ObjCProtocolDecl>(D)) { 1003 for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 1004 auto Info = Reader->lookupObjCProtocolInfo(Protocol->getName()); 1005 ProcessVersionedAPINotes(*this, Protocol, Info); 1006 } 1007 1008 return; 1009 } 1010 1011 // Tags 1012 if (auto Tag = dyn_cast<TagDecl>(D)) { 1013 // Determine the name of the entity to search for. If this is an 1014 // anonymous tag that gets its linked name from a typedef, look for the 1015 // typedef name. This allows tag-specific information to be added 1016 // to the declaration. 1017 std::string LookupName; 1018 if (auto typedefName = Tag->getTypedefNameForAnonDecl()) 1019 LookupName = typedefName->getName().str(); 1020 else 1021 LookupName = Tag->getName().str(); 1022 1023 // Use the source location to discern if this Tag is an OPTIONS macro. 1024 // For now we would like to limit this trick of looking up the APINote tag 1025 // using the EnumDecl's QualType in the case where the enum is anonymous. 1026 // This is only being used to support APINotes lookup for C++ 1027 // NS/CF_OPTIONS when C++-Interop is enabled. 1028 std::string MacroName = 1029 LookupName.empty() && Tag->getOuterLocStart().isMacroID() 1030 ? clang::Lexer::getImmediateMacroName( 1031 Tag->getOuterLocStart(), 1032 Tag->getASTContext().getSourceManager(), LangOpts) 1033 .str() 1034 : ""; 1035 1036 if (LookupName.empty() && isa<clang::EnumDecl>(Tag) && 1037 (MacroName == "CF_OPTIONS" || MacroName == "NS_OPTIONS" || 1038 MacroName == "OBJC_OPTIONS" || MacroName == "SWIFT_OPTIONS")) { 1039 1040 clang::QualType T = llvm::cast<clang::EnumDecl>(Tag)->getIntegerType(); 1041 LookupName = clang::QualType::getAsString( 1042 T.split(), getASTContext().getPrintingPolicy()); 1043 } 1044 1045 for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 1046 if (auto ParentTag = dyn_cast<TagDecl>(Tag->getDeclContext())) 1047 APINotesContext = UnwindTagContext(ParentTag, APINotes); 1048 auto Info = Reader->lookupTag(LookupName, APINotesContext); 1049 ProcessVersionedAPINotes(*this, Tag, Info); 1050 } 1051 1052 return; 1053 } 1054 1055 // Typedefs 1056 if (auto Typedef = dyn_cast<TypedefNameDecl>(D)) { 1057 for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 1058 auto Info = Reader->lookupTypedef(Typedef->getName(), APINotesContext); 1059 ProcessVersionedAPINotes(*this, Typedef, Info); 1060 } 1061 1062 return; 1063 } 1064 } 1065 1066 // Enumerators. 1067 if (DC->getRedeclContext()->isFileContext() || 1068 DC->getRedeclContext()->isExternCContext()) { 1069 if (auto EnumConstant = dyn_cast<EnumConstantDecl>(D)) { 1070 for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 1071 auto Info = Reader->lookupEnumConstant(EnumConstant->getName()); 1072 ProcessVersionedAPINotes(*this, EnumConstant, Info); 1073 } 1074 1075 return; 1076 } 1077 } 1078 1079 if (auto ObjCContainer = dyn_cast<ObjCContainerDecl>(DC)) { 1080 // Location function that looks up an Objective-C context. 1081 auto GetContext = [&](api_notes::APINotesReader *Reader) 1082 -> std::optional<api_notes::ContextID> { 1083 if (auto Protocol = dyn_cast<ObjCProtocolDecl>(ObjCContainer)) { 1084 if (auto Found = Reader->lookupObjCProtocolID(Protocol->getName())) 1085 return *Found; 1086 1087 return std::nullopt; 1088 } 1089 1090 if (auto Impl = dyn_cast<ObjCCategoryImplDecl>(ObjCContainer)) { 1091 if (auto Cat = Impl->getCategoryDecl()) 1092 ObjCContainer = Cat->getClassInterface(); 1093 else 1094 return std::nullopt; 1095 } 1096 1097 if (auto Category = dyn_cast<ObjCCategoryDecl>(ObjCContainer)) { 1098 if (Category->getClassInterface()) 1099 ObjCContainer = Category->getClassInterface(); 1100 else 1101 return std::nullopt; 1102 } 1103 1104 if (auto Impl = dyn_cast<ObjCImplDecl>(ObjCContainer)) { 1105 if (Impl->getClassInterface()) 1106 ObjCContainer = Impl->getClassInterface(); 1107 else 1108 return std::nullopt; 1109 } 1110 1111 if (auto Class = dyn_cast<ObjCInterfaceDecl>(ObjCContainer)) { 1112 if (auto Found = Reader->lookupObjCClassID(Class->getName())) 1113 return *Found; 1114 1115 return std::nullopt; 1116 } 1117 1118 return std::nullopt; 1119 }; 1120 1121 // Objective-C methods. 1122 if (auto Method = dyn_cast<ObjCMethodDecl>(D)) { 1123 for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 1124 if (auto Context = GetContext(Reader)) { 1125 // Map the selector. 1126 Selector Sel = Method->getSelector(); 1127 SmallVector<StringRef, 2> SelPieces; 1128 if (Sel.isUnarySelector()) { 1129 SelPieces.push_back(Sel.getNameForSlot(0)); 1130 } else { 1131 for (unsigned i = 0, n = Sel.getNumArgs(); i != n; ++i) 1132 SelPieces.push_back(Sel.getNameForSlot(i)); 1133 } 1134 1135 api_notes::ObjCSelectorRef SelectorRef; 1136 SelectorRef.NumArgs = Sel.getNumArgs(); 1137 SelectorRef.Identifiers = SelPieces; 1138 1139 auto Info = Reader->lookupObjCMethod(*Context, SelectorRef, 1140 Method->isInstanceMethod()); 1141 ProcessVersionedAPINotes(*this, Method, Info); 1142 } 1143 } 1144 } 1145 1146 // Objective-C properties. 1147 if (auto Property = dyn_cast<ObjCPropertyDecl>(D)) { 1148 for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 1149 if (auto Context = GetContext(Reader)) { 1150 bool isInstanceProperty = 1151 (Property->getPropertyAttributesAsWritten() & 1152 ObjCPropertyAttribute::kind_class) == 0; 1153 auto Info = Reader->lookupObjCProperty(*Context, Property->getName(), 1154 isInstanceProperty); 1155 ProcessVersionedAPINotes(*this, Property, Info); 1156 } 1157 } 1158 1159 return; 1160 } 1161 } 1162 1163 if (auto TagContext = dyn_cast<TagDecl>(DC)) { 1164 if (auto CXXMethod = dyn_cast<CXXMethodDecl>(D)) { 1165 if (!isa<CXXConstructorDecl>(CXXMethod) && 1166 !isa<CXXDestructorDecl>(CXXMethod) && 1167 !isa<CXXConversionDecl>(CXXMethod) && 1168 !CXXMethod->isOverloadedOperator()) { 1169 for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 1170 if (auto Context = UnwindTagContext(TagContext, APINotes)) { 1171 auto Info = 1172 Reader->lookupCXXMethod(Context->id, CXXMethod->getName()); 1173 ProcessVersionedAPINotes(*this, CXXMethod, Info); 1174 } 1175 } 1176 } 1177 } 1178 1179 if (auto Field = dyn_cast<FieldDecl>(D)) { 1180 if (!Field->isUnnamedBitField() && !Field->isAnonymousStructOrUnion()) { 1181 for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 1182 if (auto Context = UnwindTagContext(TagContext, APINotes)) { 1183 auto Info = Reader->lookupField(Context->id, Field->getName()); 1184 ProcessVersionedAPINotes(*this, Field, Info); 1185 } 1186 } 1187 } 1188 } 1189 1190 if (auto Tag = dyn_cast<TagDecl>(D)) { 1191 for (auto Reader : APINotes.findAPINotes(D->getLocation())) { 1192 if (auto Context = UnwindTagContext(TagContext, APINotes)) { 1193 auto Info = Reader->lookupTag(Tag->getName(), Context); 1194 ProcessVersionedAPINotes(*this, Tag, Info); 1195 } 1196 } 1197 } 1198 } 1199 } 1200