| //===--- SourceLoader.cpp - Import .swift files as modules ----------------===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| /// |
| /// \file |
| /// \brief A simple module loader that loads .swift source files. |
| /// |
| //===----------------------------------------------------------------------===// |
| |
| #include "swift/Sema/SourceLoader.h" |
| #include "swift/Subsystems.h" |
| #include "swift/AST/DiagnosticsSema.h" |
| #include "swift/Parse/DelayedParsingCallbacks.h" |
| #include "swift/Parse/PersistentParserState.h" |
| #include "swift/Basic/SourceManager.h" |
| #include "llvm/ADT/SmallString.h" |
| #include "llvm/Support/MemoryBuffer.h" |
| #include "llvm/Support/Path.h" |
| #include "llvm/Support/SaveAndRestore.h" |
| #include <system_error> |
| |
| using namespace swift; |
| |
| // FIXME: Basically the same as SerializedModuleLoader. |
| using FileOrError = llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>; |
| |
| static FileOrError findModule(ASTContext &ctx, StringRef moduleID, |
| SourceLoc importLoc) { |
| llvm::SmallString<128> inputFilename; |
| |
| for (auto Path : ctx.SearchPathOpts.ImportSearchPaths) { |
| inputFilename = Path; |
| llvm::sys::path::append(inputFilename, moduleID); |
| inputFilename.append(".swift"); |
| llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileBufOrErr = |
| llvm::MemoryBuffer::getFile(inputFilename.str()); |
| |
| // Return if we loaded a file |
| if (FileBufOrErr) |
| return FileBufOrErr; |
| // Or if we get any error other than the file not existing |
| auto err = FileBufOrErr.getError(); |
| if (err != std::errc::no_such_file_or_directory) |
| return FileBufOrErr; |
| } |
| |
| return make_error_code(std::errc::no_such_file_or_directory); |
| } |
| |
| namespace { |
| |
| /// Don't parse any function bodies except those that are transparent. |
| class SkipNonTransparentFunctions : public DelayedParsingCallbacks { |
| bool shouldDelayFunctionBodyParsing(Parser &TheParser, |
| AbstractFunctionDecl *AFD, |
| const DeclAttributes &Attrs, |
| SourceRange BodyRange) override { |
| return Attrs.hasAttribute<TransparentAttr>(); |
| } |
| }; |
| |
| } // unnamed namespace |
| |
| bool SourceLoader::canImportModule(std::pair<Identifier, SourceLoc> ID) { |
| // Search the memory buffers to see if we can find this file on disk. |
| FileOrError inputFileOrError = findModule(Ctx, ID.first.str(), |
| ID.second); |
| if (!inputFileOrError) { |
| auto err = inputFileOrError.getError(); |
| if (err != std::errc::no_such_file_or_directory) { |
| Ctx.Diags.diagnose(ID.second, diag::sema_opening_import, |
| ID.first, err.message()); |
| } |
| |
| return false; |
| } |
| return true; |
| } |
| |
| ModuleDecl *SourceLoader::loadModule(SourceLoc importLoc, |
| ArrayRef<std::pair<Identifier, |
| SourceLoc>> path) { |
| // FIXME: Swift submodules? |
| if (path.size() > 1) |
| return nullptr; |
| |
| auto moduleID = path[0]; |
| |
| FileOrError inputFileOrError = findModule(Ctx, moduleID.first.str(), |
| moduleID.second); |
| if (!inputFileOrError) { |
| auto err = inputFileOrError.getError(); |
| if (err != std::errc::no_such_file_or_directory) { |
| Ctx.Diags.diagnose(moduleID.second, diag::sema_opening_import, |
| moduleID.first, err.message()); |
| } |
| |
| return nullptr; |
| } |
| std::unique_ptr<llvm::MemoryBuffer> inputFile = |
| std::move(inputFileOrError.get()); |
| |
| addDependency(inputFile->getBufferIdentifier()); |
| |
| // Turn off debugging while parsing other modules. |
| llvm::SaveAndRestore<bool> turnOffDebug(Ctx.LangOpts.DebugConstraintSolver, |
| false); |
| |
| unsigned bufferID; |
| if (auto BufID = |
| Ctx.SourceMgr.getIDForBufferIdentifier(inputFile->getBufferIdentifier())) |
| bufferID = BufID.getValue(); |
| else |
| bufferID = Ctx.SourceMgr.addNewSourceBuffer(std::move(inputFile)); |
| |
| auto *importMod = ModuleDecl::create(moduleID.first, Ctx); |
| if (EnableResilience) |
| importMod->setResilienceStrategy(ResilienceStrategy::Resilient); |
| Ctx.LoadedModules[moduleID.first] = importMod; |
| |
| auto implicitImportKind = SourceFile::ImplicitModuleImportKind::Stdlib; |
| if (!Ctx.getStdlibModule()) |
| implicitImportKind = SourceFile::ImplicitModuleImportKind::None; |
| |
| auto *importFile = new (Ctx) SourceFile(*importMod, SourceFileKind::Library, |
| bufferID, implicitImportKind, |
| Ctx.LangOpts.KeepTokensInSourceFile); |
| importMod->addFile(*importFile); |
| |
| bool done; |
| PersistentParserState persistentState; |
| SkipNonTransparentFunctions delayCallbacks; |
| parseIntoSourceFile(*importFile, bufferID, &done, nullptr, &persistentState, |
| SkipBodies ? &delayCallbacks : nullptr); |
| assert(done && "Parser returned early?"); |
| (void)done; |
| |
| if (SkipBodies) |
| performDelayedParsing(importMod, persistentState, nullptr); |
| |
| // FIXME: Support recursive definitions in immediate modes by making type |
| // checking even lazier. |
| if (SkipBodies) |
| performNameBinding(*importFile); |
| else |
| performTypeChecking(*importFile, persistentState.getTopLevelContext(), |
| None); |
| return importMod; |
| } |
| |
| void SourceLoader::loadExtensions(NominalTypeDecl *nominal, |
| unsigned previousGeneration) { |
| // Type-checking the source automatically loads all extensions; there's |
| // nothing to do here. |
| } |