mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Merge pull request #73080 from daniel-grumberg/export-import-sgf-extract
[SymbolGraphGen] Correctly handle exported imports in swift-symbolgraph-extract
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
#define SWIFT_MODULE_H
|
||||
|
||||
#include "swift/AST/AccessNotes.h"
|
||||
#include "swift/AST/AttrKind.h"
|
||||
#include "swift/AST/Decl.h"
|
||||
#include "swift/AST/DeclContext.h"
|
||||
#include "swift/AST/Identifier.h"
|
||||
@@ -551,7 +552,7 @@ public:
|
||||
ModuleDecl *getUnderlyingModuleIfOverlay() const;
|
||||
|
||||
/// Returns true if this module is the Clang overlay of \p other.
|
||||
bool isClangOverlayOf(ModuleDecl *other);
|
||||
bool isClangOverlayOf(ModuleDecl *other) const;
|
||||
|
||||
/// Returns true if this module is the same module or either module is a clang
|
||||
/// overlay of the other.
|
||||
@@ -1094,6 +1095,24 @@ public:
|
||||
/// for that.
|
||||
void getDisplayDecls(SmallVectorImpl<Decl*> &results, bool recursive = false) const;
|
||||
|
||||
struct ImportCollector {
|
||||
SmallPtrSet<const ModuleDecl *, 4> imports;
|
||||
llvm::SmallDenseMap<const ModuleDecl *, SmallPtrSet<Decl *, 4>, 4>
|
||||
qualifiedImports;
|
||||
AccessLevel minimumDocVisibility = AccessLevel::Private;
|
||||
llvm::function_ref<bool(const ModuleDecl *)> importFilter = nullptr;
|
||||
|
||||
void collect(const ImportedModule &importedModule);
|
||||
|
||||
ImportCollector() = default;
|
||||
ImportCollector(AccessLevel minimumDocVisibility)
|
||||
: minimumDocVisibility(minimumDocVisibility) {}
|
||||
};
|
||||
|
||||
void
|
||||
getDisplayDeclsRecursivelyAndImports(SmallVectorImpl<Decl *> &results,
|
||||
ImportCollector &importCollector) const;
|
||||
|
||||
using LinkLibraryCallback = llvm::function_ref<void(LinkLibrary)>;
|
||||
|
||||
/// Generate the list of libraries needed to link this module, based on its
|
||||
@@ -1273,12 +1292,6 @@ inline SourceLoc extractNearestSourceLoc(const ModuleDecl *mod) {
|
||||
return extractNearestSourceLoc(static_cast<const Decl *>(mod));
|
||||
}
|
||||
|
||||
/// Collects modules that this module imports via `@_exported import`.
|
||||
void collectParsedExportedImports(const ModuleDecl *M,
|
||||
SmallPtrSetImpl<ModuleDecl *> &Imports,
|
||||
llvm::SmallDenseMap<ModuleDecl *, SmallPtrSet<Decl *, 4>, 4> &QualifiedImports,
|
||||
llvm::function_ref<bool(AttributedImport<ImportedModule>)> includeImport = nullptr);
|
||||
|
||||
/// If the import that would make the given declaration visibile is absent,
|
||||
/// emit a diagnostic and a fix-it suggesting adding the missing import.
|
||||
bool diagnoseMissingImportForMember(const ValueDecl *decl,
|
||||
|
||||
@@ -1573,6 +1573,10 @@ def output_dir : Separate<["-"], "output-dir">,
|
||||
HelpText<"Output directory">,
|
||||
MetaVarName<"<dir>">;
|
||||
|
||||
def experimental_allowed_reexported_modules: CommaJoined<["-"], "experimental-allowed-reexported-modules=">,
|
||||
Flags<[NoDriverOption, SwiftSymbolGraphExtractOption]>,
|
||||
HelpText<"Allow reexporting symbols from the provided modules if they are themselves exported from the main module. This is a comma separated list of module names.">;
|
||||
|
||||
def skip_synthesized_members: Flag<[ "-" ], "skip-synthesized-members">,
|
||||
Flags<[NoDriverOption, SwiftSymbolGraphExtractOption]>,
|
||||
HelpText<"Skip members inherited through classes or default implementations">;
|
||||
|
||||
@@ -162,6 +162,15 @@ namespace swift {
|
||||
void
|
||||
getTopLevelDeclsForDisplay(ModuleDecl *M, SmallVectorImpl<Decl*> &Results, bool Recursive = false);
|
||||
|
||||
/// Get all of the top-level declarations that should be printed as part of
|
||||
/// this module. This may force synthesis of top-level declarations that
|
||||
/// \p getDisplayDeclsForModule would only return if previous
|
||||
/// work happened to have synthesized them.
|
||||
void getTopLevelDeclsForDisplay(
|
||||
ModuleDecl *M, SmallVectorImpl<Decl *> &Results,
|
||||
llvm::function_ref<void(ModuleDecl *, SmallVectorImpl<Decl *> &)>
|
||||
getDisplayDeclsForModule);
|
||||
|
||||
struct ExtensionInfo {
|
||||
// The extension with the declarations to apply.
|
||||
ExtensionDecl *Ext;
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/TargetParser/Triple.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
|
||||
#include "swift/AST/AttrKind.h"
|
||||
|
||||
#ifndef SWIFT_SYMBOLGRAPHGEN_SYMBOLGRAPHOPTIONS_H
|
||||
@@ -63,6 +65,10 @@ struct SymbolGraphOptions {
|
||||
/// but SourceKit should be able to load the information when pulling symbol
|
||||
/// information for individual queries.
|
||||
bool PrintPrivateStdlibSymbols = false;
|
||||
|
||||
/// If this has a value specifies an explicit allow list of reexported module
|
||||
/// names that should be included symbol graph.
|
||||
std::optional<llvm::ArrayRef<StringRef>> AllowedReexportedModules = {};
|
||||
};
|
||||
|
||||
} // end namespace symbolgraphgen
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "swift/AST/ExistentialLayout.h"
|
||||
#include "swift/AST/FileUnit.h"
|
||||
#include "swift/AST/GenericEnvironment.h"
|
||||
#include "swift/AST/Import.h"
|
||||
#include "swift/AST/ImportCache.h"
|
||||
#include "swift/AST/LazyResolver.h"
|
||||
#include "swift/AST/LinkLibrary.h"
|
||||
@@ -39,6 +40,7 @@
|
||||
#include "swift/AST/ProtocolConformance.h"
|
||||
#include "swift/AST/SourceFile.h"
|
||||
#include "swift/AST/SynthesizedFileUnit.h"
|
||||
#include "swift/AST/Type.h"
|
||||
#include "swift/AST/TypeCheckRequests.h"
|
||||
#include "swift/Basic/Compiler.h"
|
||||
#include "swift/Basic/SourceManager.h"
|
||||
@@ -1288,42 +1290,6 @@ bool ModuleDecl::shouldCollectDisplayDecls() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
void swift::collectParsedExportedImports(const ModuleDecl *M,
|
||||
SmallPtrSetImpl<ModuleDecl *> &Imports,
|
||||
llvm::SmallDenseMap<ModuleDecl *, SmallPtrSet<Decl *, 4>, 4> &QualifiedImports,
|
||||
llvm::function_ref<bool(AttributedImport<ImportedModule>)> includeImport) {
|
||||
for (const FileUnit *file : M->getFiles()) {
|
||||
if (const SourceFile *source = dyn_cast<SourceFile>(file)) {
|
||||
if (source->hasImports()) {
|
||||
for (auto import : source->getImports()) {
|
||||
if (import.options.contains(ImportFlags::Exported) &&
|
||||
(!includeImport || includeImport(import)) &&
|
||||
import.module.importedModule->shouldCollectDisplayDecls()) {
|
||||
auto *TheModule = import.module.importedModule;
|
||||
|
||||
if (import.module.getAccessPath().size() > 0) {
|
||||
if (QualifiedImports.find(TheModule) == QualifiedImports.end()) {
|
||||
QualifiedImports.try_emplace(TheModule);
|
||||
}
|
||||
auto collectDecls = [&](ValueDecl *VD,
|
||||
DeclVisibilityKind reason) {
|
||||
if (reason == DeclVisibilityKind::VisibleAtTopLevel)
|
||||
QualifiedImports[TheModule].insert(VD);
|
||||
};
|
||||
auto consumer = makeDeclConsumer(std::move(collectDecls));
|
||||
TheModule->lookupVisibleDecls(
|
||||
import.module.getAccessPath(), consumer,
|
||||
NLKind::UnqualifiedLookup);
|
||||
} else if (!Imports.contains(TheModule)) {
|
||||
Imports.insert(TheModule);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ModuleDecl::getLocalTypeDecls(SmallVectorImpl<TypeDecl*> &Results) const {
|
||||
FORWARD(getLocalTypeDecls, (Results));
|
||||
}
|
||||
@@ -1544,41 +1510,102 @@ SourceFile::getExternalRawLocsForDecl(const Decl *D) const {
|
||||
return Result;
|
||||
}
|
||||
|
||||
void ModuleDecl::getDisplayDecls(SmallVectorImpl<Decl*> &Results, bool Recursive) const {
|
||||
if (Recursive && isParsedModule(this)) {
|
||||
SmallPtrSet<ModuleDecl *, 4> Modules;
|
||||
llvm::SmallDenseMap<ModuleDecl *, SmallPtrSet<Decl *, 4>, 4> QualifiedImports;
|
||||
collectParsedExportedImports(this, Modules, QualifiedImports);
|
||||
for (const auto &QI : QualifiedImports) {
|
||||
auto Module = QI.getFirst();
|
||||
if (Modules.contains(Module)) continue;
|
||||
void ModuleDecl::ImportCollector::collect(
|
||||
const ImportedModule &importedModule) {
|
||||
auto *module = importedModule.importedModule;
|
||||
|
||||
auto &Decls = QI.getSecond();
|
||||
Results.append(Decls.begin(), Decls.end());
|
||||
if (!module->shouldCollectDisplayDecls())
|
||||
return;
|
||||
|
||||
if (importFilter && !importFilter(module))
|
||||
return;
|
||||
|
||||
if (importedModule.getAccessPath().size() > 0) {
|
||||
auto collectDecls = [&](ValueDecl *VD, DeclVisibilityKind reason) {
|
||||
if (reason == DeclVisibilityKind::VisibleAtTopLevel)
|
||||
this->qualifiedImports[module].insert(VD);
|
||||
};
|
||||
auto consumer = makeDeclConsumer(std::move(collectDecls));
|
||||
module->lookupVisibleDecls(importedModule.getAccessPath(), consumer,
|
||||
NLKind::UnqualifiedLookup);
|
||||
} else {
|
||||
imports.insert(module);
|
||||
}
|
||||
for (const ModuleDecl *import : Modules) {
|
||||
import->getDisplayDecls(Results, Recursive);
|
||||
}
|
||||
|
||||
static void
|
||||
collectExportedImports(const ModuleDecl *module,
|
||||
ModuleDecl::ImportCollector &importCollector) {
|
||||
for (const FileUnit *file : module->getFiles()) {
|
||||
if (const SourceFile *source = dyn_cast<SourceFile>(file)) {
|
||||
if (source->hasImports()) {
|
||||
for (const auto &import : source->getImports()) {
|
||||
if (import.options.contains(ImportFlags::Exported) &&
|
||||
import.docVisibility.value_or(AccessLevel::Public) >=
|
||||
importCollector.minimumDocVisibility) {
|
||||
importCollector.collect(import.module);
|
||||
collectExportedImports(import.module.importedModule,
|
||||
importCollector);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
SmallVector<ImportedModule, 8> exportedImports;
|
||||
file->getImportedModules(exportedImports,
|
||||
ModuleDecl::ImportFilterKind::Exported);
|
||||
for (const auto &im : exportedImports) {
|
||||
// Skip collecting the underlying clang module as we already have the relevant import.
|
||||
if (module->isClangOverlayOf(im.importedModule))
|
||||
continue;
|
||||
importCollector.collect(im);
|
||||
collectExportedImports(im.importedModule, importCollector);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ModuleDecl::getDisplayDecls(SmallVectorImpl<Decl*> &Results, bool Recursive) const {
|
||||
if (Recursive) {
|
||||
ImportCollector importCollector;
|
||||
this->getDisplayDeclsRecursivelyAndImports(Results, importCollector);
|
||||
} else {
|
||||
// FIXME: Should this do extra access control filtering?
|
||||
FORWARD(getDisplayDecls, (Results));
|
||||
}
|
||||
}
|
||||
|
||||
void ModuleDecl::getDisplayDeclsRecursivelyAndImports(
|
||||
SmallVectorImpl<Decl *> &results, ImportCollector &importCollector) const {
|
||||
this->getDisplayDecls(results, /*Recursive=*/false);
|
||||
|
||||
// Look up imports recursively.
|
||||
collectExportedImports(this, importCollector);
|
||||
for (const auto &QI : importCollector.qualifiedImports) {
|
||||
auto Module = QI.getFirst();
|
||||
if (importCollector.imports.contains(Module))
|
||||
continue;
|
||||
|
||||
auto &Decls = QI.getSecond();
|
||||
results.append(Decls.begin(), Decls.end());
|
||||
}
|
||||
|
||||
for (const ModuleDecl *import : importCollector.imports)
|
||||
import->getDisplayDecls(results);
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (Recursive) {
|
||||
llvm::DenseSet<Decl *> visited;
|
||||
for (auto *D : Results) {
|
||||
for (auto *D : results) {
|
||||
// decls synthesized from implicit clang decls may appear multiple times;
|
||||
// e.g. if multiple modules with underlying clang modules are re-exported.
|
||||
// including duplicates of these is harmless, so skip them when counting
|
||||
// this assertion
|
||||
if (const auto *CD = D->getClangDecl()) {
|
||||
if (CD->isImplicit()) continue;
|
||||
if (CD->isImplicit())
|
||||
continue;
|
||||
}
|
||||
|
||||
auto inserted = visited.insert(D).second;
|
||||
assert(inserted && "there should be no duplicate decls");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -2394,7 +2421,7 @@ ModuleDecl::getDeclaringModuleAndBystander() {
|
||||
return *(declaringModuleAndBystander = {nullptr, Identifier()});
|
||||
}
|
||||
|
||||
bool ModuleDecl::isClangOverlayOf(ModuleDecl *potentialUnderlying) {
|
||||
bool ModuleDecl::isClangOverlayOf(ModuleDecl *potentialUnderlying) const {
|
||||
return getUnderlyingModuleIfOverlay() == potentialUnderlying;
|
||||
}
|
||||
|
||||
|
||||
@@ -163,6 +163,13 @@ int swift_symbolgraph_extract_main(ArrayRef<const char *> Args,
|
||||
}
|
||||
}
|
||||
|
||||
SmallVector<StringRef, 4> AllowedRexports;
|
||||
if (auto *A =
|
||||
ParsedArgs.getLastArg(OPT_experimental_allowed_reexported_modules)) {
|
||||
for (const auto *val : A->getValues())
|
||||
AllowedRexports.emplace_back(val);
|
||||
}
|
||||
|
||||
symbolgraphgen::SymbolGraphOptions Options;
|
||||
Options.OutputDir = OutputDir;
|
||||
Options.Target = Target;
|
||||
@@ -175,6 +182,7 @@ int swift_symbolgraph_extract_main(ArrayRef<const char *> Args,
|
||||
Options.EmitExtensionBlockSymbols =
|
||||
ParsedArgs.hasFlag(OPT_emit_extension_block_symbols,
|
||||
OPT_omit_extension_block_symbols, /*default=*/false);
|
||||
Options.AllowedReexportedModules = AllowedRexports;
|
||||
|
||||
if (auto *A = ParsedArgs.getLastArg(OPT_minimum_access_level)) {
|
||||
Options.MinimumAccessLevel =
|
||||
|
||||
@@ -10,9 +10,10 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "swift/Sema/IDETypeChecking.h"
|
||||
#include "swift/AST/ASTContext.h"
|
||||
#include "swift/AST/ASTDemangler.h"
|
||||
#include "swift/AST/ASTPrinter.h"
|
||||
#include "swift/AST/ASTContext.h"
|
||||
#include "swift/AST/Attr.h"
|
||||
#include "swift/AST/Decl.h"
|
||||
#include "swift/AST/Expr.h"
|
||||
@@ -25,20 +26,30 @@
|
||||
#include "swift/AST/Requirement.h"
|
||||
#include "swift/AST/SourceFile.h"
|
||||
#include "swift/AST/Types.h"
|
||||
#include "swift/Sema/IDETypeChecking.h"
|
||||
#include "swift/Sema/IDETypeCheckingRequests.h"
|
||||
#include "swift/IDE/SourceEntityWalker.h"
|
||||
#include "swift/IDE/IDERequests.h"
|
||||
#include "swift/IDE/SourceEntityWalker.h"
|
||||
#include "swift/Parse/Lexer.h"
|
||||
#include "swift/Sema/IDETypeCheckingRequests.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
|
||||
using namespace swift;
|
||||
|
||||
void
|
||||
swift::getTopLevelDeclsForDisplay(ModuleDecl *M,
|
||||
SmallVectorImpl<Decl*> &Results,
|
||||
void swift::getTopLevelDeclsForDisplay(ModuleDecl *M,
|
||||
SmallVectorImpl<Decl *> &Results,
|
||||
bool Recursive) {
|
||||
auto startingSize = Results.size();
|
||||
auto getDisplayDeclsForModule =
|
||||
[Recursive](ModuleDecl *M, SmallVectorImpl<Decl *> &Results) {
|
||||
M->getDisplayDecls(Results, Recursive);
|
||||
};
|
||||
getTopLevelDeclsForDisplay(M, Results, std::move(getDisplayDeclsForModule));
|
||||
}
|
||||
|
||||
void swift::getTopLevelDeclsForDisplay(
|
||||
ModuleDecl *M, SmallVectorImpl<Decl *> &Results,
|
||||
llvm::function_ref<void(ModuleDecl *, SmallVectorImpl<Decl *> &)>
|
||||
getDisplayDeclsForModule) {
|
||||
auto startingSize = Results.size();
|
||||
getDisplayDeclsForModule(M, Results);
|
||||
|
||||
// Force Sendable on all public types, which might synthesize some extensions.
|
||||
// FIXME: We can remove this if @_nonSendable stops creating extensions.
|
||||
@@ -48,20 +59,20 @@ swift::getTopLevelDeclsForDisplay(ModuleDecl *M,
|
||||
// Restrict this logic to public and package types. Non-public types
|
||||
// may refer to implementation details and fail at deserialization.
|
||||
auto accessScope = NTD->getFormalAccessScope();
|
||||
if (!M->isMainModule() &&
|
||||
!accessScope.isPublic() && !accessScope.isPackage())
|
||||
if (!M->isMainModule() && !accessScope.isPublic() &&
|
||||
!accessScope.isPackage())
|
||||
continue;
|
||||
|
||||
auto proto = M->getASTContext().getProtocol(KnownProtocolKind::Sendable);
|
||||
if (proto)
|
||||
(void) M->lookupConformance(NTD->getDeclaredInterfaceType(), proto);
|
||||
(void)M->lookupConformance(NTD->getDeclaredInterfaceType(), proto);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove what we fetched and fetch again, possibly now with additional
|
||||
// extensions.
|
||||
Results.resize(startingSize);
|
||||
M->getDisplayDecls(Results, Recursive);
|
||||
getDisplayDeclsForModule(M, Results);
|
||||
}
|
||||
|
||||
static bool shouldPrintAsFavorable(const Decl *D, const PrintOptions &Options) {
|
||||
|
||||
@@ -43,9 +43,14 @@ bool areModulesEqual(const ModuleDecl *lhs, const ModuleDecl *rhs, bool isClangE
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
SymbolGraphASTWalker::SymbolGraphASTWalker(ModuleDecl &M,
|
||||
const SymbolGraphOptions &Options)
|
||||
: Options(Options), M(M), MainGraph(*this, M, std::nullopt, Ctx) {}
|
||||
|
||||
SymbolGraphASTWalker::SymbolGraphASTWalker(
|
||||
ModuleDecl &M, const SmallPtrSet<ModuleDecl *, 4> ExportedImportedModules,
|
||||
const llvm::SmallDenseMap<ModuleDecl *, SmallPtrSet<Decl *, 4>, 4>
|
||||
ModuleDecl &M,
|
||||
const SmallPtrSet<const ModuleDecl *, 4> ExportedImportedModules,
|
||||
const llvm::SmallDenseMap<const ModuleDecl *, SmallPtrSet<Decl *, 4>, 4>
|
||||
QualifiedExportedImports,
|
||||
const SymbolGraphOptions &Options)
|
||||
: Options(Options), M(M), ExportedImportedModules(ExportedImportedModules),
|
||||
|
||||
@@ -48,9 +48,10 @@ struct SymbolGraphASTWalker : public SourceEntityWalker {
|
||||
const ModuleDecl &M;
|
||||
|
||||
// FIXME: these should be tracked per-graph, rather than at the top level
|
||||
const SmallPtrSet<ModuleDecl *, 4> ExportedImportedModules;
|
||||
const SmallPtrSet<const ModuleDecl *, 4> ExportedImportedModules;
|
||||
|
||||
const llvm::SmallDenseMap<ModuleDecl *, SmallPtrSet<Decl *, 4>, 4> QualifiedExportedImports;
|
||||
const llvm::SmallDenseMap<const ModuleDecl *, SmallPtrSet<Decl *, 4>, 4>
|
||||
QualifiedExportedImports;
|
||||
|
||||
/// The symbol graph for the main module of interest.
|
||||
SymbolGraph MainGraph;
|
||||
@@ -60,10 +61,14 @@ struct SymbolGraphASTWalker : public SourceEntityWalker {
|
||||
|
||||
// MARK: - Initialization
|
||||
|
||||
SymbolGraphASTWalker(ModuleDecl &M,
|
||||
const SmallPtrSet<ModuleDecl *, 4> ExportedImportedModules,
|
||||
const llvm::SmallDenseMap<ModuleDecl *, SmallPtrSet<Decl *, 4>, 4> QualifiedExportedImports,
|
||||
SymbolGraphASTWalker(
|
||||
ModuleDecl &M,
|
||||
const SmallPtrSet<const ModuleDecl *, 4> ExportedImportedModules,
|
||||
const llvm::SmallDenseMap<const ModuleDecl *, SmallPtrSet<Decl *, 4>, 4>
|
||||
QualifiedExportedImports,
|
||||
const SymbolGraphOptions &Options);
|
||||
|
||||
SymbolGraphASTWalker(ModuleDecl &M, const SymbolGraphOptions &Options);
|
||||
virtual ~SymbolGraphASTWalker() {}
|
||||
|
||||
// MARK: - Utilities
|
||||
|
||||
@@ -10,12 +10,16 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Support/JSON.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "swift/SymbolGraphGen/SymbolGraphGen.h"
|
||||
#include "swift/AST/ASTContext.h"
|
||||
#include "swift/AST/FileSystem.h"
|
||||
#include "swift/AST/Import.h"
|
||||
#include "swift/AST/Module.h"
|
||||
#include "swift/AST/NameLookup.h"
|
||||
#include "swift/Sema/IDETypeChecking.h"
|
||||
#include "swift/SymbolGraphGen/SymbolGraphGen.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/Support/JSON.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
|
||||
#include "SymbolGraphASTWalker.h"
|
||||
|
||||
@@ -54,25 +58,36 @@ int serializeSymbolGraph(SymbolGraph &SG,
|
||||
// MARK: - Main Entry Point
|
||||
|
||||
/// Emit a symbol graph JSON file for a `ModuleDecl`.
|
||||
int
|
||||
symbolgraphgen::emitSymbolGraphForModule(ModuleDecl *M,
|
||||
const SymbolGraphOptions &Options) {
|
||||
SmallVector<Decl *, 64> ModuleDecls;
|
||||
swift::getTopLevelDeclsForDisplay(M, ModuleDecls, /*recursive*/true);
|
||||
int symbolgraphgen::emitSymbolGraphForModule(
|
||||
ModuleDecl *M, const SymbolGraphOptions &Options) {
|
||||
ModuleDecl::ImportCollector importCollector(Options.MinimumAccessLevel);
|
||||
|
||||
SmallPtrSet<ModuleDecl *, 4> ExportedImportedModules;
|
||||
llvm::SmallDenseMap<ModuleDecl *, SmallPtrSet<Decl *, 4>, 4> QualifiedImports;
|
||||
auto shouldIncludeImport = [&](AttributedImport<ImportedModule> import) {
|
||||
auto docVisibility = import.docVisibility.value_or(AccessLevel::Public);
|
||||
return docVisibility >= Options.MinimumAccessLevel;
|
||||
auto importFilter = [&Options](const ModuleDecl *module) {
|
||||
if (!module)
|
||||
return false;
|
||||
|
||||
for (const auto &allowedModuleName : *Options.AllowedReexportedModules)
|
||||
if (allowedModuleName == module->getNameStr())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
};
|
||||
swift::collectParsedExportedImports(M, ExportedImportedModules, QualifiedImports, shouldIncludeImport);
|
||||
|
||||
if (Options.AllowedReexportedModules.has_value())
|
||||
importCollector.importFilter = std::move(importFilter);
|
||||
|
||||
SmallVector<Decl *, 64> ModuleDecls;
|
||||
swift::getTopLevelDeclsForDisplay(
|
||||
M, ModuleDecls, [&importCollector](ModuleDecl *M, SmallVectorImpl<Decl *> &results) {
|
||||
M->getDisplayDeclsRecursivelyAndImports(results, importCollector);
|
||||
});
|
||||
|
||||
if (Options.PrintMessages)
|
||||
llvm::errs() << ModuleDecls.size()
|
||||
<< " top-level declarations in this module.\n";
|
||||
|
||||
SymbolGraphASTWalker Walker(*M, ExportedImportedModules, QualifiedImports, Options);
|
||||
SymbolGraphASTWalker Walker(*M, importCollector.imports,
|
||||
importCollector.qualifiedImports, Options);
|
||||
|
||||
for (auto *Decl : ModuleDecls) {
|
||||
Walker.walk(Decl);
|
||||
@@ -109,8 +124,7 @@ printSymbolGraphForDecl(const ValueDecl *D, Type BaseTy,
|
||||
|
||||
llvm::json::OStream JOS(OS, Options.PrettyPrint ? 2 : 0);
|
||||
ModuleDecl *MD = D->getModuleContext();
|
||||
llvm::SmallDenseMap<ModuleDecl *, SmallPtrSet<Decl *, 4>, 4> QualifiedImports;
|
||||
SymbolGraphASTWalker Walker(*MD, {}, QualifiedImports, Options);
|
||||
SymbolGraphASTWalker Walker(*MD, Options);
|
||||
markup::MarkupContext MarkupCtx;
|
||||
SymbolGraph Graph(Walker, *MD, std::nullopt, MarkupCtx, std::nullopt,
|
||||
/*IsForSingleNode=*/true);
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %empty-directory(%t/module-generated)
|
||||
// RUN: cp -r %S/Inputs/ExportedImport/ObjcProperty.framework %t
|
||||
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -enable-objc-interop -emit-module -o %t/ObjcProperty.framework/Modules/ObjcProperty.swiftmodule/%target-swiftmodule-name -import-underlying-module -F %t -module-name ObjcProperty %S/Inputs/ExportedImport/A.swift
|
||||
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -enable-objc-interop -emit-module -o %t/ExportedImport.swiftmodule -F %t -module-name ExportedImport %s -emit-symbol-graph -emit-symbol-graph-dir %t
|
||||
// RUN: %target-swift-frontend -emit-module -o %t/ExportedImport.swiftmodule -F %t -module-name ExportedImport %s -emit-symbol-graph -emit-symbol-graph-dir %t
|
||||
// RUN: %FileCheck %s --input-file %t/ExportedImport.symbols.json
|
||||
// RUN: %target-swift-symbolgraph-extract -sdk %clang-importer-sdk -module-name ExportedImport -I %t \
|
||||
// RUN: -output-dir %t/module-generated/ -experimental-allowed-reexported-modules=ObjcProperty
|
||||
// RUN: %FileCheck %s --input-file %t/module-generated/ExportedImport.symbols.json
|
||||
|
||||
// REQUIRES: objc_interop
|
||||
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
// INTERNAL-DAG: "precise":"s:1A11SymbolFromAV"
|
||||
// INTERNAL-DAG: "precise":"s:1B9StructOneV"
|
||||
|
||||
// FIXME: Symbols from `@_exported import` do not get emitted when using swift-symbolgraph-extract
|
||||
// This is tracked by https://github.com/apple/swift-docc/issues/179.
|
||||
// FIXME: Functionality doesn't currently work swift-symbolgraph-extract as documentation visibility attribute isn't
|
||||
// exposed in the module interface
|
||||
|
||||
// FILES-NOT: DocAttrExportedImport@A.symbols.json
|
||||
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %empty-directory(%t/module-generated)
|
||||
// RUN: %target-swift-frontend %S/Inputs/DuplicateExportedImport/A.swift -module-name A -emit-module -emit-module-path %t/A.swiftmodule
|
||||
// RUN: %target-swift-frontend %s -module-name DuplicateExportedImport -emit-module -emit-module-path /dev/null -I %t -emit-symbol-graph -emit-symbol-graph-dir %t/
|
||||
// RUN: %target-swift-frontend %s -module-name DuplicateExportedImport -emit-module -emit-module-path \
|
||||
// RUN: %t/DuplicateExportedImport.swiftmodule -I %t -emit-symbol-graph -emit-symbol-graph-dir %t/
|
||||
// RUN: %FileCheck %s --input-file %t/DuplicateExportedImport.symbols.json
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name DuplicateExportedImport -I %t -output-dir %t/module-generated/ \
|
||||
// RUN: -experimental-allowed-reexported-modules=A
|
||||
// RUN: %FileCheck %s --input-file %t/module-generated/DuplicateExportedImport.symbols.json
|
||||
|
||||
// REQUIRES: asserts
|
||||
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %empty-directory(%t/module-generated)
|
||||
// RUN: %target-swift-frontend %S/Inputs/ExportedImport/A.swift -module-name A -emit-module -emit-module-path %t/A.swiftmodule
|
||||
// RUN: %target-swift-frontend %S/Inputs/ExportedImport/B.swift -module-name B -emit-module -emit-module-path %t/B.swiftmodule
|
||||
// RUN: %target-swift-frontend %s -module-name ExportedImport -emit-module -emit-module-path /dev/null -I %t -emit-symbol-graph -emit-symbol-graph-dir %t/
|
||||
// RUN: %target-swift-frontend %s -module-name ExportedImport -emit-module -emit-module-path \
|
||||
// RUN: %t/ExportedImport.swiftmodule -I %t -emit-symbol-graph -emit-symbol-graph-dir %t/
|
||||
// RUN: %FileCheck %s --input-file %t/ExportedImport.symbols.json
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name ExportedImport -I %t -output-dir \
|
||||
// RUN: %t/module-generated/ -experimental-allowed-reexported-modules=A,B
|
||||
// RUN: %FileCheck %s --input-file %t/module-generated/ExportedImport.symbols.json
|
||||
// RUN: ls %t | %FileCheck %s --check-prefix FILES
|
||||
// RUN: ls %t/module-generated/ | %FileCheck %s --check-prefix FILES
|
||||
|
||||
@_exported import A
|
||||
@_exported import struct B.StructOne
|
||||
@@ -13,7 +19,4 @@
|
||||
// CHECK-DAG: "precise":"s:1A11SymbolFromAV"
|
||||
// CHECK-DAG: "precise":"s:1B9StructOneV"
|
||||
|
||||
// FIXME: Symbols from `@_exported import` do not get emitted when using swift-symbolgraph-extract
|
||||
// This is tracked by https://github.com/apple/swift-docc/issues/179.
|
||||
|
||||
// FILES-NOT: ExportedImport@A.symbols.json
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %empty-directory(%t/module-generated)
|
||||
// RUN: %target-swift-frontend %S/Inputs/ExportedImportExtensions/A.swift -module-name A -emit-module -emit-module-path %t/A.swiftmodule
|
||||
// RUN: %target-swift-frontend %S/Inputs/ExportedImportExtensions/B.swift -module-name B -emit-module -emit-module-path %t/B.swiftmodule -I %t
|
||||
// RUN: %target-swift-frontend %s -module-name ExportedImportExtensions -emit-module -emit-module-path /dev/null -I %t -emit-symbol-graph -emit-symbol-graph-dir %t/ -emit-extension-block-symbols
|
||||
// RUN: %target-swift-frontend %s -module-name ExportedImportExtensions -emit-module -emit-module-path \
|
||||
// RUN: %t/ExportedImportExtensions.swiftmodule -I %t -emit-symbol-graph -emit-symbol-graph-dir %t/ -emit-extension-block-symbols
|
||||
// RUN: %FileCheck %s --input-file %t/ExportedImportExtensions.symbols.json
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name ExportedImportExtensions -I %t -output-dir %t/module-generated/ \
|
||||
// RUN: -emit-extension-block-symbols -experimental-allowed-reexported-modules=A,B
|
||||
// RUN: %FileCheck %s --input-file %t/module-generated/ExportedImportExtensions.symbols.json
|
||||
// RUN: ls %t | %FileCheck %s --check-prefix FILES
|
||||
// RUN: ls %t/module-generated/ | %FileCheck %s --check-prefix FILES
|
||||
|
||||
@_exported import A
|
||||
@_exported import B
|
||||
@@ -45,9 +51,6 @@ extension SymbolFromB: P {
|
||||
// CHECK-DAG: {"kind":"memberOf","source":"s:1B11SymbolFromBV24ExportedImportExtensionsE12pRequirementyyF","target":"s:1B11SymbolFromBV","targetFallback":"B.SymbolFromB","sourceOrigin":{"identifier":"s:24ExportedImportExtensions1PP12pRequirementyyF","displayName":"P.pRequirement()"}}
|
||||
// CHECK-DAG: {"kind":"conformsTo","source":"s:1B11SymbolFromBV","target":"s:24ExportedImportExtensions1PP"}
|
||||
|
||||
// FIXME: Symbols from `@_exported import` do not get emitted when using swift-symbolgraph-extract
|
||||
// This is tracked by https://github.com/apple/swift-docc/issues/179.
|
||||
|
||||
// FILES-NOT: ExportedImportExtensions@A.symbols.json
|
||||
// FILES-NOT: ExportedImportExtensions@B.symbols.json
|
||||
// FILES-NOT: A@B.symbols.json
|
||||
|
||||
29
test/SymbolGraph/Module/NestedExportedImport.swift
Normal file
29
test/SymbolGraph/Module/NestedExportedImport.swift
Normal file
@@ -0,0 +1,29 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %empty-directory(%t/module-generated)
|
||||
// RUN: split-file %s %t
|
||||
// RUN: %target-swift-frontend %t/A.swift -module-name A -emit-module -emit-module-path %t/A.swiftmodule
|
||||
// RUN: %target-swift-frontend %t/B.swift -module-name B -emit-module -emit-module-path %t/B.swiftmodule -I %t
|
||||
// RUN: %target-swift-frontend %t/C.swift -module-name C -emit-module -emit-module-path %t/C.swiftmodule -I %t \
|
||||
// RUN: -emit-symbol-graph -emit-symbol-graph-dir %t
|
||||
// RUN: %target-swift-symbolgraph-extract -module-name C -I %t -output-dir \
|
||||
// RUN: %t/module-generated/ -experimental-allowed-reexported-modules=A,B
|
||||
// RUN: %FileCheck %s --input-file %t/C.symbols.json
|
||||
// RUN: %FileCheck %s --input-file %t/module-generated/C.symbols.json
|
||||
|
||||
//--- A.swift
|
||||
public struct A {}
|
||||
public func AFunc() -> Void {}
|
||||
|
||||
//--- B.swift
|
||||
@_exported import A
|
||||
public struct B {}
|
||||
public func BFunc() -> Void {}
|
||||
|
||||
//--- C.swift
|
||||
@_exported import B
|
||||
public struct C {}
|
||||
public func CFunc() -> Void {}
|
||||
|
||||
// CHECK-DAG: "precise":"s:1CAAV"
|
||||
// CHECK-DAG: "precise":"s:1BAAV"
|
||||
// CHECK-DAG: "precise":"s:1AAAV"
|
||||
Reference in New Issue
Block a user