| //===--- Frontend.cpp - frontend utility methods --------------------------===// |
| // |
| // 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 |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file contains utility methods for parsing and performing semantic |
| // on modules. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "swift/Frontend/Frontend.h" |
| #include "swift/Subsystems.h" |
| #include "swift/Strings.h" |
| #include "swift/AST/ASTContext.h" |
| #include "swift/AST/DiagnosticsFrontend.h" |
| #include "swift/AST/DiagnosticsSema.h" |
| #include "swift/AST/Module.h" |
| #include "swift/Basic/SourceManager.h" |
| #include "swift/Parse/DelayedParsingCallbacks.h" |
| #include "swift/Parse/Lexer.h" |
| #include "swift/SIL/SILModule.h" |
| #include "swift/Serialization/SerializedModuleLoader.h" |
| #include "llvm/ADT/SmallVector.h" |
| #include "llvm/ADT/Triple.h" |
| #include "llvm/Support/CommandLine.h" |
| #include "llvm/Support/MemoryBuffer.h" |
| #include "llvm/Support/Path.h" |
| |
| using namespace swift; |
| |
| void CompilerInstance::createSILModule(bool WholeModule) { |
| assert(MainModule && "main module not created yet"); |
| TheSILModule = SILModule::createEmptyModule(getMainModule(), |
| Invocation.getSILOptions(), |
| WholeModule); |
| } |
| |
| void CompilerInstance::setPrimarySourceFile(SourceFile *SF) { |
| assert(SF); |
| assert(MainModule && "main module not created yet"); |
| assert(!PrimarySourceFile && "already has a primary source file"); |
| assert(PrimaryBufferID == NO_SUCH_BUFFER || !SF->getBufferID().hasValue() || |
| SF->getBufferID().getValue() == PrimaryBufferID); |
| PrimarySourceFile = SF; |
| PrimarySourceFile->setReferencedNameTracker(NameTracker); |
| } |
| |
| 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 *CompilerInstance::getMainModule() { |
| if (!MainModule) { |
| Identifier ID = Context->getIdentifier(Invocation.getModuleName()); |
| MainModule = ModuleDecl::create(ID, *Context); |
| if (Invocation.getFrontendOptions().EnableTesting) |
| MainModule->setTestingEnabled(); |
| |
| if (Invocation.getFrontendOptions().EnableResilience) |
| MainModule->setResilienceStrategy(ResilienceStrategy::Resilient); |
| else if (Invocation.getFrontendOptions().SILSerializeAll) |
| MainModule->setResilienceStrategy(ResilienceStrategy::Fragile); |
| } |
| return MainModule; |
| } |
| |
| void CompilerInstance::performSema() { |
| const FrontendOptions &options = Invocation.getFrontendOptions(); |
| const InputFileKind Kind = Invocation.getInputKind(); |
| ModuleDecl *MainModule = getMainModule(); |
| Context->LoadedModules[MainModule->getName()] = MainModule; |
| |
| auto modImpKind = SourceFile::ImplicitModuleImportKind::Stdlib; |
| |
| if (Kind == InputFileKind::IFK_SIL) { |
| assert(BufferIDs.size() == 1); |
| assert(MainBufferID != NO_SUCH_BUFFER); |
| // Assume WMO, if a -primary-file option was not provided. |
| createSILModule(!options.PrimaryInput.hasValue()); |
| modImpKind = SourceFile::ImplicitModuleImportKind::None; |
| } else if (Invocation.getParseStdlib()) { |
| modImpKind = SourceFile::ImplicitModuleImportKind::Builtin; |
| } |
| |
| switch (modImpKind) { |
| case SourceFile::ImplicitModuleImportKind::None: |
| case SourceFile::ImplicitModuleImportKind::Builtin: |
| break; |
| case SourceFile::ImplicitModuleImportKind::Stdlib: { |
| ModuleDecl *M = Context->getStdlibModule(true); |
| |
| if (!M) { |
| Diagnostics.diagnose(SourceLoc(), diag::error_stdlib_not_found, |
| Invocation.getTargetTriple()); |
| return; |
| } |
| |
| // If we failed to load, we should have already diagnosed |
| if (M->failedToLoad()) { |
| assert(Diagnostics.hadAnyError() && |
| "Module failed to load but nothing was diagnosed?"); |
| return; |
| } |
| |
| const auto &silOptions = Invocation.getSILOptions(); |
| if ((silOptions.Optimization <= SILOptions::SILOptMode::None && |
| (options.RequestedAction == FrontendOptions::EmitObject || |
| options.RequestedAction == FrontendOptions::Immediate || |
| options.RequestedAction == FrontendOptions::EmitSIL)) || |
| (silOptions.Optimization == SILOptions::SILOptMode::None && |
| options.RequestedAction >= FrontendOptions::EmitSILGen)) { |
| // Implicitly import the SwiftOnoneSupport module in non-optimized |
| // builds. This allows for use of popular specialized functions |
| // from the standard library, which makes the non-optimized builds |
| // execute much faster. |
| Invocation.getFrontendOptions() |
| .ImplicitImportModuleNames.push_back(SWIFT_ONONE_SUPPORT); |
| } |
| break; |
| } |
| } |
| |
| auto clangImporter = |
| static_cast<ClangImporter *>(Context->getClangModuleLoader()); |
| |
| ModuleDecl *underlying = nullptr; |
| if (options.ImportUnderlyingModule) { |
| underlying = clangImporter->loadModule(SourceLoc(), |
| std::make_pair(MainModule->getName(), |
| SourceLoc())); |
| if (!underlying) { |
| Diagnostics.diagnose(SourceLoc(), diag::error_underlying_module_not_found, |
| MainModule->getName()); |
| } |
| } |
| |
| ModuleDecl *importedHeaderModule = nullptr; |
| StringRef implicitHeaderPath = options.ImplicitObjCHeaderPath; |
| if (!implicitHeaderPath.empty()) { |
| if (!clangImporter->importBridgingHeader(implicitHeaderPath, MainModule)) { |
| importedHeaderModule = clangImporter->getImportedHeaderModule(); |
| assert(importedHeaderModule); |
| } |
| } |
| |
| SmallVector<ModuleDecl *, 4> importModules; |
| if (!options.ImplicitImportModuleNames.empty()) { |
| for (auto &ImplicitImportModuleName : options.ImplicitImportModuleNames) { |
| if (Lexer::isIdentifier(ImplicitImportModuleName)) { |
| auto moduleID = Context->getIdentifier(ImplicitImportModuleName); |
| ModuleDecl *importModule = Context->getModule(std::make_pair(moduleID, |
| SourceLoc())); |
| if (importModule) { |
| importModules.push_back(importModule); |
| } else { |
| Diagnostics.diagnose(SourceLoc(), diag::sema_no_import, |
| ImplicitImportModuleName); |
| if (Invocation.getSearchPathOptions().SDKPath.empty() && |
| llvm::Triple(llvm::sys::getProcessTriple()).isMacOSX()) { |
| Diagnostics.diagnose(SourceLoc(), diag::sema_no_import_no_sdk); |
| Diagnostics.diagnose(SourceLoc(), |
| diag::sema_no_import_no_sdk_xcrun); |
| } |
| } |
| } else { |
| Diagnostics.diagnose(SourceLoc(), diag::error_bad_module_name, |
| ImplicitImportModuleName, false); |
| } |
| } |
| } |
| |
| auto addAdditionalInitialImports = [&](SourceFile *SF) { |
| if (!underlying && !importedHeaderModule && importModules.empty()) |
| return; |
| |
| using ImportPair = |
| std::pair<ModuleDecl::ImportedModule, SourceFile::ImportOptions>; |
| SmallVector<ImportPair, 4> additionalImports; |
| |
| if (underlying) |
| additionalImports.push_back({ { /*accessPath=*/{}, underlying }, |
| SourceFile::ImportFlags::Exported }); |
| if (importedHeaderModule) |
| additionalImports.push_back({ { /*accessPath=*/{}, importedHeaderModule }, |
| SourceFile::ImportFlags::Exported }); |
| if (!importModules.empty()) { |
| for (auto &importModule : importModules) { |
| additionalImports.push_back({ { /*accessPath=*/{}, importModule }, {} }); |
| } |
| } |
| |
| SF->addImports(additionalImports); |
| }; |
| |
| if (Kind == InputFileKind::IFK_Swift_REPL) { |
| auto *SingleInputFile = |
| new (*Context) SourceFile(*MainModule, Invocation.getSourceFileKind(), |
| None, modImpKind); |
| MainModule->addFile(*SingleInputFile); |
| addAdditionalInitialImports(SingleInputFile); |
| return; |
| } |
| |
| std::unique_ptr<DelayedParsingCallbacks> DelayedCB; |
| if (Invocation.isCodeCompletion()) { |
| DelayedCB.reset( |
| new CodeCompleteDelayedCallbacks(SourceMgr.getCodeCompletionLoc())); |
| } else if (Invocation.isDelayedFunctionBodyParsing()) { |
| DelayedCB.reset(new AlwaysDelayedCallbacks); |
| } |
| |
| PersistentParserState PersistentState; |
| |
| // Make sure the main file is the first file in the module. This may only be |
| // a source file, or it may be a SIL file, which requires pumping the parser. |
| // We parse it last, though, to make sure that it can use decls from other |
| // files in the module. |
| if (MainBufferID != NO_SUCH_BUFFER) { |
| assert(Kind == InputFileKind::IFK_Swift || Kind == InputFileKind::IFK_SIL); |
| |
| if (Kind == InputFileKind::IFK_Swift) |
| SourceMgr.setHashbangBufferID(MainBufferID); |
| |
| auto *MainFile = new (*Context) SourceFile(*MainModule, |
| Invocation.getSourceFileKind(), |
| MainBufferID, modImpKind); |
| MainModule->addFile(*MainFile); |
| addAdditionalInitialImports(MainFile); |
| |
| if (MainBufferID == PrimaryBufferID) |
| setPrimarySourceFile(MainFile); |
| } |
| |
| bool hadLoadError = false; |
| |
| // Parse all the partial modules first. |
| for (auto &PM : PartialModules) { |
| assert(PM.ModuleBuffer); |
| if (!SML->loadAST(*MainModule, SourceLoc(), std::move(PM.ModuleBuffer), |
| std::move(PM.ModuleDocBuffer))) |
| hadLoadError = true; |
| } |
| |
| // Then parse all the library files. |
| for (auto BufferID : BufferIDs) { |
| if (BufferID == MainBufferID) |
| continue; |
| |
| auto *NextInput = new (*Context) SourceFile(*MainModule, |
| SourceFileKind::Library, |
| BufferID, |
| modImpKind); |
| MainModule->addFile(*NextInput); |
| addAdditionalInitialImports(NextInput); |
| |
| if (BufferID == PrimaryBufferID) |
| setPrimarySourceFile(NextInput); |
| |
| auto &Diags = NextInput->getASTContext().Diags; |
| auto DidSuppressWarnings = Diags.getSuppressWarnings(); |
| auto IsPrimary |
| = PrimaryBufferID == NO_SUCH_BUFFER || BufferID == PrimaryBufferID; |
| Diags.setSuppressWarnings(DidSuppressWarnings || !IsPrimary); |
| |
| bool Done; |
| do { |
| // Parser may stop at some erroneous constructions like #else, #endif |
| // or '}' in some cases, continue parsing until we are done |
| parseIntoSourceFile(*NextInput, BufferID, &Done, nullptr, |
| &PersistentState, DelayedCB.get()); |
| } while (!Done); |
| |
| Diags.setSuppressWarnings(DidSuppressWarnings); |
| |
| performNameBinding(*NextInput); |
| } |
| |
| if (Invocation.isCodeCompletion()) { |
| // When we are doing code completion, make sure to emit at least one |
| // diagnostic, so that ASTContext is marked as erroneous. In this case |
| // various parts of the compiler (for example, AST verifier) have less |
| // strict assumptions about the AST. |
| Diagnostics.diagnose(SourceLoc(), diag::error_doing_code_completion); |
| } |
| |
| if (hadLoadError) |
| return; |
| |
| // Compute the options we want to use for type checking. |
| OptionSet<TypeCheckingFlags> TypeCheckOptions; |
| if (PrimaryBufferID == NO_SUCH_BUFFER) { |
| TypeCheckOptions |= TypeCheckingFlags::DelayWholeModuleChecking; |
| } |
| if (options.DebugTimeFunctionBodies) { |
| TypeCheckOptions |= TypeCheckingFlags::DebugTimeFunctionBodies; |
| } |
| if (options.actionIsImmediate()) { |
| TypeCheckOptions |= TypeCheckingFlags::ForImmediateMode; |
| } |
| if (options.DebugTimeExpressionTypeChecking) { |
| TypeCheckOptions |= TypeCheckingFlags::DebugTimeExpressions; |
| } |
| |
| // Parse the main file last. |
| if (MainBufferID != NO_SUCH_BUFFER) { |
| bool mainIsPrimary = |
| (PrimaryBufferID == NO_SUCH_BUFFER || MainBufferID == PrimaryBufferID); |
| |
| SourceFile &MainFile = |
| MainModule->getMainSourceFile(Invocation.getSourceFileKind()); |
| |
| auto &Diags = MainFile.getASTContext().Diags; |
| auto DidSuppressWarnings = Diags.getSuppressWarnings(); |
| Diags.setSuppressWarnings(DidSuppressWarnings || !mainIsPrimary); |
| |
| SILParserState SILContext(TheSILModule.get()); |
| unsigned CurTUElem = 0; |
| bool Done; |
| do { |
| // Pump the parser multiple times if necessary. It will return early |
| // after parsing any top level code in a main module, or in SIL mode when |
| // there are chunks of swift decls (e.g. imports and types) interspersed |
| // with 'sil' definitions. |
| parseIntoSourceFile(MainFile, MainFile.getBufferID().getValue(), &Done, |
| TheSILModule ? &SILContext : nullptr, |
| &PersistentState, DelayedCB.get()); |
| if (mainIsPrimary) { |
| performTypeChecking(MainFile, PersistentState.getTopLevelContext(), |
| TypeCheckOptions, CurTUElem, |
| options.WarnLongFunctionBodies); |
| } |
| CurTUElem = MainFile.Decls.size(); |
| } while (!Done); |
| |
| Diags.setSuppressWarnings(DidSuppressWarnings); |
| |
| if (mainIsPrimary && !Context->hadError() && |
| Invocation.getFrontendOptions().PCMacro) { |
| performPCMacro(MainFile, PersistentState.getTopLevelContext()); |
| } |
| |
| // Playground transform knows to look out for PCMacro's changes and not |
| // to playground log them. |
| if (mainIsPrimary && !Context->hadError() && |
| Invocation.getFrontendOptions().PlaygroundTransform) |
| performPlaygroundTransform(MainFile, Invocation.getFrontendOptions().PlaygroundHighPerformance); |
| if (!mainIsPrimary) { |
| performNameBinding(MainFile); |
| } |
| } |
| |
| // Type-check each top-level input besides the main source file. |
| for (auto File : MainModule->getFiles()) |
| if (auto SF = dyn_cast<SourceFile>(File)) |
| if (PrimaryBufferID == NO_SUCH_BUFFER || SF == PrimarySourceFile) |
| performTypeChecking(*SF, PersistentState.getTopLevelContext(), |
| TypeCheckOptions, /*curElem*/0, |
| options.WarnLongFunctionBodies); |
| |
| // Even if there were no source files, we should still record known |
| // protocols. |
| if (auto *stdlib = Context->getStdlibModule()) |
| Context->recordKnownProtocols(stdlib); |
| |
| if (DelayedCB) { |
| performDelayedParsing(MainModule, PersistentState, |
| Invocation.getCodeCompletionFactory()); |
| } |
| |
| // Perform whole-module type checking. |
| if (TypeCheckOptions & TypeCheckingFlags::DelayWholeModuleChecking) { |
| for (auto File : MainModule->getFiles()) |
| if (auto SF = dyn_cast<SourceFile>(File)) |
| performWholeModuleTypeChecking(*SF); |
| } |
| |
| for (auto File : MainModule->getFiles()) |
| if (auto SF = dyn_cast<SourceFile>(File)) |
| if (PrimaryBufferID == NO_SUCH_BUFFER || SF == PrimarySourceFile) |
| finishTypeChecking(*SF); |
| } |
| |
| void CompilerInstance::performParseOnly() { |
| const InputFileKind Kind = Invocation.getInputKind(); |
| ModuleDecl *MainModule = getMainModule(); |
| Context->LoadedModules[MainModule->getName()] = MainModule; |
| |
| assert((Kind == InputFileKind::IFK_Swift || Kind == InputFileKind::IFK_Swift_Library) && |
| "only supports parsing a single .swift file"); |
| assert(BufferIDs.size() == 1 && "only supports parsing a single file"); |
| |
| if (Kind == InputFileKind::IFK_Swift) |
| SourceMgr.setHashbangBufferID(BufferIDs[0]); |
| |
| auto *Input = new (*Context) SourceFile(*MainModule, |
| Invocation.getSourceFileKind(), |
| BufferIDs[0], |
| SourceFile::ImplicitModuleImportKind::None); |
| MainModule->addFile(*Input); |
| setPrimarySourceFile(Input); |
| |
| PersistentParserState PersistentState; |
| bool Done; |
| do { |
| // Pump the parser multiple times if necessary. It will return early |
| // after parsing any top level code in a main module. |
| parseIntoSourceFile(*Input, Input->getBufferID().getValue(), &Done, |
| nullptr, &PersistentState, nullptr); |
| } while (!Done); |
| |
| assert(Context->LoadedModules.size() == 1 && |
| "Loaded a module during parse-only"); |
| } |