Skip to content

Commit 5dae683

Browse files
[swift-api-extract] Handle @_spi interfaces with correct APIAccess
rdar://83506338
1 parent 71eedb1 commit 5dae683

File tree

3 files changed

+241
-15
lines changed

3 files changed

+241
-15
lines changed

include/swift/IRGen/Linking.h

+4
Original file line numberDiff line numberDiff line change
@@ -1266,6 +1266,10 @@ class LinkEntity {
12661266
std::string mangleAsString() const;
12671267
SILLinkage getLinkage(ForDefinition_t isDefinition) const;
12681268

1269+
bool hasDecl() const {
1270+
return isDeclKind(getKind());
1271+
}
1272+
12691273
const ValueDecl *getDecl() const {
12701274
assert(isDeclKind(getKind()));
12711275
return reinterpret_cast<ValueDecl*>(Pointer);

lib/TBDGen/TBDGen.cpp

+27-13
Original file line numberDiff line numberDiff line change
@@ -1362,15 +1362,24 @@ class APIGenRecorder final : public APIRecorder {
13621362
return;
13631363

13641364
apigen::APIAvailability availability;
1365+
auto access = apigen::APIAccess::Public;
13651366
if (source.kind == SymbolSource::Kind::SIL) {
13661367
auto ref = source.getSILDeclRef();
1367-
if (ref.hasDecl())
1368+
if (ref.hasDecl()) {
13681369
availability = getAvailability(ref.getDecl());
1370+
if (ref.getDecl()->isSPI())
1371+
access = apigen::APIAccess::Private;
1372+
}
1373+
} else if (source.kind == SymbolSource::Kind::IR) {
1374+
auto ref = source.getIRLinkEntity();
1375+
if (ref.hasDecl()) {
1376+
if (ref.getDecl()->isSPI())
1377+
access = apigen::APIAccess::Private;
1378+
}
13691379
}
13701380

13711381
api.addSymbol(symbol, moduleLoc, apigen::APILinkage::Exported,
1372-
apigen::APIFlags::None, apigen::APIAccess::Public,
1373-
availability);
1382+
apigen::APIFlags::None, access, availability);
13741383
}
13751384

13761385
void addObjCInterface(const ClassDecl *decl) override {
@@ -1383,15 +1392,19 @@ class APIGenRecorder final : public APIRecorder {
13831392
StringRef name = getSelectorName(method, buffer);
13841393
apigen::APIAvailability availability;
13851394
bool isInstanceMethod = true;
1386-
if (auto *decl = method.getDecl()) {
1387-
availability = getAvailability(decl);
1388-
if (decl->getDescriptiveKind() == DescriptiveDeclKind::ClassMethod)
1395+
auto access = apigen::APIAccess::Public;
1396+
if (method.hasDecl()) {
1397+
availability = getAvailability(method.getDecl());
1398+
if (method.getDecl()->getDescriptiveKind() ==
1399+
DescriptiveDeclKind::ClassMethod)
13891400
isInstanceMethod = false;
1401+
if (method.getDecl()->isSPI())
1402+
access = apigen::APIAccess::Private;
13901403
}
13911404

13921405
auto *clsRecord = addOrGetObjCInterface(cls);
1393-
api.addObjCMethod(clsRecord, name, moduleLoc, apigen::APIAccess::Public,
1394-
isInstanceMethod, false, availability);
1406+
api.addObjCMethod(clsRecord, name, moduleLoc, access, isInstanceMethod,
1407+
false, availability);
13951408
}
13961409

13971410
private:
@@ -1439,11 +1452,12 @@ class APIGenRecorder final : public APIRecorder {
14391452
if (auto *super = decl->getSuperclassDecl())
14401453
superCls = super->getObjCRuntimeName(buffer);
14411454
apigen::APIAvailability availability = getAvailability(decl);
1442-
apigen::APIAccess access = decl->getFormalAccess() == AccessLevel::Public
1443-
? apigen::APIAccess::Public
1444-
: apigen::APIAccess::Private;
1445-
apigen::APILinkage linkage = decl->isObjC() ? apigen::APILinkage::Exported
1446-
: apigen::APILinkage::Internal;
1455+
apigen::APIAccess access =
1456+
decl->isSPI() ? apigen::APIAccess::Private : apigen::APIAccess::Public;
1457+
apigen::APILinkage linkage =
1458+
decl->getFormalAccess() == AccessLevel::Public && decl->isObjC()
1459+
? apigen::APILinkage::Exported
1460+
: apigen::APILinkage::Internal;
14471461
auto cls = api.addObjCClass(name, linkage, moduleLoc, access, availability,
14481462
superCls);
14491463
classMap.try_emplace(decl, cls);

test/APIJSON/spi.swift

+210-2
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,18 @@
33
// RUN: %target-swift-frontend %s -typecheck -emit-module-interface-path %t/MyModule.swiftinterface -enable-library-evolution -module-name MyModule -swift-version 5
44
// RUN: %target-swift-api-extract -o - -pretty-print %t/MyModule.swiftinterface -module-name MyModule -module-cache-path %t | %FileCheck %s
55

6+
// RUN: %target-swift-frontend %s -emit-module -emit-module-path %t/MyModule.swiftmodule -enable-library-evolution -module-name MyModule -swift-version 5
7+
// RUN: %target-swift-api-extract -o - -pretty-print %t/MyModule.swiftmodule -module-name MyModule -module-cache-path %t | %FileCheck %s --check-prefix=CHECK-SPI
8+
69
import Foundation
710

811
@_spi(Experimental) public func newUnprovenFunc() {}
912
@_spi(Experimental) public class MyClass : NSObject {
10-
public func spiMethod() {}
13+
@objc public func spiMethod() {}
1114
}
1215

1316
public class MyClass2 : NSObject {
14-
@_spi(Experimental) public func spiMethod() {}
17+
@_spi(Experimental) @objc public func spiMethod() {}
1518
}
1619

1720
// CHECK: {
@@ -91,3 +94,208 @@ public class MyClass2 : NSObject {
9194
// CHECK-NEXT: ],
9295
// CHECK-NEXT: "version": "1.0"
9396
// CHECK-NEXT: }
97+
98+
// CHECK-SPI: {
99+
// CHECK-SPI-NEXT: "target":
100+
// CHECK-SPI-NEXT: "globals": [
101+
// CHECK-SPI-NEXT: {
102+
// CHECK-SPI-NEXT: "name": "_$s8MyModule0A5ClassC9spiMethodyyFTj",
103+
// CHECK-SPI-NEXT: "access": "private",
104+
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule",
105+
// CHECK-SPI-NEXT: "linkage": "exported"
106+
// CHECK-SPI-NEXT: },
107+
// CHECK-SPI-NEXT: {
108+
// CHECK-SPI-NEXT: "name": "_$s8MyModule0A5ClassC9spiMethodyyFTq",
109+
// CHECK-SPI-NEXT: "access": "private",
110+
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule",
111+
// CHECK-SPI-NEXT: "linkage": "exported"
112+
// CHECK-SPI-NEXT: },
113+
// CHECK-SPI-NEXT: {
114+
// CHECK-SPI-NEXT: "name": "_$s8MyModule0A5ClassCACycfC",
115+
// CHECK-SPI-NEXT: "access": "private",
116+
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule",
117+
// CHECK-SPI-NEXT: "linkage": "exported"
118+
// CHECK-SPI-NEXT: },
119+
// CHECK-SPI-NEXT: {
120+
// CHECK-SPI-NEXT: "name": "_$s8MyModule0A5ClassCACycfc",
121+
// CHECK-SPI-NEXT: "access": "private",
122+
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule",
123+
// CHECK-SPI-NEXT: "linkage": "exported"
124+
// CHECK-SPI-NEXT: },
125+
// CHECK-SPI-NEXT: {
126+
// CHECK-SPI-NEXT: "name": "_$s8MyModule0A5ClassCMa",
127+
// CHECK-SPI-NEXT: "access": "public",
128+
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule",
129+
// CHECK-SPI-NEXT: "linkage": "exported"
130+
// CHECK-SPI-NEXT: },
131+
// CHECK-SPI-NEXT: {
132+
// CHECK-SPI-NEXT: "name": "_$s8MyModule0A5ClassCMn",
133+
// CHECK-SPI-NEXT: "access": "private",
134+
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule",
135+
// CHECK-SPI-NEXT: "linkage": "exported"
136+
// CHECK-SPI-NEXT: },
137+
// CHECK-SPI-NEXT: {
138+
// CHECK-SPI-NEXT: "name": "_$s8MyModule0A5ClassCMo",
139+
// CHECK-SPI-NEXT: "access": "private",
140+
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule",
141+
// CHECK-SPI-NEXT: "linkage": "exported"
142+
// CHECK-SPI-NEXT: },
143+
// CHECK-SPI-NEXT: {
144+
// CHECK-SPI-NEXT: "name": "_$s8MyModule0A5ClassCMu",
145+
// CHECK-SPI-NEXT: "access": "private",
146+
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule",
147+
// CHECK-SPI-NEXT: "linkage": "exported"
148+
// CHECK-SPI-NEXT: },
149+
// CHECK-SPI-NEXT: {
150+
// CHECK-SPI-NEXT: "name": "_$s8MyModule0A5ClassCN",
151+
// CHECK-SPI-NEXT: "access": "public",
152+
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule",
153+
// CHECK-SPI-NEXT: "linkage": "exported"
154+
// CHECK-SPI-NEXT: },
155+
// CHECK-SPI-NEXT: {
156+
// CHECK-SPI-NEXT: "name": "_$s8MyModule0A5ClassCfD",
157+
// CHECK-SPI-NEXT: "access": "private",
158+
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule",
159+
// CHECK-SPI-NEXT: "linkage": "exported"
160+
// CHECK-SPI-NEXT: },
161+
// CHECK-SPI-NEXT: {
162+
// CHECK-SPI-NEXT: "name": "_$s8MyModule0A6Class2C9spiMethodyyFTj",
163+
// CHECK-SPI-NEXT: "access": "private",
164+
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule",
165+
// CHECK-SPI-NEXT: "linkage": "exported"
166+
// CHECK-SPI-NEXT: },
167+
// CHECK-SPI-NEXT: {
168+
// CHECK-SPI-NEXT: "name": "_$s8MyModule0A6Class2C9spiMethodyyFTq",
169+
// CHECK-SPI-NEXT: "access": "private",
170+
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule",
171+
// CHECK-SPI-NEXT: "linkage": "exported"
172+
// CHECK-SPI-NEXT: },
173+
// CHECK-SPI-NEXT: {
174+
// CHECK-SPI-NEXT: "name": "_$s8MyModule0A6Class2CACycfC",
175+
// CHECK-SPI-NEXT: "access": "public",
176+
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule",
177+
// CHECK-SPI-NEXT: "linkage": "exported"
178+
// CHECK-SPI-NEXT: },
179+
// CHECK-SPI-NEXT: {
180+
// CHECK-SPI-NEXT: "name": "_$s8MyModule0A6Class2CACycfc",
181+
// CHECK-SPI-NEXT: "access": "public",
182+
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule",
183+
// CHECK-SPI-NEXT: "linkage": "exported"
184+
// CHECK-SPI-NEXT: },
185+
// CHECK-SPI-NEXT: {
186+
// CHECK-SPI-NEXT: "name": "_$s8MyModule0A6Class2CMa",
187+
// CHECK-SPI-NEXT: "access": "public",
188+
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule",
189+
// CHECK-SPI-NEXT: "linkage": "exported"
190+
// CHECK-SPI-NEXT: },
191+
// CHECK-SPI-NEXT: {
192+
// CHECK-SPI-NEXT: "name": "_$s8MyModule0A6Class2CMn",
193+
// CHECK-SPI-NEXT: "access": "public",
194+
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule",
195+
// CHECK-SPI-NEXT: "linkage": "exported"
196+
// CHECK-SPI-NEXT: },
197+
// CHECK-SPI-NEXT: {
198+
// CHECK-SPI-NEXT: "name": "_$s8MyModule0A6Class2CMo",
199+
// CHECK-SPI-NEXT: "access": "public",
200+
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule",
201+
// CHECK-SPI-NEXT: "linkage": "exported"
202+
// CHECK-SPI-NEXT: },
203+
// CHECK-SPI-NEXT: {
204+
// CHECK-SPI-NEXT: "name": "_$s8MyModule0A6Class2CMu",
205+
// CHECK-SPI-NEXT: "access": "public",
206+
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule",
207+
// CHECK-SPI-NEXT: "linkage": "exported"
208+
// CHECK-SPI-NEXT: },
209+
// CHECK-SPI-NEXT: {
210+
// CHECK-SPI-NEXT: "name": "_$s8MyModule0A6Class2CN",
211+
// CHECK-SPI-NEXT: "access": "public",
212+
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule",
213+
// CHECK-SPI-NEXT: "linkage": "exported"
214+
// CHECK-SPI-NEXT: },
215+
// CHECK-SPI-NEXT: {
216+
// CHECK-SPI-NEXT: "name": "_$s8MyModule0A6Class2CfD",
217+
// CHECK-SPI-NEXT: "access": "public",
218+
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule",
219+
// CHECK-SPI-NEXT: "linkage": "exported"
220+
// CHECK-SPI-NEXT: },
221+
// CHECK-SPI-NEXT: {
222+
// CHECK-SPI-NEXT: "name": "_$s8MyModule15newUnprovenFuncyyF",
223+
// CHECK-SPI-NEXT: "access": "private",
224+
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule",
225+
// CHECK-SPI-NEXT: "linkage": "exported"
226+
// CHECK-SPI-NEXT: },
227+
// CHECK-SPI-NEXT: {
228+
// CHECK-SPI-NEXT: "name": "_OBJC_CLASS_$__TtC8MyModule7MyClass",
229+
// CHECK-SPI-NEXT: "access": "private",
230+
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule",
231+
// CHECK-SPI-NEXT: "linkage": "exported"
232+
// CHECK-SPI-NEXT: },
233+
// CHECK-SPI-NEXT: {
234+
// CHECK-SPI-NEXT: "name": "_OBJC_CLASS_$__TtC8MyModule8MyClass2",
235+
// CHECK-SPI-NEXT: "access": "public",
236+
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule",
237+
// CHECK-SPI-NEXT: "linkage": "exported"
238+
// CHECK-SPI-NEXT: },
239+
// CHECK-SPI-NEXT: {
240+
// CHECK-SPI-NEXT: "name": "_OBJC_METACLASS_$__TtC8MyModule7MyClass",
241+
// CHECK-SPI-NEXT: "access": "private",
242+
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule",
243+
// CHECK-SPI-NEXT: "linkage": "exported"
244+
// CHECK-SPI-NEXT: },
245+
// CHECK-SPI-NEXT: {
246+
// CHECK-SPI-NEXT: "name": "_OBJC_METACLASS_$__TtC8MyModule8MyClass2",
247+
// CHECK-SPI-NEXT: "access": "public",
248+
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule",
249+
// CHECK-SPI-NEXT: "linkage": "exported"
250+
// CHECK-SPI-NEXT: },
251+
// CHECK-SPI-NEXT: {
252+
// CHECK-SPI-NEXT: "name": "_main",
253+
// CHECK-SPI-NEXT: "access": "public",
254+
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule",
255+
// CHECK-SPI-NEXT: "linkage": "exported"
256+
// CHECK-SPI-NEXT: }
257+
// CHECK-SPI-NEXT: ],
258+
// CHECK-SPI-NEXT: "interfaces": [
259+
// CHECK-SPI-NEXT: {
260+
// CHECK-SPI-NEXT: "name": "_TtC8MyModule7MyClass",
261+
// CHECK-SPI-NEXT: "access": "private",
262+
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule",
263+
// CHECK-SPI-NEXT: "linkage": "exported",
264+
// CHECK-SPI-NEXT: "super": "NSObject",
265+
// CHECK-SPI-NEXT: "instanceMethods": [
266+
// CHECK-SPI-NEXT: {
267+
// CHECK-SPI-NEXT: "name": "init",
268+
// CHECK-SPI-NEXT: "access": "private",
269+
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule"
270+
// CHECK-SPI-NEXT: },
271+
// CHECK-SPI-NEXT: {
272+
// CHECK-SPI-NEXT: "name": "spiMethod",
273+
// CHECK-SPI-NEXT: "access": "private",
274+
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule"
275+
// CHECK-SPI-NEXT: }
276+
// CHECK-SPI-NEXT: ],
277+
// CHECK-SPI-NEXT: "classMethods": []
278+
// CHECK-SPI-NEXT: },
279+
// CHECK-SPI-NEXT: {
280+
// CHECK-SPI-NEXT: "name": "_TtC8MyModule8MyClass2",
281+
// CHECK-SPI-NEXT: "access": "public",
282+
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule",
283+
// CHECK-SPI-NEXT: "linkage": "exported",
284+
// CHECK-SPI-NEXT: "super": "NSObject",
285+
// CHECK-SPI-NEXT: "instanceMethods": [
286+
// CHECK-SPI-NEXT: {
287+
// CHECK-SPI-NEXT: "name": "init",
288+
// CHECK-SPI-NEXT: "access": "public",
289+
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule"
290+
// CHECK-SPI-NEXT: },
291+
// CHECK-SPI-NEXT: {
292+
// CHECK-SPI-NEXT: "name": "spiMethod",
293+
// CHECK-SPI-NEXT: "access": "private",
294+
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule"
295+
// CHECK-SPI-NEXT: }
296+
// CHECK-SPI-NEXT: ],
297+
// CHECK-SPI-NEXT: "classMethods": []
298+
// CHECK-SPI-NEXT: }
299+
// CHECK-SPI-NEXT: ],
300+
// CHECK-SPI-NEXT: "version": "1.0"
301+
// CHECK-SPI-NEXT: }

0 commit comments

Comments
 (0)