[Dependency Scanning] Keep track of whether a given Swift 'import' statement is '@_exported'

This commit is contained in:
Artem Chikin
2025-02-26 15:52:46 -08:00
parent 714c862d37
commit 809dbf0994
8 changed files with 70 additions and 40 deletions

View File

@@ -154,12 +154,14 @@ struct ScannerImportStatementInfo {
uint32_t columnNumber; uint32_t columnNumber;
}; };
ScannerImportStatementInfo(std::string importIdentifier) ScannerImportStatementInfo(std::string importIdentifier, bool isExported)
: importLocations(), importIdentifier(importIdentifier) {} : importLocations(), importIdentifier(importIdentifier),
isExported(isExported) {}
ScannerImportStatementInfo(std::string importIdentifier, ScannerImportStatementInfo(std::string importIdentifier, bool isExported,
ImportDiagnosticLocationInfo location) ImportDiagnosticLocationInfo location)
: importLocations({location}), importIdentifier(importIdentifier) {} : importLocations({location}), importIdentifier(importIdentifier),
isExported(isExported) {}
void addImportLocation(ImportDiagnosticLocationInfo location) { void addImportLocation(ImportDiagnosticLocationInfo location) {
importLocations.push_back(location); importLocations.push_back(location);
@@ -169,6 +171,8 @@ struct ScannerImportStatementInfo {
SmallVector<ImportDiagnosticLocationInfo, 4> importLocations; SmallVector<ImportDiagnosticLocationInfo, 4> importLocations;
/// Imported module string. e.g. "Foo.Bar" in 'import Foo.Bar' /// Imported module string. e.g. "Foo.Bar" in 'import Foo.Bar'
std::string importIdentifier; std::string importIdentifier;
/// Is this an @_exported import
bool isExported;
}; };
/// Base class for the variant storage of ModuleDependencyInfo. /// Base class for the variant storage of ModuleDependencyInfo.
@@ -927,7 +931,7 @@ public:
/// Add a dependency on the given module, if it was not already in the set. /// Add a dependency on the given module, if it was not already in the set.
void void
addOptionalModuleImport(StringRef module, addOptionalModuleImport(StringRef module, bool isExported,
llvm::StringSet<> *alreadyAddedModules = nullptr); llvm::StringSet<> *alreadyAddedModules = nullptr);
/// Add all of the module imports in the given source /// Add all of the module imports in the given source
@@ -937,13 +941,13 @@ public:
const SourceManager *sourceManager); const SourceManager *sourceManager);
/// Add a dependency on the given module, if it was not already in the set. /// Add a dependency on the given module, if it was not already in the set.
void addModuleImport(ImportPath::Module module, void addModuleImport(ImportPath::Module module, bool isExported,
llvm::StringSet<> *alreadyAddedModules = nullptr, llvm::StringSet<> *alreadyAddedModules = nullptr,
const SourceManager *sourceManager = nullptr, const SourceManager *sourceManager = nullptr,
SourceLoc sourceLocation = SourceLoc()); SourceLoc sourceLocation = SourceLoc());
/// Add a dependency on the given module, if it was not already in the set. /// Add a dependency on the given module, if it was not already in the set.
void addModuleImport(StringRef module, void addModuleImport(StringRef module, bool isExported,
llvm::StringSet<> *alreadyAddedModules = nullptr, llvm::StringSet<> *alreadyAddedModules = nullptr,
const SourceManager *sourceManager = nullptr, const SourceManager *sourceManager = nullptr,
SourceLoc sourceLocation = SourceLoc()); SourceLoc sourceLocation = SourceLoc());

View File

