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