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.