Skip to content

Commit 164e93e

Browse files
Merge pull request #63726 from apple/QuietMisdreavus/skip-proto-impls
[SymbolGraphGen] add new flag to skip "protocol implementation" symbols rdar://59899968
2 parents 2562afa + 9cca3c1 commit 164e93e

File tree

10 files changed

+153
-68
lines changed

10 files changed

+153
-68
lines changed

Diff for: include/swift/Option/Options.td

+5
Original file line numberDiff line numberDiff line change
@@ -1455,6 +1455,11 @@ def include_spi_symbols : Flag<["-"], "include-spi-symbols">,
14551455
NoInteractiveOption, SupplementaryOutput, HelpHidden]>,
14561456
HelpText<"Add symbols with SPI information to the symbol graph">;
14571457

1458+
def skip_protocol_implementations : Flag<["-"], "skip-protocol-implementations">,
1459+
Flags<[SwiftSymbolGraphExtractOption, FrontendOption,
1460+
NoInteractiveOption, SupplementaryOutput, HelpHidden]>,
1461+
HelpText<"Skip emitting symbols that are implementations of protocol requirements or inherited from protocl extensions">;
1462+
14581463
// swift-api-digester-only options
14591464
def dump_sdk: Flag<["-", "--"], "dump-sdk">,
14601465
Flags<[NoDriverOption, SwiftAPIDigesterOption]>,

Diff for: include/swift/SymbolGraphGen/SymbolGraphOptions.h

+4
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

Diff for: lib/DriverTool/swift_symbolgraph_extract_main.cpp

+11-12
Original file line numberDiff line numberDiff line change
@@ -162,19 +162,18 @@ int swift_symbolgraph_extract_main(ArrayRef<const char *> Args,
162162
}
163163
}
164164

165-
symbolgraphgen::SymbolGraphOptions Options{
166-
OutputDir,
167-
Target,
168-
ParsedArgs.hasArg(OPT_pretty_print),
169-
AccessLevel::Public,
170-
!ParsedArgs.hasArg(OPT_skip_synthesized_members),
171-
ParsedArgs.hasArg(OPT_v),
172-
ParsedArgs.hasArg(OPT_skip_inherited_docs),
173-
ParsedArgs.hasArg(OPT_include_spi_symbols),
174-
/*IncludeClangDocs=*/false,
165+
symbolgraphgen::SymbolGraphOptions Options;
166+
Options.OutputDir = OutputDir;
167+
Options.Target = Target;
168+
Options.PrettyPrint = ParsedArgs.hasArg(OPT_pretty_print);
169+
Options.EmitSynthesizedMembers = !ParsedArgs.hasArg(OPT_skip_synthesized_members);
170+
Options.PrintMessages = ParsedArgs.hasArg(OPT_v);
171+
Options.SkipInheritedDocs = ParsedArgs.hasArg(OPT_skip_inherited_docs);
172+
Options.SkipProtocolImplementations = ParsedArgs.hasArg(OPT_skip_protocol_implementations);
173+
Options.IncludeSPISymbols = ParsedArgs.hasArg(OPT_include_spi_symbols);
174+
Options.EmitExtensionBlockSymbols =
175175
ParsedArgs.hasFlag(OPT_emit_extension_block_symbols,
176-
OPT_omit_extension_block_symbols, /*default=*/false),
177-
};
176+
OPT_omit_extension_block_symbols, /*default=*/false);
178177