@@ -60,6 +60,8 @@ using IsStaticField = BCFixed<1>;
using IsForceLoadField = BCFixed<1>; using IsForceLoadField = BCFixed<1>;
/// A bit taht indicates whether or not an import statement is optional /// A bit taht indicates whether or not an import statement is optional
using IsOptionalImport = BCFixed<1>; using IsOptionalImport = BCFixed<1>;
/// A bit taht indicates whether or not an import statement is @_exported
using IsExportedImport = BCFixed<1>;
/// Source location fields /// Source location fields
using LineNumberField = BCFixed<32>; using LineNumberField = BCFixed<32>;
@@ -176,7 +178,8 @@ using ImportStatementLayout =
IdentifierIDField, // bufferIdentifier IdentifierIDField, // bufferIdentifier
LineNumberField, // lineNumber LineNumberField, // lineNumber
ColumnNumberField, // columnNumber ColumnNumberField, // columnNumber
IsOptionalImport // isOptional IsOptionalImport, // isOptional
IsExportedImport // isExported
>; >;
using ImportStatementArrayLayout = using ImportStatementArrayLayout =
BCRecordLayout<IMPORT_STATEMENT_ARRAY_NODE, IdentifierIDArryField>; BCRecordLayout<IMPORT_STATEMENT_ARRAY_NODE, IdentifierIDArryField>;

View File

