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) {

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

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;

66 size_t suffix = RealizedPlatform.rfind("_app_extension");

67 if (suffix != StringRef::npos)

68 RealizedPlatform = RealizedPlatform.slice(0, suffix);

69 }

70

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

93static std::pair<AvailabilityResult, const NamedDecl *>

95 std::string *Message,

98

99

100

101 while (const auto *TD = dyn_cast(D)) {

103 if (const auto *TT = TD->getUnderlyingType()->getAs<TagType>()) {

104 D = TT->getDecl();

106 continue;

107 }

108 }

109 break;

110 }

111

112

113 if (const auto *ADecl = dyn_cast(D)) {

114 D = ADecl->getTemplatedDecl();

116 }

117

118

119 if (const auto *IDecl = dyn_cast(D)) {

120 if (IDecl->getDefinition()) {

121 D = IDecl->getDefinition();

123 }

124 }

125

126 if (const auto *ECD = dyn_cast(D))

128 const DeclContext *DC = ECD->getDeclContext();

129 if (const auto *TheEnumDecl = dyn_cast(DC)) {

131 D = TheEnumDecl;

132 }

133 }

134

135

136 if (const auto *MD = dyn_cast(D)) {

141 MD->getSelector() == S.ObjC().NSAPIObj->getNewSelector() &&

143 Result = Init->getAvailability(Message);

145 }

146 }

147 }

148

149 return {Result, D};

150}

151

152

153

154

155

159 assert(K != AR_Available && "Expected an unavailable declaration here!");

160

161

162 auto DeclLoc = Ctx->getBeginLoc();

163

164 if (DeclLoc.isMacroID() && S.getLangOpts().CPlusPlus &&

165 isa(OffendingDecl)) {

167 if (MacroName == "CF_OPTIONS" || MacroName == "OBJC_OPTIONS" ||

168 MacroName == "SWIFT_OPTIONS" || MacroName == "NS_OPTIONS") {

169 return false;

170 }

171 }

172

173

174

175

176

177

178

180 if (!S.getLangOpts().HLSLStrictAvailability ||

181 (DeclEnv != nullptr &&

183 llvm::Triple::EnvironmentType::Library))

184 return false;

185 }

186

188 if (const auto *VD = dyn_cast(OffendingDecl))

189 if (VD->isLocalVarDeclOrParm() && VD->isDeprecated())

190 return true;

191 }

192

193

194 auto CheckContext = [&](const Decl *C) {

197 if (AA->getIntroduced() >= DeclVersion &&

198 AA->getEnvironment() == DeclEnv)

199 return true;

201 if (C->isDeprecated())

202 return true;

204

205

206

207 if (const auto *MD = dyn_cast(OffendingDecl)) {

208 if (const auto *Impl = dyn_cast(C)) {

209 if (MD->getClassInterface() == Impl->getClassInterface())

210 return true;

211 }

212 }

213 }

214

215 if (C->isUnavailable())

216 return true;

217 return false;

218 };

219

220 do {

221 if (CheckContext(Ctx))

222 return false;

223

224

225

226 if (const auto *MethodD = dyn_cast(Ctx))

227 if (MethodD->isClassMethod() &&

228 MethodD->getSelector().getAsString() == "load")

229 return true;

230

231 if (const auto *CatOrImpl = dyn_cast(Ctx)) {

234 return false;

235 }

236

237 else if (const auto *CatD = dyn_cast(Ctx))

240 return false;

241 } while ((Ctx = cast_or_null(Ctx->getDeclContext())));

242

243 return true;

244}

245

247 const ASTContext &Context, const VersionTuple &DeploymentVersion,

248 const VersionTuple &DeclVersion, bool HasMatchingEnv) {

250 VersionTuple ForceAvailabilityFromVersion;

251 switch (Triple.getOS()) {

252

253

254

255

256 case llvm::Triple::IOS:

257 case llvm::Triple::TvOS:

258 ForceAvailabilityFromVersion = VersionTuple(11);

259 break;

260 case llvm::Triple::WatchOS:

261 ForceAvailabilityFromVersion = VersionTuple(4);

262 break;

263 case llvm::Triple::Darwin:

264 case llvm::Triple::MacOSX:

265 ForceAvailabilityFromVersion = VersionTuple(10, 13);

266 break;

267

268

269

270

271 case llvm::Triple::ShaderModel:

272 return HasMatchingEnv ? diag::warn_hlsl_availability

273 : diag::warn_hlsl_availability_unavailable;

274 default:

275

276 ForceAvailabilityFromVersion =

277 (Triple.getVendor() == llvm::Triple::Apple)

278 ? VersionTuple(0, 0)

279 : VersionTuple((unsigned)-1, (unsigned)-1);

280 }

281 if (DeploymentVersion >= ForceAvailabilityFromVersion ||

282 DeclVersion >= ForceAvailabilityFromVersion)

283 return HasMatchingEnv ? diag::warn_unguarded_availability_new

284 : diag::warn_unguarded_availability_unavailable_new;

285 return HasMatchingEnv ? diag::warn_unguarded_availability

286 : diag::warn_unguarded_availability_unavailable;

287}

