Skip to content

Commit 428d58e

Browse files
authored
Merge pull request #31303 from bitjammer/acgarland/rdar-60193198-sgf-filter-duplicate-synthesized
[SymbolGraph] Pick best synthesized member when possible
2 parents 811d6a5 + d5aa0d0 commit 428d58e

File tree

4 files changed

+82
-7
lines changed

4 files changed

+82
-7
lines changed

lib/SymbolGraphGen/SymbolGraph.cpp

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "clang/AST/DeclObjC.h"
14+
#include "swift/AST/ASTContext.h"
1415
#include "swift/AST/Decl.h"
1516
#include "swift/AST/Module.h"
1617
#include "swift/AST/ProtocolConformance.h"
@@ -218,6 +219,28 @@ void SymbolGraph::recordSuperclassSynthesizedMemberRelationships(Symbol S) {
218219
}
219220
}
220221

222+
bool SymbolGraph::synthesizedMemberIsBestCandidate(const ValueDecl *VD,
223+
const NominalTypeDecl *Owner) const {
224+
const auto *FD = dyn_cast<FuncDecl>(VD);
225+
if (!FD) {
226+
return true;
227+
}
228+
auto *DC = const_cast<DeclContext*>(Owner->getDeclContext());
229+
230+
ResolvedMemberResult Result =
231+
resolveValueMember(*DC, Owner->getSelfTypeInContext(),
232+
FD->getEffectiveFullName());
233+
234+
const auto ViableCandidates =
235+
Result.getMemberDecls(InterestedMemberKind::All);
236+
237+
if (ViableCandidates.size() < 2) {
238+
return true;
239+
}
240+
241+
return !(Result.hasBestOverload() && Result.getBestOverload() != VD);
242+
}
243+
221244
void SymbolGraph::recordConformanceSynthesizedMemberRelationships(Symbol S) {
222245
if (!Walker.Options.EmitSynthesizedMembers) {
223246
return;
@@ -264,14 +287,22 @@ void SymbolGraph::recordConformanceSynthesizedMemberRelationships(Symbol S) {
264287
continue;
265288
}
266289

290+
const auto StdlibModule = OwningNominal->getASTContext()
291+
.getStdlibModule(/*loadIfAbsent=*/true);
292+
267293
// There can be synthesized members on effectively private protocols
268294
// or things that conform to them. We don't want to include those.
269-
if (SynthMember->hasUnderscoredNaming()) {
295+
if (isImplicitlyPrivate(SynthMember,
296+
/*IgnoreContext =*/
297+
SynthMember->getModuleContext() == StdlibModule)) {
298+
continue;
299+
}
300+
301+
if (!synthesizedMemberIsBestCandidate(SynthMember, OwningNominal)) {
270302
continue;
271303
}
272304

273-
auto ExtendedSG =
274-
Walker.getModuleSymbolGraph(OwningNominal->getModuleContext());
305+
auto ExtendedSG = Walker.getModuleSymbolGraph(OwningNominal);
275306

276307
Symbol Source(this, SynthMember, OwningNominal);
277308
Symbol Target(this, OwningNominal, nullptr);
@@ -501,7 +532,8 @@ SymbolGraph::serializeDeclarationFragments(StringRef Key, Type T,
501532
T->print(Printer, getDeclarationFragmentsPrintOptions());
502533
}
503534

504-
bool SymbolGraph::isImplicitlyPrivate(const ValueDecl *VD) const {
535+
bool SymbolGraph::isImplicitlyPrivate(const ValueDecl *VD,
536+
bool IgnoreContext) const {
505537
// Don't record unconditionally private declarations
506538
if (VD->isPrivateStdlibDecl(/*treatNonBuiltinProtocolsAsPublic=*/false)) {
507539
return true;
@@ -550,15 +582,19 @@ bool SymbolGraph::isImplicitlyPrivate(const ValueDecl *VD) const {
550582
return true;
551583
}
552584

585+
if (IgnoreContext) {
586+
return false;
587+
}
588+
553589
// Check up the parent chain. Anything inside a privately named
554590
// thing is also private. We could be looking at the `B` of `_A.B`.
555591
if (const auto *DC = VD->getDeclContext()) {
556592
if (const auto *Parent = DC->getAsDecl()) {
557593
if (const auto *ParentVD = dyn_cast<ValueDecl>(Parent)) {
558-
return isImplicitlyPrivate(ParentVD);
594+
return isImplicitlyPrivate(ParentVD, IgnoreContext);
559595
} else if (const auto *Extension = dyn_cast<ExtensionDecl>(Parent)) {
560596
if (const auto *Nominal = Extension->getExtendedNominal()) {
561-
return isImplicitlyPrivate(Nominal);
597+
return isImplicitlyPrivate(Nominal, IgnoreContext);
562598
}
563599
}
564600
}

lib/SymbolGraphGen/SymbolGraph.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ struct SymbolGraph {
7575
/// Get the base print options for declaration fragments.
7676
PrintOptions getDeclarationFragmentsPrintOptions() const;
7777

78+
bool synthesizedMemberIsBestCandidate(const ValueDecl *VD,
79+
const NominalTypeDecl *Owner) const;
80+
7881
// MARK: - Symbols (Nodes)
7982

8083
/**
@@ -197,7 +200,11 @@ struct SymbolGraph {
197200
/// Returns `true` if the declaration has a name that makes it
198201
/// implicitly internal/private, such as underscore prefixes,
199202
/// and checking every named parent context as well.
200-
bool isImplicitlyPrivate(const ValueDecl *VD) const;
203+
///
204+
/// \param IgnoreContext If `true`, don't consider
205+
/// the context of the symbol to determine whether it is implicitly private.
206+
bool isImplicitlyPrivate(const ValueDecl *VD,
207+
bool IgnoreContext = false) const;
201208

202209
/// Returns `true` if the declaration should be included as a node
203210
/// in the graph.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift %s -module-name PickBestCandidate -emit-module -emit-module-path %t/
3+
// RUN: %target-swift-symbolgraph-extract -module-name PickBestCandidate -I %t -pretty-print -output-dir %t
4+
// RUN: %FileCheck %s --input-file %t/PickBestCandidate.symbols.json
5+
6+
public protocol P {
7+
func foo()
8+
func bar()
9+
}
10+
11+
public protocol Q : P {}
12+
extension Q {
13+
public func foo() {}
14+
public func bar() {}
15+
}
16+
17+
public protocol R : Q {}
18+
extension R {
19+
public func foo() {}
20+
public func bar() {}
21+
}
22+
23+
public struct MyStruct: R {
24+
public func bar() {}
25+
}
26+
27+
// MyStruct gets one and only one synthesized `foo`.
28+
// MyStruct gets no synthesized `bar`, because it has its own implementation.
29+
// CHECK-COUNT-1: ::SYNTHESIZED::

tools/driver/swift_symbolgraph_extract_main.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,9 @@ int swift_symbolgraph_extract_main(ArrayRef<const char *> Args, const char *Argv
239239
return EXIT_FAILURE;
240240
}
241241

242+
const auto &MainFile = M->getMainFile(FileUnitKind::SerializedAST);
243+
llvm::errs() << "Emitting symbol graph for module file: " << MainFile.getModuleDefiningPath() << '\n';
244+
242245
return symbolgraphgen::emitSymbolGraphForModule(M,
243246
Options);
244247
}

0 commit comments

Comments
 (0)