brintos

brintos / llvm-project-archived public Read only

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