[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;
};
ScannerImportStatementInfo(std::string importIdentifier)
: importLocations(), importIdentifier(importIdentifier) {}
ScannerImportStatementInfo(std::string importIdentifier, bool isExported)
: importLocations(), importIdentifier(importIdentifier),
isExported(isExported) {}
ScannerImportStatementInfo(std::string importIdentifier,
ScannerImportStatementInfo(std::string importIdentifier, bool isExported,
ImportDiagnosticLocationInfo location)
: importLocations({location}), importIdentifier(importIdentifier) {}
: importLocations({location}), importIdentifier(importIdentifier),
isExported(isExported) {}
void addImportLocation(ImportDiagnosticLocationInfo location) {
importLocations.push_back(location);
@@ -169,6 +171,8 @@ struct ScannerImportStatementInfo {
SmallVector<ImportDiagnosticLocationInfo, 4> importLocations;
/// Imported module string. e.g. "Foo.Bar" in 'import Foo.Bar'
std::string importIdentifier;
/// Is this an @_exported import
bool isExported;
};
/// 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.
void
addOptionalModuleImport(StringRef module,
addOptionalModuleImport(StringRef module, bool isExported,
llvm::StringSet<> *alreadyAddedModules = nullptr);
/// Add all of the module imports in the given source
@@ -937,13 +941,13 @@ public:
const SourceManager *sourceManager);
/// 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,
const SourceManager *sourceManager = nullptr,
SourceLoc sourceLocation = SourceLoc());
/// 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,
const SourceManager *sourceManager = nullptr,
SourceLoc sourceLocation = SourceLoc());

View File

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

View File

@@ -171,6 +171,7 @@ protected:
struct BinaryModuleImports {
llvm::StringSet<> moduleImports;
llvm::StringSet<> exportedModules;
std::string headerImport;
};
@@ -185,7 +186,7 @@ protected:
/// If the module has a package name matching the one
/// 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,
bool isFramework,
bool isRequiredOSSAModules,

View File

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

View File

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

View File

@@ -412,6 +412,7 @@ ModuleDependencyScanner::getMainModuleDependencyInfo(ModuleDecl *mainModule) {
// Add any implicit module names.
for (const auto &import : importInfo.AdditionalUnloadedImports) {
mainDependencies.addModuleImport(import.module.getModulePath(),
import.options.contains(ImportFlags::Exported),
&alreadyAddedModules,
&ScanASTContext.SourceMgr);
}
@@ -420,6 +421,7 @@ ModuleDependencyScanner::getMainModuleDependencyInfo(ModuleDecl *mainModule) {
for (const auto &import : importInfo.AdditionalImports) {
mainDependencies.addModuleImport(
import.module.importedModule->getNameStr(),
import.options.contains(ImportFlags::Exported),
&alreadyAddedModules);
}
@@ -432,6 +434,7 @@ ModuleDependencyScanner::getMainModuleDependencyInfo(ModuleDecl *mainModule) {
// add a dependency with the same name to trigger the search.
if (importInfo.ShouldImportUnderlyingModule) {
mainDependencies.addModuleImport(mainModule->getName().str(),
/* isExported */ true,
&alreadyAddedModules);
}
@@ -441,6 +444,7 @@ ModuleDependencyScanner::getMainModuleDependencyInfo(ModuleDecl *mainModule) {
for (const auto &tbdSymbolModule :
ScanCompilerInvocation.getTBDGenOptions().embedSymbolsFromModules) {
mainDependencies.addModuleImport(tbdSymbolModule,
/* isExported */ false,
&alreadyAddedModules);
}
}
@@ -1354,7 +1358,8 @@ void ModuleDependencyScanner::resolveCrossImportOverlayDependencies(
ModuleDependencyInfo::forSwiftSourceModule();
std::for_each(newOverlays.begin(), newOverlays.end(),
[&](Identifier modName) {
dummyMainDependencies.addModuleImport(modName.str());
dummyMainDependencies.addModuleImport(modName.str(),
/* isExported */ false);
});
// 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();
for (auto import : imInfo.AdditionalUnloadedImports) {
Result->addModuleImport(import.module.getModulePath(),
import.options.contains(ImportFlags::Exported),
&alreadyAddedModules, &Ctx.SourceMgr);
}
@@ -301,8 +302,9 @@ SwiftModuleScanner::scanInterfaceFile(Twine moduleInterfacePath,
return adjacentBinaryModulePackageOnlyImports.getError();
for (const auto &requiredImport : *adjacentBinaryModulePackageOnlyImports)
if (!alreadyAddedModules.contains(requiredImport.getKey()))
Result->addModuleImport(requiredImport.getKey(),
if (!alreadyAddedModules.contains(requiredImport.importIdentifier))
Result->addModuleImport(requiredImport.importIdentifier,
requiredImport.isExported,
&alreadyAddedModules);
}
}

View File

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