Skip to content

Commit 12477b7

Browse files
committed
[Dependency Scanning] Refactor the scanner to resolve unqualified module imports
This changes the scanner's behavior to "resolve" a discovered module's dependencies to a set of Module IDs: module name + module kind (swift textual, swift binary, clang, etc.). The 'ModuleDependencyInfo' objects that are stored in the dependency scanner's cache now carry a set of kind-qualified ModuleIDs for their dependencies, in addition to unqualified imported module names of their dependencies. Previously, the scanner's internal state would cache a module dependnecy as having its own set of dependencies which were stored as names of imported modules. This led to a design where any time we needed to process the dependency downstream from its discovery (e.g. cycle detection, graph construction), we had to query the ASTContext to resolve this dependency's imports, which shouldn't be necessary. Now, upon discovery, we "resolve" a discovered dependency by executing a lookup for each of its imported module names (this operation happens regardless of this patch) and store a fully-resolved set of dependencies in the dependency module info. Moreover, looking up a given module dependency by name (via `ASTContext`'s `getModuleDependencies`) would result in iterating over the scanner's module "loaders" and querying each for the module name. The corresponding modules would then check the scanner's cache for a respective discovered module, and if no such module is found the "loader" would search the filesystem. This meant that in practice, we searched the filesystem on many occasions where we actually had cached the required dependency, as follows: Suppose we had previously discovered a Clang module "foo" and cached its dependency info. -> ASTContext.getModuleDependencies("foo") --> (1) Swift Module "Loader" checks caches for a Swift module "foo" and doesn't find one, so it searches the filesystem for "foo" and fails to find one. --> (2) Clang Module "Loader" checks caches for a Clang module "foo", finds one and returns it to the client. This means that we were always searching the filesystem in (1) even if we knew that to be futile. With this change, queries to `ASTContext`'s `getModuleDependencies` will always check all the caches first, and only delegate to the scanner "loaders" if no cached dependency is found. The loaders are then no longer in the business of checking the cached contents. To handle cases in the scanner where we must only lookup either a Swift-only module or a Clang-only module, this patch splits 'getModuleDependencies' into an alrady-existing 'getSwiftModuleDependencies' and a newly-added 'getClangModuleDependencies'.
1 parent a6e056b commit 12477b7

22 files changed

+686
-747
lines changed

include/swift/AST/ASTContext.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -991,18 +991,20 @@ class ASTContext final {
991991

992992
/// Retrieve the module dependencies for the module with the given name.
993993
///
994-
/// \param isUnderlyingClangModule When true, only look for a Clang module
995-
/// with the given name, ignoring any Swift modules.
996-
Optional<ModuleDependencyInfo> getModuleDependencies(
994+
Optional<const ModuleDependencyInfo*> getModuleDependencies(
997995
StringRef moduleName,
998-
bool isUnderlyingClangModule,
999996
ModuleDependenciesCache &cache,
1000997
InterfaceSubContextDelegate &delegate,
1001-
bool cacheOnly = false,
1002998
llvm::Optional<std::pair<std::string, swift::ModuleDependencyKind>> dependencyOf = None);
1003999

1000+
/// Retrieve the module dependencies for the Clang module with the given name.
1001+
Optional<const ModuleDependencyInfo*> getClangModuleDependencies(
1002+
StringRef moduleName,
1003+
ModuleDependenciesCache &cache,
1004+
InterfaceSubContextDelegate &delegate);
1005+
10041006
/// Retrieve the module dependencies for the Swift module with the given name.
1005-
Optional<ModuleDependencyInfo> getSwiftModuleDependencies(
1007+
Optional<const ModuleDependencyInfo*> getSwiftModuleDependencies(
10061008
StringRef moduleName,
10071009
ModuleDependenciesCache &cache,
10081010
InterfaceSubContextDelegate &delegate);

include/swift/AST/ModuleDependencies.h

Lines changed: 85 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -74,29 +74,44 @@ enum class ModuleDependencyKind : int8_t {
7474
LastKind = SwiftPlaceholder + 1
7575
};
7676

77+
using ModuleDependencyID = std::pair<std::string, ModuleDependencyKind>;
78+
using ModuleDependencyIDSetVector =
79+
llvm::SetVector<ModuleDependencyID, std::vector<ModuleDependencyID>,
80+
std::set<ModuleDependencyID>>;
81+
7782
struct ModuleDependencyKindHash {
7883
std::size_t operator()(ModuleDependencyKind k) const {
7984
using UnderlyingType = std::underlying_type<ModuleDependencyKind>::type;
8085
return std::hash<UnderlyingType>{}(static_cast<UnderlyingType>(k));
8186
}
8287
};
8388

89+
namespace dependencies {
90+
std::string createEncodedModuleKindAndName(ModuleDependencyID id);
91+
}
92+
8493
/// Base class for the variant storage of ModuleDependencyInfo.
8594
///
8695
/// This class is mostly an implementation detail for \c ModuleDependencyInfo.
8796
class ModuleDependencyInfoStorageBase {
8897
public:
8998
const ModuleDependencyKind dependencyKind;
9099

91-
ModuleDependencyInfoStorageBase(ModuleDependencyKind dependencyKind)
92-
: dependencyKind(dependencyKind) { }
100+
ModuleDependencyInfoStorageBase(ModuleDependencyKind dependencyKind,
101+
bool resolved = false)
102+
: dependencyKind(dependencyKind), resolved(resolved) { }
93103

94104
virtual ModuleDependencyInfoStorageBase *clone() const = 0;
95105

96106
virtual ~ModuleDependencyInfoStorageBase();
97107

98108
/// The set of modules on which this module depends.
99-
std::vector<std::string> moduleDependencies;
109+
std::vector<std::string> moduleImports;
110+
111+
/// The set of modules on which this module depends, resolved
112+
/// to Module IDs, qualified by module kind: Swift, Clang, etc.
113+
std::vector<ModuleDependencyID> resolvedModuleDependencies;
114+
bool resolved;
100115
};
101116

102117
struct CommonSwiftTextualModuleDependencyDetails {
@@ -400,9 +415,29 @@ class ModuleDependencyInfo {
400415
compiledModulePath, moduleDocPath, sourceInfoPath));
401416
}
402417

403-
/// Retrieve the module-level dependencies.
404-
ArrayRef<std::string> getModuleDependencies() const {
405-
return storage->moduleDependencies;
418+
/// Retrieve the module-level imports.
419+
ArrayRef<std::string> getModuleImports() const {
420+
return storage->moduleImports;
421+
}
422+
423+
/// Retreive the module-level dependencies.
424+
const ArrayRef<ModuleDependencyID> getModuleDependencies() const {
425+
assert(storage->resolved);
426+
return storage->resolvedModuleDependencies;
427+
}
428+
429+
/// Resolve a dependency's set of `imports` with qualified Module IDs
430+
void resolveDependencies(const std::vector<ModuleDependencyID> &dependencyIDs) {
431+
assert(!storage->resolved && "Resolving an already-resolved dependency");
432+
storage->resolved = true;
433+
storage->resolvedModuleDependencies.assign(dependencyIDs.begin(), dependencyIDs.end());
434+
}
435+
436+
bool isResolved() const {
437+
return storage->resolved;
438+
}
439+
void setIsResolved(bool isResolved) {
440+
storage->resolved = isResolved;
406441
}
407442

408443
/// Whether the dependencies are for a Swift module: either Textual, Source, Binary, or Placeholder.
@@ -444,19 +479,22 @@ class ModuleDependencyInfo {
444479
getAsPlaceholderDependencyModule() const;
445480

446481
/// Add a dependency on the given module, if it was not already in the set.
447-
void addModuleDependency(StringRef module,
448-
llvm::StringSet<> *alreadyAddedModules = nullptr);
482+
void addModuleImport(StringRef module,
483+
llvm::StringSet<> *alreadyAddedModules = nullptr);
449484

450485
/// Add a dependency on the given module, if it was not already in the set.
451-
void addModuleDependency(ImportPath::Module module,
452-
llvm::StringSet<> *alreadyAddedModules = nullptr) {
453-
addModuleDependency(module.front().Item.str(), alreadyAddedModules);
486+
void addModuleImport(ImportPath::Module module,
487+
llvm::StringSet<> *alreadyAddedModules = nullptr) {
488+
addModuleImport(module.front().Item.str(), alreadyAddedModules);
454489
}
455490

456-
/// Add all of the module dependencies for the imports in the given source
457-
/// file to the set of module dependencies.
458-
void addModuleDependencies(const SourceFile &sf,
459-
llvm::StringSet<> &alreadyAddedModules);
491+
/// Add all of the module imports in the given source
492+
/// file to the set of module imports.
493+
void addModuleImport(const SourceFile &sf,
494+
llvm::StringSet<> &alreadyAddedModules);
495+
/// Add a kind-qualified module dependency ID to the set of
496+
/// module dependencies.
497+
void addModuleDependency(ModuleDependencyID dependencyID);
460498

461499
/// Get the bridging header.
462500
Optional<std::string> getBridgingHeader() const;
@@ -477,11 +515,9 @@ class ModuleDependencyInfo {
477515
/// Collect a map from a secondary module name to a list of cross-import
478516
/// overlays, when this current module serves as the primary module.
479517
llvm::StringMap<llvm::SmallSetVector<Identifier, 4>>
480-
collectCrossImportOverlayNames(ASTContext &ctx, StringRef moduleName);
518+
collectCrossImportOverlayNames(ASTContext &ctx, StringRef moduleName) const;
481519
};
482520

483-
using ModuleDependencyID = std::pair<std::string, ModuleDependencyKind>;
484-
using ModuleDependenciesVector = llvm::SmallVector<ModuleDependencyInfo, 1>;
485521
using ModuleNameToDependencyMap = llvm::StringMap<ModuleDependencyInfo>;
486522
using ModuleDependenciesKindMap =
487523
std::unordered_map<ModuleDependencyKind,
@@ -505,6 +541,9 @@ class SwiftDependencyScanningService {
505541
/// encountered.
506542
std::vector<ModuleDependencyID> AllModules;
507543

544+
/// Set containing all of the Clang modules that have already been seen.
545+
llvm::StringSet<> alreadySeenClangModules;
546+
508547
/// Dependencies for modules that have already been computed.
509548
/// This maps a dependency kind to a map of a module's name to a Dependency
510549
/// object
@@ -565,6 +604,10 @@ class SwiftDependencyScanningService {
565604
return *SharedFilesystemCache;
566605
}
567606

607+
llvm::StringSet<>& getAlreadySeenClangModules() {
608+
return getCurrentCache()->alreadySeenClangModules;
609+
}
610+
568611
/// Wrap the filesystem on the specified `CompilerInstance` with a
569612
/// caching `DependencyScanningWorkerFilesystem`
570613
void overlaySharedFilesystemCacheForCompilation(CompilerInstance &Instance);
@@ -587,8 +630,8 @@ class SwiftDependencyScanningService {
587630
}
588631

589632
/// Whether we have cached dependency information for the given module.
590-
bool hasDependencies(StringRef moduleName,
591-
Optional<ModuleDependencyKind> kind) const;
633+
bool hasDependency(StringRef moduleName,
634+
Optional<ModuleDependencyKind> kind) const;
592635

593636
/// Return a pointer to the context-specific cache state of the current
594637
/// scanning action.
@@ -599,22 +642,22 @@ class SwiftDependencyScanningService {
599642
getCacheForScanningContextHash(StringRef scanningContextHash) const;
600643

601644
/// Look for source-based module dependency details
602-
Optional<ModuleDependencyInfo>
645+
Optional<const ModuleDependencyInfo*>
603646
findSourceModuleDependency(StringRef moduleName) const;
604647

605648
/// Look for module dependencies for a module with the given name
606649
///
607650
/// \returns the cached result, or \c None if there is no cached entry.
608-
Optional<ModuleDependencyInfo>
609-
findDependencies(StringRef moduleName,
610-
Optional<ModuleDependencyKind> kind) const;
651+
Optional<const ModuleDependencyInfo*>
652+
findDependency(StringRef moduleName,
653+
Optional<ModuleDependencyKind> kind) const;
611654

612655
/// Record dependencies for the given module.
613-
const ModuleDependencyInfo *recordDependencies(StringRef moduleName,
656+
const ModuleDependencyInfo *recordDependency(StringRef moduleName,
614657
ModuleDependencyInfo dependencies);
615658

616659
/// Update stored dependencies for the given module.
617-
const ModuleDependencyInfo *updateDependencies(ModuleDependencyID moduleID,
660+
const ModuleDependencyInfo *updateDependency(ModuleDependencyID moduleID,
618661
ModuleDependencyInfo dependencies);
619662

620663
/// Reference the list of all module dependencies that are not source-based
@@ -642,23 +685,14 @@ class SwiftDependencyScanningService {
642685
class ModuleDependenciesCache {
643686
private:
644687
SwiftDependencyScanningService &globalScanningService;
645-
646-
/// References to data in `globalCache` for Swift dependencies and
647-
/// `clangModuleDependencies` for Clang dependencies accimulated during
648-
/// the current scanning action.
688+
/// References to data in the `globalScanningService` for module dependencies
649689
ModuleDependenciesKindRefMap ModuleDependenciesMap;
650-
651690
/// Name of the module under scan
652691
std::string mainScanModuleName;
653692
/// The context hash of the current scanning invocation
654693
std::string scannerContextHash;
655-
656-
/// Set containing all of the Clang modules that have already been seen.
657-
llvm::StringSet<> alreadySeenClangModules;
658694
/// The Clang dependency scanner tool
659695
clang::tooling::dependencies::DependencyScanningTool clangScanningTool;
660-
/// Discovered Clang modules are only cached locally.
661-
llvm::StringMap<ModuleDependenciesVector> clangModuleDependencies;
662696

663697
/// Retrieve the dependencies map that corresponds to the given dependency
664698
/// kind.
@@ -667,17 +701,6 @@ class ModuleDependenciesCache {
667701
const llvm::StringMap<const ModuleDependencyInfo *> &
668702
getDependencyReferencesMap(ModuleDependencyKind kind) const;
669703

670-
/// Local cache results lookup, only for modules which were discovered during
671-
/// the current scanner invocation.
672-
bool hasDependenciesLocalOnly(StringRef moduleName,
673-
Optional<ModuleDependencyKind> kind) const;
674-
675-
/// Local cache results lookup, only for modules which were discovered during
676-
/// the current scanner invocation.
677-
Optional<const ModuleDependencyInfo *>
678-
findDependenciesLocalOnly(StringRef moduleName,
679-
Optional<ModuleDependencyKind> kind) const;
680-
681704
public:
682705
ModuleDependenciesCache(SwiftDependencyScanningService &globalScanningService,
683706
std::string mainScanModuleName,
@@ -687,31 +710,36 @@ class ModuleDependenciesCache {
687710

688711
public:
689712
/// Whether we have cached dependency information for the given module.
690-
bool hasDependencies(StringRef moduleName,
691-
Optional<ModuleDependencyKind> kind) const;
713+
bool hasDependency(StringRef moduleName,
714+
Optional<ModuleDependencyKind> kind) const;
692715

693716
/// Produce a reference to the Clang scanner tool associated with this cache
694717
clang::tooling::dependencies::DependencyScanningTool& getClangScannerTool() {
695718
return clangScanningTool;
696719
}
697720
llvm::StringSet<>& getAlreadySeenClangModules() {
698-
return alreadySeenClangModules;
721+
return globalScanningService.getAlreadySeenClangModules();
699722
}
700723

701724
/// Look for module dependencies for a module with the given name
702725
///
703726
/// \returns the cached result, or \c None if there is no cached entry.
704-
Optional<ModuleDependencyInfo>
705-
findDependencies(StringRef moduleName,
706-
Optional<ModuleDependencyKind> kind) const;
727+
Optional<const ModuleDependencyInfo*>
728+
findDependency(StringRef moduleName,
729+
Optional<ModuleDependencyKind> kind) const;
707730

708731
/// Record dependencies for the given module.
709-
void recordDependencies(StringRef moduleName,
710-
ModuleDependencyInfo dependencies);
732+
void recordDependency(StringRef moduleName,
733+
ModuleDependencyInfo dependencies);
711734

712735
/// Update stored dependencies for the given module.
713-
void updateDependencies(ModuleDependencyID moduleID,
714-
ModuleDependencyInfo dependencies);
736+
void updateDependency(ModuleDependencyID moduleID,
737+
ModuleDependencyInfo dependencies);
738+
739+
/// Resolve a dependency module's set of imports
740+
/// to a kind-qualified set of module IDs.
741+
void resolveDependencyImports(ModuleDependencyID moduleID,
742+
const std::vector<ModuleDependencyID> &dependencyIDs);
715743

716744
const std::vector<ModuleDependencyID> &getAllSourceModules() const {
717745
return globalScanningService.getAllSourceModules();

include/swift/AST/ModuleLoader.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ class ModuleLoader {
321321

322322
/// Retrieve the dependencies for the given, named module, or \c None
323323
/// if no such module exists.
324-
virtual Optional<ModuleDependencyInfo> getModuleDependencies(
324+
virtual Optional<const ModuleDependencyInfo*> getModuleDependencies(
325325
StringRef moduleName,
326326
ModuleDependenciesCache &cache,
327327
InterfaceSubContextDelegate &delegate) = 0;

include/swift/ClangImporter/ClangImporter.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ class ClangImporter final : public ClangModuleLoader {
423423
ModuleDependenciesCache &cache,
424424
const clang::tooling::dependencies::FullDependenciesResult &clangDependencies);
425425

426-
Optional<ModuleDependencyInfo> getModuleDependencies(
426+
Optional<const ModuleDependencyInfo*> getModuleDependencies(
427427
StringRef moduleName, ModuleDependenciesCache &cache,
428428
InterfaceSubContextDelegate &delegate) override;
429429

0 commit comments

Comments
 (0)