1 //===--- SemaAvailability.cpp - Availability attribute 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 processes the availability attribute. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "clang/AST/Attr.h" 14 #include "clang/AST/Decl.h" 15 #include "clang/AST/DeclTemplate.h" 16 #include "clang/AST/DynamicRecursiveASTVisitor.h" 17 #include "clang/AST/ExprObjC.h" 18 #include "clang/AST/StmtObjC.h" 19 #include "clang/Basic/DiagnosticSema.h" 20 #include "clang/Basic/IdentifierTable.h" 21 #include "clang/Basic/LangOptions.h" 22 #include "clang/Basic/TargetInfo.h" 23 #include "clang/Lex/Preprocessor.h" 24 #include "clang/Sema/DelayedDiagnostic.h" 25 #include "clang/Sema/ScopeInfo.h" 26 #include "clang/Sema/Sema.h" 27 #include "clang/Sema/SemaObjC.h" 28 #include "llvm/ADT/StringRef.h" 29 #include <optional> 30 31 using namespace clang; 32 using namespace sema; 33 34 static bool hasMatchingEnvironmentOrNone(const ASTContext &Context, 35 const AvailabilityAttr *AA) { 36 IdentifierInfo *IIEnvironment = AA->getEnvironment(); 37 auto Environment = Context.getTargetInfo().getTriple().getEnvironment(); 38 if (!IIEnvironment || Environment == llvm::Triple::UnknownEnvironment) 39 return true; 40 41 llvm::Triple::EnvironmentType ET = 42 AvailabilityAttr::getEnvironmentType(IIEnvironment->getName()); 43 return Environment == ET; 44 } 45 46 static const AvailabilityAttr *getAttrForPlatform(ASTContext &Context, 47 const Decl *D) { 48 AvailabilityAttr const *PartialMatch = nullptr; 49 // Check each AvailabilityAttr to find the one for this platform. 50 // For multiple attributes with the same platform try to find one for this 51 // environment. 52 // The attribute is always on the FunctionDecl, not on the 53 // FunctionTemplateDecl. 54 if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(D)) 55 D = FTD->getTemplatedDecl(); 56 for (const auto *A : D->attrs()) { 57 if (const auto *Avail = dyn_cast<AvailabilityAttr>(A)) { 58 // FIXME: this is copied from CheckAvailability. We should try to 59 // de-duplicate. 60 61 // Check if this is an App Extension "platform", and if so chop off 62 // the suffix for matching with the actual platform. 63 StringRef ActualPlatform = Avail->getPlatform()->getName(); 64 StringRef RealizedPlatform = ActualPlatform; 65 if (Context.getLangOpts().AppExt) { 66 size_t suffix = RealizedPlatform.rfind("_app_extension"); 67 if (suffix != StringRef::npos) 68 RealizedPlatform = RealizedPlatform.slice(0, suffix); 69 } 70 71 StringRef TargetPlatform = Context.getTargetInfo().getPlatformName(); 72 73 // Match the platform name. 74 if (RealizedPlatform == TargetPlatform) { 75 // Find the best matching attribute for this environment 76 if (hasMatchingEnvironmentOrNone(Context, Avail)) 77 return Avail; 78 PartialMatch = Avail; 79 } 80 } 81 } 82 return PartialMatch; 83 } 84 85 /// The diagnostic we should emit for \c D, and the declaration that 86 /// originated it, or \c AR_Available. 87 /// 88 /// \param D The declaration to check. 89 /// \param Message If non-null, this will be populated with the message from 90 /// the availability attribute that is selected. 91 /// \param ClassReceiver If we're checking the method of a class message 92 /// send, the class. Otherwise nullptr. 93 static std::pair<AvailabilityResult, const NamedDecl *> 94 ShouldDiagnoseAvailabilityOfDecl(Sema &S, const NamedDecl *D, 95 std::string *Message, 96 ObjCInterfaceDecl *ClassReceiver) { 97 AvailabilityResult Result = D->getAvailability(Message); 98 99 // For typedefs, if the typedef declaration appears available look 100 // to the underlying type to see if it is more restrictive. 101 while (const auto *TD = dyn_cast<TypedefNameDecl>(D)) { 102 if (Result == AR_Available) { 103 if (const auto *TT = TD->getUnderlyingType()->getAs<TagType>()) { 104 D = TT->getDecl(); 105 Result = D->getAvailability(Message); 106 continue; 107 } 108 } 109 break; 110 } 111 112 // For alias templates, get the underlying declaration. 113 if (const auto *ADecl = dyn_cast<TypeAliasTemplateDecl>(D)) { 114 D = ADecl->getTemplatedDecl(); 115 Result = D->getAvailability(Message); 116 } 117 118 // Forward class declarations get their attributes from their definition. 119 if (const auto *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) { 120 if (IDecl->getDefinition()) { 121 D = IDecl->getDefinition(); 122 Result = D->getAvailability(Message); 123 } 124 } 125 126 if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) 127 if (Result == AR_Available) { 128 const DeclContext *DC = ECD->getDeclContext(); 129 if (const auto *TheEnumDecl = dyn_cast<EnumDecl>(DC)) { 130 Result = TheEnumDecl->getAvailability(Message); 131 D = TheEnumDecl; 132 } 133 } 134 135 // For +new, infer availability from -init. 136 if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) { 137 if (S.ObjC().NSAPIObj && ClassReceiver) { 138 ObjCMethodDecl *Init = ClassReceiver->lookupInstanceMethod( 139 S.ObjC().NSAPIObj->getInitSelector()); 140 if (Init && Result == AR_Available && MD->isClassMethod() && 141 MD->getSelector() == S.ObjC().NSAPIObj->getNewSelector() && 142 MD->definedInNSObject(S.getASTContext())) { 143 Result = Init->getAvailability(Message); 144 D = Init; 145 } 146 } 147 } 148 149 return {Result, D}; 150 } 151 152 153 /// whether we should emit a diagnostic for \c K and \c DeclVersion in 154 /// the context of \c Ctx. For example, we should emit an unavailable diagnostic 155 /// in a deprecated context, but not the other way around. 156 static bool ShouldDiagnoseAvailabilityInContext( 157 Sema &S, AvailabilityResult K, VersionTuple DeclVersion, 158 const IdentifierInfo *DeclEnv, Decl *Ctx, const NamedDecl *OffendingDecl) { 159 assert(K != AR_Available && "Expected an unavailable declaration here!"); 160 161 // If this was defined using CF_OPTIONS, etc. then ignore the diagnostic. 162 auto DeclLoc = Ctx->getBeginLoc(); 163 // This is only a problem in Foundation's C++ implementation for CF_OPTIONS. 164 if (DeclLoc.isMacroID() && S.getLangOpts().CPlusPlus && 165 isa<TypedefDecl>(OffendingDecl)) { 166 StringRef MacroName = S.getPreprocessor().getImmediateMacroName(DeclLoc); 167 if (MacroName == "CF_OPTIONS" || MacroName == "OBJC_OPTIONS" || 168 MacroName == "SWIFT_OPTIONS" || MacroName == "NS_OPTIONS") { 169 return false; 170 } 171 } 172 173 // In HLSL, skip emitting diagnostic if the diagnostic mode is not set to 174 // strict (-fhlsl-strict-availability), or if the target is library and the 175 // availability is restricted to a specific environment/shader stage. 176 // For libraries the availability will be checked later in 177 // DiagnoseHLSLAvailability class once where the specific environment/shader 178 // stage of the caller is known. 179 if (S.getLangOpts().HLSL) { 180 if (!S.getLangOpts().HLSLStrictAvailability || 181 (DeclEnv != nullptr && 182 S.getASTContext().getTargetInfo().getTriple().getEnvironment() == 183 llvm::Triple::EnvironmentType::Library)) 184 return false; 185 } 186 187 if (K == AR_Deprecated) { 188 if (const auto *VD = dyn_cast<VarDecl>(OffendingDecl)) 189 if (VD->isLocalVarDeclOrParm() && VD->isDeprecated()) 190 return true; 191 } 192 193 // Checks if we should emit the availability diagnostic in the context of C. 194 auto CheckContext = [&](const Decl *C) { 195 if (K == AR_NotYetIntroduced) { 196 if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, C)) 197 if (AA->getIntroduced() >= DeclVersion && 198 AA->getEnvironment() == DeclEnv) 199 return true; 200 } else if (K == AR_Deprecated) { 201 if (C->isDeprecated()) 202 return true; 203 } else if (K == AR_Unavailable) { 204 // It is perfectly fine to refer to an 'unavailable' Objective-C method 205 // when it is referenced from within the @implementation itself. In this 206 // context, we interpret unavailable as a form of access control. 207 if (const auto *MD = dyn_cast<ObjCMethodDecl>(OffendingDecl)) { 208 if (const auto *Impl = dyn_cast<ObjCImplDecl>(C)) { 209 if (MD->getClassInterface() == Impl->getClassInterface()) 210 return true; 211 } 212 } 213 } 214 215 if (C->isUnavailable()) 216 return true; 217 return false; 218 }; 219 220 do { 221 if (CheckContext(Ctx)) 222 return false; 223 224 // An implementation implicitly has the availability of the interface. 225 // Unless it is "+load" method. 226 if (const auto *MethodD = dyn_cast<ObjCMethodDecl>(Ctx)) 227 if (MethodD->isClassMethod() && 228 MethodD->getSelector().getAsString() == "load") 229 return true; 230 231 if (const auto *CatOrImpl = dyn_cast<ObjCImplDecl>(Ctx)) { 232 if (const ObjCInterfaceDecl *Interface = CatOrImpl->getClassInterface()) 233 if (CheckContext(Interface)) 234 return false; 235 } 236 // A category implicitly has the availability of the interface. 237 else if (const auto *CatD = dyn_cast<ObjCCategoryDecl>(Ctx)) 238 if (const ObjCInterfaceDecl *Interface = CatD->getClassInterface()) 239 if (CheckContext(Interface)) 240 return false; 241 } while ((Ctx = cast_or_null<Decl>(Ctx->getDeclContext()))); 242 243 return true; 244 } 245 246 static unsigned getAvailabilityDiagnosticKind( 247 const ASTContext &Context, const VersionTuple &DeploymentVersion, 248 const VersionTuple &DeclVersion, bool HasMatchingEnv) { 249 const auto &Triple = Context.getTargetInfo().getTriple(); 250 VersionTuple ForceAvailabilityFromVersion; 251 switch (Triple.getOS()) { 252 // For iOS, emit the diagnostic even if -Wunguarded-availability is 253 // not specified for deployment targets >= to iOS 11 or equivalent or 254 // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or 255 // later. 256 case llvm::Triple::IOS: 257 case llvm::Triple::TvOS: 258 ForceAvailabilityFromVersion = VersionTuple(/*Major=*/11); 259 break; 260 case llvm::Triple::WatchOS: 261 ForceAvailabilityFromVersion = VersionTuple(/*Major=*/4); 262 break; 263 case llvm::Triple::Darwin: 264 case llvm::Triple::MacOSX: 265 ForceAvailabilityFromVersion = VersionTuple(/*Major=*/10, /*Minor=*/13); 266 break; 267 // For HLSL, use diagnostic from HLSLAvailability group which 268 // are reported as errors by default and in strict diagnostic mode 269 // (-fhlsl-strict-availability) and as warnings in relaxed diagnostic 270 // mode (-Wno-error=hlsl-availability) 271 case llvm::Triple::ShaderModel: 272 return HasMatchingEnv ? diag::warn_hlsl_availability 273 : diag::warn_hlsl_availability_unavailable; 274 default: 275 // New Apple targets should always warn about availability. 276 ForceAvailabilityFromVersion = 277 (Triple.getVendor() == llvm::Triple::Apple) 278 ? VersionTuple(/*Major=*/0, 0) 279 : VersionTuple(/*Major=*/(unsigned)-1, (unsigned)-1); 280 } 281 if (DeploymentVersion >= ForceAvailabilityFromVersion || 282 DeclVersion >= ForceAvailabilityFromVersion) 283 return HasMatchingEnv ? diag::warn_unguarded_availability_new 284 : diag::warn_unguarded_availability_unavailable_new; 285 return HasMatchingEnv ? diag::warn_unguarded_availability 286 : diag::warn_unguarded_availability_unavailable; 287 } 288 289 static NamedDecl *findEnclosingDeclToAnnotate(Decl *OrigCtx) { 290 for (Decl *Ctx = OrigCtx; Ctx; 291 Ctx = cast_or_null<Decl>(Ctx->getDeclContext())) { 292 if (isa<TagDecl>(Ctx) || isa<FunctionDecl>(Ctx) || isa<ObjCMethodDecl>(Ctx)) 293 return cast<NamedDecl>(Ctx); 294 if (auto *CD = dyn_cast<ObjCContainerDecl>(Ctx)) { 295 if (auto *Imp = dyn_cast<ObjCImplDecl>(Ctx)) 296 return Imp->getClassInterface(); 297 return CD; 298 } 299 } 300 301 return dyn_cast<NamedDecl>(OrigCtx); 302 } 303 304 namespace { 305 306 struct AttributeInsertion { 307 StringRef Prefix; 308 SourceLocation Loc; 309 StringRef Suffix; 310 311 static AttributeInsertion createInsertionAfter(const NamedDecl *D) { 312 return {" ", D->getEndLoc(), ""}; 313 } 314 static AttributeInsertion createInsertionAfter(SourceLocation Loc) { 315 return {" ", Loc, ""}; 316 } 317 static AttributeInsertion createInsertionBefore(const NamedDecl *D) { 318 return {"", D->getBeginLoc(), "\n"}; 319 } 320 }; 321 322 } // end anonymous namespace 323 324 /// Tries to parse a string as ObjC method name. 325 /// 326 /// \param Name The string to parse. Expected to originate from availability 327 /// attribute argument. 328 /// \param SlotNames The vector that will be populated with slot names. In case 329 /// of unsuccessful parsing can contain invalid data. 330 /// \returns A number of method parameters if parsing was successful, 331 /// std::nullopt otherwise. 332 static std::optional<unsigned> 333 tryParseObjCMethodName(StringRef Name, SmallVectorImpl<StringRef> &SlotNames, 334 const LangOptions &LangOpts) { 335 // Accept replacements starting with - or + as valid ObjC method names. 336 if (!Name.empty() && (Name.front() == '-' || Name.front() == '+')) 337 Name = Name.drop_front(1); 338 if (Name.empty()) 339 return std::nullopt; 340 Name.split(SlotNames, ':'); 341 unsigned NumParams; 342 if (Name.back() == ':') { 343 // Remove an empty string at the end that doesn't represent any slot. 344 SlotNames.pop_back(); 345 NumParams = SlotNames.size(); 346 } else { 347 if (SlotNames.size() != 1) 348 // Not a valid method name, just a colon-separated string. 349 return std::nullopt; 350 NumParams = 0; 351 } 352 // Verify all slot names are valid. 353 bool AllowDollar = LangOpts.DollarIdents; 354 for (StringRef S : SlotNames) { 355 if (S.empty()) 356 continue; 357 if (!isValidAsciiIdentifier(S, AllowDollar)) 358 return std::nullopt; 359 } 360 return NumParams; 361 } 362 363 /// Returns a source location in which it's appropriate to insert a new 364 /// attribute for the given declaration \D. 365 static std::optional<AttributeInsertion> 366 createAttributeInsertion(const NamedDecl *D, const SourceManager &SM, 367 const LangOptions &LangOpts) { 368 if (isa<ObjCPropertyDecl>(D)) 369 return AttributeInsertion::createInsertionAfter(D); 370 if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) { 371 if (MD->hasBody()) 372 return std::nullopt; 373 return AttributeInsertion::createInsertionAfter(D); 374 } 375 if (const auto *TD = dyn_cast<TagDecl>(D)) { 376 SourceLocation Loc = 377 Lexer::getLocForEndOfToken(TD->getInnerLocStart(), 0, SM, LangOpts); 378 if (Loc.isInvalid()) 379 return std::nullopt; 380 // Insert after the 'struct'/whatever keyword. 381 return AttributeInsertion::createInsertionAfter(Loc); 382 } 383 return AttributeInsertion::createInsertionBefore(D); 384 } 385 386 /// Actually emit an availability diagnostic for a reference to an unavailable 387 /// decl. 388 /// 389 /// \param Ctx The context that the reference occurred in 390 /// \param ReferringDecl The exact declaration that was referenced. 391 /// \param OffendingDecl A related decl to \c ReferringDecl that has an 392 /// availability attribute corresponding to \c K attached to it. Note that this 393 /// may not be the same as ReferringDecl, i.e. if an EnumDecl is annotated and 394 /// we refer to a member EnumConstantDecl, ReferringDecl is the EnumConstantDecl 395 /// and OffendingDecl is the EnumDecl. 396 static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, 397 Decl *Ctx, const NamedDecl *ReferringDecl, 398 const NamedDecl *OffendingDecl, 399 StringRef Message, 400 ArrayRef<SourceLocation> Locs, 401 const ObjCInterfaceDecl *UnknownObjCClass, 402 const ObjCPropertyDecl *ObjCProperty, 403 bool ObjCPropertyAccess) { 404 // Diagnostics for deprecated or unavailable. 405 unsigned diag, diag_message, diag_fwdclass_message; 406 unsigned diag_available_here = diag::note_availability_specified_here; 407 SourceLocation NoteLocation = OffendingDecl->getLocation(); 408 409 // Matches 'diag::note_property_attribute' options. 410 unsigned property_note_select; 411 412 // Matches diag::note_availability_specified_here. 413 unsigned available_here_select_kind; 414 415 VersionTuple DeclVersion; 416 const AvailabilityAttr *AA = getAttrForPlatform(S.Context, OffendingDecl); 417 const IdentifierInfo *IIEnv = nullptr; 418 if (AA) { 419 DeclVersion = AA->getIntroduced(); 420 IIEnv = AA->getEnvironment(); 421 } 422 423 if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, IIEnv, Ctx, 424 OffendingDecl)) 425 return; 426 427 SourceLocation Loc = Locs.front(); 428 429 // The declaration can have multiple availability attributes, we are looking 430 // at one of them. 431 if (AA && AA->isInherited()) { 432 for (const Decl *Redecl = OffendingDecl->getMostRecentDecl(); Redecl; 433 Redecl = Redecl->getPreviousDecl()) { 434 const AvailabilityAttr *AForRedecl = 435 getAttrForPlatform(S.Context, Redecl); 436 if (AForRedecl && !AForRedecl->isInherited()) { 437 // If D is a declaration with inherited attributes, the note should 438 // point to the declaration with actual attributes. 439 NoteLocation = Redecl->getLocation(); 440 break; 441 } 442 } 443 } 444 445 switch (K) { 446 case AR_NotYetIntroduced: { 447 // We would like to emit the diagnostic even if -Wunguarded-availability is 448 // not specified for deployment targets >= to iOS 11 or equivalent or 449 // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or 450 // later. 451 assert(AA != nullptr && "expecting valid availability attribute"); 452 VersionTuple Introduced = AA->getIntroduced(); 453 bool EnvironmentMatchesOrNone = 454 hasMatchingEnvironmentOrNone(S.getASTContext(), AA); 455 456 const TargetInfo &TI = S.getASTContext().getTargetInfo(); 457 std::string PlatformName( 458 AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName())); 459 llvm::StringRef TargetEnvironment( 460 llvm::Triple::getEnvironmentTypeName(TI.getTriple().getEnvironment())); 461 llvm::StringRef AttrEnvironment = 462 AA->getEnvironment() ? AA->getEnvironment()->getName() : ""; 463 bool UseEnvironment = 464 (!AttrEnvironment.empty() && !TargetEnvironment.empty()); 465 466 unsigned DiagKind = getAvailabilityDiagnosticKind( 467 S.Context, S.Context.getTargetInfo().getPlatformMinVersion(), 468 Introduced, EnvironmentMatchesOrNone); 469 470 S.Diag(Loc, DiagKind) << OffendingDecl << PlatformName 471 << Introduced.getAsString() << UseEnvironment 472 << TargetEnvironment; 473 474 S.Diag(OffendingDecl->getLocation(), 475 diag::note_partial_availability_specified_here) 476 << OffendingDecl << PlatformName << Introduced.getAsString() 477 << S.Context.getTargetInfo().getPlatformMinVersion().getAsString() 478 << UseEnvironment << AttrEnvironment << TargetEnvironment; 479 480 // Do not offer to silence the warning or fixits for HLSL 481 if (S.getLangOpts().HLSL) 482 return; 483 484 if (const auto *Enclosing = findEnclosingDeclToAnnotate(Ctx)) { 485 if (const auto *TD = dyn_cast<TagDecl>(Enclosing)) 486 if (TD->getDeclName().isEmpty()) { 487 S.Diag(TD->getLocation(), 488 diag::note_decl_unguarded_availability_silence) 489 << /*Anonymous*/ 1 << TD->getKindName(); 490 return; 491 } 492 auto FixitNoteDiag = 493 S.Diag(Enclosing->getLocation(), 494 diag::note_decl_unguarded_availability_silence) 495 << /*Named*/ 0 << Enclosing; 496 // Don't offer a fixit for declarations with availability attributes. 497 if (Enclosing->hasAttr<AvailabilityAttr>()) 498 return; 499 Preprocessor &PP = S.getPreprocessor(); 500 if (!PP.isMacroDefined("API_AVAILABLE")) 501 return; 502 std::optional<AttributeInsertion> Insertion = createAttributeInsertion( 503 Enclosing, S.getSourceManager(), S.getLangOpts()); 504 if (!Insertion) 505 return; 506 StringRef PlatformName = 507 S.getASTContext().getTargetInfo().getPlatformName(); 508 509 // Apple's API_AVAILABLE macro expands roughly like this. 510 // API_AVAILABLE(ios(17.0)) 511 // __attribute__((availability(__API_AVAILABLE_PLATFORM_ios(17.0))) 512 // __attribute__((availability(ios,introduced=17.0))) 513 // In order to figure out which platform name to use in the API_AVAILABLE 514 // macro, the associated __API_AVAILABLE_PLATFORM_ macro needs to be 515 // found. The __API_AVAILABLE_PLATFORM_ macros aren't consistent about 516 // using the canonical platform name, source spelling name, or one of the 517 // other supported names (i.e. one of the keys in canonicalizePlatformName 518 // that's neither). Check all of the supported names for a match. 519 std::vector<StringRef> EquivalentPlatforms = 520 AvailabilityAttr::equivalentPlatformNames(PlatformName); 521 llvm::Twine MacroPrefix = "__API_AVAILABLE_PLATFORM_"; 522 auto AvailablePlatform = 523 llvm::find_if(EquivalentPlatforms, [&](StringRef EquivalentPlatform) { 524 return PP.isMacroDefined((MacroPrefix + EquivalentPlatform).str()); 525 }); 526 if (AvailablePlatform == EquivalentPlatforms.end()) 527 return; 528 std::string Introduced = 529 OffendingDecl->getVersionIntroduced().getAsString(); 530 FixitNoteDiag << FixItHint::CreateInsertion( 531 Insertion->Loc, 532 (llvm::Twine(Insertion->Prefix) + "API_AVAILABLE(" + 533 *AvailablePlatform + "(" + Introduced + "))" + Insertion->Suffix) 534 .str()); 535 } 536 return; 537 } 538 case AR_Deprecated: 539 diag = !ObjCPropertyAccess ? diag::warn_deprecated 540 : diag::warn_property_method_deprecated; 541 diag_message = diag::warn_deprecated_message; 542 diag_fwdclass_message = diag::warn_deprecated_fwdclass_message; 543 property_note_select = /* deprecated */ 0; 544 available_here_select_kind = /* deprecated */ 2; 545 if (const auto *AL = OffendingDecl->getAttr<DeprecatedAttr>()) 546 NoteLocation = AL->getLocation(); 547 break; 548 549 case AR_Unavailable: 550 diag = !ObjCPropertyAccess ? diag::err_unavailable 551 : diag::err_property_method_unavailable; 552 diag_message = diag::err_unavailable_message; 553 diag_fwdclass_message = diag::warn_unavailable_fwdclass_message; 554 property_note_select = /* unavailable */ 1; 555 available_here_select_kind = /* unavailable */ 0; 556 557 if (auto AL = OffendingDecl->getAttr<UnavailableAttr>()) { 558 if (AL->isImplicit() && AL->getImplicitReason()) { 559 // Most of these failures are due to extra restrictions in ARC; 560 // reflect that in the primary diagnostic when applicable. 561 auto flagARCError = [&] { 562 if (S.getLangOpts().ObjCAutoRefCount && 563 S.getSourceManager().isInSystemHeader( 564 OffendingDecl->getLocation())) 565 diag = diag::err_unavailable_in_arc; 566 }; 567 568 switch (AL->getImplicitReason()) { 569 case UnavailableAttr::IR_None: break; 570 571 case UnavailableAttr::IR_ARCForbiddenType: 572 flagARCError(); 573 diag_available_here = diag::note_arc_forbidden_type; 574 break; 575 576 case UnavailableAttr::IR_ForbiddenWeak: 577 if (S.getLangOpts().ObjCWeakRuntime) 578 diag_available_here = diag::note_arc_weak_disabled; 579 else 580 diag_available_here = diag::note_arc_weak_no_runtime; 581 break; 582 583 case UnavailableAttr::IR_ARCForbiddenConversion: 584 flagARCError(); 585 diag_available_here = diag::note_performs_forbidden_arc_conversion; 586 break; 587 588 case UnavailableAttr::IR_ARCInitReturnsUnrelated: 589 flagARCError(); 590 diag_available_here = diag::note_arc_init_returns_unrelated; 591 break; 592 593 case UnavailableAttr::IR_ARCFieldWithOwnership: 594 flagARCError(); 595 diag_available_here = diag::note_arc_field_with_ownership; 596 break; 597 } 598 } 599 } 600 break; 601 602 case AR_Available: 603 llvm_unreachable("Warning for availability of available declaration?"); 604 } 605 606 SmallVector<FixItHint, 12> FixIts; 607 if (K == AR_Deprecated) { 608 StringRef Replacement; 609 if (auto AL = OffendingDecl->getAttr<DeprecatedAttr>()) 610 Replacement = AL->getReplacement(); 611 if (auto AL = getAttrForPlatform(S.Context, OffendingDecl)) 612 Replacement = AL->getReplacement(); 613 614 CharSourceRange UseRange; 615 if (!Replacement.empty()) 616 UseRange = 617 CharSourceRange::getCharRange(Loc, S.getLocForEndOfToken(Loc)); 618 if (UseRange.isValid()) { 619 if (const auto *MethodDecl = dyn_cast<ObjCMethodDecl>(ReferringDecl)) { 620 Selector Sel = MethodDecl->getSelector(); 621 SmallVector<StringRef, 12> SelectorSlotNames; 622 std::optional<unsigned> NumParams = tryParseObjCMethodName( 623 Replacement, SelectorSlotNames, S.getLangOpts()); 624 if (NumParams && *NumParams == Sel.getNumArgs()) { 625 assert(SelectorSlotNames.size() == Locs.size()); 626 for (unsigned I = 0; I < Locs.size(); ++I) { 627 if (!Sel.getNameForSlot(I).empty()) { 628 CharSourceRange NameRange = CharSourceRange::getCharRange( 629 Locs[I], S.getLocForEndOfToken(Locs[I])); 630 FixIts.push_back(FixItHint::CreateReplacement( 631 NameRange, SelectorSlotNames[I])); 632 } else 633 FixIts.push_back( 634 FixItHint::CreateInsertion(Locs[I], SelectorSlotNames[I])); 635 } 636 } else 637 FixIts.push_back(FixItHint::CreateReplacement(UseRange, Replacement)); 638 } else 639 FixIts.push_back(FixItHint::CreateReplacement(UseRange, Replacement)); 640 } 641 } 642 643 // We emit deprecation warning for deprecated specializations 644 // when their instantiation stacks originate outside 645 // of a system header, even if the diagnostics is suppresed at the 646 // point of definition. 647 SourceLocation InstantiationLoc = 648 S.getTopMostPointOfInstantiation(ReferringDecl); 649 bool ShouldAllowWarningInSystemHeader = 650 InstantiationLoc != Loc && 651 !S.getSourceManager().isInSystemHeader(InstantiationLoc); 652 struct AllowWarningInSystemHeaders { 653 AllowWarningInSystemHeaders(DiagnosticsEngine &E, 654 bool AllowWarningInSystemHeaders) 655 : Engine(E), Prev(E.getSuppressSystemWarnings()) { 656 E.setSuppressSystemWarnings(!AllowWarningInSystemHeaders); 657 } 658 ~AllowWarningInSystemHeaders() { Engine.setSuppressSystemWarnings(Prev); } 659 660 private: 661 DiagnosticsEngine &Engine; 662 bool Prev; 663 } SystemWarningOverrideRAII(S.getDiagnostics(), 664 ShouldAllowWarningInSystemHeader); 665 666 if (!Message.empty()) { 667 S.Diag(Loc, diag_message) << ReferringDecl << Message << FixIts; 668 if (ObjCProperty) 669 S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute) 670 << ObjCProperty->getDeclName() << property_note_select; 671 } else if (!UnknownObjCClass) { 672 S.Diag(Loc, diag) << ReferringDecl << FixIts; 673 if (ObjCProperty) 674 S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute) 675 << ObjCProperty->getDeclName() << property_note_select; 676 } else { 677 S.Diag(Loc, diag_fwdclass_message) << ReferringDecl << FixIts; 678 S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class); 679 } 680 681 S.Diag(NoteLocation, diag_available_here) 682 << OffendingDecl << available_here_select_kind; 683 } 684 685 void Sema::handleDelayedAvailabilityCheck(DelayedDiagnostic &DD, Decl *Ctx) { 686 assert(DD.Kind == DelayedDiagnostic::Availability && 687 "Expected an availability diagnostic here"); 688 689 DD.Triggered = true; 690 DoEmitAvailabilityWarning( 691 *this, DD.getAvailabilityResult(), Ctx, DD.getAvailabilityReferringDecl(), 692 DD.getAvailabilityOffendingDecl(), DD.getAvailabilityMessage(), 693 DD.getAvailabilitySelectorLocs(), DD.getUnknownObjCClass(), 694 DD.getObjCProperty(), false); 695 } 696 697 static void EmitAvailabilityWarning(Sema &S, AvailabilityResult AR, 698 const NamedDecl *ReferringDecl, 699 const NamedDecl *OffendingDecl, 700 StringRef Message, 701 ArrayRef<SourceLocation> Locs, 702 const ObjCInterfaceDecl *UnknownObjCClass, 703 const ObjCPropertyDecl *ObjCProperty, 704 bool ObjCPropertyAccess) { 705 // Delay if we're currently parsing a declaration. 706 if (S.DelayedDiagnostics.shouldDelayDiagnostics()) { 707 S.DelayedDiagnostics.add( 708 DelayedDiagnostic::makeAvailability( 709 AR, Locs, ReferringDecl, OffendingDecl, UnknownObjCClass, 710 ObjCProperty, Message, ObjCPropertyAccess)); 711 return; 712 } 713 714 Decl *Ctx = cast<Decl>(S.getCurLexicalContext()); 715 DoEmitAvailabilityWarning(S, AR, Ctx, ReferringDecl, OffendingDecl, 716 Message, Locs, UnknownObjCClass, ObjCProperty, 717 ObjCPropertyAccess); 718 } 719 720 namespace { 721 722 /// Returns true if the given statement can be a body-like child of \p Parent. 723 bool isBodyLikeChildStmt(const Stmt *S, const Stmt *Parent) { 724 switch (Parent->getStmtClass()) { 725 case Stmt::IfStmtClass: 726 return cast<IfStmt>(Parent)->getThen() == S || 727 cast<IfStmt>(Parent)->getElse() == S; 728 case Stmt::WhileStmtClass: 729 return cast<WhileStmt>(Parent)->getBody() == S; 730 case Stmt::DoStmtClass: 731 return cast<DoStmt>(Parent)->getBody() == S; 732 case Stmt::ForStmtClass: 733 return cast<ForStmt>(Parent)->getBody() == S; 734 case Stmt::CXXForRangeStmtClass: 735 return cast<CXXForRangeStmt>(Parent)->getBody() == S; 736 case Stmt::ObjCForCollectionStmtClass: 737 return cast<ObjCForCollectionStmt>(Parent)->getBody() == S; 738 case Stmt::CaseStmtClass: 739 case Stmt::DefaultStmtClass: 740 return cast<SwitchCase>(Parent)->getSubStmt() == S; 741 default: 742 return false; 743 } 744 } 745 746 class StmtUSEFinder : public DynamicRecursiveASTVisitor { 747 const Stmt *Target; 748 749 public: 750 bool VisitStmt(Stmt *S) override { return S != Target; } 751 752 /// Returns true if the given statement is present in the given declaration. 753 static bool isContained(const Stmt *Target, const Decl *D) { 754 StmtUSEFinder Visitor; 755 Visitor.Target = Target; 756 return !Visitor.TraverseDecl(const_cast<Decl *>(D)); 757 } 758 }; 759 760 /// Traverses the AST and finds the last statement that used a given 761 /// declaration. 762 class LastDeclUSEFinder : public DynamicRecursiveASTVisitor { 763 const Decl *D; 764 765 public: 766 bool VisitDeclRefExpr(DeclRefExpr *DRE) override { 767 if (DRE->getDecl() == D) 768 return false; 769 return true; 770 } 771 772 static const Stmt *findLastStmtThatUsesDecl(const Decl *D, 773 const CompoundStmt *Scope) { 774 LastDeclUSEFinder Visitor; 775 Visitor.D = D; 776 for (const Stmt *S : llvm::reverse(Scope->body())) { 777 if (!Visitor.TraverseStmt(const_cast<Stmt *>(S))) 778 return S; 779 } 780 return nullptr; 781 } 782 }; 783 784 /// This class implements -Wunguarded-availability. 785 /// 786 /// This is done with a traversal of the AST of a function that makes reference 787 /// to a partially available declaration. Whenever we encounter an \c if of the 788 /// form: \c if(@available(...)), we use the version from the condition to visit 789 /// the then statement. 790 class DiagnoseUnguardedAvailability : public DynamicRecursiveASTVisitor { 791 Sema &SemaRef; 792 Decl *Ctx; 793 794 /// Stack of potentially nested 'if (@available(...))'s. 795 SmallVector<VersionTuple, 8> AvailabilityStack; 796 SmallVector<const Stmt *, 16> StmtStack; 797 798 void DiagnoseDeclAvailability(NamedDecl *D, SourceRange Range, 799 ObjCInterfaceDecl *ClassReceiver = nullptr); 800 801 public: 802 DiagnoseUnguardedAvailability(Sema &SemaRef, Decl *Ctx) 803 : SemaRef(SemaRef), Ctx(Ctx) { 804 AvailabilityStack.push_back( 805 SemaRef.Context.getTargetInfo().getPlatformMinVersion()); 806 } 807 808 bool TraverseStmt(Stmt *S) override { 809 if (!S) 810 return true; 811 StmtStack.push_back(S); 812 bool Result = DynamicRecursiveASTVisitor::TraverseStmt(S); 813 StmtStack.pop_back(); 814 return Result; 815 } 816 817 void IssueDiagnostics(Stmt *S) { TraverseStmt(S); } 818 819 bool TraverseIfStmt(IfStmt *If) override; 820 821 // for 'case X:' statements, don't bother looking at the 'X'; it can't lead 822 // to any useful diagnostics. 823 bool TraverseCaseStmt(CaseStmt *CS) override { 824 return TraverseStmt(CS->getSubStmt()); 825 } 826 827 bool VisitObjCMessageExpr(ObjCMessageExpr *Msg) override { 828 if (ObjCMethodDecl *D = Msg->getMethodDecl()) { 829 ObjCInterfaceDecl *ID = nullptr; 830 QualType ReceiverTy = Msg->getClassReceiver(); 831 if (!ReceiverTy.isNull() && ReceiverTy->getAsObjCInterfaceType()) 832 ID = ReceiverTy->getAsObjCInterfaceType()->getInterface(); 833 834 DiagnoseDeclAvailability( 835 D, SourceRange(Msg->getSelectorStartLoc(), Msg->getEndLoc()), ID); 836 } 837 return true; 838 } 839 840 bool VisitDeclRefExpr(DeclRefExpr *DRE) override { 841 DiagnoseDeclAvailability(DRE->getDecl(), 842 SourceRange(DRE->getBeginLoc(), DRE->getEndLoc())); 843 return true; 844 } 845 846 bool VisitMemberExpr(MemberExpr *ME) override { 847 DiagnoseDeclAvailability(ME->getMemberDecl(), 848 SourceRange(ME->getBeginLoc(), ME->getEndLoc())); 849 return true; 850 } 851 852 bool VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *E) override { 853 SemaRef.Diag(E->getBeginLoc(), diag::warn_at_available_unchecked_use) 854 << (!SemaRef.getLangOpts().ObjC); 855 return true; 856 } 857 858 bool VisitTypeLoc(TypeLoc Ty) override; 859 }; 860 861 void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability( 862 NamedDecl *D, SourceRange Range, ObjCInterfaceDecl *ReceiverClass) { 863 AvailabilityResult Result; 864 const NamedDecl *OffendingDecl; 865 std::tie(Result, OffendingDecl) = 866 ShouldDiagnoseAvailabilityOfDecl(SemaRef, D, nullptr, ReceiverClass); 867 if (Result != AR_Available) { 868 // All other diagnostic kinds have already been handled in 869 // DiagnoseAvailabilityOfDecl. 870 if (Result != AR_NotYetIntroduced) 871 return; 872 873 const AvailabilityAttr *AA = 874 getAttrForPlatform(SemaRef.getASTContext(), OffendingDecl); 875 assert(AA != nullptr && "expecting valid availability attribute"); 876 bool EnvironmentMatchesOrNone = 877 hasMatchingEnvironmentOrNone(SemaRef.getASTContext(), AA); 878 VersionTuple Introduced = AA->getIntroduced(); 879 880 if (EnvironmentMatchesOrNone && AvailabilityStack.back() >= Introduced) 881 return; 882 883 // If the context of this function is less available than D, we should not 884 // emit a diagnostic. 885 if (!ShouldDiagnoseAvailabilityInContext(SemaRef, Result, Introduced, 886 AA->getEnvironment(), Ctx, 887 OffendingDecl)) 888 return; 889 890 const TargetInfo &TI = SemaRef.getASTContext().getTargetInfo(); 891 std::string PlatformName( 892 AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName())); 893 llvm::StringRef TargetEnvironment(TI.getTriple().getEnvironmentName()); 894 llvm::StringRef AttrEnvironment = 895 AA->getEnvironment() ? AA->getEnvironment()->getName() : ""; 896 bool UseEnvironment = 897 (!AttrEnvironment.empty() && !TargetEnvironment.empty()); 898 899 unsigned DiagKind = getAvailabilityDiagnosticKind( 900 SemaRef.Context, 901 SemaRef.Context.getTargetInfo().getPlatformMinVersion(), Introduced, 902 EnvironmentMatchesOrNone); 903 904 SemaRef.Diag(Range.getBegin(), DiagKind) 905 << Range << D << PlatformName << Introduced.getAsString() 906 << UseEnvironment << TargetEnvironment; 907 908 SemaRef.Diag(OffendingDecl->getLocation(), 909 diag::note_partial_availability_specified_here) 910 << OffendingDecl << PlatformName << Introduced.getAsString() 911 << SemaRef.Context.getTargetInfo().getPlatformMinVersion().getAsString() 912 << UseEnvironment << AttrEnvironment << TargetEnvironment; 913 914 // Do not offer to silence the warning or fixits for HLSL 915 if (SemaRef.getLangOpts().HLSL) 916 return; 917 918 auto FixitDiag = 919 SemaRef.Diag(Range.getBegin(), diag::note_unguarded_available_silence) 920 << Range << D 921 << (SemaRef.getLangOpts().ObjC ? /*@available*/ 0 922 : /*__builtin_available*/ 1); 923 924 // Find the statement which should be enclosed in the if @available check. 925 if (StmtStack.empty()) 926 return; 927 const Stmt *StmtOfUse = StmtStack.back(); 928 const CompoundStmt *Scope = nullptr; 929 for (const Stmt *S : llvm::reverse(StmtStack)) { 930 if (const auto *CS = dyn_cast<CompoundStmt>(S)) { 931 Scope = CS; 932 break; 933 } 934 if (isBodyLikeChildStmt(StmtOfUse, S)) { 935 // The declaration won't be seen outside of the statement, so we don't 936 // have to wrap the uses of any declared variables in if (@available). 937 // Therefore we can avoid setting Scope here. 938 break; 939 } 940 StmtOfUse = S; 941 } 942 const Stmt *LastStmtOfUse = nullptr; 943 if (isa<DeclStmt>(StmtOfUse) && Scope) { 944 for (const Decl *D : cast<DeclStmt>(StmtOfUse)->decls()) { 945 if (StmtUSEFinder::isContained(StmtStack.back(), D)) { 946 LastStmtOfUse = LastDeclUSEFinder::findLastStmtThatUsesDecl(D, Scope); 947 break; 948 } 949 } 950 } 951 952 const SourceManager &SM = SemaRef.getSourceManager(); 953 SourceLocation IfInsertionLoc = 954 SM.getExpansionLoc(StmtOfUse->getBeginLoc()); 955 SourceLocation StmtEndLoc = 956 SM.getExpansionRange( 957 (LastStmtOfUse ? LastStmtOfUse : StmtOfUse)->getEndLoc()) 958 .getEnd(); 959 if (SM.getFileID(IfInsertionLoc) != SM.getFileID(StmtEndLoc)) 960 return; 961 962 StringRef Indentation = Lexer::getIndentationForLine(IfInsertionLoc, SM); 963 const char *ExtraIndentation = " "; 964 std::string FixItString; 965 llvm::raw_string_ostream FixItOS(FixItString); 966 FixItOS << "if (" << (SemaRef.getLangOpts().ObjC ? "@available" 967 : "__builtin_available") 968 << "(" 969 << AvailabilityAttr::getPlatformNameSourceSpelling( 970 SemaRef.getASTContext().getTargetInfo().getPlatformName()) 971 << " " << Introduced.getAsString() << ", *)) {\n" 972 << Indentation << ExtraIndentation; 973 FixitDiag << FixItHint::CreateInsertion(IfInsertionLoc, FixItOS.str()); 974 SourceLocation ElseInsertionLoc = Lexer::findLocationAfterToken( 975 StmtEndLoc, tok::semi, SM, SemaRef.getLangOpts(), 976 /*SkipTrailingWhitespaceAndNewLine=*/false); 977 if (ElseInsertionLoc.isInvalid()) 978 ElseInsertionLoc = 979 Lexer::getLocForEndOfToken(StmtEndLoc, 0, SM, SemaRef.getLangOpts()); 980 FixItOS.str().clear(); 981 FixItOS << "\n" 982 << Indentation << "} else {\n" 983 << Indentation << ExtraIndentation 984 << "// Fallback on earlier versions\n" 985 << Indentation << "}"; 986 FixitDiag << FixItHint::CreateInsertion(ElseInsertionLoc, FixItOS.str()); 987 } 988 } 989 990 bool DiagnoseUnguardedAvailability::VisitTypeLoc(TypeLoc Ty) { 991 const Type *TyPtr = Ty.getTypePtr(); 992 SourceRange Range{Ty.getBeginLoc(), Ty.getEndLoc()}; 993 994 if (Range.isInvalid()) 995 return true; 996 997 if (const auto *TT = dyn_cast<TagType>(TyPtr)) { 998 TagDecl *TD = TT->getDecl(); 999 DiagnoseDeclAvailability(TD, Range); 1000 1001 } else if (const auto *TD = dyn_cast<TypedefType>(TyPtr)) { 1002 TypedefNameDecl *D = TD->getDecl(); 1003 DiagnoseDeclAvailability(D, Range); 1004 1005 } else if (const auto *ObjCO = dyn_cast<ObjCObjectType>(TyPtr)) { 1006 if (NamedDecl *D = ObjCO->getInterface()) 1007 DiagnoseDeclAvailability(D, Range); 1008 } 1009 1010 return true; 1011 } 1012 1013 struct ExtractedAvailabilityExpr { 1014 const ObjCAvailabilityCheckExpr *E = nullptr; 1015 bool isNegated = false; 1016 }; 1017 1018 ExtractedAvailabilityExpr extractAvailabilityExpr(const Expr *IfCond) { 1019 const auto *E = IfCond; 1020 bool IsNegated = false; 1021 while (true) { 1022 E = E->IgnoreParens(); 1023 if (const auto *AE = dyn_cast<ObjCAvailabilityCheckExpr>(E)) { 1024 return ExtractedAvailabilityExpr{AE, IsNegated}; 1025 } 1026 1027 const auto *UO = dyn_cast<UnaryOperator>(E); 1028 if (!UO || UO->getOpcode() != UO_LNot) { 1029 return ExtractedAvailabilityExpr{}; 1030 } 1031 E = UO->getSubExpr(); 1032 IsNegated = !IsNegated; 1033 } 1034 } 1035 1036 bool DiagnoseUnguardedAvailability::TraverseIfStmt(IfStmt *If) { 1037 ExtractedAvailabilityExpr IfCond = extractAvailabilityExpr(If->getCond()); 1038 if (!IfCond.E) { 1039 // This isn't an availability checking 'if', we can just continue. 1040 return DynamicRecursiveASTVisitor::TraverseIfStmt(If); 1041 } 1042 1043 VersionTuple CondVersion = IfCond.E->getVersion(); 1044 // If we're using the '*' case here or if this check is redundant, then we 1045 // use the enclosing version to check both branches. 1046 if (CondVersion.empty() || CondVersion <= AvailabilityStack.back()) { 1047 return TraverseStmt(If->getThen()) && TraverseStmt(If->getElse()); 1048 } 1049 1050 auto *Guarded = If->getThen(); 1051 auto *Unguarded = If->getElse(); 1052 if (IfCond.isNegated) { 1053 std::swap(Guarded, Unguarded); 1054 } 1055 1056 AvailabilityStack.push_back(CondVersion); 1057 bool ShouldContinue = TraverseStmt(Guarded); 1058 AvailabilityStack.pop_back(); 1059 1060 return ShouldContinue && TraverseStmt(Unguarded); 1061 } 1062 1063 } // end anonymous namespace 1064 1065 void Sema::DiagnoseUnguardedAvailabilityViolations(Decl *D) { 1066 Stmt *Body = nullptr; 1067 1068 if (auto *FD = D->getAsFunction()) { 1069 Body = FD->getBody(); 1070 1071 if (auto *CD = dyn_cast<CXXConstructorDecl>(FD)) 1072 for (const CXXCtorInitializer *CI : CD->inits()) 1073 DiagnoseUnguardedAvailability(*this, D).IssueDiagnostics(CI->getInit()); 1074 1075 } else if (auto *MD = dyn_cast<ObjCMethodDecl>(D)) 1076 Body = MD->getBody(); 1077 else if (auto *BD = dyn_cast<BlockDecl>(D)) 1078 Body = BD->getBody(); 1079 1080 assert(Body && "Need a body here!"); 1081 1082 DiagnoseUnguardedAvailability(*this, D).IssueDiagnostics(Body); 1083 } 1084 1085 FunctionScopeInfo *Sema::getCurFunctionAvailabilityContext() { 1086 if (FunctionScopes.empty()) 1087 return nullptr; 1088 1089 // Conservatively search the entire current function scope context for 1090 // availability violations. This ensures we always correctly analyze nested 1091 // classes, blocks, lambdas, etc. that may or may not be inside if(@available) 1092 // checks themselves. 1093 return FunctionScopes.front(); 1094 } 1095 1096 void Sema::DiagnoseAvailabilityOfDecl(NamedDecl *D, 1097 ArrayRef<SourceLocation> Locs, 1098 const ObjCInterfaceDecl *UnknownObjCClass, 1099 bool ObjCPropertyAccess, 1100 bool AvoidPartialAvailabilityChecks, 1101 ObjCInterfaceDecl *ClassReceiver) { 1102 std::string Message; 1103 AvailabilityResult Result; 1104 const NamedDecl* OffendingDecl; 1105 // See if this declaration is unavailable, deprecated, or partial. 1106 std::tie(Result, OffendingDecl) = 1107 ShouldDiagnoseAvailabilityOfDecl(*this, D, &Message, ClassReceiver); 1108 if (Result == AR_Available) 1109 return; 1110 1111 if (Result == AR_NotYetIntroduced) { 1112 if (AvoidPartialAvailabilityChecks) 1113 return; 1114 1115 // We need to know the @available context in the current function to 1116 // diagnose this use, let DiagnoseUnguardedAvailabilityViolations do that 1117 // when we're done parsing the current function. 1118 if (FunctionScopeInfo *Context = getCurFunctionAvailabilityContext()) { 1119 Context->HasPotentialAvailabilityViolations = true; 1120 return; 1121 } 1122 } 1123 1124 const ObjCPropertyDecl *ObjCPDecl = nullptr; 1125 if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) { 1126 if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) { 1127 AvailabilityResult PDeclResult = PD->getAvailability(nullptr); 1128 if (PDeclResult == Result) 1129 ObjCPDecl = PD; 1130 } 1131 } 1132 1133 EmitAvailabilityWarning(*this, Result, D, OffendingDecl, Message, Locs, 1134 UnknownObjCClass, ObjCPDecl, ObjCPropertyAccess); 1135 } 1136