Skip to content

Commit d652100

Browse files
authored
[APIGen] Account for access scopes of declarations (#84116)
Correctly account for access scopes of declarations visited by APIGen: Mark declarations with non-public access scopes as private SPIs. Resolves rdar://159701853
1 parent a956308 commit d652100

File tree

2 files changed

+128
-4
lines changed

2 files changed

+128
-4
lines changed

lib/IRGen/TBDGen.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,18 @@ void swift::writeTBDFile(ModuleDecl *M, llvm::raw_ostream &os,
686686
class APIGenRecorder final : public APIRecorder {
687687
static bool isSPI(const Decl *decl) {
688688
assert(decl);
689+
690+
if (auto value = dyn_cast<ValueDecl>(decl)) {
691+
auto accessScope =
692+
value->getFormalAccessScope(/*useDC=*/nullptr,
693+
/*treatUsableFromInlineAsPublic=*/true);
694+
// Only declarations with a public access scope (`public` or `open`)
695+
// can be APIs. Exported declarations with other access scopes (`package`)
696+
// should be SPI.
697+
if (!accessScope.isPublic())
698+
return true;
699+
}
700+
689701
return decl->isSPI() || decl->isAvailableAsSPI();
690702
}
691703

test/APIJSON/apigen.swift

Lines changed: 116 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
// REQUIRES: objc_interop, OS=macosx
22
// RUN: %empty-directory(%t)
33
// RUN: %empty-directory(%t/ModuleCache)
4-
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) %s -typecheck -parse-as-library -emit-module-interface-path %t/MyModule.swiftinterface -enable-library-evolution -module-name MyModule -swift-version 5
5-
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) %s -typecheck -parse-as-library -emit-module-interface-path %t/MyModule.swiftinterface -enable-library-evolution -module-name MyModule -swift-version 5 -emit-api-descriptor-path %t/api.json
4+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) %s -typecheck -parse-as-library -emit-module-interface-path %t/MyModule.swiftinterface -enable-library-evolution -module-name MyModule -package-name MyModule -swift-version 5
5+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) %s -typecheck -parse-as-library -emit-module-interface-path %t/MyModule.swiftinterface -enable-library-evolution -module-name MyModule -package-name MyModule -swift-version 5 -emit-api-descriptor-path %t/api.json
66
// RUN: %validate-json %t/api.json | %FileCheck %s
77

