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