288

290 for (Decl *Ctx = OrigCtx; Ctx;

291 Ctx = cast_or_null(Ctx->getDeclContext())) {

292 if (isa(Ctx) || isa(Ctx) || isa(Ctx))

293 return cast(Ctx);

294 if (auto *CD = dyn_cast(Ctx)) {

295 if (auto *Imp = dyn_cast(Ctx))

296 return Imp->getClassInterface();

297 return CD;

298 }

299 }

300

301 return dyn_cast(OrigCtx);

302}

303

304namespace {

305

306struct AttributeInsertion {

307 StringRef Prefix;

309 StringRef Suffix;

310

311 static AttributeInsertion createInsertionAfter(const NamedDecl *D) {

313 }

314 static AttributeInsertion createInsertionAfter(SourceLocation Loc) {

315 return {" ", Loc, ""};

316 }

317 static AttributeInsertion createInsertionBefore(const NamedDecl *D) {

319 }

320};

321

322}

323

324

325

326

327

328

329

330

331

332static std::optional

335

336 if (!Name.empty() && (Name.front() == '-' || Name.front() == '+'))

337 Name = Name.drop_front(1);

338 if (Name.empty())

339 return std::nullopt;

340 Name.split(SlotNames, ':');

341 unsigned NumParams;

342 if (Name.back() == ':') {

343

344 SlotNames.pop_back();

345 NumParams = SlotNames.size();

346 } else {

347 if (SlotNames.size() != 1)

348

349 return std::nullopt;

350 NumParams = 0;

351 }

352

353 bool AllowDollar = LangOpts.DollarIdents;

354 for (StringRef S : SlotNames) {

355 if (S.empty())

356 continue;

358 return std::nullopt;

359 }

360 return NumParams;

361}

362

363

364

365static std::optional

368 if (isa(D))

369 return AttributeInsertion::createInsertionAfter(D);

370 if (const auto *MD = dyn_cast(D)) {

371 if (MD->hasBody())

372 return std::nullopt;

373 return AttributeInsertion::createInsertionAfter(D);

374 }

375 if (const auto *TD = dyn_cast(D)) {

379 return std::nullopt;

380

381 return AttributeInsertion::createInsertionAfter(Loc);

382 }

383 return AttributeInsertion::createInsertionBefore(D);

384}

385

386

387

388

389

390

391

392

393

394

395

399 StringRef Message,

403 bool ObjCPropertyAccess) {

404

405 unsigned diag, diag_message, diag_fwdclass_message;

406 unsigned diag_available_here = diag::note_availability_specified_here;

408

409

410 unsigned property_note_select;

411

412

413 unsigned available_here_select_kind;

414

415 VersionTuple DeclVersion;

418 if (AA) {

419 DeclVersion = AA->getIntroduced();

420 IIEnv = AA->getEnvironment();

421 }

422

424 OffendingDecl))

425 return;

426

428

429

430

431 if (AA && AA->isInherited()) {

434 const AvailabilityAttr *AForRedecl =

436 if (AForRedecl && !AForRedecl->isInherited()) {

437

438

439 NoteLocation = Redecl->getLocation();

440 break;

441 }

442 }

443 }

444

445 switch (K) {

447

448

449

450

451 assert(AA != nullptr && "expecting valid availability attribute");

452 VersionTuple Introduced = AA->getIntroduced();

453 bool EnvironmentMatchesOrNone =

455

457 std::string PlatformName(

458 AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName()));

459 llvm::StringRef TargetEnvironment(

460 llvm::Triple::getEnvironmentTypeName(TI.getTriple().getEnvironment()));

461 llvm::StringRef AttrEnvironment =

