//===--- ImportedModules.cpp -- generates the list of imported 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 // //===----------------------------------------------------------------------===// #include "ImportedModules.h" #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" #include "swift/AST/DiagnosticEngine.h" #include "swift/AST/DiagnosticsFrontend.h" #include "swift/AST/Module.h" #include "swift/Basic/LLVM.h" #include "swift/Basic/STLExtras.h" #include "swift/ClangImporter/ClangImporter.h" #include "swift/Frontend/FrontendOptions.h" #include "clang/Basic/Module.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/FileSystem.h" using namespace swift; static StringRef getTopLevelName(const clang::Module *module) { return module->getTopLevelModule()->Name; } static void findAllClangImports(const clang::Module *module, llvm::SetVector &modules) { for (auto imported : module->Imports) { modules.insert(getTopLevelName(imported)); } for (auto sub : module->submodules()) { findAllClangImports(sub, modules); } } bool swift::emitImportedModules(ModuleDecl *mainModule, const FrontendOptions &opts) { auto &Context = mainModule->getASTContext(); std::string path = opts.InputsAndOutputs.getSingleOutputFilename(); std::error_code EC; llvm::raw_fd_ostream out(path, EC, llvm::sys::fs::F_None); if (out.has_error() || EC) { Context.Diags.diagnose(SourceLoc(), diag::error_opening_output, path, EC.message()); out.clear_error(); return true; } llvm::SetVector Modules; // Find the imports in the main Swift code. llvm::SmallVector Decls; mainModule->getDisplayDecls(Decls); for (auto D : Decls) { auto ID = dyn_cast(D); if (!ID) continue; auto modulePath = ID->getModulePath(); // only the top-level name is needed (i.e. A in A.B.C) Modules.insert(modulePath[0].Item.str()); } // And now look in the C code we're possibly using. auto clangImporter = static_cast(Context.getClangModuleLoader()); StringRef implicitHeaderPath = opts.ImplicitObjCHeaderPath; if (!implicitHeaderPath.empty()) { if (!clangImporter->importBridgingHeader(implicitHeaderPath, mainModule)) { SmallVector imported; clangImporter->getImportedHeaderModule()->getImportedModules( imported, {ModuleDecl::ImportFilterKind::Public, ModuleDecl::ImportFilterKind::Private, ModuleDecl::ImportFilterKind::ImplementationOnly, ModuleDecl::ImportFilterKind::SPIAccessControl}); for (auto IM : imported) { if (auto clangModule = IM.importedModule->findUnderlyingClangModule()) Modules.insert(getTopLevelName(clangModule)); else assert(IM.importedModule->isStdlibModule() && "unexpected non-stdlib swift module"); } } } if (opts.ImportUnderlyingModule) { auto underlyingModule = clangImporter->loadModule(SourceLoc(), ImportPath::Module::Builder(mainModule->getName()).get()); if (!underlyingModule) { Context.Diags.diagnose(SourceLoc(), diag::error_underlying_module_not_found, mainModule->getName()); return true; } auto clangModule = underlyingModule->findUnderlyingClangModule(); findAllClangImports(clangModule, Modules); } for (auto name : Modules) { out << name << "\n"; } return false; }