SemaAvailability.cpp 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967
  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. #include "clang/AST/Attr.h"
  13. #include "clang/AST/Decl.h"
  14. #include "clang/AST/RecursiveASTVisitor.h"
  15. #include "clang/Basic/DiagnosticSema.h"
  16. #include "clang/Basic/TargetInfo.h"
  17. #include "clang/Lex/Preprocessor.h"
  18. #include "clang/Sema/DelayedDiagnostic.h"
  19. #include "clang/Sema/ScopeInfo.h"
  20. #include "clang/Sema/Sema.h"
  21. #include <optional>
  22. using namespace clang;
  23. using namespace sema;
  24. static const AvailabilityAttr *getAttrForPlatform(ASTContext &Context,
  25. const Decl *D) {
  26. // Check each AvailabilityAttr to find the one for this platform.
  27. for (const auto *A : D->attrs()) {
  28. if (const auto *Avail = dyn_cast<AvailabilityAttr>(A)) {
  29. // FIXME: this is copied from CheckAvailability. We should try to
  30. // de-duplicate.
  31. // Check if this is an App Extension "platform", and if so chop off
  32. // the suffix for matching with the actual platform.
  33. StringRef ActualPlatform = Avail->getPlatform()->getName();
  34. StringRef RealizedPlatform = ActualPlatform;
  35. if (Context.getLangOpts().AppExt) {
  36. size_t suffix = RealizedPlatform.rfind("_app_extension");
  37. if (suffix != StringRef::npos)
  38. RealizedPlatform = RealizedPlatform.slice(0, suffix);
  39. }
  40. StringRef TargetPlatform = Context.getTargetInfo().getPlatformName();
  41. // Match the platform name.
  42. if (RealizedPlatform == TargetPlatform)
  43. return Avail;
  44. }
  45. }
  46. return nullptr;
  47. }
  48. /// The diagnostic we should emit for \c D, and the declaration that
  49. /// originated it, or \c AR_Available.
  50. ///
  51. /// \param D The declaration to check.
  52. /// \param Message If non-null, this will be populated with the message from
  53. /// the availability attribute that is selected.
  54. /// \param ClassReceiver If we're checking the method of a class message
  55. /// send, the class. Otherwise nullptr.
  56. static std::pair<AvailabilityResult, const NamedDecl *>
  57. ShouldDiagnoseAvailabilityOfDecl(Sema &S, const NamedDecl *D,
  58. std::string *Message,
  59. ObjCInterfaceDecl *ClassReceiver) {
  60. AvailabilityResult Result = D->getAvailability(Message);
  61. // For typedefs, if the typedef declaration appears available look
  62. // to the underlying type to see if it is more restrictive.
  63. while (const auto *TD = dyn_cast<TypedefNameDecl>(D)) {
  64. if (Result == AR_Available) {
  65. if (const auto *TT = TD->getUnderlyingType()->getAs<TagType>()) {
  66. D = TT->getDecl();
  67. Result = D->getAvailability(Message);
  68. continue;
  69. }
  70. }
  71. break;
  72. }
  73. // Forward class declarations get their attributes from their definition.
  74. if (const auto *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) {
  75. if (IDecl->getDefinition()) {
  76. D = IDecl->getDefinition();
  77. Result = D->getAvailability(Message);
  78. }
  79. }
  80. if (const auto *ECD = dyn_cast<EnumConstantDecl>(D))
  81. if (Result == AR_Available) {
  82. const DeclContext *DC = ECD->getDeclContext();
  83. if (const auto *TheEnumDecl = dyn_cast<EnumDecl>(DC)) {
  84. Result = TheEnumDecl->getAvailability(Message);
  85. D = TheEnumDecl;
  86. }
  87. }
  88. // For +new, infer availability from -init.
  89. if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
  90. if (S.NSAPIObj && ClassReceiver) {
  91. ObjCMethodDecl *Init = ClassReceiver->lookupInstanceMethod(
  92. S.NSAPIObj->getInitSelector());
  93. if (Init && Result == AR_Available && MD->isClassMethod() &&
  94. MD->getSelector() == S.NSAPIObj->getNewSelector() &&
  95. MD->definedInNSObject(S.getASTContext())) {
  96. Result = Init->getAvailability(Message);
  97. D = Init;
  98. }
  99. }
  100. }
  101. return {Result, D};
  102. }
  103. /// whether we should emit a diagnostic for \c K and \c DeclVersion in
  104. /// the context of \c Ctx. For example, we should emit an unavailable diagnostic
  105. /// in a deprecated context, but not the other way around.
  106. static bool
  107. ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K,
  108. VersionTuple DeclVersion, Decl *Ctx,
  109. const NamedDecl *OffendingDecl) {
  110. assert(K != AR_Available && "Expected an unavailable declaration here!");
  111. // Checks if we should emit the availability diagnostic in the context of C.
  112. auto CheckContext = [&](const Decl *C) {
  113. if (K == AR_NotYetIntroduced) {
  114. if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, C))
  115. if (AA->getIntroduced() >= DeclVersion)
  116. return true;
  117. } else if (K == AR_Deprecated) {
  118. if (C->isDeprecated())
  119. return true;
  120. } else if (K == AR_Unavailable) {
  121. // It is perfectly fine to refer to an 'unavailable' Objective-C method
  122. // when it is referenced from within the @implementation itself. In this
  123. // context, we interpret unavailable as a form of access control.
  124. if (const auto *MD = dyn_cast<ObjCMethodDecl>(OffendingDecl)) {
  125. if (const auto *Impl = dyn_cast<ObjCImplDecl>(C)) {
  126. if (MD->getClassInterface() == Impl->getClassInterface())
  127. return true;
  128. }
  129. }
  130. }
  131. if (C->isUnavailable())
  132. return true;
  133. return false;
  134. };
  135. do {
  136. if (CheckContext(Ctx))
  137. return false;
  138. // An implementation implicitly has the availability of the interface.
  139. // Unless it is "+load" method.
  140. if (const auto *MethodD = dyn_cast<ObjCMethodDecl>(Ctx))
  141. if (MethodD->isClassMethod() &&
  142. MethodD->getSelector().getAsString() == "load")
  143. return true;
  144. if (const auto *CatOrImpl = dyn_cast<ObjCImplDecl>(Ctx)) {
  145. if (const ObjCInterfaceDecl *Interface = CatOrImpl->getClassInterface())
  146. if (CheckContext(Interface))
  147. return false;
  148. }
  149. // A category implicitly has the availability of the interface.
  150. else if (const auto *CatD = dyn_cast<ObjCCategoryDecl>(Ctx))
  151. if (const ObjCInterfaceDecl *Interface = CatD->getClassInterface())
  152. if (CheckContext(Interface))
  153. return false;
  154. } while ((Ctx = cast_or_null<Decl>(Ctx->getDeclContext())));
  155. return true;
  156. }
  157. static bool
  158. shouldDiagnoseAvailabilityByDefault(const ASTContext &Context,
  159. const VersionTuple &DeploymentVersion,
  160. const VersionTuple &DeclVersion) {
  161. const auto &Triple = Context.getTargetInfo().getTriple();
  162. VersionTuple ForceAvailabilityFromVersion;
  163. switch (Triple.getOS()) {
  164. case llvm::Triple::IOS:
  165. case llvm::Triple::TvOS:
  166. ForceAvailabilityFromVersion = VersionTuple(/*Major=*/11);
  167. break;
  168. case llvm::Triple::WatchOS:
  169. ForceAvailabilityFromVersion = VersionTuple(/*Major=*/4);
  170. break;
  171. case llvm::Triple::Darwin:
  172. case llvm::Triple::MacOSX:
  173. ForceAvailabilityFromVersion = VersionTuple(/*Major=*/10, /*Minor=*/13);
  174. break;
  175. case llvm::Triple::ShaderModel:
  176. // Always enable availability diagnostics for shader models.
  177. return true;
  178. default:
  179. // New targets should always warn about availability.
  180. return Triple.getVendor() == llvm::Triple::Apple;
  181. }
  182. return DeploymentVersion >= ForceAvailabilityFromVersion ||
  183. DeclVersion >= ForceAvailabilityFromVersion;
  184. }
  185. static NamedDecl *findEnclosingDeclToAnnotate(Decl *OrigCtx) {
  186. for (Decl *Ctx = OrigCtx; Ctx;
  187. Ctx = cast_or_null<Decl>(Ctx->getDeclContext())) {
  188. if (isa<TagDecl>(Ctx) || isa<FunctionDecl>(Ctx) || isa<ObjCMethodDecl>(Ctx))
  189. return cast<NamedDecl>(Ctx);
  190. if (auto *CD = dyn_cast<ObjCContainerDecl>(Ctx)) {
  191. if (auto *Imp = dyn_cast<ObjCImplDecl>(Ctx))
  192. return Imp->getClassInterface();
  193. return CD;
  194. }
  195. }
  196. return dyn_cast<NamedDecl>(OrigCtx);
  197. }
  198. namespace {
  199. struct AttributeInsertion {
  200. StringRef Prefix;
  201. SourceLocation Loc;
  202. StringRef Suffix;
  203. static AttributeInsertion createInsertionAfter(const NamedDecl *D) {
  204. return {" ", D->getEndLoc(), ""};
  205. }
  206. static AttributeInsertion createInsertionAfter(SourceLocation Loc) {
  207. return {" ", Loc, ""};
  208. }
  209. static AttributeInsertion createInsertionBefore(const NamedDecl *D) {
  210. return {"", D->getBeginLoc(), "\n"};
  211. }
  212. };
  213. } // end anonymous namespace
  214. /// Tries to parse a string as ObjC method name.
  215. ///
  216. /// \param Name The string to parse. Expected to originate from availability
  217. /// attribute argument.
  218. /// \param SlotNames The vector that will be populated with slot names. In case
  219. /// of unsuccessful parsing can contain invalid data.
  220. /// \returns A number of method parameters if parsing was successful,
  221. /// std::nullopt otherwise.
  222. static std::optional<unsigned>
  223. tryParseObjCMethodName(StringRef Name, SmallVectorImpl<StringRef> &SlotNames,
  224. const LangOptions &LangOpts) {
  225. // Accept replacements starting with - or + as valid ObjC method names.
  226. if (!Name.empty() && (Name.front() == '-' || Name.front() == '+'))
  227. Name = Name.drop_front(1);
  228. if (Name.empty())
  229. return std::nullopt;
  230. Name.split(SlotNames, ':');
  231. unsigned NumParams;
  232. if (Name.back() == ':') {
  233. // Remove an empty string at the end that doesn't represent any slot.
  234. SlotNames.pop_back();
  235. NumParams = SlotNames.size();
  236. } else {
  237. if (SlotNames.size() != 1)
  238. // Not a valid method name, just a colon-separated string.
  239. return std::nullopt;
  240. NumParams = 0;
  241. }
  242. // Verify all slot names are valid.
  243. bool AllowDollar = LangOpts.DollarIdents;
  244. for (StringRef S : SlotNames) {
  245. if (S.empty())
  246. continue;
  247. if (!isValidAsciiIdentifier(S, AllowDollar))
  248. return std::nullopt;
  249. }
  250. return NumParams;
  251. }
  252. /// Returns a source location in which it's appropriate to insert a new
  253. /// attribute for the given declaration \D.
  254. static std::optional<AttributeInsertion>
  255. createAttributeInsertion(const NamedDecl *D, const SourceManager &SM,
  256. const LangOptions &LangOpts) {
  257. if (isa<ObjCPropertyDecl>(D))
  258. return AttributeInsertion::createInsertionAfter(D);
  259. if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
  260. if (MD->hasBody())
  261. return std::nullopt;
  262. return AttributeInsertion::createInsertionAfter(D);
  263. }
  264. if (const auto *TD = dyn_cast<TagDecl>(D)) {
  265. SourceLocation Loc =
  266. Lexer::getLocForEndOfToken(TD->getInnerLocStart(), 0, SM, LangOpts);
  267. if (Loc.isInvalid())
  268. return std::nullopt;
  269. // Insert after the 'struct'/whatever keyword.
  270. return AttributeInsertion::createInsertionAfter(Loc);
  271. }
  272. return AttributeInsertion::createInsertionBefore(D);
  273. }
  274. /// Actually emit an availability diagnostic for a reference to an unavailable
  275. /// decl.
  276. ///
  277. /// \param Ctx The context that the reference occurred in
  278. /// \param ReferringDecl The exact declaration that was referenced.
  279. /// \param OffendingDecl A related decl to \c ReferringDecl that has an
  280. /// availability attribute corresponding to \c K attached to it. Note that this
  281. /// may not be the same as ReferringDecl, i.e. if an EnumDecl is annotated and
  282. /// we refer to a member EnumConstantDecl, ReferringDecl is the EnumConstantDecl
  283. /// and OffendingDecl is the EnumDecl.
  284. static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
  285. Decl *Ctx, const NamedDecl *ReferringDecl,
  286. const NamedDecl *OffendingDecl,
  287. StringRef Message,
  288. ArrayRef<SourceLocation> Locs,
  289. const ObjCInterfaceDecl *UnknownObjCClass,
  290. const ObjCPropertyDecl *ObjCProperty,
  291. bool ObjCPropertyAccess) {
  292. // Diagnostics for deprecated or unavailable.
  293. unsigned diag, diag_message, diag_fwdclass_message;
  294. unsigned diag_available_here = diag::note_availability_specified_here;
  295. SourceLocation NoteLocation = OffendingDecl->getLocation();
  296. // Matches 'diag::note_property_attribute' options.
  297. unsigned property_note_select;
  298. // Matches diag::note_availability_specified_here.
  299. unsigned available_here_select_kind;
  300. VersionTuple DeclVersion;
  301. if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, OffendingDecl))
  302. DeclVersion = AA->getIntroduced();
  303. if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, Ctx,
  304. OffendingDecl))
  305. return;
  306. SourceLocation Loc = Locs.front();
  307. // The declaration can have multiple availability attributes, we are looking
  308. // at one of them.
  309. const AvailabilityAttr *A = getAttrForPlatform(S.Context, OffendingDecl);
  310. if (A && A->isInherited()) {
  311. for (const Decl *Redecl = OffendingDecl->getMostRecentDecl(); Redecl;
  312. Redecl = Redecl->getPreviousDecl()) {
  313. const AvailabilityAttr *AForRedecl =
  314. getAttrForPlatform(S.Context, Redecl);
  315. if (AForRedecl && !AForRedecl->isInherited()) {
  316. // If D is a declaration with inherited attributes, the note should
  317. // point to the declaration with actual attributes.
  318. NoteLocation = Redecl->getLocation();
  319. break;
  320. }
  321. }
  322. }
  323. switch (K) {
  324. case AR_NotYetIntroduced: {
  325. // We would like to emit the diagnostic even if -Wunguarded-availability is
  326. // not specified for deployment targets >= to iOS 11 or equivalent or
  327. // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or
  328. // later.
  329. const AvailabilityAttr *AA =
  330. getAttrForPlatform(S.getASTContext(), OffendingDecl);
  331. VersionTuple Introduced = AA->getIntroduced();
  332. bool UseNewWarning = shouldDiagnoseAvailabilityByDefault(
  333. S.Context, S.Context.getTargetInfo().getPlatformMinVersion(),
  334. Introduced);
  335. unsigned Warning = UseNewWarning ? diag::warn_unguarded_availability_new
  336. : diag::warn_unguarded_availability;
  337. std::string PlatformName(AvailabilityAttr::getPrettyPlatformName(
  338. S.getASTContext().getTargetInfo().getPlatformName()));
  339. S.Diag(Loc, Warning) << OffendingDecl << PlatformName
  340. << Introduced.getAsString();
  341. S.Diag(OffendingDecl->getLocation(),
  342. diag::note_partial_availability_specified_here)
  343. << OffendingDecl << PlatformName << Introduced.getAsString()
  344. << S.Context.getTargetInfo().getPlatformMinVersion().getAsString();
  345. if (const auto *Enclosing = findEnclosingDeclToAnnotate(Ctx)) {
  346. if (const auto *TD = dyn_cast<TagDecl>(Enclosing))
  347. if (TD->getDeclName().isEmpty()) {
  348. S.Diag(TD->getLocation(),
  349. diag::note_decl_unguarded_availability_silence)
  350. << /*Anonymous*/ 1 << TD->getKindName();
  351. return;
  352. }
  353. auto FixitNoteDiag =
  354. S.Diag(Enclosing->getLocation(),
  355. diag::note_decl_unguarded_availability_silence)
  356. << /*Named*/ 0 << Enclosing;
  357. // Don't offer a fixit for declarations with availability attributes.
  358. if (Enclosing->hasAttr<AvailabilityAttr>())
  359. return;
  360. if (!S.getPreprocessor().isMacroDefined("API_AVAILABLE"))
  361. return;
  362. std::optional<AttributeInsertion> Insertion = createAttributeInsertion(
  363. Enclosing, S.getSourceManager(), S.getLangOpts());
  364. if (!Insertion)
  365. return;
  366. std::string PlatformName =
  367. AvailabilityAttr::getPlatformNameSourceSpelling(
  368. S.getASTContext().getTargetInfo().getPlatformName())
  369. .lower();
  370. std::string Introduced =
  371. OffendingDecl->getVersionIntroduced().getAsString();
  372. FixitNoteDiag << FixItHint::CreateInsertion(
  373. Insertion->Loc,
  374. (llvm::Twine(Insertion->Prefix) + "API_AVAILABLE(" + PlatformName +
  375. "(" + Introduced + "))" + Insertion->Suffix)
  376. .str());
  377. }
  378. return;
  379. }
  380. case AR_Deprecated:
  381. diag = !ObjCPropertyAccess ? diag::warn_deprecated
  382. : diag::warn_property_method_deprecated;
  383. diag_message = diag::warn_deprecated_message;
  384. diag_fwdclass_message = diag::warn_deprecated_fwdclass_message;
  385. property_note_select = /* deprecated */ 0;
  386. available_here_select_kind = /* deprecated */ 2;
  387. if (const auto *AL = OffendingDecl->getAttr<DeprecatedAttr>())
  388. NoteLocation = AL->getLocation();
  389. break;
  390. case AR_Unavailable:
  391. diag = !ObjCPropertyAccess ? diag::err_unavailable
  392. : diag::err_property_method_unavailable;
  393. diag_message = diag::err_unavailable_message;
  394. diag_fwdclass_message = diag::warn_unavailable_fwdclass_message;
  395. property_note_select = /* unavailable */ 1;
  396. available_here_select_kind = /* unavailable */ 0;
  397. if (auto AL = OffendingDecl->getAttr<UnavailableAttr>()) {
  398. if (AL->isImplicit() && AL->getImplicitReason()) {
  399. // Most of these failures are due to extra restrictions in ARC;
  400. // reflect that in the primary diagnostic when applicable.
  401. auto flagARCError = [&] {
  402. if (S.getLangOpts().ObjCAutoRefCount &&
  403. S.getSourceManager().isInSystemHeader(
  404. OffendingDecl->getLocation()))
  405. diag = diag::err_unavailable_in_arc;
  406. };
  407. switch (AL->getImplicitReason()) {
  408. case UnavailableAttr::IR_None: break;
  409. case UnavailableAttr::IR_ARCForbiddenType:
  410. flagARCError();
  411. diag_available_here = diag::note_arc_forbidden_type;
  412. break;
  413. case UnavailableAttr::IR_ForbiddenWeak:
  414. if (S.getLangOpts().ObjCWeakRuntime)
  415. diag_available_here = diag::note_arc_weak_disabled;
  416. else
  417. diag_available_here = diag::note_arc_weak_no_runtime;
  418. break;
  419. case UnavailableAttr::IR_ARCForbiddenConversion:
  420. flagARCError();
  421. diag_available_here = diag::note_performs_forbidden_arc_conversion;
  422. break;
  423. case UnavailableAttr::IR_ARCInitReturnsUnrelated:
  424. flagARCError();
  425. diag_available_here = diag::note_arc_init_returns_unrelated;
  426. break;
  427. case UnavailableAttr::IR_ARCFieldWithOwnership:
  428. flagARCError();
  429. diag_available_here = diag::note_arc_field_with_ownership;
  430. break;
  431. }
  432. }
  433. }
  434. break;
  435. case AR_Available:
  436. llvm_unreachable("Warning for availability of available declaration?");
  437. }
  438. SmallVector<FixItHint, 12> FixIts;
  439. if (K == AR_Deprecated) {
  440. StringRef Replacement;
  441. if (auto AL = OffendingDecl->getAttr<DeprecatedAttr>())
  442. Replacement = AL->getReplacement();
  443. if (auto AL = getAttrForPlatform(S.Context, OffendingDecl))
  444. Replacement = AL->getReplacement();
  445. CharSourceRange UseRange;
  446. if (!Replacement.empty())
  447. UseRange =
  448. CharSourceRange::getCharRange(Loc, S.getLocForEndOfToken(Loc));
  449. if (UseRange.isValid()) {
  450. if (const auto *MethodDecl = dyn_cast<ObjCMethodDecl>(ReferringDecl)) {
  451. Selector Sel = MethodDecl->getSelector();
  452. SmallVector<StringRef, 12> SelectorSlotNames;
  453. std::optional<unsigned> NumParams = tryParseObjCMethodName(
  454. Replacement, SelectorSlotNames, S.getLangOpts());
  455. if (NumParams && *NumParams == Sel.getNumArgs()) {
  456. assert(SelectorSlotNames.size() == Locs.size());
  457. for (unsigned I = 0; I < Locs.size(); ++I) {
  458. if (!Sel.getNameForSlot(I).empty()) {
  459. CharSourceRange NameRange = CharSourceRange::getCharRange(
  460. Locs[I], S.getLocForEndOfToken(Locs[I]));
  461. FixIts.push_back(FixItHint::CreateReplacement(
  462. NameRange, SelectorSlotNames[I]));
  463. } else
  464. FixIts.push_back(
  465. FixItHint::CreateInsertion(Locs[I], SelectorSlotNames[I]));
  466. }
  467. } else
  468. FixIts.push_back(FixItHint::CreateReplacement(UseRange, Replacement));
  469. } else
  470. FixIts.push_back(FixItHint::CreateReplacement(UseRange, Replacement));
  471. }
  472. }
  473. if (!Message.empty()) {
  474. S.Diag(Loc, diag_message) << ReferringDecl << Message << FixIts;
  475. if (ObjCProperty)
  476. S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
  477. << ObjCProperty->getDeclName() << property_note_select;
  478. } else if (!UnknownObjCClass) {
  479. S.Diag(Loc, diag) << ReferringDecl << FixIts;
  480. if (ObjCProperty)
  481. S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
  482. << ObjCProperty->getDeclName() << property_note_select;
  483. } else {
  484. S.Diag(Loc, diag_fwdclass_message) << ReferringDecl << FixIts;
  485. S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class);
  486. }
  487. S.Diag(NoteLocation, diag_available_here)
  488. << OffendingDecl << available_here_select_kind;
  489. }
  490. void Sema::handleDelayedAvailabilityCheck(DelayedDiagnostic &DD, Decl *Ctx) {
  491. assert(DD.Kind == DelayedDiagnostic::Availability &&
  492. "Expected an availability diagnostic here");
  493. DD.Triggered = true;
  494. DoEmitAvailabilityWarning(
  495. *this, DD.getAvailabilityResult(), Ctx, DD.getAvailabilityReferringDecl(),
  496. DD.getAvailabilityOffendingDecl(), DD.getAvailabilityMessage(),
  497. DD.getAvailabilitySelectorLocs(), DD.getUnknownObjCClass(),
  498. DD.getObjCProperty(), false);
  499. }
  500. static void EmitAvailabilityWarning(Sema &S, AvailabilityResult AR,
  501. const NamedDecl *ReferringDecl,
  502. const NamedDecl *OffendingDecl,
  503. StringRef Message,
  504. ArrayRef<SourceLocation> Locs,
  505. const ObjCInterfaceDecl *UnknownObjCClass,
  506. const ObjCPropertyDecl *ObjCProperty,
  507. bool ObjCPropertyAccess) {
  508. // Delay if we're currently parsing a declaration.
  509. if (S.DelayedDiagnostics.shouldDelayDiagnostics()) {
  510. S.DelayedDiagnostics.add(
  511. DelayedDiagnostic::makeAvailability(
  512. AR, Locs, ReferringDecl, OffendingDecl, UnknownObjCClass,
  513. ObjCProperty, Message, ObjCPropertyAccess));
  514. return;
  515. }
  516. Decl *Ctx = cast<Decl>(S.getCurLexicalContext());
  517. DoEmitAvailabilityWarning(S, AR, Ctx, ReferringDecl, OffendingDecl,
  518. Message, Locs, UnknownObjCClass, ObjCProperty,
  519. ObjCPropertyAccess);
  520. }
  521. namespace {
  522. /// Returns true if the given statement can be a body-like child of \p Parent.
  523. bool isBodyLikeChildStmt(const Stmt *S, const Stmt *Parent) {
  524. switch (Parent->getStmtClass()) {
  525. case Stmt::IfStmtClass:
  526. return cast<IfStmt>(Parent)->getThen() == S ||
  527. cast<IfStmt>(Parent)->getElse() == S;
  528. case Stmt::WhileStmtClass:
  529. return cast<WhileStmt>(Parent)->getBody() == S;
  530. case Stmt::DoStmtClass:
  531. return cast<DoStmt>(Parent)->getBody() == S;
  532. case Stmt::ForStmtClass:
  533. return cast<ForStmt>(Parent)->getBody() == S;
  534. case Stmt::CXXForRangeStmtClass:
  535. return cast<CXXForRangeStmt>(Parent)->getBody() == S;
  536. case Stmt::ObjCForCollectionStmtClass:
  537. return cast<ObjCForCollectionStmt>(Parent)->getBody() == S;
  538. case Stmt::CaseStmtClass:
  539. case Stmt::DefaultStmtClass:
  540. return cast<SwitchCase>(Parent)->getSubStmt() == S;
  541. default:
  542. return false;
  543. }
  544. }
  545. class StmtUSEFinder : public RecursiveASTVisitor<StmtUSEFinder> {
  546. const Stmt *Target;
  547. public:
  548. bool VisitStmt(Stmt *S) { return S != Target; }
  549. /// Returns true if the given statement is present in the given declaration.
  550. static bool isContained(const Stmt *Target, const Decl *D) {
  551. StmtUSEFinder Visitor;
  552. Visitor.Target = Target;
  553. return !Visitor.TraverseDecl(const_cast<Decl *>(D));
  554. }
  555. };
  556. /// Traverses the AST and finds the last statement that used a given
  557. /// declaration.
  558. class LastDeclUSEFinder : public RecursiveASTVisitor<LastDeclUSEFinder> {
  559. const Decl *D;
  560. public:
  561. bool VisitDeclRefExpr(DeclRefExpr *DRE) {
  562. if (DRE->getDecl() == D)
  563. return false;
  564. return true;
  565. }
  566. static const Stmt *findLastStmtThatUsesDecl(const Decl *D,
  567. const CompoundStmt *Scope) {
  568. LastDeclUSEFinder Visitor;
  569. Visitor.D = D;
  570. for (const Stmt *S : llvm::reverse(Scope->body())) {
  571. if (!Visitor.TraverseStmt(const_cast<Stmt *>(S)))
  572. return S;
  573. }
  574. return nullptr;
  575. }
  576. };
  577. /// This class implements -Wunguarded-availability.
  578. ///
  579. /// This is done with a traversal of the AST of a function that makes reference
  580. /// to a partially available declaration. Whenever we encounter an \c if of the
  581. /// form: \c if(@available(...)), we use the version from the condition to visit
  582. /// the then statement.
  583. class DiagnoseUnguardedAvailability
  584. : public RecursiveASTVisitor<DiagnoseUnguardedAvailability> {
  585. typedef RecursiveASTVisitor<DiagnoseUnguardedAvailability> Base;
  586. Sema &SemaRef;
  587. Decl *Ctx;
  588. /// Stack of potentially nested 'if (@available(...))'s.
  589. SmallVector<VersionTuple, 8> AvailabilityStack;
  590. SmallVector<const Stmt *, 16> StmtStack;
  591. void DiagnoseDeclAvailability(NamedDecl *D, SourceRange Range,
  592. ObjCInterfaceDecl *ClassReceiver = nullptr);
  593. public:
  594. DiagnoseUnguardedAvailability(Sema &SemaRef, Decl *Ctx)
  595. : SemaRef(SemaRef), Ctx(Ctx) {
  596. AvailabilityStack.push_back(
  597. SemaRef.Context.getTargetInfo().getPlatformMinVersion());
  598. }
  599. bool TraverseStmt(Stmt *S) {
  600. if (!S)
  601. return true;
  602. StmtStack.push_back(S);
  603. bool Result = Base::TraverseStmt(S);
  604. StmtStack.pop_back();
  605. return Result;
  606. }
  607. void IssueDiagnostics(Stmt *S) { TraverseStmt(S); }
  608. bool TraverseIfStmt(IfStmt *If);
  609. // for 'case X:' statements, don't bother looking at the 'X'; it can't lead
  610. // to any useful diagnostics.
  611. bool TraverseCaseStmt(CaseStmt *CS) { return TraverseStmt(CS->getSubStmt()); }
  612. bool VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *PRE) { return true; }
  613. bool VisitObjCMessageExpr(ObjCMessageExpr *Msg) {
  614. if (ObjCMethodDecl *D = Msg->getMethodDecl()) {
  615. ObjCInterfaceDecl *ID = nullptr;
  616. QualType ReceiverTy = Msg->getClassReceiver();
  617. if (!ReceiverTy.isNull() && ReceiverTy->getAsObjCInterfaceType())
  618. ID = ReceiverTy->getAsObjCInterfaceType()->getInterface();
  619. DiagnoseDeclAvailability(
  620. D, SourceRange(Msg->getSelectorStartLoc(), Msg->getEndLoc()), ID);
  621. }
  622. return true;
  623. }
  624. bool VisitDeclRefExpr(DeclRefExpr *DRE) {
  625. DiagnoseDeclAvailability(DRE->getDecl(),
  626. SourceRange(DRE->getBeginLoc(), DRE->getEndLoc()));
  627. return true;
  628. }
  629. bool VisitMemberExpr(MemberExpr *ME) {
  630. DiagnoseDeclAvailability(ME->getMemberDecl(),
  631. SourceRange(ME->getBeginLoc(), ME->getEndLoc()));
  632. return true;
  633. }
  634. bool VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *E) {
  635. SemaRef.Diag(E->getBeginLoc(), diag::warn_at_available_unchecked_use)
  636. << (!SemaRef.getLangOpts().ObjC);
  637. return true;
  638. }
  639. bool VisitTypeLoc(TypeLoc Ty);
  640. };
  641. void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability(
  642. NamedDecl *D, SourceRange Range, ObjCInterfaceDecl *ReceiverClass) {
  643. AvailabilityResult Result;
  644. const NamedDecl *OffendingDecl;
  645. std::tie(Result, OffendingDecl) =
  646. ShouldDiagnoseAvailabilityOfDecl(SemaRef, D, nullptr, ReceiverClass);
  647. if (Result != AR_Available) {
  648. // All other diagnostic kinds have already been handled in
  649. // DiagnoseAvailabilityOfDecl.
  650. if (Result != AR_NotYetIntroduced)
  651. return;
  652. const AvailabilityAttr *AA =
  653. getAttrForPlatform(SemaRef.getASTContext(), OffendingDecl);
  654. VersionTuple Introduced = AA->getIntroduced();
  655. if (AvailabilityStack.back() >= Introduced)
  656. return;
  657. // If the context of this function is less available than D, we should not
  658. // emit a diagnostic.
  659. if (!ShouldDiagnoseAvailabilityInContext(SemaRef, Result, Introduced, Ctx,
  660. OffendingDecl))
  661. return;
  662. // We would like to emit the diagnostic even if -Wunguarded-availability is
  663. // not specified for deployment targets >= to iOS 11 or equivalent or
  664. // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or
  665. // later.
  666. unsigned DiagKind =
  667. shouldDiagnoseAvailabilityByDefault(
  668. SemaRef.Context,
  669. SemaRef.Context.getTargetInfo().getPlatformMinVersion(), Introduced)
  670. ? diag::warn_unguarded_availability_new
  671. : diag::warn_unguarded_availability;
  672. std::string PlatformName(AvailabilityAttr::getPrettyPlatformName(
  673. SemaRef.getASTContext().getTargetInfo().getPlatformName()));
  674. SemaRef.Diag(Range.getBegin(), DiagKind)
  675. << Range << D << PlatformName << Introduced.getAsString();
  676. SemaRef.Diag(OffendingDecl->getLocation(),
  677. diag::note_partial_availability_specified_here)
  678. << OffendingDecl << PlatformName << Introduced.getAsString()
  679. << SemaRef.Context.getTargetInfo()
  680. .getPlatformMinVersion()
  681. .getAsString();
  682. auto FixitDiag =
  683. SemaRef.Diag(Range.getBegin(), diag::note_unguarded_available_silence)
  684. << Range << D
  685. << (SemaRef.getLangOpts().ObjC ? /*@available*/ 0
  686. : /*__builtin_available*/ 1);
  687. // Find the statement which should be enclosed in the if @available check.
  688. if (StmtStack.empty())
  689. return;
  690. const Stmt *StmtOfUse = StmtStack.back();
  691. const CompoundStmt *Scope = nullptr;
  692. for (const Stmt *S : llvm::reverse(StmtStack)) {
  693. if (const auto *CS = dyn_cast<CompoundStmt>(S)) {
  694. Scope = CS;
  695. break;
  696. }
  697. if (isBodyLikeChildStmt(StmtOfUse, S)) {
  698. // The declaration won't be seen outside of the statement, so we don't
  699. // have to wrap the uses of any declared variables in if (@available).
  700. // Therefore we can avoid setting Scope here.
  701. break;
  702. }
  703. StmtOfUse = S;
  704. }
  705. const Stmt *LastStmtOfUse = nullptr;
  706. if (isa<DeclStmt>(StmtOfUse) && Scope) {
  707. for (const Decl *D : cast<DeclStmt>(StmtOfUse)->decls()) {
  708. if (StmtUSEFinder::isContained(StmtStack.back(), D)) {
  709. LastStmtOfUse = LastDeclUSEFinder::findLastStmtThatUsesDecl(D, Scope);
  710. break;
  711. }
  712. }
  713. }
  714. const SourceManager &SM = SemaRef.getSourceManager();
  715. SourceLocation IfInsertionLoc =
  716. SM.getExpansionLoc(StmtOfUse->getBeginLoc());
  717. SourceLocation StmtEndLoc =
  718. SM.getExpansionRange(
  719. (LastStmtOfUse ? LastStmtOfUse : StmtOfUse)->getEndLoc())
  720. .getEnd();
  721. if (SM.getFileID(IfInsertionLoc) != SM.getFileID(StmtEndLoc))
  722. return;
  723. StringRef Indentation = Lexer::getIndentationForLine(IfInsertionLoc, SM);
  724. const char *ExtraIndentation = " ";
  725. std::string FixItString;
  726. llvm::raw_string_ostream FixItOS(FixItString);
  727. FixItOS << "if (" << (SemaRef.getLangOpts().ObjC ? "@available"
  728. : "__builtin_available")
  729. << "("
  730. << AvailabilityAttr::getPlatformNameSourceSpelling(
  731. SemaRef.getASTContext().getTargetInfo().getPlatformName())
  732. << " " << Introduced.getAsString() << ", *)) {\n"
  733. << Indentation << ExtraIndentation;
  734. FixitDiag << FixItHint::CreateInsertion(IfInsertionLoc, FixItOS.str());
  735. SourceLocation ElseInsertionLoc = Lexer::findLocationAfterToken(
  736. StmtEndLoc, tok::semi, SM, SemaRef.getLangOpts(),
  737. /*SkipTrailingWhitespaceAndNewLine=*/false);
  738. if (ElseInsertionLoc.isInvalid())
  739. ElseInsertionLoc =
  740. Lexer::getLocForEndOfToken(StmtEndLoc, 0, SM, SemaRef.getLangOpts());
  741. FixItOS.str().clear();
  742. FixItOS << "\n"
  743. << Indentation << "} else {\n"
  744. << Indentation << ExtraIndentation
  745. << "// Fallback on earlier versions\n"
  746. << Indentation << "}";
  747. FixitDiag << FixItHint::CreateInsertion(ElseInsertionLoc, FixItOS.str());
  748. }
  749. }
  750. bool DiagnoseUnguardedAvailability::VisitTypeLoc(TypeLoc Ty) {
  751. const Type *TyPtr = Ty.getTypePtr();
  752. SourceRange Range{Ty.getBeginLoc(), Ty.getEndLoc()};
  753. if (Range.isInvalid())
  754. return true;
  755. if (const auto *TT = dyn_cast<TagType>(TyPtr)) {
  756. TagDecl *TD = TT->getDecl();
  757. DiagnoseDeclAvailability(TD, Range);
  758. } else if (const auto *TD = dyn_cast<TypedefType>(TyPtr)) {
  759. TypedefNameDecl *D = TD->getDecl();
  760. DiagnoseDeclAvailability(D, Range);
  761. } else if (const auto *ObjCO = dyn_cast<ObjCObjectType>(TyPtr)) {
  762. if (NamedDecl *D = ObjCO->getInterface())
  763. DiagnoseDeclAvailability(D, Range);
  764. }
  765. return true;
  766. }
  767. bool DiagnoseUnguardedAvailability::TraverseIfStmt(IfStmt *If) {
  768. VersionTuple CondVersion;
  769. if (auto *E = dyn_cast<ObjCAvailabilityCheckExpr>(If->getCond())) {
  770. CondVersion = E->getVersion();
  771. // If we're using the '*' case here or if this check is redundant, then we
  772. // use the enclosing version to check both branches.
  773. if (CondVersion.empty() || CondVersion <= AvailabilityStack.back())
  774. return TraverseStmt(If->getThen()) && TraverseStmt(If->getElse());
  775. } else {
  776. // This isn't an availability checking 'if', we can just continue.
  777. return Base::TraverseIfStmt(If);
  778. }
  779. AvailabilityStack.push_back(CondVersion);
  780. bool ShouldContinue = TraverseStmt(If->getThen());
  781. AvailabilityStack.pop_back();
  782. return ShouldContinue && TraverseStmt(If->getElse());
  783. }
  784. } // end anonymous namespace
  785. void Sema::DiagnoseUnguardedAvailabilityViolations(Decl *D) {
  786. Stmt *Body = nullptr;
  787. if (auto *FD = D->getAsFunction()) {
  788. // FIXME: We only examine the pattern decl for availability violations now,
  789. // but we should also examine instantiated templates.
  790. if (FD->isTemplateInstantiation())
  791. return;
  792. Body = FD->getBody();
  793. if (auto *CD = dyn_cast<CXXConstructorDecl>(FD))
  794. for (const CXXCtorInitializer *CI : CD->inits())
  795. DiagnoseUnguardedAvailability(*this, D).IssueDiagnostics(CI->getInit());
  796. } else if (auto *MD = dyn_cast<ObjCMethodDecl>(D))
  797. Body = MD->getBody();
  798. else if (auto *BD = dyn_cast<BlockDecl>(D))
  799. Body = BD->getBody();
  800. assert(Body && "Need a body here!");
  801. DiagnoseUnguardedAvailability(*this, D).IssueDiagnostics(Body);
  802. }
  803. FunctionScopeInfo *Sema::getCurFunctionAvailabilityContext() {
  804. if (FunctionScopes.empty())
  805. return nullptr;
  806. // Conservatively search the entire current function scope context for
  807. // availability violations. This ensures we always correctly analyze nested
  808. // classes, blocks, lambdas, etc. that may or may not be inside if(@available)
  809. // checks themselves.
  810. return FunctionScopes.front();
  811. }
  812. void Sema::DiagnoseAvailabilityOfDecl(NamedDecl *D,
  813. ArrayRef<SourceLocation> Locs,
  814. const ObjCInterfaceDecl *UnknownObjCClass,
  815. bool ObjCPropertyAccess,
  816. bool AvoidPartialAvailabilityChecks,
  817. ObjCInterfaceDecl *ClassReceiver) {
  818. std::string Message;
  819. AvailabilityResult Result;
  820. const NamedDecl* OffendingDecl;
  821. // See if this declaration is unavailable, deprecated, or partial.
  822. std::tie(Result, OffendingDecl) =
  823. ShouldDiagnoseAvailabilityOfDecl(*this, D, &Message, ClassReceiver);
  824. if (Result == AR_Available)
  825. return;
  826. if (Result == AR_NotYetIntroduced) {
  827. if (AvoidPartialAvailabilityChecks)
  828. return;
  829. // We need to know the @available context in the current function to
  830. // diagnose this use, let DiagnoseUnguardedAvailabilityViolations do that
  831. // when we're done parsing the current function.
  832. if (FunctionScopeInfo *Context = getCurFunctionAvailabilityContext()) {
  833. Context->HasPotentialAvailabilityViolations = true;
  834. return;
  835. }
  836. }
  837. const ObjCPropertyDecl *ObjCPDecl = nullptr;
  838. if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
  839. if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) {
  840. AvailabilityResult PDeclResult = PD->getAvailability(nullptr);
  841. if (PDeclResult == Result)
  842. ObjCPDecl = PD;
  843. }
  844. }
  845. EmitAvailabilityWarning(*this, Result, D, OffendingDecl, Message, Locs,
  846. UnknownObjCClass, ObjCPDecl, ObjCPropertyAccess);
  847. }