462 AA->getEnvironment() ? AA->getEnvironment()->getName() : "";

463 bool UseEnvironment =

464 (!AttrEnvironment.empty() && !TargetEnvironment.empty());

465

468 Introduced, EnvironmentMatchesOrNone);

469

470 S.Diag(Loc, DiagKind) << OffendingDecl << PlatformName

471 << Introduced.getAsString() << UseEnvironment

472 << TargetEnvironment;

473

475 diag::note_partial_availability_specified_here)

476 << OffendingDecl << PlatformName << Introduced.getAsString()

478 << UseEnvironment << AttrEnvironment << TargetEnvironment;

479

480

482 return;

483

485 if (const auto *TD = dyn_cast(Enclosing))

486 if (TD->getDeclName().isEmpty()) {

487 S.Diag(TD->getLocation(),

488 diag::note_decl_unguarded_availability_silence)

489 << 1 << TD->getKindName();

490 return;

491 }

492 auto FixitNoteDiag =

493 S.Diag(Enclosing->getLocation(),

494 diag::note_decl_unguarded_availability_silence)

495 << 0 << Enclosing;

496

497 if (Enclosing->hasAttr())

498 return;

501 return;

504 if (!Insertion)

505 return;

506 StringRef PlatformName =

508

509

510

511

512

513

514

515

516

517

518

519 std::vector EquivalentPlatforms =

520 AvailabilityAttr::equivalentPlatformNames(PlatformName);

521 llvm::Twine MacroPrefix = "__API_AVAILABLE_PLATFORM_";

522 auto AvailablePlatform =

523 llvm::find_if(EquivalentPlatforms, [&](StringRef EquivalentPlatform) {

524 return PP.isMacroDefined((MacroPrefix + EquivalentPlatform).str());

525 });

526 if (AvailablePlatform == EquivalentPlatforms.end())

527 return;

528 std::string Introduced =

531 Insertion->Loc,

532 (llvm::Twine(Insertion->Prefix) + "API_AVAILABLE(" +

533 *AvailablePlatform + "(" + Introduced + "))" + Insertion->Suffix)

534 .str());

535 }

536 return;

537 }

539 diag = !ObjCPropertyAccess ? diag::warn_deprecated

540 : diag::warn_property_method_deprecated;

541 diag_message = diag::warn_deprecated_message;

542 diag_fwdclass_message = diag::warn_deprecated_fwdclass_message;

543 property_note_select = 0;

544 available_here_select_kind = 2;

545 if (const auto *AL = OffendingDecl->getAttr())

546 NoteLocation = AL->getLocation();

547 break;

548

550 diag = !ObjCPropertyAccess ? diag::err_unavailable

551 : diag::err_property_method_unavailable;

552 diag_message = diag::err_unavailable_message;

553 diag_fwdclass_message = diag::warn_unavailable_fwdclass_message;

554 property_note_select = 1;

555 available_here_select_kind = 0;

556

557 if (auto AL = OffendingDecl->getAttr()) {

558 if (AL->isImplicit() && AL->getImplicitReason()) {

559

560

561 auto flagARCError = [&] {

565 diag = diag::err_unavailable_in_arc;

566 };

567

568 switch (AL->getImplicitReason()) {

569 case UnavailableAttr::IR_None: break;

570

571 case UnavailableAttr::IR_ARCForbiddenType:

572 flagARCError();

573 diag_available_here = diag::note_arc_forbidden_type;

574 break;

575

576 case UnavailableAttr::IR_ForbiddenWeak:

578 diag_available_here = diag::note_arc_weak_disabled;

579 else

580 diag_available_here = diag::note_arc_weak_no_runtime;

581 break;

582

583 case UnavailableAttr::IR_ARCForbiddenConversion:

584 flagARCError();

585 diag_available_here = diag::note_performs_forbidden_arc_conversion;

586 break;

587

588 case UnavailableAttr::IR_ARCInitReturnsUnrelated:

589 flagARCError();

590 diag_available_here = diag::note_arc_init_returns_unrelated;

591 break;

592

593 case UnavailableAttr::IR_ARCFieldWithOwnership:

594 flagARCError();

595 diag_available_here = diag::note_arc_field_with_ownership;

596 break;

597 }

598 }

599 }

600 break;

601

603 llvm_unreachable("Warning for availability of available declaration?");

604 }

605

608 StringRef Replacement;

609 if (auto AL = OffendingDecl->getAttr())

