Skip to content

Commit 170dcd8

Browse files
Merge pull request #36863 from apple/QuietMisdreavus/docs-inheritance
[SymbolGraph] Add information about "inherited docs" for synthesized symbols
2 parents 89039a8 + 640aa21 commit 170dcd8

File tree

14 files changed

+138
-6
lines changed

14 files changed

+138
-6
lines changed

include/swift/Frontend/FrontendOptions.h

+4
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,10 @@ class FrontendOptions {
394394
///
395395
/// \sa SymbolGraphASTWalker
396396
std::string SymbolGraphOutputDir;
397+
398+
/// Whether to emit doc comment information in symbol graphs for symbols
399+
/// which are inherited through classes or default implementations.
400+
bool SkipInheritedDocs = false;
397401

398402
private:
399403
static bool canActionEmitDependencies(ActionType);

include/swift/Option/Options.td

+6
Original file line numberDiff line numberDiff line change
@@ -1214,4 +1214,10 @@ def minimum_access_level : Separate<["-"], "minimum-access-level">,
12141214
HelpText<"Include symbols with this access level or more">,
12151215
MetaVarName<"<level>">;
12161216

1217+
def skip_inherited_docs : Flag<["-"], "skip-inherited-docs">,
1218+
Flags<[SwiftSymbolGraphExtractOption, FrontendOption,
1219+
NoInteractiveOption, SupplementaryOutput, HelpHidden]>,
1220+
HelpText<"Skip emitting doc comments for members inherited through classes or "
1221+
"default implementations">;
1222+
12171223
include "FrontendOptions.td"

include/swift/Serialization/SerializationOptions.h

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ namespace swift {
3131
const char *DocOutputPath = nullptr;
3232
const char *SourceInfoOutputPath = nullptr;
3333
std::string SymbolGraphOutputDir;
34+
bool SkipSymbolGraphInheritedDocs = true;
3435

3536
StringRef GroupInfoPath;
3637
StringRef ImportedHeader;

include/swift/SymbolGraphGen/SymbolGraphOptions.h

+3
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ struct SymbolGraphOptions {
3939
/// Whether to print informational messages when rendering
4040
/// a symbol graph.
4141
bool PrintMessages;
42+
43+
/// Whether to skip docs for symbols with compound, "SYNTHESIZED" USRs.
44+
bool SkipInheritedDocs;
4245
};
4346

4447
} // end namespace symbolgraphgen

lib/Frontend/ArgsToFrontendOptionsConverter.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,8 @@ bool ArgsToFrontendOptionsConverter::convert(
248248
if (const Arg *A = Args.getLastArg(OPT_emit_symbol_graph_dir)) {
249249
Opts.SymbolGraphOutputDir = A->getValue();
250250
}
251+
252+
Opts.SkipInheritedDocs = Args.hasArg(OPT_skip_inherited_docs);
251253

252254
return false;
253255
}

lib/Frontend/Frontend.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ SerializationOptions CompilerInvocation::computeSerializationOptions(
168168
llvm::sys::fs::make_absolute(OutputDir);
169169
serializationOpts.SymbolGraphOutputDir = OutputDir.str().str();
170170
}
171+
serializationOpts.SkipSymbolGraphInheritedDocs = opts.SkipInheritedDocs;
171172

172173
if (!getIRGenOptions().ForceLoadSymbolName.empty())
173174
serializationOpts.AutolinkForceLoad = true;

lib/Serialization/Serialization.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -5635,6 +5635,7 @@ void swift::serialize(ModuleOrSourceFile DC,
56355635
AccessLevel::Public,
56365636
/*EmitSynthesizedMembers*/true,
56375637
/*PrintMessages*/false,
5638+
/*EmitInheritedDocs*/options.SkipSymbolGraphInheritedDocs,
56385639
};
56395640
symbolgraphgen::emitSymbolGraphForModule(M, SGOpts);
56405641
}

lib/SymbolGraphGen/Edge.cpp

+22
Original file line numberDiff line numberDiff line change
@@ -57,5 +57,27 @@ void Edge::serialize(llvm::json::OStream &OS) const {
5757
});
5858
}
5959
}
60+
61+
const ValueDecl *InheritingDecl = nullptr;
62+
if (const auto *ID = Source.getDeclInheritingDocs()) {
63+
if (Target.getSymbolDecl() == ID || Source.getSynthesizedBaseTypeDecl())
64+
InheritingDecl = ID;
65+
}
66+
67+
// If our source symbol is a inheriting decl, write in information about
68+
// where it's inheriting docs from.
69+
if (InheritingDecl) {
70+
Symbol inheritedSym(Graph, InheritingDecl, nullptr);
71+
SmallString<256> USR, Display;
72+
llvm::raw_svector_ostream DisplayOS(Display);
73+
74+
inheritedSym.getUSR(USR);
75+
inheritedSym.printPath(DisplayOS);
76+
77+
OS.attributeObject("sourceOrigin", [&](){
78+
OS.attribute("identifier", USR.str());
79+
OS.attribute("displayName", Display.str());
80+
});
81+
}
6082
});
6183
}

