clang: lib/Sema/SemaAvailability.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
28#include "llvm/ADT/StringRef.h"
29#include
30
31using namespace clang;
32using namespace sema;
33
35 const AvailabilityAttr *AA) {
37 auto Environment = Context.getTargetInfo().getTriple().getEnvironment();
38 if (!IIEnvironment || Environment == llvm::Triple::UnknownEnvironment)
39 return true;
40
41 llvm::Triple::EnvironmentType ET =
42 AvailabilityAttr::getEnvironmentType(IIEnvironment->getName());
43 return Environment == ET;
44}
45
47 const Decl *D) {
48 AvailabilityAttr const *PartialMatch = nullptr;
49
50
51
52
53
54 if (const auto *FTD = dyn_cast(D))
55 D = FTD->getTemplatedDecl();
56 for (const auto *A : D->attrs()) {
57 if (const auto *Avail = dyn_cast(A)) {
58
59
60
61
62
63 StringRef ActualPlatform = Avail->getPlatform()->getName();
64 StringRef RealizedPlatform = ActualPlatform;
65 if (Context.getLangOpts().AppExt) {
66 size_t suffix = RealizedPlatform.rfind("_app_extension");
67 if (suffix != StringRef::npos)
68 RealizedPlatform = RealizedPlatform.slice(0, suffix);
69 }
70
71 StringRef TargetPlatform = Context.getTargetInfo().getPlatformName();
72
73
74 if (RealizedPlatform == TargetPlatform) {
75
77 return Avail;
78 PartialMatch = Avail;
79 }
80 }
81 }
82 return PartialMatch;
83}
84
85
86
87
88
89
90
91
92
93std::pair<AvailabilityResult, const NamedDecl *>
97
98
99
100 while (const auto *TD = dyn_cast(D)) {
102 break;
103 for (const Type *T = TD->getUnderlyingType().getTypePtr(); ; ) {
104 if (auto *TT = dyn_cast(T)) {
105 D = TT->getDecl()->getDefinitionOrSelf();
107
108
109
110 goto done;
111 } else {
112 const Type *NextT =
113 T->getLocallyUnqualifiedSingleStepDesugaredType().getTypePtr();
114 if (NextT == T)
115 goto done;
116 T = NextT;
117 continue;
118 }
120 break;
121 }
122 }
123done:
124
125 if (const auto *ADecl = dyn_cast(D)) {
126 D = ADecl->getTemplatedDecl();
128 }
129
130
131 if (const auto *IDecl = dyn_cast(D)) {
132 if (IDecl->getDefinition()) {
133 D = IDecl->getDefinition();
135 }
136 }
137
138 if (const auto *ECD = dyn_cast(D))
140 const DeclContext *DC = ECD->getDeclContext();
141 if (const auto *TheEnumDecl = dyn_cast(DC)) {
142 Result = TheEnumDecl->getAvailability(Message);
143 D = TheEnumDecl;
144 }
145 }
146
147
148 if (const auto *MD = dyn_cast(D)) {
149 if (ObjC().NSAPIObj && ClassReceiver) {
151 ObjC().NSAPIObj->getInitSelector());
153 MD->getSelector() == ObjC().NSAPIObj->getNewSelector() &&
155 Result = Init->getAvailability(Message);
157 }
158 }
159 }
160
162}
163
164
165
166
170 assert(K != AR_Available && "Expected an unavailable declaration here!");
171
172
174
175 if (DeclLoc.isMacroID() && S.getLangOpts().CPlusPlus &&
178 if (MacroName == "CF_OPTIONS" || MacroName == "OBJC_OPTIONS" ||
179 MacroName == "SWIFT_OPTIONS" || MacroName == "NS_OPTIONS") {
180 return false;
181 }
182 }
183
184
185
186
187
188
189
190
191
193 if (!S.getLangOpts().HLSLStrictAvailability ||
194 (DeclEnv != nullptr &&
196 llvm::Triple::EnvironmentType::Library))
197 return false;
198 }
199
201 if (const auto *VD = dyn_cast(OffendingDecl))
202 if (VD->isLocalVarDeclOrParm() && VD->isDeprecated())
203 return true;
204 }
205
206
207 auto CheckContext = [&](const Decl *C) {
210 if (AA->getIntroduced() >= DeclVersion &&
211 AA->getEnvironment() == DeclEnv)
212 return true;
214 if (C->isDeprecated())
215 return true;
217
218
219
220 if (const auto *MD = dyn_cast(OffendingDecl)) {
221 if (const auto *Impl = dyn_cast(C)) {
222 if (MD->getClassInterface() == Impl->getClassInterface())
223 return true;
224 }
225 }
226 }
227
228 if (C->isUnavailable())
229 return true;
230 return false;
231 };
232
233 do {
234 if (CheckContext(Ctx))
235 return false;
236
237
238
239 if (const auto *MethodD = dyn_cast(Ctx))
240 if (MethodD->isClassMethod() &&
241 MethodD->getSelector().getAsString() == "load")
242 return true;
243
244 if (const auto *CatOrImpl = dyn_cast(Ctx)) {
247 return false;
248 }
249
250 else if (const auto *CatD = dyn_cast(Ctx))
253 return false;
254 } while ((Ctx = cast_or_null(Ctx->getDeclContext())));
255
256 return true;
257}
258
260 const ASTContext &Context, const VersionTuple &DeploymentVersion,
261 const VersionTuple &DeclVersion, bool HasMatchingEnv) {
262 const auto &Triple = Context.getTargetInfo().getTriple();
263 VersionTuple ForceAvailabilityFromVersion;
264 switch (Triple.getOS()) {
265
266
267
268
269 case llvm::Triple::IOS:
270 case llvm::Triple::TvOS:
271 ForceAvailabilityFromVersion = VersionTuple(11);
272 break;
273 case llvm::Triple::WatchOS:
274 ForceAvailabilityFromVersion = VersionTuple(4);
275 break;
276 case llvm::Triple::Darwin:
277 case llvm::Triple::MacOSX:
278 ForceAvailabilityFromVersion = VersionTuple(10, 13);
279 break;
280
281
282
283
284 case llvm::Triple::ShaderModel:
285 return HasMatchingEnv ? diag::warn_hlsl_availability
286 : diag::warn_hlsl_availability_unavailable;
287 default:
288
289 ForceAvailabilityFromVersion =
290 (Triple.getVendor() == llvm::Triple::Apple)
291 ? VersionTuple(0, 0)
292 : VersionTuple((unsigned)-1, (unsigned)-1);
293 }
294 if (DeploymentVersion >= ForceAvailabilityFromVersion ||
295 DeclVersion >= ForceAvailabilityFromVersion)
296 return HasMatchingEnv ? diag::warn_unguarded_availability_new
297 : diag::warn_unguarded_availability_unavailable_new;
298 return HasMatchingEnv ? diag::warn_unguarded_availability
299 : diag::warn_unguarded_availability_unavailable;
300}
301
303 for (Decl *Ctx = OrigCtx; Ctx;
304 Ctx = cast_or_null(Ctx->getDeclContext())) {
307 if (auto *CD = dyn_cast(Ctx)) {
308 if (auto *Imp = dyn_cast(Ctx))
309 return Imp->getClassInterface();
310 return CD;
311 }
312 }
313
314 return dyn_cast(OrigCtx);
315}
316
317namespace {
318
319struct AttributeInsertion {
320 StringRef Prefix;
321 SourceLocation Loc;
322 StringRef Suffix;
323
324 static AttributeInsertion createInsertionAfter(const NamedDecl *D) {
325 return {" ", D->getEndLoc(), ""};
326 }
327 static AttributeInsertion createInsertionAfter(SourceLocation Loc) {
328 return {" ", Loc, ""};
329 }
330 static AttributeInsertion createInsertionBefore(const NamedDecl *D) {
332 }
333};
334
335}
336
337
338
339
340
341
342
343
344
345static std::optional
348
349 if (!Name.empty() && (Name.front() == '-' || Name.front() == '+'))
350 Name = Name.drop_front(1);
351 if (Name.empty())
352 return std::nullopt;
353 Name.split(SlotNames, ':');
354 unsigned NumParams;
355 if (Name.back() == ':') {
356
357 SlotNames.pop_back();
358 NumParams = SlotNames.size();
359 } else {
360 if (SlotNames.size() != 1)
361
362 return std::nullopt;
363 NumParams = 0;
364 }
365
366 bool AllowDollar = LangOpts.DollarIdents;
367 for (StringRef S : SlotNames) {
368 if (S.empty())
369 continue;
371 return std::nullopt;
372 }
373 return NumParams;
374}
375
376
377
378static std::optional
382 return AttributeInsertion::createInsertionAfter(D);
383 if (const auto *MD = dyn_cast(D)) {
384 if (MD->hasBody())
385 return std::nullopt;
386 return AttributeInsertion::createInsertionAfter(D);
387 }
388 if (const auto *TD = dyn_cast(D)) {
392 return std::nullopt;
393
394 return AttributeInsertion::createInsertionAfter(Loc);
395 }
396 return AttributeInsertion::createInsertionBefore(D);
397}
398
399
400
401
402
403
404
405
406
407
408
412 StringRef Message,
416 bool ObjCPropertyAccess) {
417
418 unsigned diag, diag_message, diag_fwdclass_message;
419 unsigned diag_available_here = diag::note_availability_specified_here;
421
422
423 unsigned property_note_select;
424
425
426 unsigned available_here_select_kind;
427
428 VersionTuple DeclVersion;
431 if (AA) {
432 DeclVersion = AA->getIntroduced();
433 IIEnv = AA->getEnvironment();
434 }
435
437 OffendingDecl))
438 return;
439
441
442
443
444 if (AA && AA->isInherited()) {
447 const AvailabilityAttr *AForRedecl =
449 if (AForRedecl && !AForRedecl->isInherited()) {
450
451
452 NoteLocation = Redecl->getLocation();
453 break;
454 }
455 }
456 }
457
458 switch (K) {
460
461
462
463
464 assert(AA != nullptr && "expecting valid availability attribute");
465 VersionTuple Introduced = AA->getIntroduced();
466 bool EnvironmentMatchesOrNone =
468
470 std::string PlatformName(
471 AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName()));
472 llvm::StringRef TargetEnvironment(
473 llvm::Triple::getEnvironmentTypeName(TI.getTriple().getEnvironment()));
474 llvm::StringRef AttrEnvironment =
475 AA->getEnvironment() ? AA->getEnvironment()->getName() : "";
476 bool UseEnvironment =
477 (!AttrEnvironment.empty() && !TargetEnvironment.empty());
478
481 Introduced, EnvironmentMatchesOrNone);
482
483 S.Diag(Loc, DiagKind) << OffendingDecl << PlatformName
484 << Introduced.getAsString() << UseEnvironment
485 << TargetEnvironment;
486
488 diag::note_partial_availability_specified_here)
489 << OffendingDecl << PlatformName << Introduced.getAsString()
491 << UseEnvironment << AttrEnvironment << TargetEnvironment;
492
493
495 return;
496
498 if (const auto *TD = dyn_cast(Enclosing))
499 if (TD->getDeclName().isEmpty()) {
500 S.Diag(TD->getLocation(),
501 diag::note_decl_unguarded_availability_silence)
502 << 1 << TD->getKindName();
503 return;
504 }
505 auto FixitNoteDiag =
506 S.Diag(Enclosing->getLocation(),
507 diag::note_decl_unguarded_availability_silence)
508 << 0 << Enclosing;
509
510 if (Enclosing->hasAttr())
511 return;
514 return;
517 if (!Insertion)
518 return;
519 StringRef PlatformName =
521
522
523
524
525
526
527
528
529
530
531
532 std::vector EquivalentPlatforms =
533 AvailabilityAttr::equivalentPlatformNames(PlatformName);
534 llvm::Twine MacroPrefix = "__API_AVAILABLE_PLATFORM_";
535 auto AvailablePlatform =
536 llvm::find_if(EquivalentPlatforms, [&](StringRef EquivalentPlatform) {
537 return PP.isMacroDefined((MacroPrefix + EquivalentPlatform).str());
538 });
539 if (AvailablePlatform == EquivalentPlatforms.end())
540 return;
541 std::string Introduced =
544 Insertion->Loc,
545 (llvm::Twine(Insertion->Prefix) + "API_AVAILABLE(" +
546 *AvailablePlatform + "(" + Introduced + "))" + Insertion->Suffix)
547 .str());
548 }
549 return;
550 }
552
553
554 if (const auto *FD = dyn_cast_or_null(S.getCurFunctionDecl());
555 FD && FD->isImplicit())
556 return;
557
558 if (ObjCPropertyAccess)
559 diag = diag::warn_property_method_deprecated;
561 diag = diag::warn_deprecated_switch_case;
562 else
563 diag = diag::warn_deprecated;
564
565 diag_message = diag::warn_deprecated_message;
566 diag_fwdclass_message = diag::warn_deprecated_fwdclass_message;
567 property_note_select = 0;
568 available_here_select_kind = 2;
569 if (const auto *AL = OffendingDecl->getAttr())
570 NoteLocation = AL->getLocation();
571 break;
572
574 diag = !ObjCPropertyAccess ? diag::err_unavailable
575 : diag::err_property_method_unavailable;
576 diag_message = diag::err_unavailable_message;
577 diag_fwdclass_message = diag::warn_unavailable_fwdclass_message;
578 property_note_select = 1;
579 available_here_select_kind = 0;
580
581 if (auto AL = OffendingDecl->getAttr()) {
582 if (AL->isImplicit() && AL->getImplicitReason()) {
583
584
585 auto flagARCError = [&] {
589 diag = diag::err_unavailable_in_arc;
590 };
591
592 switch (AL->getImplicitReason()) {
593 case UnavailableAttr::IR_None: break;
594
595 case UnavailableAttr::IR_ARCForbiddenType:
596 flagARCError();
597 diag_available_here = diag::note_arc_forbidden_type;
598 break;
599
600 case UnavailableAttr::IR_ForbiddenWeak:
602 diag_available_here = diag::note_arc_weak_disabled;
603 else
604 diag_available_here = diag::note_arc_weak_no_runtime;
605 break;
606
607 case UnavailableAttr::IR_ARCForbiddenConversion:
608 flagARCError();
609 diag_available_here = diag::note_performs_forbidden_arc_conversion;
610 break;
611
612 case UnavailableAttr::IR_ARCInitReturnsUnrelated:
613 flagARCError();
614 diag_available_here = diag::note_arc_init_returns_unrelated;
615 break;
616
617 case UnavailableAttr::IR_ARCFieldWithOwnership:
618 flagARCError();
619 diag_available_here = diag::note_arc_field_with_ownership;
620 break;
621 }
622 }
623 }
624 break;
625
627 llvm_unreachable("Warning for availability of available declaration?");
628 }
629
632 StringRef Replacement;
633 if (auto AL = OffendingDecl->getAttr())
634 Replacement = AL->getReplacement();
636 Replacement = AL->getReplacement();
637
639 if (!Replacement.empty())
640 UseRange =
642 if (UseRange.isValid()) {
643 if (const auto *MethodDecl = dyn_cast(ReferringDecl)) {
644 Selector Sel = MethodDecl->getSelector();
647 Replacement, SelectorSlotNames, S.getLangOpts());
648 if (NumParams && *NumParams == Sel.getNumArgs()) {
649 assert(SelectorSlotNames.size() == Locs.size());
650 for (unsigned I = 0; I < Locs.size(); ++I) {
655 NameRange, SelectorSlotNames[I]));
656 } else
657 FixIts.push_back(
659 }
660 } else
662 } else
664 }
665 }
666
667
668
669
670
673 bool ShouldAllowWarningInSystemHeader =
674 InstantiationLoc != Loc &&
676 struct AllowWarningInSystemHeaders {
678 bool AllowWarningInSystemHeaders)
681 }
682 ~AllowWarningInSystemHeaders() { Engine.setSuppressSystemWarnings(Prev); }
683
684 private:
686 bool Prev;
688 ShouldAllowWarningInSystemHeader);
689
690 if (!Message.empty()) {
691 S.Diag(Loc, diag_message) << ReferringDecl << Message << FixIts;
692 if (ObjCProperty)
693 S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
694 << ObjCProperty->getDeclName() << property_note_select;
695 } else if (!UnknownObjCClass) {
696 S.Diag(Loc, diag) << ReferringDecl << FixIts;
697 if (ObjCProperty)
698 S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
699 << ObjCProperty->getDeclName() << property_note_select;
700 } else {
701 S.Diag(Loc, diag_fwdclass_message) << ReferringDecl << FixIts;
702 S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class);
703 }
704
705 S.Diag(NoteLocation, diag_available_here)
706 << OffendingDecl << available_here_select_kind;
707}
708
711 "Expected an availability diagnostic here");
712
719}
720
724 StringRef Message,
728 bool ObjCPropertyAccess) {
729
733 AR, Locs, ReferringDecl, OffendingDecl, UnknownObjCClass,
734 ObjCProperty, Message, ObjCPropertyAccess));
735 return;
736 }
737
740 Message, Locs, UnknownObjCClass, ObjCProperty,
741 ObjCPropertyAccess);
742}
743
744namespace {
745
746
747bool isBodyLikeChildStmt(const Stmt *S, const Stmt *Parent) {
749 case Stmt::IfStmtClass:
750 return cast(Parent)->getThen() == S ||
752 case Stmt::WhileStmtClass:
754 case Stmt::DoStmtClass:
756 case Stmt::ForStmtClass:
758 case Stmt::CXXForRangeStmtClass:
760 case Stmt::ObjCForCollectionStmtClass:
762 case Stmt::CaseStmtClass:
763 case Stmt::DefaultStmtClass:
765 default:
766 return false;
767 }
768}
769
772
773public:
774 bool VisitStmt(Stmt *S) override { return S != Target; }
775
776
777 static bool isContained(const Stmt *Target, const Decl *D) {
778 StmtUSEFinder Visitor;
779 Visitor.Target = Target;
780 return !Visitor.TraverseDecl(const_cast<Decl *>(D));
781 }
782};
783
784
785
787 const Decl *D;
788
789public:
790 bool VisitDeclRefExpr(DeclRefExpr *DRE) override {
792 return false;
793 return true;
794 }
795
796 static const Stmt *findLastStmtThatUsesDecl(const Decl *D,
798 LastDeclUSEFinder Visitor;
799 Visitor.D = D;
800 for (const Stmt *S : llvm::reverse(Scope->body())) {
801 if (!Visitor.TraverseStmt(const_cast<Stmt *>(S)))
802 return S;
803 }
804 return nullptr;
805 }
806};
807
808
809
810
811
812
813
815 Sema &SemaRef;
817
818
819 SmallVector<VersionTuple, 8> AvailabilityStack;
820 SmallVector<const Stmt *, 16> StmtStack;
821
822 void DiagnoseDeclAvailability(NamedDecl *D, SourceRange Range,
823 ObjCInterfaceDecl *ClassReceiver = nullptr);
824
825public:
826 DiagnoseUnguardedAvailability(Sema &SemaRef, Decl *Ctx)
827 : SemaRef(SemaRef), Ctx(Ctx) {
828 AvailabilityStack.push_back(
830 }
831
832 bool TraverseStmt(Stmt *S) override {
833 if (!S)
834 return true;
835 StmtStack.push_back(S);
837 StmtStack.pop_back();
839 }
840
841 void IssueDiagnostics(Stmt *S) { TraverseStmt(S); }
842
843 bool TraverseIfStmt(IfStmt *If) override;
844
845
846
847 bool TraverseCaseStmt(CaseStmt *CS) override {
848 return TraverseStmt(CS->getSubStmt());
849 }
850
851 bool VisitObjCMessageExpr(ObjCMessageExpr *Msg) override {
853 ObjCInterfaceDecl *ID = nullptr;
857
858 DiagnoseDeclAvailability(
860 }
861 return true;
862 }
863
864 bool VisitDeclRefExpr(DeclRefExpr *DRE) override {
865 DiagnoseDeclAvailability(DRE->getDecl(),
867 return true;
868 }
869
870 bool VisitMemberExpr(MemberExpr *ME) override {
873 return true;
874 }
875
876 bool VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *E) override {
877 SemaRef.Diag(E->getBeginLoc(), diag::warn_at_available_unchecked_use)
879 return true;
880 }
881
882 bool VisitTypeLoc(TypeLoc Ty) override;
883};
884
885void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability(
889 std::tie(Result, OffendingDecl) =
892
893
895 return;
896
897 const AvailabilityAttr *AA =
899 assert(AA != nullptr && "expecting valid availability attribute");
900 bool EnvironmentMatchesOrNone =
902 VersionTuple Introduced = AA->getIntroduced();
903
904 if (EnvironmentMatchesOrNone && AvailabilityStack.back() >= Introduced)
905 return;
906
907
908
910 AA->getEnvironment(), Ctx,
911 OffendingDecl))
912 return;
913
915 std::string PlatformName(
916 AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName()));
917 llvm::StringRef TargetEnvironment(TI.getTriple().getEnvironmentName());
918 llvm::StringRef AttrEnvironment =
919 AA->getEnvironment() ? AA->getEnvironment()->getName() : "";
920 bool UseEnvironment =
921 (!AttrEnvironment.empty() && !TargetEnvironment.empty());
922
926 EnvironmentMatchesOrNone);
927
928 SemaRef.Diag(Range.getBegin(), DiagKind)
929 << Range << D << PlatformName << Introduced.getAsString()
930 << UseEnvironment << TargetEnvironment;
931
933 diag::note_partial_availability_specified_here)
934 << OffendingDecl << PlatformName << Introduced.getAsString()
936 << UseEnvironment << AttrEnvironment << TargetEnvironment;
937
938
940 return;
941
942 auto FixitDiag =
943 SemaRef.Diag(Range.getBegin(), diag::note_unguarded_available_silence)
946 : 1);
947
948
949 if (StmtStack.empty())
950 return;
951 const Stmt *StmtOfUse = StmtStack.back();
953 for (const Stmt *S : llvm::reverse(StmtStack)) {
954 if (const auto *CS = dyn_cast(S)) {
956 break;
957 }
958 if (isBodyLikeChildStmt(StmtOfUse, S)) {
959
960
961
962 break;
963 }
964 StmtOfUse = S;
965 }
966 const Stmt *LastStmtOfUse = nullptr;
969 if (StmtUSEFinder::isContained(StmtStack.back(), D)) {
970 LastStmtOfUse = LastDeclUSEFinder::findLastStmtThatUsesDecl(D, Scope);
971 break;
972 }
973 }
974 }
975
980 SM.getExpansionRange(
981 (LastStmtOfUse ? LastStmtOfUse : StmtOfUse)->getEndLoc())
982 .getEnd();
983 if (SM.getFileID(IfInsertionLoc) != SM.getFileID(StmtEndLoc))
984 return;
985
987 const char *ExtraIndentation = " ";
988 std::string FixItString;
989 llvm::raw_string_ostream FixItOS(FixItString);
990 FixItOS << "if (" << (SemaRef.getLangOpts().ObjC ? "@available"
991 : "__builtin_available")
992 << "("
993 << AvailabilityAttr::getPlatformNameSourceSpelling(
995 << " " << Introduced.getAsString() << ", *)) {\n"
996 << Indentation << ExtraIndentation;
999 StmtEndLoc, tok::semi, SM, SemaRef.getLangOpts(),
1000 false);
1001 if (ElseInsertionLoc.isInvalid())
1002 ElseInsertionLoc =
1004 FixItOS.str().clear();
1005 FixItOS << "\n"
1006 << Indentation << "} else {\n"
1007 << Indentation << ExtraIndentation
1008 << "// Fallback on earlier versions\n"
1009 << Indentation << "}";
1011 }
1012}
1013
1014bool DiagnoseUnguardedAvailability::VisitTypeLoc(TypeLoc Ty) {
1017
1018 if (Range.isInvalid())
1019 return true;
1020
1021 if (const auto *TT = dyn_cast(TyPtr)) {
1023 DiagnoseDeclAvailability(TD, Range);
1024
1025 } else if (const auto *TD = dyn_cast(TyPtr)) {
1027 DiagnoseDeclAvailability(D, Range);
1028
1029 } else if (const auto *ObjCO = dyn_cast(TyPtr)) {
1030 if (NamedDecl *D = ObjCO->getInterface())
1031 DiagnoseDeclAvailability(D, Range);
1032 }
1033
1034 return true;
1035}
1036
1037struct ExtractedAvailabilityExpr {
1038 const ObjCAvailabilityCheckExpr *E = nullptr;
1039 bool isNegated = false;
1040};
1041
1042ExtractedAvailabilityExpr extractAvailabilityExpr(const Expr *IfCond) {
1043 const auto *E = IfCond;
1044 bool IsNegated = false;
1045 while (true) {
1047 if (const auto *AE = dyn_cast(E)) {
1048 return ExtractedAvailabilityExpr{AE, IsNegated};
1049 }
1050
1051 const auto *UO = dyn_cast(E);
1052 if (!UO || UO->getOpcode() != UO_LNot) {
1053 return ExtractedAvailabilityExpr{};
1054 }
1055 E = UO->getSubExpr();
1056 IsNegated = !IsNegated;
1057 }
1058}
1059
1060bool DiagnoseUnguardedAvailability::TraverseIfStmt(IfStmt *If) {
1061 ExtractedAvailabilityExpr IfCond = extractAvailabilityExpr(If->getCond());
1062 if (!IfCond.E) {
1063
1064 return DynamicRecursiveASTVisitor::TraverseIfStmt(If);
1065 }
1066
1067 VersionTuple CondVersion = IfCond.E->getVersion();
1068
1069
1070 if (CondVersion.empty() || CondVersion <= AvailabilityStack.back()) {
1071 return TraverseStmt(If->getThen()) && TraverseStmt(If->getElse());
1072 }
1073
1074 auto *Guarded = If->getThen();
1075 auto *Unguarded = If->getElse();
1076 if (IfCond.isNegated) {
1077 std::swap(Guarded, Unguarded);
1078 }
1079
1080 AvailabilityStack.push_back(CondVersion);
1081 bool ShouldContinue = TraverseStmt(Guarded);
1082 AvailabilityStack.pop_back();
1083
1084 return ShouldContinue && TraverseStmt(Unguarded);
1085}
1086
1087}
1088
1090 Stmt *Body = nullptr;
1091
1093 Body = FD->getBody();
1094
1095 if (auto *CD = dyn_cast(FD))
1097 DiagnoseUnguardedAvailability(*this, D).IssueDiagnostics(CI->getInit());
1098
1099 } else if (auto *MD = dyn_cast(D))
1100 Body = MD->getBody();
1101 else if (auto *BD = dyn_cast(D))
1102 Body = BD->getBody();
1103
1104 assert(Body && "Need a body here!");
1105
1106 DiagnoseUnguardedAvailability(*this, D).IssueDiagnostics(Body);
1107}
1108
1111 return nullptr;
1112
1113
1114
1115
1116
1118}
1119
1123 bool ObjCPropertyAccess,
1124 bool AvoidPartialAvailabilityChecks,
1126
1127 std::string Message;
1130
1131 std::tie(Result, OffendingDecl) =
1134 return;
1135
1137 if (AvoidPartialAvailabilityChecks)
1138 return;
1139
1140
1141
1142
1144 Context->HasPotentialAvailabilityViolations = true;
1145 return;
1146 }
1147 }
1148
1150 if (const auto *MD = dyn_cast(D)) {
1153 if (PDeclResult == Result)
1154 ObjCPDecl = PD;
1155 }
1156 }
1157
1159 UnknownObjCClass, ObjCPDecl, ObjCPropertyAccess);
1160}
1161
1165 false,
1166 false,
1167 nullptr);
1168}
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
Defines the clang::Preprocessor interface.
static unsigned getAvailabilityDiagnosticKind(const ASTContext &Context, const VersionTuple &DeploymentVersion, const VersionTuple &DeclVersion, bool HasMatchingEnv)
Definition SemaAvailability.cpp:259
static bool hasMatchingEnvironmentOrNone(const ASTContext &Context, const AvailabilityAttr *AA)
Definition SemaAvailability.cpp:34
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...
Definition SemaAvailability.cpp:379
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)
Definition SemaAvailability.cpp:721
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.
Definition SemaAvailability.cpp:409
static NamedDecl * findEnclosingDeclToAnnotate(Decl *OrigCtx)
Definition SemaAvailability.cpp:302
static std::optional< unsigned > tryParseObjCMethodName(StringRef Name, SmallVectorImpl< StringRef > &SlotNames, const LangOptions &LangOpts)
Tries to parse a string as ObjC method name.
Definition SemaAvailability.cpp:346
static const AvailabilityAttr * getAttrForPlatform(ASTContext &Context, const Decl *D)
Definition SemaAvailability.cpp:46
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.
Definition SemaAvailability.cpp:167
This file declares semantic analysis for Objective-C.
Defines the Objective-C statement AST node classes.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
const TargetInfo & getTargetInfo() const
Represents a C++ base or member initializer.
Represents a character-granular source range.
static CharSourceRange getCharRange(SourceRange R)
CompoundStmt - This represents a group of statements like { stmt stmt }.
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
SourceLocation getEndLoc() const LLVM_READONLY
SourceLocation getBeginLoc() const
Decl - This represents one declaration (or definition), e.g.
Decl * getPreviousDecl()
Retrieve the previous declaration that declares the same entity as this declaration,...
SourceLocation getEndLoc() const LLVM_READONLY
AvailabilityResult getAvailability(std::string *Message=nullptr, VersionTuple EnclosingVersion=VersionTuple(), StringRef *RealizedPlatform=nullptr) const
Determine the availability of the given declaration.
FunctionDecl * getAsFunction() LLVM_READONLY
Returns the function itself, or the templated function if this is a function template.
SourceLocation getLocation() const
DeclContext * getDeclContext()
SourceLocation getBeginLoc() const LLVM_READONLY
VersionTuple getVersionIntroduced() const
Retrieve the version of the target platform in which this declaration was introduced.
Concrete class used by the front-end to report problems and issues.
void setSuppressSystemWarnings(bool Val)
When set to true mask warnings that come from system headers.
bool getSuppressSystemWarnings() const
virtual bool TraverseStmt(MaybeConst< Stmt > *S)
This represents one expression.
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
static FixItHint CreateReplacement(CharSourceRange RemoveRange, StringRef Code)
Create a code modification hint that replaces the given source range with the given code string.
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.
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.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
static SourceLocation findLocationAfterToken(SourceLocation loc, tok::TokenKind TKind, const SourceManager &SM, const LangOptions &LangOpts, bool SkipTrailingWhitespaceAndNewLine)
Checks that the given token is the first token that occurs after the given location (this excludes co...
static StringRef getIndentationForLine(SourceLocation Loc, const SourceManager &SM)
Returns the leading whitespace for line that corresponds to the given location Loc.
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.
ValueDecl * getMemberDecl() const
Retrieve the member declaration to which this expression refers.
SourceLocation getEndLoc() const LLVM_READONLY
SourceLocation getBeginLoc() const LLVM_READONLY
This represents a decl that may have a name.
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
NamedDecl * getMostRecentDecl()
SourceLocation getBeginLoc() const
VersionTuple getVersion() const
Represents an ObjC class declaration.
ObjCMethodDecl * lookupInstanceMethod(Selector Sel) const
Lookup an instance method for a given selector.
QualType getClassReceiver() const
Returns the type of a class message send, or NULL if the message is not a class message.
const ObjCMethodDecl * getMethodDecl() const
SourceLocation getEndLoc() const LLVM_READONLY
SourceLocation getSelectorStartLoc() const
ObjCMethodDecl - Represents an instance or class method declaration.
Represents one property declaration in an Objective-C interface.
static ObjCPropertyDecl * findPropertyDecl(const DeclContext *DC, const IdentifierInfo *propertyID, ObjCPropertyQueryKind queryKind)
Lookup a property by name in the specified DeclContext.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
bool isMacroDefined(StringRef Id)
StringRef getImmediateMacroName(SourceLocation Loc)
Retrieve the name of the immediate macro expansion.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Scope - A scope is a transient data structure that is used while parsing the program.
Smart pointer class that efficiently represents Objective-C method names.
StringRef getNameForSlot(unsigned argIndex) const
Retrieve the name at a given position in the selector.
unsigned getNumArgs() const
SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID)
Emit a diagnostic.
bool shouldDelayDiagnostics()
Determines whether diagnostics should be delayed.
void add(const sema::DelayedDiagnostic &diag)
Adds a delayed diagnostic.
Sema - This implements semantic analysis and AST building for C.
SmallVector< sema::FunctionScopeInfo *, 4 > FunctionScopes
Stack containing information about each of the nested function, block, and method scopes that are cur...
Preprocessor & getPreprocessor() const
const ExpressionEvaluationContextRecord & currentEvaluationContext() const
class clang::Sema::DelayedDiagnostics DelayedDiagnostics
FunctionDecl * getCurFunctionDecl(bool AllowLambda=false) const
Returns a pointer to the innermost enclosing function, or nullptr if the current context is not insid...
DiagnosticsEngine & getDiagnostics() const
ASTContext & getASTContext() const
void DiagnoseUnguardedAvailabilityViolations(Decl *FD)
Issue any -Wunguarded-availability warnings in FD.
Definition SemaAvailability.cpp:1089
SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset=0)
Calls Lexer::getLocForEndOfToken()
const LangOptions & getLangOpts() const
DeclContext * getCurLexicalContext() const
SourceManager & getSourceManager() const
void DiagnoseAvailabilityOfDecl(NamedDecl *D, ArrayRef< SourceLocation > Locs, const ObjCInterfaceDecl *UnknownObjCClass, bool ObjCPropertyAccess, bool AvoidPartialAvailabilityChecks, ObjCInterfaceDecl *ClassReceiver)
Definition SemaAvailability.cpp:1120
std::pair< AvailabilityResult, const NamedDecl * > ShouldDiagnoseAvailabilityOfDecl(const NamedDecl *D, std::string *Message, ObjCInterfaceDecl *ClassReceiver)
The diagnostic we should emit for D, and the declaration that originated it, or AR_Available.
Definition SemaAvailability.cpp:94
sema::FunctionScopeInfo * getCurFunctionAvailabilityContext()
Retrieve the current function, if any, that should be analyzed for potential availability violations.
Definition SemaAvailability.cpp:1109
SourceLocation getTopMostPointOfInstantiation(const NamedDecl *) const
Returns the top most location responsible for the definition of N.
void handleDelayedAvailabilityCheck(sema::DelayedDiagnostic &DD, Decl *Ctx)
Definition SemaAvailability.cpp:709
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.
Stmt - This represents one statement.
StmtClass getStmtClass() const
SourceLocation getBeginLoc() const LLVM_READONLY
Represents the declaration of a struct/union/class/enum.
TagDecl * getDefinitionOrSelf() const
Exposes information about the current target.
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
StringRef getPlatformName() const
Retrieve the name of the platform as it is used in the availability attribute.
VersionTuple getPlatformMinVersion() const
Retrieve the minimum desired version of the platform, to which the program should be compiled.
Base wrapper for a particular "section" of type source info.
SourceLocation getEndLoc() const
Get the end source location.
SourceLocation getBeginLoc() const
Get the begin source location.
const Type * getTypePtr() const
The base class of the type hierarchy.
const ObjCObjectType * getAsObjCInterfaceType() const
Base class for declarations which introduce a typedef-name.
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.
Defines the clang::TargetInfo interface.
std::variant< struct RequiresDecl, struct HeaderDecl, struct UmbrellaDirDecl, struct ModuleDecl, struct ExcludeDecl, struct ExportDecl, struct ExportAsDecl, struct ExternModuleDecl, struct UseDecl, struct LinkDecl, struct ConfigMacrosDecl, struct ConflictDecl > Decl
All declarations that can appear in a module declaration.
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
@ 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.
@ Result
The result type of a method or function.
const FunctionProtoType * T
AvailabilityResult
Captures the result of checking the availability of a declaration.
DynamicRecursiveASTVisitorBase< false > DynamicRecursiveASTVisitor
U cast(CodeGen::Address addr)
@ Interface
The "__interface" keyword introduces the elaborated-type-specifier.
bool IsCaseExpr
Whether evaluating an expression for a switch case label.