Skip to content

Commit 4ec3e52

Browse files
add new flag to skip "protocol implementation" symbols
rdar://59899968
1 parent 3b4d03c commit 4ec3e52

File tree

9 files changed

+112
-44
lines changed

9 files changed

+112
-44
lines changed

include/swift/Option/Options.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1444,6 +1444,11 @@ def include_spi_symbols : Flag<["-"], "include-spi-symbols">,
14441444
NoInteractiveOption, SupplementaryOutput, HelpHidden]>,
14451445
HelpText<"Add symbols with SPI information to the symbol graph">;
14461446

1447+
def skip_protocol_implementations : Flag<["-"], "skip-protocol-implementations">,
1448+
Flags<[SwiftSymbolGraphExtractOption, FrontendOption,
1449+
NoInteractiveOption, SupplementaryOutput, HelpHidden]>,
1450+
HelpText<"Skip emitting symbols that are implementations of protocol requirements or inherited from protocl extensions">;
1451+
14471452
// swift-api-digester-only options
14481453
def dump_sdk: Flag<["-", "--"], "dump-sdk">,
14491454
Flags<[NoDriverOption, SwiftAPIDigesterOption]>,

include/swift/SymbolGraphGen/SymbolGraphOptions.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ struct SymbolGraphOptions {
4343
/// Whether to skip docs for symbols with compound, "SYNTHESIZED" USRs.
4444
bool SkipInheritedDocs = false;
4545

46+
/// Whether to skip emitting symbols that are implementations of protocol requirements or
47+
/// inherited from protocol extensions.
48+
bool SkipProtocolImplementations = false;
49+
4650
/// Whether to emit symbols with SPI information.
4751
bool IncludeSPISymbols = false;
4852

lib/DriverTool/swift_symbolgraph_extract_main.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ int swift_symbolgraph_extract_main(ArrayRef<const char *> Args,
170170
!ParsedArgs.hasArg(OPT_skip_synthesized_members),
171171
ParsedArgs.hasArg(OPT_v),
172172
ParsedArgs.hasArg(OPT_skip_inherited_docs),
173+
ParsedArgs.hasArg(OPT_skip_protocol_implementations),
173174
ParsedArgs.hasArg(OPT_include_spi_symbols),
174175
/*IncludeClangDocs=*/false,
175176
ParsedArgs.hasFlag(OPT_emit_extension_block_symbols,

lib/Frontend/CompilerInvocation.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1337,6 +1337,7 @@ static void ParseSymbolGraphArgs(symbolgraphgen::SymbolGraphOptions &Opts,
13371337
Opts.Target = LangOpts.Target;
13381338

13391339
Opts.SkipInheritedDocs = Args.hasArg(OPT_skip_inherited_docs);
1340+
Opts.SkipProtocolImplementations = Args.hasArg(OPT_skip_protocol_implementations);
13401341
Opts.IncludeSPISymbols = Args.hasArg(OPT_include_spi_symbols);
13411342
Opts.EmitExtensionBlockSymbols =
13421343
Args.hasFlag(OPT_emit_extension_block_symbols,

lib/SymbolGraphGen/Edge.cpp

Lines changed: 1 addition & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -20,33 +20,6 @@
2020
using namespace swift;
2121
using namespace symbolgraphgen;
2222

23-
namespace {
24-
const ValueDecl *getForeignProtocolRequirement(const ValueDecl *VD, const ModuleDecl *M) {
25-
std::queue<const ValueDecl *> requirements;
26-
while (true) {
27-
for (auto *req : VD->getSatisfiedProtocolRequirements()) {
28-
if (req->getModuleContext()->getNameStr() != M->getNameStr())
29-
return req;
30-
else
31-
requirements.push(req);
32-
}
33-
if (requirements.empty())
34-
return nullptr;
35-
VD = requirements.front();
36-
requirements.pop();
37-
}
38-
}
39-
40-
const ValueDecl *getProtocolRequirement(const ValueDecl *VD) {
41-
auto reqs = VD->getSatisfiedProtocolRequirements();
42-
43-
if (!reqs.empty())
44-
return reqs.front();
45-
else
46-
return nullptr;
47-
}
48-
} // end anonymous namespace
49-
5023
void Edge::serialize(llvm::json::OStream &OS) const {
5124
OS.object([&](){
5225
OS.attribute("kind", Kind.Name);
@@ -87,22 +60,7 @@ void Edge::serialize(llvm::json::OStream &OS) const {
8760
}
8861
}
8962

90-
const ValueDecl *InheritingDecl = nullptr;
91-
if (const auto *ID = Source.getDeclInheritingDocs())
92-
InheritingDecl = ID;
93-
94-
if (!InheritingDecl && Source.getSynthesizedBaseTypeDecl())
95-
InheritingDecl = Source.getSymbolDecl();
96-
97-
if (!InheritingDecl) {
98-
if (const auto *ID = getForeignProtocolRequirement(Source.getSymbolDecl(), &Graph->M))
99-
InheritingDecl = ID;
100-
}
101-
102-
if (!InheritingDecl) {
103-
if (const auto *ID = getProtocolRequirement(Source.getSymbolDecl()))
104-
InheritingDecl = ID;
105-
}
63+
const ValueDecl *InheritingDecl = Source.getInheritedDecl();
10664

10765
// If our source symbol is a inheriting decl, write in information about
10866
// where it's inheriting docs from.

lib/SymbolGraphGen/Symbol.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
#include "SymbolGraphASTWalker.h"
3131
#include "DeclarationFragmentPrinter.h"
3232

33+
#include <queue>
34+
3335
using namespace swift;
3436
using namespace symbolgraphgen;
3537

@@ -223,6 +225,60 @@ const ValueDecl *Symbol::getDeclInheritingDocs() const {
223225
}
224226
}
225227

228+
const ValueDecl *Symbol::getForeignProtocolRequirement() const {
229+
if (const auto *VD = dyn_cast_or_null<ValueDecl>(D)) {
230+
std::queue<const ValueDecl *> requirements;
231+
while (true) {
232+
for (auto *req : VD->getSatisfiedProtocolRequirements()) {
233+
if (req->getModuleContext()->getNameStr() != Graph->M.getNameStr())
234+
return req;
235+
else
236+
requirements.push(req);
237+
}
238+
if (requirements.empty())
239+
return nullptr;
240+
VD = requirements.front();
241+
requirements.pop();
242+
}
243+
}
244+
245+
return nullptr;
246+
}
247+
248+
const ValueDecl *Symbol::getProtocolRequirement() const {
249+
if (const auto *VD = dyn_cast_or_null<ValueDecl>(D)) {
250+
auto reqs = VD->getSatisfiedProtocolRequirements();
251+
252+
if (!reqs.empty())
253+
return reqs.front();
254+
else
255+
return nullptr;
256+
}
257+
258+
return nullptr;
259+
}
260+
261+
const ValueDecl *Symbol::getInheritedDecl() const {
262+
const ValueDecl *InheritingDecl = nullptr;
263+
if (const auto *ID = getDeclInheritingDocs())
264+
InheritingDecl = ID;
265+
266+
if (!InheritingDecl && getSynthesizedBaseTypeDecl())
267+
InheritingDecl = getSymbolDecl();
268+
269+
if (!InheritingDecl) {
270+
if (const auto *ID = getForeignProtocolRequirement())
271+
InheritingDecl = ID;
272+
}
273+
274+
if (!InheritingDecl) {
275+
if (const auto *ID = getProtocolRequirement())
276+
InheritingDecl = ID;
277+
}
278+
279+
return InheritingDecl;
280+
}
281+
226282
namespace {
227283

228284
StringRef getFileNameForDecl(const Decl *D) {

lib/SymbolGraphGen/Symbol.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,19 @@ class Symbol {
130130
/// the symbol has its own doc comments to render.
131131
const ValueDecl *getDeclInheritingDocs() const;
132132

133+
/// If this symbol is an implementation of a protocol requirement for a
134+
/// protocol declared outside its module, returns the upstream decl for that
135+
/// requirement.
136+
const ValueDecl *getForeignProtocolRequirement() const;
137+
138+
/// If this symbol is an implementation of a protocol requirement, returns the
139+
/// upstream decl for that requirement.
140+
const ValueDecl *getProtocolRequirement() const;
141+
142+
/// If this symbol is a synthesized symbol or an implementation of a protocol
143+
/// requirement, returns the upstream decl.
144+
const ValueDecl *getInheritedDecl() const;
145+
133146
static bool supportsKind(DeclKind Kind);
134147

135148
/// Determines the effective access level of the given extension.

lib/SymbolGraphGen/SymbolGraph.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,10 @@ SymbolGraph::isRequirementOrDefaultImplementation(const ValueDecl *VD) const {
189189
// MARK: - Symbols (Nodes)
190190

191191
void SymbolGraph::recordNode(Symbol S) {
192+
if (Walker.Options.SkipProtocolImplementations && S.getInheritedDecl()) {
193+
return;
194+
}
195+
192196
Nodes.insert(S);
193197

194198
// Record all of the possible relationships (edges) originating
@@ -294,7 +298,7 @@ bool SymbolGraph::synthesizedMemberIsBestCandidate(const ValueDecl *VD,
294298
}
295299

296300
void SymbolGraph::recordConformanceSynthesizedMemberRelationships(Symbol S) {
297-
if (!Walker.Options.EmitSynthesizedMembers) {
301+
if (!Walker.Options.EmitSynthesizedMembers || Walker.Options.SkipProtocolImplementations) {
298302
return;
299303
}
300304
const auto D = S.getLocalSymbolDecl();
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift %s -module-name SkipProtocolImplementations -emit-module -emit-module-path %t/
3+
// RUN: %target-swift-symbolgraph-extract -module-name SkipProtocolImplementations -I %t -skip-protocol-implementations -pretty-print -output-dir %t
4+
// RUN: %FileCheck %s --input-file %t/SkipProtocolImplementations.symbols.json
5+
6+
// make sure that using `-skip-protocol-implementations` removes the functions from `SomeProtocol` on `SomeStruct`
7+
// CHECK-NOT: s:27SkipProtocolImplementations04SomeB0PAAE9bonusFuncyyF::SYNTHESIZED::s:27SkipProtocolImplementations10SomeStructV
8+
// CHECK-NOT: s:27SkipProtocolImplementations10SomeStructV8someFuncyyF
9+
10+
// the `-skip-protocol-implementations` code should drop any symbol that would get source-origin information
11+
// CHECK-NOT: sourceOrigin
12+
13+
// however, we want to make sure that the conformance relationship itself stays
14+
// CHECK: conformsTo
15+
16+
public protocol SomeProtocol {
17+
func someFunc()
18+
}
19+
20+
public extension SomeProtocol {
21+
func bonusFunc() {}
22+
}
23+
24+
public struct SomeStruct: SomeProtocol {
25+
public func someFunc() {}
26+
}

0 commit comments

Comments
 (0)