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