Skip to content

Commit 78159c8

Browse files
committed
[Explicit Module Builds] Handle #canImport in the dependency scanner by adding scanner "loaders" to the ASTContext.
1 parent 39d4e01 commit 78159c8

File tree

4 files changed

+255
-138
lines changed

4 files changed

+255
-138
lines changed
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
//===--- ModuleDependencyScanner.h - Import Swift modules --------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "swift/AST/ASTContext.h"
14+
#include "swift/Frontend/ModuleInterfaceLoader.h"
15+
#include "swift/Serialization/SerializedModuleLoader.h"
16+
17+
namespace swift {
18+
/// A module "loader" that looks for .swiftinterface and .swiftmodule files
19+
/// for the purpose of determining dependencies, but does not attempt to
20+
/// load the module files.
21+
class ModuleDependencyScanner : public SerializedModuleLoaderBase {
22+
/// The module we're scanning dependencies of.
23+
Identifier moduleName;
24+
25+
/// Scan the given interface file to determine dependencies.
26+
llvm::ErrorOr<ModuleDependencies> scanInterfaceFile(
27+
Twine moduleInterfacePath, bool isFramework);
28+
29+
InterfaceSubContextDelegate &astDelegate;
30+
public:
31+
Optional<ModuleDependencies> dependencies;
32+
33+
/// Describes the kind of dependencies this scanner is able to identify
34+
ModuleDependenciesKind dependencyKind;
35+
36+
ModuleDependencyScanner(
37+
ASTContext &ctx, ModuleLoadingMode LoadMode, Identifier moduleName,
38+
InterfaceSubContextDelegate &astDelegate,
39+
ModuleDependenciesKind dependencyKind = ModuleDependenciesKind::Swift)
40+
: SerializedModuleLoaderBase(ctx, nullptr, LoadMode,
41+
/*IgnoreSwiftSourceInfoFile=*/true),
42+
moduleName(moduleName), astDelegate(astDelegate),
43+
dependencyKind(dependencyKind) {}
44+
45+
std::error_code findModuleFilesInDirectory(
46+
AccessPathElem ModuleID,
47+
const SerializedModuleBaseName &BaseName,
48+
SmallVectorImpl<char> *ModuleInterfacePath,
49+
std::unique_ptr<llvm::MemoryBuffer> *ModuleBuffer,
50+
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer,
51+
std::unique_ptr<llvm::MemoryBuffer> *ModuleSourceInfoBuffer,
52+
bool IsFramework) override;
53+
54+
virtual void collectVisibleTopLevelModuleNames(
55+
SmallVectorImpl<Identifier> &names) const override {
56+
llvm_unreachable("Not used");
57+
}
58+
};
59+
60+
/// A ModuleLoader that loads placeholder dependency module stubs specified in
61+
/// -placeholder-dependency-module-map-file
62+
/// This loader is used only in dependency scanning to inform the scanner that a
63+
/// set of modules constitute placeholder dependencies that are not visible to the
64+
/// scanner but will nevertheless be provided by the scanner's clients.
65+
/// This "loader" will not attempt to load any module files.
66+
class PlaceholderSwiftModuleScanner : public ModuleDependencyScanner {
67+
/// Scan the given placeholder module map
68+
void parsePlaceholderModuleMap(StringRef fileName) {
69+
ExplicitModuleMapParser parser(Allocator);
70+
auto result =
71+
parser.parseSwiftExplicitModuleMap(fileName, PlaceholderDependencyModuleMap);
72+
if (result == std::errc::invalid_argument) {
73+
Ctx.Diags.diagnose(SourceLoc(),
74+
diag::placeholder_dependency_module_map_corrupted,
75+
fileName);
76+
}
77+
else if (result == std::errc::no_such_file_or_directory) {
78+
Ctx.Diags.diagnose(SourceLoc(),
79+
diag::placeholder_dependency_module_map_missing,
80+
fileName);
81+
}
82+
}
83+
84+
llvm::StringMap<ExplicitModuleInfo> PlaceholderDependencyModuleMap;
85+
llvm::BumpPtrAllocator Allocator;
86+
87+
public:
88+
PlaceholderSwiftModuleScanner(ASTContext &ctx, ModuleLoadingMode LoadMode,
89+
Identifier moduleName,
90+
StringRef PlaceholderDependencyModuleMap,
91+
InterfaceSubContextDelegate &astDelegate)
92+
: ModuleDependencyScanner(ctx, LoadMode, moduleName, astDelegate,
93+
ModuleDependenciesKind::SwiftPlaceholder) {
94+
95+
// FIXME: Find a better place for this map to live, to avoid
96+
// doing the parsing on every module.
97+
if (!PlaceholderDependencyModuleMap.empty()) {
98+
parsePlaceholderModuleMap(PlaceholderDependencyModuleMap);
99+
}
100+
}
101+
102+
std::error_code findModuleFilesInDirectory(
103+
AccessPathElem ModuleID, const SerializedModuleBaseName &BaseName,
104+
SmallVectorImpl<char> *ModuleInterfacePath,
105+
std::unique_ptr<llvm::MemoryBuffer> *ModuleBuffer,
106+
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer,
107+
std::unique_ptr<llvm::MemoryBuffer> *ModuleSourceInfoBuffer,
108+
bool IsFramework) override;
109+
};
110+
}

