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