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