lib/Frontend/Frontend.cpp

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "swift/SILOptimizer/Utils/Generics.h"
3434
#include "swift/Serialization/SerializationOptions.h"
3535
#include "swift/Serialization/SerializedModuleLoader.h"
36+
#include "swift/Serialization/ModuleDependencyScanner.h"
3637
#include "swift/Strings.h"
3738
#include "swift/Subsystems.h"
3839
#include "clang/AST/ASTContext.h"
@@ -520,9 +521,36 @@ bool CompilerInstance::setUpModuleLoaders() {
520521
this->DefaultSerializedLoader = ISML.get();
521522
Context->addModuleLoader(std::move(ISML));
522523
}
523-
524+
524525
Context->addModuleLoader(std::move(clangImporter), /*isClang*/ true);
525526

527+
// When scanning for dependencies, we must add the scanner loaders in order to handle
528+
// ASTContext operations such as canImportModule
529+
if (Invocation.getFrontendOptions().RequestedAction ==
530+
FrontendOptions::ActionType::ScanDependencies) {
531+
auto ModuleCachePath = getModuleCachePathFromClang(Context
532+
->getClangModuleLoader()->getClangInstance());
533+
auto &FEOpts = Invocation.getFrontendOptions();
534+
ModuleInterfaceLoaderOptions LoaderOpts(FEOpts);
535+
InterfaceSubContextDelegateImpl ASTDelegate(Context->SourceMgr, Context->Diags,
536+
Context->SearchPathOpts, Context->LangOpts,
537+
LoaderOpts,
538+
Context->getClangModuleLoader(),
539+
/*buildModuleCacheDirIfAbsent*/false,
540+
ModuleCachePath,
541+
FEOpts.PrebuiltModuleCachePath,
542+
FEOpts.SerializeModuleInterfaceDependencyHashes,
543+
FEOpts.shouldTrackSystemDependencies());
544+
auto mainModuleName = Context->getIdentifier(FEOpts.ModuleName);
545+
std::unique_ptr<PlaceholderSwiftModuleScanner> PSMS =
546+
std::make_unique<PlaceholderSwiftModuleScanner>(*Context,
547+
MLM,
548+
mainModuleName,
549+
Context->SearchPathOpts.PlaceholderDependencyModuleMap,
550+
ASTDelegate);
551+
Context->addModuleLoader(std::move(PSMS));
552+
}
553+
526554
return false;
527555
}
528556

lib/Serialization/ModuleDependencyScanner.cpp

Lines changed: 61 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -19,157 +19,81 @@
1919
#include "swift/Basic/FileTypes.h"
2020
#include "swift/Frontend/ModuleInterfaceLoader.h"
2121
#include "swift/Serialization/SerializedModuleLoader.h"
22+
#include "swift/Serialization/ModuleDependencyScanner.h"
2223
#include "swift/Subsystems.h"
2324
using namespace swift;
2425
using llvm::ErrorOr;
2526

