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