@@ -171,6 +171,7 @@ protected:
struct BinaryModuleImports { struct BinaryModuleImports {
llvm::StringSet<> moduleImports; llvm::StringSet<> moduleImports;
llvm::StringSet<> exportedModules;
std::string headerImport; std::string headerImport;
}; };
@@ -185,7 +186,7 @@ protected:
/// If the module has a package name matching the one /// If the module has a package name matching the one
/// specified, return a set of package-only imports for this module. /// specified, return a set of package-only imports for this module.
static llvm::ErrorOr<llvm::StringSet<>> static llvm::ErrorOr<std::vector<ScannerImportStatementInfo>>
getMatchingPackageOnlyImportsOfModule(Twine modulePath, getMatchingPackageOnlyImportsOfModule(Twine modulePath,
bool isFramework, bool isFramework,
bool isRequiredOSSAModules, bool isRequiredOSSAModules,

View File

@@ -117,16 +117,16 @@ bool ModuleDependencyInfo::isTestableImport(StringRef moduleName) const {
} }
void ModuleDependencyInfo::addOptionalModuleImport( void ModuleDependencyInfo::addOptionalModuleImport(
StringRef module, llvm::StringSet<> *alreadyAddedModules) { StringRef module, bool isExported, llvm::StringSet<> *alreadyAddedModules) {
if (!alreadyAddedModules || alreadyAddedModules->insert(module).second) if (!alreadyAddedModules || alreadyAddedModules->insert(module).second)
storage->optionalModuleImports.push_back(module.str()); storage->optionalModuleImports.push_back({module.str(), isExported});
} }
void ModuleDependencyInfo::addModuleImport( void ModuleDependencyInfo::addModuleImport(
StringRef module, llvm::StringSet<> *alreadyAddedModules, StringRef module, bool isExported, llvm::StringSet<> *alreadyAddedModules,
const SourceManager *sourceManager, SourceLoc sourceLocation) { const SourceManager *sourceManager, SourceLoc sourceLocation) {
auto scannerImportLocToDiagnosticLocInfo = auto scannerImportLocToDiagnosticLocInfo =
[&sourceManager](SourceLoc sourceLocation) { [&sourceManager, isExported](SourceLoc sourceLocation) {
auto lineAndColumnNumbers = auto lineAndColumnNumbers =
sourceManager->getLineAndColumnInBuffer(sourceLocation); sourceManager->getLineAndColumnInBuffer(sourceLocation);
return ScannerImportStatementInfo::ImportDiagnosticLocationInfo( return ScannerImportStatementInfo::ImportDiagnosticLocationInfo(
@@ -137,14 +137,16 @@ void ModuleDependencyInfo::addModuleImport(
sourceManager->isOwning(sourceLocation); sourceManager->isOwning(sourceLocation);
if (alreadyAddedModules && alreadyAddedModules->contains(module)) { if (alreadyAddedModules && alreadyAddedModules->contains(module)) {
if (validSourceLocation) {
// Find a prior import of this module and add import location // Find a prior import of this module and add import location
// and adjust whether or not this module is ever imported as exported
for (auto &existingImport : storage->moduleImports) { for (auto &existingImport : storage->moduleImports) {
if (existingImport.importIdentifier == module) { if (existingImport.importIdentifier == module) {
if (validSourceLocation) {
existingImport.addImportLocation( existingImport.addImportLocation(
scannerImportLocToDiagnosticLocInfo(sourceLocation)); scannerImportLocToDiagnosticLocInfo(sourceLocation));
break;
} }
existingImport.isExported |= isExported;
break;
} }
} }
} else { } else {
@@ -153,15 +155,15 @@ void ModuleDependencyInfo::addModuleImport(
if (validSourceLocation) if (validSourceLocation)
storage->moduleImports.push_back(ScannerImportStatementInfo( storage->moduleImports.push_back(ScannerImportStatementInfo(
module.str(), scannerImportLocToDiagnosticLocInfo(sourceLocation))); module.str(), isExported, scannerImportLocToDiagnosticLocInfo(sourceLocation)));
else else
storage->moduleImports.push_back( storage->moduleImports.push_back(
ScannerImportStatementInfo(module.str())); ScannerImportStatementInfo(module.str(), isExported));
} }
} }
void ModuleDependencyInfo::addModuleImport( void ModuleDependencyInfo::addModuleImport(
ImportPath::Module module, llvm::StringSet<> *alreadyAddedModules, ImportPath::Module module, bool isExported, llvm::StringSet<> *alreadyAddedModules,
const SourceManager *sourceManager, SourceLoc sourceLocation) { const SourceManager *sourceManager, SourceLoc sourceLocation) {
std::string ImportedModuleName = module.front().Item.str().str(); std::string ImportedModuleName = module.front().Item.str().str();
auto submodulePath = module.getSubmodulePath(); auto submodulePath = module.getSubmodulePath();
@@ -174,7 +176,7 @@ void ModuleDependencyInfo::addModuleImport(
alreadyAddedModules); alreadyAddedModules);
} }
addModuleImport(ImportedModuleName, alreadyAddedModules, addModuleImport(ImportedModuleName, isExported, alreadyAddedModules,
sourceManager, sourceLocation); sourceManager, sourceLocation);
} }
@@ -203,7 +205,8 @@ void ModuleDependencyInfo::addModuleImports(
importDecl->isExported())) importDecl->isExported()))
continue; continue;
addModuleImport(realPath, &alreadyAddedModules, sourceManager, addModuleImport(realPath, importDecl->isExported(),
&alreadyAddedModules, sourceManager,
importDecl->getLoc()); importDecl->getLoc());
// Additionally, keep track of which dependencies of a Source // Additionally, keep track of which dependencies of a Source

View File

@@ -240,10 +240,12 @@ bool ModuleDependenciesCacheDeserializer::readGraph(
&macroDependencies](ModuleDependencyInfo &moduleDep) { &macroDependencies](ModuleDependencyInfo &moduleDep) {
// Add imports of this module // Add imports of this module
for (const auto &moduleName : currentModuleImports) for (const auto &moduleName : currentModuleImports)
moduleDep.addModuleImport(moduleName.importIdentifier); moduleDep.addModuleImport(moduleName.importIdentifier,
moduleName.isExported);
// Add optional imports of this module // Add optional imports of this module
for (const auto &moduleName : currentOptionalModuleImports) for (const auto &moduleName : currentOptionalModuleImports)
moduleDep.addOptionalModuleImport(moduleName.importIdentifier); moduleDep.addOptionalModuleImport(moduleName.importIdentifier,
moduleName.isExported);
// Add qualified dependencies of this module // Add qualified dependencies of this module
moduleDep.setImportedClangDependencies(importedClangDependenciesIDs); moduleDep.setImportedClangDependencies(importedClangDependenciesIDs);
@@ -408,10 +410,10 @@ bool ModuleDependenciesCacheDeserializer::readGraph(
case IMPORT_STATEMENT_NODE: { case IMPORT_STATEMENT_NODE: {
unsigned importIdentifierID, bufferIdentifierID; unsigned importIdentifierID, bufferIdentifierID;
unsigned lineNumber, columnNumber; unsigned lineNumber, columnNumber;
bool isOptional; bool isOptional, isExported;
ImportStatementLayout::readRecord(Scratch, importIdentifierID, ImportStatementLayout::readRecord(Scratch, importIdentifierID,
bufferIdentifierID, lineNumber, bufferIdentifierID, lineNumber,
columnNumber, isOptional); columnNumber, isOptional, isExported);
auto importIdentifier = getIdentifier(importIdentifierID); auto importIdentifier = getIdentifier(importIdentifierID);
if (!importIdentifier) if (!importIdentifier)
llvm::report_fatal_error("Bad import statement info: no import name"); llvm::report_fatal_error("Bad import statement info: no import name");
@@ -421,7 +423,7 @@ bool ModuleDependenciesCacheDeserializer::readGraph(
llvm::report_fatal_error( llvm::report_fatal_error(
"Bad import statement info: no buffer identifier"); "Bad import statement info: no buffer identifier");
ImportStatements.push_back(ScannerImportStatementInfo( ImportStatements.push_back(ScannerImportStatementInfo(
importIdentifier.value(), importIdentifier.value(), isExported,
ScannerImportStatementInfo::ImportDiagnosticLocationInfo( ScannerImportStatementInfo::ImportDiagnosticLocationInfo(
bufferIdentifier.value(), lineNumber, columnNumber))); bufferIdentifier.value(), lineNumber, columnNumber)));
break; break;
@@ -1443,7 +1445,7 @@ unsigned ModuleDependenciesCacheSerializer::writeImportStatementInfos(
Out, ScratchRecord, AbbrCodes[ImportStatementLayout::Code], Out, ScratchRecord, AbbrCodes[ImportStatementLayout::Code],
getIdentifier(importInfo.importIdentifier), getIdentifier(importInfo.importIdentifier),
getIdentifier(importLoc.bufferIdentifier), importLoc.lineNumber, getIdentifier(importLoc.bufferIdentifier), importLoc.lineNumber,
importLoc.columnNumber, isOptional); importLoc.columnNumber, isOptional, importInfo.isExported);
count++; count++;
} }
}; };

View File

@@ -412,6 +412,7 @@ ModuleDependencyScanner::getMainModuleDependencyInfo(ModuleDecl *mainModule) {
// Add any implicit module names. // Add any implicit module names.
for (const auto &import : importInfo.AdditionalUnloadedImports) { for (const auto &import : importInfo.AdditionalUnloadedImports) {
mainDependencies.addModuleImport(import.module.getModulePath(), mainDependencies.addModuleImport(import.module.getModulePath(),
import.options.contains(ImportFlags::Exported),
&alreadyAddedModules, &alreadyAddedModules,
&ScanASTContext.SourceMgr); &ScanASTContext.SourceMgr);
} }
@@ -420,6 +421,7 @@ ModuleDependencyScanner::getMainModuleDependencyInfo(ModuleDecl *mainModule) {
for (const auto &import : importInfo.AdditionalImports) { for (const auto &import : importInfo.AdditionalImports) {
mainDependencies.addModuleImport( mainDependencies.addModuleImport(
import.module.importedModule->getNameStr(), import.module.importedModule->getNameStr(),
import.options.contains(ImportFlags::Exported),
&alreadyAddedModules); &alreadyAddedModules);
} }
@@ -432,6 +434,7 @@ ModuleDependencyScanner::getMainModuleDependencyInfo(ModuleDecl *mainModule) {
// add a dependency with the same name to trigger the search. // add a dependency with the same name to trigger the search.
if (importInfo.ShouldImportUnderlyingModule) { if (importInfo.ShouldImportUnderlyingModule) {
mainDependencies.addModuleImport(mainModule->getName().str(), mainDependencies.addModuleImport(mainModule->getName().str(),
/* isExported */ true,
&alreadyAddedModules); &alreadyAddedModules);
} }
@@ -441,6 +444,7 @@ ModuleDependencyScanner::getMainModuleDependencyInfo(ModuleDecl *mainModule) {
for (const auto &tbdSymbolModule : for (const auto &tbdSymbolModule :
ScanCompilerInvocation.getTBDGenOptions().embedSymbolsFromModules) { ScanCompilerInvocation.getTBDGenOptions().embedSymbolsFromModules) {
mainDependencies.addModuleImport(tbdSymbolModule, mainDependencies.addModuleImport(tbdSymbolModule,
/* isExported */ false,
&alreadyAddedModules); &alreadyAddedModules);
} }
} }
@@ -1354,7 +1358,8 @@ void ModuleDependencyScanner::resolveCrossImportOverlayDependencies(
ModuleDependencyInfo::forSwiftSourceModule(); ModuleDependencyInfo::forSwiftSourceModule();
std::for_each(newOverlays.begin(), newOverlays.end(), std::for_each(newOverlays.begin(), newOverlays.end(),
[&](Identifier modName) { [&](Identifier modName) {
dummyMainDependencies.addModuleImport(modName.str()); dummyMainDependencies.addModuleImport(modName.str(),
/* isExported */ false);
}); });
// Record the dummy main module's direct dependencies. The dummy main module // Record the dummy main module's direct dependencies. The dummy main module

View File

@@ -276,6 +276,7 @@ SwiftModuleScanner::scanInterfaceFile(Twine moduleInterfacePath,
auto &imInfo = mainMod->getImplicitImportInfo(); auto &imInfo = mainMod->getImplicitImportInfo();
for (auto import : imInfo.AdditionalUnloadedImports) { for (auto import : imInfo.AdditionalUnloadedImports) {
Result->addModuleImport(import.module.getModulePath(), Result->addModuleImport(import.module.getModulePath(),
import.options.contains(ImportFlags::Exported),
&alreadyAddedModules, &Ctx.SourceMgr); &alreadyAddedModules, &Ctx.SourceMgr);
} }
@@ -301,8 +302,9 @@ SwiftModuleScanner::scanInterfaceFile(Twine moduleInterfacePath,
return adjacentBinaryModulePackageOnlyImports.getError(); return adjacentBinaryModulePackageOnlyImports.getError();
for (const auto &requiredImport : *adjacentBinaryModulePackageOnlyImports) for (const auto &requiredImport : *adjacentBinaryModulePackageOnlyImports)
if (!alreadyAddedModules.contains(requiredImport.getKey())) if (!alreadyAddedModules.contains(requiredImport.importIdentifier))
Result->addModuleImport(requiredImport.getKey(), Result->addModuleImport(requiredImport.importIdentifier,
requiredImport.isExported,
&alreadyAddedModules); &alreadyAddedModules);
} }
} }

View File

@@ -344,7 +344,7 @@ std::optional<std::string> SerializedModuleLoaderBase::invalidModuleReason(seria
llvm_unreachable("bad status"); llvm_unreachable("bad status");
} }
llvm::ErrorOr<llvm::StringSet<>> llvm::ErrorOr<std::vector<ScannerImportStatementInfo>>
SerializedModuleLoaderBase::getMatchingPackageOnlyImportsOfModule( SerializedModuleLoaderBase::getMatchingPackageOnlyImportsOfModule(
Twine modulePath, bool isFramework, bool isRequiredOSSAModules, Twine modulePath, bool isFramework, bool isRequiredOSSAModules,
StringRef SDKName, StringRef packageName, llvm::vfs::FileSystem *fileSystem, StringRef SDKName, StringRef packageName, llvm::vfs::FileSystem *fileSystem,
@@ -353,7 +353,7 @@ SerializedModuleLoaderBase::getMatchingPackageOnlyImportsOfModule(
if (!moduleBuf) if (!moduleBuf)
return moduleBuf.getError(); return moduleBuf.getError();
llvm::StringSet<> importedModuleNames; std::vector<ScannerImportStatementInfo> importedModuleNames;
// Load the module file without validation. // Load the module file without validation.
std::shared_ptr<const ModuleFileSharedCore> loadedModuleFile; std::shared_ptr<const ModuleFileSharedCore> loadedModuleFile;
serialization::ValidationInfo loadInfo = ModuleFileSharedCore::load( serialization::ValidationInfo loadInfo = ModuleFileSharedCore::load(
@@ -376,7 +376,7 @@ SerializedModuleLoaderBase::getMatchingPackageOnlyImportsOfModule(
if (dotPos != std::string::npos) if (dotPos != std::string::npos)
moduleName = moduleName.slice(0, dotPos); moduleName = moduleName.slice(0, dotPos);
importedModuleNames.insert(moduleName); importedModuleNames.push_back({moduleName.str(), dependency.isExported()});
} }
return importedModuleNames; return importedModuleNames;
@@ -482,6 +482,7 @@ SerializedModuleLoaderBase::getImportsOfModule(
ModuleLoadingBehavior transitiveBehavior, StringRef packageName, ModuleLoadingBehavior transitiveBehavior, StringRef packageName,
bool isTestableImport) { bool isTestableImport) {
llvm::StringSet<> importedModuleNames; llvm::StringSet<> importedModuleNames;
llvm::StringSet<> importedExportedModuleNames;
std::string importedHeader = ""; std::string importedHeader = "";
for (const auto &dependency : loadedModuleFile.getDependencies()) { for (const auto &dependency : loadedModuleFile.getDependencies()) {
if (dependency.isHeader()) { if (dependency.isHeader()) {
@@ -516,9 +517,12 @@ SerializedModuleLoaderBase::getImportsOfModule(
moduleName = "std"; moduleName = "std";
importedModuleNames.insert(moduleName); importedModuleNames.insert(moduleName);
if (dependency.isExported())
importedExportedModuleNames.insert(moduleName);
} }
return SerializedModuleLoaderBase::BinaryModuleImports{importedModuleNames, return SerializedModuleLoaderBase::BinaryModuleImports{importedModuleNames,
importedExportedModuleNames,
importedHeader}; importedHeader};
} }
@@ -603,17 +607,23 @@ SerializedModuleLoaderBase::scanModuleFile(Twine modulePath, bool isFramework,
auto importedModuleSet = binaryModuleImports->moduleImports; auto importedModuleSet = binaryModuleImports->moduleImports;
std::vector<ScannerImportStatementInfo> moduleImports; std::vector<ScannerImportStatementInfo> moduleImports;
moduleImports.reserve(importedModuleSet.size()); moduleImports.reserve(importedModuleSet.size());
llvm::transform( llvm::transform(importedModuleSet.keys(), std::back_inserter(moduleImports),
importedModuleSet.keys(), std::back_inserter(moduleImports), [&binaryModuleImports](llvm::StringRef N) {
[](llvm::StringRef N) { return ScannerImportStatementInfo(N.str()); }); return ScannerImportStatementInfo(
N.str(),
binaryModuleImports->exportedModules.contains(N));
});
auto importedHeader = binaryModuleImports->headerImport; auto importedHeader = binaryModuleImports->headerImport;
auto &importedOptionalModuleSet = binaryModuleOptionalImports->moduleImports; auto &importedOptionalModuleSet = binaryModuleOptionalImports->moduleImports;
auto &importedExportedOptionalModuleSet =
binaryModuleOptionalImports->exportedModules;
std::vector<ScannerImportStatementInfo> optionalModuleImports; std::vector<ScannerImportStatementInfo> optionalModuleImports;
for (const auto optionalImportedModule : importedOptionalModuleSet.keys()) for (const auto optionalImportedModule : importedOptionalModuleSet.keys())
if (!importedModuleSet.contains(optionalImportedModule)) if (!importedModuleSet.contains(optionalImportedModule))
optionalModuleImports.push_back( optionalModuleImports.push_back(
ScannerImportStatementInfo(optionalImportedModule.str())); {optionalImportedModule.str(),
importedExportedOptionalModuleSet.contains(optionalImportedModule)});
std::vector<LinkLibrary> linkLibraries; std::vector<LinkLibrary> linkLibraries;
{ {