Skip to content

Cache visible Clang modules for interface printing in ModuleDecl #74307

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions include/swift/AST/Module.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MD5.h"
#include <optional>
#include <unordered_map>
#include <set>

namespace clang {
Expand Down Expand Up @@ -537,6 +538,11 @@ class ModuleDecl
std::optional<std::pair<ModuleDecl *, Identifier>>
declaringModuleAndBystander;

/// A cache of this module's visible Clang modules
/// parameterized by the Swift interface print mode.
using VisibleClangModuleSet = llvm::DenseMap<const clang::Module *, ModuleDecl *>;
std::unordered_map<PrintOptions::InterfaceMode, VisibleClangModuleSet> CachedVisibleClangModuleSet;

/// If this module is an underscored cross import overlay, gets the underlying
/// module that declared it (which may itself be a cross-import overlay),
/// along with the name of the required bystander module. Used by tooling to
Expand Down Expand Up @@ -578,6 +584,14 @@ class ModuleDecl
bool getRequiredBystandersIfCrossImportOverlay(
ModuleDecl *declaring, SmallVectorImpl<Identifier> &bystanderNames);

/// Computes all Clang modules that are visible from this moule.
/// This includes any modules that are imported transitively through public
/// (`@_exported`) imports.
///
/// The computed map associates each visible Clang module with the
/// corresponding Swift module.
const VisibleClangModuleSet &
getVisibleClangModules(PrintOptions::InterfaceMode contentMode);

/// Walks and loads the declared, underscored cross-import overlays of this
/// module and its underlying clang module, transitively, to find all cross
Expand Down
57 changes: 1 addition & 56 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5724,8 +5724,6 @@ class TypePrinter : public TypeVisitor<TypePrinter> {

ASTPrinter &Printer;
const PrintOptions &Options;
std::optional<llvm::DenseMap<const clang::Module *, ModuleDecl *>>
VisibleClangModules;

void printGenericArgs(ArrayRef<Type> flatArgs) {
Printer << "<";
Expand Down Expand Up @@ -5799,56 +5797,6 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
return T->hasSimpleTypeRepr();
}

/// Computes the map that is cached by `getVisibleClangModules()`.
/// Do not call directly.
llvm::DenseMap<const clang::Module *, ModuleDecl *>
computeVisibleClangModules() {
assert(Options.CurrentModule &&
"CurrentModule needs to be set to determine imported Clang modules");

llvm::DenseMap<const clang::Module *, ModuleDecl *> Result;

// For the current module, consider both private and public imports.
ModuleDecl::ImportFilter Filter = ModuleDecl::ImportFilterKind::Exported;
Filter |= ModuleDecl::ImportFilterKind::Default;

// For private or package swiftinterfaces, also look through @_spiOnly imports.
if (!Options.printPublicInterface())
Filter |= ModuleDecl::ImportFilterKind::SPIOnly;
// Consider package import for package interface
if (Options.printPackageInterface())
Filter |= ModuleDecl::ImportFilterKind::PackageOnly;

SmallVector<ImportedModule, 4> Imports;
Options.CurrentModule->getImportedModules(Imports, Filter);

SmallVector<ModuleDecl *, 4> ModulesToProcess;
for (const auto &Import : Imports) {
ModulesToProcess.push_back(Import.importedModule);
}

SmallPtrSet<ModuleDecl *, 4> Processed;
while (!ModulesToProcess.empty()) {
ModuleDecl *Mod = ModulesToProcess.back();
ModulesToProcess.pop_back();

if (!Processed.insert(Mod).second)
continue;

if (const clang::Module *ClangModule = Mod->findUnderlyingClangModule())
Result[ClangModule] = Mod;

// For transitive imports, consider only public imports.
Imports.clear();
Mod->getImportedModules(Imports, ModuleDecl::ImportFilterKind::Exported);
for (const auto &Import : Imports) {
ModulesToProcess.push_back(Import.importedModule);
}
}

return Result;
}

/// Returns all Clang modules that are visible from `Options.CurrentModule`.
/// This includes any modules that are imported transitively through public
/// (`@_exported`) imports.
Expand All @@ -5857,10 +5805,7 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
/// corresponding Swift module.
const llvm::DenseMap<const clang::Module *, ModuleDecl *> &
getVisibleClangModules() {
if (!VisibleClangModules) {
VisibleClangModules = computeVisibleClangModules();
}
return *VisibleClangModules;
return Options.CurrentModule->getVisibleClangModules(Options.InterfaceContentKind);
}

template <typename T>
Expand Down
48 changes: 48 additions & 0 deletions lib/AST/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1719,6 +1719,54 @@ void ModuleDecl::getMissingImportedModules(
FORWARD(getMissingImportedModules, (imports));
}

const llvm::DenseMap<const clang::Module *, ModuleDecl *> &
ModuleDecl::getVisibleClangModules(PrintOptions::InterfaceMode contentMode) {
if (CachedVisibleClangModuleSet.find(contentMode) != CachedVisibleClangModuleSet.end())
return CachedVisibleClangModuleSet[contentMode];
else
CachedVisibleClangModuleSet.emplace(contentMode, VisibleClangModuleSet{});
VisibleClangModuleSet &result = CachedVisibleClangModuleSet[contentMode];

// For the current module, consider both private and public imports.
ModuleDecl::ImportFilter Filter = ModuleDecl::ImportFilterKind::Exported;
Filter |= ModuleDecl::ImportFilterKind::Default;

// For private or package swiftinterfaces, also look through @_spiOnly imports.
if (contentMode != PrintOptions::InterfaceMode::Public)
Filter |= ModuleDecl::ImportFilterKind::SPIOnly;
// Consider package import for package interface
if (contentMode == PrintOptions::InterfaceMode::Package)
Filter |= ModuleDecl::ImportFilterKind::PackageOnly;

SmallVector<ImportedModule, 32> Imports;
getImportedModules(Imports, Filter);

SmallVector<ModuleDecl *, 32> ModulesToProcess;
for (const auto &Import : Imports)
ModulesToProcess.push_back(Import.importedModule);

SmallPtrSet<ModuleDecl *, 32> Processed;
while (!ModulesToProcess.empty()) {
ModuleDecl *Mod = ModulesToProcess.back();
ModulesToProcess.pop_back();

if (!Processed.insert(Mod).second)
continue;

if (const clang::Module *ClangModule = Mod->findUnderlyingClangModule())
result[ClangModule] = Mod;

// For transitive imports, consider only public imports.
Imports.clear();
Mod->getImportedModules(Imports, ModuleDecl::ImportFilterKind::Exported);
for (const auto &Import : Imports) {
ModulesToProcess.push_back(Import.importedModule);
}
}

return result;
}

void
SourceFile::getImportedModules(SmallVectorImpl<ImportedModule> &modules,
ModuleDecl::ImportFilter filter) const {
Expand Down