610 Replacement = AL->getReplacement();

612 Replacement = AL->getReplacement();

613

615 if (!Replacement.empty())

616 UseRange =

618 if (UseRange.isValid()) {

619 if (const auto *MethodDecl = dyn_cast(ReferringDecl)) {

620 Selector Sel = MethodDecl->getSelector();

623 Replacement, SelectorSlotNames, S.getLangOpts());

624 if (NumParams && *NumParams == Sel.getNumArgs()) {

625 assert(SelectorSlotNames.size() == Locs.size());

626 for (unsigned I = 0; I < Locs.size(); ++I) {

631 NameRange, SelectorSlotNames[I]));

632 } else

633 FixIts.push_back(

635 }

636 } else

638 } else

640 }

641 }

642

643

644

645

646

649 bool ShouldAllowWarningInSystemHeader =

650 InstantiationLoc != Loc &&

652 struct AllowWarningInSystemHeaders {

654 bool AllowWarningInSystemHeaders)

655 : Engine(E), Prev(E.getSuppressSystemWarnings()) {

656 E.setSuppressSystemWarnings(!AllowWarningInSystemHeaders);

657 }

658 ~AllowWarningInSystemHeaders() { Engine.setSuppressSystemWarnings(Prev); }

659

660 private:

662 bool Prev;

664 ShouldAllowWarningInSystemHeader);

665

666 if (!Message.empty()) {

667 S.Diag(Loc, diag_message) << ReferringDecl << Message << FixIts;

668 if (ObjCProperty)

669 S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)

670 << ObjCProperty->getDeclName() << property_note_select;

671 } else if (!UnknownObjCClass) {

672 S.Diag(Loc, diag) << ReferringDecl << FixIts;

673 if (ObjCProperty)

674 S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)

675 << ObjCProperty->getDeclName() << property_note_select;

676 } else {

677 S.Diag(Loc, diag_fwdclass_message) << ReferringDecl << FixIts;

678 S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class);

679 }

680

681 S.Diag(NoteLocation, diag_available_here)

682 << OffendingDecl << available_here_select_kind;

683}

684

687 "Expected an availability diagnostic here");

688

695}

696

700 StringRef Message,

704 bool ObjCPropertyAccess) {

705

709 AR, Locs, ReferringDecl, OffendingDecl, UnknownObjCClass,

710 ObjCProperty, Message, ObjCPropertyAccess));

711 return;

712 }

713

716 Message, Locs, UnknownObjCClass, ObjCProperty,

717 ObjCPropertyAccess);

718}

719

720namespace {

721

722

723bool isBodyLikeChildStmt(const Stmt *S, const Stmt *Parent) {

724 switch (Parent->getStmtClass()) {

725 case Stmt::IfStmtClass:

726 return cast(Parent)->getThen() == S ||

727 cast(Parent)->getElse() == S;

728 case Stmt::WhileStmtClass:

729 return cast(Parent)->getBody() == S;

730 case Stmt::DoStmtClass:

731 return cast(Parent)->getBody() == S;

732 case Stmt::ForStmtClass:

733 return cast(Parent)->getBody() == S;

734 case Stmt::CXXForRangeStmtClass:

735 return cast(Parent)->getBody() == S;

736 case Stmt::ObjCForCollectionStmtClass:

737 return cast(Parent)->getBody() == S;

738 case Stmt::CaseStmtClass:

739 case Stmt::DefaultStmtClass:

740 return cast(Parent)->getSubStmt() == S;

741 default:

742 return false;

743 }

744}

745

748

749public:

750 bool VisitStmt(Stmt *S) override { return S != Target; }

751

752

753 static bool isContained(const Stmt *Target, const Decl *D) {

754 StmtUSEFinder Visitor;

755 Visitor.Target = Target;

756 return !Visitor.TraverseDecl(const_cast<Decl *>(D));

757 }

758};

759

760

761

764

765public:

766 bool VisitDeclRefExpr(DeclRefExpr *DRE) override {

768 return false;

769 return true;

770 }

771

772 static const Stmt *findLastStmtThatUsesDecl(const Decl *D,

774 LastDeclUSEFinder Visitor;

775 Visitor.D = D;

776 for (const Stmt *S : llvm::reverse(Scope->body())) {

777 if (!Visitor.TraverseStmt(const_cast<Stmt *>(S)))

778 return S;

779 }

780 return nullptr;

781 }

