mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[Serialization] Preserve submodule import paths through serialization.
This is a bit of a hack, but Clang submodules are the only case we have to support. Part of <rdar://problem/13140302> Swift SVN r20287
This commit is contained in:
@@ -81,16 +81,18 @@ public:
|
||||
private:
|
||||
const unsigned IsExported : 1;
|
||||
const unsigned IsHeader : 1;
|
||||
const unsigned IsScoped : 1;
|
||||
|
||||
Dependency(StringRef path, bool exported, bool isHeader)
|
||||
: RawPath(path), IsExported(exported), IsHeader(isHeader){}
|
||||
Dependency(StringRef path, bool isHeader, bool exported, bool isScoped)
|
||||
: RawPath(path), IsExported(exported), IsHeader(isHeader),
|
||||
IsScoped(isScoped) {}
|
||||
|
||||
public:
|
||||
Dependency(StringRef path, bool exported)
|
||||
: Dependency(path, exported, false) {}
|
||||
Dependency(StringRef path, bool exported, bool isScoped)
|
||||
: Dependency(path, false, exported, isScoped) {}
|
||||
|
||||
static Dependency forHeader(StringRef headerPath, bool exported) {
|
||||
return Dependency(headerPath, exported, true);
|
||||
return Dependency(headerPath, true, exported, false);
|
||||
}
|
||||
|
||||
bool isLoaded() const {
|
||||
@@ -99,6 +101,9 @@ public:
|
||||
|
||||
bool isExported() const { return IsExported; }
|
||||
bool isHeader() const { return IsHeader; }
|
||||
bool isScoped() const { return IsScoped; }
|
||||
|
||||
std::string getPrettyPrintedPath() const;
|
||||
};
|
||||
|
||||
private:
|
||||
@@ -505,7 +510,7 @@ public:
|
||||
///
|
||||
/// If the name matches the name of the current module, a shadowed module
|
||||
/// is loaded instead.
|
||||
Module *getModule(Identifier name);
|
||||
Module *getModule(ArrayRef<Identifier> name);
|
||||
|
||||
/// Reads a substitution record from \c DeclTypeCursor.
|
||||
///
|
||||
|
||||
@@ -355,7 +355,10 @@ namespace input_block {
|
||||
using ImportedModuleLayout = BCRecordLayout<
|
||||
IMPORTED_MODULE,
|
||||
BCFixed<1>, // exported?
|
||||
BCBlob // module name, optionally followed by a null and then an import path
|
||||
BCFixed<1>, // scoped?
|
||||
BCBlob // module name, with submodule path pieces separated by \0s.
|
||||
// If the 'scoped' flag is set, the final path piece is an access
|
||||
// path within the module.
|
||||
>;
|
||||
|
||||
using LinkLibraryLayout = BCRecordLayout<
|
||||
|
||||
@@ -1347,25 +1347,27 @@ Module *ModuleFile::getModule(ModuleID MID) {
|
||||
return getModule(getIdentifier(MID));
|
||||
}
|
||||
|
||||
Module *ModuleFile::getModule(Identifier name) {
|
||||
if (name.empty())
|
||||
Module *ModuleFile::getModule(ArrayRef<Identifier> name) {
|
||||
if (name.empty() || name.front().empty())
|
||||
return getContext().TheBuiltinModule;
|
||||
|
||||
// FIXME: duplicated from NameBinder::getModule
|
||||
// FIXME: provide a real source location.
|
||||
if (name == FileContext->getParentModule()->Name) {
|
||||
if (name.size() == 1 &&
|
||||
name.front() == FileContext->getParentModule()->Name) {
|
||||
if (!ShadowedModule) {
|
||||
auto importer = getContext().getClangModuleLoader();
|
||||
assert(importer && "no way to import shadowed module");
|
||||
ShadowedModule = importer->loadModule(SourceLoc(),
|
||||
std::make_pair(name, SourceLoc()));
|
||||
{ { name.front(), SourceLoc() } });
|
||||
}
|
||||
|
||||
return ShadowedModule;
|
||||
}
|
||||
|
||||
// FIXME: provide a real source location.
|
||||
return getContext().getModule(std::make_pair(name, SourceLoc()));
|
||||
SmallVector<ImportDecl::AccessPathElement, 4> importPath;
|
||||
for (auto pathElem : name)
|
||||
importPath.push_back({ pathElem, SourceLoc() });
|
||||
return getContext().getModule(importPath);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -181,6 +181,12 @@ SerializedModuleLoader::validateSerializedAST(StringRef data) {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string ModuleFile::Dependency::getPrettyPrintedPath() const {
|
||||
std::string output = RawPath.str();
|
||||
std::replace(output.begin(), output.end(), '\0', '.');
|
||||
return output;
|
||||
}
|
||||
|
||||
namespace {
|
||||
class PrettyModuleFileDeserialization : public llvm::PrettyStackTraceEntry {
|
||||
const ModuleFile &File;
|
||||
@@ -579,9 +585,10 @@ ModuleFile::ModuleFile(
|
||||
SourcePaths.push_back(blobData);
|
||||
break;
|
||||
case input_block::IMPORTED_MODULE: {
|
||||
bool exported;
|
||||
input_block::ImportedModuleLayout::readRecord(scratch, exported);
|
||||
Dependencies.push_back({blobData, exported});
|
||||
bool exported, scoped;
|
||||
input_block::ImportedModuleLayout::readRecord(scratch,
|
||||
exported, scoped);
|
||||
Dependencies.push_back({blobData, exported, scoped});
|
||||
break;
|
||||
}
|
||||
case input_block::LINK_LIBRARY: {
|
||||
@@ -803,16 +810,28 @@ bool ModuleFile::associateWithFileContext(FileUnit *file) {
|
||||
continue;
|
||||
}
|
||||
|
||||
StringRef modulePath, scopePath;
|
||||
std::tie(modulePath, scopePath) = dependency.RawPath.split('\0');
|
||||
StringRef modulePathStr = dependency.RawPath;
|
||||
StringRef scopePath;
|
||||
if (dependency.isScoped()) {
|
||||
auto splitPoint = modulePathStr.find_last_of('\0');
|
||||
assert(splitPoint != StringRef::npos);
|
||||
scopePath = modulePathStr.substr(splitPoint+1);
|
||||
modulePathStr = modulePathStr.slice(0, splitPoint);
|
||||
}
|
||||
|
||||
auto moduleID = ctx.getIdentifier(modulePath);
|
||||
assert(!moduleID.empty() &&
|
||||
SmallVector<Identifier, 4> modulePath;
|
||||
while (!modulePathStr.empty()) {
|
||||
StringRef nextComponent;
|
||||
std::tie(nextComponent, modulePathStr) = modulePathStr.split('\0');
|
||||
modulePath.push_back(ctx.getIdentifier(nextComponent));
|
||||
assert(!modulePath.back().empty() &&
|
||||
"invalid module name (submodules not yet supported)");
|
||||
auto module = getModule(moduleID);
|
||||
}
|
||||
auto module = getModule(modulePath);
|
||||
if (!module) {
|
||||
// If we're missing the module we're shadowing, treat that specially.
|
||||
if (moduleID == file->getParentModule()->Name) {
|
||||
if (modulePath.size() == 1 &&
|
||||
modulePath.front() == file->getParentModule()->Name) {
|
||||
error(ModuleStatus::MissingShadowedModule);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -25,8 +25,11 @@
|
||||
#include "swift/Basic/STLExtras.h"
|
||||
#include "swift/Basic/SourceManager.h"
|
||||
#include "swift/ClangImporter/ClangImporter.h"
|
||||
#include "swift/ClangImporter/ClangModule.h"
|
||||
#include "swift/Serialization/BCRecordLayout.h"
|
||||
|
||||
#include "clang/Basic/Module.h"
|
||||
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/Bitcode/BitstreamWriter.h"
|
||||
@@ -400,8 +403,23 @@ removeDuplicateImports(SmallVectorImpl<Module::ImportedModule> &imports) {
|
||||
using ImportPathBlob = llvm::SmallString<64>;
|
||||
static void flattenImportPath(const Module::ImportedModule &import,
|
||||
ImportPathBlob &out) {
|
||||
// FIXME: Submodules?
|
||||
ArrayRef<FileUnit *> files = import.second->getFiles();
|
||||
if (auto clangModule = dyn_cast<ClangModuleUnit>(files.front())) {
|
||||
// FIXME: This is an awful hack to handle Clang submodules.
|
||||
// Once Swift has a native notion of submodules, this can go away.
|
||||
const clang::Module *submodule = clangModule->getClangModule();
|
||||
SmallVector<StringRef, 4> submoduleNames;
|
||||
do {
|
||||
submoduleNames.push_back(submodule->Name);
|
||||
submodule = submodule->Parent;
|
||||
} while (submodule);
|
||||
std::reverse(submoduleNames.begin(), submoduleNames.end());
|
||||
interleave(submoduleNames,
|
||||
[&out](StringRef next) { out.append(next); },
|
||||
[&out] { out.push_back('\0'); });
|
||||
} else {
|
||||
out.append(import.second->Name.str());
|
||||
}
|
||||
|
||||
if (import.first.empty())
|
||||
return;
|
||||
@@ -474,7 +492,7 @@ void Serializer::writeInputFiles(FilenamesTy inputFiles,
|
||||
ImportPathBlob importPath;
|
||||
flattenImportPath(import, importPath);
|
||||
ImportedModule.emit(ScratchRecord, publicImportSet.count(import),
|
||||
importPath);
|
||||
!import.first.empty(), importPath);
|
||||
}
|
||||
|
||||
if (!moduleLinkName.empty()) {
|
||||
|
||||
@@ -243,13 +243,13 @@ FileUnit *SerializedModuleLoader::loadAST(
|
||||
assert(!missing.empty() && "unknown missing dependency?");
|
||||
if (missing.size() == 1) {
|
||||
Ctx.Diags.diagnose(*diagLoc, diag::serialization_missing_single_dependency,
|
||||
missing.begin()->RawPath);
|
||||
missing.front().getPrettyPrintedPath());
|
||||
} else {
|
||||
llvm::SmallString<64> missingNames;
|
||||
missingNames += '\'';
|
||||
interleave(missing,
|
||||
[&](const ModuleFile::Dependency &next) {
|
||||
missingNames += next.RawPath;
|
||||
missingNames += next.getPrettyPrintedPath();
|
||||
},
|
||||
[&] { missingNames += "', '"; });
|
||||
missingNames += '\'';
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
// RUN: rm -rf %t/clang-module-cache
|
||||
// RUN: %swift %clang-importer-sdk -parse -verify -module-cache-path %t/clang-module-cache -target x86_64-apple-macosx10.9 %s
|
||||
// RUN: rm -rf %t && mkdir -p %t
|
||||
// RUN: %swift %clang-importer-sdk -parse -verify -module-cache-path %t/clang-module-cache %s
|
||||
// RUN: ls -lR %t/clang-module-cache | FileCheck %s
|
||||
// CHECK: ctypes{{.*}}.pcm
|
||||
|
||||
// RUN: %swift %clang-importer-sdk -emit-module-path %t/submodules.swiftmodule -module-cache-path %t/clang-module-cache %s
|
||||
// RUN: echo 'import submodules; println("\(x), \(y)")' | %swift %clang-importer-sdk -parse - -I %t
|
||||
// RUN: echo 'import submodules; println("\(x), \(y)")' | not %swift -parse - -I %t 2>&1 | FileCheck -check-prefix=MISSING %s
|
||||
|
||||
import ctypes
|
||||
import ctypes.bits
|
||||
// MISSING: missing required modules:
|
||||
// MISSING-DAG: 'ctypes.bits'
|
||||
// MISSING-DAG: 'ctypes'
|
||||
|
||||
// From bits submodule
|
||||
var x : DWORD = MY_INT
|
||||
var y : CInt = x
|
||||
public var x : DWORD = MY_INT
|
||||
public var y : CInt = x
|
||||
|
||||
Reference in New Issue
Block a user