clang  16.0.0git
SemaAvailability.cpp
Go to the documentation of this file.
1 //===--- SemaAvailability.cpp - Availability attribute handling -----------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file processes the availability attribute.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "clang/AST/Attr.h"
14 #include "clang/AST/Decl.h"
17 #include "clang/Basic/TargetInfo.h"
18 #include "clang/Lex/Preprocessor.h"
20 #include "clang/Sema/ScopeInfo.h"
21 #include "clang/Sema/Sema.h"
22 
23 using namespace clang;
24 using namespace sema;
25 
26 static const AvailabilityAttr *getAttrForPlatform(ASTContext &Context,
27  const Decl *D) {
28  // Check each AvailabilityAttr to find the one for this platform.
29  for (const auto *A : D->attrs()) {
30  if (const auto *Avail = dyn_cast<AvailabilityAttr>(A)) {
31  // FIXME: this is copied from CheckAvailability. We should try to
32  // de-duplicate.
33 
34  // Check if this is an App Extension "platform", and if so chop off
35  // the suffix for matching with the actual platform.
36  StringRef ActualPlatform = Avail->getPlatform()->getName();
37  StringRef RealizedPlatform = ActualPlatform;
38  if (Context.getLangOpts().AppExt) {
39  size_t suffix = RealizedPlatform.rfind("_app_extension");
40  if (suffix != StringRef::npos)
41  RealizedPlatform = RealizedPlatform.slice(0, suffix);
42  }
43 
44  StringRef TargetPlatform = Context.getTargetInfo().getPlatformName();
45 
46  // Match the platform name.
47  if (RealizedPlatform == TargetPlatform)
48  return Avail;
49  }
50  }
51  return nullptr;
52 }
53 
54 /// The diagnostic we should emit for \c D, and the declaration that
55 /// originated it, or \c AR_Available.
56 ///
57 /// \param D The declaration to check.
58 /// \param Message If non-null, this will be populated with the message from
59 /// the availability attribute that is selected.
60 /// \param ClassReceiver If we're checking the method of a class message
61 /// send, the class. Otherwise nullptr.
62 static std::pair<AvailabilityResult, const NamedDecl *>
64  std::string *Message,
65  ObjCInterfaceDecl *ClassReceiver) {
66  AvailabilityResult Result = D->getAvailability(Message);
67 
68  // For typedefs, if the typedef declaration appears available look
69  // to the underlying type to see if it is more restrictive.
70  while (const auto *TD = dyn_cast<TypedefNameDecl>(D)) {
71  if (Result == AR_Available) {
72  if (const auto *TT = TD->getUnderlyingType()->getAs<TagType>()) {
73  D = TT->getDecl();
74  Result = D->getAvailability(Message);
75  continue;
76  }
77  }
78  break;
79  }
80 
81  // Forward class declarations get their attributes from their definition.
82  if (const auto *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) {
83  if (IDecl->getDefinition()) {
84  D = IDecl->getDefinition();
85  Result = D->getAvailability(Message);
86  }
87  }
88 
89  if (const auto *ECD = dyn_cast<EnumConstantDecl>(D))
90  if (Result == AR_Available) {
91  const DeclContext *DC = ECD->getDeclContext();
92  if (const auto *TheEnumDecl = dyn_cast<EnumDecl>(DC)) {
93  Result = TheEnumDecl->getAvailability(Message);
94  D = TheEnumDecl;
95  }
96  }
97 
98  // For +new, infer availability from -init.
99  if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
100  if (S.NSAPIObj && ClassReceiver) {
101  ObjCMethodDecl *Init = ClassReceiver->lookupInstanceMethod(
102  S.NSAPIObj->getInitSelector());
103  if (Init && Result == AR_Available && MD->isClassMethod() &&
104  MD->getSelector() == S.NSAPIObj->getNewSelector() &&
105  MD->definedInNSObject(S.getASTContext())) {
106  Result = Init->getAvailability(Message);
107  D = Init;
108  }
109  }
110  }
111 
112  return {Result, D};
113 }
114 
115 
116 /// whether we should emit a diagnostic for \c K and \c DeclVersion in
117 /// the context of \c Ctx. For example, we should emit an unavailable diagnostic
118 /// in a deprecated context, but not the other way around.
119 static bool
121  VersionTuple DeclVersion, Decl *Ctx,
122  const NamedDecl *OffendingDecl) {
123  assert(K != AR_Available && "Expected an unavailable declaration here!");
124 
125  // Checks if we should emit the availability diagnostic in the context of C.
126  auto CheckContext = [&](const Decl *C) {
127  if (K == AR_NotYetIntroduced) {
128  if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, C))
129  if (AA->getIntroduced() >= DeclVersion)
130  return true;
131  } else if (K == AR_Deprecated) {
132  if (C->isDeprecated())
133  return true;
134  } else if (K == AR_Unavailable) {
135  // It is perfectly fine to refer to an 'unavailable' Objective-C method
136  // when it is referenced from within the @implementation itself. In this
137  // context, we interpret unavailable as a form of access control.
138  if (const auto *MD = dyn_cast<ObjCMethodDecl>(OffendingDecl)) {
139  if (const auto *Impl = dyn_cast<ObjCImplDecl>(C)) {
140  if (MD->getClassInterface() == Impl->getClassInterface())
141  return true;
142  }
143  }
144  }
145 
146  if (C->isUnavailable())
147  return true;
148  return false;
149  };
150 
151  do {
152  if (CheckContext(Ctx))
153  return false;
154 
155  // An implementation implicitly has the availability of the interface.
156  // Unless it is "+load" method.
157  if (const auto *MethodD = dyn_cast<ObjCMethodDecl>(Ctx))
158  if (MethodD->isClassMethod() &&
159  MethodD->getSelector().getAsString() == "load")
160  return true;
161 
162  if (const auto *CatOrImpl = dyn_cast<ObjCImplDecl>(Ctx)) {
163  if (const ObjCInterfaceDecl *Interface = CatOrImpl->getClassInterface())
164  if (CheckContext(Interface))
165  return false;
166  }
167  // A category implicitly has the availability of the interface.
168  else if (const auto *CatD = dyn_cast<ObjCCategoryDecl>(Ctx))
169  if (const ObjCInterfaceDecl *Interface = CatD->getClassInterface())
170  if (CheckContext(Interface))
171  return false;
172  } while ((Ctx = cast_or_null<Decl>(Ctx->getDeclContext())));
173 
174  return true;
175 }
176 
177 static bool
179  const VersionTuple &DeploymentVersion,
180  const VersionTuple &DeclVersion) {
181  const auto &Triple = Context.getTargetInfo().getTriple();
182  VersionTuple ForceAvailabilityFromVersion;
183  switch (Triple.getOS()) {
184  case llvm::Triple::IOS:
185  case llvm::Triple::TvOS:
186  ForceAvailabilityFromVersion = VersionTuple(/*Major=*/11);
187  break;
188  case llvm::Triple::WatchOS:
189  ForceAvailabilityFromVersion = VersionTuple(/*Major=*/4);
190  break;
191  case llvm::Triple::Darwin:
192  case llvm::Triple::MacOSX:
193  ForceAvailabilityFromVersion = VersionTuple(/*Major=*/10, /*Minor=*/13);
194  break;
195  case llvm::Triple::ShaderModel:
196  // Always enable availability diagnostics for shader models.
197  return true;
198  default:
199  // New targets should always warn about availability.
200  return Triple.getVendor() == llvm::Triple::Apple;
201  }
202  return DeploymentVersion >= ForceAvailabilityFromVersion ||
203  DeclVersion >= ForceAvailabilityFromVersion;
204 }
205 
207  for (Decl *Ctx = OrigCtx; Ctx;
208  Ctx = cast_or_null<Decl>(Ctx->getDeclContext())) {
209  if (isa<TagDecl>(Ctx) || isa<FunctionDecl>(Ctx) || isa<ObjCMethodDecl>(Ctx))
210  return cast<NamedDecl>(Ctx);
211  if (auto *CD = dyn_cast<ObjCContainerDecl>(Ctx)) {
212  if (auto *Imp = dyn_cast<ObjCImplDecl>(Ctx))
213  return Imp->getClassInterface();
214  return CD;
215  }
216  }
217 
218  return dyn_cast<NamedDecl>(OrigCtx);
219 }
220 
221 namespace {
222 
223 struct AttributeInsertion {
224  StringRef Prefix;
225  SourceLocation Loc;
226  StringRef Suffix;
227 
228  static AttributeInsertion createInsertionAfter(const NamedDecl *D) {
229  return {" ", D->getEndLoc(), ""};
230  }
231  static AttributeInsertion createInsertionAfter(SourceLocation Loc) {
232  return {" ", Loc, ""};
233  }
234  static AttributeInsertion createInsertionBefore(const NamedDecl *D) {
235  return {"", D->getBeginLoc(), "\n"};
236  }
237 };
238 
239 } // end anonymous namespace
240 
241 /// Tries to parse a string as ObjC method name.
242 ///
243 /// \param Name The string to parse. Expected to originate from availability
244 /// attribute argument.
245 /// \param SlotNames The vector that will be populated with slot names. In case
246 /// of unsuccessful parsing can contain invalid data.
247 /// \returns A number of method parameters if parsing was successful, None
248 /// otherwise.
249 static Optional<unsigned>
251  const LangOptions &LangOpts) {
252  // Accept replacements starting with - or + as valid ObjC method names.
253  if (!Name.empty() && (Name.front() == '-' || Name.front() == '+'))
254  Name = Name.drop_front(1);
255  if (Name.empty())
256  return None;
257  Name.split(SlotNames, ':');
258  unsigned NumParams;
259  if (Name.back() == ':') {
260  // Remove an empty string at the end that doesn't represent any slot.
261  SlotNames.pop_back();
262  NumParams = SlotNames.size();
263  } else {
264  if (SlotNames.size() != 1)
265  // Not a valid method name, just a colon-separated string.
266  return None;
267  NumParams = 0;
268  }
269  // Verify all slot names are valid.
270  bool AllowDollar = LangOpts.DollarIdents;
271  for (StringRef S : SlotNames) {
272  if (S.empty())
273  continue;
274  if (!isValidAsciiIdentifier(S, AllowDollar))
275  return None;
276  }
277  return NumParams;
278 }
279 
280 /// Returns a source location in which it's appropriate to insert a new
281 /// attribute for the given declaration \D.
284  const LangOptions &LangOpts) {
285  if (isa<ObjCPropertyDecl>(D))
286  return AttributeInsertion::createInsertionAfter(D);
287  if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
288  if (MD->hasBody())
289  return None;
290  return AttributeInsertion::createInsertionAfter(D);
291  }
292  if (const auto *TD = dyn_cast<TagDecl>(D)) {
293  SourceLocation Loc =
294  Lexer::getLocForEndOfToken(TD->getInnerLocStart(), 0, SM, LangOpts);
295  if (Loc.isInvalid())
296  return None;
297  // Insert after the 'struct'/whatever keyword.
298  return AttributeInsertion::createInsertionAfter(Loc);
299  }
300  return AttributeInsertion::createInsertionBefore(D);
301 }
302 
303 /// Actually emit an availability diagnostic for a reference to an unavailable
304 /// decl.
305 ///
306 /// \param Ctx The context that the reference occurred in
307 /// \param ReferringDecl The exact declaration that was referenced.
308 /// \param OffendingDecl A related decl to \c ReferringDecl that has an
309 /// availability attribute corresponding to \c K attached to it. Note that this
310 /// may not be the same as ReferringDecl, i.e. if an EnumDecl is annotated and
311 /// we refer to a member EnumConstantDecl, ReferringDecl is the EnumConstantDecl
312 /// and OffendingDecl is the EnumDecl.
314  Decl *Ctx, const NamedDecl *ReferringDecl,
315  const NamedDecl *OffendingDecl,
316  StringRef Message,
318  const ObjCInterfaceDecl *UnknownObjCClass,
319  const ObjCPropertyDecl *ObjCProperty,
320  bool ObjCPropertyAccess) {
321  // Diagnostics for deprecated or unavailable.
322  unsigned diag, diag_message, diag_fwdclass_message;
323  unsigned diag_available_here = diag::note_availability_specified_here;
324  SourceLocation NoteLocation = OffendingDecl->getLocation();
325 
326  // Matches 'diag::note_property_attribute' options.
327  unsigned property_note_select;
328 
329  // Matches diag::note_availability_specified_here.
330  unsigned available_here_select_kind;
331 
332  VersionTuple DeclVersion;
333  if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, OffendingDecl))
334  DeclVersion = AA->getIntroduced();
335 
336  if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, Ctx,
337  OffendingDecl))
338  return;
339 
340  SourceLocation Loc = Locs.front();
341 
342  // The declaration can have multiple availability attributes, we are looking
343  // at one of them.
344  const AvailabilityAttr *A = getAttrForPlatform(S.Context, OffendingDecl);
345  if (A && A->isInherited()) {
346  for (const Decl *Redecl = OffendingDecl->getMostRecentDecl(); Redecl;
347  Redecl = Redecl->getPreviousDecl()) {
348  const AvailabilityAttr *AForRedecl =
349  getAttrForPlatform(S.Context, Redecl);
350  if (AForRedecl && !AForRedecl->isInherited()) {
351  // If D is a declaration with inherited attributes, the note should
352  // point to the declaration with actual attributes.
353  NoteLocation = Redecl->getLocation();
354  break;
355  }
356  }
357  }
358 
359  switch (K) {
360  case AR_NotYetIntroduced: {
361  // We would like to emit the diagnostic even if -Wunguarded-availability is
362  // not specified for deployment targets >= to iOS 11 or equivalent or
363  // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or
364  // later.
365  const AvailabilityAttr *AA =
366  getAttrForPlatform(S.getASTContext(), OffendingDecl);
367  VersionTuple Introduced = AA->getIntroduced();
368 
369  bool UseNewWarning = shouldDiagnoseAvailabilityByDefault(
371  Introduced);
372  unsigned Warning = UseNewWarning ? diag::warn_unguarded_availability_new
373  : diag::warn_unguarded_availability;
374 
375  std::string PlatformName(AvailabilityAttr::getPrettyPlatformName(
377 
378  S.Diag(Loc, Warning) << OffendingDecl << PlatformName
379  << Introduced.getAsString();
380 
381  S.Diag(OffendingDecl->getLocation(),
382  diag::note_partial_availability_specified_here)
383  << OffendingDecl << PlatformName << Introduced.getAsString()
384  << S.Context.getTargetInfo().getPlatformMinVersion().getAsString();
385 
386  if (const auto *Enclosing = findEnclosingDeclToAnnotate(Ctx)) {
387  if (const auto *TD = dyn_cast<TagDecl>(Enclosing))
388  if (TD->getDeclName().isEmpty()) {
389  S.Diag(TD->getLocation(),
390  diag::note_decl_unguarded_availability_silence)
391  << /*Anonymous*/ 1 << TD->getKindName();
392  return;
393  }
394  auto FixitNoteDiag =
395  S.Diag(Enclosing->getLocation(),
396  diag::note_decl_unguarded_availability_silence)
397  << /*Named*/ 0 << Enclosing;
398  // Don't offer a fixit for declarations with availability attributes.
399  if (Enclosing->hasAttr<AvailabilityAttr>())
400  return;
401  if (!S.getPreprocessor().isMacroDefined("API_AVAILABLE"))
402  return;
404  Enclosing, S.getSourceManager(), S.getLangOpts());
405  if (!Insertion)
406  return;
407  std::string PlatformName =
408  AvailabilityAttr::getPlatformNameSourceSpelling(
410  .lower();
411  std::string Introduced =
412  OffendingDecl->getVersionIntroduced().getAsString();
413  FixitNoteDiag << FixItHint::CreateInsertion(
414  Insertion->Loc,
415  (llvm::Twine(Insertion->Prefix) + "API_AVAILABLE(" + PlatformName +
416  "(" + Introduced + "))" + Insertion->Suffix)
417  .str());
418  }
419  return;
420  }
421  case AR_Deprecated:
422  diag = !ObjCPropertyAccess ? diag::warn_deprecated
423  : diag::warn_property_method_deprecated;
424  diag_message = diag::warn_deprecated_message;
425  diag_fwdclass_message = diag::warn_deprecated_fwdclass_message;
426  property_note_select = /* deprecated */ 0;
427  available_here_select_kind = /* deprecated */ 2;
428  if (const auto *AL = OffendingDecl->getAttr<DeprecatedAttr>())
429  NoteLocation = AL->getLocation();
430  break;
431 
432  case AR_Unavailable:
433  diag = !ObjCPropertyAccess ? diag::err_unavailable
434  : diag::err_property_method_unavailable;
435  diag_message = diag::err_unavailable_message;
436  diag_fwdclass_message = diag::warn_unavailable_fwdclass_message;
437  property_note_select = /* unavailable */ 1;
438  available_here_select_kind = /* unavailable */ 0;
439 
440  if (auto AL = OffendingDecl->getAttr<UnavailableAttr>()) {
441  if (AL->isImplicit() && AL->getImplicitReason()) {
442  // Most of these failures are due to extra restrictions in ARC;
443  // reflect that in the primary diagnostic when applicable.
444  auto flagARCError = [&] {
445  if (S.getLangOpts().ObjCAutoRefCount &&
447  OffendingDecl->getLocation()))
448  diag = diag::err_unavailable_in_arc;
449  };
450 
451  switch (AL->getImplicitReason()) {
452  case UnavailableAttr::IR_None: break;
453 
454  case UnavailableAttr::IR_ARCForbiddenType:
455  flagARCError();
456  diag_available_here = diag::note_arc_forbidden_type;
457  break;
458 
459  case UnavailableAttr::IR_ForbiddenWeak:
460  if (S.getLangOpts().ObjCWeakRuntime)
461  diag_available_here = diag::note_arc_weak_disabled;
462  else
463  diag_available_here = diag::note_arc_weak_no_runtime;
464  break;
465 
466  case UnavailableAttr::IR_ARCForbiddenConversion:
467  flagARCError();
468  diag_available_here = diag::note_performs_forbidden_arc_conversion;
469  break;
470 
471  case UnavailableAttr::IR_ARCInitReturnsUnrelated:
472  flagARCError();
473  diag_available_here = diag::note_arc_init_returns_unrelated;
474  break;
475 
476  case UnavailableAttr::IR_ARCFieldWithOwnership:
477  flagARCError();
478  diag_available_here = diag::note_arc_field_with_ownership;
479  break;
480  }
481  }
482  }
483  break;
484 
485  case AR_Available:
486  llvm_unreachable("Warning for availability of available declaration?");
487  }
488 
490  if (K == AR_Deprecated) {
491  StringRef Replacement;
492  if (auto AL = OffendingDecl->getAttr<DeprecatedAttr>())
493  Replacement = AL->getReplacement();
494  if (auto AL = getAttrForPlatform(S.Context, OffendingDecl))
495  Replacement = AL->getReplacement();
496 
497  CharSourceRange UseRange;
498  if (!Replacement.empty())
499  UseRange =
501  if (UseRange.isValid()) {
502  if (const auto *MethodDecl = dyn_cast<ObjCMethodDecl>(ReferringDecl)) {
503  Selector Sel = MethodDecl->getSelector();
504  SmallVector<StringRef, 12> SelectorSlotNames;
506  Replacement, SelectorSlotNames, S.getLangOpts());
507  if (NumParams && *NumParams == Sel.getNumArgs()) {
508  assert(SelectorSlotNames.size() == Locs.size());
509  for (unsigned I = 0; I < Locs.size(); ++I) {
510  if (!Sel.getNameForSlot(I).empty()) {
512  Locs[I], S.getLocForEndOfToken(Locs[I]));
513  FixIts.push_back(FixItHint::CreateReplacement(
514  NameRange, SelectorSlotNames[I]));
515  } else
516  FixIts.push_back(
517  FixItHint::CreateInsertion(Locs[I], SelectorSlotNames[I]));
518  }
519  } else
520  FixIts.push_back(FixItHint::CreateReplacement(UseRange, Replacement));
521  } else
522  FixIts.push_back(FixItHint::CreateReplacement(UseRange, Replacement));
523  }
524  }
525 
526  if (!Message.empty()) {
527  S.Diag(Loc, diag_message) << ReferringDecl << Message << FixIts;
528  if (ObjCProperty)
529  S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
530  << ObjCProperty->getDeclName() << property_note_select;
531  } else if (!UnknownObjCClass) {
532  S.Diag(Loc, diag) << ReferringDecl << FixIts;
533  if (ObjCProperty)
534  S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
535  << ObjCProperty->getDeclName() << property_note_select;
536  } else {
537  S.Diag(Loc, diag_fwdclass_message) << ReferringDecl << FixIts;
538  S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class);
539  }
540 
541  S.Diag(NoteLocation, diag_available_here)
542  << OffendingDecl << available_here_select_kind;
543 }
544 
546  assert(DD.Kind == DelayedDiagnostic::Availability &&
547  "Expected an availability diagnostic here");
548 
549  DD.Triggered = true;
554  DD.getObjCProperty(), false);
555 }
556 
558  const NamedDecl *ReferringDecl,
559  const NamedDecl *OffendingDecl,
560  StringRef Message,
562  const ObjCInterfaceDecl *UnknownObjCClass,
563  const ObjCPropertyDecl *ObjCProperty,
564  bool ObjCPropertyAccess) {
565  // Delay if we're currently parsing a declaration.
569  AR, Locs, ReferringDecl, OffendingDecl, UnknownObjCClass,
570  ObjCProperty, Message, ObjCPropertyAccess));
571  return;
572  }
573 
574  Decl *Ctx = cast<Decl>(S.getCurLexicalContext());
575  DoEmitAvailabilityWarning(S, AR, Ctx, ReferringDecl, OffendingDecl,
576  Message, Locs, UnknownObjCClass, ObjCProperty,
577  ObjCPropertyAccess);
578 }
579 
580 namespace {
581 
582 /// Returns true if the given statement can be a body-like child of \p Parent.
583 bool isBodyLikeChildStmt(const Stmt *S, const Stmt *Parent) {
584  switch (Parent->getStmtClass()) {
585  case Stmt::IfStmtClass:
586  return cast<IfStmt>(Parent)->getThen() == S ||
587  cast<IfStmt>(Parent)->getElse() == S;
588  case Stmt::WhileStmtClass:
589  return cast<WhileStmt>(Parent)->getBody() == S;
590  case Stmt::DoStmtClass:
591  return cast<DoStmt>(Parent)->getBody() == S;
592  case Stmt::ForStmtClass:
593  return cast<ForStmt>(Parent)->getBody() == S;
594  case Stmt::CXXForRangeStmtClass:
595  return cast<CXXForRangeStmt>(Parent)->getBody() == S;
596  case Stmt::ObjCForCollectionStmtClass:
597  return cast<ObjCForCollectionStmt>(Parent)->getBody() == S;
598  case Stmt::CaseStmtClass:
599  case Stmt::DefaultStmtClass:
600  return cast<SwitchCase>(Parent)->getSubStmt() == S;
601  default:
602  return false;
603  }
604 }
605 
606 class StmtUSEFinder : public RecursiveASTVisitor<StmtUSEFinder> {
607  const Stmt *Target;
608 
609 public:
610  bool VisitStmt(Stmt *S) { return S != Target; }
611 
612  /// Returns true if the given statement is present in the given declaration.
613  static bool isContained(const Stmt *Target, const Decl *D) {
614  StmtUSEFinder Visitor;
615  Visitor.Target = Target;
616  return !Visitor.TraverseDecl(const_cast<Decl *>(D));
617  }
618 };
619 
620 /// Traverses the AST and finds the last statement that used a given
621 /// declaration.
622 class LastDeclUSEFinder : public RecursiveASTVisitor<LastDeclUSEFinder> {
623  const Decl *D;
624 
625 public:
626  bool VisitDeclRefExpr(DeclRefExpr *DRE) {
627  if (DRE->getDecl() == D)
628  return false;
629  return true;
630  }
631 
632  static const Stmt *findLastStmtThatUsesDecl(const Decl *D,
633  const CompoundStmt *Scope) {
634  LastDeclUSEFinder Visitor;
635  Visitor.D = D;
636  for (const Stmt *S : llvm::reverse(Scope->body())) {
637  if (!Visitor.TraverseStmt(const_cast<Stmt *>(S)))
638  return S;
639  }
640  return nullptr;
641  }
642 };
643 
644 /// This class implements -Wunguarded-availability.
645 ///
646 /// This is done with a traversal of the AST of a function that makes reference
647 /// to a partially available declaration. Whenever we encounter an \c if of the
648 /// form: \c if(@available(...)), we use the version from the condition to visit
649 /// the then statement.
650 class DiagnoseUnguardedAvailability
651  : public RecursiveASTVisitor<DiagnoseUnguardedAvailability> {
653 
654  Sema &SemaRef;
655  Decl *Ctx;
656 
657  /// Stack of potentially nested 'if (@available(...))'s.
658  SmallVector<VersionTuple, 8> AvailabilityStack;
660 
661  void DiagnoseDeclAvailability(NamedDecl *D, SourceRange Range,
662  ObjCInterfaceDecl *ClassReceiver = nullptr);
663 
664 public:
665  DiagnoseUnguardedAvailability(Sema &SemaRef, Decl *Ctx)
666  : SemaRef(SemaRef), Ctx(Ctx) {
667  AvailabilityStack.push_back(
669  }
670 
671  bool TraverseStmt(Stmt *S) {
672  if (!S)
673  return true;
674  StmtStack.push_back(S);
675  bool Result = Base::TraverseStmt(S);
676  StmtStack.pop_back();
677  return Result;
678  }
679 
680  void IssueDiagnostics(Stmt *S) { TraverseStmt(S); }
681 
682  bool TraverseIfStmt(IfStmt *If);
683 
684  // for 'case X:' statements, don't bother looking at the 'X'; it can't lead
685  // to any useful diagnostics.
686  bool TraverseCaseStmt(CaseStmt *CS) { return TraverseStmt(CS->getSubStmt()); }
687 
688  bool VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *PRE) { return true; }
689 
690  bool VisitObjCMessageExpr(ObjCMessageExpr *Msg) {
691  if (ObjCMethodDecl *D = Msg->getMethodDecl()) {
692  ObjCInterfaceDecl *ID = nullptr;
693  QualType ReceiverTy = Msg->getClassReceiver();
694  if (!ReceiverTy.isNull() && ReceiverTy->getAsObjCInterfaceType())
695  ID = ReceiverTy->getAsObjCInterfaceType()->getInterface();
696 
697  DiagnoseDeclAvailability(
698  D, SourceRange(Msg->getSelectorStartLoc(), Msg->getEndLoc()), ID);
699  }
700  return true;
701  }
702 
703  bool VisitDeclRefExpr(DeclRefExpr *DRE) {
704  DiagnoseDeclAvailability(DRE->getDecl(),
705  SourceRange(DRE->getBeginLoc(), DRE->getEndLoc()));
706  return true;
707  }
708 
709  bool VisitMemberExpr(MemberExpr *ME) {
710  DiagnoseDeclAvailability(ME->getMemberDecl(),
711  SourceRange(ME->getBeginLoc(), ME->getEndLoc()));
712  return true;
713  }
714 
715  bool VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *E) {
716  SemaRef.Diag(E->getBeginLoc(), diag::warn_at_available_unchecked_use)
717  << (!SemaRef.getLangOpts().ObjC);
718  return true;
719  }
720 
721  bool VisitTypeLoc(TypeLoc Ty);
722 };
723 
724 void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability(
725  NamedDecl *D, SourceRange Range, ObjCInterfaceDecl *ReceiverClass) {
726  AvailabilityResult Result;
727  const NamedDecl *OffendingDecl;
728  std::tie(Result, OffendingDecl) =
729  ShouldDiagnoseAvailabilityOfDecl(SemaRef, D, nullptr, ReceiverClass);
730  if (Result != AR_Available) {
731  // All other diagnostic kinds have already been handled in
732  // DiagnoseAvailabilityOfDecl.
733  if (Result != AR_NotYetIntroduced)
734  return;
735 
736  const AvailabilityAttr *AA =
737  getAttrForPlatform(SemaRef.getASTContext(), OffendingDecl);
738  VersionTuple Introduced = AA->getIntroduced();
739 
740  if (AvailabilityStack.back() >= Introduced)
741  return;
742 
743  // If the context of this function is less available than D, we should not
744  // emit a diagnostic.
745  if (!ShouldDiagnoseAvailabilityInContext(SemaRef, Result, Introduced, Ctx,
746  OffendingDecl))
747  return;
748 
749  // We would like to emit the diagnostic even if -Wunguarded-availability is
750  // not specified for deployment targets >= to iOS 11 or equivalent or
751  // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or
752  // later.
753  unsigned DiagKind =
755  SemaRef.Context,
756  SemaRef.Context.getTargetInfo().getPlatformMinVersion(), Introduced)
757  ? diag::warn_unguarded_availability_new
758  : diag::warn_unguarded_availability;
759 
760  std::string PlatformName(AvailabilityAttr::getPrettyPlatformName(
762 
763  SemaRef.Diag(Range.getBegin(), DiagKind)
764  << Range << D << PlatformName << Introduced.getAsString();
765 
766  SemaRef.Diag(OffendingDecl->getLocation(),
767  diag::note_partial_availability_specified_here)
768  << OffendingDecl << PlatformName << Introduced.getAsString()
769  << SemaRef.Context.getTargetInfo()
771  .getAsString();
772 
773  auto FixitDiag =
774  SemaRef.Diag(Range.getBegin(), diag::note_unguarded_available_silence)
775  << Range << D
776  << (SemaRef.getLangOpts().ObjC ? /*@available*/ 0
777  : /*__builtin_available*/ 1);
778 
779  // Find the statement which should be enclosed in the if @available check.
780  if (StmtStack.empty())
781  return;
782  const Stmt *StmtOfUse = StmtStack.back();
783  const CompoundStmt *Scope = nullptr;
784  for (const Stmt *S : llvm::reverse(StmtStack)) {
785  if (const auto *CS = dyn_cast<CompoundStmt>(S)) {
786  Scope = CS;
787  break;
788  }
789  if (isBodyLikeChildStmt(StmtOfUse, S)) {
790  // The declaration won't be seen outside of the statement, so we don't
791  // have to wrap the uses of any declared variables in if (@available).
792  // Therefore we can avoid setting Scope here.
793  break;
794  }
795  StmtOfUse = S;
796  }
797  const Stmt *LastStmtOfUse = nullptr;
798  if (isa<DeclStmt>(StmtOfUse) && Scope) {
799  for (const Decl *D : cast<DeclStmt>(StmtOfUse)->decls()) {
800  if (StmtUSEFinder::isContained(StmtStack.back(), D)) {
801  LastStmtOfUse = LastDeclUSEFinder::findLastStmtThatUsesDecl(D, Scope);
802  break;
803  }
804  }
805  }
806 
807  const SourceManager &SM = SemaRef.getSourceManager();
808  SourceLocation IfInsertionLoc =
809  SM.getExpansionLoc(StmtOfUse->getBeginLoc());
810  SourceLocation StmtEndLoc =
811  SM.getExpansionRange(
812  (LastStmtOfUse ? LastStmtOfUse : StmtOfUse)->getEndLoc())
813  .getEnd();
814  if (SM.getFileID(IfInsertionLoc) != SM.getFileID(StmtEndLoc))
815  return;
816 
817  StringRef Indentation = Lexer::getIndentationForLine(IfInsertionLoc, SM);
818  const char *ExtraIndentation = " ";
819  std::string FixItString;
820  llvm::raw_string_ostream FixItOS(FixItString);
821  FixItOS << "if (" << (SemaRef.getLangOpts().ObjC ? "@available"
822  : "__builtin_available")
823  << "("
824  << AvailabilityAttr::getPlatformNameSourceSpelling(
826  << " " << Introduced.getAsString() << ", *)) {\n"
827  << Indentation << ExtraIndentation;
828  FixitDiag << FixItHint::CreateInsertion(IfInsertionLoc, FixItOS.str());
830  StmtEndLoc, tok::semi, SM, SemaRef.getLangOpts(),
831  /*SkipTrailingWhitespaceAndNewLine=*/false);
832  if (ElseInsertionLoc.isInvalid())
833  ElseInsertionLoc =
834  Lexer::getLocForEndOfToken(StmtEndLoc, 0, SM, SemaRef.getLangOpts());
835  FixItOS.str().clear();
836  FixItOS << "\n"
837  << Indentation << "} else {\n"
838  << Indentation << ExtraIndentation
839  << "// Fallback on earlier versions\n"
840  << Indentation << "}";
841  FixitDiag << FixItHint::CreateInsertion(ElseInsertionLoc, FixItOS.str());
842  }
843 }
844 
845 bool DiagnoseUnguardedAvailability::VisitTypeLoc(TypeLoc Ty) {
846  const Type *TyPtr = Ty.getTypePtr();
848 
849  if (Range.isInvalid())
850  return true;
851 
852  if (const auto *TT = dyn_cast<TagType>(TyPtr)) {
853  TagDecl *TD = TT->getDecl();
854  DiagnoseDeclAvailability(TD, Range);
855 
856  } else if (const auto *TD = dyn_cast<TypedefType>(TyPtr)) {
857  TypedefNameDecl *D = TD->getDecl();
858  DiagnoseDeclAvailability(D, Range);
859 
860  } else if (const auto *ObjCO = dyn_cast<ObjCObjectType>(TyPtr)) {
861  if (NamedDecl *D = ObjCO->getInterface())
862  DiagnoseDeclAvailability(D, Range);
863  }
864 
865  return true;
866 }
867 
868 bool DiagnoseUnguardedAvailability::TraverseIfStmt(IfStmt *If) {
869  VersionTuple CondVersion;
870  if (auto *E = dyn_cast<ObjCAvailabilityCheckExpr>(If->getCond())) {
871  CondVersion = E->getVersion();
872 
873  // If we're using the '*' case here or if this check is redundant, then we
874  // use the enclosing version to check both branches.
875  if (CondVersion.empty() || CondVersion <= AvailabilityStack.back())
876  return TraverseStmt(If->getThen()) && TraverseStmt(If->getElse());
877  } else {
878  // This isn't an availability checking 'if', we can just continue.
879  return Base::TraverseIfStmt(If);
880  }
881 
882  AvailabilityStack.push_back(CondVersion);
883  bool ShouldContinue = TraverseStmt(If->getThen());
884  AvailabilityStack.pop_back();
885 
886  return ShouldContinue && TraverseStmt(If->getElse());
887 }
888 
889 } // end anonymous namespace
890 
892  Stmt *Body = nullptr;
893 
894  if (auto *FD = D->getAsFunction()) {
895  // FIXME: We only examine the pattern decl for availability violations now,
896  // but we should also examine instantiated templates.
897  if (FD->isTemplateInstantiation())
898  return;
899 
900  Body = FD->getBody();
901  } else if (auto *MD = dyn_cast<ObjCMethodDecl>(D))
902  Body = MD->getBody();
903  else if (auto *BD = dyn_cast<BlockDecl>(D))
904  Body = BD->getBody();
905 
906  assert(Body && "Need a body here!");
907 
908  DiagnoseUnguardedAvailability(*this, D).IssueDiagnostics(Body);
909 }
910 
912  if (FunctionScopes.empty())
913  return nullptr;
914 
915  // Conservatively search the entire current function scope context for
916  // availability violations. This ensures we always correctly analyze nested
917  // classes, blocks, lambdas, etc. that may or may not be inside if(@available)
918  // checks themselves.
919  return FunctionScopes.front();
920 }
921 
924  const ObjCInterfaceDecl *UnknownObjCClass,
925  bool ObjCPropertyAccess,
926  bool AvoidPartialAvailabilityChecks,
927  ObjCInterfaceDecl *ClassReceiver) {
928  std::string Message;
929  AvailabilityResult Result;
930  const NamedDecl* OffendingDecl;
931  // See if this declaration is unavailable, deprecated, or partial.
932  std::tie(Result, OffendingDecl) =
933  ShouldDiagnoseAvailabilityOfDecl(*this, D, &Message, ClassReceiver);
934  if (Result == AR_Available)
935  return;
936 
937  if (Result == AR_NotYetIntroduced) {
938  if (AvoidPartialAvailabilityChecks)
939  return;
940 
941  // We need to know the @available context in the current function to
942  // diagnose this use, let DiagnoseUnguardedAvailabilityViolations do that
943  // when we're done parsing the current function.
944  if (FunctionScopeInfo *Context = getCurFunctionAvailabilityContext()) {
945  Context->HasPotentialAvailabilityViolations = true;
946  return;
947  }
948  }
949 
950  const ObjCPropertyDecl *ObjCPDecl = nullptr;
951  if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
952  if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) {
953  AvailabilityResult PDeclResult = PD->getAvailability(nullptr);
954  if (PDeclResult == Result)
955  ObjCPDecl = PD;
956  }
957  }
958 
959  EmitAvailabilityWarning(*this, Result, D, OffendingDecl, Message, Locs,
960  UnknownObjCClass, ObjCPDecl, ObjCPropertyAccess);
961 }
clang::ObjCInterfaceDecl
Represents an ObjC class declaration.
Definition: DeclObjC.h:1149
clang::CaseStmt
CaseStmt - Represent a case statement.
Definition: Stmt.h:1603
clang::sema::DelayedDiagnostic::getObjCProperty
const ObjCPropertyDecl * getObjCProperty() const
Definition: DelayedDiagnostic.h:225
clang::Decl::getBeginLoc
SourceLocation getBeginLoc() const LLVM_READONLY
Definition: DeclBase.h:424
clang::sema::DelayedDiagnostic::getAvailabilityReferringDecl
const NamedDecl * getAvailabilityReferringDecl() const
Definition: DelayedDiagnostic.h:177
clang::Decl::getEndLoc
SourceLocation getEndLoc() const LLVM_READONLY
Definition: DeclBase.h:428
clang::SourceRange
A trivial tuple used to represent a source range.
Definition: SourceLocation.h:210
string
string(SUBSTRING ${CMAKE_CURRENT_BINARY_DIR} 0 ${PATH_LIB_START} PATH_HEAD) string(SUBSTRING $
Definition: CMakeLists.txt:22
clang::DeclContext
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition: DeclBase.h:1389
clang::FixItHint::CreateInsertion
static FixItHint CreateInsertion(SourceLocation InsertionLoc, StringRef Code, bool BeforePreviousInsertions=false)
Create a code modification hint that inserts the given code string at a specific location.
Definition: Diagnostic.h:97
clang::Sema::getASTContext
ASTContext & getASTContext() const
Definition: Sema.h:1637
clang::Decl::getAsFunction
FunctionDecl * getAsFunction() LLVM_READONLY
Returns the function itself, or the templated function if this is a function template.
Definition: DeclBase.cpp:227
clang::Sema::handleDelayedAvailabilityCheck
void handleDelayedAvailabilityCheck(sema::DelayedDiagnostic &DD, Decl *Ctx)
Definition: SemaAvailability.cpp:545
llvm::SmallVector
Definition: LLVM.h:38
clang::AR_Deprecated
@ AR_Deprecated
Definition: DeclBase.h:72
clang::SourceLocation
Encodes a location in the source.
Definition: SourceLocation.h:86
clang::NamedDecl
This represents a decl that may have a name.
Definition: Decl.h:247
TargetInfo.h
clang::MultiVersionKind::Target
@ Target
clang::QualType
A (possibly-)qualified type.
Definition: Type.h:737
Attr.h
clang::ObjCAvailabilityCheckExpr::getBeginLoc
SourceLocation getBeginLoc() const
Definition: ExprObjC.h:1703
clang::Sema::Diag
SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID, bool DeferHint=false)
Emit a diagnostic.
Definition: Sema.cpp:1881
clang::IfStmt
IfStmt - This represents an if/then/else.
Definition: Stmt.h:1940
clang::Sema::getSourceManager
SourceManager & getSourceManager() const
Definition: Sema.h:1635
llvm::Optional< unsigned >
clang::TypeLoc::getEndLoc
SourceLocation getEndLoc() const
Get the end source location.
Definition: TypeLoc.cpp:234
clang::TagType
Definition: Type.h:4792
clang::Decl::getAttr
T * getAttr() const
Definition: DeclBase.h:556
clang::ObjCObjectType::getInterface
ObjCInterfaceDecl * getInterface() const
Gets the interface declaration for this object type, if the base type really is an interface.
Definition: Type.h:6249
clang::TypeLoc::getTypePtr
const Type * getTypePtr() const
Definition: TypeLoc.h:136
clang::sema::DelayedDiagnostic
A diagnostic message which has been conditionally emitted pending the complete parsing of the current...
Definition: DelayedDiagnostic.h:124
clang::SourceManager
This class handles loading and caching of source files into memory.
Definition: SourceManager.h:636
clang::Sema::Context
ASTContext & Context
Definition: Sema.h:409
clang::Type
The base class of the type hierarchy.
Definition: Type.h:1565
Preprocessor.h
clang::Decl::getAvailability
AvailabilityResult getAvailability(std::string *Message=nullptr, VersionTuple EnclosingVersion=VersionTuple(), StringRef *RealizedPlatform=nullptr) const
Determine the availability of the given declaration.
Definition: DeclBase.cpp:636
Decl.h
clang::TypeLoc::getBeginLoc
SourceLocation getBeginLoc() const
Get the begin source location.
Definition: TypeLoc.cpp:191
clang::ObjCPropertyRefExpr
ObjCPropertyRefExpr - A dot-syntax expression to access an ObjC property.
Definition: ExprObjC.h:614
clang::Sema::getLangOpts
const LangOptions & getLangOpts() const
Definition: Sema.h:1630
clang::Sema::getCurLexicalContext
DeclContext * getCurLexicalContext() const
Definition: Sema.h:13645
clang::CharSourceRange::getCharRange
static CharSourceRange getCharRange(SourceRange R)
Definition: SourceLocation.h:265
tryParseObjCMethodName
static Optional< unsigned > tryParseObjCMethodName(StringRef Name, SmallVectorImpl< StringRef > &SlotNames, const LangOptions &LangOpts)
Tries to parse a string as ObjC method name.
Definition: SemaAvailability.cpp:250
clang::sema::DelayedDiagnostic::Kind
DDKind Kind
Definition: DelayedDiagnostic.h:128
clang::ObjCInterfaceDecl::lookupInstanceMethod
ObjCMethodDecl * lookupInstanceMethod(Selector Sel) const
Lookup an instance method for a given selector.
Definition: DeclObjC.h:1823
clang::isValidAsciiIdentifier
LLVM_READONLY bool isValidAsciiIdentifier(StringRef S, bool AllowDollar=false)
Return true if this is a valid ASCII identifier.
Definition: CharInfo.h:228
clang::CompoundStmt
CompoundStmt - This represents a group of statements like { stmt stmt }.
Definition: Stmt.h:1410
clang::AR_Available
@ AR_Available
Definition: DeclBase.h:70
clang::Selector::getNameForSlot
StringRef getNameForSlot(unsigned argIndex) const
Retrieve the name at a given position in the selector.
Definition: IdentifierTable.cpp:585
clang::Scope
Scope - A scope is a transient data structure that is used while parsing the program.
Definition: Scope.h:40
clang::DeclRefExpr::getEndLoc
SourceLocation getEndLoc() const LLVM_READONLY
Definition: Expr.cpp:603
clang::ObjCMessageExpr::getSelectorStartLoc
SourceLocation getSelectorStartLoc() const
Definition: ExprObjC.h:1409
clang::ASTContext
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:209
ShouldDiagnoseAvailabilityOfDecl
static std::pair< AvailabilityResult, const NamedDecl * > ShouldDiagnoseAvailabilityOfDecl(Sema &S, const NamedDecl *D, std::string *Message, ObjCInterfaceDecl *ClassReceiver)
The diagnostic we should emit for D, and the declaration that originated it, or AR_Available.
Definition: SemaAvailability.cpp:63
clang::RecursiveASTVisitor
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
Definition: RecursiveASTVisitor.h:152
clang::Selector::getNumArgs
unsigned getNumArgs() const
Definition: IdentifierTable.cpp:563
clang::ObjCAvailabilityCheckExpr
A runtime availability query.
Definition: ExprObjC.h:1686
clang::TargetInfo::getPlatformMinVersion
VersionTuple getPlatformMinVersion() const
Retrieve the minimum desired version of the platform, to which the program should be compiled.
Definition: TargetInfo.h:1521
DelayedDiagnostic.h
clang::Preprocessor::isMacroDefined
bool isMacroDefined(StringRef Id)
Definition: Preprocessor.h:1193
clang::DeclRefExpr::getDecl
ValueDecl * getDecl()
Definition: Expr.h:1304
clang::Lexer::getIndentationForLine
static StringRef getIndentationForLine(SourceLocation Loc, const SourceManager &SM)
Returns the leading whitespace for line that corresponds to the given location Loc.
Definition: Lexer.cpp:1093
clang::ObjCAvailabilityCheckExpr::getVersion
VersionTuple getVersion() const
Definition: ExprObjC.h:1709
clang::TagDecl
Represents the declaration of a struct/union/class/enum.
Definition: Decl.h:3423
clang::Sema::getLocForEndOfToken
SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset=0)
Calls Lexer::getLocForEndOfToken()
Definition: Sema.cpp:56
clang::sema::DelayedDiagnostic::Availability
@ Availability
Definition: DelayedDiagnostic.h:126
clang::IfStmt::getElse
Stmt * getElse()
Definition: Stmt.h:2040
Base
clang::Sema::DiagnoseAvailabilityOfDecl
void DiagnoseAvailabilityOfDecl(NamedDecl *D, ArrayRef< SourceLocation > Locs, const ObjCInterfaceDecl *UnknownObjCClass, bool ObjCPropertyAccess, bool AvoidPartialAvailabilityChecks=false, ObjCInterfaceDecl *ClassReceiver=nullptr)
Definition: SemaAvailability.cpp:922
clang::Sema::DelayedDiagnostics::shouldDelayDiagnostics
bool shouldDelayDiagnostics()
Determines whether diagnostics should be delayed.
Definition: Sema.h:954
clang::ObjCMessageExpr
An expression that sends a message to the given Objective-C object or class.
Definition: ExprObjC.h:940
clang::Type::getAsObjCInterfaceType
const ObjCObjectType * getAsObjCInterfaceType() const
Definition: Type.cpp:1729
Sema.h
clang::MemberExpr::getMemberDecl
ValueDecl * getMemberDecl() const
Retrieve the member declaration to which this expression refers.
Definition: Expr.h:3252
clang::DeclRefExpr::getBeginLoc
SourceLocation getBeginLoc() const LLVM_READONLY
Definition: Expr.cpp:598
clang::NamedDecl::getMostRecentDecl
NamedDecl * getMostRecentDecl()
Definition: Decl.h:473
DiagnosticSema.h
clang::sema::FunctionScopeInfo
Retains information about a function, method, or block that is currently being parsed.
Definition: ScopeInfo.h:102
clang::transformer::EditKind::Range
@ Range
clang::TargetInfo::getTriple
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
Definition: TargetInfo.h:1195
clang::MemberExpr::getBeginLoc
SourceLocation getBeginLoc() const LLVM_READONLY
Definition: Expr.cpp:1792
clang::Sema::DiagnoseUnguardedAvailabilityViolations
void DiagnoseUnguardedAvailabilityViolations(Decl *FD)
Issue any -Wunguarded-availability warnings in FD.
Definition: SemaAvailability.cpp:891
clang::Decl::getPreviousDecl
Decl * getPreviousDecl()
Retrieve the previous declaration that declares the same entity as this declaration,...
Definition: DeclBase.h:1026
findEnclosingDeclToAnnotate
static NamedDecl * findEnclosingDeclToAnnotate(Decl *OrigCtx)
Definition: SemaAvailability.cpp:206
shouldDiagnoseAvailabilityByDefault
static bool shouldDiagnoseAvailabilityByDefault(const ASTContext &Context, const VersionTuple &DeploymentVersion, const VersionTuple &DeclVersion)
Definition: SemaAvailability.cpp:178
clang::sema::DelayedDiagnostic::getAvailabilityOffendingDecl
const NamedDecl * getAvailabilityOffendingDecl() const
Definition: DelayedDiagnostic.h:182
clang::QualType::isNull
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition: Type.h:802
llvm::ArrayRef
Definition: LLVM.h:34
clang::sema::DelayedDiagnostic::getUnknownObjCClass
const ObjCInterfaceDecl * getUnknownObjCClass() const
Definition: DelayedDiagnostic.h:221
clang::Decl
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:83
clang::TypeLoc
Base wrapper for a particular "section" of type source info.
Definition: TypeLoc.h:58
clang::ObjCPropertyDecl
Represents one property declaration in an Objective-C interface.
Definition: DeclObjC.h:732
clang::CharSourceRange
Represents a character-granular source range.
Definition: SourceLocation.h:253
clang::Sema
Sema - This implements semantic analysis and AST building for C.
Definition: Sema.h:358
clang::MemberExpr::getEndLoc
SourceLocation getEndLoc() const LLVM_READONLY
Definition: Expr.cpp:1806
clang::Decl::attrs
attr_range attrs() const
Definition: DeclBase.h:519
clang::Sema::getCurFunctionAvailabilityContext
sema::FunctionScopeInfo * getCurFunctionAvailabilityContext()
Retrieve the current function, if any, that should be analyzed for potential availability violations.
Definition: SemaAvailability.cpp:911
clang::ASTContext::getTargetInfo
const TargetInfo & getTargetInfo() const
Definition: ASTContext.h:773
getAttrForPlatform
static const AvailabilityAttr * getAttrForPlatform(ASTContext &Context, const Decl *D)
Definition: SemaAvailability.cpp:26
clang::LangOptions
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:81
clang::IfStmt::getCond
Expr * getCond()
Definition: Stmt.h:2019
clang::Sema::getPreprocessor
Preprocessor & getPreprocessor() const
Definition: Sema.h:1636
clang::sema::DelayedDiagnostic::getAvailabilitySelectorLocs
ArrayRef< SourceLocation > getAvailabilitySelectorLocs() const
Definition: DelayedDiagnostic.h:191
clang::ObjCMethodDecl
ObjCMethodDecl - Represents an instance or class method declaration.
Definition: DeclObjC.h:139
ScopeInfo.h
clang::AR_NotYetIntroduced
@ AR_NotYetIntroduced
Definition: DeclBase.h:71
clang::CharSourceRange::isValid
bool isValid() const
Definition: SourceLocation.h:291
clang::Builtin::ID
ID
Definition: Builtins.h:52
clang::SourceLocation::isInvalid
bool isInvalid() const
Definition: SourceLocation.h:111
clang::AR_Unavailable
@ AR_Unavailable
Definition: DeclBase.h:73
clang
Definition: CalledOnceCheck.h:17
clang::ObjCMessageExpr::getEndLoc
SourceLocation getEndLoc() const LLVM_READONLY
Definition: ExprObjC.h:1443
clang::Selector
Smart pointer class that efficiently represents Objective-C method names.
Definition: IdentifierTable.h:759
RecursiveASTVisitor.h
clang::Stmt
Stmt - This represents one statement.
Definition: Stmt.h:71
clang::AvailabilityResult
AvailabilityResult
Captures the result of checking the availability of a declaration.
Definition: DeclBase.h:69
clang::sema::DelayedDiagnostic::getAvailabilityMessage
StringRef getAvailabilityMessage() const
Definition: DelayedDiagnostic.h:186
clang::SourceManager::isInSystemHeader
bool isInSystemHeader(SourceLocation Loc) const
Returns if a SourceLocation is in a system header.
Definition: SourceManager.h:1504
clang::sema::DelayedDiagnostic::getAvailabilityResult
AvailabilityResult getAvailabilityResult() const
Definition: DelayedDiagnostic.h:197
clang::NamedDecl::getDeclName
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
Definition: Decl.h:313
clang::TargetInfo::getPlatformName
StringRef getPlatformName() const
Retrieve the name of the platform as it is used in the availability attribute.
Definition: TargetInfo.h:1517
clang::ObjCMessageExpr::getMethodDecl
const ObjCMethodDecl * getMethodDecl() const
Definition: ExprObjC.h:1346
clang::Stmt::getBeginLoc
SourceLocation getBeginLoc() const LLVM_READONLY
Definition: Stmt.cpp:336
clang::IfStmt::getThen
Stmt * getThen()
Definition: Stmt.h:2031
clang::TypedefNameDecl
Base class for declarations which introduce a typedef-name.
Definition: Decl.h:3275
clang::CaseStmt::getSubStmt
Stmt * getSubStmt()
Definition: Stmt.h:1722
ShouldDiagnoseAvailabilityInContext
static bool ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K, VersionTuple DeclVersion, Decl *Ctx, const NamedDecl *OffendingDecl)
whether we should emit a diagnostic for K and DeclVersion in the context of Ctx.
Definition: SemaAvailability.cpp:120
clang::MemberExpr
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition: Expr.h:3169
DoEmitAvailabilityWarning
static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, Decl *Ctx, const NamedDecl *ReferringDecl, const NamedDecl *OffendingDecl, StringRef Message, ArrayRef< SourceLocation > Locs, const ObjCInterfaceDecl *UnknownObjCClass, const ObjCPropertyDecl *ObjCProperty, bool ObjCPropertyAccess)
Actually emit an availability diagnostic for a reference to an unavailable decl.
Definition: SemaAvailability.cpp:313
Parent
NodeId Parent
Definition: ASTDiff.cpp:190
clang::Lexer::getLocForEndOfToken
static SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset, const SourceManager &SM, const LangOptions &LangOpts)
Computes the source location just past the end of the token at this source location.
Definition: Lexer.cpp:787
clang::sema::DelayedDiagnostic::makeAvailability
static DelayedDiagnostic makeAvailability(AvailabilityResult AR, ArrayRef< SourceLocation > Locs, const NamedDecl *ReferringDecl, const NamedDecl *OffendingDecl, const ObjCInterfaceDecl *UnknownObjCClass, const ObjCPropertyDecl *ObjCProperty, StringRef Msg, bool ObjCPropertyAccess)
Definition: DelayedDiagnostic.cpp:24
createAttributeInsertion
static Optional< AttributeInsertion > createAttributeInsertion(const NamedDecl *D, const SourceManager &SM, const LangOptions &LangOpts)
Returns a source location in which it's appropriate to insert a new attribute for the given declarati...
Definition: SemaAvailability.cpp:283
llvm::SmallVectorImpl
Definition: Randstruct.h:18
clang::ObjCMessageExpr::getClassReceiver
QualType getClassReceiver() const
Returns the type of a class message send, or NULL if the message is not a class message.
Definition: ExprObjC.h:1269
clang::Lexer::findLocationAfterToken
static SourceLocation findLocationAfterToken(SourceLocation loc, tok::TokenKind TKind, const SourceManager &SM, const LangOptions &LangOpts, bool SkipTrailingWhitespaceAndNewLine)
Checks that the given token is the first token that occurs after the given location (this excludes co...
Definition: Lexer.cpp:1292
SM
#define SM(sm)
Definition: Cuda.cpp:79
clang::Decl::getVersionIntroduced
VersionTuple getVersionIntroduced() const
Retrieve the version of the target platform in which this declaration was introduced.
Definition: DeclBase.cpp:688
clang::Sema::NSAPIObj
std::unique_ptr< NSAPI > NSAPIObj
Caches identifiers/selectors for NSFoundation APIs.
Definition: Sema.h:1167
clang::Decl::getLocation
SourceLocation getLocation() const
Definition: DeclBase.h:432
clang::DeclRefExpr
A reference to a declared variable, function, enum, etc.
Definition: Expr.h:1232
EmitAvailabilityWarning
static void EmitAvailabilityWarning(Sema &S, AvailabilityResult AR, const NamedDecl *ReferringDecl, const NamedDecl *OffendingDecl, StringRef Message, ArrayRef< SourceLocation > Locs, const ObjCInterfaceDecl *UnknownObjCClass, const ObjCPropertyDecl *ObjCProperty, bool ObjCPropertyAccess)
Definition: SemaAvailability.cpp:557
clang::Sema::DelayedDiagnostics::add
void add(const sema::DelayedDiagnostic &diag)
Adds a delayed diagnostic.
Definition: DelayedDiagnostic.h:325
clang::ObjCPropertyDecl::findPropertyDecl
static ObjCPropertyDecl * findPropertyDecl(const DeclContext *DC, const IdentifierInfo *propertyID, ObjCPropertyQueryKind queryKind)
Lookup a property by name in the specified DeclContext.
Definition: DeclObjC.cpp:179
clang::ASTContext::getLangOpts
const LangOptions & getLangOpts() const
Definition: ASTContext.h:791
clang::FixItHint::CreateReplacement
static FixItHint CreateReplacement(CharSourceRange RemoveRange, StringRef Code)
Create a code modification hint that replaces the given source range with the given code string.
Definition: Diagnostic.h:134
clang::Sema::DelayedDiagnostics
class clang::Sema::DelayedDiagnostics DelayedDiagnostics
clang::sema::DelayedDiagnostic::Triggered
bool Triggered
Definition: DelayedDiagnostic.h:129
clang::Decl::getDeclContext
DeclContext * getDeclContext()
Definition: DeclBase.h:441