26-
namespace {
2727

28-
/// A module "loader" that looks for .swiftinterface and .swiftmodule files
29-
/// for the purpose of determining dependencies, but does not attempt to
30-
/// load the module files.
31-
class ModuleDependencyScanner : public SerializedModuleLoaderBase {
32-
/// The module we're scanning dependencies of.
33-
Identifier moduleName;
34-
35-
/// Scan the given interface file to determine dependencies.
36-
ErrorOr<ModuleDependencies> scanInterfaceFile(
37-
Twine moduleInterfacePath, bool isFramework);
38-
39-
InterfaceSubContextDelegate &astDelegate;
40-
public:
41-
Optional<ModuleDependencies> dependencies;
42-
43-
/// Describes the kind of dependencies this scanner is able to identify
44-
ModuleDependenciesKind dependencyKind;
45-
46-
ModuleDependencyScanner(
47-
ASTContext &ctx, ModuleLoadingMode LoadMode, Identifier moduleName,
48-
InterfaceSubContextDelegate &astDelegate,
49-
ModuleDependenciesKind dependencyKind = ModuleDependenciesKind::Swift)
50-
: SerializedModuleLoaderBase(ctx, nullptr, LoadMode,
51-
/*IgnoreSwiftSourceInfoFile=*/true),
52-
moduleName(moduleName), astDelegate(astDelegate),
53-
dependencyKind(dependencyKind) {}
54-
55-
virtual std::error_code findModuleFilesInDirectory(
56-
AccessPathElem ModuleID,
57-
const SerializedModuleBaseName &BaseName,
58-
SmallVectorImpl<char> *ModuleInterfacePath,
59-
std::unique_ptr<llvm::MemoryBuffer> *ModuleBuffer,
60-
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer,
61-
std::unique_ptr<llvm::MemoryBuffer> *ModuleSourceInfoBuffer,
62-
bool IsFramework) override {
63-
using namespace llvm::sys;
64-
65-
auto &fs = *Ctx.SourceMgr.getFileSystem();
66-
67-
auto ModPath = BaseName.getName(file_types::TY_SwiftModuleFile);
68-
auto InPath = BaseName.getName(file_types::TY_SwiftModuleInterfaceFile);
69-
70-
if (LoadMode == ModuleLoadingMode::OnlySerialized || !fs.exists(InPath)) {
71-
if (fs.exists(ModPath)) {
72-
// The module file will be loaded directly.
73-
auto dependencies = scanModuleFile(ModPath);
74-
if (dependencies) {
75-
this->dependencies = std::move(dependencies.get());
76-
return std::error_code();
77-
}
78-
return dependencies.getError();
79-
} else {
80-
return std::make_error_code(std::errc::no_such_file_or_directory);
28+
std::error_code ModuleDependencyScanner::findModuleFilesInDirectory(
29+
AccessPathElem ModuleID,
30+
const SerializedModuleBaseName &BaseName,
31+
SmallVectorImpl<char> *ModuleInterfacePath,
32+
std::unique_ptr<llvm::MemoryBuffer> *ModuleBuffer,
33+
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer,
34+
std::unique_ptr<llvm::MemoryBuffer> *ModuleSourceInfoBuffer,
35+
bool IsFramework) {
36+
using namespace llvm::sys;
37+
38+
auto &fs = *Ctx.SourceMgr.getFileSystem();
39+
40+
auto ModPath = BaseName.getName(file_types::TY_SwiftModuleFile);
41+
auto InPath = BaseName.getName(file_types::TY_SwiftModuleInterfaceFile);
42+
43+
if (LoadMode == ModuleLoadingMode::OnlySerialized || !fs.exists(InPath)) {
44+
if (fs.exists(ModPath)) {
45+
// The module file will be loaded directly.
46+
auto dependencies = scanModuleFile(ModPath);
47+
if (dependencies) {
48+
this->dependencies = std::move(dependencies.get());
49+
return std::error_code();
8150
}
51+
return dependencies.getError();
52+
} else {
53+
return std::make_error_code(std::errc::no_such_file_or_directory);
8254
}
83-
assert(fs.exists(InPath));
84-
// Use the private interface file if exits.
85-
auto PrivateInPath =
86-
BaseName.getName(file_types::TY_PrivateSwiftModuleInterfaceFile);
87-
if (fs.exists(PrivateInPath)) {
88-
InPath = PrivateInPath;
89-
}
90-
auto dependencies = scanInterfaceFile(InPath, IsFramework);
91-
if (dependencies) {
92-
this->dependencies = std::move(dependencies.get());
93-
return std::error_code();
94-
}
95-
96-
return dependencies.getError();
9755
}
98-
99-
virtual void collectVisibleTopLevelModuleNames(
100-
SmallVectorImpl<Identifier> &names) const override {
101-
llvm_unreachable("Not used");
56+
assert(fs.exists(InPath));
57+
// Use the private interface file if exits.
58+
auto PrivateInPath =
59+
BaseName.getName(file_types::TY_PrivateSwiftModuleInterfaceFile);
60+
if (fs.exists(PrivateInPath)) {
61+
InPath = PrivateInPath;
10262
}
103-
};
104-
105-
/// A ModuleLoader that loads placeholder dependency module stubs specified in
106-
/// -placeholder-dependency-module-map-file
107-
/// This loader is used only in dependency scanning to inform the scanner that a
108-
/// set of modules constitute placeholder dependencies that are not visible to the
109-
/// scanner but will nevertheless be provided by the scanner's clients.
110-
/// This "loader" will not attempt to load any module files.
111-
class PlaceholderSwiftModuleScanner : public ModuleDependencyScanner {
112-
/// Scan the given placeholder module map
113-
void parsePlaceholderModuleMap(StringRef fileName) {
114-
ExplicitModuleMapParser parser(Allocator);
115-
auto result =
116-
parser.parseSwiftExplicitModuleMap(fileName, PlaceholderDependencyModuleMap);
117-
if (result == std::errc::invalid_argument) {
118-
Ctx.Diags.diagnose(SourceLoc(),
119-
diag::placeholder_dependency_module_map_corrupted,
120-
fileName);
121-
}
122-
else if (result == std::errc::no_such_file_or_directory) {
123-
Ctx.Diags.diagnose(SourceLoc(),
124-
diag::placeholder_dependency_module_map_missing,
125-
fileName);
126-
}
63+
auto dependencies = scanInterfaceFile(InPath, IsFramework);
64+
if (dependencies) {
65+
this->dependencies = std::move(dependencies.get());
66+
return std::error_code();
12767
}
12868

129-
llvm::StringMap<ExplicitModuleInfo> PlaceholderDependencyModuleMap;
130-
llvm::BumpPtrAllocator Allocator;
131-
132-
public:
133-
PlaceholderSwiftModuleScanner(ASTContext &ctx, ModuleLoadingMode LoadMode,
134-
Identifier moduleName,
135-
StringRef PlaceholderDependencyModuleMap,
136-
InterfaceSubContextDelegate &astDelegate)
137-
: ModuleDependencyScanner(ctx, LoadMode, moduleName, astDelegate,
138-
ModuleDependenciesKind::SwiftPlaceholder) {
139-
140-
// FIXME: Find a better place for this map to live, to avoid
141-
// doing the parsing on every module.
142-
if (!PlaceholderDependencyModuleMap.empty()) {
143-
parsePlaceholderModuleMap(PlaceholderDependencyModuleMap);
144-
}
145-
}
69+
return dependencies.getError();
70+
}
14671

147-
std::error_code findModuleFilesInDirectory(
148-
AccessPathElem ModuleID, const SerializedModuleBaseName &BaseName,
149-
SmallVectorImpl<char> *ModuleInterfacePath,
150-
std::unique_ptr<llvm::MemoryBuffer> *ModuleBuffer,
151-
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer,
152-
std::unique_ptr<llvm::MemoryBuffer> *ModuleSourceInfoBuffer,
153-
bool IsFramework) override {
154-
StringRef moduleName = ModuleID.Item.str();
155-
auto it = PlaceholderDependencyModuleMap.find(moduleName);
156-
// If no placeholder module stub path is given matches the name, return with an
157-
// error code.
158-
if (it == PlaceholderDependencyModuleMap.end()) {
159-
return std::make_error_code(std::errc::not_supported);
160-
}
161-
auto &moduleInfo = it->getValue();
162-
assert(!moduleInfo.moduleBuffer &&
163-
"Placeholder dependency module stubs cannot have an associated buffer");
16472

165-
auto dependencies = ModuleDependencies::forPlaceholderSwiftModuleStub(
166-
moduleInfo.modulePath, moduleInfo.moduleDocPath,
167-
moduleInfo.moduleSourceInfoPath);
168-
this->dependencies = std::move(dependencies);
169-
return std::error_code{};
73+
std::error_code PlaceholderSwiftModuleScanner::findModuleFilesInDirectory(
74+
AccessPathElem ModuleID, const SerializedModuleBaseName &BaseName,
75+
SmallVectorImpl<char> *ModuleInterfacePath,
76+
std::unique_ptr<llvm::MemoryBuffer> *ModuleBuffer,
77+
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer,
78+
std::unique_ptr<llvm::MemoryBuffer> *ModuleSourceInfoBuffer,
79+
bool IsFramework) {
80+
StringRef moduleName = ModuleID.Item.str();
81+
auto it = PlaceholderDependencyModuleMap.find(moduleName);
82+
// If no placeholder module stub path is given matches the name, return with an
83+
// error code.
84+
if (it == PlaceholderDependencyModuleMap.end()) {
85+
return std::make_error_code(std::errc::not_supported);
17086
}
171-
};
172-
} // namespace
87+
auto &moduleInfo = it->getValue();
88+
assert(!moduleInfo.moduleBuffer &&
89+
"Placeholder dependency module stubs cannot have an associated buffer");
90+
91+
auto dependencies = ModuleDependencies::forPlaceholderSwiftModuleStub(
92+
moduleInfo.modulePath, moduleInfo.moduleDocPath,
93+
moduleInfo.moduleSourceInfoPath);
94+
this->dependencies = std::move(dependencies);
95+
return std::error_code{};
96+
}
17397

17498
static std::vector<std::string> getCompiledCandidates(ASTContext &ctx,
17599
StringRef moduleName,

0 commit comments

Comments
 (0)