Skip to content

[Dependency Scanner] Use pragma clang module import in the hack file used to invoke the clang dependency scanner. #32590

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 30, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 18 additions & 24 deletions lib/ClangImporter/ClangModuleDependencyScanner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ using namespace clang::tooling;
using namespace clang::tooling::dependencies;

class swift::ClangModuleDependenciesCacheImpl {
/// The name of the file used for the "import hack" to compute module
/// Cache the names of the files used for the "import hack" to compute module
/// dependencies.
/// FIXME: This should go away once Clang's dependency scanning library
/// can scan by module name.
std::string importHackFile;
llvm::StringMap<std::string> importHackFileCache;

public:
/// Set containing all of the Clang modules that have already been seen.
Expand All @@ -43,38 +43,41 @@ class swift::ClangModuleDependenciesCacheImpl {
DependencyScanningTool tool;

ClangModuleDependenciesCacheImpl()
: service(ScanningMode::MinimizedSourcePreprocessing,
ScanningOutputFormat::Full),
: importHackFileCache(),
service(ScanningMode::MinimizedSourcePreprocessing, ScanningOutputFormat::Full),
tool(service) { }
~ClangModuleDependenciesCacheImpl();

/// Retrieve the name of the file used for the "import hack" that is
/// used to scan the dependencies of a Clang module.
llvm::ErrorOr<StringRef> getImportHackFile();
llvm::ErrorOr<StringRef> getImportHackFile(StringRef moduleName);
};

ClangModuleDependenciesCacheImpl::~ClangModuleDependenciesCacheImpl() {
if (!importHackFile.empty()) {
llvm::sys::fs::remove(importHackFile);
if (!importHackFileCache.empty()) {
for (auto& it: importHackFileCache) {
llvm::sys::fs::remove(it.second);
}
}
}

llvm::ErrorOr<StringRef> ClangModuleDependenciesCacheImpl::getImportHackFile() {
if (!importHackFile.empty())
return importHackFile;
llvm::ErrorOr<StringRef> ClangModuleDependenciesCacheImpl::getImportHackFile(StringRef moduleName) {
auto cacheIt = importHackFileCache.find(moduleName.str());
if (cacheIt != importHackFileCache.end())
return cacheIt->second;

// Create a temporary file.
int resultFD;
SmallString<128> resultPath;
if (auto error = llvm::sys::fs::createTemporaryFile(
"import-hack", "m", resultFD, resultPath))
"import-hack-" + moduleName.str(), "c", resultFD, resultPath))
return error;

llvm::raw_fd_ostream out(resultFD, /*shouldClose=*/true);
out << "@import HACK_MODULE_NAME;\n";
out << "#pragma clang module import " << moduleName.str() << ";\n";
llvm::sys::RemoveFileOnSignal(resultPath);
importHackFile = resultPath.str().str();
return importHackFile;
importHackFileCache.insert(std::make_pair(moduleName, resultPath.str().str()));
return importHackFileCache[moduleName];
}

namespace {
Expand Down Expand Up @@ -283,12 +286,11 @@ Optional<ModuleDependencies> ClangImporter::getModuleDependencies(
auto clangImpl = getOrCreateClangImpl(cache);

// HACK! Replace the module import buffer name with the source file hack.
auto importHackFile = clangImpl->getImportHackFile();
auto importHackFile = clangImpl->getImportHackFile(moduleName);
if (!importHackFile) {
// FIXME: Emit a diagnostic here.
return None;
}

// Reform the Clang importer options.
// FIXME: Just save a reference or copy so we can get this back.
ClangImporterOptions importerOpts;
Expand All @@ -299,20 +301,13 @@ Optional<ModuleDependencies> ClangImporter::getModuleDependencies(
getClangDepScanningInvocationArguments(
ctx, importerOpts, *importHackFile);

// HACK! Trick out a .m file to use to import the module we name.
std::string moduleNameHackDefine =
("-DHACK_MODULE_NAME=" + moduleName).str();
commandLineArgs.push_back(moduleNameHackDefine);
commandLineArgs.push_back("-fmodules-ignore-macro=HACK_MODULE_NAME");

std::string workingDir =
ctx.SourceMgr.getFileSystem()->getCurrentWorkingDirectory().get();
CompileCommand command(workingDir, *importHackFile, commandLineArgs, "-");
SingleCommandCompilationDatabase database(command);

auto clangDependencies = clangImpl->tool.getFullDependencies(
database, workingDir, clangImpl->alreadySeen);

if (!clangDependencies) {
// FIXME: Route this to a normal diagnostic.
llvm::logAllUnhandledErrors(clangDependencies.takeError(), llvm::errs());
Expand All @@ -321,7 +316,6 @@ Optional<ModuleDependencies> ClangImporter::getModuleDependencies(

// Record module dependencies for each module we found.
recordModuleDependencies(cache, *clangDependencies);

return cache.findDependencies(moduleName, ModuleDependenciesKind::Clang);
}

Expand Down