clang 24.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 =
118 T->getLocallyUnqualifiedSingleStepDesugaredType().getTypePtr();
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 // Don't emit deprecated warnings when defining special member functions.
216 if (const auto *FD = dyn_cast<FunctionDecl>(C); FD && FD->isDefaulted())
217 return true;
218 } else if (K == AR_Unavailable) {
219 // It is perfectly fine to refer to an 'unavailable' Objective-C method
220 // when it is referenced from within the @implementation itself. In this
221 // context, we interpret unavailable as a form of access control.
222 if (const auto *MD = dyn_cast<ObjCMethodDecl>(OffendingDecl)) {
223 if (const auto *Impl = dyn_cast<ObjCImplDecl>(C)) {
224 if (MD->getClassInterface() == Impl->getClassInterface())
225 return true;
226 }
227 }
228 }
229
230 if (C->isUnavailable())
231 return true;
232 return false;
233 };
234
235 do {
236 if (CheckContext(Ctx))
237 return false;
238
239 // An implementation implicitly has the availability of the interface.
240 // Unless it is "+load" method.
241 if (const auto *MethodD = dyn_cast<ObjCMethodDecl>(Ctx))
242 if (MethodD->isClassMethod() &&
243 MethodD->getSelector().getAsString() == "load")
244 return true;
245
246 if (const auto *CatOrImpl = dyn_cast<ObjCImplDecl>(Ctx)) {
247 if (const ObjCInterfaceDecl *Interface = CatOrImpl->getClassInterface())
248 if (CheckContext(Interface))
249 return false;
250 }
251 // A category implicitly has the availability of the interface.
252 else if (const auto *CatD = dyn_cast<ObjCCategoryDecl>(Ctx))
253 if (const ObjCInterfaceDecl *Interface = CatD->getClassInterface())
254 if (CheckContext(Interface))
255 return false;
256 } while ((Ctx = cast_or_null<Decl>(Ctx->getDeclContext())));
257
258 return true;
259}
260
262 const ASTContext &Context, const VersionTuple &DeploymentVersion,
263 const VersionTuple &DeclVersion, bool HasMatchingEnv) {
264 const auto &Triple = Context.getTargetInfo().getTriple();
265 VersionTuple ForceAvailabilityFromVersion;
266 switch (Triple.getOS()) {
267 // For iOS, emit the diagnostic even if -Wunguarded-availability is
268 // not specified for deployment targets >= to iOS 11 or equivalent or
269 // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or
270 // later.
271 case llvm::Triple::IOS:
272 case llvm::Triple::TvOS:
273 ForceAvailabilityFromVersion = VersionTuple(/*Major=*/11);
274 break;
275 case llvm::Triple::WatchOS:
276 ForceAvailabilityFromVersion = VersionTuple(/*Major=*/4);
277 break;
278 case llvm::Triple::Darwin:
279 case llvm::Triple::MacOSX:
280 ForceAvailabilityFromVersion = VersionTuple(/*Major=*/10, /*Minor=*/13);
281 break;
282 // For HLSL, use diagnostic from HLSLAvailability group which
283 // are reported as errors by default and in strict diagnostic mode
284 // (-fhlsl-strict-availability) and as warnings in relaxed diagnostic
285 // mode (-Wno-error=hlsl-availability)
286 case llvm::Triple::ShaderModel:
287 return HasMatchingEnv ? diag::warn_hlsl_availability
288 : diag::warn_hlsl_availability_unavailable;
289 default:
290 // New Apple targets should always warn about availability.
291 ForceAvailabilityFromVersion =
292 (Triple.getVendor() == llvm::Triple::Apple)
293 ? VersionTuple(/*Major=*/0, 0)
294 : VersionTuple(/*Major=*/(unsigned)-1, (unsigned)-1);
295 }
296 if (DeploymentVersion >= ForceAvailabilityFromVersion ||
297 DeclVersion >= ForceAvailabilityFromVersion)
298 return HasMatchingEnv ? diag::warn_unguarded_availability_new
299 : diag::warn_unguarded_availability_unavailable_new;
300 return HasMatchingEnv ? diag::warn_unguarded_availability
301 : diag::warn_unguarded_availability_unavailable;
302}
303
305 for (Decl *Ctx = OrigCtx; Ctx;
306 Ctx = cast_or_null<Decl>(Ctx->getDeclContext())) {
307 if (isa<TagDecl>(Ctx) || isa<FunctionDecl>(Ctx) || isa<ObjCMethodDecl>(Ctx))
308 return cast<NamedDecl>(Ctx);
309 if (auto *CD = dyn_cast<ObjCContainerDecl>(Ctx)) {
310 if (auto *Imp = dyn_cast<ObjCImplDecl>(Ctx))
311 return Imp->getClassInterface();
312 return CD;
313 }
314 }
315
316 return dyn_cast<NamedDecl>(OrigCtx);
317}
318
319namespace {
320
321struct AttributeInsertion {
322 StringRef Prefix;
323 SourceLocation Loc;
324 StringRef Suffix;
325
326 static AttributeInsertion createInsertionAfter(const NamedDecl *D) {
327 return {" ", D->getEndLoc(), ""};
328 }
329 static AttributeInsertion createInsertionAfter(SourceLocation Loc) {
330 return {" ", Loc, ""};
331 }
332 static AttributeInsertion createInsertionBefore(const NamedDecl *D) {
333 return {"", D->getBeginLoc(), "\n"};
334 }
335};
336
337} // end anonymous namespace
338
339/// Tries to parse a string as ObjC method name.
340///
341/// \param Name The string to parse. Expected to originate from availability
342/// attribute argument.
343/// \param SlotNames The vector that will be populated with slot names. In case
344/// of unsuccessful parsing can contain invalid data.
345/// \returns A number of method parameters if parsing was successful,
346/// std::nullopt otherwise.
347static std::optional<unsigned>
349 const LangOptions &LangOpts) {
350 // Accept replacements starting with - or + as valid ObjC method names.
351 if (!Name.empty() && (Name.front() == '-' || Name.front() == '+'))
352 Name = Name.drop_front(1);
353 if (Name.empty())
354 return std::nullopt;
355 Name.split(SlotNames, ':');
356 unsigned NumParams;
357 if (Name.back() == ':') {
358 // Remove an empty string at the end that doesn't represent any slot.
359 SlotNames.pop_back();
360 NumParams = SlotNames.size();
361 } else {
362 if (SlotNames.size() != 1)
363 // Not a valid method name, just a colon-separated string.
364 return std::nullopt;
365 NumParams = 0;
366 }
367 // Verify all slot names are valid.
368 bool AllowDollar = LangOpts.DollarIdents;
369 for (StringRef S : SlotNames) {
370 if (S.empty())
371 continue;
372 if (!isValidAsciiIdentifier(S, AllowDollar))
373 return std::nullopt;
374 }
375 return NumParams;
376}
377
378/// Returns a source location in which it's appropriate to insert a new
379/// attribute for the given declaration \D.
380static std::optional<AttributeInsertion>
382 const LangOptions &LangOpts) {
384 return AttributeInsertion::createInsertionAfter(D);
385 if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
386 if (MD->hasBody())
387 return std::nullopt;
388 return AttributeInsertion::createInsertionAfter(D);
389 }
390 if (const auto *TD = dyn_cast<TagDecl>(D)) {
391 SourceLocation Loc =
392 Lexer::getLocForEndOfToken(TD->getInnerLocStart(), 0, SM, LangOpts);
393 if (Loc.isInvalid())
394 return std::nullopt;
395 // Insert after the 'struct'/whatever keyword.
396 return AttributeInsertion::createInsertionAfter(Loc);
397 }
398 return AttributeInsertion::createInsertionBefore(D);
399}
400
401/// Actually emit an availability diagnostic for a reference to an unavailable
402/// decl.
403///
404/// \param Ctx The context that the reference occurred in
405/// \param ReferringDecl The exact declaration that was referenced.
406/// \param OffendingDecl A related decl to \c ReferringDecl that has an
407/// availability attribute corresponding to \c K attached to it. Note that this
408/// may not be the same as ReferringDecl, i.e. if an EnumDecl is annotated and
409/// we refer to a member EnumConstantDecl, ReferringDecl is the EnumConstantDecl
410/// and OffendingDecl is the EnumDecl.
412 Decl *Ctx, const NamedDecl *ReferringDecl,
413 const NamedDecl *OffendingDecl,
414 StringRef Message,
416 const ObjCInterfaceDecl *UnknownObjCClass,
417 const ObjCPropertyDecl *ObjCProperty,
418 bool ObjCPropertyAccess) {
419 // Diagnostics for deprecated or unavailable.
420 unsigned diag, diag_message, diag_fwdclass_message;
421 unsigned diag_available_here = diag::note_availability_specified_here;
422 SourceLocation NoteLocation = OffendingDecl->getLocation();
423
424 // Matches 'diag::note_property_attribute' options.
425 unsigned property_note_select;
426
427 // Matches diag::note_availability_specified_here.
428 unsigned available_here_select_kind;
429
430 VersionTuple DeclVersion;
431 const AvailabilityAttr *AA = getAttrForPlatform(S.Context, OffendingDecl);
432 const IdentifierInfo *IIEnv = nullptr;
433 if (AA) {
434 DeclVersion = AA->getEffectiveIntroduced();
435 IIEnv = AA->getEffectiveEnvironment();
436 }
437
438 if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, IIEnv, Ctx,
439 OffendingDecl))
440 return;
441
442 SourceLocation Loc = Locs.front();
443
444 // The declaration can have multiple availability attributes, we are looking
445 // at one of them.
446 if (AA && AA->isInherited()) {
447 for (const Decl *Redecl = OffendingDecl->getMostRecentDecl(); Redecl;
448 Redecl = Redecl->getPreviousDecl()) {
449 const AvailabilityAttr *AForRedecl =
450 getAttrForPlatform(S.Context, Redecl);
451 if (AForRedecl && !AForRedecl->isInherited()) {
452 // If D is a declaration with inherited attributes, the note should
453 // point to the declaration with actual attributes.
454 NoteLocation = Redecl->getLocation();
455 break;
456 }
457 }
458 }
459
460 switch (K) {
461 case AR_NotYetIntroduced: {
462 // We would like to emit the diagnostic even if -Wunguarded-availability is
463 // not specified for deployment targets >= to iOS 11 or equivalent or
464 // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or
465 // later.
466 assert(AA != nullptr && "expecting valid availability attribute");
467 VersionTuple Introduced = AA->getEffectiveIntroduced();
468 bool EnvironmentMatchesOrNone =
469 hasMatchingEnvironmentOrNone(S.getASTContext(), AA->getEffectiveAttr());
470
471 const TargetInfo &TI = S.getASTContext().getTargetInfo();
472 std::string PlatformName(
473 AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName()));
474 llvm::StringRef TargetEnvironment(
475 llvm::Triple::getEnvironmentTypeName(TI.getTriple().getEnvironment()));
476 llvm::StringRef AttrEnvironment =
477 AA->getEnvironment() ? AA->getEnvironment()->getName() : "";
478 bool UseEnvironment =
479 (!AttrEnvironment.empty() && !TargetEnvironment.empty());
480
481 unsigned DiagKind = getAvailabilityDiagnosticKind(
483 Introduced, EnvironmentMatchesOrNone);
484
485 S.Diag(Loc, DiagKind) << OffendingDecl << PlatformName
486 << Introduced.getAsString() << UseEnvironment
487 << TargetEnvironment;
488
489 S.Diag(OffendingDecl->getLocation(),
490 diag::note_partial_availability_specified_here)
491 << OffendingDecl << PlatformName << Introduced.getAsString()
492 << S.Context.getTargetInfo().getPlatformMinVersion().getAsString()
493 << UseEnvironment << AttrEnvironment << TargetEnvironment;
494
495 // Do not offer to silence the warning or fixits for HLSL
496 if (S.getLangOpts().HLSL)
497 return;
498
499 if (const auto *Enclosing = findEnclosingDeclToAnnotate(Ctx)) {
500 if (const auto *TD = dyn_cast<TagDecl>(Enclosing))
501 if (TD->getDeclName().isEmpty()) {
502 S.Diag(TD->getLocation(),
503 diag::note_decl_unguarded_availability_silence)
504 << /*Anonymous*/ 1 << TD->getKindName();
505 return;
506 }
507 auto FixitNoteDiag =
508 S.Diag(Enclosing->getLocation(),
509 diag::note_decl_unguarded_availability_silence)
510 << /*Named*/ 0 << Enclosing;
511 // Don't offer a fixit for declarations with availability attributes.
512 if (Enclosing->hasAttr<AvailabilityAttr>())
513 return;
515 if (!PP.isMacroDefined("API_AVAILABLE"))
516 return;
517 std::optional<AttributeInsertion> Insertion = createAttributeInsertion(
518 Enclosing, S.getSourceManager(), S.getLangOpts());
519 if (!Insertion)
520 return;
521 StringRef PlatformName =
523
524 // Apple's API_AVAILABLE macro expands roughly like this.
525 // API_AVAILABLE(ios(17.0))
526 // __attribute__((availability(__API_AVAILABLE_PLATFORM_ios(17.0)))
527 // __attribute__((availability(ios,introduced=17.0)))
528 // In order to figure out which platform name to use in the API_AVAILABLE
529 // macro, the associated __API_AVAILABLE_PLATFORM_ macro needs to be
530 // found. The __API_AVAILABLE_PLATFORM_ macros aren't consistent about
531 // using the canonical platform name, source spelling name, or one of the
532 // other supported names (i.e. one of the keys in canonicalizePlatformName
533 // that's neither). Check all of the supported names for a match.
534 std::vector<StringRef> EquivalentPlatforms =
535 AvailabilityAttr::equivalentPlatformNames(PlatformName);
536 llvm::Twine MacroPrefix = "__API_AVAILABLE_PLATFORM_";
537 auto AvailablePlatform =
538 llvm::find_if(EquivalentPlatforms, [&](StringRef EquivalentPlatform) {
539 return PP.isMacroDefined((MacroPrefix + EquivalentPlatform).str());
540 });
541 if (AvailablePlatform == EquivalentPlatforms.end())
542 return;
543 std::string Introduced =
544 OffendingDecl->getVersionIntroduced().getAsString();
545 FixitNoteDiag << FixItHint::CreateInsertion(
546 Insertion->Loc,
547 (llvm::Twine(Insertion->Prefix) + "API_AVAILABLE(" +
548 *AvailablePlatform + "(" + Introduced + "))" + Insertion->Suffix)
549 .str());
550 }
551 return;
552 }
553 case AR_Deprecated:
554 if (ObjCPropertyAccess)
555 diag = diag::warn_property_method_deprecated;
557 diag = diag::warn_deprecated_switch_case;
558 else
559 diag = diag::warn_deprecated;
560
561 diag_message = diag::warn_deprecated_message;
562 diag_fwdclass_message = diag::warn_deprecated_fwdclass_message;
563 property_note_select = /* deprecated */ 0;
564 available_here_select_kind = /* deprecated */ 2;
565 if (const auto *AL = OffendingDecl->getAttr<DeprecatedAttr>())
566 NoteLocation = AL->getLocation();
567 break;
568
569 case AR_Unavailable:
570 diag = !ObjCPropertyAccess ? diag::err_unavailable
571 : diag::err_property_method_unavailable;
572 diag_message = diag::err_unavailable_message;
573 diag_fwdclass_message = diag::warn_unavailable_fwdclass_message;
574 property_note_select = /* unavailable */ 1;
575 available_here_select_kind = /* unavailable */ 0;
576
577 if (auto AL = OffendingDecl->getAttr<UnavailableAttr>()) {
578 if (AL->isImplicit() && AL->getImplicitReason()) {
579 // Most of these failures are due to extra restrictions in ARC;
580 // reflect that in the primary diagnostic when applicable.
581 auto flagARCError = [&] {
582 if (S.getLangOpts().ObjCAutoRefCount &&
584 OffendingDecl->getLocation()))
585 diag = diag::err_unavailable_in_arc;
586 };
587
588 switch (AL->getImplicitReason()) {
589 case UnavailableAttr::IR_None: break;
590
591 case UnavailableAttr::IR_ARCForbiddenType:
592 flagARCError();
593 diag_available_here = diag::note_arc_forbidden_type;
594 break;
595
596 case UnavailableAttr::IR_ForbiddenWeak:
597 if (S.getLangOpts().ObjCWeakRuntime)
598 diag_available_here = diag::note_arc_weak_disabled;
599 else
600 diag_available_here = diag::note_arc_weak_no_runtime;
601 break;
602
603 case UnavailableAttr::IR_ARCForbiddenConversion:
604 flagARCError();
605 diag_available_here = diag::note_performs_forbidden_arc_conversion;
606 break;
607
608 case UnavailableAttr::IR_ARCInitReturnsUnrelated:
609 flagARCError();
610 diag_available_here = diag::note_arc_init_returns_unrelated;
611 break;
612
613 case UnavailableAttr::IR_ARCFieldWithOwnership:
614 flagARCError();
615 diag_available_here = diag::note_arc_field_with_ownership;
616 break;
617 }
618 }
619 }
620 break;
621
622 case AR_Available:
623 llvm_unreachable("Warning for availability of available declaration?");
624 }
625
627 if (K == AR_Deprecated) {
628 StringRef Replacement;
629 if (auto AL = OffendingDecl->getAttr<DeprecatedAttr>())
630 Replacement = AL->getReplacement();
631 if (auto AL = getAttrForPlatform(S.Context, OffendingDecl))
632 Replacement = AL->getReplacement();
633
634 CharSourceRange UseRange;
635 if (!Replacement.empty())
636 UseRange =
638 if (UseRange.isValid()) {
639 if (const auto *MethodDecl = dyn_cast<ObjCMethodDecl>(ReferringDecl)) {
640 Selector Sel = MethodDecl->getSelector();
641 SmallVector<StringRef, 12> SelectorSlotNames;
642 std::optional<unsigned> NumParams = tryParseObjCMethodName(
643 Replacement, SelectorSlotNames, S.getLangOpts());
644 if (NumParams && *NumParams == Sel.getNumArgs()) {
645 assert(SelectorSlotNames.size() == Locs.size());
646 for (unsigned I = 0; I < Locs.size(); ++I) {
647 if (!Sel.getNameForSlot(I).empty()) {
649 Locs[I], S.getLocForEndOfToken(Locs[I]));
650 FixIts.push_back(FixItHint::CreateReplacement(
651 NameRange, SelectorSlotNames[I]));
652 } else
653 FixIts.push_back(
654 FixItHint::CreateInsertion(Locs[I], SelectorSlotNames[I]));
655 }
656 } else
657 FixIts.push_back(FixItHint::CreateReplacement(UseRange, Replacement));
658 } else
659 FixIts.push_back(FixItHint::CreateReplacement(UseRange, Replacement));
660 }
661 }
662
663 // We emit deprecation warning for deprecated specializations
664 // when their instantiation stacks originate outside
665 // of a system header, even if the diagnostics is suppresed at the
666 // point of definition.
667 SourceLocation InstantiationLoc =
668 S.getTopMostPointOfInstantiation(ReferringDecl);
669 bool ShouldAllowWarningInSystemHeader =
670 InstantiationLoc != Loc &&
671 !S.getSourceManager().isInSystemHeader(InstantiationLoc);
672 ForceSystemWarningsRAII SystemWarningOverrideRAII(
673 S.getDiagnostics(), ShouldAllowWarningInSystemHeader);
674
675 if (!Message.empty()) {
676 S.Diag(Loc, diag_message) << ReferringDecl << Message << FixIts;
677 if (ObjCProperty)
678 S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
679 << ObjCProperty->getDeclName() << property_note_select;
680 } else if (!UnknownObjCClass) {
681 S.Diag(Loc, diag) << ReferringDecl << FixIts;
682 if (ObjCProperty)
683 S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
684 << ObjCProperty->getDeclName() << property_note_select;
685 } else {
686 S.Diag(Loc, diag_fwdclass_message) << ReferringDecl << FixIts;
687 S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class);
688 }
689
690 S.Diag(NoteLocation, diag_available_here)
691 << OffendingDecl << available_here_select_kind;
692}
693
696 "Expected an availability diagnostic here");
697
698 DD.Triggered = true;
703 DD.getObjCProperty(), false);
704}
705
707 const NamedDecl *ReferringDecl,
708 const NamedDecl *OffendingDecl,
709 StringRef Message,
711 const ObjCInterfaceDecl *UnknownObjCClass,
712 const ObjCPropertyDecl *ObjCProperty,
713 bool ObjCPropertyAccess) {
714 // Delay if we're currently parsing a declaration.
718 AR, Locs, ReferringDecl, OffendingDecl, UnknownObjCClass,
719 ObjCProperty, Message, ObjCPropertyAccess));
720 return;
721 }
722
724 DoEmitAvailabilityWarning(S, AR, Ctx, ReferringDecl, OffendingDecl,
725 Message, Locs, UnknownObjCClass, ObjCProperty,
726 ObjCPropertyAccess);
727}
728
729namespace {
730
731/// Returns true if the given statement can be a body-like child of \p Parent.
732bool isBodyLikeChildStmt(const Stmt *S, const Stmt *Parent) {
733 switch (Parent->getStmtClass()) {
734 case Stmt::IfStmtClass:
735 return cast<IfStmt>(Parent)->getThen() == S ||
736 cast<IfStmt>(Parent)->getElse() == S;
737 case Stmt::WhileStmtClass:
738 return cast<WhileStmt>(Parent)->getBody() == S;
739 case Stmt::DoStmtClass:
740 return cast<DoStmt>(Parent)->getBody() == S;
741 case Stmt::ForStmtClass:
742 return cast<ForStmt>(Parent)->getBody() == S;
743 case Stmt::CXXForRangeStmtClass:
744 return cast<CXXForRangeStmt>(Parent)->getBody() == S;
745 case Stmt::ObjCForCollectionStmtClass:
746 return cast<ObjCForCollectionStmt>(Parent)->getBody() == S;
747 case Stmt::CaseStmtClass:
748 case Stmt::DefaultStmtClass:
749 return cast<SwitchCase>(Parent)->getSubStmt() == S;
750 default:
751 return false;
752 }
753}
754
755class StmtUSEFinder : public DynamicRecursiveASTVisitor {
756 const Stmt *Target;
757
758public:
759 bool VisitStmt(Stmt *S) override { return S != Target; }
760
761 /// Returns true if the given statement is present in the given declaration.
762 static bool isContained(const Stmt *Target, const Decl *D) {
763 StmtUSEFinder Visitor;
764 Visitor.Target = Target;
765 return !Visitor.TraverseDecl(const_cast<Decl *>(D));
766 }
767};
768
769/// Traverses the AST and finds the last statement that used a given
770/// declaration.
771class LastDeclUSEFinder : public DynamicRecursiveASTVisitor {
772 const Decl *D;
773
774public:
775 bool VisitDeclRefExpr(DeclRefExpr *DRE) override {
776 if (DRE->getDecl() == D)
777 return false;
778 return true;
779 }
780
781 static const Stmt *findLastStmtThatUsesDecl(const Decl *D,
782 const CompoundStmt *Scope) {
783 LastDeclUSEFinder Visitor;
784 Visitor.D = D;
785 for (const Stmt *S : llvm::reverse(Scope->body())) {
786 if (!Visitor.TraverseStmt(const_cast<Stmt *>(S)))
787 return S;
788 }
789 return nullptr;
790 }
791};
792
793/// This class implements -Wunguarded-availability.
794///
795/// This is done with a traversal of the AST of a function that makes reference
796/// to a partially available declaration. Whenever we encounter an \c if of the
797/// form: \c if(@available(...)), we use the version from the condition to visit
798/// the then statement.
799class DiagnoseUnguardedAvailability : public DynamicRecursiveASTVisitor {
800 Sema &SemaRef;
801 Decl *Ctx;
802
803 /// Stack of potentially nested 'if (@available(...))'s.
804 SmallVector<VersionTuple, 8> AvailabilityStack;
805 SmallVector<const Stmt *, 16> StmtStack;
806
807 void DiagnoseDeclAvailability(NamedDecl *D, SourceRange Range,
808 ObjCInterfaceDecl *ClassReceiver = nullptr);
809
810public:
811 DiagnoseUnguardedAvailability(Sema &SemaRef, Decl *Ctx)
812 : SemaRef(SemaRef), Ctx(Ctx) {
813 AvailabilityStack.push_back(
815 }
816
817 bool TraverseStmt(Stmt *S) override {
818 if (!S)
819 return true;
820 StmtStack.push_back(S);
822 StmtStack.pop_back();
823 return Result;
824 }
825
826 void IssueDiagnostics(Stmt *S) { TraverseStmt(S); }
827
828 bool TraverseIfStmt(IfStmt *If) override;
829
830 // for 'case X:' statements, don't bother looking at the 'X'; it can't lead
831 // to any useful diagnostics.
832 bool TraverseCaseStmt(CaseStmt *CS) override {
833 return TraverseStmt(CS->getSubStmt());
834 }
835
836 bool VisitObjCMessageExpr(ObjCMessageExpr *Msg) override {
837 if (ObjCMethodDecl *D = Msg->getMethodDecl()) {
838 ObjCInterfaceDecl *ID = nullptr;
839 QualType ReceiverTy = Msg->getClassReceiver();
840 if (!ReceiverTy.isNull() && ReceiverTy->getAsObjCInterfaceType())
841 ID = ReceiverTy->getAsObjCInterfaceType()->getInterface();
842
843 DiagnoseDeclAvailability(
844 D, SourceRange(Msg->getSelectorStartLoc(), Msg->getEndLoc()), ID);
845 }
846 return true;
847 }
848
849 bool VisitDeclRefExpr(DeclRefExpr *DRE) override {
850 DiagnoseDeclAvailability(DRE->getDecl(),
851 SourceRange(DRE->getBeginLoc(), DRE->getEndLoc()));
852 return true;
853 }
854
855 bool VisitMemberExpr(MemberExpr *ME) override {
856 DiagnoseDeclAvailability(ME->getMemberDecl(),
857 SourceRange(ME->getBeginLoc(), ME->getEndLoc()));
858 return true;
859 }
860
861 bool VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *E) override {
862 SemaRef.Diag(E->getBeginLoc(), diag::warn_at_available_unchecked_use)
863 << (!SemaRef.getLangOpts().ObjC);
864 return true;
865 }
866
867 bool VisitTypeLoc(TypeLoc Ty) override;
868};
869
870void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability(
871 NamedDecl *D, SourceRange Range, ObjCInterfaceDecl *ReceiverClass) {
873 const NamedDecl *OffendingDecl;
874 std::tie(Result, OffendingDecl) =
875 SemaRef.ShouldDiagnoseAvailabilityOfDecl(D, nullptr, ReceiverClass);
876 if (Result != AR_Available) {
877 // All other diagnostic kinds have already been handled in
878 // DiagnoseAvailabilityOfDecl.
880 return;
881
882 const AvailabilityAttr *AA =
883 getAttrForPlatform(SemaRef.getASTContext(), OffendingDecl);
884 assert(AA != nullptr && "expecting valid availability attribute");
885 bool EnvironmentMatchesOrNone = hasMatchingEnvironmentOrNone(
886 SemaRef.getASTContext(), AA->getEffectiveAttr());
887 VersionTuple Introduced = AA->getEffectiveIntroduced();
888
889 if (EnvironmentMatchesOrNone && AvailabilityStack.back() >= Introduced)
890 return;
891
892 // If the context of this function is less available than D, we should not
893 // emit a diagnostic.
894 if (!ShouldDiagnoseAvailabilityInContext(SemaRef, Result, Introduced,
895 AA->getEffectiveEnvironment(), Ctx,
896 OffendingDecl))
897 return;
898
899 const TargetInfo &TI = SemaRef.getASTContext().getTargetInfo();
900 std::string PlatformName(
901 AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName()));
902 llvm::StringRef TargetEnvironment(TI.getTriple().getEnvironmentName());
903 llvm::StringRef AttrEnvironment =
904 AA->getEnvironment() ? AA->getEnvironment()->getName() : "";
905 bool UseEnvironment =
906 (!AttrEnvironment.empty() && !TargetEnvironment.empty());
907
908 unsigned DiagKind = getAvailabilityDiagnosticKind(
909 SemaRef.Context,
910 SemaRef.Context.getTargetInfo().getPlatformMinVersion(), Introduced,
911 EnvironmentMatchesOrNone);
912
913 SemaRef.Diag(Range.getBegin(), DiagKind)
914 << Range << D << PlatformName << Introduced.getAsString()
915 << UseEnvironment << TargetEnvironment;
916
917 SemaRef.Diag(OffendingDecl->getLocation(),
918 diag::note_partial_availability_specified_here)
919 << OffendingDecl << PlatformName << Introduced.getAsString()
920 << SemaRef.Context.getTargetInfo().getPlatformMinVersion().getAsString()
921 << UseEnvironment << AttrEnvironment << TargetEnvironment;
922
923 // Do not offer to silence the warning or fixits for HLSL
924 if (SemaRef.getLangOpts().HLSL)
925 return;
926
927 auto FixitDiag =
928 SemaRef.Diag(Range.getBegin(), diag::note_unguarded_available_silence)
929 << Range << D
930 << (SemaRef.getLangOpts().ObjC ? /*@available*/ 0
931 : /*__builtin_available*/ 1);
932
933 // Find the statement which should be enclosed in the if @available check.
934 if (StmtStack.empty())
935 return;
936 const Stmt *StmtOfUse = StmtStack.back();
937 const CompoundStmt *Scope = nullptr;
938 for (const Stmt *S : llvm::reverse(StmtStack)) {
939 if (const auto *CS = dyn_cast<CompoundStmt>(S)) {
940 Scope = CS;
941 break;
942 }
943 if (isBodyLikeChildStmt(StmtOfUse, S)) {
944 // The declaration won't be seen outside of the statement, so we don't
945 // have to wrap the uses of any declared variables in if (@available).
946 // Therefore we can avoid setting Scope here.
947 break;
948 }
949 StmtOfUse = S;
950 }
951 const Stmt *LastStmtOfUse = nullptr;
952 if (isa<DeclStmt>(StmtOfUse) && Scope) {
953 for (const Decl *D : cast<DeclStmt>(StmtOfUse)->decls()) {
954 if (StmtUSEFinder::isContained(StmtStack.back(), D)) {
955 LastStmtOfUse = LastDeclUSEFinder::findLastStmtThatUsesDecl(D, Scope);
956 break;
957 }
958 }
959 }
960
961 const SourceManager &SM = SemaRef.getSourceManager();
962 SourceLocation IfInsertionLoc =
963 SM.getExpansionLoc(StmtOfUse->getBeginLoc());
964 SourceLocation StmtEndLoc =
966 (LastStmtOfUse ? LastStmtOfUse : StmtOfUse)->getEndLoc())
967 .getEnd();
968 if (SM.getFileID(IfInsertionLoc) != SM.getFileID(StmtEndLoc))
969 return;
970
971 StringRef Indentation = Lexer::getIndentationForLine(IfInsertionLoc, SM);
972 const char *ExtraIndentation = " ";
973 std::string FixItString;
974 llvm::raw_string_ostream FixItOS(FixItString);
975 StringRef FixItPlatformName;
976 VersionTuple FixItVersion;
977
978 if (AA->getInferredAttr()) {
979 FixItPlatformName = "anyAppleOS";
980 FixItVersion = AA->getIntroduced();
981 } else {
982 FixItPlatformName = AvailabilityAttr::getPlatformNameSourceSpelling(
984 FixItVersion = AA->getEffectiveIntroduced();
985 }
986 FixItOS << "if ("
987 << (SemaRef.getLangOpts().ObjC ? "@available"
988 : "__builtin_available")
989 << "(" << FixItPlatformName << " " << FixItVersion.getAsString()
990 << ", *)) {\n"
991 << Indentation << ExtraIndentation;
992 FixitDiag << FixItHint::CreateInsertion(IfInsertionLoc, FixItOS.str());
994 StmtEndLoc, tok::semi, SM, SemaRef.getLangOpts(),
995 /*SkipTrailingWhitespaceAndNewLine=*/false);
996 if (ElseInsertionLoc.isInvalid())
997 ElseInsertionLoc =
998 Lexer::getLocForEndOfToken(StmtEndLoc, 0, SM, SemaRef.getLangOpts());
999 FixItOS.str().clear();
1000 FixItOS << "\n"
1001 << Indentation << "} else {\n"
1002 << Indentation << ExtraIndentation
1003 << "// Fallback on earlier versions\n"
1004 << Indentation << "}";
1005 FixitDiag << FixItHint::CreateInsertion(ElseInsertionLoc, FixItOS.str());
1006 }
1007}
1008
1009bool DiagnoseUnguardedAvailability::VisitTypeLoc(TypeLoc Ty) {
1010 const Type *TyPtr = Ty.getTypePtr();
1012
1013 if (Range.isInvalid())
1014 return true;
1015
1016 if (const auto *TT = dyn_cast<TagType>(TyPtr)) {
1017 TagDecl *TD = TT->getDecl()->getDefinitionOrSelf();
1018 DiagnoseDeclAvailability(TD, Range);
1019
1020 } else if (const auto *TD = dyn_cast<TypedefType>(TyPtr)) {
1021 TypedefNameDecl *D = TD->getDecl();
1022 DiagnoseDeclAvailability(D, Range);
1023
1024 } else if (const auto *ObjCO = dyn_cast<ObjCObjectType>(TyPtr)) {
1025 if (NamedDecl *D = ObjCO->getInterface())
1026 DiagnoseDeclAvailability(D, Range);
1027 }
1028
1029 return true;
1030}
1031
1032struct ExtractedAvailabilityExpr {
1033 const ObjCAvailabilityCheckExpr *E = nullptr;
1034 bool isNegated = false;
1035};
1036
1037ExtractedAvailabilityExpr extractAvailabilityExpr(const Expr *IfCond) {
1038 const auto *E = IfCond;
1039 bool IsNegated = false;
1040 while (true) {
1041 E = E->IgnoreParens();
1042 if (const auto *AE = dyn_cast<ObjCAvailabilityCheckExpr>(E)) {
1043 return ExtractedAvailabilityExpr{AE, IsNegated};
1044 }
1045
1046 const auto *UO = dyn_cast<UnaryOperator>(E);
1047 if (!UO || UO->getOpcode() != UO_LNot) {
1048 return ExtractedAvailabilityExpr{};
1049 }
1050 E = UO->getSubExpr();
1051 IsNegated = !IsNegated;
1052 }
1053}
1054
1055bool DiagnoseUnguardedAvailability::TraverseIfStmt(IfStmt *If) {
1056 Expr *Cond = If->getCond();
1057 if (!Cond)
1058 return DynamicRecursiveASTVisitor::TraverseIfStmt(If);
1059
1060 ExtractedAvailabilityExpr IfCond = extractAvailabilityExpr(Cond);
1061 if (!IfCond.E) {
1062 // This isn't an availability checking 'if', we can just continue.
1063 return DynamicRecursiveASTVisitor::TraverseIfStmt(If);
1064 }
1065
1066 VersionTuple CondVersion = IfCond.E->getVersion();
1067 // If we're using the '*' case here or if this check is redundant, then we
1068 // use the enclosing version to check both branches.
1069 if (CondVersion.empty() || CondVersion <= AvailabilityStack.back()) {
1070 return TraverseStmt(If->getThen()) && TraverseStmt(If->getElse());
1071 }
1072
1073 auto *Guarded = If->getThen();
1074 auto *Unguarded = If->getElse();
1075 if (IfCond.isNegated) {
1076 std::swap(Guarded, Unguarded);
1077 }
1078
1079 AvailabilityStack.push_back(CondVersion);
1080 bool ShouldContinue = TraverseStmt(Guarded);
1081 AvailabilityStack.pop_back();
1082
1083 return ShouldContinue && TraverseStmt(Unguarded);
1084}
1085
1086} // end anonymous namespace
1087
1089 Stmt *Body = nullptr;
1090
1091 if (auto *FD = D->getAsFunction()) {
1092 Body = FD->getBody();
1093
1094 if (auto *CD = dyn_cast<CXXConstructorDecl>(FD))
1095 for (const CXXCtorInitializer *CI : CD->inits())
1096 DiagnoseUnguardedAvailability(*this, D).IssueDiagnostics(CI->getInit());
1097
1098 } else if (auto *MD = dyn_cast<ObjCMethodDecl>(D))
1099 Body = MD->getBody();
1100 else if (auto *BD = dyn_cast<BlockDecl>(D))
1101 Body = BD->getBody();
1102
1103 assert(Body && "Need a body here!");
1104
1105 DiagnoseUnguardedAvailability(*this, D).IssueDiagnostics(Body);
1106}
1107
1109 if (FunctionScopes.empty())
1110 return nullptr;
1111
1112 // Conservatively search the entire current function scope context for
1113 // availability violations. This ensures we always correctly analyze nested
1114 // classes, blocks, lambdas, etc. that may or may not be inside if(@available)
1115 // checks themselves.
1116 return FunctionScopes.front();
1117}
1118
1121 const ObjCInterfaceDecl *UnknownObjCClass,
1122 bool ObjCPropertyAccess,
1123 bool AvoidPartialAvailabilityChecks,
1124 ObjCInterfaceDecl *ClassReceiver) {
1125
1126 std::string Message;
1128 const NamedDecl* OffendingDecl;
1129 // See if this declaration is unavailable, deprecated, or partial.
1130 std::tie(Result, OffendingDecl) =
1131 ShouldDiagnoseAvailabilityOfDecl(D, &Message, ClassReceiver);
1132 if (Result == AR_Available)
1133 return;
1134
1135 if (Result == AR_NotYetIntroduced) {
1136 if (AvoidPartialAvailabilityChecks)
1137 return;
1138
1139 // We need to know the @available context in the current function to
1140 // diagnose this use, let DiagnoseUnguardedAvailabilityViolations do that
1141 // when we're done parsing the current function.
1143 Context->HasPotentialAvailabilityViolations = true;
1144 return;
1145 }
1146 }
1147
1148 const ObjCPropertyDecl *ObjCPDecl = nullptr;
1149 if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
1150 if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) {
1151 AvailabilityResult PDeclResult = PD->getAvailability(nullptr);
1152 if (PDeclResult == Result)
1153 ObjCPDecl = PD;
1154 }
1155 }
1156
1157 EmitAvailabilityWarning(*this, Result, D, OffendingDecl, Message, Locs,
1158 UnknownObjCClass, ObjCPDecl, ObjCPropertyAccess);
1159}
1160
1163 DiagnoseAvailabilityOfDecl(D, Locs, /*UnknownObjCClass=*/nullptr,
1164 /*ObjCPropertyAccess=*/false,
1165 /*AvoidPartialAvailabilityChecks=*/false,
1166 /*ClassReceiver=*/nullptr);
1167}
Defines the C++ template declaration subclasses.
Defines the classes clang::DelayedDiagnostic and clang::AccessedEntity.
Defines the clang::IdentifierInfo, clang::IdentifierTable, and clang::Selector interfaces.
Result
Implement __builtin_bit_cast and related operations.
Defines the clang::LangOptions interface.
llvm::MachO::Target Target
Definition MachO.h:51
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:245
const TargetInfo & getTargetInfo() const
Definition ASTContext.h:971
Represents a C++ base or member initializer.
Definition DeclCXX.h:2407
Stmt * getSubStmt()
Definition Stmt.h:2045
Represents a byte-granular source range.
static CharSourceRange getCharRange(SourceRange R)
SourceLocation getEnd() const
CompoundStmt - This represents a group of statements like { stmt stmt }.
Definition Stmt.h:1752
body_range body()
Definition Stmt.h:1815
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition DeclBase.h:1468
ValueDecl * getDecl()
Definition Expr.h:1362
SourceLocation getEndLoc() const LLVM_READONLY
Definition Expr.cpp:561
SourceLocation getBeginLoc() const
Definition Expr.h:1373
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:1080
SourceLocation getEndLoc() const LLVM_READONLY
Definition DeclBase.h:445
T * getAttr() const
Definition DeclBase.h:583
AvailabilityResult getAvailability(std::string *Message=nullptr, VersionTuple EnclosingVersion=VersionTuple(), StringRef *RealizedPlatform=nullptr) const
Determine the availability of the given declaration.
Definition DeclBase.cpp:779
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:449
DeclContext * getDeclContext()
Definition DeclBase.h:458
attr_range attrs() const
Definition DeclBase.h:545
SourceLocation getBeginLoc() const LLVM_READONLY
Definition DeclBase.h:441
VersionTuple getVersionIntroduced() const
Retrieve the version of the target platform in which this declaration was introduced.
Definition DeclBase.cpp:832
virtual bool TraverseStmt(MaybeConst< Stmt > *S)
This represents one expression.
Definition Expr.h:113
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
Definition Expr.cpp:3125
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:140
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:103
RAII class that temporarily forces warnings in system headers and system macros to be shown on a Diag...
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:2271
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:1437
static StringRef getIndentationForLine(SourceLocation Loc, const SourceManager &SM)
Returns the leading whitespace for line that corresponds to the given location Loc.
Definition Lexer.cpp:1209
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:882
ValueDecl * getMemberDecl() const
Retrieve the member declaration to which this expression refers.
Definition Expr.h:3495
SourceLocation getEndLoc() const LLVM_READONLY
Definition Expr.cpp:1844
SourceLocation getBeginLoc() const LLVM_READONLY
Definition Expr.cpp:1830
This represents a decl that may have a name.
Definition Decl.h:275
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
Definition Decl.h:341
NamedDecl * getMostRecentDecl()
Definition Decl.h:502
SourceLocation getBeginLoc() const
Definition ExprObjC.h:1752
VersionTuple getVersion() const
Definition ExprObjC.h:1758
Represents an ObjC class declaration.
Definition DeclObjC.h:1160
ObjCMethodDecl * lookupInstanceMethod(Selector Sel) const
Lookup an instance method for a given selector.
Definition DeclObjC.h:1853
QualType getClassReceiver() const
Returns the type of a class message send, or NULL if the message is not a class message.
Definition ExprObjC.h:1319
const ObjCMethodDecl * getMethodDecl() const
Definition ExprObjC.h:1396
SourceLocation getEndLoc() const LLVM_READONLY
Definition ExprObjC.h:1491
SourceLocation getSelectorStartLoc() const
Definition ExprObjC.h:1459
ObjCMethodDecl - Represents an instance or class method declaration.
Definition DeclObjC.h:140
Represents one property declaration in an Objective-C interface.
Definition DeclObjC.h:734
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:1005
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:1424
void add(const sema::DelayedDiagnostic &diag)
Adds a delayed diagnostic.
Sema - This implements semantic analysis and AST building for C.
Definition Sema.h:863
SmallVector< sema::FunctionScopeInfo *, 4 > FunctionScopes
Stack containing information about each of the nested function, block, and method scopes that are cur...
Definition Sema.h:1268
Preprocessor & getPreprocessor() const
Definition Sema.h:934
const ExpressionEvaluationContextRecord & currentEvaluationContext() const
Definition Sema.h:7071
class clang::Sema::DelayedDiagnostics DelayedDiagnostics
ASTContext & Context
Definition Sema.h:1332
DiagnosticsEngine & getDiagnostics() const
Definition Sema.h:932
SemaObjC & ObjC()
Definition Sema.h:1544
ASTContext & getASTContext() const
Definition Sema.h:935
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:928
DeclContext * getCurLexicalContext() const
Definition Sema.h:1169
SourceManager & getSourceManager() const
Definition Sema.h:933
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.
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
CharSourceRange getExpansionRange(SourceLocation Loc) const
Given a SourceLocation object, return the range of tokens covered by the expansion in the ultimate fi...
bool isInSystemHeader(SourceLocation Loc) const
Returns if a SourceLocation is in a system header.
SourceLocation getExpansionLoc(SourceLocation Loc) const
Given a SourceLocation object Loc, return the expansion location referenced by the ID.
A trivial tuple used to represent a source range.
Stmt - This represents one statement.
Definition Stmt.h:85
StmtClass getStmtClass() const
Definition Stmt.h:1505
SourceLocation getBeginLoc() const LLVM_READONLY
Definition Stmt.cpp:355
Represents the declaration of a struct/union/class/enum.
Definition Decl.h:3856
TagDecl * getDefinitionOrSelf() const
Definition Decl.h:4039
Exposes information about the current target.
Definition TargetInfo.h:228
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:1879
const ObjCObjectType * getAsObjCInterfaceType() const
Definition Type.cpp:2064
Base class for declarations which introduce a typedef-name.
Definition Decl.h:3701
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.
Top level wrappers for InstallAPI frontend operations.
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:906
const FunctionProtoType * T
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:6019
bool IsCaseExpr
Whether evaluating an expression for a switch case label.
Definition Sema.h:6996