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