SemaAvailability.cpp 35 KB

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