782};

783

784

785

786

787

788

789

791 Sema &SemaRef;

793

794

797

800

801public:

802 DiagnoseUnguardedAvailability(Sema &SemaRef, Decl *Ctx)

803 : SemaRef(SemaRef), Ctx(Ctx) {

804 AvailabilityStack.push_back(

806 }

807

808 bool TraverseStmt(Stmt *S) override {

809 if (!S)

810 return true;

811 StmtStack.push_back(S);

813 StmtStack.pop_back();

814 return Result;

815 }

816

817 void IssueDiagnostics(Stmt *S) { TraverseStmt(S); }

818

819 bool TraverseIfStmt(IfStmt *If) override;

820

821

822

823 bool TraverseCaseStmt(CaseStmt *CS) override {

824 return TraverseStmt(CS->getSubStmt());

825 }

826

827 bool VisitObjCMessageExpr(ObjCMessageExpr *Msg) override {

833

834 DiagnoseDeclAvailability(

836 }

837 return true;

838 }

839

840 bool VisitDeclRefExpr(DeclRefExpr *DRE) override {

841 DiagnoseDeclAvailability(DRE->getDecl(),

843 return true;

844 }

845

846 bool VisitMemberExpr(MemberExpr *ME) override {

849 return true;

850 }

851

853 SemaRef.Diag(E->getBeginLoc(), diag::warn_at_available_unchecked_use)

855 return true;

856 }

857

858 bool VisitTypeLoc(TypeLoc Ty) override;

859};

860

861void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability(

865 std::tie(Result, OffendingDecl) =

868

869

871 return;

872

873 const AvailabilityAttr *AA =

875 assert(AA != nullptr && "expecting valid availability attribute");

876 bool EnvironmentMatchesOrNone =

878 VersionTuple Introduced = AA->getIntroduced();

879

880 if (EnvironmentMatchesOrNone && AvailabilityStack.back() >= Introduced)

881 return;

882

883

884

886 AA->getEnvironment(), Ctx,

887 OffendingDecl))

888 return;

889

891 std::string PlatformName(

892 AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName()));

893 llvm::StringRef TargetEnvironment(TI.getTriple().getEnvironmentName());

894 llvm::StringRef AttrEnvironment =

895 AA->getEnvironment() ? AA->getEnvironment()->getName() : "";

896 bool UseEnvironment =

897 (!AttrEnvironment.empty() && !TargetEnvironment.empty());

898

902 EnvironmentMatchesOrNone);

903

905 << Range << D << PlatformName << Introduced.getAsString()

906 << UseEnvironment << TargetEnvironment;

907

909 diag::note_partial_availability_specified_here)

910 << OffendingDecl << PlatformName << Introduced.getAsString()

912 << UseEnvironment << AttrEnvironment << TargetEnvironment;

913

914

916 return;

917

918 auto FixitDiag =

919 SemaRef.Diag(Range.getBegin(), diag::note_unguarded_available_silence)

921 << (SemaRef.getLangOpts().ObjC ? 0

922 : 1);

923

924

925 if (StmtStack.empty())

926 return;

927 const Stmt *StmtOfUse = StmtStack.back();

929 for (const Stmt *S : llvm::reverse(StmtStack)) {

930 if (const auto *CS = dyn_cast(S)) {

932 break;

933 }

934 if (isBodyLikeChildStmt(StmtOfUse, S)) {

935

936

937

938 break;

939 }

940 StmtOfUse = S;

941 }

942 const Stmt *LastStmtOfUse = nullptr;

943 if (isa(StmtOfUse) && Scope) {

944 for (const Decl *D : cast(StmtOfUse)->decls()) {

945 if (StmtUSEFinder::isContained(StmtStack.back(), D)) {

946 LastStmtOfUse = LastDeclUSEFinder::findLastStmtThatUsesDecl(D, Scope);

947 break;

948 }

949 }

950 }

951

956 SM.getExpansionRange(

957 (LastStmtOfUse ? LastStmtOfUse : StmtOfUse)->getEndLoc())

958 .getEnd();

959 if (SM.getFileID(IfInsertionLoc) != SM.getFileID(StmtEndLoc))

960 return;

961

963 const char *ExtraIndentation = " ";

964 std::string FixItString;

965 llvm::raw_string_ostream FixItOS(FixItString);

966 FixItOS << "if (" << (SemaRef.getLangOpts().ObjC ? "@available"

967 : "__builtin_available")

