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