88
import Foundation
@@ -19,6 +19,21 @@ public class Test : NSObject {
1919
public class Derived : Test {
2020
@objc public override func method1() {}
2121
public override func nonObjc() {}
22+
23+
private var _readOnly : Int
24+
package init(readOnly: Int) {
25+
_readOnly = readOnly
26+
}
27+
public package(set) var readOnly : Int {
28+
get { _readOnly }
29+
set { _readOnly = newValue }
30+
}
31+
}
32+
33+
// Member declarations inside a `public extension` are public implicitly
34+
public extension Derived {
35+
func inheritlyPublic() {}
36+
private func privateFunc() {}
2237
}
2338

2439
// Not derived from NSObject. ObjC metadata is still emitted but not exported.
@@ -35,7 +50,7 @@ public class Test3 : NSObject {
3550
}
3651

3752
@available(macOS 10.13, *)
38-
public func myFunction() -> Int {
53+
package func myFunction() -> Int {
3954
return 0
4055
}
4156

@@ -45,14 +60,24 @@ public func myFunction1() {}
4560
@available(*, unavailable)
4661
public func myFunction2() {}
4762

63+
package func packageFunction() {}
64+
65+
internal func internalFunction() {}
66+
67+
private func privateFunction() {}
68+
69+
fileprivate func fileprivateFunction() {}
70+
71+
func implicitInternalFunction() {}
72+
4873
@available(macOS 10.13, *)
4974
public var myGlobalVar: Int = 42
5075

5176
// CHECK: "target"
5277
// CHECK-NEXT: "globals": [
5378
// CHECK-NEXT: {
5479
// CHECK-NEXT: "name": "_$s8MyModule10myFunctionSiyF",
55-
// CHECK-NEXT: "access": "public",
80+
// CHECK-NEXT: "access": "private",
5681
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
5782
// CHECK-NEXT: "linkage": "exported",
5883
// CHECK-NEXT: "introduced": "10.13"
@@ -93,6 +118,12 @@ public var myGlobalVar: Int = 42
93118
// CHECK-NEXT: "introduced": "10.13"
94119
// CHECK-NEXT: },
95120
// CHECK-NEXT: {
121+
// CHECK-NEXT: "name": "_$s8MyModule15packageFunctionyyF",
122+
// CHECK-NEXT: "access": "private",
123+
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
124+
// CHECK-NEXT: "linkage": "exported"
125+
// CHECK-NEXT: },
126+
// CHECK-NEXT: {
96127
// CHECK-NEXT: "name": "_$s8MyModule4TestC7method1yyFTj",
97128
// CHECK-NEXT: "access": "public",
98129
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
@@ -316,6 +347,80 @@ public var myGlobalVar: Int = 42
316347
// CHECK-NEXT: "linkage": "exported"
317348
// CHECK-NEXT: },
318349
// CHECK-NEXT: {
350+
// CHECK-NEXT: "name": "_$s8MyModule7DerivedC15inheritlyPublicyyF",
351+
// CHECK-NEXT: "access": "public",
352+
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
353+
// CHECK-NEXT: "linkage": "exported"
354+
// CHECK-NEXT: },
355+
// CHECK-NEXT: {
356+
// CHECK-NEXT: "name": "_$s8MyModule7DerivedC8readOnlyACSi_tcfC",
357+
// CHECK-NEXT: "access": "private",
358+
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
359+
// CHECK-NEXT: "linkage": "exported"
360+
// CHECK-NEXT: },
361+
// CHECK-NEXT: {
362+
// CHECK-NEXT: "name": "_$s8MyModule7DerivedC8readOnlyACSi_tcfCTj",
363+
// CHECK-NEXT: "access": "private",
364+
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
365+
// CHECK-NEXT: "linkage": "exported"
366+
// CHECK-NEXT: },
367+
// CHECK-NEXT: {
368+
// CHECK-NEXT: "name": "_$s8MyModule7DerivedC8readOnlyACSi_tcfCTq",
369+
// CHECK-NEXT: "access": "private",
370+
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
371+
// CHECK-NEXT: "linkage": "exported"
372+
// CHECK-NEXT: },
373+
// CHECK-NEXT: {
374+
// CHECK-NEXT: "name": "_$s8MyModule7DerivedC8readOnlyACSi_tcfc",
375+
// CHECK-NEXT: "access": "private",
376+
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
377+
// CHECK-NEXT: "linkage": "exported"
378+
// CHECK-NEXT: },
379+
// CHECK-NEXT: {
380+
// CHECK-NEXT: "name": "_$s8MyModule7DerivedC8readOnlySivMTj",
381+
// CHECK-NEXT: "access": "private",
382+
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
383+
// CHECK-NEXT: "linkage": "exported",
384+
// CHECK-NEXT: "introduced": "10.13"
385+
// CHECK-NEXT: },
386+
// CHECK-NEXT: {
387+
// CHECK-NEXT: "name": "_$s8MyModule7DerivedC8readOnlySivMTq",
388+
// CHECK-NEXT: "access": "private",
389+
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
390+
// CHECK-NEXT: "linkage": "exported",
391+
// CHECK-NEXT: "introduced": "10.13"
392+
// CHECK-NEXT: },
393+
// CHECK-NEXT: {
394+
// CHECK-NEXT: "name": "_$s8MyModule7DerivedC8readOnlySivgTj",
395+
// CHECK-NEXT: "access": "public",
396+
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
397+
// CHECK-NEXT: "linkage": "exported"
398+
// CHECK-NEXT: },
399+
// CHECK-NEXT: {
400+
// CHECK-NEXT: "name": "_$s8MyModule7DerivedC8readOnlySivgTq",
401+
// CHECK-NEXT: "access": "public",
402+
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
403+
// CHECK-NEXT: "linkage": "exported"
404+
// CHECK-NEXT: },
405+
// CHECK-NEXT: {
406+
// CHECK-NEXT: "name": "_$s8MyModule7DerivedC8readOnlySivpMV",
407+
// CHECK-NEXT: "access": "public",
408+
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
409+
// CHECK-NEXT: "linkage": "exported"
410+
// CHECK-NEXT: },
411+
// CHECK-NEXT: {
412+
// CHECK-NEXT: "name": "_$s8MyModule7DerivedC8readOnlySivsTj",
413+
// CHECK-NEXT: "access": "private",
414+
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
415+
// CHECK-NEXT: "linkage": "exported"
416+
// CHECK-NEXT: },
417+
// CHECK-NEXT: {
418+
// CHECK-NEXT: "name": "_$s8MyModule7DerivedC8readOnlySivsTq",
419+
// CHECK-NEXT: "access": "private",
420+
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
421+
// CHECK-NEXT: "linkage": "exported"
422+
// CHECK-NEXT: },
423+
// CHECK-NEXT: {
319424
// CHECK-NEXT: "name": "_$s8MyModule7DerivedCACycfC",
320425
// CHECK-NEXT: "access": "public",
321426
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
@@ -349,6 +454,13 @@ public var myGlobalVar: Int = 42
349454
// CHECK-NEXT: "introduced": "10.13"
350455
// CHECK-NEXT: },
351456
// CHECK-NEXT: {
457+
// CHECK-NEXT: "name": "_$s8MyModule7DerivedCMu",
458+
// CHECK-NEXT: "access": "public",
459+
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",
460+
// CHECK-NEXT: "linkage": "exported",
461+
// CHECK-NEXT: "introduced": "10.13"
462+
// CHECK-NEXT: },
463+
// CHECK-NEXT: {
352464
// CHECK-NEXT: "name": "_$s8MyModule7DerivedCN",
353465
// CHECK-NEXT: "access": "public",
354466
// CHECK-NEXT: "file": "SOURCE_DIR/test/APIJSON/apigen.swift",

0 commit comments

Comments
 (0)