lib/SymbolGraphGen/FormatVersion.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@
1515

1616
#define SWIFT_SYMBOLGRAPH_FORMAT_MAJOR 0
1717
#define SWIFT_SYMBOLGRAPH_FORMAT_MINOR 5
18-
#define SWIFT_SYMBOLGRAPH_FORMAT_PATCH 2
18+
#define SWIFT_SYMBOLGRAPH_FORMAT_PATCH 3
1919

2020
#endif // SWIFT_SYMBOLGRAPHGEN_FORMATVERSION_H

lib/SymbolGraphGen/Symbol.cpp

+27-5
Original file line numberDiff line numberDiff line change
@@ -172,12 +172,34 @@ void Symbol::serializeRange(size_t InitialIndentation,
172172
});
173173
}
174174

175-
void Symbol::serializeDocComment(llvm::json::OStream &OS) const {
175+
const ValueDecl *Symbol::getDeclInheritingDocs() const {
176+
// get the decl that would provide docs for this symbol
176177
const auto *DocCommentProvidingDecl =
177-
dyn_cast_or_null<ValueDecl>(
178-
getDocCommentProvidingDecl(VD, /*AllowSerialized=*/true));
179-
if (!DocCommentProvidingDecl) {
180-
DocCommentProvidingDecl = VD;
178+
dyn_cast_or_null<ValueDecl>(
179+
getDocCommentProvidingDecl(VD, /*AllowSerialized=*/true));
180+
181+
// if the decl is the same as the one for this symbol, we're not
182+
// inheriting docs, so return null. however, if this symbol is
183+
// a synthesized symbol, `VD` is actually the source symbol, and
184+
// we should point to that one regardless.
185+
if (DocCommentProvidingDecl == VD && !SynthesizedBaseTypeDecl) {
186+
return nullptr;
187+
} else {
188+
// otherwise, return whatever `getDocCommentProvidingDecl` returned.
189+
// it will be null if there are no decls that provide docs for this
190+
// symbol.
191+
return DocCommentProvidingDecl;
192+
}
193+
}
194+
195+
void Symbol::serializeDocComment(llvm::json::OStream &OS) const {
196+
const auto *DocCommentProvidingDecl = VD;
197+
if (!Graph->Walker.Options.SkipInheritedDocs) {
198+
DocCommentProvidingDecl = dyn_cast_or_null<ValueDecl>(
199+
getDocCommentProvidingDecl(VD, /*AllowSerialized=*/true));
200+
if (!DocCommentProvidingDecl) {
201+
DocCommentProvidingDecl = VD;
202+
}
181203
}
182204
auto RC = DocCommentProvidingDecl->getRawComment(/*SerializedOK=*/true);
183205
if (RC.isEmpty()) {

lib/SymbolGraphGen/Symbol.h

+5
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,11 @@ class Symbol {
111111
void printPath(llvm::raw_ostream &OS) const;
112112

113113
void getUSR(SmallVectorImpl<char> &USR) const;
114+
115+
/// If this symbol is inheriting docs from a parent class, protocol, or default
116+
/// implementation, returns that decl. Returns null if there are no docs or if
117+
/// the symbol has its own doc comments to render.
118+
const ValueDecl *getDeclInheritingDocs() const;
114119

115120
static bool supportsKind(DeclKind Kind);
116121
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend %s -module-name InheritedDocs -emit-module -emit-module-path %t/InheritedDocs.swiftmodule -emit-module-source-info-path %t/InheritedDocs.swiftsourceinfo -emit-module-doc-path %t/InheritedDocs.swiftdoc
3+
4+
// RUN: %target-swift-symbolgraph-extract -module-name InheritedDocs -I %t -pretty-print -output-dir %t
5+
// RUN: %FileCheck %s --input-file %t/InheritedDocs.symbols.json --check-prefixes CHECK,DOCS
6+
// RUN: %FileCheck %s --input-file %t/InheritedDocs.symbols.json --check-prefixes IMPL
7+
// RUN: %FileCheck %s --input-file %t/InheritedDocs.symbols.json --check-prefixes BONUS
8+
// RUN: %FileCheck %s --input-file %t/InheritedDocs.symbols.json --check-prefixes BONUS-DOCS
9+
10+
// RUN: %target-swift-symbolgraph-extract -module-name InheritedDocs -I %t -pretty-print -output-dir %t -skip-inherited-docs
11+
// RUN: %FileCheck %s --input-file %t/InheritedDocs.symbols.json --check-prefixes CHECK,SKIP
12+
// RUN: %FileCheck %s --input-file %t/InheritedDocs.symbols.json --check-prefixes IMPL
13+
// RUN: %FileCheck %s --input-file %t/InheritedDocs.symbols.json --check-prefixes BONUS
14+
// RUN: %FileCheck %s --input-file %t/InheritedDocs.symbols.json --check-prefixes BONUS-SKIP
15+
16+
// RUN: %empty-directory(%t)
17+
// RUN: %target-build-swift %s -module-name InheritedDocs -emit-module -emit-module-path %t/InheritedDocs.swiftmodule -emit-symbol-graph -emit-symbol-graph-dir %t/ -skip-inherited-docs
18+
// RUN: %FileCheck %s --input-file %t/InheritedDocs.symbols.json --check-prefixes SKIP
19+
20+
// DOCS-COUNT-3: Some Function
21+
// BONUS-DOCS-COUNT-2: Bonus docs!
22+
// SKIP-COUNT-1: Some Function
23+
// BONUS-SKIP-COUNT-1: Bonus docs!
24+
25+
// synthesized symbols should have a sourceOrigin field that points to where its docs come from
26+
27+
// CHECK: "source": "s:13InheritedDocs1PPAAE8someFuncyyF::SYNTHESIZED::s:13InheritedDocs1SV"
28+
// CHECK-NEXT: "target": "s:13InheritedDocs1SV"
29+
// CHECK-NEXT: "sourceOrigin"
30+
// CHECK-NEXT: "identifier": "s:13InheritedDocs1PP8someFuncyyF"
31+
// CHECK-NEXT: "displayName": "P.someFunc()"
32+
33+
// non-synthesized symbols that nonetheless inherit docs (like this extension) should have the same
34+
35+
// IMPL: "source": "s:13InheritedDocs1PPAAE8someFuncyyF"
36+
// IMPL-NEXT: "target": "s:13InheritedDocs1PP8someFuncyyF"
37+
// IMPL-NEXT: "sourceOrigin"
38+
// IMPL-NEXT: "identifier": "s:13InheritedDocs1PP8someFuncyyF"
39+
// IMPL-NEXT: "displayName": "P.someFunc()"
40+
41+
// synthesized symbols that point directly to their docs should also have a sourceOrigin field
42+
43+
// BONUS: "source": "s:13InheritedDocs1PPAAE9bonusFuncyyF::SYNTHESIZED::s:13InheritedDocs1SV"
44+
// BONUS-NEXT: "target": "s:13InheritedDocs1SV"
45+
// BONUS-NEXT: "sourceOrigin"
46+
// BONUS-NEXT: "identifier": "s:13InheritedDocs1PPAAE9bonusFuncyyF"
47+
// BONUS-NEXT: "displayName": "P.bonusFunc()"
48+
49+
/// Protocol P
50+
public protocol P {
51+
/// Some Function
52+
func someFunc()
53+
}
54+
55+
public extension P {
56+
func someFunc() {}
57+
58+
/// Bonus docs!
59+
func bonusFunc() {}
60+
}
61+
62+
public struct S: P {
63+
}

tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -870,6 +870,7 @@ fillSymbolInfo(CursorSymbolInfo &Symbol, const DeclInfo &DInfo,
870870
AccessLevel::Private,
871871
/*EmitSynthesizedMembers*/ false,
872872
/*PrintMessages*/ false,
873+
/*SkipInheritedDocs*/ false,
873874
};
874875

875876
symbolgraphgen::printSymbolGraphForDecl(DInfo.VD, DInfo.BaseType,

tools/driver/swift_symbolgraph_extract_main.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ int swift_symbolgraph_extract_main(ArrayRef<const char *> Args,
167167
AccessLevel::Public,
168168
!ParsedArgs.hasArg(OPT_skip_synthesized_members),
169169
ParsedArgs.hasArg(OPT_v),
170+
ParsedArgs.hasArg(OPT_skip_inherited_docs),
170171
};
171172

172173
if (auto *A = ParsedArgs.getLastArg(OPT_minimum_access_level)) {

0 commit comments

Comments
 (0)