968 << "("

969 << AvailabilityAttr::getPlatformNameSourceSpelling(

971 << " " << Introduced.getAsString() << ", *)) {\n"

972 << Indentation << ExtraIndentation;

975 StmtEndLoc, tok::semi, SM, SemaRef.getLangOpts(),

976 false);

977 if (ElseInsertionLoc.isInvalid())

978 ElseInsertionLoc =

980 FixItOS.str().clear();

981 FixItOS << "\n"

982 << Indentation << "} else {\n"

983 << Indentation << ExtraIndentation

984 << "// Fallback on earlier versions\n"

985 << Indentation << "}";

987 }

988}

989

990bool DiagnoseUnguardedAvailability::VisitTypeLoc(TypeLoc Ty) {

993

995 return true;

996

997 if (const auto *TT = dyn_cast(TyPtr)) {

998 TagDecl *TD = TT->getDecl();

999 DiagnoseDeclAvailability(TD, Range);

1000

1001 } else if (const auto *TD = dyn_cast(TyPtr)) {

1003 DiagnoseDeclAvailability(D, Range);

1004

1005 } else if (const auto *ObjCO = dyn_cast(TyPtr)) {

1006 if (NamedDecl *D = ObjCO->getInterface())

1007 DiagnoseDeclAvailability(D, Range);

1008 }

1009

1010 return true;

1011}

1012

1013struct ExtractedAvailabilityExpr {

1015 bool isNegated = false;

1016};

1017

1018ExtractedAvailabilityExpr extractAvailabilityExpr(const Expr *IfCond) {

1019 const auto *E = IfCond;

1020 bool IsNegated = false;

1021 while (true) {

1023 if (const auto *AE = dyn_cast(E)) {

1024 return ExtractedAvailabilityExpr{AE, IsNegated};

1025 }

1026

1027 const auto *UO = dyn_cast(E);

1028 if (!UO || UO->getOpcode() != UO_LNot) {

1029 return ExtractedAvailabilityExpr{};

1030 }

1031 E = UO->getSubExpr();

1032 IsNegated = !IsNegated;

1033 }

1034}

1035

1036bool DiagnoseUnguardedAvailability::TraverseIfStmt(IfStmt *If) {

1037 ExtractedAvailabilityExpr IfCond = extractAvailabilityExpr(If->getCond());

1038 if (!IfCond.E) {

1039

1040 return DynamicRecursiveASTVisitor::TraverseIfStmt(If);

1041 }

1042

1043 VersionTuple CondVersion = IfCond.E->getVersion();

1044

1045

1046 if (CondVersion.empty() || CondVersion <= AvailabilityStack.back()) {

1047 return TraverseStmt(If->getThen()) && TraverseStmt(If->getElse());

1048 }

1049

1050 auto *Guarded = If->getThen();

1051 auto *Unguarded = If->getElse();

1052 if (IfCond.isNegated) {

1053 std::swap(Guarded, Unguarded);

1054 }

1055

1056 AvailabilityStack.push_back(CondVersion);

1057 bool ShouldContinue = TraverseStmt(Guarded);

1058 AvailabilityStack.pop_back();

1059

1060 return ShouldContinue && TraverseStmt(Unguarded);

1061}

1062

1063}

1064

1066 Stmt *Body = nullptr;

1067

1069 Body = FD->getBody();

1070

1071 if (auto *CD = dyn_cast(FD))

1073 DiagnoseUnguardedAvailability(*this, D).IssueDiagnostics(CI->getInit());

1074

1075 } else if (auto *MD = dyn_cast(D))

1076 Body = MD->getBody();

1077 else if (auto *BD = dyn_cast(D))

1078 Body = BD->getBody();

1079

1080 assert(Body && "Need a body here!");

1081

1082 DiagnoseUnguardedAvailability(*this, D).IssueDiagnostics(Body);

1083}

1084

1087 return nullptr;

1088

1089

1090

1091

1092

1094}

1095

1099 bool ObjCPropertyAccess,

1100 bool AvoidPartialAvailabilityChecks,

1102 std::string Message;

1105

1106 std::tie(Result, OffendingDecl) =

1109 return;

1110

1112 if (AvoidPartialAvailabilityChecks)

1113 return;

1114

1115

1116

1117

1119 Context->HasPotentialAvailabilityViolations = true;

1120 return;

1121 }

1122 }

1123

