mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[AST] Rewrite collectExportedImports() to be non-recursive.
The issue with recursion here is that if there are enough modules involved, this function will blow the process stack, particularly in the case where the `FileUnit`s are not `SourceFile`s, since in that instance a `SmallVector` gets allocated on the stack for each level of the recursion. rdar://130527640
This commit is contained in:
@@ -1535,31 +1535,36 @@ void ModuleDecl::ImportCollector::collect(
|
||||
}
|
||||
|
||||
static void
|
||||
collectExportedImports(const ModuleDecl *module,
|
||||
collectExportedImports(const ModuleDecl *topLevelModule,
|
||||
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);
|
||||
SmallVector<const ModuleDecl *> stack;
|
||||
stack.push_back(topLevelModule);
|
||||
while (!stack.empty()) {
|
||||
const ModuleDecl *module = stack.pop_back_val();
|
||||
|
||||
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);
|
||||
stack.push_back(import.module.importedModule);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} 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);
|
||||
} 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);
|
||||
stack.push_back(im.importedModule);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user