mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Allow for emission of swift.extension symbols for extensions to external types in swiftSymbolGraphGen (#59047)
This includes: - bumping the SWIFT_SYMBOLGRAPH_FORMAT_MINOR version - introduction of the "swift.extension" symbol and "extensionTo" relationship - adding support for ExtensionDecl to the Symbol class - adding a "typeKind" field to the symbol's extension mixin which indicates what kind of symbol was extended - intoduction of the -emit-extension-block-symbols flag, which enables the behavior outlined below - adaptions to SymbolGraphASTWalker that ensure a swift.extension symbol is emitted for each extension to a type that does not exist in the local symbol graph - adaptions to SymbolGraph and SymbolGraphASTWalker that ensure member and conformance relationships are correctly associated with the swift.extension symbol instead of the original type declaration's (extended nominal's) symbol where applicable - adaptions to SymbolGraphASTWalker that ensure swift.extension symbols are connected to their respective extended nominal's symbol using an extensionTo relationship Testing: - adds SymbolGraph tests that test behavior only relevant in -emit-extension-block-symbols mode - adapts some SymbolGraph tests to additionally test similar behavior for extensions to external types in -emit-extension-block-symbols mode - adapts some SymbolGraph tests to (additionally or exclusively) test the behavior with -emit-extension-block-symbols mode enabled Bugfixes: - fixes a bug where some conformsTo relationships implicated by the conformances declared on an extension to an external type were not emitted (see test/SymbolGraph/Relationships/ConformsTo/Indirect.swift) Further changes: - documents the strategy for naming and associating children declared in extensions to typealiases (see test/SymbolGraph/Relationships/MemberOf/Typealias.swift, test/SymbolGraph/Symbols/Names.swift)
This commit is contained in:
@@ -1357,6 +1357,11 @@ def pretty_print: Flag<["-"], "pretty-print">,
|
||||
Flags<[SwiftAPIExtractOption, SwiftSymbolGraphExtractOption]>,
|
||||
HelpText<"Pretty-print the output JSON">;
|
||||
|
||||
def emit_extension_block_symbols: Flag<["-"], "emit-extension-block-symbols">,
|
||||
Flags<[SwiftSymbolGraphExtractOption, FrontendOption,
|
||||
NoInteractiveOption, SupplementaryOutput, HelpHidden]>,
|
||||
HelpText<"Emit 'swift.extension' symbols for extensions to external types instead of directly associating members and conformances with the extended nominal when generating symbol graphs">;
|
||||
|
||||
// swift-symbolgraph-extract-only options
|
||||
def output_dir : Separate<["-"], "output-dir">,
|
||||
Flags<[NoDriverOption, SwiftSymbolGraphExtractOption, SwiftAPIDigesterOption,
|
||||
|
||||
@@ -48,6 +48,11 @@ struct SymbolGraphOptions {
|
||||
|
||||
/// Whether to include documentation for clang nodes or not.
|
||||
bool IncludeClangDocs = false;
|
||||
|
||||
/// Whether to emit "swift.extension" symbols for extensions to external types
|
||||
/// along with "extensionTo" relationships instead of directly associating
|
||||
/// members and conformances with the extended nominal.
|
||||
bool EmitExtensionBlockSymbols = false;
|
||||
};
|
||||
|
||||
} // end namespace symbolgraphgen
|
||||
|
||||
@@ -617,6 +617,7 @@ ToolChain::constructInvocation(const CompileJobAction &job,
|
||||
context.Args.AddLastArg(Arguments, options::OPT_emit_symbol_graph_dir);
|
||||
}
|
||||
context.Args.AddLastArg(Arguments, options::OPT_include_spi_symbols);
|
||||
context.Args.AddLastArg(Arguments, options::OPT_emit_extension_block_symbols);
|
||||
context.Args.AddLastArg(Arguments, options::OPT_symbol_graph_minimum_access_level);
|
||||
|
||||
return II;
|
||||
@@ -1113,6 +1114,7 @@ ToolChain::constructInvocation(const MergeModuleJobAction &job,
|
||||
context.Args.AddLastArg(Arguments, options::OPT_emit_symbol_graph);
|
||||
context.Args.AddLastArg(Arguments, options::OPT_emit_symbol_graph_dir);
|
||||
context.Args.AddLastArg(Arguments, options::OPT_include_spi_symbols);
|
||||
context.Args.AddLastArg(Arguments, options::OPT_emit_extension_block_symbols);
|
||||
context.Args.AddLastArg(Arguments, options::OPT_symbol_graph_minimum_access_level);
|
||||
|
||||
context.Args.AddLastArg(Arguments, options::OPT_import_objc_header);
|
||||
|
||||
@@ -172,6 +172,7 @@ int swift_symbolgraph_extract_main(ArrayRef<const char *> Args,
|
||||
ParsedArgs.hasArg(OPT_skip_inherited_docs),
|
||||
ParsedArgs.hasArg(OPT_include_spi_symbols),
|
||||
/*IncludeClangDocs=*/false,
|
||||
ParsedArgs.hasArg(OPT_emit_extension_block_symbols),
|
||||
};
|
||||
|
||||
if (auto *A = ParsedArgs.getLastArg(OPT_minimum_access_level)) {
|
||||
|
||||
@@ -1300,6 +1300,8 @@ static void ParseSymbolGraphArgs(symbolgraphgen::SymbolGraphOptions &Opts,
|
||||
|
||||
Opts.SkipInheritedDocs = Args.hasArg(OPT_skip_inherited_docs);
|
||||
Opts.IncludeSPISymbols = Args.hasArg(OPT_include_spi_symbols);
|
||||
Opts.EmitExtensionBlockSymbols =
|
||||
Args.hasArg(OPT_emit_extension_block_symbols);
|
||||
|
||||
if (auto *A = Args.getLastArg(OPT_symbol_graph_minimum_access_level)) {
|
||||
Opts.MinimumAccessLevel =
|
||||
|
||||
@@ -104,7 +104,20 @@ struct RelationshipKind {
|
||||
static inline RelationshipKind OptionalRequirementOf() {
|
||||
return RelationshipKind { "optionalRequirementOf" };
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
A symbol A extends a symbol B with members or conformances.
|
||||
|
||||
This relationship describes the connection between extension blocks
|
||||
(swift.extension symbols) and the type they extend.
|
||||
|
||||
The implied inverse of this relationship is a symbol B that is extended
|
||||
by an extension block symbol A.
|
||||
*/
|
||||
static inline RelationshipKind ExtensionTo() {
|
||||
return RelationshipKind{"extensionTo"};
|
||||
}
|
||||
|
||||
bool operator==(const RelationshipKind &Other) const {
|
||||
return Name == Other.Name;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#define SWIFT_SYMBOLGRAPHGEN_FORMATVERSION_H
|
||||
|
||||
#define SWIFT_SYMBOLGRAPH_FORMAT_MAJOR 0
|
||||
#define SWIFT_SYMBOLGRAPH_FORMAT_MINOR 5
|
||||
#define SWIFT_SYMBOLGRAPH_FORMAT_PATCH 3
|
||||
#define SWIFT_SYMBOLGRAPH_FORMAT_MINOR 6
|
||||
#define SWIFT_SYMBOLGRAPH_FORMAT_PATCH 0
|
||||
|
||||
#endif // SWIFT_SYMBOLGRAPHGEN_FORMATVERSION_H
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
// Adds Symbol Graph JSON serialization to other types.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "JSON.h"
|
||||
#include "Symbol.h"
|
||||
#include "swift/AST/ASTContext.h"
|
||||
#include "swift/AST/Decl.h"
|
||||
#include "swift/AST/FileUnit.h"
|
||||
@@ -21,7 +23,6 @@
|
||||
#include "swift/AST/USRGeneration.h"
|
||||
#include "swift/ClangImporter/ClangModule.h"
|
||||
#include "swift/Serialization/SerializedModuleLoader.h"
|
||||
#include "JSON.h"
|
||||
|
||||
void swift::symbolgraphgen::serialize(const llvm::VersionTuple &VT,
|
||||
llvm::json::OStream &OS) {
|
||||
@@ -69,6 +70,8 @@ void swift::symbolgraphgen::serialize(const ExtensionDecl *Extension,
|
||||
if (const auto *ExtendedModule = ExtendedNominal->getModuleContext()) {
|
||||
OS.attribute("extendedModule", ExtendedModule->getNameStr());
|
||||
}
|
||||
|
||||
OS.attribute("typeKind", Symbol::getKind(ExtendedNominal).first);
|
||||
}
|
||||
|
||||
SmallVector<Requirement, 4> FilteredRequirements;
|
||||
|
||||
@@ -33,16 +33,24 @@
|
||||
using namespace swift;
|
||||
using namespace symbolgraphgen;
|
||||
|
||||
Symbol::Symbol(SymbolGraph *Graph, const ExtensionDecl *ED,
|
||||
const NominalTypeDecl *SynthesizedBaseTypeDecl, Type BaseType)
|
||||
: Symbol::Symbol(Graph, nullptr, ED, SynthesizedBaseTypeDecl, BaseType) {}
|
||||
|
||||
Symbol::Symbol(SymbolGraph *Graph, const ValueDecl *VD,
|
||||
const NominalTypeDecl *SynthesizedBaseTypeDecl,
|
||||
Type BaseType)
|
||||
: Graph(Graph),
|
||||
VD(VD),
|
||||
BaseType(BaseType),
|
||||
SynthesizedBaseTypeDecl(SynthesizedBaseTypeDecl) {
|
||||
if (!BaseType && SynthesizedBaseTypeDecl)
|
||||
BaseType = SynthesizedBaseTypeDecl->getDeclaredInterfaceType();
|
||||
const NominalTypeDecl *SynthesizedBaseTypeDecl, Type BaseType)
|
||||
: Symbol::Symbol(Graph, VD, nullptr, SynthesizedBaseTypeDecl, BaseType) {}
|
||||
|
||||
Symbol::Symbol(SymbolGraph *Graph, const ValueDecl *VD, const ExtensionDecl *ED,
|
||||
const NominalTypeDecl *SynthesizedBaseTypeDecl, Type BaseType)
|
||||
: Graph(Graph), D(VD), BaseType(BaseType),
|
||||
SynthesizedBaseTypeDecl(SynthesizedBaseTypeDecl) {
|
||||
if (!BaseType && SynthesizedBaseTypeDecl)
|
||||
BaseType = SynthesizedBaseTypeDecl->getDeclaredInterfaceType();
|
||||
if (D == nullptr) {
|
||||
D = ED;
|
||||
}
|
||||
}
|
||||
|
||||
void Symbol::serializeKind(StringRef Identifier, StringRef DisplayName,
|
||||
llvm::json::OStream &OS) const {
|
||||
@@ -52,10 +60,10 @@ void Symbol::serializeKind(StringRef Identifier, StringRef DisplayName,
|
||||
});
|
||||
}
|
||||
|
||||
std::pair<StringRef, StringRef> Symbol::getKind(const ValueDecl *VD) const {
|
||||
std::pair<StringRef, StringRef> Symbol::getKind(const Decl *D) {
|
||||
// Make sure supportsKind stays in sync with getKind.
|
||||
assert(Symbol::supportsKind(VD->getKind()) && "unsupported decl kind");
|
||||
switch (VD->getKind()) {
|
||||
assert(Symbol::supportsKind(D->getKind()) && "unsupported decl kind");
|
||||
switch (D->getKind()) {
|
||||
case swift::DeclKind::Class:
|
||||
return {"swift.class", "Class"};
|
||||
case swift::DeclKind::Struct:
|
||||
@@ -70,7 +78,9 @@ std::pair<StringRef, StringRef> Symbol::getKind(const ValueDecl *VD) const {
|
||||
return {"swift.init", "Initializer"};
|
||||
case swift::DeclKind::Destructor:
|
||||
return {"swift.deinit", "Deinitializer"};
|
||||
case swift::DeclKind::Func:
|
||||
case swift::DeclKind::Func: {
|
||||
const auto *VD = cast<ValueDecl>(D);
|
||||
|
||||
if (VD->isOperator())
|
||||
return {"swift.func.op", "Operator"};
|
||||
if (VD->isStatic())
|
||||
@@ -78,29 +88,38 @@ std::pair<StringRef, StringRef> Symbol::getKind(const ValueDecl *VD) const {
|
||||
if (VD->getDeclContext()->getSelfNominalTypeDecl())
|
||||
return {"swift.method", "Instance Method"};
|
||||
return {"swift.func", "Function"};
|
||||
case swift::DeclKind::Var:
|
||||
}
|
||||
case swift::DeclKind::Var: {
|
||||
const auto *VD = cast<ValueDecl>(D);
|
||||
|
||||
if (VD->isStatic())
|
||||
return {"swift.type.property", "Type Property"};
|
||||
if (VD->getDeclContext()->getSelfNominalTypeDecl())
|
||||
return {"swift.property", "Instance Property"};
|
||||
return {"swift.var", "Global Variable"};
|
||||
case swift::DeclKind::Subscript:
|
||||
}
|
||||
case swift::DeclKind::Subscript: {
|
||||
const auto *VD = cast<ValueDecl>(D);
|
||||
|
||||
if (VD->isStatic())
|
||||
return {"swift.type.subscript", "Type Subscript"};
|
||||
return {"swift.subscript", "Instance Subscript"};
|
||||
}
|
||||
case swift::DeclKind::TypeAlias:
|
||||
return {"swift.typealias", "Type Alias"};
|
||||
case swift::DeclKind::AssociatedType:
|
||||
return {"swift.associatedtype", "Associated Type"};
|
||||
case swift::DeclKind::Extension:
|
||||
return {"swift.extension", "Extension"};
|
||||
default:
|
||||
llvm::errs() << "Unsupported kind: " << VD->getKindName(VD->getKind());
|
||||
llvm::errs() << "Unsupported kind: " << D->getKindName(D->getKind());
|
||||
llvm_unreachable("Unsupported declaration kind for symbol graph");
|
||||
}
|
||||
}
|
||||
|
||||
void Symbol::serializeKind(llvm::json::OStream &OS) const {
|
||||
AttributeRAII A("kind", OS);
|
||||
std::pair<StringRef, StringRef> IDAndName = getKind(VD);
|
||||
std::pair<StringRef, StringRef> IDAndName = getKind(D);
|
||||
serializeKind(IDAndName.first, IDAndName.second, OS);
|
||||
}
|
||||
|
||||
@@ -128,7 +147,14 @@ void Symbol::serializeNames(llvm::json::OStream &OS) const {
|
||||
SmallVector<PathComponent, 8> PathComponents;
|
||||
getPathComponents(PathComponents);
|
||||
|
||||
if (isa<GenericTypeDecl>(VD) || isa<EnumElementDecl>(VD)) {
|
||||
const ValueDecl *Decl = nullptr;
|
||||
if (const auto *ED = dyn_cast<ExtensionDecl>(D)) {
|
||||
Decl = ED->getExtendedNominal();
|
||||
} else if (const auto *VD = dyn_cast<ValueDecl>(D)) {
|
||||
Decl = VD;
|
||||
}
|
||||
|
||||
if (isa<GenericTypeDecl>(Decl) || isa<EnumElementDecl>(Decl)) {
|
||||
SmallString<64> FullyQualifiedTitle;
|
||||
|
||||
for (const auto *It = PathComponents.begin(); It != PathComponents.end(); ++It) {
|
||||
@@ -180,15 +206,14 @@ void Symbol::serializeRange(size_t InitialIndentation,
|
||||
|
||||
const ValueDecl *Symbol::getDeclInheritingDocs() const {
|
||||
// get the decl that would provide docs for this symbol
|
||||
const auto *DocCommentProvidingDecl =
|
||||
dyn_cast_or_null<ValueDecl>(
|
||||
getDocCommentProvidingDecl(VD, /*AllowSerialized=*/true));
|
||||
|
||||
const auto *DocCommentProvidingDecl = dyn_cast_or_null<ValueDecl>(
|
||||
getDocCommentProvidingDecl(D, /*AllowSerialized=*/true));
|
||||
|
||||
// if the decl is the same as the one for this symbol, we're not
|
||||
// inheriting docs, so return null. however, if this symbol is
|
||||
// a synthesized symbol, `VD` is actually the source symbol, and
|
||||
// a synthesized symbol, `D` is actually the source symbol, and
|
||||
// we should point to that one regardless.
|
||||
if (DocCommentProvidingDecl == VD && !SynthesizedBaseTypeDecl) {
|
||||
if (DocCommentProvidingDecl == D && !SynthesizedBaseTypeDecl) {
|
||||
return nullptr;
|
||||
} else {
|
||||
// otherwise, return whatever `getDocCommentProvidingDecl` returned.
|
||||
@@ -200,13 +225,13 @@ const ValueDecl *Symbol::getDeclInheritingDocs() const {
|
||||
|
||||
namespace {
|
||||
|
||||
StringRef getFileNameForDecl(const ValueDecl *VD) {
|
||||
if (!VD) return StringRef{};
|
||||
StringRef getFileNameForDecl(const Decl *D) {
|
||||
if (!D) return StringRef{};
|
||||
|
||||
SourceLoc Loc = VD->getLoc(/*SerializedOK=*/true);
|
||||
SourceLoc Loc = D->getLoc(/*SerializedOK=*/true);
|
||||
if (Loc.isInvalid()) return StringRef{};
|
||||
|
||||
SourceManager &SourceM = VD->getASTContext().SourceMgr;
|
||||
SourceManager &SourceM = D->getASTContext().SourceMgr;
|
||||
return SourceM.getDisplayNameForLoc(Loc);
|
||||
}
|
||||
|
||||
@@ -230,7 +255,7 @@ void serializeFileURI(llvm::json::OStream &OS, StringRef FileName) {
|
||||
}
|
||||
|
||||
void Symbol::serializeDocComment(llvm::json::OStream &OS) const {
|
||||
if (ClangNode ClangN = VD->getClangNode()) {
|
||||
if (ClangNode ClangN = D->getClangNode()) {
|
||||
if (!Graph->Walker.Options.IncludeClangDocs)
|
||||
return;
|
||||
|
||||
@@ -256,7 +281,7 @@ void Symbol::serializeDocComment(llvm::json::OStream &OS) const {
|
||||
StringRef FileName = getFileNameForDecl(ClangD);
|
||||
if (!FileName.empty())
|
||||
serializeFileURI(OS, FileName);
|
||||
if (const auto *ModuleD = VD->getModuleContext()) {
|
||||
if (const auto *ModuleD = D->getModuleContext()) {
|
||||
OS.attribute("module", ModuleD->getNameStr());
|
||||
}
|
||||
OS.attributeArray("lines", [&]() {
|
||||
@@ -271,12 +296,12 @@ void Symbol::serializeDocComment(llvm::json::OStream &OS) const {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto *DocCommentProvidingDecl = VD;
|
||||
const auto *DocCommentProvidingDecl = D;
|
||||
if (!Graph->Walker.Options.SkipInheritedDocs) {
|
||||
DocCommentProvidingDecl = dyn_cast_or_null<ValueDecl>(
|
||||
getDocCommentProvidingDecl(VD, /*AllowSerialized=*/true));
|
||||
getDocCommentProvidingDecl(D, /*AllowSerialized=*/true));
|
||||
if (!DocCommentProvidingDecl) {
|
||||
DocCommentProvidingDecl = VD;
|
||||
DocCommentProvidingDecl = D;
|
||||
}
|
||||
}
|
||||
auto RC = DocCommentProvidingDecl->getRawComment(/*SerializedOK=*/true);
|
||||
@@ -323,7 +348,7 @@ void Symbol::serializeDocComment(llvm::json::OStream &OS) const {
|
||||
}
|
||||
|
||||
void Symbol::serializeFunctionSignature(llvm::json::OStream &OS) const {
|
||||
if (const auto *FD = dyn_cast_or_null<FuncDecl>(VD)) {
|
||||
if (const auto *FD = dyn_cast_or_null<FuncDecl>(D)) {
|
||||
OS.attributeObject("functionSignature", [&](){
|
||||
|
||||
// Parameters
|
||||
@@ -392,12 +417,16 @@ static SubstitutionMap getSubMapForDecl(const ValueDecl *D, Type BaseType) {
|
||||
}
|
||||
|
||||
void Symbol::serializeSwiftGenericMixin(llvm::json::OStream &OS) const {
|
||||
|
||||
SubstitutionMap SubMap;
|
||||
if (BaseType)
|
||||
SubMap = getSubMapForDecl(VD, BaseType);
|
||||
const auto *VD = dyn_cast<ValueDecl>(D);
|
||||
|
||||
if (const auto *GC = VD->getAsGenericContext()) {
|
||||
if (VD && BaseType) {
|
||||
SubMap = getSubMapForDecl(VD, BaseType);
|
||||
} else {
|
||||
SubMap = {};
|
||||
}
|
||||
|
||||
if (const auto *GC = D->getAsGenericContext()) {
|
||||
if (const auto Generics = GC->getGenericSignature()) {
|
||||
|
||||
SmallVector<const GenericTypeParamType *, 4> FilteredParams;
|
||||
@@ -405,9 +434,9 @@ void Symbol::serializeSwiftGenericMixin(llvm::json::OStream &OS) const {
|
||||
filterGenericParams(Generics.getGenericParams(), FilteredParams,
|
||||
SubMap);
|
||||
|
||||
const auto *Self = dyn_cast<NominalTypeDecl>(VD);
|
||||
const auto *Self = dyn_cast<NominalTypeDecl>(D);
|
||||
if (!Self) {
|
||||
Self = VD->getDeclContext()->getSelfNominalTypeDecl();
|
||||
Self = D->getDeclContext()->getSelfNominalTypeDecl();
|
||||
}
|
||||
|
||||
filterGenericRequirements(Generics.getRequirements(), Self,
|
||||
@@ -439,9 +468,13 @@ void Symbol::serializeSwiftGenericMixin(llvm::json::OStream &OS) const {
|
||||
}
|
||||
|
||||
void Symbol::serializeSwiftExtensionMixin(llvm::json::OStream &OS) const {
|
||||
if (const auto *Extension
|
||||
= dyn_cast_or_null<ExtensionDecl>(VD->getDeclContext())) {
|
||||
::serialize(Extension, OS);
|
||||
if (const auto *ED = dyn_cast<ExtensionDecl>(D)) {
|
||||
::serialize(ED, OS);
|
||||
} else if (const auto *VD = dyn_cast<ValueDecl>(D)) {
|
||||
if (const auto *Extension =
|
||||
dyn_cast_or_null<ExtensionDecl>(VD->getDeclContext())) {
|
||||
::serialize(Extension, OS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -450,41 +483,48 @@ void Symbol::serializeDeclarationFragmentMixin(llvm::json::OStream &OS) const {
|
||||
}
|
||||
|
||||
void Symbol::serializeAccessLevelMixin(llvm::json::OStream &OS) const {
|
||||
OS.attribute("accessLevel", getAccessLevelSpelling(VD->getFormalAccess()));
|
||||
if (const auto *ED = dyn_cast<ExtensionDecl>(D)) {
|
||||
OS.attribute("accessLevel",
|
||||
getAccessLevelSpelling(getEffectiveAccessLevel(ED)));
|
||||
} else if (const auto *VD = dyn_cast<ValueDecl>(D)) {
|
||||
OS.attribute("accessLevel", getAccessLevelSpelling(VD->getFormalAccess()));
|
||||
}
|
||||
}
|
||||
|
||||
void Symbol::serializeMetadataMixin(llvm::json::OStream &OS) const {
|
||||
StringRef Category = documentationMetadataForDecl(VD);
|
||||
StringRef Category = documentationMetadataForDecl(D);
|
||||
if (!Category.empty())
|
||||
OS.attribute("metadata", Category);
|
||||
}
|
||||
|
||||
void Symbol::serializeLocationMixin(llvm::json::OStream &OS) const {
|
||||
if (ClangNode ClangN = VD->getClangNode()) {
|
||||
if (!Graph->Walker.Options.IncludeClangDocs)
|
||||
return;
|
||||
if (const auto *VD = dyn_cast<ValueDecl>(D)) {
|
||||
if (ClangNode ClangN = VD->getClangNode()) {
|
||||
if (!Graph->Walker.Options.IncludeClangDocs)
|
||||
return;
|
||||
|
||||
if (auto *ClangD = ClangN.getAsDecl()) {
|
||||
StringRef FileName = getFileNameForDecl(ClangD);
|
||||
if (!FileName.empty()) {
|
||||
OS.attributeObject("location", [&](){
|
||||
// TODO: We should use a common function to fill in the location
|
||||
// information for both cursor info and symbol graph gen, then also
|
||||
// include position here.
|
||||
serializeFileURI(OS, FileName);
|
||||
});
|
||||
if (auto *ClangD = ClangN.getAsDecl()) {
|
||||
StringRef FileName = getFileNameForDecl(ClangD);
|
||||
if (!FileName.empty()) {
|
||||
OS.attributeObject("location", [&](){
|
||||
// TODO: We should use a common function to fill in the location
|
||||
// information for both cursor info and symbol graph gen, then also
|
||||
// include position here.
|
||||
serializeFileURI(OS, FileName);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
auto FileName = getFileNameForDecl(VD);
|
||||
|
||||
auto FileName = getFileNameForDecl(D);
|
||||
if (FileName.empty()) {
|
||||
return;
|
||||
}
|
||||
// TODO: Fold serializePosition into serializeFileURI so we don't need to load Loc twice?
|
||||
auto Loc = VD->getLoc(/*SerializedOK=*/true);
|
||||
auto Loc = D->getLoc(/*SerializedOK=*/true);
|
||||
if (Loc.isInvalid()) {
|
||||
return;
|
||||
}
|
||||
@@ -566,7 +606,7 @@ llvm::StringMap<Availability> &Availabilities) {
|
||||
|
||||
void Symbol::serializeAvailabilityMixin(llvm::json::OStream &OS) const {
|
||||
llvm::StringMap<Availability> Availabilities;
|
||||
getInheritedAvailabilities(VD, Availabilities);
|
||||
getInheritedAvailabilities(D, Availabilities);
|
||||
|
||||
if (Availabilities.empty()) {
|
||||
return;
|
||||
@@ -580,7 +620,7 @@ void Symbol::serializeAvailabilityMixin(llvm::json::OStream &OS) const {
|
||||
}
|
||||
|
||||
void Symbol::serializeSPIMixin(llvm::json::OStream &OS) const {
|
||||
if (VD->isSPI())
|
||||
if (D->isSPI())
|
||||
OS.attribute("spi", true);
|
||||
}
|
||||
|
||||
@@ -605,52 +645,78 @@ void Symbol::serialize(llvm::json::OStream &OS) const {
|
||||
});
|
||||
}
|
||||
|
||||
swift::DeclName Symbol::getName(const Decl *D) const {
|
||||
if (const auto *ED = dyn_cast<ExtensionDecl>(D)) {
|
||||
return ED->getExtendedNominal()->getName();
|
||||
} else {
|
||||
return cast<ValueDecl>(D)->getName();
|
||||
}
|
||||
}
|
||||
|
||||
const ValueDecl *Symbol::getSymbolDecl() const {
|
||||
if (const auto *ED = dyn_cast<ExtensionDecl>(D)) {
|
||||
return ED->getExtendedNominal();
|
||||
} else {
|
||||
return cast<ValueDecl>(D);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Symbol::getPathComponents(SmallVectorImpl<PathComponent> &Components) const {
|
||||
const ValueDecl *Decl = nullptr;
|
||||
if (const auto *ED = dyn_cast<ExtensionDecl>(D)) {
|
||||
Decl = ED->getExtendedNominal();
|
||||
} else if (const auto *VD = dyn_cast<ValueDecl>(D)) {
|
||||
Decl = VD;
|
||||
}
|
||||
|
||||
// Note: this is also used for sourcekit's cursor-info request, so can be
|
||||
// called on local symbols too. For such symbols, the path contains all parent
|
||||
// decl contexts that are currently representable in the symbol graph,
|
||||
// skipping over the rest (e.g. containing closures and accessors).
|
||||
|
||||
auto collectPathComponents = [&](const ValueDecl *Decl,
|
||||
SmallVectorImpl<PathComponent> &DeclComponents) {
|
||||
// Collect the spellings, kinds, and decls of the fully qualified identifier
|
||||
// components.
|
||||
while (Decl && !isa<ModuleDecl>(Decl)) {
|
||||
SmallString<32> Scratch;
|
||||
Decl->getName().getString(Scratch);
|
||||
if (supportsKind(Decl->getKind()))
|
||||
DeclComponents.push_back({Scratch, getKind(Decl).first, Decl});
|
||||
auto collectPathComponents =
|
||||
[&](const ValueDecl *Decl,
|
||||
SmallVectorImpl<PathComponent> &DeclComponents) {
|
||||
// Collect the spellings, kinds, and decls of the fully qualified
|
||||
// identifier components.
|
||||
while (Decl && !isa<ModuleDecl>(Decl)) {
|
||||
SmallString<32> Scratch;
|
||||
getName(Decl).getString(Scratch);
|
||||
|
||||
// Find the next parent.
|
||||
auto *DC = Decl->getDeclContext();
|
||||
while (DC && DC->getContextKind() == DeclContextKind::AbstractClosureExpr)
|
||||
DC = DC->getParent();
|
||||
if (DC) {
|
||||
if (const auto *Nominal = DC->getSelfNominalTypeDecl()) {
|
||||
Decl = Nominal;
|
||||
} else {
|
||||
Decl = dyn_cast_or_null<ValueDecl>(DC->getAsDecl());
|
||||
if (supportsKind(Decl->getKind()))
|
||||
DeclComponents.push_back({Scratch, getKind(Decl).first, Decl});
|
||||
|
||||
// Find the next parent.
|
||||
auto *DC = Decl->getDeclContext();
|
||||
while (DC &&
|
||||
DC->getContextKind() == DeclContextKind::AbstractClosureExpr)
|
||||
DC = DC->getParent();
|
||||
if (DC) {
|
||||
if (const auto *Nominal = DC->getSelfNominalTypeDecl()) {
|
||||
Decl = Nominal;
|
||||
} else {
|
||||
Decl = dyn_cast_or_null<ValueDecl>(DC->getAsDecl());
|
||||
}
|
||||
} else {
|
||||
Decl = nullptr;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Decl = nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
if (const auto BaseTypeDecl = getSynthesizedBaseTypeDecl()) {
|
||||
// This is a synthesized member of some base type declaration, actually
|
||||
// existing on another type, such as a default implementation of
|
||||
// a protocol. Build a path as if it were defined in the base type.
|
||||
SmallString<32> LastPathComponent;
|
||||
VD->getName().getString(LastPathComponent);
|
||||
if (supportsKind(VD->getKind()))
|
||||
Components.push_back({LastPathComponent, getKind(VD).first, VD});
|
||||
getName(Decl).getString(LastPathComponent);
|
||||
if (supportsKind(Decl->getKind()))
|
||||
Components.push_back({LastPathComponent, getKind(Decl).first, Decl});
|
||||
collectPathComponents(BaseTypeDecl, Components);
|
||||
} else {
|
||||
// Otherwise, this is just a normal declaration, so we can build
|
||||
// its path normally.
|
||||
collectPathComponents(VD, Components);
|
||||
collectPathComponents(Decl, Components);
|
||||
}
|
||||
|
||||
// The list is leaf-to-root, but we want root-to-leaf, so reverse it.
|
||||
@@ -697,7 +763,7 @@ void Symbol::printPath(llvm::raw_ostream &OS) const {
|
||||
|
||||
void Symbol::getUSR(SmallVectorImpl<char> &USR) const {
|
||||
llvm::raw_svector_ostream OS(USR);
|
||||
ide::printDeclUSR(VD, OS);
|
||||
ide::printDeclUSR(D, OS);
|
||||
if (SynthesizedBaseTypeDecl) {
|
||||
OS << "::SYNTHESIZED::";
|
||||
ide::printDeclUSR(SynthesizedBaseTypeDecl, OS);
|
||||
@@ -717,9 +783,30 @@ bool Symbol::supportsKind(DeclKind Kind) {
|
||||
case DeclKind::Var: LLVM_FALLTHROUGH;
|
||||
case DeclKind::Subscript: LLVM_FALLTHROUGH;
|
||||
case DeclKind::TypeAlias: LLVM_FALLTHROUGH;
|
||||
case DeclKind::AssociatedType:
|
||||
case DeclKind::AssociatedType: LLVM_FALLTHROUGH;
|
||||
case DeclKind::Extension:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
AccessLevel Symbol::getEffectiveAccessLevel(const ExtensionDecl *ED) {
|
||||
AccessLevel maxPropertyAL = AccessLevel::Private;
|
||||
for (auto Member : ED->getMembers()) {
|
||||
if (const auto *VMember = dyn_cast<ValueDecl>(Member)) {
|
||||
maxPropertyAL = std::max(maxPropertyAL, VMember->getFormalAccess());
|
||||
}
|
||||
}
|
||||
|
||||
AccessLevel maxInheritedAL = AccessLevel::Private;
|
||||
for (auto Inherited : ED->getInherited()) {
|
||||
if (const auto *Proto = dyn_cast_or_null<ProtocolDecl>(
|
||||
Inherited.getType()->getAnyNominal())) {
|
||||
maxInheritedAL = std::max(maxInheritedAL, Proto->getFormalAccess());
|
||||
}
|
||||
}
|
||||
|
||||
return std::min(ED->getExtendedNominal()->getFormalAccess(),
|
||||
std::max(maxPropertyAL, maxInheritedAL));
|
||||
}
|
||||
|
||||
@@ -32,11 +32,16 @@ struct SymbolGraph;
|
||||
class Symbol {
|
||||
/// The symbol graph in which this symbol resides.
|
||||
SymbolGraph *Graph;
|
||||
const ValueDecl *VD;
|
||||
/// Either a ValueDecl* or ExtensionDecl*.
|
||||
const Decl *D;
|
||||
Type BaseType;
|
||||
const NominalTypeDecl *SynthesizedBaseTypeDecl;
|
||||
|
||||
std::pair<StringRef, StringRef> getKind(const ValueDecl *VD) const;
|
||||
Symbol(SymbolGraph *Graph, const ValueDecl *VD, const ExtensionDecl *ED,
|
||||
const NominalTypeDecl *SynthesizedBaseTypeDecl,
|
||||
Type BaseTypeForSubstitution = Type());
|
||||
|
||||
swift::DeclName getName(const Decl *D) const;
|
||||
|
||||
void serializeKind(StringRef Identifier, StringRef DisplayName,
|
||||
llvm::json::OStream &OS) const;
|
||||
@@ -81,6 +86,10 @@ class Symbol {
|
||||
void serializeSPIMixin(llvm::json::OStream &OS) const;
|
||||
|
||||
public:
|
||||
Symbol(SymbolGraph *Graph, const ExtensionDecl *ED,
|
||||
const NominalTypeDecl *SynthesizedBaseTypeDecl,
|
||||
Type BaseTypeForSubstitution = Type());
|
||||
|
||||
Symbol(SymbolGraph *Graph, const ValueDecl *VD,
|
||||
const NominalTypeDecl *SynthesizedBaseTypeDecl,
|
||||
Type BaseTypeForSubstitution = Type());
|
||||
@@ -91,9 +100,9 @@ public:
|
||||
return Graph;
|
||||
}
|
||||
|
||||
const ValueDecl *getSymbolDecl() const {
|
||||
return VD;
|
||||
}
|
||||
const ValueDecl *getSymbolDecl() const;
|
||||
|
||||
const Decl *getLocalSymbolDecl() const { return D; }
|
||||
|
||||
Type getBaseType() const {
|
||||
return BaseType;
|
||||
@@ -122,6 +131,26 @@ public:
|
||||
const ValueDecl *getDeclInheritingDocs() const;
|
||||
|
||||
static bool supportsKind(DeclKind Kind);
|
||||
|
||||
/// Determines the effective access level of the given extension.
|
||||
///
|
||||
/// The effective access level is defined as the minimum of:
|
||||
/// - the maximum access level of a property or conformance
|
||||
/// - the access level of the extended nominal
|
||||
///
|
||||
/// The effective access level is defined this way so that the extension
|
||||
/// symbol's access level equals the highest access level of any of the
|
||||
/// symbols the extension symbol has a relationship to.
|
||||
///
|
||||
/// This function is not logically equivalent to
|
||||
/// `ExtensionDecl.getMaxAccessLevel()`, which computes the maximum access
|
||||
/// level any of the `ExtensionDecl`'s members
|
||||
/// **can** have based on the extended type and types used in constraints.
|
||||
static AccessLevel getEffectiveAccessLevel(const ExtensionDecl *ED);
|
||||
|
||||
/// Determines the kind of Symbol the given declaration produces and
|
||||
/// returns the respective symbol kind identifier and kind name.
|
||||
static std::pair<StringRef, StringRef> getKind(const Decl *D);
|
||||
};
|
||||
|
||||
} // end namespace symbolgraphgen
|
||||
@@ -151,18 +180,19 @@ template <> struct DenseMapInfo<Symbol> {
|
||||
static unsigned getHashValue(const Symbol S) {
|
||||
unsigned H = 0;
|
||||
H ^= DenseMapInfo<SymbolGraph *>::getHashValue(S.getGraph());
|
||||
H ^= DenseMapInfo<const swift::ValueDecl *>::getHashValue(S.getSymbolDecl());
|
||||
H ^=
|
||||
DenseMapInfo<const swift::Decl *>::getHashValue(S.getLocalSymbolDecl());
|
||||
H ^= DenseMapInfo<const swift::NominalTypeDecl *>::getHashValue(S.getSynthesizedBaseTypeDecl());
|
||||
H ^= DenseMapInfo<swift::Type>::getHashValue(S.getBaseType());
|
||||
return H;
|
||||
}
|
||||
static bool isEqual(const Symbol LHS, const Symbol RHS) {
|
||||
return LHS.getGraph() == RHS.getGraph() &&
|
||||
LHS.getSymbolDecl() == RHS.getSymbolDecl() &&
|
||||
LHS.getSynthesizedBaseTypeDecl() ==
|
||||
RHS.getSynthesizedBaseTypeDecl() &&
|
||||
DenseMapInfo<swift::Type>::
|
||||
isEqual(LHS.getBaseType(), RHS.getBaseType());
|
||||
LHS.getLocalSymbolDecl() == RHS.getLocalSymbolDecl() &&
|
||||
LHS.getSynthesizedBaseTypeDecl() ==
|
||||
RHS.getSynthesizedBaseTypeDecl() &&
|
||||
DenseMapInfo<swift::Type>::isEqual(LHS.getBaseType(),
|
||||
RHS.getBaseType());
|
||||
}
|
||||
};
|
||||
} // end namespace llvm
|
||||
|
||||
@@ -29,26 +29,21 @@
|
||||
using namespace swift;
|
||||
using namespace symbolgraphgen;
|
||||
|
||||
SymbolGraph::SymbolGraph(SymbolGraphASTWalker &Walker,
|
||||
ModuleDecl &M,
|
||||
SymbolGraph::SymbolGraph(SymbolGraphASTWalker &Walker, ModuleDecl &M,
|
||||
Optional<ModuleDecl *> ExtendedModule,
|
||||
markup::MarkupContext &Ctx,
|
||||
Optional<llvm::VersionTuple> ModuleVersion,
|
||||
bool IsForSingleNode)
|
||||
: Walker(Walker),
|
||||
M(M),
|
||||
ExtendedModule(ExtendedModule),
|
||||
Ctx(Ctx),
|
||||
ModuleVersion(ModuleVersion),
|
||||
IsForSingleNode(IsForSingleNode) {
|
||||
if (auto *DM = M.getDeclaringModuleIfCrossImportOverlay()) {
|
||||
DeclaringModule = DM;
|
||||
SmallVector<Identifier, 1> Bystanders;
|
||||
if (M.getRequiredBystandersIfCrossImportOverlay(DM, Bystanders)) {
|
||||
BystanderModules = Bystanders;
|
||||
}
|
||||
: Walker(Walker), M(M), ExtendedModule(ExtendedModule), Ctx(Ctx),
|
||||
ModuleVersion(ModuleVersion), IsForSingleNode(IsForSingleNode) {
|
||||
if (auto *DM = M.getDeclaringModuleIfCrossImportOverlay()) {
|
||||
DeclaringModule = DM;
|
||||
SmallVector<Identifier, 1> Bystanders;
|
||||
if (M.getRequiredBystandersIfCrossImportOverlay(DM, Bystanders)) {
|
||||
BystanderModules = Bystanders;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Utilities
|
||||
|
||||
@@ -224,7 +219,7 @@ void SymbolGraph::recordEdge(Symbol Source,
|
||||
}
|
||||
|
||||
void SymbolGraph::recordMemberRelationship(Symbol S) {
|
||||
const auto *DC = S.getSymbolDecl()->getDeclContext();
|
||||
const auto *DC = S.getLocalSymbolDecl()->getDeclContext();
|
||||
switch (DC->getContextKind()) {
|
||||
case DeclContextKind::GenericTypeDecl:
|
||||
case DeclContextKind::ExtensionDecl:
|
||||
@@ -242,12 +237,25 @@ void SymbolGraph::recordMemberRelationship(Symbol S) {
|
||||
if (isRequirementOrDefaultImplementation(S.getSymbolDecl())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (DC->getSelfNominalTypeDecl() == nullptr) {
|
||||
// If we couldn't look up the type the member is declared on (e.g.
|
||||
// because the member is declared in an extension whose extended type
|
||||
// doesn't exist), don't record a memberOf relationship.
|
||||
return;
|
||||
}
|
||||
|
||||
// If this is an extension to an external type, we use the extension
|
||||
// symbol itself as the target.
|
||||
if (auto const *Extension =
|
||||
dyn_cast_or_null<ExtensionDecl>(DC->getAsDecl())) {
|
||||
|
||||
if (this->Walker.shouldBeRecordedAsExtension(Extension)) {
|
||||
return recordEdge(S, Symbol(this, Extension, nullptr),
|
||||
RelationshipKind::MemberOf());
|
||||
}
|
||||
}
|
||||
|
||||
return recordEdge(S,
|
||||
Symbol(this, DC->getSelfNominalTypeDecl(), nullptr),
|
||||
RelationshipKind::MemberOf());
|
||||
@@ -289,11 +297,11 @@ void SymbolGraph::recordConformanceSynthesizedMemberRelationships(Symbol S) {
|
||||
if (!Walker.Options.EmitSynthesizedMembers) {
|
||||
return;
|
||||
}
|
||||
const auto VD = S.getSymbolDecl();
|
||||
const auto D = S.getLocalSymbolDecl();
|
||||
const NominalTypeDecl *OwningNominal = nullptr;
|
||||
if (const auto *ThisNominal = dyn_cast<NominalTypeDecl>(VD)) {
|
||||
if (const auto *ThisNominal = dyn_cast<NominalTypeDecl>(D)) {
|
||||
OwningNominal = ThisNominal;
|
||||
} else if (const auto *Extension = dyn_cast<ExtensionDecl>(VD)) {
|
||||
} else if (const auto *Extension = dyn_cast<ExtensionDecl>(D)) {
|
||||
if (const auto *ExtendedNominal = Extension->getExtendedNominal()) {
|
||||
if (!ExtendedNominal->getModuleContext()->getNameStr()
|
||||
.equals(M.getNameStr())) {
|
||||
@@ -328,6 +336,12 @@ void SymbolGraph::recordConformanceSynthesizedMemberRelationships(Symbol S) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If D is not the OwningNominal, it is an ExtensionDecl. In that case
|
||||
// we only want to get members that were enabled by this exact extension.
|
||||
if (D != OwningNominal && Info.EnablingExt != D) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const auto ExtensionMember : Info.Ext->getMembers()) {
|
||||
if (const auto SynthMember = dyn_cast<ValueDecl>(ExtensionMember)) {
|
||||
if (SynthMember->isObjC()) {
|
||||
@@ -352,11 +366,10 @@ void SymbolGraph::recordConformanceSynthesizedMemberRelationships(Symbol S) {
|
||||
auto ExtendedSG = Walker.getModuleSymbolGraph(OwningNominal);
|
||||
|
||||
Symbol Source(this, SynthMember, OwningNominal);
|
||||
Symbol Target(this, OwningNominal, nullptr);
|
||||
|
||||
ExtendedSG->Nodes.insert(Source);
|
||||
|
||||
ExtendedSG->recordEdge(Source, Target, RelationshipKind::MemberOf());
|
||||
ExtendedSG->recordEdge(Source, S, RelationshipKind::MemberOf());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -447,27 +460,24 @@ void SymbolGraph::recordOptionalRequirementRelationships(Symbol S) {
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SymbolGraph::recordConformanceRelationships(Symbol S) {
|
||||
const auto VD = S.getSymbolDecl();
|
||||
if (const auto *NTD = dyn_cast<NominalTypeDecl>(VD)) {
|
||||
void SymbolGraph::recordConformanceRelationships(Symbol S) {
|
||||
const auto D = S.getLocalSymbolDecl();
|
||||
if (const auto *NTD = dyn_cast<NominalTypeDecl>(D)) {
|
||||
if (auto *PD = dyn_cast<ProtocolDecl>(NTD)) {
|
||||
PD->walkInheritedProtocols([&](ProtocolDecl *inherited) {
|
||||
if (inherited != PD) {
|
||||
recordEdge(Symbol(this, VD, nullptr),
|
||||
Symbol(this, inherited, nullptr),
|
||||
RelationshipKind::ConformsTo(),
|
||||
nullptr);
|
||||
recordEdge(S, Symbol(this, inherited, nullptr),
|
||||
RelationshipKind::ConformsTo(), nullptr);
|
||||
}
|
||||
|
||||
return TypeWalker::Action::Continue;
|
||||
});
|
||||
} else {
|
||||
for (const auto *Conformance : NTD->getAllConformances()) {
|
||||
recordEdge(Symbol(this, VD, nullptr),
|
||||
Symbol(this, Conformance->getProtocol(), nullptr),
|
||||
RelationshipKind::ConformsTo(),
|
||||
dyn_cast_or_null<ExtensionDecl>(Conformance->getDeclContext()));
|
||||
recordEdge(
|
||||
S, Symbol(this, Conformance->getProtocol(), nullptr),
|
||||
RelationshipKind::ConformsTo(),
|
||||
dyn_cast_or_null<ExtensionDecl>(Conformance->getDeclContext()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -546,7 +556,7 @@ SymbolGraph::serializeDeclarationFragments(StringRef Key,
|
||||
Options.setBaseType(S.getBaseType());
|
||||
Options.PrintAsMember = true;
|
||||
}
|
||||
S.getSymbolDecl()->print(Printer, Options);
|
||||
S.getLocalSymbolDecl()->print(Printer, Options);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -565,7 +575,7 @@ SymbolGraph::serializeSubheadingDeclarationFragments(StringRef Key,
|
||||
llvm::json::OStream &OS) {
|
||||
DeclarationFragmentPrinter Printer(this, OS, Key);
|
||||
|
||||
if (const auto *TD = dyn_cast<GenericTypeDecl>(S.getSymbolDecl())) {
|
||||
if (const auto *TD = dyn_cast<GenericTypeDecl>(S.getLocalSymbolDecl())) {
|
||||
Printer.printAbridgedType(TD, /*PrintKeyword=*/true);
|
||||
} else {
|
||||
auto Options = getSubHeadingDeclarationFragmentsPrintOptions();
|
||||
@@ -573,7 +583,7 @@ SymbolGraph::serializeSubheadingDeclarationFragments(StringRef Key,
|
||||
Options.setBaseType(S.getBaseType());
|
||||
Options.PrintAsMember = true;
|
||||
}
|
||||
S.getSymbolDecl()->print(Printer, Options);
|
||||
S.getLocalSymbolDecl()->print(Printer, Options);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -637,7 +647,9 @@ bool SymbolGraph::isImplicitlyPrivate(const Decl *D,
|
||||
|
||||
if (const auto *Extension = dyn_cast<ExtensionDecl>(D)) {
|
||||
if (const auto *Nominal = Extension->getExtendedNominal()) {
|
||||
return isImplicitlyPrivate(Nominal, IgnoreContext);
|
||||
return isImplicitlyPrivate(Nominal, IgnoreContext) ||
|
||||
Symbol::getEffectiveAccessLevel(Extension) <
|
||||
Walker.Options.MinimumAccessLevel;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -79,10 +79,8 @@ struct SymbolGraph {
|
||||
*/
|
||||
bool IsForSingleNode;
|
||||
|
||||
SymbolGraph(SymbolGraphASTWalker &Walker,
|
||||
ModuleDecl &M,
|
||||
Optional<ModuleDecl *> ExtendedModule,
|
||||
markup::MarkupContext &Ctx,
|
||||
SymbolGraph(SymbolGraphASTWalker &Walker, ModuleDecl &M,
|
||||
Optional<ModuleDecl *> ExtendedModule, markup::MarkupContext &Ctx,
|
||||
Optional<llvm::VersionTuple> ModuleVersion = None,
|
||||
bool IsForSingleNode = false);
|
||||
|
||||
|
||||
@@ -33,15 +33,14 @@ bool areModulesEqual(const ModuleDecl *lhs, const ModuleDecl *rhs) {
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
SymbolGraphASTWalker::SymbolGraphASTWalker(ModuleDecl &M,
|
||||
const SmallPtrSet<ModuleDecl *, 4> ExportedImportedModules,
|
||||
const llvm::SmallDenseMap<ModuleDecl *, SmallPtrSet<Decl *, 4>, 4> QualifiedExportedImports,
|
||||
const SymbolGraphOptions &Options)
|
||||
: Options(Options),
|
||||
M(M),
|
||||
ExportedImportedModules(ExportedImportedModules),
|
||||
QualifiedExportedImports(QualifiedExportedImports),
|
||||
MainGraph(*this, M, None, Ctx) {}
|
||||
SymbolGraphASTWalker::SymbolGraphASTWalker(
|
||||
ModuleDecl &M, const SmallPtrSet<ModuleDecl *, 4> ExportedImportedModules,
|
||||
const llvm::SmallDenseMap<ModuleDecl *, SmallPtrSet<Decl *, 4>, 4>
|
||||
QualifiedExportedImports,
|
||||
const SymbolGraphOptions &Options)
|
||||
: Options(Options), M(M), ExportedImportedModules(ExportedImportedModules),
|
||||
QualifiedExportedImports(QualifiedExportedImports),
|
||||
MainGraph(*this, M, None, Ctx) {}
|
||||
|
||||
/// Get a "sub" symbol graph for the parent module of a type that
|
||||
/// the main module `M` is extending.
|
||||
@@ -88,11 +87,9 @@ SymbolGraph *SymbolGraphASTWalker::getModuleSymbolGraph(const Decl *D) {
|
||||
if (Found != ExtendedModuleGraphs.end()) {
|
||||
return Found->getValue();
|
||||
}
|
||||
auto *Memory = Ctx.allocate(sizeof(SymbolGraph), alignof(SymbolGraph));
|
||||
auto *SG = new (Memory) SymbolGraph(*this,
|
||||
MainGraph.M,
|
||||
Optional<ModuleDecl *>(M),
|
||||
Ctx);
|
||||
auto *Memory = Ctx.allocate(sizeof(SymbolGraph), alignof(SymbolGraph));
|
||||
auto *SG = new (Memory)
|
||||
SymbolGraph(*this, MainGraph.M, Optional<ModuleDecl *>(M), Ctx);
|
||||
|
||||
ExtendedModuleGraphs.insert({M->getNameStr(), SG});
|
||||
return SG;
|
||||
@@ -117,29 +114,29 @@ bool isUnavailableOrObsoleted(const Decl *D) {
|
||||
} // end anonymous namespace
|
||||
|
||||
bool SymbolGraphASTWalker::walkToDeclPre(Decl *D, CharSourceRange Range) {
|
||||
if (isUnavailableOrObsoleted(D)) {
|
||||
return false;
|
||||
}
|
||||
if (isUnavailableOrObsoleted(D)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (D->getKind()) {
|
||||
// We'll record nodes for the following kinds of declarations.
|
||||
case swift::DeclKind::Class:
|
||||
case swift::DeclKind::Struct:
|
||||
case swift::DeclKind::Enum:
|
||||
case swift::DeclKind::EnumElement:
|
||||
case swift::DeclKind::Protocol:
|
||||
case swift::DeclKind::Constructor:
|
||||
case swift::DeclKind::Func:
|
||||
case swift::DeclKind::Var:
|
||||
case swift::DeclKind::Subscript:
|
||||
case swift::DeclKind::TypeAlias:
|
||||
case swift::DeclKind::AssociatedType:
|
||||
case swift::DeclKind::Extension:
|
||||
break;
|
||||
|
||||
// We'll descend into everything else.
|
||||
default:
|
||||
return true;
|
||||
switch (D->getKind()) {
|
||||
// We'll record nodes for the following kinds of declarations.
|
||||
case swift::DeclKind::Class:
|
||||
case swift::DeclKind::Struct:
|
||||
case swift::DeclKind::Enum:
|
||||
case swift::DeclKind::EnumElement:
|
||||
case swift::DeclKind::Protocol:
|
||||
case swift::DeclKind::Constructor:
|
||||
case swift::DeclKind::Func:
|
||||
case swift::DeclKind::Var:
|
||||
case swift::DeclKind::Subscript:
|
||||
case swift::DeclKind::TypeAlias:
|
||||
case swift::DeclKind::AssociatedType:
|
||||
case swift::DeclKind::Extension:
|
||||
break;
|
||||
|
||||
// We'll descend into everything else.
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
||||
auto SG = getModuleSymbolGraph(D);
|
||||
@@ -158,25 +155,83 @@ bool SymbolGraphASTWalker::walkToDeclPre(Decl *D, CharSourceRange Range) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We only treat extensions to external types as extensions. Extensions to
|
||||
// local types are directly associated with the extended nominal.
|
||||
auto const shouldBeRecordedAsExtension =
|
||||
this->shouldBeRecordedAsExtension(Extension);
|
||||
|
||||
Symbol Source = shouldBeRecordedAsExtension
|
||||
? Symbol(ExtendedSG, Extension, nullptr)
|
||||
: Symbol(ExtendedSG, ExtendedNominal, nullptr);
|
||||
// The extended nominal is recorded elsewhere for local types.
|
||||
if (shouldBeRecordedAsExtension) {
|
||||
ExtendedSG->recordNode(Source);
|
||||
|
||||
// Next to the extension symbol itself, we also introduce a relationship
|
||||
// between the extension symbol and the extended nominal.
|
||||
ExtendedSG->recordEdge(Source,
|
||||
Symbol(ExtendedSG, ExtendedNominal, nullptr),
|
||||
RelationshipKind::ExtensionTo());
|
||||
}
|
||||
|
||||
// If there are some protocol conformances on this extension, we'll
|
||||
// grab them for some new conformsTo relationships.
|
||||
if (!Extension->getInherited().empty()) {
|
||||
// We want to add conformsTo relationships for all protocols implicitly
|
||||
// implied by those explicitly stated on the extension.
|
||||
//
|
||||
// Thus, we have to expand two syntactic constructs:
|
||||
// * `protocol A: B, C { ... }` declarations, where those that still have
|
||||
// to be expanded are stored in `UnexpandedProtocols`
|
||||
// that still have to be expanded
|
||||
// * `typealias A = B & C` declarations, which are directly expanded to
|
||||
// unexpanded protocols in `HandleProtocolOrComposition`
|
||||
//
|
||||
// The expansion adds the base protocol to `Protocols` and calls
|
||||
// `HandleProtocolOrComposition` for the implied protocols. This process
|
||||
// continues until there is nothing left to expand (`UnexpandedProtocols`
|
||||
// is empty), because `HandleProtocolOrComposition` didn't add any new
|
||||
// unexpanded protocols. At that point, all direct and indirect
|
||||
// conformances are stored in `Protocols`.
|
||||
|
||||
// The symbol graph to use to record these relationships.
|
||||
SmallVector<const ProtocolDecl *, 4> Protocols;
|
||||
SmallVector<const ProtocolCompositionType *, 4> UnexpandedCompositions;
|
||||
SmallVector<const ProtocolDecl *, 4> UnexpandedProtocols;
|
||||
|
||||
// Unwrap `UnexpandedCompositions` and add all unexpanded protocols to the
|
||||
// `UnexpandedProtocols` list for expansion.
|
||||
auto HandleProtocolOrComposition = [&](Type Ty) {
|
||||
if (const auto *Proto =
|
||||
dyn_cast_or_null<ProtocolDecl>(Ty->getAnyNominal())) {
|
||||
Protocols.push_back(Proto);
|
||||
} else if (const auto *Comp = Ty->getAs<ProtocolCompositionType>()) {
|
||||
dyn_cast_or_null<ProtocolDecl>(Ty->getAnyNominal())) {
|
||||
UnexpandedProtocols.push_back(Proto);
|
||||
return;
|
||||
}
|
||||
|
||||
SmallVector<const ProtocolCompositionType *, 4> UnexpandedCompositions;
|
||||
|
||||
if (const auto *Comp = Ty->getAs<ProtocolCompositionType>()) {
|
||||
UnexpandedCompositions.push_back(Comp);
|
||||
} else {
|
||||
abort();
|
||||
llvm_unreachable("Expected ProtocolDecl or ProtocolCompositionType");
|
||||
}
|
||||
|
||||
while (const auto *Comp = UnexpandedCompositions.pop_back_val()) {
|
||||
for (const auto &Member : Comp->getMembers()) {
|
||||
if (const auto *Proto =
|
||||
dyn_cast_or_null<ProtocolDecl>(Member->getAnyNominal())) {
|
||||
Protocols.push_back(Proto);
|
||||
UnexpandedProtocols.push_back(Proto);
|
||||
} else if (const auto *Comp =
|
||||
Member->getAs<ProtocolCompositionType>()) {
|
||||
UnexpandedCompositions.push_back(Comp);
|
||||
} else {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Start the process with the conformances stated
|
||||
// explicitly on the extension.
|
||||
for (const auto &InheritedLoc : Extension->getInherited()) {
|
||||
auto InheritedTy = InheritedLoc.getType();
|
||||
if (!InheritedTy) {
|
||||
@@ -185,30 +240,31 @@ bool SymbolGraphASTWalker::walkToDeclPre(Decl *D, CharSourceRange Range) {
|
||||
HandleProtocolOrComposition(InheritedTy);
|
||||
}
|
||||
|
||||
while (!UnexpandedCompositions.empty()) {
|
||||
const auto *Comp = UnexpandedCompositions.pop_back_val();
|
||||
for (const auto &Member : Comp->getMembers()) {
|
||||
HandleProtocolOrComposition(Member);
|
||||
// "Recursively" expand the unexpanded list and populate
|
||||
// the expanded `Protocols` list (in an iterative manner).
|
||||
while (!UnexpandedProtocols.empty()) {
|
||||
const auto *Proto = UnexpandedProtocols.pop_back_val();
|
||||
for (const auto &InheritedEntry : Proto->getInherited()) {
|
||||
auto InheritedTy = InheritedEntry.getType();
|
||||
if (!InheritedTy) {
|
||||
continue;
|
||||
}
|
||||
HandleProtocolOrComposition(InheritedTy);
|
||||
}
|
||||
Protocols.push_back(Proto);
|
||||
}
|
||||
|
||||
Symbol Source(ExtendedSG, ExtendedNominal, nullptr);
|
||||
|
||||
// Record the expanded list of protocols.
|
||||
for (const auto *Proto : Protocols) {
|
||||
Symbol Target(&MainGraph, Proto, nullptr);
|
||||
ExtendedSG->recordEdge(Source, Target, RelationshipKind::ConformsTo(),
|
||||
Extension);
|
||||
}
|
||||
|
||||
// While we won't record this node per se, or all of the other kinds of
|
||||
// relationships, we might establish some synthesized members because we
|
||||
// We also might establish some synthesized members because we
|
||||
// extended an external type.
|
||||
if (ExtendedNominal->getModuleContext() != &M) {
|
||||
ExtendedSG->recordConformanceSynthesizedMemberRelationships({
|
||||
ExtendedSG,
|
||||
ExtendedNominal,
|
||||
nullptr
|
||||
});
|
||||
ExtendedSG->recordConformanceSynthesizedMemberRelationships(Source);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,3 +366,9 @@ bool SymbolGraphASTWalker::isExportedImportedModule(const ModuleDecl *M) const {
|
||||
bool SymbolGraphASTWalker::isOurModule(const ModuleDecl *M) const {
|
||||
return areModulesEqual(M, &this->M) || isExportedImportedModule(M);
|
||||
}
|
||||
|
||||
bool SymbolGraphASTWalker::shouldBeRecordedAsExtension(
|
||||
const ExtensionDecl *ED) const {
|
||||
return Options.EmitExtensionBlockSymbols &&
|
||||
!areModulesEqual(ED->getModuleContext(), ED->getExtendedNominal()->getModuleContext());
|
||||
}
|
||||
|
||||
@@ -113,6 +113,12 @@ struct SymbolGraphASTWalker : public SourceEntityWalker {
|
||||
|
||||
/// Returns whether the given module is the main module, or is an `@_exported import` module.
|
||||
virtual bool isOurModule(const ModuleDecl *M) const;
|
||||
|
||||
public:
|
||||
/// Returns whether the given ExtensionDecl is to be recorded as an extra
|
||||
/// extension block symbol, or if its members should be directly associated
|
||||
/// with its extended nominal.
|
||||
virtual bool shouldBeRecordedAsExtension(const ExtensionDecl *ED) const;
|
||||
};
|
||||
|
||||
} // end namespace symbolgraphgen
|
||||
|
||||
23
test/SymbolGraph/ClangImporter/ClangExtensions.swift
Normal file
23
test/SymbolGraph/ClangImporter/ClangExtensions.swift
Normal file
@@ -0,0 +1,23 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: cp -r %S/Inputs/EmitWhileBuilding/EmitWhileBuilding.framework %t
|
||||
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -enable-objc-interop -emit-module-path %t/EmitWhileBuilding.framework/Modules/EmitWhileBuilding.swiftmodule/%target-swiftmodule-name -import-underlying-module -F %t -module-name EmitWhileBuilding -disable-objc-attr-requires-foundation-module %s %S/Inputs/EmitWhileBuilding/Extra.swift -emit-symbol-graph -emit-symbol-graph-dir %t -emit-extension-block-symbols
|
||||
// RUN: %FileCheck %s --input-file %t/EmitWhileBuilding.symbols.json --check-prefix TYPE
|
||||
// RUN: %FileCheck %s --input-file %t/EmitWhileBuilding.symbols.json --check-prefix EXTENSION
|
||||
// RUN: %{python} -c 'import os.path; import sys; sys.exit(1 if os.path.exists(sys.argv[1]) else 0)' %t/EmitWhileBuilding@EmitWhileBuilding.symbols.json
|
||||
|
||||
// RUN: %target-swift-symbolgraph-extract -sdk %clang-importer-sdk -module-name EmitWhileBuilding -F %t -output-dir %t -pretty-print -v -emit-extension-block-symbols
|
||||
// RUN: %FileCheck %s --input-file %t/EmitWhileBuilding.symbols.json --check-prefix TYPE
|
||||
// RUN: %FileCheck %s --input-file %t/EmitWhileBuilding.symbols.json --check-prefix EXTENSION
|
||||
// RUN: %{python} -c 'import os.path; import sys; sys.exit(1 if os.path.exists(sys.argv[1]) else 0)' %t/EmitWhileBuilding@EmitWhileBuilding.symbols.json
|
||||
|
||||
// REQUIRES: objc_interop
|
||||
|
||||
// ensure that the symbol `Foo.Bar` does appear in the base module's symbol graph
|
||||
// and that there is no "swift.extension" symbol there
|
||||
|
||||
// TYPE: "s:So3FooV17EmitWhileBuildingE3BarO",
|
||||
// EXTENSION-NOT: swift.extension
|
||||
|
||||
public extension Foo {
|
||||
enum Bar { }
|
||||
}
|
||||
@@ -20,4 +20,3 @@ public extension String {
|
||||
case bar
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
double testVariable = 1.0;
|
||||
|
||||
struct Foo { };
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name EmptyExtension -I %t -pretty-print -output-dir %t
|
||||
// RUN: %{python} -c 'import os.path; import sys; sys.exit(1 if os.path.exists(sys.argv[1]) else 0)' %t/EmptyExtension@Swift.symbols.json
|
||||
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-build-swift %s -module-name EmptyExtension -emit-module -emit-module-path %t/
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name EmptyExtension -I %t -pretty-print -output-dir %t -emit-extension-block-symbols
|
||||
// RUN: %{python} -c 'import os.path; import sys; sys.exit(1 if os.path.exists(sys.argv[1]) else 0)' %t/EmptyExtension@Swift.symbols.json
|
||||
|
||||
|
||||
extension Sequence {
|
||||
func foo() {}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,27 @@
|
||||
// Testing with Extension Block Symbols Off:
|
||||
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-build-swift %s -module-name BasicExtension -emit-module -emit-module-path %t/
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name BasicExtension -I %t -pretty-print -output-dir %t
|
||||
// RUN: %FileCheck %s --input-file %t/BasicExtension@Swift.symbols.json --check-prefix EXTRACT
|
||||
// RUN: %FileCheck %s --input-file %t/BasicExtension@Swift.symbols.json --check-prefixes ALL,EXTRACT,EBSOff,EBSOff_EXTRACT
|
||||
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-build-swift %s -module-name BasicExtension -emit-module -emit-module-path %t/ -emit-symbol-graph -emit-symbol-graph-dir %t
|
||||
// RUN: %FileCheck %s --input-file %t/BasicExtension@Swift.symbols.json --check-prefix BUILD
|
||||
// RUN: %FileCheck %s --input-file %t/BasicExtension@Swift.symbols.json --check-prefixes ALL,BUILD,EBSOff,EBSOff_BUILD
|
||||
|
||||
|
||||
// Testing with Extension Block Symbols On:
|
||||
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-build-swift %s -module-name BasicExtension -emit-module -emit-module-path %t/
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name BasicExtension -I %t -pretty-print -output-dir %t -emit-extension-block-symbols
|
||||
// RUN: %FileCheck %s --input-file %t/BasicExtension@Swift.symbols.json --check-prefixes ALL,EXTRACT,EBSOn,EBSOn_EXTRACT
|
||||
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-build-swift %s -module-name BasicExtension -emit-module -emit-module-path %t/ -emit-symbol-graph -emit-symbol-graph-dir %t -emit-extension-block-symbols
|
||||
// RUN: %FileCheck %s --input-file %t/BasicExtension@Swift.symbols.json --check-prefixes ALL,BUILD,EBSOn,EBSOn_BUILD
|
||||
|
||||
/// We add some useless capabilities to ``Swift/String``.
|
||||
extension String {
|
||||
/// Return something.
|
||||
public var something: String {
|
||||
@@ -14,28 +29,43 @@ extension String {
|
||||
}
|
||||
}
|
||||
|
||||
// EXTRACT: module
|
||||
// EXTRACT-NEXT: "name": "BasicExtension"
|
||||
|
||||
// BUILD: module
|
||||
// BUILD: "name":"BasicExtension"
|
||||
// Check for module name:
|
||||
|
||||
// EXTRACT: "precise": "s:SS14BasicExtensionE9somethingSSvp"
|
||||
// ALL-LABEL: module
|
||||
|
||||
// BUILD: "precise":"s:SS14BasicExtensionE9somethingSSvp"
|
||||
// ALL: {{"name": ?"BasicExtension"}}
|
||||
|
||||
// EXTRACT: "kind": "memberOf"
|
||||
// EXTRACT-NEXT: "source": "s:SS14BasicExtensionE9somethingSSvp"
|
||||
// EXTRACT-NEXT: "target": "s:SS"
|
||||
|
||||
// BUILD: "kind":"memberOf"
|
||||
// BUILD: "source":"s:SS14BasicExtensionE9somethingSSvp"
|
||||
// BUILD: "target":"s:SS"
|
||||
// Check for Symbols and Documentation Strings:
|
||||
|
||||
// Symbols and relationships are not ordered. Therefore, we have to use
|
||||
// the `-DAG` variant if we have more than one symbol/relationship.
|
||||
|
||||
// ALL-LABEL: symbols
|
||||
|
||||
// ALL-DAG: {{"precise": ?"s:SS14BasicExtensionE9somethingSSvp"}}
|
||||
// EBSOn-DAG: {{"precise": ?"s:e:s:SS14BasicExtensionE9somethingSSvp"}}
|
||||
|
||||
// BUILD-DAG: Return something.
|
||||
// EBSOn_BUILD-DAG: We add some useless capabilities to ``Swift/String``.
|
||||
|
||||
// EBSOn-DAG: {{"swiftExtension": ?{[[:space:]]*"extendedModule": ?"Swift",[[:space:]]*"typeKind": ?"swift.struct"[[:space:]]*}}}
|
||||
|
||||
// Check for Relationships:
|
||||
|
||||
// ALL-LABEL: relationships
|
||||
|
||||
// EBSOff: {{"kind": ?"memberOf",[[:space:]]*"source": ?"s:SS14BasicExtensionE9somethingSSvp",[[:space:]]*"target": ?"s:SS"}}
|
||||
|
||||
// EBSOn-DAG: {{"kind": ?"memberOf",[[:space:]]*"source": ?"s:SS14BasicExtensionE9somethingSSvp",[[:space:]]*"target": ?"s:e:s:SS14BasicExtensionE9somethingSSvp"}}
|
||||
// EBSOn-DAG: {{"kind": ?"extensionTo",[[:space:]]*"source": ?"s:e:s:SS14BasicExtensionE9somethingSSvp",[[:space:]]*"target": ?"s:SS"}}
|
||||
|
||||
|
||||
// Check for Symbols that should NOT be included:
|
||||
|
||||
// Extending `String` creates a memberOf relationship above.
|
||||
// However, it should not be included as a node because `String`
|
||||
// is owned by the Swift module.
|
||||
// rdar://58876107
|
||||
// EXTRACT-NOT: "precise": "s:SS"
|
||||
|
||||
// BUILD-NOT: "precise":"s:SS"
|
||||
// ALL-NOT: {{"precise": ?"s:SS"}}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// RUN: %target-build-swift %S/Inputs/CrossImport/B.swift -I %t -module-name B -emit-module -emit-module-path %t/
|
||||
// RUN: %target-build-swift %s -module-name _A_B -I %t -emit-module -emit-module-path %t/
|
||||
// RUN: cp -r %S/Inputs/CrossImport/A.swiftcrossimport %t/
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name A -I %t -pretty-print -output-dir %t
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name A -I %t -pretty-print -output-dir %t -emit-extension-block-symbols
|
||||
// RUN: %FileCheck %s --input-file %t/_A_B@A.symbols.json --check-prefix CHECK-MOD
|
||||
// RUN: %FileCheck %s --input-file %t/_A_B@A.symbols.json --check-prefix CHECK-A
|
||||
// RUN: %FileCheck %s --input-file %t/_A_B@B.symbols.json --check-prefix CHECK-MOD
|
||||
@@ -37,7 +37,11 @@ extension B {
|
||||
|
||||
// CHECK-A-NOT: s:1BAAV4_A_BE14untransmogrify1AAEVyF
|
||||
// CHECK-A-DAG: s:1AAAV4_A_BE12transmogrify1BAEVyF
|
||||
// CHECK-A-DAG: s:e:s:1AAAV4_A_BE12transmogrify1BAEVyF
|
||||
// CHECK-A-DAG: s:4_A_B11LocalStructV
|
||||
// CHECK-A-DAG: s:4_A_B11LocalStructV8someFuncyyF
|
||||
// CHECK-A-NOT: s:e:s:4_A_B11LocalStructV8someFuncyyF
|
||||
// CHECK-A-NOT: s:e:s:1BAAV4_A_BE14untransmogrify1AAEVyF
|
||||
|
||||
// CHECK-B: s:1BAAV4_A_BE14untransmogrify1AAEVyF
|
||||
// CHECK-B-DAG: s:1BAAV4_A_BE14untransmogrify1AAEVyF
|
||||
// CHECK-B-DAG: s:e:s:1BAAV4_A_BE14untransmogrify1AAEVyF
|
||||
|
||||
@@ -3,17 +3,20 @@
|
||||
// RUN: %target-build-swift %S/Inputs/NestedExtensions/B.swift -I %t -module-name B -emit-module -emit-module-path %t/
|
||||
// RUN: %target-build-swift %s -module-name NestedExtensions -emit-module -I %t -emit-module-path %t/
|
||||
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name A -I %t -pretty-print -output-dir %t
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name B -I %t -pretty-print -output-dir %t
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name NestedExtensions -I %t -pretty-print -output-dir %t
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name A -I %t -pretty-print -output-dir %t -emit-extension-block-symbols
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name B -I %t -pretty-print -output-dir %t -emit-extension-block-symbols
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name NestedExtensions -I %t -pretty-print -output-dir %t -emit-extension-block-symbols
|
||||
|
||||
// RUN: %FileCheck %s --input-file %t/B.symbols.json --check-prefix=MODULEB
|
||||
// RUN: %FileCheck %s --input-file %t/B@A.symbols.json --check-prefix=MODULEBATA
|
||||
|
||||
// RUN: %FileCheck %s --input-file %t/NestedExtensions@A.symbols.json --check-prefix=NESTEDATA
|
||||
// RUN: %{python} -c 'import os.path; import sys; sys.exit(1 if os.path.exists(sys.argv[1]) else 0)' %t/NestedExtensions@B.symbols.json
|
||||
|
||||
// RUN: %FileCheck %s --input-file %t/NestedExtensions.symbols.json --check-prefix=NESTED
|
||||
|
||||
|
||||
|
||||
import A
|
||||
import B
|
||||
|
||||
@@ -35,10 +38,13 @@ extension AStruct.BStruct.CStruct where Thing: Equatable {
|
||||
|
||||
// BStruct belongs to AStruct and so should only ever appear in B@A extension symbol graph files.
|
||||
// MODULEB-NOT: BStruct
|
||||
// MODULEBATA: "precise": "s:1A7AStructV1BE7BStructV"
|
||||
// MODULEB-NOT: "swift.extension"
|
||||
// MODULEBATA-DAG: "precise": "s:1A7AStructV1BE7BStructV"
|
||||
// MODULEBATA-DAG: "precise": "s:e:s:1A7AStructV1BE7BStructV"
|
||||
|
||||
// CStruct belongs to BStruct, and BStruct belongs to AStruct, so should only appear in NestedExtension@A.
|
||||
// NESTED-NOT: BStruct
|
||||
// NESTED-NOT: CStruct
|
||||
// NESTEDATB-NOT: BStruct
|
||||
// NESTEDATA: "precise": "s:1A7AStructV1BE7BStructV16NestedExtensionsE7CStructV"
|
||||
// NESTED-NOT: "swift.extension"
|
||||
// NESTEDATA-DAG: "precise": "s:1A7AStructV1BE7BStructV16NestedExtensionsE7CStructV"
|
||||
// NESTEDATA-DAG: "precise": "s:e:s:1A7AStructV1BE7BStructV16NestedExtensionsE7CStructV"
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-build-swift %s -module-name FilterImplicitlyPrivate -emit-module -emit-module-path %t/
|
||||
// RUN: %target-build-swift %S/Inputs/ExternalUnderscored.swift -module-name ExternalUnderscored -emit-module -emit-module-path %t/
|
||||
// RUN: %target-build-swift %s -module-name FilterImplicitlyPrivate -emit-module -emit-module-path %t/ -I %t
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name FilterImplicitlyPrivate -I %t -pretty-print -output-dir %t
|
||||
// RUN: %FileCheck %s --input-file %t/FilterImplicitlyPrivate.symbols.json
|
||||
// RUN: %{python} -c 'import os.path; import sys; sys.exit(1 if os.path.exists(sys.argv[1]) else 0)' %t/FilterImplicitlyPrivate@ExternalUnderscored.symbols.json
|
||||
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-build-swift %S/Inputs/ExternalUnderscored.swift -module-name ExternalUnderscored -emit-module -emit-module-path %t/
|
||||
// RUN: %target-build-swift %s -module-name FilterImplicitlyPrivate -emit-module -emit-module-path %t/ -I %t
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name FilterImplicitlyPrivate -I %t -pretty-print -output-dir %t -emit-extension-block-symbols
|
||||
// RUN: %FileCheck %s --input-file %t/FilterImplicitlyPrivate.symbols.json
|
||||
// RUN: %{python} -c 'import os.path; import sys; sys.exit(1 if os.path.exists(sys.argv[1]) else 0)' %t/FilterImplicitlyPrivate@ExternalUnderscored.symbols.json
|
||||
|
||||
// Make sure extensions on implicitly private (< public or underscored, or inside one of those)
|
||||
// don't emit relationships (or symbols)
|
||||
@@ -46,5 +55,13 @@ extension _PublicUnderscored.InternalInner: CustomDebugStringConvertible {
|
||||
}
|
||||
}
|
||||
|
||||
import ExternalUnderscored
|
||||
|
||||
extension _ExternalUnderscored: CustomDebugStringConvertible {
|
||||
public var debugDescription: String {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK: "symbols": []
|
||||
// CHECK: "relationships": []
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-build-swift %s -module-name Indirect -emit-module -emit-module-path %t/
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name Indirect -I %t -pretty-print -output-dir %t
|
||||
// RUN: %target-build-swift %S/Inputs/ExternalIndirect.swift -module-name ExternalIndirect -emit-module -emit-module-path %t/
|
||||
// RUN: %target-build-swift %s -module-name Indirect -emit-module -emit-module-path %t/ -I %t
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name Indirect -I %t -pretty-print -output-dir %t -emit-extension-block-symbols
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name ExternalIndirect -I %t -pretty-print -output-dir %t -emit-extension-block-symbols
|
||||
// RUN: %FileCheck %s --input-file %t/Indirect.symbols.json
|
||||
// RUN: %FileCheck %s --input-file %t/ExternalIndirect.symbols.json --check-prefix EXTERNAL
|
||||
// RUN: %FileCheck %s --input-file %t/Indirect@ExternalIndirect.symbols.json --check-prefix EXTENSION
|
||||
|
||||
public protocol P {
|
||||
func foo()
|
||||
@@ -21,3 +25,21 @@ public struct S : Q {
|
||||
|
||||
// S : Q
|
||||
// CHECK-DAG: "kind": "conformsTo",{{[[:space:]]*}}"source": "s:8Indirect1SV",{{[[:space:]]*}}"target": "s:8Indirect1QP"
|
||||
|
||||
import ExternalIndirect
|
||||
|
||||
extension ES: EQ {
|
||||
public func foo() {}
|
||||
}
|
||||
|
||||
// EQ : EP
|
||||
// EXTERNAL-DAG: "kind": "conformsTo",{{[[:space:]]*}}"source": "s:16ExternalIndirect2EQP",{{[[:space:]]*}}"target": "s:16ExternalIndirect2EPP"
|
||||
|
||||
// extension ES : EP
|
||||
// EXTENSION-DAG: "kind": "conformsTo",{{[[:space:]]*}}"source": "s:e:s:16ExternalIndirect2ESV0B0E3fooyyF",{{[[:space:]]*}}"target": "s:16ExternalIndirect2EPP"
|
||||
|
||||
// extension ES : EQ
|
||||
// EXTENSION-DAG: "kind": "conformsTo",{{[[:space:]]*}}"source": "s:e:s:16ExternalIndirect2ESV0B0E3fooyyF",{{[[:space:]]*}}"target": "s:16ExternalIndirect2EQP"
|
||||
|
||||
// extension ES -> ES
|
||||
// EXTENSION-DAG: "kind": "extensionTo",{{[[:space:]]*}}"source": "s:e:s:16ExternalIndirect2ESV0B0E3fooyyF",{{[[:space:]]*}}"target": "s:16ExternalIndirect2ESV"
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
public protocol EP {
|
||||
func foo()
|
||||
}
|
||||
|
||||
public protocol EQ : EP {}
|
||||
|
||||
public struct ES { }
|
||||
@@ -0,0 +1 @@
|
||||
public struct _ExternalUnderscored {}
|
||||
@@ -0,0 +1,3 @@
|
||||
public struct ExternalS {}
|
||||
|
||||
public typealias ExternalA = ExternalS
|
||||
48
test/SymbolGraph/Relationships/MemberOf/Typealias.swift
Normal file
48
test/SymbolGraph/Relationships/MemberOf/Typealias.swift
Normal file
@@ -0,0 +1,48 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-build-swift %S/Inputs/ExternalTypealias.swift -module-name ExternalTypealias -emit-module -emit-module-path %t/
|
||||
// RUN: %target-build-swift %s -module-name Typealias -emit-module -emit-module-path %t/ -I %t
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name Typealias -I %t -pretty-print -output-dir %t
|
||||
// RUN: %FileCheck %s --input-file %t/Typealias.symbols.json
|
||||
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-build-swift %S/Inputs/ExternalTypealias.swift -module-name ExternalTypealias -emit-module -emit-module-path %t/
|
||||
// RUN: %target-build-swift %s -module-name Typealias -emit-module -emit-module-path %t/ -I %t
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name Typealias -I %t -pretty-print -output-dir %t
|
||||
// RUN: %FileCheck %s --input-file %t/Typealias@ExternalTypealias.symbols.json --check-prefix EXTERNAL
|
||||
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-build-swift %S/Inputs/ExternalTypealias.swift -module-name ExternalTypealias -emit-module -emit-module-path %t/
|
||||
// RUN: %target-build-swift %s -module-name Typealias -emit-module -emit-module-path %t/ -I %t
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name Typealias -I %t -pretty-print -output-dir %t -emit-extension-block-symbols
|
||||
// RUN: %FileCheck %s --input-file %t/Typealias@ExternalTypealias.symbols.json --check-prefix EBS_EXTERNAL
|
||||
|
||||
public struct S {}
|
||||
|
||||
public typealias A = S
|
||||
|
||||
// Members of a typealias should be associated with the original type,
|
||||
// not the typealias symbol
|
||||
public extension A {
|
||||
func foo() {}
|
||||
}
|
||||
|
||||
// CHECK: "kind": "memberOf"
|
||||
// CHECK-NEXT: "source": "s:9Typealias1SV3fooyyF"
|
||||
// CHECK-NEXT: "target": "s:9Typealias1SV"
|
||||
|
||||
|
||||
// This also applies to extensions to externally defined typealiases
|
||||
|
||||
import ExternalTypealias
|
||||
|
||||
public extension ExternalA {
|
||||
func foo() {}
|
||||
}
|
||||
|
||||
// EXTERNAL: "kind": "memberOf"
|
||||
// EXTERNAL-NEXT: "source": "s:17ExternalTypealias0A1SV0B0E3fooyyF"
|
||||
// EXTERNAL-NEXT: "target": "s:17ExternalTypealias0A1SV"
|
||||
|
||||
// EBS_EXTERNAL: "kind": "extensionTo"
|
||||
// EBS_EXTERNAL-NEXT: "source": "s:e:s:17ExternalTypealias0A1SV0B0E3fooyyF"
|
||||
// EBS_EXTERNAL-NEXT: "target": "s:17ExternalTypealias0A1SV"
|
||||
@@ -7,9 +7,22 @@
|
||||
// RUN: %FileCheck %s --input-file %t/ConditionalConformance.symbols.json --check-prefix=CONFORMS
|
||||
// RUN: %FileCheck %s --input-file %t/ConditionalConformance.symbols.json --check-prefix=MEMBER
|
||||
|
||||
// RUN: %FileCheck %s --input-file %t/ConditionalConformance@Swift.symbols.json --check-prefix=SYNTHEXT
|
||||
// RUN: %FileCheck %s --input-file %t/ConditionalConformance@Swift.symbols.json --check-prefix=CONFORMSEXT
|
||||
// RUN: %FileCheck %s --input-file %t/ConditionalConformance@Swift.symbols.json --check-prefix=MEMBEREXT
|
||||
// RUN: %FileCheck %s --input-file %t/ConditionalConformance@Swift.symbols.json --check-prefixes=SYNTHEXT,EBSOff_SYNTHEXT
|
||||
// RUN: %FileCheck %s --input-file %t/ConditionalConformance@Swift.symbols.json --check-prefixes=CONFORMSEXT,EBSOff_CONFORMSEXT
|
||||
// RUN: %FileCheck %s --input-file %t/ConditionalConformance@Swift.symbols.json --check-prefixes=MEMBEREXT,EBSOff_MEMBEREXT
|
||||
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-build-swift %s -module-name ConditionalConformance -emit-module -emit-module-path %t/
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name ConditionalConformance -I %t -pretty-print -output-dir %t -emit-extension-block-symbols
|
||||
|
||||
// R\UN: %FileCheck %s --input-file %t/ConditionalConformance.symbols.json
|
||||
// RUN: %FileCheck %s --input-file %t/ConditionalConformance.symbols.json --check-prefix=SYNTH
|
||||
// RUN: %FileCheck %s --input-file %t/ConditionalConformance.symbols.json --check-prefix=CONFORMS
|
||||
// RUN: %FileCheck %s --input-file %t/ConditionalConformance.symbols.json --check-prefix=MEMBER
|
||||
|
||||
// RUN: %FileCheck %s --input-file %t/ConditionalConformance@Swift.symbols.json --check-prefixes=SYNTHEXT,EBSOn_SYNTHEXT
|
||||
// RUN: %FileCheck %s --input-file %t/ConditionalConformance@Swift.symbols.json --check-prefixes=CONFORMSEXT,EBSOn_CONFORMSEXT
|
||||
// RUN: %FileCheck %s --input-file %t/ConditionalConformance@Swift.symbols.json --check-prefixes=MEMBEREXT,EBSOn_MEMBEREXT
|
||||
|
||||
// Relationships to Swift.Array should only go into the @Swift file.
|
||||
// C\HECK-NOT: "s:Sa"
|
||||
@@ -49,7 +62,8 @@ extension S: P where T == Int {
|
||||
}
|
||||
|
||||
// CONFORMSEXT: "kind": "conformsTo"
|
||||
// CONFORMSEXT-NEXT: "source": "s:Sa"
|
||||
// EBSOff_CONFORMSEXT-NEXT: "source": "s:Sa"
|
||||
// EBSOn_CONFORMSEXT-NEXT: "source": "s:e:s:Sa22ConditionalConformanceSiRszlE3baryyF"
|
||||
// CONFORMSEXT-NEXT: "target": "s:22ConditionalConformance1PP"
|
||||
// CONFORMSEXT-NEXT: swiftConstraints
|
||||
// CONFORMSEXT: "kind": "sameType"
|
||||
@@ -58,9 +72,11 @@ extension S: P where T == Int {
|
||||
|
||||
extension Array: P where Element == Int {
|
||||
// SYNTHEXT: "source": "s:22ConditionalConformance1PPAAE3fooyyF::SYNTHESIZED::s:Sa"
|
||||
// SYNTHEXT-NEXT: "target": "s:Sa"
|
||||
// EBSOff_SYNTHEXT-NEXT: "target": "s:Sa"
|
||||
// EBSOn_SYNTHEXT-NEXT: "target": "s:e:s:Sa22ConditionalConformanceSiRszlE3baryyF"
|
||||
|
||||
// MEMBEREXT: "source": "s:Sa22ConditionalConformanceSiRszlE3baryyF",
|
||||
// MEMBEREXT-NEXT: "target": "s:Sa",
|
||||
// MEMBEREXT: "source": "s:Sa22ConditionalConformanceSiRszlE3baryyF"
|
||||
// EBSOff_MEMBEREXT-NEXT: "target": "s:Sa"
|
||||
// EBSOn_MEMBEREXT-NEXT: "target": "s:e:s:Sa22ConditionalConformanceSiRszlE3baryyF"
|
||||
public func bar() {}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-build-swift %S/Inputs/RemoteP.swift -module-name RemoteP -emit-module -emit-module-path %t/
|
||||
// RUN: %target-build-swift %s -module-name EnablingDeclaration -emit-module -emit-module-path %t/ -I %t
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name EnablingDeclaration -I %t -pretty-print -output-dir %t
|
||||
// RUN: %FileCheck %s --input-file %t/EnablingDeclaration@RemoteP.symbols.json --check-prefix=SYNTH
|
||||
// RUN: %FileCheck %s --input-file %t/EnablingDeclaration@RemoteP.symbols.json --check-prefix=NOSYNTH
|
||||
import RemoteP
|
||||
|
||||
// unrelated to the P protocol and P.extraFunc()
|
||||
public extension PImpl {
|
||||
func foo() {}
|
||||
}
|
||||
|
||||
// NOSYNTH-NOT: {{"PImpl",[[:space:]]*"extraFunc\(\)"}}
|
||||
|
||||
// related to the P protocol and enables the synthesized member NoImpl.extraFunc()
|
||||
extension NoPImpl: P {
|
||||
public func someFunc() {}
|
||||
|
||||
public func otherFunc() {}
|
||||
|
||||
public func bonusFunc() {}
|
||||
}
|
||||
|
||||
// SYNTH: {{"NoPImpl",[[:space:]]*"extraFunc\(\)"}}
|
||||
@@ -12,3 +12,13 @@ public extension P {
|
||||
/// Extra default docs!
|
||||
func extraFunc() {}
|
||||
}
|
||||
|
||||
public struct PImpl: P {
|
||||
public func someFunc() {}
|
||||
|
||||
public func otherFunc() {}
|
||||
|
||||
public func bonusFunc() {}
|
||||
}
|
||||
|
||||
public struct NoPImpl {}
|
||||
|
||||
@@ -2,13 +2,14 @@
|
||||
// RUN: %target-swift-frontend %S/Inputs/RemoteP.swift -module-name RemoteP -emit-module -emit-module-path %t/RemoteP.swiftmodule -emit-module-source-info-path %t/RemoteP.swiftsourceinfo -emit-module-doc-path %t/RemoteP.swiftdoc
|
||||
// RUN: %target-swift-frontend %s -module-name RemoteInheritedDocs -emit-module -emit-module-path %t/RemoteInheritedDocs.swiftmodule -emit-module-source-info-path %t/RemoteInheritedDocs.swiftsourceinfo -emit-module-doc-path %t/RemoteInheritedDocs.swiftdoc -I %t
|
||||
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name RemoteInheritedDocs -I %t -pretty-print -output-dir %t
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name RemoteInheritedDocs -I %t -pretty-print -output-dir %t -emit-extension-block-symbols
|
||||
// RUN: %FileCheck %s --input-file %t/RemoteInheritedDocs.symbols.json --check-prefix SOME
|
||||
// RUN: %FileCheck %s --input-file %t/RemoteInheritedDocs.symbols.json --check-prefix OTHER
|
||||
// RUN: %FileCheck %s --input-file %t/RemoteInheritedDocs.symbols.json --check-prefix BONUS
|
||||
// RUN: %FileCheck %s --input-file %t/RemoteInheritedDocs.symbols.json --check-prefix INHERIT
|
||||
// RUN: %FileCheck %s --input-file %t/RemoteInheritedDocs.symbols.json --check-prefix LOCAL
|
||||
// RUN: %FileCheck %s --input-file %t/RemoteInheritedDocs.symbols.json --check-prefix OVERRIDE
|
||||
// RUN: %FileCheck %s --input-file %t/RemoteInheritedDocs@RemoteP.symbols.json --check-prefix EXTENSION
|
||||
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name RemoteInheritedDocs -I %t -pretty-print -output-dir %t -skip-inherited-docs
|
||||
// RUN: %FileCheck %s --input-file %t/RemoteInheritedDocs.symbols.json --check-prefix SOME
|
||||
@@ -44,6 +45,8 @@
|
||||
// OVERRIDE-NOT: Extra default docs!
|
||||
// OVERRIDE-NOT: Extension override!
|
||||
|
||||
// EXTENSION-NOT: Some Protocol
|
||||
|
||||
import RemoteP
|
||||
|
||||
// The `RemoteP.P` protocol has three methods: `someFunc` and `bonusFunc` don't have docs upstream,
|
||||
@@ -53,6 +56,9 @@ import RemoteP
|
||||
// `RemoteP.P` also has an extension with a default implementation for `extraFunc` that does have
|
||||
// docs, but overriding it here should prevent those from appearing
|
||||
|
||||
// When emitting extension block symbols, local extension blocks should never inherit documentation
|
||||
// from the original type declaration.
|
||||
|
||||
public struct S: P {
|
||||
public func someFunc() {}
|
||||
|
||||
@@ -68,4 +74,3 @@ public extension P {
|
||||
/// Extension override!
|
||||
func someFunc() {}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-build-swift %s -module-name IncludeInternal -emit-module -emit-module-path %t/
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name IncludeInternal -I %t -pretty-print -output-dir %t -minimum-access-level internal
|
||||
// RUN: %target-build-swift %S/Inputs/Internal.swift -module-name Internal -emit-module -emit-module-path %t/ -enable-testing
|
||||
// RUN: %target-build-swift %s -module-name IncludeInternal -emit-module -emit-module-path %t/ -I %t
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name IncludeInternal -I %t -pretty-print -output-dir %t -minimum-access-level internal -emit-extension-block-symbols
|
||||
// RUN: %FileCheck %s --input-file %t/IncludeInternal.symbols.json
|
||||
// RUN: %FileCheck %s --input-file %t/IncludeInternal@Internal.symbols.json --check-prefix EXTENSION
|
||||
// RUN: %FileCheck %s --input-file %t/IncludeInternal@Internal.symbols.json --check-prefix EXTENSION_EBS
|
||||
|
||||
public struct ShouldAppear {
|
||||
public var x: Int
|
||||
@@ -18,3 +21,17 @@ private struct ShouldntAppear {
|
||||
// CHECK: ShouldAppear
|
||||
// CHECK: ShouldAlsoAppear
|
||||
// CHECK-NOT: ShouldntAppear
|
||||
|
||||
@testable import Internal
|
||||
|
||||
extension S {
|
||||
func shouldAppear() { }
|
||||
}
|
||||
|
||||
extension S {
|
||||
private func shouldntAppear() { }
|
||||
}
|
||||
|
||||
// EXTENSION: shouldAppear
|
||||
// EXTENSION-NOT: shouldntAppear
|
||||
// EXTENSION_EBS-COUNT-1: "swift.extension"
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
struct S { }
|
||||
7
test/SymbolGraph/Symbols/Inputs/ExternalNames.swift
Normal file
7
test/SymbolGraph/Symbols/Inputs/ExternalNames.swift
Normal file
@@ -0,0 +1,7 @@
|
||||
public struct ExternalStruct {
|
||||
public struct InnerStruct {}
|
||||
|
||||
public typealias InnerTypeAlias = InnerStruct
|
||||
|
||||
public enum InnerEnum {}
|
||||
}
|
||||
@@ -3,6 +3,11 @@
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name SelfNotLinked -I %t -pretty-print -output-dir %t
|
||||
// RUN: %FileCheck %s --input-file %t/SelfNotLinked@Swift.symbols.json --match-full-lines --strict-whitespace
|
||||
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-build-swift %s -module-name SelfNotLinked -emit-module -emit-module-path %t/
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name SelfNotLinked -I %t -pretty-print -output-dir %t -emit-extension-block-symbols
|
||||
// RUN: %FileCheck %s --input-file %t/SelfNotLinked@Swift.symbols.json --match-full-lines --strict-whitespace
|
||||
|
||||
extension Sequence where Self : Collection {
|
||||
public func foo(x: Self) {}
|
||||
}
|
||||
@@ -43,5 +48,3 @@ extension Sequence where Self : Collection {
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: ],
|
||||
// CHECK-NEXT: "accessLevel": "public"
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: ],
|
||||
|
||||
17
test/SymbolGraph/Symbols/Mixins/DocComment/Extension.swift
Normal file
17
test/SymbolGraph/Symbols/Mixins/DocComment/Extension.swift
Normal file
@@ -0,0 +1,17 @@
|
||||
// FYI: The lit commands and FileCheck statements are at the bottom of the file, to be resilient
|
||||
// against changes to the doc comment format.
|
||||
|
||||
/// This should be captured
|
||||
extension String: CustomDebugStringConvertible {
|
||||
var debugDescription: String {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-build-swift %s -module-name Extension -emit-module-path %t/Extension.swiftmodule
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name Extension -I %t -pretty-print -output-dir %t -emit-extension-block-symbols
|
||||
// RUN: %FileCheck %s --input-file %t/Extension@Swift.symbols.json
|
||||
|
||||
// CHECK: This should be captured
|
||||
3
test/SymbolGraph/Symbols/Mixins/Inputs/SPIP.swift
Normal file
3
test/SymbolGraph/Symbols/Mixins/Inputs/SPIP.swift
Normal file
@@ -0,0 +1,3 @@
|
||||
/// SPI Protocol doc
|
||||
@_spi(SPI)
|
||||
public protocol P { }
|
||||
@@ -1,13 +1,32 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-build-swift %s -module-name Location -emit-module-path %t/Location.swiftmodule
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name Location -I %t -pretty-print -output-dir %t
|
||||
// RUN: %FileCheck %s --input-file %t/Location.symbols.json
|
||||
// FYI: The lit commands and FileCheck statements are at the bottom of the file, to be resilient
|
||||
// against changes to the doc comment format.
|
||||
|
||||
/// This is a struct.
|
||||
/// location points here
|
||||
/// v
|
||||
public struct MyStruct {}
|
||||
|
||||
// CHECK: location
|
||||
// CHECK-NEXT: uri
|
||||
// CHECK-NEXT: position
|
||||
// CHECK-NEXT: "line": 6
|
||||
/// location points here
|
||||
/// v
|
||||
public extension String {
|
||||
func foo() { }
|
||||
}
|
||||
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-build-swift %s -module-name Location -emit-module-path %t/Location.swiftmodule
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name Location -I %t -pretty-print -output-dir %t -emit-extension-block-symbols
|
||||
// RUN: %FileCheck %s --input-file %t/Location.symbols.json
|
||||
// RUN: %FileCheck %s --input-file %t/Location@Swift.symbols.json --check-prefix EXTENSION
|
||||
|
||||
|
||||
// CHECK: "location"
|
||||
// CHECK-NEXT: "uri"
|
||||
// CHECK-NEXT: "position"
|
||||
// CHECK-NEXT: "line": 5
|
||||
// CHECK-NEXT: "character": 14
|
||||
|
||||
// EXTENSION-LABEL: "swift.extension"
|
||||
// EXTENSION: "location"
|
||||
// EXTENSION-NEXT: "uri"
|
||||
// EXTENSION-NEXT: "position"
|
||||
// EXTENSION-NEXT: "line": 9
|
||||
// EXTENSION-NEXT: "character": 7
|
||||
|
||||
@@ -1,18 +1,28 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-build-swift %s -module-name SPI -emit-module -emit-module-path %t/SPI.swiftmodule -include-spi-symbols
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name SPI -I %t -pretty-print -output-dir %t -include-spi-symbols
|
||||
// RUN: %target-build-swift %S/Inputs/SPIP.swift -module-name SPIP -emit-module -emit-module-path %t/ -include-spi-symbols
|
||||
// RUN: %target-build-swift %s -module-name SPI -emit-module -emit-module-path %t/SPI.swiftmodule -include-spi-symbols -I %t
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name SPI -I %t -pretty-print -output-dir %t -include-spi-symbols -emit-extension-block-symbols
|
||||
// RUN: %FileCheck %s --input-file %t/SPI.symbols.json --check-prefix SPI
|
||||
// RUN: %FileCheck %s --input-file %t/SPI@SPIP.symbols.json --check-prefix SPI_EXT_SPIP
|
||||
// RUN: %FileCheck %s --input-file %t/SPI@Swift.symbols.json --check-prefix SPI_EXT_Swift
|
||||
// RUN: %FileCheck %s --input-file %t/SPI.symbols.json --check-prefix SPIDOC
|
||||
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name SPI -I %t -pretty-print -output-dir %t
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-build-swift %S/Inputs/SPIP.swift -module-name SPIP -emit-module -emit-module-path %t/ -include-spi-symbols
|
||||
// RUN: %target-build-swift %s -module-name SPI -emit-module -emit-module-path %t/SPI.swiftmodule -include-spi-symbols -I %t
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name SPI -I %t -pretty-print -output-dir %t -emit-extension-block-symbols
|
||||
// RUN: %FileCheck %s --input-file %t/SPI.symbols.json --check-prefix NOSPI
|
||||
// RUN: %{python} -c 'import os.path; import sys; sys.exit(1 if os.path.exists(sys.argv[1]) else 0)' %t/SPI@SPIP.symbols.json
|
||||
// RUN: %{python} -c 'import os.path; import sys; sys.exit(1 if os.path.exists(sys.argv[1]) else 0)' %t/SPI@Swift.symbols.json
|
||||
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-build-swift %S/Inputs/SPIP.swift -module-name SPIP -emit-module -emit-module-path %t/
|
||||
// RUN: %target-build-swift %s -module-name SPI -emit-module -emit-module-path %t/SPI.swiftmodule -emit-symbol-graph -emit-symbol-graph-dir %t/ -include-spi-symbols -v
|
||||
// RUN: %FileCheck %s --input-file %t/SPI.symbols.json --check-prefix SPI-COMPILE
|
||||
// RUN: %FileCheck %s --input-file %t/SPI.symbols.json --check-prefix SPIDOC
|
||||
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-build-swift %S/Inputs/SPIP.swift -module-name SPIP -emit-module -emit-module-path %t/
|
||||
// RUN: %target-build-swift %s -module-name SPI -emit-module -emit-module-path %t/SPI.swiftmodule -emit-symbol-graph -emit-symbol-graph-dir %t/
|
||||
// RUN: %FileCheck %s --input-file %t/SPI.symbols.json --check-prefix NOSPI-COMPILE
|
||||
|
||||
@@ -28,3 +38,24 @@
|
||||
// NOSPI-COMPILE-NOT: s:3SPI10SomeStructV
|
||||
|
||||
// SPIDOC: This is some struct, there
|
||||
|
||||
#if canImport(SPIP)
|
||||
@_spi(SPI) import SPIP
|
||||
|
||||
public extension P {
|
||||
func foo() { }
|
||||
}
|
||||
|
||||
@_spi(SPI)
|
||||
extension String: P {}
|
||||
#endif
|
||||
|
||||
// SPI_EXT_SPIP-DAG: "precise": "s:4SPIP1PP3SPIE3fooyyF"
|
||||
// SPI_EXT_SPIP-DAG: "spi": true
|
||||
// SPI_EXT_SPIP-DAG: "precise": "s:e:s:4SPIP1PP3SPIE3fooyyF"
|
||||
// SPI_EXT_SPIP-DAG: "spi": true
|
||||
|
||||
// SPI_EXT_Swift-DAG: "precise": "s:e:s:SSs:4SPIP1PP"
|
||||
// SPI_EXT_Swift-DAG: "spi": true
|
||||
// SPI_EXT_Swift-DAG: "precise": "s:4SPIP1PP3SPIE3fooyyF::SYNTHESIZED::s:SS"
|
||||
// SPI_EXT_Swift-DAG: "spi": true
|
||||
|
||||
@@ -1,13 +1,22 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-build-swift %s -module-name Names -emit-module -emit-module-path %t/
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name Names -I %t -pretty-print -output-dir %t
|
||||
// RUN: %target-build-swift %S/Inputs/ExternalNames.swift -module-name ExternalNames -emit-module -emit-module-path %t/
|
||||
// RUN: %target-build-swift %s -module-name Names -emit-module -emit-module-path %t/ -I %t
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name Names -I %t -pretty-print -output-dir %t -emit-extension-block-symbols
|
||||
// RUN: %FileCheck %s --input-file %t/Names.symbols.json
|
||||
// RUN: %FileCheck %s --input-file %t/Names.symbols.json --check-prefix=FUNC
|
||||
// RUN: %FileCheck %s --input-file %t/Names.symbols.json --check-prefix=INNERTYPE
|
||||
// RUN: %FileCheck %s --input-file %t/Names.symbols.json --check-prefix=INNERTYPEALIAS
|
||||
// RUN: %FileCheck %s --input-file %t/Names.symbols.json --check-prefix=INNERENUM
|
||||
// RUN: %FileCheck %s --input-file %t/Names.symbols.json --check-prefix=INNERCASE
|
||||
|
||||
// RUN: %FileCheck %s --input-file %t/Names@ExternalNames.symbols.json --check-prefix=EXT_INNERTYPE
|
||||
// RUN: %FileCheck %s --input-file %t/Names@ExternalNames.symbols.json --check-prefix=EXT_INNERENUM
|
||||
|
||||
// RUN: %FileCheck %s --input-file %t/Names.symbols.json --check-prefix=INNERTYPEALIAS
|
||||
// RUN: %FileCheck %s --input-file %t/Names.symbols.json --check-prefix=INNERTYPEALIAS_INNERINNERTYPE
|
||||
|
||||
// RUN: %FileCheck %s --input-file %t/Names@ExternalNames.symbols.json --check-prefix=EXT_INNERTYPEALIAS
|
||||
// RUN: %FileCheck %s --input-file %t/Names@ExternalNames.symbols.json --check-prefix=EXT_INNERTYPEALIAS_INNERINNERTYPE
|
||||
|
||||
public struct MyStruct {
|
||||
public struct InnerStruct {}
|
||||
|
||||
@@ -20,6 +29,28 @@ public struct MyStruct {
|
||||
}
|
||||
}
|
||||
|
||||
public extension MyStruct.InnerTypeAlias {
|
||||
struct InnerInnerStruct {}
|
||||
}
|
||||
|
||||
import ExternalNames
|
||||
|
||||
public extension ExternalStruct.InnerStruct {
|
||||
func foo() {}
|
||||
}
|
||||
|
||||
public extension ExternalStruct.InnerTypeAlias {
|
||||
func bar() {}
|
||||
}
|
||||
|
||||
public extension ExternalStruct.InnerEnum {
|
||||
func foo() {}
|
||||
}
|
||||
|
||||
public extension ExternalStruct.InnerTypeAlias {
|
||||
struct InnerInnerStruct {}
|
||||
}
|
||||
|
||||
// CHECK-LABEL: "precise": "s:5Names8MyStructV"
|
||||
// CHECK: names
|
||||
// CHECK-NEXT: "title": "MyStruct"
|
||||
@@ -32,10 +63,6 @@ public struct MyStruct {
|
||||
// INNERTYPE: names
|
||||
// INNERTYPE-NEXT: "title": "MyStruct.InnerStruct"
|
||||
|
||||
// INNERTYPEALIAS-LABEL: "precise": "s:5Names8MyStructV14InnerTypeAliasa"
|
||||
// INNERTYPEALIAS: names
|
||||
// INNERTYPEALIAS-NEXT: "title": "MyStruct.InnerTypeAlias"
|
||||
|
||||
// INNERENUM-LABEL: "precise": "s:5Names8MyStructV9InnerEnumO",
|
||||
// INNERENUM: names
|
||||
// INNERENUM-NEXT: "title": "MyStruct.InnerEnum"
|
||||
@@ -43,3 +70,39 @@ public struct MyStruct {
|
||||
// INNERCASE-LABEL: "precise": "s:5Names8MyStructV9InnerEnumO0D4CaseyA2EmF",
|
||||
// INNERCASE: names
|
||||
// INNERCASE-NEXT: "title": "MyStruct.InnerEnum.InnerCase",
|
||||
|
||||
// EXT_INNERTYPE-LABEL: "precise": "s:e:s:13ExternalNames0A6StructV05InnerC0V0B0E3fooyyF"
|
||||
// EXT_INNERTYPE: names
|
||||
// EXT_INNERTYPE-NEXT: "title": "ExternalStruct.InnerStruct"
|
||||
|
||||
// EXT_INNERENUM-LABEL: "precise": "s:e:s:13ExternalNames0A6StructV9InnerEnumO0B0E3fooyyF",
|
||||
// EXT_INNERENUM: names
|
||||
// EXT_INNERENUM-NEXT: "title": "ExternalStruct.InnerEnum"
|
||||
|
||||
|
||||
// The typealias symbol itself should use the name of the typealias
|
||||
|
||||
// INNERTYPEALIAS-LABEL: "precise": "s:5Names8MyStructV14InnerTypeAliasa"
|
||||
// INNERTYPEALIAS: names
|
||||
// INNERTYPEALIAS-NEXT: "title": "MyStruct.InnerTypeAlias"
|
||||
|
||||
// Types declared in extensions to typealiases should always use the name of their
|
||||
// original (aliased) parent type
|
||||
|
||||
// INNERTYPEALIAS_INNERINNERTYPE-LABEL: "precise": "s:5Names8MyStructV05InnerC0V0ddC0V"
|
||||
// INNERTYPEALIAS_INNERINNERTYPE: names
|
||||
// INNERTYPEALIAS_INNERINNERTYPE-NEXT: "title": "MyStruct.InnerStruct.InnerInnerStruct"
|
||||
|
||||
// Extension symbols which extend a typealias should use the name of the original
|
||||
// (aliased) type
|
||||
|
||||
// EXT_INNERTYPEALIAS-LABEL: "precise": "s:e:s:13ExternalNames0A6StructV05InnerC0V0B0E3baryyF"
|
||||
// EXT_INNERTYPEALIAS: names
|
||||
// EXT_INNERTYPEALIAS-NEXT: "title": "ExternalStruct.InnerStruct"
|
||||
|
||||
// Symbols declared in an extension to a typealias should also use the name of the original
|
||||
// (aliased) type
|
||||
|
||||
// EXT_INNERTYPEALIAS_INNERINNERTYPE-LABEL: "precise": "s:13ExternalNames0A6StructV05InnerC0V0B0E0ddC0V"
|
||||
// EXT_INNERTYPEALIAS_INNERINNERTYPE: names
|
||||
// EXT_INNERTYPEALIAS_INNERINNERTYPE-NEXT: "title": "ExternalStruct.InnerStruct.InnerInnerStruct"
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-build-swift %s -module-name PathComponents -emit-module -emit-module-path %t/
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name PathComponents -I %t -pretty-print -output-dir %t
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name PathComponents -I %t -pretty-print -output-dir %t -emit-extension-block-symbols
|
||||
// RUN: %FileCheck %s --input-file %t/PathComponents.symbols.json
|
||||
// RUN: %FileCheck %s --input-file %t/PathComponents@Swift.symbols.json --check-prefix EXTENSION
|
||||
// RUN: %FileCheck %s --input-file %t/PathComponents@Swift.symbols.json --check-prefix EXTENSION_EBS
|
||||
|
||||
public struct Outer {
|
||||
public struct Inner {
|
||||
@@ -17,3 +19,26 @@ public struct Outer {
|
||||
// CHECK-NEXT: "Inner"
|
||||
// CHECK-NEXT: "x"
|
||||
// CHECK-NEXT: ]
|
||||
|
||||
|
||||
public extension String {
|
||||
public struct Inner {
|
||||
public var x: Int { 1 }
|
||||
}
|
||||
}
|
||||
|
||||
// EXTENSION: "precise": "s:SS14PathComponentsE5InnerV1xSivp"
|
||||
// EXTENSION-NEXT: "interfaceLanguage": "swift"
|
||||
// EXTENSION-NEXT: },
|
||||
// EXTENSION-NEXT: "pathComponents": [
|
||||
// EXTENSION-NEXT: "String"
|
||||
// EXTENSION-NEXT: "Inner"
|
||||
// EXTENSION-NEXT: "x"
|
||||
// EXTENSION-NEXT: ]
|
||||
|
||||
// EXTENSION_EBS: "precise": "s:e:s:SS14PathComponentsE5InnerV"
|
||||
// EXTENSION_EBS-NEXT: "interfaceLanguage": "swift"
|
||||
// EXTENSION_EBS-NEXT: },
|
||||
// EXTENSION_EBS-NEXT: "pathComponents": [
|
||||
// EXTENSION_EBS-NEXT: "String"
|
||||
// EXTENSION_EBS-NEXT: ]
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-build-swift %s -module-name Unavailable -emit-module -emit-module-path %t/
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name Unavailable -I %t -pretty-print -output-dir %t
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name Unavailable -I %t -pretty-print -output-dir %t -emit-extension-block-symbols
|
||||
// RUN: %FileCheck %s --input-file %t/Unavailable.symbols.json
|
||||
// RUN: %{python} -c 'import os.path; import sys; sys.exit(1 if os.path.exists(sys.argv[1]) else 0)' %t/Unavailable@Swift.symbols.json
|
||||
|
||||
// REQUIRES: OS=macosx
|
||||
|
||||
@@ -26,3 +27,13 @@ extension ShouldAppear {
|
||||
}
|
||||
|
||||
// CHECK-NOT: shouldntAppear
|
||||
|
||||
@available(OSX, unavailable)
|
||||
extension String {
|
||||
public func shouldntAppear1() { }
|
||||
}
|
||||
|
||||
@available(OSX, obsoleted: 10.9)
|
||||
extension String {
|
||||
public func shouldntAppear2() {}
|
||||
}
|
||||
|
||||
@@ -1004,7 +1004,8 @@ fillSymbolInfo(CursorSymbolInfo &Symbol, const DeclInfo &DInfo,
|
||||
/*PrintMessages=*/false,
|
||||
/*SkipInheritedDocs=*/false,
|
||||
/*IncludeSPISymbols=*/true,
|
||||
/*IncludeClangDocs=*/true
|
||||
/*IncludeClangDocs=*/true,
|
||||
/*EmitExtensionBlockSymbols=*/false,
|
||||
};
|
||||
|
||||
symbolgraphgen::printSymbolGraphForDecl(DInfo.VD, DInfo.BaseType,
|
||||
|
||||
Reference in New Issue
Block a user