Skip to content

Commit 0b07c34

Browse files
authored
Merge pull request #68978 from tshortli/improve-api-extract-accuracy
TBDGen: Improve the accuracy of swift-api-extract output
2 parents eccf94d + 80b1f4c commit 0b07c34

File tree

10 files changed

+166
-70
lines changed

10 files changed

+166
-70
lines changed

lib/IRGen/TBDGen.cpp

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ void TBDGenVisitor::addSymbolInternal(StringRef name, SymbolKind kind,
8181
}
8282
}
8383
#endif
84-
recorder.addSymbol(name, kind, source);
84+
recorder.addSymbol(name, kind, source,
85+
DeclStack.empty() ? nullptr : DeclStack.back());
8586
}
8687

8788
static std::vector<OriginallyDefinedInAttr::ActiveVersion>
@@ -613,9 +614,8 @@ TBDFile GenerateTBDRequest::evaluate(Evaluator &evaluator,
613614
targets.push_back(targetVar);
614615
}
615616

616-
auto addSymbol = [&](StringRef symbol, SymbolKind kind, SymbolSource source) {
617-
file.addSymbol(kind, symbol, targets);
618-
};
617+
auto addSymbol = [&](StringRef symbol, SymbolKind kind, SymbolSource source,
618+
Decl *decl) { file.addSymbol(kind, symbol, targets); };
619619
SimpleAPIRecorder recorder(addSymbol);
620620
TBDGenVisitor visitor(desc, recorder);
621621
visitor.visit(desc);
@@ -626,7 +626,8 @@ std::vector<std::string>
626626
PublicSymbolsRequest::evaluate(Evaluator &evaluator,
627627
TBDGenDescriptor desc) const {
628628
std::vector<std::string> symbols;
629-
auto addSymbol = [&](StringRef symbol, SymbolKind kind, SymbolSource source) {
629+
auto addSymbol = [&](StringRef symbol, SymbolKind kind, SymbolSource source,
630+
Decl *decl) {
630631
if (kind == SymbolKind::GlobalSymbol)
631632
symbols.push_back(symbol.str());
632633
// TextAPI ObjC Class Kinds represents two symbols.
@@ -655,10 +656,11 @@ void swift::writeTBDFile(ModuleDecl *M, llvm::raw_ostream &os,
655656
}
656657

657658
class APIGenRecorder final : public APIRecorder {
658-
bool isSPI(const ValueDecl* VD) {
659-
assert(VD);
660-
return VD->isSPI() || VD->isAvailableAsSPI();
659+
static bool isSPI(const Decl *decl) {
660+
assert(decl);
661+
return decl->isSPI() || decl->isAvailableAsSPI();
661662
}
663+
662664
public:
663665
APIGenRecorder(apigen::API &api, ModuleDecl *module)
664666
: api(api), module(module) {
@@ -667,26 +669,17 @@ class APIGenRecorder final : public APIRecorder {
667669
}
668670
~APIGenRecorder() {}
669671

670-
void addSymbol(StringRef symbol, SymbolKind kind,
671-
SymbolSource source) override {
672+
void addSymbol(StringRef symbol, SymbolKind kind, SymbolSource source,
673+
Decl *decl) override {
672674
if (kind != SymbolKind::GlobalSymbol)
673675
return;
674676

675677
apigen::APIAvailability availability;
676678
auto access = apigen::APIAccess::Public;
677-
if (source.kind == SymbolSource::Kind::SIL) {
678-
auto ref = source.getSILDeclRef();
679-
if (ref.hasDecl()) {
680-
availability = getAvailability(ref.getDecl());
681-
if (isSPI(ref.getDecl()))
682-
access = apigen::APIAccess::Private;
683-
}
684-
} else if (source.kind == SymbolSource::Kind::IR) {
685-
auto ref = source.getIRLinkEntity();
686-
if (ref.hasDecl()) {
687-
if (isSPI(ref.getDecl()))
688-
access = apigen::APIAccess::Private;
689-
}
679+
if (decl) {
680+
availability = getAvailability(decl);
681+
if (isSPI(decl))
682+
access = apigen::APIAccess::Private;
690683
}
691684

692685
api.addSymbol(symbol, moduleLoc, apigen::APILinkage::Exported,
@@ -712,7 +705,7 @@ class APIGenRecorder final : public APIRecorder {
712705
if (method.getDecl()->getDescriptiveKind() ==
713706
DescriptiveDeclKind::ClassMethod)
714707
isInstanceMethod = false;
715-
if (method.getDecl()->isSPI())
708+
if (isSPI(method.getDecl()))
716709
access = apigen::APIAccess::Private;
717710
}
718711

@@ -778,7 +771,7 @@ class APIGenRecorder final : public APIRecorder {
778771
superCls = super->getObjCRuntimeName(buffer);
779772
apigen::APIAvailability availability = getAvailability(decl);
780773
apigen::APIAccess access =
781-
decl->isSPI() ? apigen::APIAccess::Private : apigen::APIAccess::Public;
774+
isSPI(decl) ? apigen::APIAccess::Private : apigen::APIAccess::Public;
782775
apigen::APILinkage linkage =
783776
decl->getFormalAccess() == AccessLevel::Public && decl->isObjC()
784777
? apigen::APILinkage::Exported
@@ -811,7 +804,7 @@ class APIGenRecorder final : public APIRecorder {
811804
buildCategoryName(decl, cls, nameBuffer);
812805
apigen::APIAvailability availability = getAvailability(decl);
813806
apigen::APIAccess access =
814-
decl->isSPI() ? apigen::APIAccess::Private : apigen::APIAccess::Public;
807+
isSPI(decl) ? apigen::APIAccess::Private : apigen::APIAccess::Public;
815808
apigen::APILinkage linkage =
816809
decl->getMaxAccessLevel() == AccessLevel::Public
817810
? apigen::APILinkage::Exported
@@ -863,7 +856,8 @@ SymbolSourceMapRequest::evaluate(Evaluator &evaluator,
863856
auto &Ctx = desc.getParentModule()->getASTContext();
864857
auto *SymbolSources = Ctx.Allocate<SymbolSourceMap>();
865858

866-
auto addSymbol = [=](StringRef symbol, SymbolKind kind, SymbolSource source) {
859+
auto addSymbol = [=](StringRef symbol, SymbolKind kind, SymbolSource source,
860+
Decl *decl) {
867861
SymbolSources->insert({symbol, source});
868862
};
869863

lib/IRGen/TBDGenVisitor.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ class APIRecorder {
6262
virtual ~APIRecorder() {}
6363

6464
virtual void addSymbol(StringRef name, llvm::MachO::SymbolKind kind,
65-
SymbolSource source) {}
65+
SymbolSource source, Decl *decl) {}
6666
virtual void addObjCInterface(const ClassDecl *decl) {}
6767
virtual void addObjCCategory(const ExtensionDecl *decl) {}
6868
virtual void addObjCMethod(const GenericContext *ctx, SILDeclRef method) {}
@@ -71,14 +71,15 @@ class APIRecorder {
7171
class SimpleAPIRecorder final : public APIRecorder {
7272
public:
7373
using SymbolCallbackFn = llvm::function_ref<void(
74-
StringRef, llvm::MachO::SymbolKind, SymbolSource)>;
74+
StringRef, llvm::MachO::SymbolKind, SymbolSource, Decl *)>;
7575

7676
SimpleAPIRecorder(SymbolCallbackFn func) : func(func) {}
7777

7878
void addSymbol(StringRef symbol, llvm::MachO::SymbolKind kind,
79-
SymbolSource source) override {
80-
func(symbol, kind, source);
79+
SymbolSource source, Decl *decl) override {
80+
func(symbol, kind, source, decl);
8181
}
82+
8283
private:
8384
SymbolCallbackFn func;
8485
};

lib/SIL/IR/SILSymbolVisitor.cpp

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -646,19 +646,24 @@ class SILSymbolVisitorImpl : public ASTVisitor<SILSymbolVisitorImpl> {
646646
void addMethod(SILDeclRef method) {
647647
assert(method.getDecl()->getDeclContext() == CD);
648648

649-
if (VirtualFunctionElimination || CD->hasResilientMetadata()) {
650-
if (FirstTime) {
651-
FirstTime = false;
652-
653-
// If the class is itself resilient and has at least one vtable
654-
// entry, it has a method lookup function.
649+
// If the class is itself resilient and has at least one vtable
650+
// entry, it has a method lookup function.
651+
bool hasLookupFunc =
652+
VirtualFunctionElimination || CD->hasResilientMetadata();
653+
if (FirstTime) {
654+
FirstTime = false;
655+
656+
if (hasLookupFunc)
655657
Visitor.addMethodLookupFunction(CD);
656-
}
658+
}
657659

660+
if (!Visitor.willVisitDecl(method.getDecl()))
661+
return;
662+
if (hasLookupFunc)
658663
Visitor.addDispatchThunk(method);
659-
}
660664

661665
Visitor.addMethodDescriptor(method);
666+
Visitor.didVisitDecl(method.getDecl());
662667
}
663668

664669
void addMethodOverride(SILDeclRef baseRef, SILDeclRef derivedRef) {}

test/APIJSON/access.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44

55
// REQUIRES: objc_interop, OS=macosx
66
// RUN: %empty-directory(%t)
7+
// RUN: %empty-directory(%t/ModuleCache)
78
// RUN: cp %s %t/MyModule.swiftinterface
8-
// RUN: %target-swift-api-extract -target x86_64-apple-macos11.0 -o - -pretty-print %t/MyModule.swiftinterface -module-name MyModule -module-cache-path %t | %FileCheck %s
9+
// RUN: %target-swift-api-extract -target x86_64-apple-macos11.0 -o - -pretty-print %t/MyModule.swiftinterface -module-name MyModule -module-cache-path %t/ModuleCache | %FileCheck %s
910

1011
public func publicFunction()
1112
internal func internalFunction()

test/APIJSON/apigen.swift

Lines changed: 52 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
// REQUIRES: objc_interop, OS=macosx
22
// RUN: %empty-directory(%t)
3-
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) %s -typecheck -emit-module-interface-path %t/MyModule.swiftinterface -enable-library-evolution -module-name MyModule -swift-version 5
4-
// RUN: %target-swift-api-extract -o - -pretty-print %t/MyModule.swiftinterface -module-name MyModule -module-cache-path %t | %FileCheck %s
3+
// 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-api-extract -o - -pretty-print %t/MyModule.swiftinterface -module-name MyModule -module-cache-path %t/ModuleCache | %FileCheck %s
56

67
import Foundation
78

89
@available(macOS 10.13, *)
910
public class Test : NSObject {
1011
@objc public func method1() {}
12+
@available(macOS 10.14, *)
1113
@objc public class func method2() {}
1214
public func nonObjc() {}
1315
}
@@ -42,6 +44,9 @@ public func myFunction1() {}
4244
@available(*, unavailable)
4345
public func myFunction2() {}
4446

47+
@available(macOS 10.13, *)
48+
public var myGlobalVar: Int = 42
49+
4550
// CHECK: "target"
4651
// CHECK-NEXT: "globals": [
4752
// CHECK-NEXT: {
@@ -66,6 +71,27 @@ public func myFunction2() {}
6671
// CHECK-NEXT: "unavailable": true
6772
// CHECK-NEXT: },
6873
// CHECK-NEXT: {
74+
// CHECK-NEXT: "name": "_$s8MyModule11myGlobalVarSivM",
75+
// CHECK-NEXT: "access": "public",
76+
// CHECK-NEXT: "file": "/@input/MyModule.swiftinterface",
77+
// CHECK-NEXT: "linkage": "exported",
78+
// CHECK-NEXT: "introduced": "10.13"
79+
// CHECK-NEXT: },
80+
// CHECK-NEXT: {
81+
// CHECK-NEXT: "name": "_$s8MyModule11myGlobalVarSivg",
82+
// CHECK-NEXT: "access": "public",
83+
// CHECK-NEXT: "file": "/@input/MyModule.swiftinterface",
84+
// CHECK-NEXT: "linkage": "exported",
85+
// CHECK-NEXT: "introduced": "10.13"
86+
// CHECK-NEXT: },
87+
// CHECK-NEXT: {
88+
// CHECK-NEXT: "name": "_$s8MyModule11myGlobalVarSivs",
89+
// CHECK-NEXT: "access": "public",
90+
// CHECK-NEXT: "file": "/@input/MyModule.swiftinterface",
91+
// CHECK-NEXT: "linkage": "exported",
92+
// CHECK-NEXT: "introduced": "10.13"
93+
// CHECK-NEXT: },
94+
// CHECK-NEXT: {
6995
// CHECK-NEXT: "name": "_$s8MyModule4TestC7method1yyFTj",
7096
// CHECK-NEXT: "access": "public",
7197
// CHECK-NEXT: "file": "/@input/MyModule.swiftinterface",
@@ -81,13 +107,15 @@ public func myFunction2() {}
81107
// CHECK-NEXT: "name": "_$s8MyModule4TestC7method2yyFZTj",
82108
// CHECK-NEXT: "access": "public",
83109
// CHECK-NEXT: "file": "/@input/MyModule.swiftinterface",
84-
// CHECK-NEXT: "linkage": "exported"
110+
// CHECK-NEXT: "linkage": "exported",
111+
// CHECK-NEXT: "introduced": "10.14"
85112
// CHECK-NEXT: },
86113
// CHECK-NEXT: {
87114
// CHECK-NEXT: "name": "_$s8MyModule4TestC7method2yyFZTq",
88115
// CHECK-NEXT: "access": "public",
89116
// CHECK-NEXT: "file": "/@input/MyModule.swiftinterface",
90-
// CHECK-NEXT: "linkage": "exported"
117+
// CHECK-NEXT: "linkage": "exported",
118+
// CHECK-NEXT: "introduced": "10.14"
91119
// CHECK-NEXT: },
92120
// CHECK-NEXT: {
93121
// CHECK-NEXT: "name": "_$s8MyModule4TestC7nonObjcyyFTj",
@@ -117,31 +145,36 @@ public func myFunction2() {}
117145
// CHECK-NEXT: "name": "_$s8MyModule4TestCMa",
118146
// CHECK-NEXT: "access": "public",
119147
// CHECK-NEXT: "file": "/@input/MyModule.swiftinterface",
120-
// CHECK-NEXT: "linkage": "exported"
148+
// CHECK-NEXT: "linkage": "exported",
149+
// CHECK-NEXT: "introduced": "10.13"
121150
// CHECK-NEXT: },
122151
// CHECK-NEXT: {
123152
// CHECK-NEXT: "name": "_$s8MyModule4TestCMn",
124153
// CHECK-NEXT: "access": "public",
125154
// CHECK-NEXT: "file": "/@input/MyModule.swiftinterface",
126-
// CHECK-NEXT: "linkage": "exported"
155+
// CHECK-NEXT: "linkage": "exported",
156+
// CHECK-NEXT: "introduced": "10.13"
127157
// CHECK-NEXT: },
128158
// CHECK-NEXT: {
129159
// CHECK-NEXT: "name": "_$s8MyModule4TestCMo",
130160
// CHECK-NEXT: "access": "public",
131161
// CHECK-NEXT: "file": "/@input/MyModule.swiftinterface",
132-
// CHECK-NEXT: "linkage": "exported"
162+
// CHECK-NEXT: "linkage": "exported",
163+
// CHECK-NEXT: "introduced": "10.13"
133164
// CHECK-NEXT: },
134165
// CHECK-NEXT: {
135166
// CHECK-NEXT: "name": "_$s8MyModule4TestCMu",
136167
// CHECK-NEXT: "access": "public",
137168
// CHECK-NEXT: "file": "/@input/MyModule.swiftinterface",
138-
// CHECK-NEXT: "linkage": "exported"
169+
// CHECK-NEXT: "linkage": "exported",
170+
// CHECK-NEXT: "introduced": "10.13"
139171
// CHECK-NEXT: },
140172
// CHECK-NEXT: {
141173
// CHECK-NEXT: "name": "_$s8MyModule4TestCN",
142174
// CHECK-NEXT: "access": "public",
143175
// CHECK-NEXT: "file": "/@input/MyModule.swiftinterface",
144-
// CHECK-NEXT: "linkage": "exported"
176+
// CHECK-NEXT: "linkage": "exported",
177+
// CHECK-NEXT: "introduced": "10.13"
145178
// CHECK-NEXT: },
146179
// CHECK-NEXT: {
147180
// CHECK-NEXT: "name": "_$s8MyModule4TestCfD",
@@ -291,25 +324,29 @@ public func myFunction2() {}
291324
// CHECK-NEXT: "name": "_$s8MyModule7DerivedCMa",
292325
// CHECK-NEXT: "access": "public",
293326
// CHECK-NEXT: "file": "/@input/MyModule.swiftinterface",
294-
// CHECK-NEXT: "linkage": "exported"
327+
// CHECK-NEXT: "linkage": "exported",
328+
// CHECK-NEXT: "introduced": "10.13"
295329
// CHECK-NEXT: },
296330
// CHECK-NEXT: {
297331
// CHECK-NEXT: "name": "_$s8MyModule7DerivedCMn",
298332
// CHECK-NEXT: "access": "public",
299333
// CHECK-NEXT: "file": "/@input/MyModule.swiftinterface",
300-
// CHECK-NEXT: "linkage": "exported"
334+
// CHECK-NEXT: "linkage": "exported",
335+
// CHECK-NEXT: "introduced": "10.13"
301336
// CHECK-NEXT: },
302337
// CHECK-NEXT: {
303338
// CHECK-NEXT: "name": "_$s8MyModule7DerivedCMo",
304339
// CHECK-NEXT: "access": "public",
305340
// CHECK-NEXT: "file": "/@input/MyModule.swiftinterface",
306-
// CHECK-NEXT: "linkage": "exported"
341+
// CHECK-NEXT: "linkage": "exported",
342+
// CHECK-NEXT: "introduced": "10.13"
307343
// CHECK-NEXT: },
308344
// CHECK-NEXT: {
309345
// CHECK-NEXT: "name": "_$s8MyModule7DerivedCN",
310346
// CHECK-NEXT: "access": "public",
311347
// CHECK-NEXT: "file": "/@input/MyModule.swiftinterface",
312-
// CHECK-NEXT: "linkage": "exported"
348+
// CHECK-NEXT: "linkage": "exported",
349+
// CHECK-NEXT: "introduced": "10.13"
313350
// CHECK-NEXT: },
314351
// CHECK-NEXT: {
315352
// CHECK-NEXT: "name": "_$s8MyModule7DerivedCfD",
@@ -342,7 +379,8 @@ public func myFunction2() {}
342379
// CHECK-NEXT: {
343380
// CHECK-NEXT: "name": "method2",
344381
// CHECK-NEXT: "access": "public",
345-
// CHECK-NEXT: "file": "/@input/MyModule.swiftinterface"
382+
// CHECK-NEXT: "file": "/@input/MyModule.swiftinterface",
383+
// CHECK-NEXT: "introduced": "10.14"
346384
// CHECK-NEXT: }
347385
// CHECK-NEXT: ]
348386
// CHECK-NEXT: },

test/APIJSON/extension.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
// REQUIRES: objc_interop, OS=macosx
22
// RUN: %empty-directory(%t)
3-
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) %s -typecheck -emit-module-interface-path %t/MyModule.swiftinterface -enable-library-evolution -module-name MyModule -swift-version 5
4-
// RUN: %target-swift-api-extract -o - -pretty-print %t/MyModule.swiftinterface -module-name MyModule -module-cache-path %t | %FileCheck %s
3+
// 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-api-extract -o - -pretty-print %t/MyModule.swiftinterface -module-name MyModule -module-cache-path %t/ModuleCache | %FileCheck %s
56

67
import Foundation
78

@@ -105,4 +106,4 @@ extension B {
105106
// CHECK-NEXT: ],
106107
// CHECK-NEXT: "classMethods": []
107108
// CHECK-NEXT: }
108-
// CHECK-NEXT: ],
109+
// CHECK-NEXT: ],

test/APIJSON/non-objc-class.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
// REQUIRES: objc_interop, OS=macosx
22
// RUN: %empty-directory(%t)
3-
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) %s -typecheck -emit-module-interface-path %t/MyModule.swiftinterface -enable-library-evolution -module-name MyModule -swift-version 5
4-
// RUN: %target-swift-api-extract -o - -pretty-print %t/MyModule.swiftinterface -module-name MyModule -module-cache-path %t | %FileCheck %s
3+
// 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-api-extract -o - -pretty-print %t/MyModule.swiftinterface -module-name MyModule -module-cache-path %t/ModuleCache | %FileCheck %s
56

67
import Foundation
78

test/APIJSON/non-swift-api.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// RUN: cp %S/Inputs/module.modulemap %t/NativeDep.framework/Modules
55
// RUN: cp %S/Inputs/NativeDep.h %t/NativeDep.framework/Headers
66

7-
// RUN: %target-swift-frontend %s -emit-module -emit-module-interface-path %t/MyModule.swiftinterface -emit-module-path %t/MyModule.swiftmodule -F %t -enable-library-evolution -module-cache-path %t/cache -module-name MyModule -swift-version 5
7+
// RUN: %target-swift-frontend %s -parse-as-library -emit-module -emit-module-interface-path %t/MyModule.swiftinterface -emit-module-path %t/MyModule.swiftmodule -F %t -enable-library-evolution -module-cache-path %t/cache -module-name MyModule -swift-version 5
88

99
/// Check that both swiftmodule and swiftinterface can be used as input.
1010
// RUN: %target-swift-api-extract -o - -pretty-print %t/MyModule.swiftmodule -module-name MyModule -module-cache-path %t/cache -F %t | %FileCheck %s

0 commit comments

Comments
 (0)