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