179178
if (auto *A = ParsedArgs.getLastArg(OPT_minimum_access_level)) {
180179
Options.MinimumAccessLevel =

Diff for: lib/Frontend/CompilerInvocation.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -1339,6 +1339,7 @@ static void ParseSymbolGraphArgs(symbolgraphgen::SymbolGraphOptions &Opts,
13391339
Opts.Target = LangOpts.Target;
13401340

13411341
Opts.SkipInheritedDocs = Args.hasArg(OPT_skip_inherited_docs);
1342+
Opts.SkipProtocolImplementations = Args.hasArg(OPT_skip_protocol_implementations);
13421343
Opts.IncludeSPISymbols = Args.hasArg(OPT_include_spi_symbols);
13431344
Opts.EmitExtensionBlockSymbols =
13441345
Args.hasFlag(OPT_emit_extension_block_symbols,

Diff for: lib/SymbolGraphGen/Edge.cpp

+1-43
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.

Diff for: lib/SymbolGraphGen/Symbol.cpp

+56
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

@@ -225,6 +227,60 @@ const ValueDecl *Symbol::getDeclInheritingDocs() const {
225227
}
226228
}
227229

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

230286
StringRef getFileNameForDecl(const Decl *D) {

Diff for: lib/SymbolGraphGen/Symbol.h

+13
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.

Diff for: lib/SymbolGraphGen/SymbolGraph.cpp

+11-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include "clang/AST/DeclObjC.h"
1414
#include "swift/AST/ASTContext.h"
15+
#include "swift/AST/Comment.h"
1516
#include "swift/AST/Decl.h"
1617
#include "swift/AST/Module.h"
1718
#include "swift/AST/ProtocolConformance.h"
@@ -189,6 +190,15 @@ SymbolGraph::isRequirementOrDefaultImplementation(const ValueDecl *VD) const {
189190
// MARK: - Symbols (Nodes)
190191

191192
void SymbolGraph::recordNode(Symbol S) {
193+
if (Walker.Options.SkipProtocolImplementations && S.getInheritedDecl()) {
194+
const auto *DocCommentProvidingDecl =
195+
getDocCommentProvidingDecl(S.getLocalSymbolDecl(), /*AllowSerialized=*/true);
196+
197+
// allow implementation symbols to remain if they have their own comment
198+
if (DocCommentProvidingDecl != S.getLocalSymbolDecl())
199+
return;
200+
}
201+
192202
Nodes.insert(S);
193203

194204
// Record all of the possible relationships (edges) originating
@@ -294,7 +304,7 @@ bool SymbolGraph::synthesizedMemberIsBestCandidate(const ValueDecl *VD,
294304
}
295305

296306
void SymbolGraph::recordConformanceSynthesizedMemberRelationships(Symbol S) {
297-
if (!Walker.Options.EmitSynthesizedMembers) {
307+
if (!Walker.Options.EmitSynthesizedMembers || Walker.Options.SkipProtocolImplementations) {
298308
return;
299309
}
300310
const auto D = S.getLocalSymbolDecl();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend %s -module-name SkipProtocolImplementations -emit-module -emit-module-path %t/SkipProtocolImplementations.swiftmodule -emit-symbol-graph -emit-symbol-graph-dir %t/ -skip-protocol-implementations
3+
// RUN: %{python} -m json.tool %t/SkipProtocolImplementations.symbols.json %t/SkipProtocolImplementations.formatted.symbols.json
4+
// RUN: %FileCheck %s --input-file %t/SkipProtocolImplementations.formatted.symbols.json
5+
6+
// RUN: %empty-directory(%t)
7+
// RUN: %target-swift-frontend %s -module-name SkipProtocolImplementations -emit-module -emit-module-path %t/SkipProtocolImplementations.swiftmodule -emit-module-doc-path %t/SkipProtocolImplementations.swiftdoc
8+
// RUN: %target-swift-symbolgraph-extract -module-name SkipProtocolImplementations -I %t -skip-protocol-implementations -pretty-print -output-dir %t
9+
// RUN: %FileCheck %s --input-file %t/SkipProtocolImplementations.symbols.json
10+
11+
// make sure that using `-skip-protocol-implementations` removes the functions from `SomeProtocol` on `SomeStruct`
12+
// CHECK-NOT: s:27SkipProtocolImplementations04SomeB0PAAE9bonusFuncyyF::SYNTHESIZED::s:27SkipProtocolImplementations10SomeStructV
13+
// CHECK-NOT: s:27SkipProtocolImplementations10SomeStructV8someFuncyyF
14+
15+
// CHECK-LABEL: "symbols": [
16+
17+
// SomeStruct.otherFunc() should be present because it has its own doc comment
18+
// CHECK: s:27SkipProtocolImplementations10SomeStructV9otherFuncyyF
19+
20+
// CHECK-LABEL: "relationships": [
21+
22+
// we want to make sure that the conformance relationship itself stays
23+
// CHECK-DAG: conformsTo
24+
25+
// SomeStruct.otherFunc() should be the only one with sourceOrigin information
26+
// CHECK-COUNT-1: sourceOrigin
27+
28+
public protocol SomeProtocol {
29+
/// Base docs
30+
func someFunc()
31+
32+
/// Base docs
33+
func otherFunc()
34+
}
35+
36+
public extension SomeProtocol {
37+
func bonusFunc() {}
38+
}
39+
40+
public struct SomeStruct: SomeProtocol {
41+
public func someFunc() {}
42+
43+
/// Local docs
44+
public func otherFunc() {}
45+
}

Diff for: tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp

+6-12
Original file line numberDiff line numberDiff line change
@@ -1013,18 +1013,12 @@ fillSymbolInfo(CursorSymbolInfo &Symbol, const DeclInfo &DInfo,
10131013
if (AddSymbolGraph) {
10141014
SmallVector<symbolgraphgen::PathComponent, 4> PathComponents;
10151015
SmallVector<symbolgraphgen::FragmentInfo, 8> FragmentInfos;
1016-
symbolgraphgen::SymbolGraphOptions Options{
1017-
"",
1018-
Invoc.getLangOptions().Target,
1019-
/*PrettyPrint=*/false,
1020-
AccessLevel::Private,
1021-
/*EmitSynthesizedMembers=*/false,
1022-
/*PrintMessages=*/false,
1023-
/*SkipInheritedDocs=*/false,
1024-
/*IncludeSPISymbols=*/true,
1025-
/*IncludeClangDocs=*/true,
1026-
/*EmitExtensionBlockSymbols=*/false,
1027-
};
1016+
1017+
symbolgraphgen::SymbolGraphOptions Options;
1018+
Options.Target = Invoc.getLangOptions().Target;
1019+
Options.MinimumAccessLevel = AccessLevel::Private;
1020+
Options.IncludeSPISymbols = true;
1021+
Options.IncludeClangDocs = true;
10281022

10291023
symbolgraphgen::printSymbolGraphForDecl(DInfo.VD, DInfo.BaseType,
10301024
DInfo.InSynthesizedExtension,

0 commit comments

Comments
 (0)