23 using namespace clang;
29 for (
const auto *A : D->
attrs()) {
30 if (
const auto *Avail = dyn_cast<AvailabilityAttr>(A)) {
36 StringRef ActualPlatform = Avail->getPlatform()->getName();
37 StringRef RealizedPlatform = ActualPlatform;
39 size_t suffix = RealizedPlatform.rfind(
"_app_extension");
40 if (suffix != StringRef::npos)
41 RealizedPlatform = RealizedPlatform.slice(0, suffix);
47 if (RealizedPlatform == TargetPlatform)
62 static std::pair<AvailabilityResult, const NamedDecl *>
70 while (
const auto *TD = dyn_cast<TypedefNameDecl>(D)) {
72 if (
const auto *TT = TD->getUnderlyingType()->getAs<
TagType>()) {
82 if (
const auto *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) {
83 if (IDecl->getDefinition()) {
84 D = IDecl->getDefinition();
89 if (
const auto *ECD = dyn_cast<EnumConstantDecl>(D))
92 if (
const auto *TheEnumDecl = dyn_cast<EnumDecl>(DC)) {
99 if (
const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
103 if (Init && Result ==
AR_Available && MD->isClassMethod() &&
104 MD->getSelector() == S.
NSAPIObj->getNewSelector() &&
106 Result = Init->getAvailability(Message);
121 VersionTuple DeclVersion,
Decl *Ctx,
123 assert(K !=
AR_Available &&
"Expected an unavailable declaration here!");
126 auto CheckContext = [&](
const Decl *C) {
129 if (AA->getIntroduced() >= DeclVersion)
132 if (C->isDeprecated())
138 if (
const auto *MD = dyn_cast<ObjCMethodDecl>(OffendingDecl)) {
139 if (
const auto *Impl = dyn_cast<ObjCImplDecl>(C)) {
140 if (MD->getClassInterface() == Impl->getClassInterface())
146 if (C->isUnavailable())
152 if (CheckContext(Ctx))
157 if (
const auto *MethodD = dyn_cast<ObjCMethodDecl>(Ctx))
158 if (MethodD->isClassMethod() &&
159 MethodD->getSelector().getAsString() ==
"load")
162 if (
const auto *CatOrImpl = dyn_cast<ObjCImplDecl>(Ctx)) {
164 if (CheckContext(Interface))
168 else if (
const auto *CatD = dyn_cast<ObjCCategoryDecl>(Ctx))
170 if (CheckContext(Interface))
179 const VersionTuple &DeploymentVersion,
180 const VersionTuple &DeclVersion) {
182 VersionTuple ForceAvailabilityFromVersion;
183 switch (Triple.getOS()) {
184 case llvm::Triple::IOS:
185 case llvm::Triple::TvOS:
186 ForceAvailabilityFromVersion = VersionTuple(11);
188 case llvm::Triple::WatchOS:
189 ForceAvailabilityFromVersion = VersionTuple(4);
191 case llvm::Triple::Darwin:
192 case llvm::Triple::MacOSX:
193 ForceAvailabilityFromVersion = VersionTuple(10, 13);
197 return Triple.getVendor() == llvm::Triple::Apple;
199 return DeploymentVersion >= ForceAvailabilityFromVersion ||
200 DeclVersion >= ForceAvailabilityFromVersion;
204 for (
Decl *Ctx = OrigCtx; Ctx;
205 Ctx = cast_or_null<Decl>(Ctx->getDeclContext())) {
206 if (isa<TagDecl>(Ctx) || isa<FunctionDecl>(Ctx) || isa<ObjCMethodDecl>(Ctx))
207 return cast<NamedDecl>(Ctx);
208 if (
auto *CD = dyn_cast<ObjCContainerDecl>(Ctx)) {
209 if (
auto *Imp = dyn_cast<ObjCImplDecl>(Ctx))
210 return Imp->getClassInterface();
215 return dyn_cast<NamedDecl>(OrigCtx);
220 struct AttributeInsertion {
225 static AttributeInsertion createInsertionAfter(
const NamedDecl *D) {
228 static AttributeInsertion createInsertionAfter(
SourceLocation Loc) {
229 return {
" ", Loc,
""};
231 static AttributeInsertion createInsertionBefore(
const NamedDecl *D) {
250 if (!Name.empty() && (Name.front() ==
'-' || Name.front() ==
'+'))
251 Name = Name.drop_front(1);
254 Name.split(SlotNames,
':');
256 if (Name.back() ==
':') {
258 SlotNames.pop_back();
259 NumParams = SlotNames.size();
261 if (SlotNames.size() != 1)
267 bool AllowDollar = LangOpts.DollarIdents;
268 for (StringRef S : SlotNames) {
282 if (isa<ObjCPropertyDecl>(D))
283 return AttributeInsertion::createInsertionAfter(D);
284 if (
const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
287 return AttributeInsertion::createInsertionAfter(D);
289 if (
const auto *TD = dyn_cast<TagDecl>(D)) {
295 return AttributeInsertion::createInsertionAfter(Loc);
297 return AttributeInsertion::createInsertionBefore(D);
317 bool ObjCPropertyAccess) {
319 unsigned diag, diag_message, diag_fwdclass_message;
320 unsigned diag_available_here = diag::note_availability_specified_here;
324 unsigned property_note_select;
327 unsigned available_here_select_kind;
329 VersionTuple DeclVersion;
331 DeclVersion = AA->getIntroduced();
342 if (A && A->isInherited()) {
345 const AvailabilityAttr *AForRedecl =
347 if (AForRedecl && !AForRedecl->isInherited()) {
350 NoteLocation = Redecl->getLocation();
362 const AvailabilityAttr *AA =
364 VersionTuple Introduced = AA->getIntroduced();
369 unsigned Warning = UseNewWarning ? diag::warn_unguarded_availability_new
370 : diag::warn_unguarded_availability;
372 std::string PlatformName(AvailabilityAttr::getPrettyPlatformName(
375 S.
Diag(Loc, Warning) << OffendingDecl << PlatformName
376 << Introduced.getAsString();
379 diag::note_partial_availability_specified_here)
380 << OffendingDecl << PlatformName << Introduced.getAsString()
384 if (
const auto *TD = dyn_cast<TagDecl>(Enclosing))
385 if (TD->getDeclName().isEmpty()) {
386 S.
Diag(TD->getLocation(),
387 diag::note_decl_unguarded_availability_silence)
388 << 1 << TD->getKindName();
392 S.
Diag(Enclosing->getLocation(),
393 diag::note_decl_unguarded_availability_silence)
396 if (Enclosing->hasAttr<AvailabilityAttr>())
405 AvailabilityAttr::getPlatformNameSourceSpelling(
412 (llvm::Twine(Insertion->Prefix) +
"API_AVAILABLE(" + PlatformName +
413 "(" + Introduced +
"))" + Insertion->Suffix)
419 diag = !ObjCPropertyAccess ? diag::warn_deprecated
420 : diag::warn_property_method_deprecated;
421 diag_message = diag::warn_deprecated_message;
422 diag_fwdclass_message = diag::warn_deprecated_fwdclass_message;
423 property_note_select = 0;
424 available_here_select_kind = 2;
425 if (
const auto *AL = OffendingDecl->
getAttr<DeprecatedAttr>())
426 NoteLocation = AL->getLocation();
430 diag = !ObjCPropertyAccess ? diag::err_unavailable
431 : diag::err_property_method_unavailable;
432 diag_message = diag::err_unavailable_message;
433 diag_fwdclass_message = diag::warn_unavailable_fwdclass_message;
434 property_note_select = 1;
435 available_here_select_kind = 0;
437 if (
auto AL = OffendingDecl->
getAttr<UnavailableAttr>()) {
438 if (AL->isImplicit() && AL->getImplicitReason()) {
441 auto flagARCError = [&] {
445 diag = diag::err_unavailable_in_arc;
448 switch (AL->getImplicitReason()) {
449 case UnavailableAttr::IR_None:
break;
451 case UnavailableAttr::IR_ARCForbiddenType:
453 diag_available_here = diag::note_arc_forbidden_type;
456 case UnavailableAttr::IR_ForbiddenWeak:
458 diag_available_here = diag::note_arc_weak_disabled;
460 diag_available_here = diag::note_arc_weak_no_runtime;
463 case UnavailableAttr::IR_ARCForbiddenConversion:
465 diag_available_here = diag::note_performs_forbidden_arc_conversion;
468 case UnavailableAttr::IR_ARCInitReturnsUnrelated:
470 diag_available_here = diag::note_arc_init_returns_unrelated;
473 case UnavailableAttr::IR_ARCFieldWithOwnership:
475 diag_available_here = diag::note_arc_field_with_ownership;
483 llvm_unreachable(
"Warning for availability of available declaration?");
488 StringRef Replacement;
489 if (
auto AL = OffendingDecl->
getAttr<DeprecatedAttr>())
490 Replacement = AL->getReplacement();
492 Replacement = AL->getReplacement();
495 if (!Replacement.empty())
499 if (
const auto *MethodDecl = dyn_cast<ObjCMethodDecl>(ReferringDecl)) {
500 Selector Sel = MethodDecl->getSelector();
504 if (NumParams && NumParams.getValue() == Sel.
getNumArgs()) {
505 assert(SelectorSlotNames.size() == Locs.size());
506 for (
unsigned I = 0; I < Locs.size(); ++I) {
511 NameRange, SelectorSlotNames[I]));
523 if (!Message.empty()) {
524 S.
Diag(Loc, diag_message) << ReferringDecl << Message << FixIts;
527 << ObjCProperty->
getDeclName() << property_note_select;
528 }
else if (!UnknownObjCClass) {
529 S.
Diag(Loc, diag) << ReferringDecl << FixIts;
532 << ObjCProperty->
getDeclName() << property_note_select;
534 S.
Diag(Loc, diag_fwdclass_message) << ReferringDecl << FixIts;
538 S.
Diag(NoteLocation, diag_available_here)
539 << OffendingDecl << available_here_select_kind;
544 "Expected an availability diagnostic here");
561 bool ObjCPropertyAccess) {
566 AR, Locs, ReferringDecl, OffendingDecl, UnknownObjCClass,
567 ObjCProperty, Message, ObjCPropertyAccess));
573 Message, Locs, UnknownObjCClass, ObjCProperty,
581 switch (
Parent->getStmtClass()) {
582 case Stmt::IfStmtClass:
583 return cast<IfStmt>(
Parent)->getThen() == S ||
584 cast<IfStmt>(
Parent)->getElse() == S;
585 case Stmt::WhileStmtClass:
586 return cast<WhileStmt>(
Parent)->getBody() == S;
587 case Stmt::DoStmtClass:
588 return cast<DoStmt>(
Parent)->getBody() == S;
589 case Stmt::ForStmtClass:
590 return cast<ForStmt>(
Parent)->getBody() == S;
591 case Stmt::CXXForRangeStmtClass:
592 return cast<CXXForRangeStmt>(
Parent)->getBody() == S;
593 case Stmt::ObjCForCollectionStmtClass:
594 return cast<ObjCForCollectionStmt>(
Parent)->getBody() == S;
595 case Stmt::CaseStmtClass:
596 case Stmt::DefaultStmtClass:
597 return cast<SwitchCase>(
Parent)->getSubStmt() == S;
607 bool VisitStmt(
Stmt *S) {
return S !=
Target; }
610 static bool isContained(
const Stmt *Target,
const Decl *D) {
611 StmtUSEFinder Visitor;
613 return !Visitor.TraverseDecl(
const_cast<Decl *
>(D));
629 static const Stmt *findLastStmtThatUsesDecl(
const Decl *D,
631 LastDeclUSEFinder Visitor;
633 for (
const Stmt *S : llvm::reverse(
Scope->body())) {
634 if (!Visitor.TraverseStmt(
const_cast<Stmt *
>(S)))
647 class DiagnoseUnguardedAvailability
662 DiagnoseUnguardedAvailability(
Sema &SemaRef,
Decl *Ctx)
663 : SemaRef(SemaRef), Ctx(Ctx) {
664 AvailabilityStack.push_back(
668 bool TraverseStmt(
Stmt *S) {
671 StmtStack.push_back(S);
672 bool Result = Base::TraverseStmt(S);
673 StmtStack.pop_back();
677 void IssueDiagnostics(
Stmt *S) { TraverseStmt(S); }
679 bool TraverseIfStmt(
IfStmt *If);
694 DiagnoseDeclAvailability(
701 DiagnoseDeclAvailability(DRE->
getDecl(),
721 void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability(
725 std::tie(Result, OffendingDecl) =
733 const AvailabilityAttr *AA =
735 VersionTuple Introduced = AA->getIntroduced();
737 if (AvailabilityStack.back() >= Introduced)
754 ? diag::warn_unguarded_availability_new
755 : diag::warn_unguarded_availability;
757 std::string PlatformName(AvailabilityAttr::getPrettyPlatformName(
761 <<
Range << D << PlatformName << Introduced.getAsString();
764 diag::note_partial_availability_specified_here)
765 << OffendingDecl << PlatformName << Introduced.getAsString()
771 SemaRef.
Diag(
Range.getBegin(), diag::note_unguarded_available_silence)
777 if (StmtStack.empty())
779 const Stmt *StmtOfUse = StmtStack.back();
781 for (
const Stmt *S : llvm::reverse(StmtStack)) {
782 if (
const auto *CS = dyn_cast<CompoundStmt>(S)) {
786 if (isBodyLikeChildStmt(StmtOfUse, S)) {
794 const Stmt *LastStmtOfUse =
nullptr;
795 if (isa<DeclStmt>(StmtOfUse) &&
Scope) {
796 for (
const Decl *D : cast<DeclStmt>(StmtOfUse)->decls()) {
797 if (StmtUSEFinder::isContained(StmtStack.back(), D)) {
798 LastStmtOfUse = LastDeclUSEFinder::findLastStmtThatUsesDecl(D,
Scope);
808 SM.getExpansionRange(
809 (LastStmtOfUse ? LastStmtOfUse : StmtOfUse)->getEndLoc())
811 if (
SM.getFileID(IfInsertionLoc) !=
SM.getFileID(StmtEndLoc))
815 const char *ExtraIndentation =
" ";
817 llvm::raw_string_ostream FixItOS(FixItString);
818 FixItOS <<
"if (" << (SemaRef.
getLangOpts().ObjC ?
"@available"
819 :
"__builtin_available")
821 << AvailabilityAttr::getPlatformNameSourceSpelling(
823 <<
" " << Introduced.getAsString() <<
", *)) {\n"
824 << Indentation << ExtraIndentation;
832 FixItOS.str().clear();
834 << Indentation <<
"} else {\n"
835 << Indentation << ExtraIndentation
836 <<
"// Fallback on earlier versions\n"
837 << Indentation <<
"}";
842 bool DiagnoseUnguardedAvailability::VisitTypeLoc(
TypeLoc Ty) {
846 if (
Range.isInvalid())
849 if (
const auto *TT = dyn_cast<TagType>(TyPtr)) {
851 DiagnoseDeclAvailability(TD, Range);
853 }
else if (
const auto *TD = dyn_cast<TypedefType>(TyPtr)) {
855 DiagnoseDeclAvailability(D, Range);
857 }
else if (
const auto *ObjCO = dyn_cast<ObjCObjectType>(TyPtr)) {
858 if (
NamedDecl *D = ObjCO->getInterface())
859 DiagnoseDeclAvailability(D, Range);
865 bool DiagnoseUnguardedAvailability::TraverseIfStmt(
IfStmt *If) {
866 VersionTuple CondVersion;
867 if (
auto *E = dyn_cast<ObjCAvailabilityCheckExpr>(If->
getCond())) {
872 if (CondVersion.empty() || CondVersion <= AvailabilityStack.back())
873 return TraverseStmt(If->
getThen()) && TraverseStmt(If->
getElse());
876 return Base::TraverseIfStmt(If);
879 AvailabilityStack.push_back(CondVersion);
880 bool ShouldContinue = TraverseStmt(If->
getThen());
881 AvailabilityStack.pop_back();
883 return ShouldContinue && TraverseStmt(If->
getElse());
889 Stmt *Body =
nullptr;
894 if (FD->isTemplateInstantiation())
897 Body = FD->getBody();
898 }
else if (
auto *MD = dyn_cast<ObjCMethodDecl>(D))
899 Body = MD->getBody();
900 else if (
auto *BD = dyn_cast<BlockDecl>(D))
901 Body = BD->getBody();
903 assert(Body &&
"Need a body here!");
905 DiagnoseUnguardedAvailability(*
this, D).IssueDiagnostics(Body);
909 if (FunctionScopes.empty())
916 return FunctionScopes.front();
922 bool ObjCPropertyAccess,
923 bool AvoidPartialAvailabilityChecks,
929 std::tie(Result, OffendingDecl) =
935 if (AvoidPartialAvailabilityChecks)
942 Context->HasPotentialAvailabilityViolations =
true;
948 if (
const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
951 if (PDeclResult == Result)
957 UnknownObjCClass, ObjCPDecl, ObjCPropertyAccess);