1125 if (const auto *MD = dyn_cast(D)) {

1128 if (PDeclResult == Result)

1129 ObjCPDecl = PD;

1130 }

1131 }

1132

1134 UnknownObjCClass, ObjCPDecl, ObjCPropertyAccess);

1135}

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)

static std::pair< AvailabilityResult, const NamedDecl * > ShouldDiagnoseAvailabilityOfDecl(Sema &S, const NamedDecl *D, std::string *Message, ObjCInterfaceDecl *ClassReceiver)

The diagnostic we should emit for D, and the declaration that originated it, or AR_Available.

static bool hasMatchingEnvironmentOrNone(const ASTContext &Context, const AvailabilityAttr *AA)

static std::optional< AttributeInsertion > createAttributeInsertion(const NamedDecl *D, const SourceManager &SM, const LangOptions &LangOpts)

Returns a source location in which it's appropriate to insert a new attribute for the given declarati...

static void EmitAvailabilityWarning(Sema &S, AvailabilityResult AR, const NamedDecl *ReferringDecl, const NamedDecl *OffendingDecl, StringRef Message, ArrayRef< SourceLocation > Locs, const ObjCInterfaceDecl *UnknownObjCClass, const ObjCPropertyDecl *ObjCProperty, bool ObjCPropertyAccess)

static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, Decl *Ctx, const NamedDecl *ReferringDecl, const NamedDecl *OffendingDecl, StringRef Message, ArrayRef< SourceLocation > Locs, const ObjCInterfaceDecl *UnknownObjCClass, const ObjCPropertyDecl *ObjCProperty, bool ObjCPropertyAccess)

Actually emit an availability diagnostic for a reference to an unavailable decl.

static NamedDecl * findEnclosingDeclToAnnotate(Decl *OrigCtx)

static std::optional< unsigned > tryParseObjCMethodName(StringRef Name, SmallVectorImpl< StringRef > &SlotNames, const LangOptions &LangOpts)

Tries to parse a string as ObjC method name.

static const AvailabilityAttr * getAttrForPlatform(ASTContext &Context, const Decl *D)

static bool ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K, VersionTuple DeclVersion, const IdentifierInfo *DeclEnv, Decl *Ctx, const NamedDecl *OffendingDecl)

whether we should emit a diagnostic for K and DeclVersion in the context of Ctx.

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 LangOptions & getLangOpts() const

const TargetInfo & getTargetInfo() const

Represents a C++ base or member initializer.

CaseStmt - Represent a case statement.

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...

A reference to a declared variable, function, enum, etc.

SourceLocation getBeginLoc() const LLVM_READONLY

SourceLocation getEndLoc() const LLVM_READONLY

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

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.

Recursive AST visitor that supports extension via dynamic dispatch.

virtual bool TraverseStmt(Stmt *S)

Recursively visit a statement or expression, by dispatching to Traverse*() based on the argument's dy...

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.

MemberExpr - [C99 6.5.2.3] Structure and Union Members.

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()

A runtime availability query.

Represents an ObjC class declaration.

ObjCMethodDecl * lookupInstanceMethod(Selector Sel) const

Lookup an instance method for a given selector.

An expression that sends a message to the given Objective-C object or class.

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.

ObjCInterfaceDecl * getInterface() const

Gets the interface declaration for this object type, if the base type really is an interface.

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.

A (possibly-)qualified type.

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, bool DeferHint=false)

Emit a diagnostic.

std::unique_ptr< NSAPI > NSAPIObj

Caches identifiers/selectors for NSFoundation APIs.

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

class clang::Sema::DelayedDiagnostics DelayedDiagnostics

DiagnosticsEngine & getDiagnostics() const

ASTContext & getASTContext() const

void DiagnoseUnguardedAvailabilityViolations(Decl *FD)

Issue any -Wunguarded-availability warnings in FD.

SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset=0)

Calls Lexer::getLocForEndOfToken()

const LangOptions & getLangOpts() const

DeclContext * getCurLexicalContext() const

SourceManager & getSourceManager() const

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.

SourceLocation getBegin() const

Stmt - This represents one statement.

SourceLocation getBeginLoc() const LLVM_READONLY

Represents the declaration of a struct/union/class/enum.

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.

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.

@ Result

The result type of a method or function.

AvailabilityResult

Captures the result of checking the availability of a declaration.

@ Interface

The "__interface" keyword introduces the elaborated-type-specifier.