Skip to content

Commit 18a9d70

Browse files
authored
[APIGen] Handle SPI availability for nested decls (#85048)
- Add SPI availability information to `APIAvailability` from attribute `@_spi_available`. - Correctly obtain effective availability for nested declarations without immediate availability attributes. Resolves rdar://159702280 <!-- If this pull request is targeting a release branch, please fill out the following form: https://github.com/swiftlang/.github/blob/main/PULL_REQUEST_TEMPLATE/release.md?plain=1 Otherwise, replace this comment with a description of your changes and rationale. Provide links to external references/discussions if appropriate. If this pull request resolves any GitHub issues, link them like so: Resolves <link to issue>, resolves <link to another issue>. For more information about linking a pull request to an issue, see: https://docs.github.com/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue --> <!-- Before merging this pull request, you must run the Swift continuous integration tests. For information about triggering CI builds via @swift-ci, see: https://github.com/apple/swift/blob/main/docs/ContinuousIntegration.md#swift-ci Thank you for your contribution to Swift! -->
1 parent b6c29f1 commit 18a9d70

File tree

7 files changed

+381
-294
lines changed

7 files changed

+381
-294
lines changed

lib/IRGen/APIGen.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ static void serialize(llvm::json::OStream &OS, APIAvailability availability) {
8484
OS.attribute("obsoleted", availability.obsoleted);
8585
if (availability.unavailable)
8686
OS.attribute("unavailable", availability.unavailable);
87+
if (availability.spiAvailable)
88+
OS.attribute("SPIAvailable", availability.spiAvailable);
8789
}
8890

8991
static void serialize(llvm::json::OStream &OS, APILinkage linkage) {

lib/IRGen/APIGen.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,11 @@ struct APIAvailability {
7272
std::string introduced;
7373
std::string obsoleted;
7474
bool unavailable = false;
75+
bool spiAvailable = false;
7576

7677
bool empty() {
77-
return introduced.empty() && obsoleted.empty() && !unavailable;
78+
return introduced.empty() && obsoleted.empty() && !unavailable &&
79+
!spiAvailable;
7880
}
7981
};
8082

lib/IRGen/TBDGen.cpp

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -702,7 +702,7 @@ void swift::writeTBDFile(ModuleDecl *M, llvm::raw_ostream &os,
702702
}
703703

704704
class APIGenRecorder final : public APIRecorder {
705-
static bool isSPI(const Decl *decl) {
705+
bool isSPI(const Decl *decl) {
706706
assert(decl);
707707

708708
if (auto value = dyn_cast<ValueDecl>(decl)) {
@@ -716,7 +716,7 @@ class APIGenRecorder final : public APIRecorder {
716716
return true;
717717
}
718718

719-
return decl->isSPI() || decl->isAvailableAsSPI();
719+
return decl->isSPI() || getAvailability(decl).spiAvailable;
720720
}
721721

722722
public:
@@ -821,25 +821,31 @@ class APIGenRecorder final : public APIRecorder {
821821
llvm::DenseMap<CategoryNameKey, unsigned> CategoryCounts;
822822

823823
apigen::APIAvailability getAvailability(const Decl *decl) {
824-
std::optional<bool> unavailable;
824+
std::optional<bool> unavailable, spiAvailable;
825825
std::string introduced, obsoleted;
826-
bool hasFallbackUnavailability = false;
826+
bool hasFallbackUnavailability = false, hasFallbackSPIAvailability = false;
827827
auto platform = targetPlatform(module->getASTContext().LangOpts);
828-
for (auto attr : decl->getSemanticAvailableAttrs()) {
828+
const Decl *declForAvailability = decl->getInnermostDeclWithAvailability();
829+
if (!declForAvailability)
830+
return {};
831+
for (auto attr : declForAvailability->getSemanticAvailableAttrs()) {
829832
if (!attr.isPlatformSpecific()) {
830833
hasFallbackUnavailability = attr.isUnconditionallyUnavailable();
834+
hasFallbackSPIAvailability = attr.isSPI();
831835
continue;
832836
}
833837
if (attr.getPlatform() != platform)
834838
continue;
835839
unavailable = attr.isUnconditionallyUnavailable();
840+
spiAvailable = attr.isSPI();
836841
if (attr.getIntroduced())
837842
introduced = attr.getIntroduced()->getAsString();
838843
if (attr.getObsoleted())
839844
obsoleted = attr.getObsoleted()->getAsString();
840845
}
841846
return {introduced, obsoleted,
842-
unavailable.value_or(hasFallbackUnavailability)};
847+
unavailable.value_or(hasFallbackUnavailability),
848+
spiAvailable.value_or(hasFallbackSPIAvailability)};
843849
}
844850

845851
StringRef getSelectorName(SILDeclRef method, SmallString<128> &buffer) {

test/APIJSON/apigen.swift

Lines changed: 47 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -127,13 +127,15 @@ public var myGlobalVar: Int = 42
127127
// CHECK-NEXT: "name": "_$s8MyModule4TestC7method1yyFTj",
128128
// CHECK-NEXT: "access": "public",
129129
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
130-
// CHECK-NEXT: "linkage": "exported"
130+
// CHECK-NEXT: "linkage": "exported",
131+
// CHECK-NEXT: "introduced": "10.13"
131132
// CHECK-NEXT: },
132133
// CHECK-NEXT: {
133134
// CHECK-NEXT: "name": "_$s8MyModule4TestC7method1yyFTq",
134135
// CHECK-NEXT: "access": "public",
135136
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
136137
// CHECK-NEXT: "linkage": "exported"
138+
// CHECK-NEXT: "introduced": "10.13"
137139
// CHECK-NEXT: },
138140
// CHECK-NEXT: {
139141
// CHECK-NEXT: "name": "_$s8MyModule4TestC7method2yyFZTj",
@@ -153,25 +155,29 @@ public var myGlobalVar: Int = 42
153155
// CHECK-NEXT: "name": "_$s8MyModule4TestC7nonObjcyyFTj",
154156
// CHECK-NEXT: "access": "public",
155157
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
156-
// CHECK-NEXT: "linkage": "exported"
158+
// CHECK-NEXT: "linkage": "exported",
159+
// CHECK-NEXT: "introduced": "10.13"
157160
// CHECK-NEXT: },
158161
// CHECK-NEXT: {
159162
// CHECK-NEXT: "name": "_$s8MyModule4TestC7nonObjcyyFTq",
160163
// CHECK-NEXT: "access": "public",
161164
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
162-
// CHECK-NEXT: "linkage": "exported"
165+
// CHECK-NEXT: "linkage": "exported",
166+
// CHECK-NEXT: "introduced": "10.13"
163167
// CHECK-NEXT: },
164168
// CHECK-NEXT: {
165169
// CHECK-NEXT: "name": "_$s8MyModule4TestCACycfC",
166170
// CHECK-NEXT: "access": "public",
167171
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
168-
// CHECK-NEXT: "linkage": "exported"
172+
// CHECK-NEXT: "linkage": "exported",
173+
// CHECK-NEXT: "introduced": "10.13"
169174
// CHECK-NEXT: },
170175
// CHECK-NEXT: {
171176
// CHECK-NEXT: "name": "_$s8MyModule4TestCACycfc",
172177
// CHECK-NEXT: "access": "public",
173178
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
174-
// CHECK-NEXT: "linkage": "exported"
179+
// CHECK-NEXT: "linkage": "exported",
180+
// CHECK-NEXT: "introduced": "10.13"
175181
// CHECK-NEXT: },
176182
// CHECK-NEXT: {
177183
// CHECK-NEXT: "name": "_$s8MyModule4TestCMa",
@@ -212,7 +218,8 @@ public var myGlobalVar: Int = 42
212218
// CHECK-NEXT: "name": "_$s8MyModule4TestCfD",
213219
// CHECK-NEXT: "access": "public",
214220
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
215-
// CHECK-NEXT: "linkage": "exported"
221+
// CHECK-NEXT: "linkage": "exported",
222+
// CHECK-NEXT: "introduced": "10.13"
216223
// CHECK-NEXT: },
217224
// CHECK-NEXT: {
218225
// CHECK-NEXT: "name": "_$s8MyModule5Test2CMa",
@@ -350,31 +357,36 @@ public var myGlobalVar: Int = 42
350357
// CHECK-NEXT: "name": "_$s8MyModule7DerivedC15inheritlyPublicyyF",
351358
// CHECK-NEXT: "access": "public",
352359
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
353-
// CHECK-NEXT: "linkage": "exported"
360+
// CHECK-NEXT: "linkage": "exported",
361+
// CHECK-NEXT: "introduced": "10.13"
354362
// CHECK-NEXT: },
355363
// CHECK-NEXT: {
356364
// CHECK-NEXT: "name": "_$s8MyModule7DerivedC8readOnlyACSi_tcfC",
357365
// CHECK-NEXT: "access": "private",
358366
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
359-
// CHECK-NEXT: "linkage": "exported"
367+
// CHECK-NEXT: "linkage": "exported",
368+
// CHECK-NEXT: "introduced": "10.13"
360369
// CHECK-NEXT: },
361370
// CHECK-NEXT: {
362371
// CHECK-NEXT: "name": "_$s8MyModule7DerivedC8readOnlyACSi_tcfCTj",
363372
// CHECK-NEXT: "access": "private",
364373
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
365-
// CHECK-NEXT: "linkage": "exported"
374+
// CHECK-NEXT: "linkage": "exported",
375+
// CHECK-NEXT: "introduced": "10.13"
366376
// CHECK-NEXT: },
367377
// CHECK-NEXT: {
368378
// CHECK-NEXT: "name": "_$s8MyModule7DerivedC8readOnlyACSi_tcfCTq",
369379
// CHECK-NEXT: "access": "private",
370380
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
371-
// CHECK-NEXT: "linkage": "exported"
381+
// CHECK-NEXT: "linkage": "exported",
382+
// CHECK-NEXT: "introduced": "10.13"
372383
// CHECK-NEXT: },
373384
// CHECK-NEXT: {
374385
// CHECK-NEXT: "name": "_$s8MyModule7DerivedC8readOnlyACSi_tcfc",
375386
// CHECK-NEXT: "access": "private",
376387
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
377-
// CHECK-NEXT: "linkage": "exported"
388+
// CHECK-NEXT: "linkage": "exported",
389+
// CHECK-NEXT: "introduced": "10.13"
378390
// CHECK-NEXT: },
379391
// CHECK-NEXT: {
380392
// CHECK-NEXT: "name": "_$s8MyModule7DerivedC8readOnlySivMTj",
@@ -394,43 +406,50 @@ public var myGlobalVar: Int = 42
394406
// CHECK-NEXT: "name": "_$s8MyModule7DerivedC8readOnlySivgTj",
395407
// CHECK-NEXT: "access": "public",
396408
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
397-
// CHECK-NEXT: "linkage": "exported"
409+
// CHECK-NEXT: "linkage": "exported",
410+
// CHECK-NEXT: "introduced": "10.13"
398411
// CHECK-NEXT: },
399412
// CHECK-NEXT: {
400413
// CHECK-NEXT: "name": "_$s8MyModule7DerivedC8readOnlySivgTq",
401414
// CHECK-NEXT: "access": "public",
402415
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
403-
// CHECK-NEXT: "linkage": "exported"
416+
// CHECK-NEXT: "linkage": "exported",
417+
// CHECK-NEXT: "introduced": "10.13"
404418
// CHECK-NEXT: },
405419
// CHECK-NEXT: {
406420
// CHECK-NEXT: "name": "_$s8MyModule7DerivedC8readOnlySivpMV",
407421
// CHECK-NEXT: "access": "public",
408422
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
409-
// CHECK-NEXT: "linkage": "exported"
423+
// CHECK-NEXT: "linkage": "exported",
424+
// CHECK-NEXT: "introduced": "10.13"
410425
// CHECK-NEXT: },
411426
// CHECK-NEXT: {
412427
// CHECK-NEXT: "name": "_$s8MyModule7DerivedC8readOnlySivsTj",
413428
// CHECK-NEXT: "access": "private",
414429
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
415-
// CHECK-NEXT: "linkage": "exported"
430+
// CHECK-NEXT: "linkage": "exported",
431+
// CHECK-NEXT: "introduced": "10.13"
416432
// CHECK-NEXT: },
417433
// CHECK-NEXT: {
418434
// CHECK-NEXT: "name": "_$s8MyModule7DerivedC8readOnlySivsTq",
419435
// CHECK-NEXT: "access": "private",
420436
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
421-
// CHECK-NEXT: "linkage": "exported"
437+
// CHECK-NEXT: "linkage": "exported",
438+
// CHECK-NEXT: "introduced": "10.13"
422439
// CHECK-NEXT: },
423440
// CHECK-NEXT: {
424441
// CHECK-NEXT: "name": "_$s8MyModule7DerivedCACycfC",
425442
// CHECK-NEXT: "access": "public",
426443
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
427-
// CHECK-NEXT: "linkage": "exported"
444+
// CHECK-NEXT: "linkage": "exported",
445+
// CHECK-NEXT: "introduced": "10.13"
428446
// CHECK-NEXT: },
429447
// CHECK-NEXT: {
430448
// CHECK-NEXT: "name": "_$s8MyModule7DerivedCACycfc",
431449
// CHECK-NEXT: "access": "public",
432450
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
433-
// CHECK-NEXT: "linkage": "exported"
451+
// CHECK-NEXT: "linkage": "exported",
452+
// CHECK-NEXT: "introduced": "10.13"
434453
// CHECK-NEXT: },
435454
// CHECK-NEXT: {
436455
// CHECK-NEXT: "name": "_$s8MyModule7DerivedCMa",
@@ -471,7 +490,8 @@ public var myGlobalVar: Int = 42
471490
// CHECK-NEXT: "name": "_$s8MyModule7DerivedCfD",
472491
// CHECK-NEXT: "access": "public",
473492
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
474-
// CHECK-NEXT: "linkage": "exported"
493+
// CHECK-NEXT: "linkage": "exported",
494+
// CHECK-NEXT: "introduced": "10.13"
475495
// CHECK-NEXT: }
476496
// CHECK-NEXT: ],
477497
// CHECK-NEXT: "interfaces": [
@@ -486,12 +506,14 @@ public var myGlobalVar: Int = 42
486506
// CHECK-NEXT: {
487507
// CHECK-NEXT: "name": "method1",
488508
// CHECK-NEXT: "access": "public",
489-
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift"
509+
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
510+
// CHECK-NEXT: "introduced": "10.13"
490511
// CHECK-NEXT: },
491512
// CHECK-NEXT: {
492513
// CHECK-NEXT: "name": "init",
493514
// CHECK-NEXT: "access": "public",
494-
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift"
515+
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
516+
// CHECK-NEXT: "introduced": "10.13"
495517
// CHECK-NEXT: }
496518
// CHECK-NEXT: ],
497519
// CHECK-NEXT: "classMethods": [
@@ -539,12 +561,14 @@ public var myGlobalVar: Int = 42
539561
// CHECK-NEXT: {
540562
// CHECK-NEXT: "name": "method1",
541563
// CHECK-NEXT: "access": "public",
542-
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift"
564+
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
565+
// CHECK-NEXT: "introduced": "10.13"
543566
// CHECK-NEXT: },
544567
// CHECK-NEXT: {
545568
// CHECK-NEXT: "name": "init",
546569
// CHECK-NEXT: "access": "public",
547-
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift"
570+
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
571+
// CHECK-NEXT: "introduced": "10.13"
548572
// CHECK-NEXT: }
549573
// CHECK-NEXT: ],
550574
// CHECK-NEXT: "classMethods": []

0 commit comments

Comments
 (0)