//===--- SerializedModuleLoader.cpp - Import Swift modules ------*- c++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// #include "swift/Serialization/SerializedModuleLoader.h" #include "ModuleFile.h" #include "swift/Subsystems.h" #include "swift/AST/AST.h" #include "swift/AST/Component.h" #include "swift/AST/Diagnostics.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/system_error.h" using namespace swift; namespace { class SerializedModule : public LoadedModule { public: SerializedModule(ASTContext &ctx, SerializedModuleLoader &owner, Identifier name, Component *comp) : LoadedModule(DeclContextKind::SerializedModule, name, comp, ctx, owner) {} static bool classof(const DeclContext *DC) { return DC->getContextKind() == DeclContextKind::SerializedModule; } }; typedef std::pair AccessPathElem; } // FIXME: Copied from SourceLoader. Not bothering to fix until we decide that // the source loader search path should be the same as the module loader search // path. static llvm::error_code findModule(ASTContext &ctx, AccessPathElem moduleID, llvm::OwningPtr &buffer){ llvm::SmallString<64> moduleFilename(moduleID.first.str()); moduleFilename += ".sm"; llvm::SmallString<128> inputFilename; // First, search in the directory corresponding to the import location. // FIXME: This screams for a proper FileManager abstraction. llvm::SMLoc rawLoc = moduleID.second.Value; int currentBufferID = ctx.SourceMgr.FindBufferContainingLoc(rawLoc); if (currentBufferID >= 0) { const llvm::MemoryBuffer *importingBuffer = ctx.SourceMgr.getBufferInfo(currentBufferID).Buffer; StringRef currentDirectory = llvm::sys::path::parent_path(importingBuffer->getBufferIdentifier()); if (!currentDirectory.empty()) { inputFilename = currentDirectory; llvm::sys::path::append(inputFilename, moduleFilename.str()); llvm::error_code err = llvm::MemoryBuffer::getFile(inputFilename, buffer); if (!err) return err; } } // Second, search in the current directory. llvm::error_code err = llvm::MemoryBuffer::getFile(moduleFilename, buffer); if (!err) return err; // If we fail, search each import search path. for (auto Path : ctx.ImportSearchPaths) { inputFilename = Path; llvm::sys::path::append(inputFilename, moduleFilename.str()); err = llvm::MemoryBuffer::getFile(inputFilename, buffer); if (!err) return err; } return err; } static Module *makeTU(ASTContext &ctx, AccessPathElem moduleID, ArrayRef inputPaths) { Component *comp = new (ctx.Allocate(1)) Component(); TranslationUnit *TU = new (ctx) TranslationUnit(moduleID.first, comp, ctx, /*IsMainModule=*/false, /*IsReplModule=*/false); ctx.LoadedModules[moduleID.first.str()] = TU; std::vector BufferIDs; for (auto &path : inputPaths) { // Open the input file. llvm::OwningPtr InputFile; if (llvm::MemoryBuffer::getFileOrSTDIN(path, InputFile)) return nullptr; // Transfer ownership of the MemoryBuffer to the SourceMgr. // FIXME: include location llvm::SMLoc rawLoc = moduleID.second.Value; BufferIDs.push_back(ctx.SourceMgr.AddNewSourceBuffer(InputFile.take(), rawLoc)); } for (auto &BufferID : BufferIDs) { unsigned BufferOffset = 0; const llvm::MemoryBuffer *Buffer = ctx.SourceMgr.getMemoryBuffer(BufferID); do { parseIntoTranslationUnit(TU, BufferID, &BufferOffset, 0, /*SIL=*/nullptr); } while (BufferOffset != Buffer->getBufferSize()); } performNameBinding(TU); performTypeChecking(TU); return TU; } static Module *error(SerializedModuleLoader &owner, ASTContext &ctx, AccessPathElem moduleID, ModuleStatus reason) { switch (reason) { case ModuleStatus::Valid: case ModuleStatus::FallBackToTranslationUnit: llvm_unreachable("not an error"); case ModuleStatus::Malformed: ctx.Diags.diagnose(moduleID.second, diag::serialization_malformed_module); break; case ModuleStatus::FormatTooNew: ctx.Diags.diagnose(moduleID.second, diag::serialization_module_too_new); break; } // Return a dummy module to avoid future errors. auto comp = new (ctx.Allocate(1)) Component(); auto module = new (ctx) SerializedModule(ctx, owner, moduleID.first, comp); ctx.LoadedModules[moduleID.first.str()] = module; return module; } Module *SerializedModuleLoader::loadModule(SourceLoc importLoc, Module::AccessPathTy path) { // FIXME: Swift submodules? if (path.size() > 1) return nullptr; auto moduleID = path[0]; llvm::OwningPtr inputFile; if (llvm::error_code err = findModule(Ctx, moduleID, inputFile)) { if (err.value() != llvm::errc::no_such_file_or_directory) { Ctx.Diags.diagnose(moduleID.second, diag::sema_opening_import, moduleID.first.str(), err.message()); } return nullptr; } assert(inputFile); Module *result; llvm::OwningPtr loadedModuleFile; ModuleStatus err = ModuleFile::load(std::move(inputFile), loadedModuleFile); switch (err) { case ModuleStatus::Valid: llvm_unreachable("non-fallback modules not supported yet!"); case ModuleStatus::FallBackToTranslationUnit: result = makeTU(Ctx, moduleID, loadedModuleFile->getInputSourcePaths()); break; case ModuleStatus::FormatTooNew: case ModuleStatus::Malformed: return error(*this, Ctx, moduleID, err); } return result; }