Skip to content

Commit 51ce1f2

Browse files
committed
[SymbolGraph] Look for @_spi on extensions
Consider declarations inside `@_spi` extensions to be internal. Clean up the "implicitly private" check to work for `Decl` and not just `ValueDecl`, allowing it to be used directly on extensions instead of having to look for extensions everywhere. rdar://63361634
1 parent 21f5032 commit 51ce1f2

File tree

6 files changed

+63
-52
lines changed

6 files changed

+63
-52
lines changed

Diff for: lib/SymbolGraphGen/SymbolGraph.cpp

+45-42
Original file line numberDiff line numberDiff line change
@@ -566,71 +566,74 @@ SymbolGraph::serializeDeclarationFragments(StringRef Key, Type T,
566566
T->print(Printer, getDeclarationFragmentsPrintOptions());
567567
}
568568

569-
bool SymbolGraph::isImplicitlyPrivate(const ValueDecl *VD,
569+
bool SymbolGraph::isImplicitlyPrivate(const Decl *D,
570570
bool IgnoreContext) const {
571571
// Don't record unconditionally private declarations
572-
if (VD->isPrivateStdlibDecl(/*treatNonBuiltinProtocolsAsPublic=*/false)) {
572+
if (D->isPrivateStdlibDecl(/*treatNonBuiltinProtocolsAsPublic=*/false)) {
573573
return true;
574574
}
575575

576576
// Don't record effectively internal declarations if specified
577577
if (Walker.Options.MinimumAccessLevel > AccessLevel::Internal &&
578-
VD->hasUnderscoredNaming()) {
578+
D->hasUnderscoredNaming()) {
579579
return true;
580580
}
581581

582-
// Don't include declarations with the @_spi attribute for now.
583-
if (VD->getAttrs().getAttribute(DeclAttrKind::DAK_SPIAccessControl)) {
584-
return true;
582+
// Don't include declarations with the @_spi attribute unless the
583+
// access control filter is internal or below.
584+
if (D->isSPI()) {
585+
return Walker.Options.MinimumAccessLevel > AccessLevel::Internal;
585586
}
586587

587-
// Symbols must meet the minimum access level to be included in the graph.
588-
if (VD->getFormalAccess() < Walker.Options.MinimumAccessLevel) {
589-
return true;
588+
if (const auto *Extension = dyn_cast<ExtensionDecl>(D)) {
589+
if (const auto *Nominal = Extension->getExtendedNominal()) {
590+
return isImplicitlyPrivate(Nominal, IgnoreContext);
591+
}
590592
}
591593

592-
// Special cases below.
594+
if (const auto *VD = dyn_cast<ValueDecl>(D)) {
595+
// Symbols must meet the minimum access level to be included in the graph.
596+
if (VD->getFormalAccess() < Walker.Options.MinimumAccessLevel) {
597+
return true;
598+
}
593599

594-
auto BaseName = VD->getBaseName().userFacingName();
600+
// Special cases below.
595601

596-
// ${MODULE}Version{Number,String} in ${Module}.h
597-
SmallString<32> VersionNameIdentPrefix { M.getName().str() };
598-
VersionNameIdentPrefix.append("Version");
599-
if (BaseName.startswith(VersionNameIdentPrefix.str())) {
600-
return true;
601-
}
602+
auto BaseName = VD->getBaseName().userFacingName();
602603

603-
// Automatically mapped SIMD types
604-
auto IsGlobalSIMDType = llvm::StringSwitch<bool>(BaseName)
605-
#define MAP_SIMD_TYPE(C_TYPE, _, __) \
606-
.Case("swift_" #C_TYPE "2", true) \
607-
.Case("swift_" #C_TYPE "3", true) \
608-
.Case("swift_" #C_TYPE "4", true)
609-
#include "swift/ClangImporter/SIMDMappedTypes.def"
610-
.Case("SWIFT_TYPEDEFS", true)
611-
.Case("char16_t", true)
612-
.Case("char32_t", true)
613-
.Default(false);
614-
615-
if (IsGlobalSIMDType) {
616-
return true;
617-
}
604+
// ${MODULE}Version{Number,String} in ${Module}.h
605+
SmallString<32> VersionNameIdentPrefix { M.getName().str() };
606+
VersionNameIdentPrefix.append("Version");
607+
if (BaseName.startswith(VersionNameIdentPrefix.str())) {
608+
return true;
609+
}
618610

619-
if (IgnoreContext) {
620-
return false;
611+
// Automatically mapped SIMD types
612+
auto IsGlobalSIMDType = llvm::StringSwitch<bool>(BaseName)
613+
#define MAP_SIMD_TYPE(C_TYPE, _, __) \
614+
.Case("swift_" #C_TYPE "2", true) \
615+
.Case("swift_" #C_TYPE "3", true) \
616+
.Case("swift_" #C_TYPE "4", true)
617+
#include "swift/ClangImporter/SIMDMappedTypes.def"
618+
.Case("SWIFT_TYPEDEFS", true)
619+
.Case("char16_t", true)
620+
.Case("char32_t", true)
621+
.Default(false);
622+
623+
if (IsGlobalSIMDType) {
624+
return true;
625+
}
626+
627+
if (IgnoreContext) {
628+
return false;
629+
}
621630
}
622631

623632
// Check up the parent chain. Anything inside a privately named
624633
// thing is also private. We could be looking at the `B` of `_A.B`.
625-
if (const auto *DC = VD->getDeclContext()) {
634+
if (const auto *DC = D->getDeclContext()) {
626635
if (const auto *Parent = DC->getAsDecl()) {
627-
if (const auto *ParentVD = dyn_cast<ValueDecl>(Parent)) {
628-
return isImplicitlyPrivate(ParentVD, IgnoreContext);
629-
} else if (const auto *Extension = dyn_cast<ExtensionDecl>(Parent)) {
630-
if (const auto *Nominal = Extension->getExtendedNominal()) {
631-
return isImplicitlyPrivate(Nominal, IgnoreContext);
632-
}
633-
}
636+
return isImplicitlyPrivate(Parent, IgnoreContext);
634637
}
635638
}
636639
return false;

Diff for: lib/SymbolGraphGen/SymbolGraph.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -215,8 +215,8 @@ struct SymbolGraph {
215215
/// and checking every named parent context as well.
216216
///
217217
/// \param IgnoreContext If `true`, don't consider
218-
/// the context of the symbol to determine whether it is implicitly private.
219-
bool isImplicitlyPrivate(const ValueDecl *VD,
218+
/// the context of the declaration to determine whether it is implicitly private.
219+
bool isImplicitlyPrivate(const Decl *D,
220220
bool IgnoreContext = false) const;
221221

222222
/// Returns `true` if the declaration should be included as a node

Diff for: lib/SymbolGraphGen/SymbolGraphASTWalker.cpp

+6-5
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,17 @@ SymbolGraph *SymbolGraphASTWalker::getModuleSymbolGraph(const Decl *D) {
4646
if (this->M.getNameStr().equals(M->getNameStr())) {
4747
return &MainGraph;
4848
}
49-
auto Found = ExtendedModuleGraphs.find(M);
49+
auto Found = ExtendedModuleGraphs.find(M->getNameStr());
5050
if (Found != ExtendedModuleGraphs.end()) {
51-
return Found->getSecond();
51+
return Found->getValue();
5252
}
5353
auto *Memory = Ctx.allocate(sizeof(SymbolGraph), alignof(SymbolGraph));
5454
auto *SG = new (Memory) SymbolGraph(*this,
5555
MainGraph.M,
5656
Optional<ModuleDecl *>(M),
5757
Ctx);
58-
ExtendedModuleGraphs.insert({M, SG});
58+
59+
ExtendedModuleGraphs.insert({M->getNameStr(), SG});
5960
return SG;
6061
}
6162

@@ -108,8 +109,8 @@ bool SymbolGraphASTWalker::walkToDeclPre(Decl *D, CharSourceRange Range) {
108109
if (const auto *Extension = dyn_cast<ExtensionDecl>(D)) {
109110
const auto *ExtendedNominal = Extension->getExtendedNominal();
110111
auto ExtendedSG = getModuleSymbolGraph(ExtendedNominal);
111-
// Ignore effecively private decls.
112-
if (ExtendedSG->isImplicitlyPrivate(ExtendedNominal)) {
112+
// Ignore effectively private decls.
113+
if (ExtendedSG->isImplicitlyPrivate(Extension)) {
113114
return false;
114115
}
115116

Diff for: lib/SymbolGraphGen/SymbolGraphASTWalker.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ struct SymbolGraphASTWalker : public SourceEntityWalker {
5151
SymbolGraph MainGraph;
5252

5353
/// A map of modules whose types were extended by the main module of interest `M`.
54-
llvm::DenseMap<ModuleDecl *, SymbolGraph *> ExtendedModuleGraphs;
54+
llvm::StringMap<SymbolGraph *> ExtendedModuleGraphs;
5555

5656
// MARK: - Initialization
5757

Diff for: lib/SymbolGraphGen/SymbolGraphGen.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ symbolgraphgen::emitSymbolGraphForModule(ModuleDecl *M,
7373

7474
Success |= serializeSymbolGraph(Walker.MainGraph, Options);
7575

76-
for (auto Pair : Walker.ExtendedModuleGraphs) {
77-
Success |= serializeSymbolGraph(*Pair.getSecond(), Options);
76+
for (const auto &Entry : Walker.ExtendedModuleGraphs) {
77+
Success |= serializeSymbolGraph(*Entry.getValue(), Options);
7878
}
7979

8080
return Success;

Diff for: test/SymbolGraph/Symbols/SkipsSPI.swift

+7
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,10 @@ extension StructShouldntAppear.InnerStructShouldntAppear {
5757
@_spi(OtherModule)
5858
public func extendedFunctionShouldntAppear() {}
5959
}
60+
61+
@_spi(OtherModule)
62+
extension StructShouldAppear {
63+
// Although StructShouldAppear is fair to include, this extension is
64+
// tagged as SPI, so everything inside it should be considered SPI as well.
65+
public func functionInSPIExtensionShouldntAppear() {}
66+
}

0 commit comments

Comments
 (0)