std::pair<std::unique_ptr<llvm::MemoryBuffer>, std::unique_ptr<llvm::MemoryBuffer>> CompilerInstance::getInputBufferAndModuleDocBufferIfPresent( const InputFile &input) { if (auto b = input.buffer()) { return std::make_pair(llvm::MemoryBuffer::getMemBufferCopy( b->getBuffer(), b->getBufferIdentifier()), nullptr); } // FIXME: Working with filenames is fragile, maybe use the real path // or have some kind of FileManager. using FileOrError = llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>; FileOrError inputFileOrErr = llvm::MemoryBuffer::getFileOrSTDIN(input.file()); if (!inputFileOrErr) { Diagnostics.diagnose(SourceLoc(), diag::error_open_input_file, input.file(), inputFileOrErr.getError().message()); return std::make_pair(nullptr, nullptr); } if (!serialization::isSerializedAST((*inputFileOrErr)->getBuffer())) return std::make_pair(std::move(*inputFileOrErr), nullptr); if (Optional<std::unique_ptr<llvm::MemoryBuffer>> moduleDocBuffer = openModuleDoc(input)) { return std::make_pair(std::move(*inputFileOrErr), std::move(*moduleDocBuffer)); } return std::make_pair(nullptr, nullptr); }
Optional<std::unique_ptr<llvm::MemoryBuffer>> CompilerInstance::openModuleDoc(const InputFile &input) { llvm::SmallString<128> moduleDocFilePath(input.file()); llvm::sys::path::replace_extension(moduleDocFilePath, SERIALIZED_MODULE_DOC_EXTENSION); using FileOrError = llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>; FileOrError moduleDocFileOrErr = llvm::MemoryBuffer::getFileOrSTDIN(moduleDocFilePath); if (moduleDocFileOrErr) return std::move(*moduleDocFileOrErr); if (moduleDocFileOrErr.getError() == std::errc::no_such_file_or_directory) return std::unique_ptr<llvm::MemoryBuffer>(); Diagnostics.diagnose(SourceLoc(), diag::error_open_input_file, moduleDocFilePath, moduleDocFileOrErr.getError().message()); return None; }
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; }
bool CompilerInstance::setupForFileAt(unsigned i) { bool MainMode = (Invocation.getInputKind() == InputFileKind::IFK_Swift); bool SILMode = (Invocation.getInputKind() == InputFileKind::IFK_SIL); auto &File = Invocation.getFrontendOptions().Inputs.getInputFilenames()[i]; // FIXME: Working with filenames is fragile, maybe use the real path // or have some kind of FileManager. using namespace llvm::sys::path; if (Optional<unsigned> ExistingBufferID = SourceMgr.getIDForBufferIdentifier(File)) { if (SILMode || (MainMode && filename(File) == "main.swift")) MainBufferID = ExistingBufferID.getValue(); if (Invocation.getFrontendOptions().Inputs.isPrimaryInputAFileAt(i)) PrimaryBufferID = ExistingBufferID.getValue(); return false; // replaced by a memory buffer. } // Open the input file. using FileOrError = llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>; FileOrError InputFileOrErr = llvm::MemoryBuffer::getFileOrSTDIN(File); if (!InputFileOrErr) { Diagnostics.diagnose(SourceLoc(), diag::error_open_input_file, File, InputFileOrErr.getError().message()); return true; } if (serialization::isSerializedAST(InputFileOrErr.get()->getBuffer())) { llvm::SmallString<128> ModuleDocFilePath(File); llvm::sys::path::replace_extension(ModuleDocFilePath, SERIALIZED_MODULE_DOC_EXTENSION); FileOrError ModuleDocOrErr = llvm::MemoryBuffer::getFileOrSTDIN(ModuleDocFilePath.str()); if (!ModuleDocOrErr && ModuleDocOrErr.getError() != std::errc::no_such_file_or_directory) { Diagnostics.diagnose(SourceLoc(), diag::error_open_input_file, File, ModuleDocOrErr.getError().message()); return true; } PartialModules.push_back( {std::move(InputFileOrErr.get()), ModuleDocOrErr ? std::move(ModuleDocOrErr.get()) : nullptr}); return false; } // Transfer ownership of the MemoryBuffer to the SourceMgr. unsigned BufferID = SourceMgr.addNewSourceBuffer(std::move(InputFileOrErr.get())); InputSourceCodeBufferIDs.push_back(BufferID); if (SILMode || (MainMode && filename(File) == "main.swift")) MainBufferID = BufferID; if (Invocation.getFrontendOptions().Inputs.isPrimaryInputAFileAt(i)) PrimaryBufferID = BufferID; return false; }
bool CompilerInstance::setup(const CompilerInvocation &Invok) { Invocation = Invok; // Honor -Xllvm. if (!Invok.getFrontendOptions().LLVMArgs.empty()) { llvm::SmallVector<const char *, 4> Args; Args.push_back("swift (LLVM option parsing)"); for (unsigned i = 0, e = Invok.getFrontendOptions().LLVMArgs.size(); i != e; ++i) Args.push_back(Invok.getFrontendOptions().LLVMArgs[i].c_str()); Args.push_back(nullptr); llvm::cl::ParseCommandLineOptions(Args.size()-1, Args.data()); } if (Invocation.getDiagnosticOptions().ShowDiagnosticsAfterFatalError) { Diagnostics.setShowDiagnosticsAfterFatalError(); } if (Invocation.getDiagnosticOptions().SuppressWarnings) { Diagnostics.setSuppressWarnings(true); } if (Invocation.getDiagnosticOptions().WarningsAsErrors) { Diagnostics.setWarningsAsErrors(true); } // If we are asked to emit a module documentation file, configure lexing and // parsing to remember comments. if (!Invocation.getFrontendOptions().ModuleDocOutputPath.empty()) Invocation.getLangOptions().AttachCommentsToDecls = true; Context.reset(new ASTContext(Invocation.getLangOptions(), Invocation.getSearchPathOptions(), SourceMgr, Diagnostics)); if (Invocation.getFrontendOptions().EnableSourceImport) { bool immediate = Invocation.getFrontendOptions().actionIsImmediate(); bool enableResilience = Invocation.getFrontendOptions().EnableResilience; Context->addModuleLoader(SourceLoader::create(*Context, !immediate, enableResilience, DepTracker)); } auto SML = SerializedModuleLoader::create(*Context, DepTracker); this->SML = SML.get(); Context->addModuleLoader(std::move(SML)); // Wire up the Clang importer. If the user has specified an SDK, use it. // Otherwise, we just keep it around as our interface to Clang's ABI // knowledge. auto clangImporter = ClangImporter::create(*Context, Invocation.getClangImporterOptions(), DepTracker); if (!clangImporter) { Diagnostics.diagnose(SourceLoc(), diag::error_clang_importer_create_fail); return true; } Context->addModuleLoader(std::move(clangImporter), /*isClang*/true); assert(Lexer::isIdentifier(Invocation.getModuleName())); Optional<unsigned> CodeCompletionBufferID; auto CodeCompletePoint = Invocation.getCodeCompletionPoint(); if (CodeCompletePoint.first) { auto MemBuf = CodeCompletePoint.first; // CompilerInvocation doesn't own the buffers, copy to a new buffer. CodeCompletionBufferID = SourceMgr.addMemBufferCopy(MemBuf); BufferIDs.push_back(*CodeCompletionBufferID); SourceMgr.setCodeCompletionPoint(*CodeCompletionBufferID, CodeCompletePoint.second); } bool MainMode = (Invocation.getInputKind() == InputFileKind::IFK_Swift); bool SILMode = (Invocation.getInputKind() == InputFileKind::IFK_SIL); if (SILMode) Invocation.getLangOptions().EnableAccessControl = false; const Optional<SelectedInput> &PrimaryInput = Invocation.getFrontendOptions().PrimaryInput; // Add the memory buffers first, these will be associated with a filename // and they can replace the contents of an input filename. for (unsigned i = 0, e = Invocation.getInputBuffers().size(); i != e; ++i) { // CompilerInvocation doesn't own the buffers, copy to a new buffer. auto *InputBuffer = Invocation.getInputBuffers()[i]; auto Copy = std::unique_ptr<llvm::MemoryBuffer>( llvm::MemoryBuffer::getMemBufferCopy( InputBuffer->getBuffer(), InputBuffer->getBufferIdentifier())); if (serialization::isSerializedAST(Copy->getBuffer())) { PartialModules.push_back({ std::move(Copy), nullptr }); } else { unsigned BufferID = SourceMgr.addNewSourceBuffer(std::move(Copy)); BufferIDs.push_back(BufferID); if (SILMode) MainBufferID = BufferID; if (PrimaryInput && PrimaryInput->isBuffer() && PrimaryInput->Index == i) PrimaryBufferID = BufferID; } } for (unsigned i = 0, e = Invocation.getInputFilenames().size(); i != e; ++i) { auto &File = Invocation.getInputFilenames()[i]; // FIXME: Working with filenames is fragile, maybe use the real path // or have some kind of FileManager. using namespace llvm::sys::path; if (Optional<unsigned> ExistingBufferID = SourceMgr.getIDForBufferIdentifier(File)) { if (SILMode || (MainMode && filename(File) == "main.swift")) MainBufferID = ExistingBufferID.getValue(); if (PrimaryInput && PrimaryInput->isFilename() && PrimaryInput->Index == i) PrimaryBufferID = ExistingBufferID.getValue(); continue; // replaced by a memory buffer. } // Open the input file. using FileOrError = llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>; FileOrError InputFileOrErr = llvm::MemoryBuffer::getFileOrSTDIN(File); if (!InputFileOrErr) { Diagnostics.diagnose(SourceLoc(), diag::error_open_input_file, File, InputFileOrErr.getError().message()); return true; } if (serialization::isSerializedAST(InputFileOrErr.get()->getBuffer())) { llvm::SmallString<128> ModuleDocFilePath(File); llvm::sys::path::replace_extension(ModuleDocFilePath, SERIALIZED_MODULE_DOC_EXTENSION); FileOrError ModuleDocOrErr = llvm::MemoryBuffer::getFileOrSTDIN(ModuleDocFilePath.str()); if (!ModuleDocOrErr && ModuleDocOrErr.getError() != std::errc::no_such_file_or_directory) { Diagnostics.diagnose(SourceLoc(), diag::error_open_input_file, File, ModuleDocOrErr.getError().message()); return true; } PartialModules.push_back({ std::move(InputFileOrErr.get()), ModuleDocOrErr? std::move(ModuleDocOrErr.get()) : nullptr }); continue; } // Transfer ownership of the MemoryBuffer to the SourceMgr. unsigned BufferID = SourceMgr.addNewSourceBuffer(std::move(InputFileOrErr.get())); BufferIDs.push_back(BufferID); if (SILMode || (MainMode && filename(File) == "main.swift")) MainBufferID = BufferID; if (PrimaryInput && PrimaryInput->isFilename() && PrimaryInput->Index == i) PrimaryBufferID = BufferID; } // Set the primary file to the code-completion point if one exists. if (CodeCompletionBufferID.hasValue()) PrimaryBufferID = *CodeCompletionBufferID; if (MainMode && MainBufferID == NO_SUCH_BUFFER && BufferIDs.size() == 1) MainBufferID = BufferIDs.front(); return false; }
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); 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; }