clang 23.0.0git
SemaAvailability.cpp
Go to the documentation of this file.
1//===--- SemaAvailability.cpp - Availability attribute handling -----------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file processes the availability attribute.
10//
11//===----------------------------------------------------------------------===//
12
13#include "clang/AST/Attr.h"
14#include "clang/AST/Decl.h"
17#include "clang/AST/ExprObjC.h"
18#include "clang/AST/StmtObjC.h"
26#include "clang/Sema/Sema.h"
27#include "clang/Sema/SemaObjC.h"
28#include "llvm/ADT/StringRef.h"
29#include <optional>
30
31using namespace clang;
32using namespace sema;
33
34static bool hasMatchingEnvironmentOrNone(const ASTContext &Context,
35 const AvailabilityAttr *AA) {
36 const IdentifierInfo *IIEnvironment = AA->getEnvironment();
37 auto Environment = Context.getTargetInfo().getTriple().getEnvironment();
38 if (!IIEnvironment || Environment == llvm::Triple::UnknownEnvironment)
39 return true;
40
41 llvm::Triple::EnvironmentType ET =
42 AvailabilityAttr::getEnvironmentType(IIEnvironment->getName());
43 return Environment == ET;
44}
45
46static const AvailabilityAttr *getAttrForPlatform(ASTContext &Context,
47 const Decl *D) {
48 AvailabilityAttr const *PartialMatch = nullptr;
49 // Check each AvailabilityAttr to find the one for this platform.
50 // For multiple attributes with the same platform try to find one for this
51 // environment.
52 // The attribute is always on the FunctionDecl, not on the
53 // FunctionTemplateDecl.
54 if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(D))
55 D = FTD->getTemplatedDecl();
56 for (const auto *A : D->attrs()) {
57 if (const auto *Avail = dyn_cast<AvailabilityAttr>(A)) {
58 // FIXME: this is copied from CheckAvailability. We should try to
59 // de-duplicate.
60
61 // If this attr has an inferred platform-specific attr (e.g. anyappleos
62 // → ios/macos/...), use that for platform matching but return the
63 // original.
64 const AvailabilityAttr *EffectiveAvail = Avail->getEffectiveAttr();
65
66 // Check if this is an App Extension "platform", and if so chop off
67 // the suffix for matching with the actual platform.
68 StringRef ActualPlatform = EffectiveAvail->getPlatform()->getName();
69 StringRef RealizedPlatform = ActualPlatform;
70 if (Context.getLangOpts().AppExt) {
71 size_t suffix = RealizedPlatform.rfind("_app_extension");
72 if (suffix != StringRef::npos)
73 RealizedPlatform = RealizedPlatform.slice(0, suffix);
74 }
75
76 StringRef TargetPlatform = Context.getTargetInfo().getPlatformName();
77
78 // Match the platform name.
79 if (RealizedPlatform == TargetPlatform) {
80 // Find the best matching attribute for this environment
81 if (hasMatchingEnvironmentOrNone(Context, EffectiveAvail))
82 return Avail;
83 PartialMatch = Avail;
84 }
85 }
86 }
87 return PartialMatch;
88}
89
90/// The diagnostic we should emit for \c D, and the declaration that
91/// originated it, or \c AR_Available.
92///
93/// \param D The declaration to check.
94/// \param Message If non-null, this will be populated with the message from
95/// the availability attribute that is selected.
96/// \param ClassReceiver If we're checking the method of a class message
97/// send, the class. Otherwise nullptr.
98std::pair<AvailabilityResult, const NamedDecl *>
100 ObjCInterfaceDecl *ClassReceiver) {
102
103 // For typedefs, if the typedef declaration appears available look
104 // to the underlying type to see if it is more restrictive.
105 while (const auto *TD = dyn_cast<TypedefNameDecl>(D)) {
106 if (Result != AR_Available)
107 break;
108 for (const Type *T = TD->getUnderlyingType().getTypePtr(); /**/; /**/) {
109 if (auto *TT = dyn_cast<TagType>(T)) {
110 D = TT->getDecl()->getDefinitionOrSelf();
111 } else if (isa<SubstTemplateTypeParmType>(T)) {
112 // A Subst* node represents a use through a template.
113 // Any uses of the underlying declaration happened through it's template
114 // specialization.
115 goto done;
116 } else {
117 const Type *NextT =
119 if (NextT == T)
120 goto done;
121 T = NextT;
122 continue;
123 }
124 Result = D->getAvailability(Message);
125 break;
126 }
127 }
128done:
129 // Forward class declarations get their attributes from their definition.
130 if (const auto *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) {
131 if (IDecl->getDefinition()) {
132 D = IDecl->getDefinition();
133 Result = D->getAvailability(Message);
134 }
135 }
136
137 if (const auto *ECD = dyn_cast<EnumConstantDecl>(D))
138 if (Result == AR_Available) {
139 const DeclContext *DC = ECD->getDeclContext();
140 if (const auto *TheEnumDecl = dyn_cast<EnumDecl>(DC)) {
141 Result = TheEnumDecl->getAvailability(Message);
142 D = TheEnumDecl;
143 }
144 }
145
146 // For +new, infer availability from -init.
147 if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
148 if (ObjC().NSAPIObj && ClassReceiver) {
149 ObjCMethodDecl *Init = ClassReceiver->lookupInstanceMethod(
150 ObjC().NSAPIObj->getInitSelector());
151 if (Init && Result == AR_Available && MD->isClassMethod() &&
152 MD->getSelector() == ObjC().NSAPIObj->getNewSelector() &&
153 MD->definedInNSObject(getASTContext())) {
154 Result = Init->getAvailability(Message);
155 D = Init;
156 }
157 }
158 }
159
160 return {Result, D};
161}
162
163/// whether we should emit a diagnostic for \c K and \c DeclVersion in
164/// the context of \c Ctx. For example, we should emit an unavailable diagnostic
165/// in a deprecated context, but not the other way around.
167 Sema &S, AvailabilityResult K, VersionTuple DeclVersion,
168 const IdentifierInfo *DeclEnv, Decl *Ctx, const NamedDecl *OffendingDecl) {
169 assert(K != AR_Available && "Expected an unavailable declaration here!");
170
171 // If this was defined using CF_OPTIONS, etc. then ignore the diagnostic.
172 auto DeclLoc = Ctx->getBeginLoc();
173 // This is only a problem in Foundation's C++ implementation for CF_OPTIONS.
174 if (DeclLoc.isMacroID() && S.getLangOpts().CPlusPlus &&
175 isa<TypedefDecl>(OffendingDecl)) {
176 StringRef MacroName = S.getPreprocessor().getImmediateMacroName(DeclLoc);
177 if (MacroName == "CF_OPTIONS" || MacroName == "OBJC_OPTIONS" ||
178 MacroName == "SWIFT_OPTIONS" || MacroName == "NS_OPTIONS") {
179 return false;
180 }
181 }
182
183 // In HLSL, skip emitting diagnostic if the diagnostic mode is not set to
184 // strict (-fhlsl-strict-availability), or if the target is library and the
185 // availability is restricted to a specific environment/shader stage.
186 // For libraries the availability will be checked later in
187 // DiagnoseHLSLAvailability class once where the specific environment/shader
188 // stage of the caller is known.
189 // We only do this for APIs that are not explicitly deprecated. Any API that
190 // is explicitly deprecated we always issue a diagnostic on.
191 if (S.getLangOpts().HLSL && K != AR_Deprecated) {
192 if (!S.getLangOpts().HLSLStrictAvailability ||
193 (DeclEnv != nullptr &&
194 S.getASTContext().getTargetInfo().getTriple().getEnvironment() ==
195 llvm::Triple::EnvironmentType::Library))
196 return false;
197 }
198
199 if (K == AR_Deprecated) {
200 if (const auto *VD = dyn_cast<VarDecl>(OffendingDecl))
201 if (VD->isLocalVarDeclOrParm() && VD->isDeprecated())
202 return true;
203 }
204
205 // Checks if we should emit the availability diagnostic in the context of C.
206 auto CheckContext = [&](const Decl *C) {
207 if (K == AR_NotYetIntroduced) {
208 if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, C))
209 if (AA->getEffectiveIntroduced() >= DeclVersion &&
210 AA->getEffectiveEnvironment() == DeclEnv)
211 return true;
212 } else if (K == AR_Deprecated) {
213 if (C->isDeprecated())
214 return true;
215 } else if (K == AR_Unavailable) {
216 // It is perfectly fine to refer to an 'unavailable' Objective-C method
217 // when it is referenced from within the @implementation itself. In this
218 // context, we interpret unavailable as a form of access control.
219 if (const auto *MD = dyn_cast<ObjCMethodDecl>(OffendingDecl)) {
220 if (const auto *Impl = dyn_cast<ObjCImplDecl>(C)) {
221 if (MD->getClassInterface() == Impl->getClassInterface())
222 return true;
223 }
224 }
225 }
226
227 if (C->isUnavailable())
228 return true;
229 return false;
230 };
231
232 do {
233 if (CheckContext(Ctx))
234 return false;
235
236 // An implementation implicitly has the availability of the interface.
237 // Unless it is "+load" method.
238 if (const auto *MethodD = dyn_cast<ObjCMethodDecl>(Ctx))
239 if (MethodD->isClassMethod() &&
240 MethodD->getSelector().getAsString() == "load")
241 return true;
242
243 if (const auto *CatOrImpl = dyn_cast<ObjCImplDecl>(Ctx)) {
244 if (const ObjCInterfaceDecl *Interface = CatOrImpl->getClassInterface())
245 if (CheckContext(Interface))
246 return false;
247 }
248 // A category implicitly has the availability of the interface.
249 else if (const auto *CatD = dyn_cast<ObjCCategoryDecl>(Ctx))
250 if (const ObjCInterfaceDecl *Interface = CatD->getClassInterface())
251 if (CheckContext(Interface))
252 return false;
253 } while ((Ctx = cast_or_null<Decl>(Ctx->getDeclContext())));
254
255 return true;
256}
257
259 const ASTContext &Context, const VersionTuple &DeploymentVersion,
260 const VersionTuple &DeclVersion, bool HasMatchingEnv) {
261 const auto &Triple = Context.getTargetInfo().getTriple();
262 VersionTuple ForceAvailabilityFromVersion;
263 switch (Triple.getOS()) {
264 // For iOS, emit the diagnostic even if -Wunguarded-availability is
265 // not specified for deployment targets >= to iOS 11 or equivalent or
266 // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or
267 // later.
268 case llvm::Triple::IOS:
269 case llvm::Triple::TvOS:
270 ForceAvailabilityFromVersion = VersionTuple(/*Major=*/11);
271 break;
272 case llvm::Triple::WatchOS:
273 ForceAvailabilityFromVersion = VersionTuple(/*Major=*/4);
274 break;
275 case llvm::Triple::Darwin:
276 case llvm::Triple::MacOSX:
277 ForceAvailabilityFromVersion = VersionTuple(/*Major=*/10, /*Minor=*/13);
278 break;
279 // For HLSL, use diagnostic from HLSLAvailability group which
280 // are reported as errors by default and in strict diagnostic mode
281 // (-fhlsl-strict-availability) and as warnings in relaxed diagnostic
282 // mode (-Wno-error=hlsl-availability)
283 case llvm::Triple::ShaderModel:
284 return HasMatchingEnv ? diag::warn_hlsl_availability
285 : diag::warn_hlsl_availability_unavailable;
286 default:
287 // New Apple targets should always warn about availability.
288 ForceAvailabilityFromVersion =
289 (Triple.getVendor() == llvm::Triple::Apple)
290 ? VersionTuple(/*Major=*/0, 0)
291 : VersionTuple(/*Major=*/(unsigned)-1, (unsigned)-1);
292 }
293 if (DeploymentVersion >= ForceAvailabilityFromVersion ||
294 DeclVersion >= ForceAvailabilityFromVersion)
295 return HasMatchingEnv ? diag::warn_unguarded_availability_new
296 : diag::warn_unguarded_availability_unavailable_new;
297 return HasMatchingEnv ? diag::warn_unguarded_availability
298 : diag::warn_unguarded_availability_unavailable;
299}
300
302 for (Decl *Ctx = OrigCtx; Ctx;
303 Ctx = cast_or_null<Decl>(Ctx->getDeclContext())) {
304 if (isa<TagDecl>(Ctx) || isa<FunctionDecl>(Ctx) || isa<ObjCMethodDecl>(Ctx))
305 return cast<NamedDecl>(Ctx);
306 if (auto *CD = dyn_cast<ObjCContainerDecl>(Ctx)) {
307 if (auto *Imp = dyn_cast<ObjCImplDecl>(Ctx))
308 return Imp->getClassInterface();
309 return CD;
310 }
311 }
312
313 return dyn_cast<NamedDecl>(OrigCtx);
314}
315
316namespace {
317
318struct AttributeInsertion {
319 StringRef Prefix;
320 SourceLocation Loc;
321 StringRef Suffix;
322
323 static AttributeInsertion createInsertionAfter(const NamedDecl *D) {
324 return {" ", D->getEndLoc(), ""};
325 }
326 static AttributeInsertion createInsertionAfter(SourceLocation Loc) {
327 return {" ", Loc, ""};
328 }
329 static AttributeInsertion createInsertionBefore(const NamedDecl *D) {
330 return {"", D->getBeginLoc(), "\n"};
331 }
332};
333
334} // end anonymous namespace
335
336/// Tries to parse a string as ObjC method name.
337///
338/// \param Name The string to parse. Expected to originate from availability
339/// attribute argument.
340/// \param SlotNames The vector that will be populated with slot names. In case
341/// of unsuccessful parsing can contain invalid data.
342/// \returns A number of method parameters if parsing was successful,
343/// std::nullopt otherwise.
344static std::optional<unsigned>
346 const LangOptions &LangOpts) {
347 // Accept replacements starting with - or + as valid ObjC method names.
348 if (!Name.empty() && (Name.front() == '-' || Name.front() == '+'))
349 Name = Name.drop_front(1);
350 if (Name.empty())
351 return std::nullopt;
352 Name.split(SlotNames, ':');
353 unsigned NumParams;
354 if (Name.back() == ':') {
355 // Remove an empty string at the end that doesn't represent any slot.
356 SlotNames.pop_back();
357 NumParams = SlotNames.size();
358 } else {
359 if (SlotNames.size() != 1)
360 // Not a valid method name, just a colon-separated string.
361 return std::nullopt;
362 NumParams = 0;
363 }
364 // Verify all slot names are valid.
365 bool AllowDollar = LangOpts.DollarIdents;
366 for (StringRef S : SlotNames) {
367 if (S.empty())
368 continue;
369 if (!isValidAsciiIdentifier(S, AllowDollar))
370 return std::nullopt;
371 }
372 return NumParams;
373}
374
375/// Returns a source location in which it's appropriate to insert a new
376/// attribute for the given declaration \D.
377static std::optional<AttributeInsertion>
379 const LangOptions &LangOpts) {
381 return AttributeInsertion::createInsertionAfter(D);
382 if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
383 if (MD->hasBody())
384 return std::nullopt;
385 return AttributeInsertion::createInsertionAfter(D);
386 }
387 if (const auto *TD = dyn_cast<TagDecl>(D)) {
388 SourceLocation Loc =
389 Lexer::getLocForEndOfToken(TD->getInnerLocStart(), 0, SM, LangOpts);
390 if (Loc.isInvalid())
391 return std::nullopt;
392 // Insert after the 'struct'/whatever keyword.
393 return AttributeInsertion::createInsertionAfter(Loc);
394 }
395 return AttributeInsertion::createInsertionBefore(D);
396}
397
398/// Actually emit an availability diagnostic for a reference to an unavailable
399/// decl.
400///
401/// \param Ctx The context that the reference occurred in
402/// \param ReferringDecl The exact declaration that was referenced.
403/// \param OffendingDecl A related decl to \c ReferringDecl that has an
404/// availability attribute corresponding to \c K attached to it. Note that this
405/// may not be the same as ReferringDecl, i.e. if an EnumDecl is annotated and
406/// we refer to a member EnumConstantDecl, ReferringDecl is the EnumConstantDecl
407/// and OffendingDecl is the EnumDecl.
409 Decl *Ctx, const NamedDecl *ReferringDecl,
410 const NamedDecl *OffendingDecl,
411 StringRef Message,
413 const ObjCInterfaceDecl *UnknownObjCClass,
414 const ObjCPropertyDecl *ObjCProperty,
415 bool ObjCPropertyAccess) {
416 // Diagnostics for deprecated or unavailable.
417 unsigned diag, diag_message, diag_fwdclass_message;
418 unsigned diag_available_here = diag::note_availability_specified_here;
419 SourceLocation NoteLocation = OffendingDecl->getLocation();
420
421 // Matches 'diag::note_property_attribute' options.
422 unsigned property_note_select;
423
424 // Matches diag::note_availability_specified_here.
425 unsigned available_here_select_kind;
426
427 VersionTuple DeclVersion;
428 const AvailabilityAttr *AA = getAttrForPlatform(S.Context, OffendingDecl);
429 const IdentifierInfo *IIEnv = nullptr;
430 if (AA) {
431 DeclVersion = AA->getEffectiveIntroduced();
432 IIEnv = AA->getEffectiveEnvironment();
433 }
434
435 if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, IIEnv, Ctx,
436 OffendingDecl))
437 return;
438
439 SourceLocation Loc = Locs.front();
440
441 // The declaration can have multiple availability attributes, we are looking
442 // at one of them.
443 if (AA && AA->isInherited()) {
444 for (const Decl *Redecl = OffendingDecl->getMostRecentDecl(); Redecl;
445 Redecl = Redecl->getPreviousDecl()) {
446 const AvailabilityAttr *AForRedecl =
447 getAttrForPlatform(S.Context, Redecl);
448 if (AForRedecl && !AForRedecl->isInherited()) {
449 // If D is a declaration with inherited attributes, the note should
450 // point to the declaration with actual attributes.
451 NoteLocation = Redecl->getLocation();
452 break;
453 }
454 }
455 }
456
457 switch (K) {
458 case AR_NotYetIntroduced: {
459 // We would like to emit the diagnostic even if -Wunguarded-availability is
460 // not specified for deployment targets >= to iOS 11 or equivalent or
461 // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or
462 // later.
463 assert(AA != nullptr && "expecting valid availability attribute");
464 VersionTuple Introduced = AA->getEffectiveIntroduced();
465 bool EnvironmentMatchesOrNone =
466 hasMatchingEnvironmentOrNone(S.getASTContext(), AA->getEffectiveAttr());
467
468 const TargetInfo &TI = S.getASTContext().getTargetInfo();
469 std::string PlatformName(
470 AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName()));
471 llvm::StringRef TargetEnvironment(
472 llvm::Triple::getEnvironmentTypeName(TI.getTriple().getEnvironment()));
473 llvm::StringRef AttrEnvironment =
474 AA->getEnvironment() ? AA->getEnvironment()->getName() : "";
475 bool UseEnvironment =
476 (!AttrEnvironment.empty() && !TargetEnvironment.empty());
477
478 unsigned DiagKind = getAvailabilityDiagnosticKind(
480 Introduced, EnvironmentMatchesOrNone);
481
482 S.Diag(Loc, DiagKind) << OffendingDecl << PlatformName
483 << Introduced.getAsString() << UseEnvironment
484 << TargetEnvironment;
485
486 S.Diag(OffendingDecl->getLocation(),
487 diag::note_partial_availability_specified_here)
488 << OffendingDecl << PlatformName << Introduced.getAsString()
489 << S.Context.getTargetInfo().getPlatformMinVersion().getAsString()
490 << UseEnvironment << AttrEnvironment << TargetEnvironment;
491
492 // Do not offer to silence the warning or fixits for HLSL
493 if (S.getLangOpts().HLSL)
494 return;
495
496 if (const auto *Enclosing = findEnclosingDeclToAnnotate(Ctx)) {
497 if (const auto *TD = dyn_cast<TagDecl>(Enclosing))
498 if (TD->getDeclName().isEmpty()) {
499 S.Diag(TD->getLocation(),
500 diag::note_decl_unguarded_availability_silence)
501 << /*Anonymous*/ 1 << TD->getKindName();
502 return;
503 }
504 auto FixitNoteDiag =
505 S.Diag(Enclosing->getLocation(),
506 diag::note_decl_unguarded_availability_silence)
507 << /*Named*/ 0 << Enclosing;
508 // Don't offer a fixit for declarations with availability attributes.
509 if (Enclosing->hasAttr<AvailabilityAttr>())
510 return;
512 if (!PP.isMacroDefined("API_AVAILABLE"))
513 return;
514 std::optional<AttributeInsertion> Insertion = createAttributeInsertion(
515 Enclosing, S.getSourceManager(), S.getLangOpts());
516 if (!Insertion)
517 return;
518 StringRef PlatformName =
520
521 // Apple's API_AVAILABLE macro expands roughly like this.
522 // API_AVAILABLE(ios(17.0))
523 // __attribute__((availability(__API_AVAILABLE_PLATFORM_ios(17.0)))
524 // __attribute__((availability(ios,introduced=17.0)))
525 // In order to figure out which platform name to use in the API_AVAILABLE
526 // macro, the associated __API_AVAILABLE_PLATFORM_ macro needs to be
527 // found. The __API_AVAILABLE_PLATFORM_ macros aren't consistent about
528 // using the canonical platform name, source spelling name, or one of the
529 // other supported names (i.e. one of the keys in canonicalizePlatformName
530 // that's neither). Check all of the supported names for a match.
531 std::vector<StringRef> EquivalentPlatforms =
532 AvailabilityAttr::equivalentPlatformNames(PlatformName);
533 llvm::Twine MacroPrefix = "__API_AVAILABLE_PLATFORM_";
534 auto AvailablePlatform =
535 llvm::find_if(EquivalentPlatforms, [&](StringRef EquivalentPlatform) {
536 return PP.isMacroDefined((MacroPrefix + EquivalentPlatform).str());
537 });
538 if (AvailablePlatform == EquivalentPlatforms.end())
539 return;
540 std::string Introduced =
541 OffendingDecl->getVersionIntroduced().getAsString();
542 FixitNoteDiag << FixItHint::CreateInsertion(
543 Insertion->Loc,
544 (llvm::Twine(Insertion->Prefix) + "API_AVAILABLE(" +
545 *AvailablePlatform + "(" + Introduced + "))" + Insertion->Suffix)
546 .str());
547 }
548 return;
549 }
550 case AR_Deprecated:
551 // Suppress -Wdeprecated-declarations in implicit
552 // functions.
553 if (const auto *FD = dyn_cast_or_null<FunctionDecl>(S.getCurFunctionDecl());
554 FD && FD->isImplicit())
555 return;
556
557 if (ObjCPropertyAccess)
558 diag = diag::warn_property_method_deprecated;
560 diag = diag::warn_deprecated_switch_case;
561 else
562 diag = diag::warn_deprecated;
563
564 diag_message = diag::warn_deprecated_message;
565 diag_fwdclass_message = diag::warn_deprecated_fwdclass_message;
566 property_note_select = /* deprecated */ 0;
567 available_here_select_kind = /* deprecated */ 2;
568 if (const auto *AL = OffendingDecl->getAttr<DeprecatedAttr>())
569 NoteLocation = AL->getLocation();
570 break;
571
572 case AR_Unavailable:
573 diag = !ObjCPropertyAccess ? diag::err_unavailable
574 : diag::err_property_method_unavailable;
575 diag_message = diag::err_unavailable_message;
576 diag_fwdclass_message = diag::warn_unavailable_fwdclass_message;
577 property_note_select = /* unavailable */ 1;
578 available_here_select_kind = /* unavailable */ 0;
579
580 if (auto AL = OffendingDecl->getAttr<UnavailableAttr>()) {
581 if (AL->isImplicit() && AL->getImplicitReason()) {
582 // Most of these failures are due to extra restrictions in ARC;
583 // reflect that in the primary diagnostic when applicable.
584 auto flagARCError = [&] {
585 if (S.getLangOpts().ObjCAutoRefCount &&
587 OffendingDecl->getLocation()))
588 diag = diag::err_unavailable_in_arc;
589 };
590
591 switch (AL->getImplicitReason()) {
592 case UnavailableAttr::IR_None: break;
593
594 case UnavailableAttr::IR_ARCForbiddenType:
595 flagARCError();
596 diag_available_here = diag::note_arc_forbidden_type;
597 break;
598
599 case UnavailableAttr::IR_ForbiddenWeak:
600 if (S.getLangOpts().ObjCWeakRuntime)
601 diag_available_here = diag::note_arc_weak_disabled;
602 else
603 diag_available_here = diag::note_arc_weak_no_runtime;
604 break;
605
606 case UnavailableAttr::IR_ARCForbiddenConversion:
607 flagARCError();
608 diag_available_here = diag::note_performs_forbidden_arc_conversion;
609 break;
610
611 case UnavailableAttr::IR_ARCInitReturnsUnrelated:
612 flagARCError();
613 diag_available_here = diag::note_arc_init_returns_unrelated;
614 break;
615
616 case UnavailableAttr::IR_ARCFieldWithOwnership:
617 flagARCError();
618 diag_available_here = diag::note_arc_field_with_ownership;
619 break;
620 }
621 }
622 }
623 break;
624
625 case AR_Available:
626 llvm_unreachable("Warning for availability of available declaration?");
627 }
628
630 if (K == AR_Deprecated) {
631 StringRef Replacement;
632 if (auto AL = OffendingDecl->getAttr<DeprecatedAttr>())
633 Replacement = AL->getReplacement();
634 if (auto AL = getAttrForPlatform(S.Context, OffendingDecl))
635 Replacement = AL->getReplacement();
636
637 CharSourceRange UseRange;
638 if (!Replacement.empty())
639 UseRange =
641 if (UseRange.isValid()) {
642 if (const auto *MethodDecl = dyn_cast<ObjCMethodDecl>(ReferringDecl)) {
643 Selector Sel = MethodDecl->getSelector();
644 SmallVector<StringRef, 12> SelectorSlotNames;
645 std::optional<unsigned> NumParams = tryParseObjCMethodName(
646 Replacement, SelectorSlotNames, S.getLangOpts());
647 if (NumParams && *NumParams == Sel.getNumArgs()) {
648 assert(SelectorSlotNames.size() == Locs.size());
649 for (unsigned I = 0; I < Locs.size(); ++I) {
650 if (!Sel.getNameForSlot(I).empty()) {
652 Locs[I], S.getLocForEndOfToken(Locs[I]));
653 FixIts.push_back(FixItHint::CreateReplacement(
654 NameRange, SelectorSlotNames[I]));
655 } else
656 FixIts.push_back(
657 FixItHint::CreateInsertion(Locs[I], SelectorSlotNames[I]));
658 }
659 } else
660 FixIts.push_back(FixItHint::CreateReplacement(UseRange, Replacement));
661 } else
662 FixIts.push_back(FixItHint::CreateReplacement(UseRange, Replacement));
663 }
664 }
665
666 // We emit deprecation warning for deprecated specializations
667 // when their instantiation stacks originate outside
668 // of a system header, even if the diagnostics is suppresed at the
669 // point of definition.
670 SourceLocation InstantiationLoc =
671 S.getTopMostPointOfInstantiation(ReferringDecl);
672 bool ShouldAllowWarningInSystemHeader =
673 InstantiationLoc != Loc &&
674 !S.getSourceManager().isInSystemHeader(InstantiationLoc);
675 struct AllowWarningInSystemHeaders {
676 AllowWarningInSystemHeaders(DiagnosticsEngine &E,
677 bool AllowWarningInSystemHeaders)
678 : Engine(E), Prev(E.getForceSystemWarnings()) {
679 if (AllowWarningInSystemHeaders)
680 Engine.setForceSystemWarnings(true);
681 }
682 ~AllowWarningInSystemHeaders() { Engine.setForceSystemWarnings(Prev); }
683
684 private:
685 DiagnosticsEngine &Engine;
686 bool Prev;
687 } SystemWarningOverrideRAII(S.getDiagnostics(),
688 ShouldAllowWarningInSystemHeader);
689
690 if (!Message.empty()) {
691 S.Diag(Loc, diag_message) << ReferringDecl << Message << FixIts;
692 if (ObjCProperty)
693 S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
694 << ObjCProperty->getDeclName() << property_note_select;
695 } else if (!UnknownObjCClass) {
696 S.Diag(Loc, diag) << ReferringDecl << FixIts;
697 if (ObjCProperty)
698 S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
699 << ObjCProperty->getDeclName() << property_note_select;
700 } else {
701 S.Diag(Loc, diag_fwdclass_message) << ReferringDecl << FixIts;
702 S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class);
703 }
704
705 S.Diag(NoteLocation, diag_available_here)
706 << OffendingDecl << available_here_select_kind;
707}
708
711 "Expected an availability diagnostic here");
712
713 DD.Triggered = true;
718 DD.getObjCProperty(), false);
719}
720
722 const NamedDecl *ReferringDecl,
723 const NamedDecl *OffendingDecl,
724 StringRef Message,
726 const ObjCInterfaceDecl *UnknownObjCClass,
727 const ObjCPropertyDecl *ObjCProperty,
728 bool ObjCPropertyAccess) {
729 // Delay if we're currently parsing a declaration.
733 AR, Locs, ReferringDecl, OffendingDecl, UnknownObjCClass,
734 ObjCProperty, Message, ObjCPropertyAccess));
735 return;
736 }
737
739 DoEmitAvailabilityWarning(S, AR, Ctx, ReferringDecl, OffendingDecl,
740 Message, Locs, UnknownObjCClass, ObjCProperty,
741 ObjCPropertyAccess);
742}
743
744namespace {
745
746/// Returns true if the given statement can be a body-like child of \p Parent.
747bool isBodyLikeChildStmt(const Stmt *S, const Stmt *Parent) {
748 switch (Parent->getStmtClass()) {
749 case Stmt::IfStmtClass:
750 return cast<IfStmt>(Parent)->getThen() == S ||
751 cast<IfStmt>(Parent)->getElse() == S;
752 case Stmt::WhileStmtClass:
753 return cast<WhileStmt>(Parent)->getBody() == S;
754 case Stmt::DoStmtClass:
755 return cast<DoStmt>(Parent)->getBody() == S;
756 case Stmt::ForStmtClass:
757 return cast<ForStmt>(Parent)->getBody() == S;
758 case Stmt::CXXForRangeStmtClass:
759 return cast<CXXForRangeStmt>(Parent)->getBody() == S;
760 case Stmt::ObjCForCollectionStmtClass:
761 return cast<ObjCForCollectionStmt>(Parent)->getBody() == S;
762 case Stmt::CaseStmtClass:
763 case Stmt::DefaultStmtClass:
764 return cast<SwitchCase>(Parent)->getSubStmt() == S;
765 default:
766 return false;
767 }
768}
769
770class StmtUSEFinder : public DynamicRecursiveASTVisitor {
771 const Stmt *Target;
772
773public:
774 bool VisitStmt(Stmt *S) override { return S != Target; }
775
776 /// Returns true if the given statement is present in the given declaration.
777 static bool isContained(const Stmt *Target, const Decl *D) {
778 StmtUSEFinder Visitor;
779 Visitor.Target = Target;
780 return !Visitor.TraverseDecl(const_cast<Decl *>(D));
781 }
782};
783
784/// Traverses the AST and finds the last statement that used a given
785/// declaration.
786class LastDeclUSEFinder : public DynamicRecursiveASTVisitor {
787 const Decl *D;
788
789public:
790 bool VisitDeclRefExpr(DeclRefExpr *DRE) override {
791 if (DRE->getDecl() == D)
792 return false;
793 return true;
794 }
795
796 static const Stmt *findLastStmtThatUsesDecl(const Decl *D,
797 const CompoundStmt *Scope) {
798 LastDeclUSEFinder Visitor;
799 Visitor.D = D;
800 for (const Stmt *S : llvm::reverse(Scope->body())) {
801 if (!Visitor.TraverseStmt(const_cast<Stmt *>(S)))
802 return S;
803 }
804 return nullptr;
805 }
806};
807
808/// This class implements -Wunguarded-availability.
809///
810/// This is done with a traversal of the AST of a function that makes reference
811/// to a partially available declaration. Whenever we encounter an \c if of the
812/// form: \c if(@available(...)), we use the version from the condition to visit
813/// the then statement.
814class DiagnoseUnguardedAvailability : public DynamicRecursiveASTVisitor {
815 Sema &SemaRef;
816 Decl *Ctx;
817
818 /// Stack of potentially nested 'if (@available(...))'s.
819 SmallVector<VersionTuple, 8> AvailabilityStack;
820 SmallVector<const Stmt *, 16> StmtStack;
821
822 void DiagnoseDeclAvailability(NamedDecl *D, SourceRange Range,
823 ObjCInterfaceDecl *ClassReceiver = nullptr);
824
825public:
826 DiagnoseUnguardedAvailability(Sema &SemaRef, Decl *Ctx)
827 : SemaRef(SemaRef), Ctx(Ctx) {
828 AvailabilityStack.push_back(
830 }
831
832 bool TraverseStmt(Stmt *S) override {
833 if (!S)
834 return true;
835 StmtStack.push_back(S);
837 StmtStack.pop_back();
838 return Result;
839 }
840
841 void IssueDiagnostics(Stmt *S) { TraverseStmt(S); }
842
843 bool TraverseIfStmt(IfStmt *If) override;
844
845 // for 'case X:' statements, don't bother looking at the 'X'; it can't lead
846 // to any useful diagnostics.
847 bool TraverseCaseStmt(CaseStmt *CS) override {
848 return TraverseStmt(CS->getSubStmt());
849 }
850
851 bool VisitObjCMessageExpr(ObjCMessageExpr *Msg) override {
852 if (ObjCMethodDecl *D = Msg->getMethodDecl()) {
853 ObjCInterfaceDecl *ID = nullptr;
854 QualType ReceiverTy = Msg->getClassReceiver();
855 if (!ReceiverTy.isNull() && ReceiverTy->getAsObjCInterfaceType())
856 ID = ReceiverTy->getAsObjCInterfaceType()->getInterface();
857
858 DiagnoseDeclAvailability(
859 D, SourceRange(Msg->getSelectorStartLoc(), Msg->getEndLoc()), ID);
860 }
861 return true;
862 }
863
864 bool VisitDeclRefExpr(DeclRefExpr *DRE) override {
865 DiagnoseDeclAvailability(DRE->getDecl(),
866 SourceRange(DRE->getBeginLoc(), DRE->getEndLoc()));
867 return true;
868 }
869
870 bool VisitMemberExpr(MemberExpr *ME) override {
871 DiagnoseDeclAvailability(ME->getMemberDecl(),
872 SourceRange(ME->getBeginLoc(), ME->getEndLoc()));
873 return true;
874 }
875
876 bool VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *E) override {
877 SemaRef.Diag(E->getBeginLoc(), diag::warn_at_available_unchecked_use)
878 << (!SemaRef.getLangOpts().ObjC);
879 return true;
880 }
881
882 bool VisitTypeLoc(TypeLoc Ty) override;
883};
884
885void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability(
886 NamedDecl *D, SourceRange Range, ObjCInterfaceDecl *ReceiverClass) {
888 const NamedDecl *OffendingDecl;
889 std::tie(Result, OffendingDecl) =
890 SemaRef.ShouldDiagnoseAvailabilityOfDecl(D, nullptr, ReceiverClass);
891 if (Result != AR_Available) {
892 // All other diagnostic kinds have already been handled in
893 // DiagnoseAvailabilityOfDecl.
895 return;
896
897 const AvailabilityAttr *AA =
898 getAttrForPlatform(SemaRef.getASTContext(), OffendingDecl);
899 assert(AA != nullptr && "expecting valid availability attribute");
900 bool EnvironmentMatchesOrNone = hasMatchingEnvironmentOrNone(
901 SemaRef.getASTContext(), AA->getEffectiveAttr());
902 VersionTuple Introduced = AA->getEffectiveIntroduced();
903
904 if (EnvironmentMatchesOrNone && AvailabilityStack.back() >= Introduced)
905 return;
906
907 // If the context of this function is less available than D, we should not
908 // emit a diagnostic.
909 if (!ShouldDiagnoseAvailabilityInContext(SemaRef, Result, Introduced,
910 AA->getEffectiveEnvironment(), Ctx,
911 OffendingDecl))
912 return;
913
914 const TargetInfo &TI = SemaRef.getASTContext().getTargetInfo();
915 std::string PlatformName(
916 AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName()));
917 llvm::StringRef TargetEnvironment(TI.getTriple().getEnvironmentName());
918 llvm::StringRef AttrEnvironment =
919 AA->getEnvironment() ? AA->getEnvironment()->getName() : "";
920 bool UseEnvironment =
921 (!AttrEnvironment.empty() && !TargetEnvironment.empty());
922
923 unsigned DiagKind = getAvailabilityDiagnosticKind(
924 SemaRef.Context,
925 SemaRef.Context.getTargetInfo().getPlatformMinVersion(), Introduced,
926 EnvironmentMatchesOrNone);
927
928 SemaRef.Diag(Range.getBegin(), DiagKind)
929 << Range << D << PlatformName << Introduced.getAsString()
930 << UseEnvironment << TargetEnvironment;
931
932 SemaRef.Diag(OffendingDecl->getLocation(),
933 diag::note_partial_availability_specified_here)
934 << OffendingDecl << PlatformName << Introduced.getAsString()
935 << SemaRef.Context.getTargetInfo().getPlatformMinVersion().getAsString()
936 << UseEnvironment << AttrEnvironment << TargetEnvironment;
937
938 // Do not offer to silence the warning or fixits for HLSL
939 if (SemaRef.getLangOpts().HLSL)
940 return;
941
942 auto FixitDiag =
943 SemaRef.Diag(Range.getBegin(), diag::note_unguarded_available_silence)
944 << Range << D
945 << (SemaRef.getLangOpts().ObjC ? /*@available*/ 0
946 : /*__builtin_available*/ 1);
947
948 // Find the statement which should be enclosed in the if @available check.
949 if (StmtStack.empty())
950 return;
951 const Stmt *StmtOfUse = StmtStack.back();
952 const CompoundStmt *Scope = nullptr;
953 for (const Stmt *S : llvm::reverse(StmtStack)) {
954 if (const auto *CS = dyn_cast<CompoundStmt>(S)) {
955 Scope = CS;
956 break;
957 }
958 if (isBodyLikeChildStmt(StmtOfUse, S)) {
959 // The declaration won't be seen outside of the statement, so we don't
960 // have to wrap the uses of any declared variables in if (@available).
961 // Therefore we can avoid setting Scope here.
962 break;
963 }
964 StmtOfUse = S;
965 }
966 const Stmt *LastStmtOfUse = nullptr;
967 if (isa<DeclStmt>(StmtOfUse) && Scope) {
968 for (const Decl *D : cast<DeclStmt>(StmtOfUse)->decls()) {
969 if (StmtUSEFinder::isContained(StmtStack.back(), D)) {
970 LastStmtOfUse = LastDeclUSEFinder::findLastStmtThatUsesDecl(D, Scope);
971 break;
972 }
973 }
974 }
975
976 const SourceManager &SM = SemaRef.getSourceManager();
977 SourceLocation IfInsertionLoc =
978 SM.getExpansionLoc(StmtOfUse->getBeginLoc());
979 SourceLocation StmtEndLoc =
980 SM.getExpansionRange(
981 (LastStmtOfUse ? LastStmtOfUse : StmtOfUse)->getEndLoc())
982 .getEnd();
983 if (SM.getFileID(IfInsertionLoc) != SM.getFileID(StmtEndLoc))
984 return;
985
986 StringRef Indentation = Lexer::getIndentationForLine(IfInsertionLoc, SM);
987 const char *ExtraIndentation = " ";
988 std::string FixItString;
989 llvm::raw_string_ostream FixItOS(FixItString);
990 StringRef FixItPlatformName;
991 VersionTuple FixItVersion;
992
993 if (AA->getInferredAttr()) {
994 FixItPlatformName = "anyAppleOS";
995 FixItVersion = AA->getIntroduced();
996 } else {
997 FixItPlatformName = AvailabilityAttr::getPlatformNameSourceSpelling(
999 FixItVersion = AA->getEffectiveIntroduced();
1000 }
1001 FixItOS << "if ("
1002 << (SemaRef.getLangOpts().ObjC ? "@available"
1003 : "__builtin_available")
1004 << "(" << FixItPlatformName << " " << FixItVersion.getAsString()
1005 << ", *)) {\n"
1006 << Indentation << ExtraIndentation;
1007 FixitDiag << FixItHint::CreateInsertion(IfInsertionLoc, FixItOS.str());
1009 StmtEndLoc, tok::semi, SM, SemaRef.getLangOpts(),
1010 /*SkipTrailingWhitespaceAndNewLine=*/false);
1011 if (ElseInsertionLoc.isInvalid())
1012 ElseInsertionLoc =
1013 Lexer::getLocForEndOfToken(StmtEndLoc, 0, SM, SemaRef.getLangOpts());
1014 FixItOS.str().clear();
1015 FixItOS << "\n"
1016 << Indentation << "} else {\n"
1017 << Indentation << ExtraIndentation
1018 << "// Fallback on earlier versions\n"
1019 << Indentation << "}";
1020 FixitDiag << FixItHint::CreateInsertion(ElseInsertionLoc, FixItOS.str());
1021 }
1022}
1023
1024bool DiagnoseUnguardedAvailability::VisitTypeLoc(TypeLoc Ty) {
1025 const Type *TyPtr = Ty.getTypePtr();
1027
1028 if (Range.isInvalid())
1029 return true;
1030
1031 if (const auto *TT = dyn_cast<TagType>(TyPtr)) {
1032 TagDecl *TD = TT->getDecl()->getDefinitionOrSelf();
1033 DiagnoseDeclAvailability(TD, Range);
1034
1035 } else if (const auto *TD = dyn_cast<TypedefType>(TyPtr)) {
1036 TypedefNameDecl *D = TD->getDecl();
1037 DiagnoseDeclAvailability(D, Range);
1038
1039 } else if (const auto *ObjCO = dyn_cast<ObjCObjectType>(TyPtr)) {
1040 if (NamedDecl *D = ObjCO->getInterface())
1041 DiagnoseDeclAvailability(D, Range);
1042 }
1043
1044 return true;
1045}
1046
1047struct ExtractedAvailabilityExpr {
1048 const ObjCAvailabilityCheckExpr *E = nullptr;
1049 bool isNegated = false;
1050};
1051
1052ExtractedAvailabilityExpr extractAvailabilityExpr(const Expr *IfCond) {
1053 const auto *E = IfCond;
1054 bool IsNegated = false;
1055 while (true) {
1056 E = E->IgnoreParens();
1057 if (const auto *AE = dyn_cast<ObjCAvailabilityCheckExpr>(E)) {
1058 return ExtractedAvailabilityExpr{AE, IsNegated};
1059 }
1060
1061 const auto *UO = dyn_cast<UnaryOperator>(E);
1062 if (!UO || UO->getOpcode() != UO_LNot) {
1063 return ExtractedAvailabilityExpr{};
1064 }
1065 E = UO->getSubExpr();
1066 IsNegated = !IsNegated;
1067 }
1068}
1069
1070bool DiagnoseUnguardedAvailability::TraverseIfStmt(IfStmt *If) {
1071 ExtractedAvailabilityExpr IfCond = extractAvailabilityExpr(If->getCond());
1072 if (!IfCond.E) {
1073 // This isn't an availability checking 'if', we can just continue.
1074 return DynamicRecursiveASTVisitor::TraverseIfStmt(If);
1075 }
1076
1077 VersionTuple CondVersion = IfCond.E->getVersion();
1078 // If we're using the '*' case here or if this check is redundant, then we
1079 // use the enclosing version to check both branches.
1080 if (CondVersion.empty() || CondVersion <= AvailabilityStack.back()) {
1081 return TraverseStmt(If->getThen()) && TraverseStmt(If->getElse());
1082 }
1083
1084 auto *Guarded = If->getThen();
1085 auto *Unguarded = If->getElse();
1086 if (IfCond.isNegated) {
1087 std::swap(Guarded, Unguarded);
1088 }
1089
1090 AvailabilityStack.push_back(CondVersion);
1091 bool ShouldContinue = TraverseStmt(Guarded);
1092 AvailabilityStack.pop_back();
1093
1094 return ShouldContinue && TraverseStmt(Unguarded);
1095}
1096
1097} // end anonymous namespace
1098
1100 Stmt *Body = nullptr;
1101
1102 if (auto *FD = D->getAsFunction()) {
1103 Body = FD->getBody();
1104
1105 if (auto *CD = dyn_cast<CXXConstructorDecl>(FD))
1106 for (const CXXCtorInitializer *CI : CD->inits())
1107 DiagnoseUnguardedAvailability(*this, D).IssueDiagnostics(CI->getInit());
1108
1109 } else if (auto *MD = dyn_cast<ObjCMethodDecl>(D))
1110 Body = MD->getBody();
1111 else if (auto *BD = dyn_cast<BlockDecl>(D))
1112 Body = BD->getBody();
1113
1114 assert(Body && "Need a body here!");
1115
1116 DiagnoseUnguardedAvailability(*this, D).IssueDiagnostics(Body);
1117}
1118
1120 if (FunctionScopes.empty())
1121 return nullptr;
1122
1123 // Conservatively search the entire current function scope context for
1124 // availability violations. This ensures we always correctly analyze nested
1125 // classes, blocks, lambdas, etc. that may or may not be inside if(@available)
1126 // checks themselves.
1127 return FunctionScopes.front();
1128}
1129
1132 const ObjCInterfaceDecl *UnknownObjCClass,
1133 bool ObjCPropertyAccess,
1134 bool AvoidPartialAvailabilityChecks,
1135 ObjCInterfaceDecl *ClassReceiver) {
1136
1137 std::string Message;
1139 const NamedDecl* OffendingDecl;
1140 // See if this declaration is unavailable, deprecated, or partial.
1141 std::tie(Result, OffendingDecl) =
1142 ShouldDiagnoseAvailabilityOfDecl(D, &Message, ClassReceiver);
1143 if (Result == AR_Available)
1144 return;
1145
1146 if (Result == AR_NotYetIntroduced) {
1147 if (AvoidPartialAvailabilityChecks)
1148 return;
1149
1150 // We need to know the @available context in the current function to
1151 // diagnose this use, let DiagnoseUnguardedAvailabilityViolations do that
1152 // when we're done parsing the current function.
1154 Context->HasPotentialAvailabilityViolations = true;
1155 return;
1156 }
1157 }
1158
1159 const ObjCPropertyDecl *ObjCPDecl = nullptr;
1160 if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
1161 if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) {
1162 AvailabilityResult PDeclResult = PD->getAvailability(nullptr);
1163 if (PDeclResult == Result)
1164 ObjCPDecl = PD;
1165 }
1166 }
1167
1168 EmitAvailabilityWarning(*this, Result, D, OffendingDecl, Message, Locs,
1169 UnknownObjCClass, ObjCPDecl, ObjCPropertyAccess);
1170}
1171
1174 DiagnoseAvailabilityOfDecl(D, Locs, /*UnknownObjCClass=*/nullptr,
1175 /*ObjCPropertyAccess=*/false,
1176 /*AvoidPartialAvailabilityChecks=*/false,
1177 /*ClassReceiver=*/nullptr);
1178}
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
#define SM(sm)
Defines the clang::Preprocessor interface.
static unsigned getAvailabilityDiagnosticKind(const ASTContext &Context, const VersionTuple &DeploymentVersion, const VersionTuple &DeclVersion, bool HasMatchingEnv)
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 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.
This file declares semantic analysis for Objective-C.
Defines the Objective-C statement AST node classes.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:227
const TargetInfo & getTargetInfo() const
Definition ASTContext.h:924
Represents a C++ base or member initializer.
Definition DeclCXX.h:2389
Stmt * getSubStmt()
Definition Stmt.h:2039
Represents a byte-granular source range.
static CharSourceRange getCharRange(SourceRange R)
CompoundStmt - This represents a group of statements like { stmt stmt }.
Definition Stmt.h:1746
body_range body()
Definition Stmt.h:1809
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition DeclBase.h:1462
ValueDecl * getDecl()
Definition Expr.h:1341
SourceLocation getEndLoc() const LLVM_READONLY
Definition Expr.cpp:551
SourceLocation getBeginLoc() const
Definition Expr.h:1352
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:1074
SourceLocation getEndLoc() const LLVM_READONLY
Definition DeclBase.h:443
T * getAttr() const
Definition DeclBase.h:581
AvailabilityResult getAvailability(std::string *Message=nullptr, VersionTuple EnclosingVersion=VersionTuple(), StringRef *RealizedPlatform=nullptr) const
Determine the availability of the given declaration.
Definition DeclBase.cpp:776
FunctionDecl * getAsFunction() LLVM_READONLY
Returns the function itself, or the templated function if this is a function template.
Definition DeclBase.cpp:273
SourceLocation getLocation() const
Definition DeclBase.h:447
DeclContext * getDeclContext()
Definition DeclBase.h:456
attr_range attrs() const
Definition DeclBase.h:543
SourceLocation getBeginLoc() const LLVM_READONLY
Definition DeclBase.h:439
VersionTuple getVersionIntroduced() const
Retrieve the version of the target platform in which this declaration was introduced.
Definition DeclBase.cpp:829
Concrete class used by the front-end to report problems and issues.
Definition Diagnostic.h:233
bool getForceSystemWarnings() const
Definition Diagnostic.h:740
virtual bool TraverseStmt(MaybeConst< Stmt > *S)
This represents one expression.
Definition Expr.h:112
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
Definition Expr.cpp:3086
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:141
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:104
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:2265
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
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:1409
static StringRef getIndentationForLine(SourceLocation Loc, const SourceManager &SM)
Returns the leading whitespace for line that corresponds to the given location Loc.
Definition Lexer.cpp:1186
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:859
ValueDecl * getMemberDecl() const
Retrieve the member declaration to which this expression refers.
Definition Expr.h:3450
SourceLocation getEndLoc() const LLVM_READONLY
Definition Expr.cpp:1808
SourceLocation getBeginLoc() const LLVM_READONLY
Definition Expr.cpp:1794
This represents a decl that may have a name.
Definition Decl.h:274
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
Definition Decl.h:340
NamedDecl * getMostRecentDecl()
Definition Decl.h:501
SourceLocation getBeginLoc() const
Definition ExprObjC.h:1751
VersionTuple getVersion() const
Definition ExprObjC.h:1757
Represents an ObjC class declaration.
Definition DeclObjC.h:1154
ObjCMethodDecl * lookupInstanceMethod(Selector Sel) const
Lookup an instance method for a given selector.
Definition DeclObjC.h:1847
QualType getClassReceiver() const
Returns the type of a class message send, or NULL if the message is not a class message.
Definition ExprObjC.h:1318
const ObjCMethodDecl * getMethodDecl() const
Definition ExprObjC.h:1395
SourceLocation getEndLoc() const LLVM_READONLY
Definition ExprObjC.h:1490
SourceLocation getSelectorStartLoc() const
Definition ExprObjC.h:1458
ObjCMethodDecl - Represents an instance or class method declaration.
Definition DeclObjC.h:140
Represents one property declaration in an Objective-C interface.
Definition DeclObjC.h:731
static ObjCPropertyDecl * findPropertyDecl(const DeclContext *DC, const IdentifierInfo *propertyID, ObjCPropertyQueryKind queryKind)
Lookup a property by name in the specified DeclContext.
Definition DeclObjC.cpp:176
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
bool isMacroDefined(StringRef Id)
StringRef getImmediateMacroName(SourceLocation Loc)
Retrieve the name of the immediate macro expansion.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition TypeBase.h:1004
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition TypeBase.h:8436
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)
Emit a diagnostic.
Definition SemaBase.cpp:61
bool shouldDelayDiagnostics()
Determines whether diagnostics should be delayed.
Definition Sema.h:1398
void add(const sema::DelayedDiagnostic &diag)
Adds a delayed diagnostic.
Sema - This implements semantic analysis and AST building for C.
Definition Sema.h:868
SmallVector< sema::FunctionScopeInfo *, 4 > FunctionScopes
Stack containing information about each of the nested function, block, and method scopes that are cur...
Definition Sema.h:1244
Preprocessor & getPreprocessor() const
Definition Sema.h:938
const ExpressionEvaluationContextRecord & currentEvaluationContext() const
Definition Sema.h:7010
class clang::Sema::DelayedDiagnostics DelayedDiagnostics
FunctionDecl * getCurFunctionDecl(bool AllowLambda=false) const
Returns a pointer to the innermost enclosing function, or nullptr if the current context is not insid...
Definition Sema.cpp:1725
ASTContext & Context
Definition Sema.h:1308
DiagnosticsEngine & getDiagnostics() const
Definition Sema.h:936
SemaObjC & ObjC()
Definition Sema.h:1518
ASTContext & getASTContext() const
Definition Sema.h:939
void DiagnoseUnguardedAvailabilityViolations(Decl *FD)
Issue any -Wunguarded-availability warnings in FD.
SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset=0)
Calls Lexer::getLocForEndOfToken()
Definition Sema.cpp:84
const LangOptions & getLangOpts() const
Definition Sema.h:932
DeclContext * getCurLexicalContext() const
Definition Sema.h:1145
SourceManager & getSourceManager() const
Definition Sema.h:937
void DiagnoseAvailabilityOfDecl(NamedDecl *D, ArrayRef< SourceLocation > Locs, const ObjCInterfaceDecl *UnknownObjCClass, bool ObjCPropertyAccess, bool AvoidPartialAvailabilityChecks, ObjCInterfaceDecl *ClassReceiver)
std::pair< AvailabilityResult, const NamedDecl * > ShouldDiagnoseAvailabilityOfDecl(const NamedDecl *D, std::string *Message, ObjCInterfaceDecl *ClassReceiver)
The diagnostic we should emit for D, and the declaration that originated it, or AR_Available.
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 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.
Stmt - This represents one statement.
Definition Stmt.h:86
StmtClass getStmtClass() const
Definition Stmt.h:1499
SourceLocation getBeginLoc() const LLVM_READONLY
Definition Stmt.cpp:355
Represents the declaration of a struct/union/class/enum.
Definition Decl.h:3732
TagDecl * getDefinitionOrSelf() const
Definition Decl.h:3915
Exposes information about the current target.
Definition TargetInfo.h:227
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
StringRef getPlatformName() const
Retrieve the name of the platform as it is used in the availability attribute.
VersionTuple getPlatformMinVersion() const
Retrieve the minimum desired version of the platform, to which the program should be compiled.
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:227
SourceLocation getBeginLoc() const
Get the begin source location.
Definition TypeLoc.cpp:193
const Type * getTypePtr() const
Definition TypeLoc.h:137
The base class of the type hierarchy.
Definition TypeBase.h:1871
QualType getLocallyUnqualifiedSingleStepDesugaredType() const
Pull a single level of sugar off of this locally-unqualified type.
Definition Type.cpp:558
const ObjCObjectType * getAsObjCInterfaceType() const
Definition Type.cpp:1942
Base class for declarations which introduce a typedef-name.
Definition Decl.h:3577
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
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.
std::variant< struct RequiresDecl, struct HeaderDecl, struct UmbrellaDirDecl, struct ModuleDecl, struct ExcludeDecl, struct ExportDecl, struct ExportAsDecl, struct ExternModuleDecl, struct UseDecl, struct LinkDecl, struct ConfigMacrosDecl, struct ConflictDecl > Decl
All declarations that can appear in a module declaration.
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
@ 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.
Definition TypeBase.h:905
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
DynamicRecursiveASTVisitorBase< false > DynamicRecursiveASTVisitor
U cast(CodeGen::Address addr)
Definition Address.h:327
@ Interface
The "__interface" keyword introduces the elaborated-type-specifier.
Definition TypeBase.h:5966
bool IsCaseExpr
Whether evaluating an expression for a switch case label.
Definition Sema.h:6935