//===--- ClangImporter.cpp - Import Clang Modules -------------------------===// // // 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 // //===----------------------------------------------------------------------===// // // This file implements support for loading Clang modules into Swift. // //===----------------------------------------------------------------------===// #include "swift/ClangImporter/ClangImporter.h" #include "swift/ClangImporter/ClangModule.h" #include "ImporterImpl.h" #include "swift/Subsystems.h" #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" #include "swift/AST/LinkLibrary.h" #include "swift/AST/Module.h" #include "swift/AST/NameLookup.h" #include "swift/AST/Types.h" #include "swift/Basic/Range.h" #include "swift/Basic/StringExtras.h" #include "swift/ClangImporter/ClangImporterOptions.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/Module.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Version.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Sema.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Path.h" #include #include using namespace swift; // Commonly-used Clang classes. using clang::CompilerInstance; using clang::CompilerInvocation; ClangImporterCtorTy swift::getClangImporterCtor() { return &ClangImporter::create; } #pragma mark Internal data structures namespace { class SwiftModuleLoaderAction : public clang::SyntaxOnlyAction { protected: /// BeginSourceFileAction - Callback at the start of processing a single /// input. /// /// \return True on success; on failure \see ExecutionAction() and /// EndSourceFileAction() will not be called. virtual bool BeginSourceFileAction(CompilerInstance &ci, StringRef filename) { // Enable incremental processing, so we can load modules after we've // finished parsing our fake translation unit. ci.getPreprocessor().enableIncrementalProcessing(); return clang::SyntaxOnlyAction::BeginSourceFileAction(ci, filename); } }; } ClangImporter::ClangImporter(ASTContext &ctx, bool splitPrepositions) : Impl(*new Implementation(ctx, splitPrepositions)) { } ClangImporter::~ClangImporter() { delete &Impl; } void ClangImporter::setTypeResolver(LazyResolver &resolver) { Impl.setTypeResolver(&resolver); } void ClangImporter::clearTypeResolver() { Impl.setTypeResolver(nullptr); } namespace { namespace attr_fallback {} } namespace clang { using namespace ::attr_fallback; } /// Hack: returns true if Clang has a particular attribute. #define MAKE_HAS_ATTR(NAME) \ namespace { \ namespace attr_fallback { \ class NAME##Attr; \ } \ } \ static constexpr bool has##NAME##Attr() { \ return !std::is_same::value; \ } MAKE_HAS_ATTR(ObjCRootClass) MAKE_HAS_ATTR(NotAnAttributeClangWillEverImplement) static_assert(hasObjCRootClassAttr(), "MAKE_HAS_ATTR is broken"); static_assert(!hasNotAnAttributeClangWillEverImplementAttr(), "MAKE_HAS_ATTR is broken"); MAKE_HAS_ATTR(ObjCCompleteDefinition) #pragma mark Module loading ClangImporter *ClangImporter::create(ASTContext &ctx, StringRef targetTriple, const ClangImporterOptions &clangImporterOpts) { std::unique_ptr importer{ new ClangImporter(ctx, ctx.LangOpts.SplitPrepositions) }; // Get the SearchPathOptions to use when creating the Clang importer. SearchPathOptions &searchPathOpts = ctx.SearchPathOpts; // Create a Clang diagnostics engine. // FIXME: Route these diagnostics back to Swift's diagnostics engine, // somehow. We'll lose macro expansions, but so what. auto clangDiags(CompilerInstance::createDiagnostics( new clang::DiagnosticOptions, 0, nullptr)); // Don't stop emitting messages if we ever can't find a file. // FIXME: This is actually a general problem: any "fatal" error could mess up // the CompilerInvocation. clangDiags->setDiagnosticMapping(clang::diag::err_module_not_found, clang::diag::Mapping::MAP_ERROR, clang::SourceLocation()); // Construct the invocation arguments for Objective-C ARC with the current // target. // // FIXME: Figure out an appropriate OS deployment version to pass along. std::vector invocationArgStrs = { "-x", "objective-c", "-std=gnu11", "-fobjc-arc", "-fmodules", "-fblocks", "-fsyntax-only", "-w", "-triple", targetTriple.str(), "-I", searchPathOpts.RuntimeResourcePath, "-DSWIFT_PROTOCOL=__attribute__((annotate(\"" SWIFT_NATIVE_ANNOTATION_STRING "\")))", "-fretain-comments-from-system-headers", "swift.m" }; if (ctx.LangOpts.EnableAppExtensionRestrictions) { invocationArgStrs.push_back("-fapplication-extension"); } // FIXME: Once we're all building with the internal Clang, remove this guard. // It might also make more sense to put this in a header. if (hasObjCCompleteDefinitionAttr()) { invocationArgStrs.push_back("-DSWIFT_CLASS=" "__attribute__((objc_complete_definition)) " "__attribute__((annotate(\"" SWIFT_NATIVE_ANNOTATION_STRING "\")))"); } else { invocationArgStrs.push_back("-DSWIFT_CLASS=" "__attribute__((annotate(\"" SWIFT_NATIVE_ANNOTATION_STRING "\")))"); } if (searchPathOpts.SDKPath.empty()) { invocationArgStrs.push_back("-nostdsysteminc"); } else { invocationArgStrs.push_back("-isysroot"); invocationArgStrs.push_back(searchPathOpts.SDKPath); } for (auto path : searchPathOpts.ImportSearchPaths) { invocationArgStrs.push_back("-I"); invocationArgStrs.push_back(path); } for (auto path : searchPathOpts.FrameworkSearchPaths) { invocationArgStrs.push_back("-F"); invocationArgStrs.push_back(path); } const std::string &moduleCachePath = clangImporterOpts.ModuleCachePath; // Set the module cache path. if (moduleCachePath.empty()) { llvm::SmallString<128> DefaultModuleCache; llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/false, DefaultModuleCache); llvm::sys::path::append(DefaultModuleCache, "org.llvm.clang"); llvm::sys::path::append(DefaultModuleCache, "ModuleCache"); invocationArgStrs.push_back("-fmodules-cache-path="); invocationArgStrs.back().append(DefaultModuleCache.str()); } else { invocationArgStrs.push_back("-fmodules-cache-path="); invocationArgStrs.back().append(moduleCachePath); } const std::string &overrideResourceDir = clangImporterOpts.OverrideResourceDir; if (overrideResourceDir.empty()) { llvm::SmallString<128> resourceDir(searchPathOpts.RuntimeResourcePath); // Adjust the path torefer to our copy of the Clang headers under // lib/swift/clang. llvm::sys::path::append(resourceDir, "clang", CLANG_VERSION_STRING); // Set the Clang resource directory to the path we computed. invocationArgStrs.push_back("-resource-dir"); invocationArgStrs.push_back(resourceDir.str()); } else { invocationArgStrs.push_back("-resource-dir"); invocationArgStrs.push_back(overrideResourceDir); } for (auto extraArg : clangImporterOpts.ExtraArgs) { invocationArgStrs.push_back(extraArg); } std::vector invocationArgs; for (auto &argStr : invocationArgStrs) invocationArgs.push_back(argStr.c_str()); // Create a new Clang compiler invocation. llvm::IntrusiveRefCntPtr invocation = new CompilerInvocation; if (!CompilerInvocation::CreateFromArgs(*invocation, &invocationArgs.front(), (&invocationArgs.front() + invocationArgs.size()), *clangDiags)) return nullptr; importer->Impl.Invocation = invocation; // Create an almost-empty memory buffer corresponding to the file "swift.m" auto sourceBuffer = llvm::MemoryBuffer::getMemBuffer("extern int __swift;"); invocation->getPreprocessorOpts().addRemappedFile("swift.m", sourceBuffer); // Create a compiler instance. importer->Impl.Instance.reset(new CompilerInstance); auto &instance = *importer->Impl.Instance; instance.setDiagnostics(&*clangDiags); instance.setInvocation(&*invocation); // Create the associated action. importer->Impl.Action.reset(new SwiftModuleLoaderAction); // Execute the action. We effectively inline most of // CompilerInstance::ExecuteAction here, because we need to leave the AST // open for future module loading. // FIXME: This has to be cleaned up on the Clang side before we can improve // things here. // Create the target instance. instance.setTarget( clang::TargetInfo::CreateTargetInfo(*clangDiags,&instance.getTargetOpts())); if (!instance.hasTarget()) return nullptr; // Inform the target of the language options. // // FIXME: We shouldn't need to do this, the target should be immutable once // created. This complexity should be lifted elsewhere. instance.getTarget().setForcedLangOptions(instance.getLangOpts()); // Run the action. auto &action = *importer->Impl.Action; if (action.BeginSourceFile(instance, instance.getFrontendOpts().Inputs[0])) { action.Execute(); // Note: don't call EndSourceFile here! } // FIXME: This is necessary because Clang doesn't really support what we're // doing, and TUScope has gone stale. instance.getSema().TUScope = nullptr; // Create the selectors we'll be looking for. auto &clangContext = importer->Impl.Instance->getASTContext(); importer->Impl.objectAtIndexedSubscript = clangContext.Selectors.getUnarySelector( &clangContext.Idents.get("objectAtIndexedSubscript")); clang::IdentifierInfo *setObjectAtIndexedSubscriptIdents[2] = { &clangContext.Idents.get("setObject"), &clangContext.Idents.get("atIndexedSubscript") }; importer->Impl.setObjectAtIndexedSubscript = clangContext.Selectors.getSelector(2, setObjectAtIndexedSubscriptIdents); importer->Impl.objectForKeyedSubscript = clangContext.Selectors.getUnarySelector( &clangContext.Idents.get("objectForKeyedSubscript")); clang::IdentifierInfo *setObjectForKeyedSubscriptIdents[2] = { &clangContext.Idents.get("setObject"), &clangContext.Idents.get("forKeyedSubscript") }; importer->Impl.setObjectForKeyedSubscript = clangContext.Selectors.getSelector(2, setObjectForKeyedSubscriptIdents); return importer.release(); } Module *ClangImporter::loadModule( SourceLoc importLoc, ArrayRef> path) { // Convert the Swift import path over to a Clang import path. // FIXME: Map source locations over. Fun, fun! SmallVector, 4> clangPath; auto &clangContext = Impl.Instance->getASTContext(); for (auto component : path) { clangPath.push_back({&clangContext.Idents.get(component.first.str()), clang::SourceLocation()} ); } // Load the Clang module. // FIXME: The source location here is completely bogus. It can't be // invalid, and it can't be the same thing twice in a row, so we just use // a counter. Having real source locations would be far, far better. // FIXME: This should not print a message if we just can't find a Clang // module -- that's Swift's responsibility, since there could in theory be a // later module loader. auto &srcMgr = clangContext.getSourceManager(); clang::SourceLocation clangImportLoc = srcMgr.getLocForStartOfFile(srcMgr.getMainFileID()) .getLocWithOffset(Impl.ImportCounter++); auto clangModule = Impl.Instance->loadModule(clangImportLoc, clangPath, clang::Module::AllVisible, /*IsInclusionDirective=*/false); if (!clangModule) return nullptr; // Bump the generation count. ++Impl.Generation; Impl.SwiftContext.bumpGeneration(); Impl.CachedVisibleDecls.clear(); Impl.CurrentCacheState = Implementation::CacheState::Invalid; auto &cacheEntry = Impl.ModuleWrappers[clangModule]; if (ClangModuleUnit *cached = cacheEntry.getPointer()) { Module *M = cached->getParentModule(); if (!cacheEntry.getInt()) { // Force load adapter modules for all imported modules. // FIXME: This forces the creation of wrapper modules for all imports as // well, and may do unnecessary work. cacheEntry.setInt(true); M->forAllVisibleModules(path, [&](Module::ImportedModule import) {}); } return M; } // Build the representation of the Clang module in Swift. // FIXME: The name of this module could end up as a key in the ASTContext, // but that's not correct for submodules. Identifier name = Impl.SwiftContext.getIdentifier((*clangModule).Name); auto result = Module::create(name, Impl.SwiftContext); auto file = new (Impl.SwiftContext) ClangModuleUnit(*result, *this, clangModule); result->addFile(*file); cacheEntry.setPointerAndInt(file, true); // FIXME: Total hack. if (!Impl.firstClangModule) Impl.firstClangModule = file; // Force load adapter modules for all imported modules. // FIXME: This forces the creation of wrapper modules for all imports as // well, and may do unnecessary work. result->forAllVisibleModules(path, [](Module::ImportedModule import) {}); return result; } ClangModuleUnit * ClangImporter::Implementation::getWrapperForModule(ClangImporter &importer, clang::Module *underlying) { auto &cacheEntry = ModuleWrappers[underlying]; if (ClangModuleUnit *cached = cacheEntry.getPointer()) return cached; // FIXME: Handle hierarchical names better. Identifier name = SwiftContext.getIdentifier(underlying->Name); auto wrapper = Module::create(name, SwiftContext); auto file = new (SwiftContext) ClangModuleUnit(*wrapper, importer, underlying); wrapper->addFile(*file); cacheEntry.setPointer(file); return file; } clang::Module *ClangImporter::Implementation::getClangSubmoduleForDecl( const clang::Decl *D, bool allowForwardDeclaration) { const clang::Decl *actual = nullptr; if (auto OID = dyn_cast(D)) { // Put the Objective-C class into the module that contains the @interface // definition, not just some @class forward declaration. actual = OID->getDefinition(); if (!actual && !allowForwardDeclaration) return nullptr; } else if (auto TD = dyn_cast(D)) { actual = TD->getDefinition(); if (!actual && !allowForwardDeclaration) return nullptr; } if (!actual) actual = D->getCanonicalDecl(); return actual->getOwningModule(); } ClangModuleUnit *ClangImporter::Implementation::getClangModuleForDecl( const clang::Decl *D, bool allowForwardDeclaration) { clang::Module *M = getClangSubmoduleForDecl(D, allowForwardDeclaration); if (!M) return nullptr; // Get the parent module because currently we don't represent submodules with // ClangModule. // FIXME: this is just a workaround until we can import submodules. M = M->getTopLevelModule(); auto &importer = static_cast(*SwiftContext.getClangModuleLoader()); return getWrapperForModule(importer, M); } #pragma mark Source locations clang::SourceLocation ClangImporter::Implementation::importSourceLoc(SourceLoc loc) { // FIXME: Implement! return clang::SourceLocation(); } SourceLoc ClangImporter::Implementation::importSourceLoc(clang::SourceLocation loc) { // FIXME: Implement! return SourceLoc(); } SourceRange ClangImporter::Implementation::importSourceRange(clang::SourceRange loc) { // FIXME: Implement! return SourceRange(); } #pragma mark Importing names /// \brief Determine whether the given name is reserved for Swift. static bool isSwiftReservedName(StringRef name) { /// FIXME: Check Swift keywords. return llvm::StringSwitch(name) .Cases("true", "false", true) .Default(false); } clang::DeclarationName ClangImporter::Implementation::importName(Identifier name) { // FIXME: When we start dealing with C++, we can map over some operator // names. if (name.isOperator()) return clang::DeclarationName(); if (isSwiftReservedName(name.str())) return clang::DeclarationName(); // Map the identifier. If it's some kind of keyword, it can't be mapped. auto ident = &Instance->getASTContext().Idents.get(name.str()); if (ident->getTokenID() != clang::tok::identifier) return clang::DeclarationName(); return ident; } Identifier ClangImporter::Implementation::importName(clang::DeclarationName name, StringRef suffix, StringRef removePrefix) { // FIXME: At some point, we'll be able to import operators as well. if (!name || name.getNameKind() != clang::DeclarationName::Identifier) return Identifier(); StringRef nameStr = name.getAsIdentifierInfo()->getName(); // Remove the prefix, if any. if (!removePrefix.empty()) { assert(nameStr.startswith(removePrefix) && "name doesn't start with given removal prefix"); nameStr = nameStr.slice(removePrefix.size(), nameStr.size()); } // Get the Swift identifier. if (suffix.empty()) { if (isSwiftReservedName(nameStr)) return Identifier(); return SwiftContext.getIdentifier(nameStr); } // Append the suffix, and try again. llvm::SmallString<64> nameBuf; nameBuf += nameStr; nameBuf += suffix; if (isSwiftReservedName(nameBuf)) return Identifier(); return SwiftContext.getIdentifier(nameBuf); } /// Split the given selector piece at the given index, updating /// capitalization as required. /// /// \param selector The selector piece. /// \param index The index at which to split. /// \param buffer Buffer used for scratch space. /// /// \returns a pair of strings \c (before,after), where \c after has /// has its capitalization adjusted if necessary. static std::pair splitSelectorPieceAt(StringRef selector, unsigned index, SmallVectorImpl &buffer) { // If the split point is at the end of the selector, the solution is // trivial. if (selector.str().size() == index) { return { selector, "" }; } // Split at the index and lowercase the parameter name. return { selector.substr(0, index), camel_case::toLowercaseWord(selector.substr(index), buffer) }; } /// Split the first selector piece into a function name and first /// parameter name, if possible. /// /// \param selector The selector piece to split. /// \param scratch Scratch space to use when forming strings. /// /// \returns a (function name, first parameter name) pair describing /// the split. If no split is possible, the function name will be \c /// selector and the parameter name will be empty. static std::pair splitFirstSelectorPiece(StringRef selector, SmallVectorImpl &scratch) { // Get the camelCase words in this selector. auto words = camel_case::getWords(selector); if (words.empty()) return { selector, "" }; // If "init" is the first word, we have an initializer. if (*words.begin() == "init") { return splitSelectorPieceAt(selector, 4, scratch); } // Scan words from the back of the selector looking for a // preposition. auto lastPrep = std::find_if(words.rbegin(), words.rend(), [&](StringRef word) -> bool { return getPrepositionKind(word) != PK_None; }); // If we found a preposition, split here. if (lastPrep != words.rend()) { if (getPrepositionKind(*lastPrep)) { return splitSelectorPieceAt(selector, std::prev(lastPrep.base()).getPosition(), scratch); } } // Nothing to split. return { selector, "" }; } /// Import an argument name. static Identifier importArgName(ASTContext &ctx, StringRef name) { // Simple case: empty name. if (name.empty()) return Identifier(); // If the first word isn't a non-directional preposition, lowercase // it to form the argument name. llvm::SmallString<16> scratch; auto firstWord = camel_case::getFirstWord(name); if (!ctx.LangOpts.SplitPrepositions || getPrepositionKind(firstWord) != PK_Nondirectional) return ctx.getIdentifier(camel_case::toLowercaseWord(name, scratch)); // The first word is a non-directional preposition. // If there's only one word, we're left with no argument name. if (firstWord.size() == name.size()) return Identifier(); return ctx.getIdentifier( camel_case::toLowercaseWord(name.substr(firstWord.size()), scratch)); } DeclName ClangImporter::Implementation::importName(clang::Selector selector, bool isInitializer) { assert(!selector.isNull() && "Null selector?"); // Zero-argument selectors. if (selector.isUnarySelector()) { auto name = selector.getNameForSlot(0); // Simple case. if (!isInitializer || name.size() == 4) return SwiftContext.getIdentifier(name); // This is an initializer with no parameters but a name that // contains more than 'init', so synthesize an argument to capture // what follows 'init'. assert(camel_case::getFirstWord(name).equals("init")); auto baseName = SwiftContext.Id_init; auto argName = importArgName(SwiftContext, name.substr(4)); return DeclName(SwiftContext, baseName, argName); } // Determine the base name and first argument name. Identifier baseName; SmallVector argumentNames; StringRef firstPiece = selector.getNameForSlot(0); if (isInitializer) { assert(camel_case::getFirstWord(firstPiece).equals("init")); baseName = SwiftContext.Id_init; argumentNames.push_back(importArgName(SwiftContext, firstPiece.substr(4))); } else if (SplitPrepositions) { llvm::SmallString<16> scratch; StringRef funcName, firstArgName; std::tie(funcName, firstArgName) = splitFirstSelectorPiece(firstPiece, scratch); baseName = SwiftContext.getIdentifier(funcName); argumentNames.push_back(importArgName(SwiftContext, firstArgName)); } else { baseName = SwiftContext.getIdentifier(firstPiece); argumentNames.push_back(Identifier()); } // Determine the remaining argument names. for (unsigned i = 1, e = selector.getNumArgs(); i < e; ++i) { argumentNames.push_back(importArgName(SwiftContext, selector.getNameForSlot(i))); } return DeclName(SwiftContext, baseName, argumentNames); } #pragma mark Name lookup void ClangImporter::lookupValue(Identifier name, VisibleDeclConsumer &consumer){ auto &pp = Impl.Instance->getPreprocessor(); auto &sema = Impl.Instance->getSema(); // If the given name matches one of a special set of renamed // protocol names, perform protocol lookup. For example, the // NSObject protocol is named NSObjectProto so that it does not // conflict with the NSObject class. // FIXME: It would be better to put protocols into a submodule, so // that normal name lookup would prefer the class (NSObject) but // protocols would be visible with, e.g., protocols.NSObject. auto lookupNameKind = clang::Sema::LookupOrdinaryName; if (false) { } #define RENAMED_PROTOCOL(ObjCName, SwiftName) \ else if (name.str().equals(#SwiftName)) { \ name = Impl.SwiftContext.getIdentifier(#ObjCName); \ lookupNameKind = clang::Sema::LookupObjCProtocolName; \ } #include "RenamedProtocols.def" // Map the name. If we can't represent the Swift name in Clang, bail out now. auto clangName = Impl.importName(name); if (!clangName) return; // See if there's a preprocessor macro we can import by this name. clang::IdentifierInfo *clangID = clangName.getAsIdentifierInfo(); if (clangID && clangID->hasMacroDefinition()) { if (auto clangMacro = pp.getMacroInfo(clangID)) { if (auto valueDecl = Impl.importMacro(name, clangMacro)) { consumer.foundDecl(valueDecl, DeclVisibilityKind::VisibleAtTopLevel); } } } // Perform name lookup into the global scope. // FIXME: Map source locations over. clang::LookupResult lookupResult(sema, clangName, clang::SourceLocation(), lookupNameKind); bool FoundType = false; bool FoundAny = false; if (sema.LookupName(lookupResult, /*Scope=*/0)) { // FIXME: Filter based on access path? C++ access control? for (auto decl : lookupResult) { if (auto swiftDecl = Impl.importDeclReal(decl->getUnderlyingDecl())) if (auto valueDecl = dyn_cast(swiftDecl)) { // If the importer gave us a declaration from the stdlib, make sure // it does not show up in the lookup results for the imported module. if (valueDecl->getDeclContext()->isModuleScopeContext() && valueDecl->getModuleContext() == Impl.getStdlibModule()) continue; consumer.foundDecl(valueDecl, DeclVisibilityKind::VisibleAtTopLevel); FoundType = FoundType || isa(valueDecl); FoundAny = true; } } } if (lookupNameKind == clang::Sema::LookupOrdinaryName && !FoundType) { // Look up a tag name if we did not find a type with this name already. // We don't want to introduce multiple types with same name. lookupResult.clear(clang::Sema::LookupTagName); if (sema.LookupName(lookupResult, /*Scope=*/0)) { // FIXME: Filter based on access path? C++ access control? for (auto decl : lookupResult) { if (auto swiftDecl = Impl.importDeclReal(decl->getUnderlyingDecl())) if (auto valueDecl = dyn_cast(swiftDecl)) { consumer.foundDecl(valueDecl, DeclVisibilityKind::VisibleAtTopLevel); FoundAny = true; } } } } if (lookupNameKind == clang::Sema::LookupOrdinaryName && !FoundAny) { // Look up a protocol name if we did not find anything with this // name already. lookupResult.clear(clang::Sema::LookupObjCProtocolName); if (sema.LookupName(lookupResult, /*Scope=*/0)) { // FIXME: Filter based on access path? C++ access control? for (auto decl : lookupResult) { if (auto swiftDecl = Impl.importDeclReal(decl->getUnderlyingDecl())) if (auto valueDecl = dyn_cast(swiftDecl)) consumer.foundDecl(valueDecl, DeclVisibilityKind::VisibleAtTopLevel); } } } } static bool isDeclaredInModule(const ClangModuleUnit *ModuleFilter, const ValueDecl *VD) { auto ContainingUnit = VD->getDeclContext()->getModuleScopeContext(); return ModuleFilter == ContainingUnit; } static const clang::Module *getClangOwningModule(ClangNode Node, const clang::ASTContext &ClangCtx) { auto ExtSource = ClangCtx.getExternalSource(); assert(ExtSource); if (const clang::Decl *D = Node.getAsDecl()) return ExtSource->getModule(D->getOwningModuleID()); if (const clang::MacroInfo *MI = Node.getAsMacro()) return ExtSource->getModule(MI->getOwningModuleID()); return nullptr; } static bool isVisibleFromModule(const ClangModuleUnit *ModuleFilter, const ValueDecl *VD) { // Include a value from module X if: // * no particular module was requested, or // * module X was specifically requested. if (!ModuleFilter) return true; auto ContainingUnit = VD->getDeclContext()->getModuleScopeContext(); if (ModuleFilter == ContainingUnit) return true; auto Wrapper = dyn_cast(ContainingUnit); if (!Wrapper) return false; auto ClangNode = VD->getClangNode(); assert(ClangNode); auto OwningClangModule = getClangOwningModule(ClangNode, ModuleFilter->getClangASTContext()); // FIXME: This only triggers for implicitly-generated decls like // __builtin_va_list, which we probably shouldn't be importing anyway. // But it also includes the builtin declarations for 'id', 'Class', 'SEL', // and '__int128_t'. if (!OwningClangModule) return true; // FIXME: If this is in another module, we shouldn't really be considering // it here, but the recursive lookup through exports doesn't seem to be // working right yet. return ModuleFilter->getClangModule()->isModuleVisible(OwningClangModule); } namespace { class ClangVectorDeclConsumer : public clang::VisibleDeclConsumer { std::vector results; public: ClangVectorDeclConsumer() = default; void FoundDecl(clang::NamedDecl *ND, clang::NamedDecl *Hiding, clang::DeclContext *Ctx, bool InBaseClass) override { if (!ND->getIdentifier()) return; if (ND->isModulePrivate()) return; results.push_back(ND); } llvm::MutableArrayRef getResults() { return results; } }; class FilteringVisibleDeclConsumer : public swift::VisibleDeclConsumer { swift::VisibleDeclConsumer &NextConsumer; const ClangModuleUnit *ModuleFilter = nullptr; public: FilteringVisibleDeclConsumer(swift::VisibleDeclConsumer &consumer, const ClangModuleUnit *CMU) : NextConsumer(consumer), ModuleFilter(CMU) {} void foundDecl(ValueDecl *VD, DeclVisibilityKind Reason) override { if (isVisibleFromModule(ModuleFilter, VD)) NextConsumer.foundDecl(VD, Reason); } }; class FilteringDeclaredDeclConsumer : public swift::VisibleDeclConsumer { swift::VisibleDeclConsumer &NextConsumer; const ClangModuleUnit *ModuleFilter = nullptr; public: FilteringDeclaredDeclConsumer(swift::VisibleDeclConsumer &consumer, const ClangModuleUnit *CMU) : NextConsumer(consumer), ModuleFilter(CMU) {} void foundDecl(ValueDecl *VD, DeclVisibilityKind Reason) override { if (isDeclaredInModule(ModuleFilter, VD)) NextConsumer.foundDecl(VD, Reason); } }; } // unnamed namespace void ClangImporter::lookupVisibleDecls(VisibleDeclConsumer &Consumer) const { if (Impl.CurrentCacheState != Implementation::CacheState::Valid) { do { Impl.CurrentCacheState = Implementation::CacheState::InProgress; Impl.CachedVisibleDecls.clear(); ClangVectorDeclConsumer clangConsumer; auto &sema = Impl.getClangSema(); sema.LookupVisibleDecls(sema.getASTContext().getTranslationUnitDecl(), clang::Sema::LookupNameKind::LookupAnyName, clangConsumer); // Sort all the Clang decls we find, so that we process them // deterministically. This *shouldn't* be necessary, but the importer // definitely still has ordering dependencies. auto results = clangConsumer.getResults(); llvm::array_pod_sort(results.begin(), results.end(), [](clang::NamedDecl * const *lhs, clang::NamedDecl * const *rhs) -> int { return clang::DeclarationName::compare((*lhs)->getDeclName(), (*rhs)->getDeclName()); }); for (const clang::NamedDecl *clangDecl : results) { if (Impl.CurrentCacheState != Implementation::CacheState::InProgress) break; if (Decl *imported = Impl.importDeclReal(clangDecl)) Impl.CachedVisibleDecls.push_back(cast(imported)); } // If we changed things /while/ we were caching, we need to start over // and try again. Fortunately we record a map of decls we've already // imported, so most of the work is just the lookup and then going // through the list. } while (Impl.CurrentCacheState != Implementation::CacheState::InProgress); auto &ClangPP = Impl.getClangPreprocessor(); for (auto I = ClangPP.macro_begin(), E = ClangPP.macro_end(); I != E; ++I) { if (!I->first->hasMacroDefinition()) continue; auto Name = Impl.importName(I->first); if (Name.empty()) continue; if (auto *Imported = Impl.importMacro(Name, I->second->getMacroInfo())) { Impl.CachedVisibleDecls.push_back(Imported); } } Impl.CurrentCacheState = Implementation::CacheState::Valid; } for (auto VD : Impl.CachedVisibleDecls) Consumer.foundDecl(VD, DeclVisibilityKind::VisibleAtTopLevel); } void ClangModuleUnit::lookupVisibleDecls(Module::AccessPathTy AccessPath, VisibleDeclConsumer &Consumer, NLKind LookupKind) const { FilteringVisibleDeclConsumer filterConsumer(Consumer, this); owner.lookupVisibleDecls(filterConsumer); } namespace { class VectorDeclPtrConsumer : public swift::VisibleDeclConsumer { public: SmallVectorImpl &Results; explicit VectorDeclPtrConsumer(SmallVectorImpl &Decls) : Results(Decls) {} virtual void foundDecl(ValueDecl *VD, DeclVisibilityKind Reason) override { Results.push_back(VD); } }; } // unnamed namespace void ClangModuleUnit::getTopLevelDecls(SmallVectorImpl &results) const { VectorDeclPtrConsumer Consumer(results); FilteringDeclaredDeclConsumer FilterConsumer(Consumer, this); owner.lookupVisibleDecls(FilterConsumer); } static void getImportDecls(ClangModuleUnit *ClangUnit, clang::Module *M, SmallVectorImpl &Results) { SmallVector Exported; M->getExportedModules(Exported); ASTContext &Ctx = ClangUnit->getASTContext(); for (auto *ImportedMod : M->Imports) { SmallVector, 4> AccessPath; auto *TmpMod = ImportedMod; while (TmpMod) { AccessPath.push_back({ Ctx.getIdentifier(TmpMod->Name), SourceLoc() }); TmpMod = TmpMod->Parent; } std::reverse(AccessPath.begin(), AccessPath.end()); bool IsExported = false; for (auto *ExportedMod : Exported) { if (ImportedMod == ExportedMod) { IsExported = true; break; } } Results.push_back(ImportDecl::create( Ctx, ClangUnit, SourceLoc(), ImportKind::Module, SourceLoc(), IsExported, AccessPath)); } } void ClangModuleUnit::getDisplayDecls(SmallVectorImpl &results) const { getImportDecls(const_cast(this), clangModule, results); getTopLevelDecls(results); } void ClangModuleUnit::lookupValue(Module::AccessPathTy accessPath, DeclName name, NLKind lookupKind, SmallVectorImpl &results) const { if (!Module::matchesAccessPath(accessPath, name)) return; // There should be no multi-part top-level decls in a Clang module. if (!name.isSimpleName()) return; VectorDeclConsumer vectorWriter(results); FilteringVisibleDeclConsumer filteringConsumer(vectorWriter, this); owner.lookupValue(name.getBaseName(), filteringConsumer); } void ClangImporter::loadExtensions(NominalTypeDecl *nominal, unsigned previousGeneration) { auto objcClass = dyn_cast_or_null( nominal->getClangDecl()); if (!objcClass) { if (auto typeResolver = Impl.getTypeResolver()) typeResolver->resolveDeclSignature(nominal); if (nominal->isObjC()) { // Map the name. If we can't represent the Swift name in Clang, bail out // now. auto clangName = Impl.importName(nominal->getName()); if (!clangName) return; auto &sema = Impl.Instance->getSema(); // Perform name lookup into the global scope. // FIXME: Map source locations over. clang::LookupResult lookupResult(sema, clangName, clang::SourceLocation(), clang::Sema::LookupOrdinaryName); if (sema.LookupName(lookupResult, /*Scope=*/0)) { // FIXME: Filter based on access path? C++ access control? for (auto clangDecl : lookupResult) { objcClass = dyn_cast(clangDecl); if (objcClass) break; } } } } if (!objcClass) return; // Import all of the visible categories. Simply loading them adds them to // the list of extensions. for (auto I = objcClass->visible_categories_begin(), E = objcClass->visible_categories_end(); I != E; ++I) { Impl.importDeclReal(*I); } } void ClangModuleUnit::getImportedModules( SmallVectorImpl &imports, Module::ImportFilter filter) const { auto topLevelAdapter = getAdapterModule(); SmallVector imported; if (filter == Module::ImportFilter::Public) { clangModule->getExportedModules(imported); } else { if (filter == Module::ImportFilter::All) { imported.append(clangModule->Imports.begin(), clangModule->Imports.end()); } else { SmallVector publicImports; clangModule->getExportedModules(publicImports); std::copy_if(clangModule->Imports.begin(), clangModule->Imports.end(), std::back_inserter(imported), [&](clang::Module *mod) { return publicImports.end() != std::find(publicImports.begin(), publicImports.end(), mod); }); } // FIXME: The parent module isn't exactly a private import, but it is // needed for link dependencies. if (clangModule->Parent) imported.push_back(clangModule->Parent); } for (auto importMod : imported) { auto wrapper = owner.Impl.getWrapperForModule(owner, importMod); auto actualMod = wrapper->getAdapterModule(); if (!actualMod || actualMod == topLevelAdapter) actualMod = wrapper->getParentModule(); imports.push_back({Module::AccessPathTy(), actualMod}); } if (filter != Module::ImportFilter::Public) imports.push_back({Module::AccessPathTy(), getASTContext().getStdlibModule()}); } /// Returns true if the first selector piece matches the given identifier. static bool selectorMatchesName(clang::Selector sel, DeclName name) { if (name.isSimpleName()) return sel.getNameForSlot(0) == name.getBaseName().str(); if (sel.getNumArgs() != name.getArgumentNames().size() + 1) return false; if (sel.getNameForSlot(0) != name.getBaseName().str()) return false; for (unsigned i = 1, e = sel.getNumArgs(); i < e; ++i) if (sel.getNameForSlot(i) != name.getArgumentNames()[i-1].str()) return false; return true; } static void lookupClassMembersImpl(ClangImporter::Implementation &Impl, VisibleDeclConsumer &consumer, DeclName name = DeclName()) { clang::Sema &S = Impl.getClangSema(); clang::ExternalASTSource *source = S.getExternalSource(); // When looking for a subscript, we actually look for the getters // and setters. clang::IdentifierInfo *objectAtIndexedSubscriptId = nullptr; clang::IdentifierInfo *objectForKeyedSubscriptId = nullptr; clang::IdentifierInfo *setObjectId = nullptr; clang::IdentifierInfo *atIndexedSubscriptId = nullptr; clang::IdentifierInfo *forKeyedSubscriptId = nullptr; bool isSubscript = name.isSimpleName(Impl.SwiftContext.Id_subscript); if (isSubscript) { auto &identTable = S.Context.Idents; objectAtIndexedSubscriptId = &identTable.get("objectAtIndexedSubscript"); objectForKeyedSubscriptId = &identTable.get("objectForKeyedSubscript"); setObjectId = &identTable.get("setObject"); atIndexedSubscriptId = &identTable.get("atIndexedSubscript"); forKeyedSubscriptId = &identTable.get("forKeyedSubscript"); } // Function that determines whether the given selector is acceptable. auto acceptableSelector = [&](clang::Selector sel) -> bool { if (!name) return true; switch (sel.getNumArgs()) { case 0: if (isSubscript) return false; break; case 1: if (isSubscript) return sel.getIdentifierInfoForSlot(0) == objectAtIndexedSubscriptId || sel.getIdentifierInfoForSlot(0) == objectForKeyedSubscriptId; break; case 2: if (isSubscript) return (sel.getIdentifierInfoForSlot(0) == setObjectId && (sel.getIdentifierInfoForSlot(1) == atIndexedSubscriptId || sel.getIdentifierInfoForSlot(1) == forKeyedSubscriptId)); break; default: if (isSubscript) return false; break; } return selectorMatchesName(sel, name); }; // Force load all external methods. // FIXME: Copied from Clang's SemaCodeComplete. for (uint32_t i = 0, n = source->GetNumExternalSelectors(); i != n; ++i) { clang::Selector sel = source->GetExternalSelector(i); if (sel.isNull() || S.MethodPool.count(sel)) continue; if (!acceptableSelector(sel)) continue; S.ReadMethodPool(sel); } // FIXME: Does not include methods from protocols. // FIXME: Do we really have to import every single method? // FIXME: Need a more efficient table in Clang to find "all selectors whose // first piece is this name". auto importMethods = [&](const clang::ObjCMethodList *list) { for (; list != nullptr; list = list->getNext()) { if (list->Method->isUnavailable()) continue; // If the method is a property accessor, we want the property. const clang::NamedDecl *searchForDecl = list->Method; if (list->Method->isPropertyAccessor()) { if (auto property = list->Method->findPropertyDecl()) { // ... unless we are enumerating all decls. In this case, if we see // a getter, return a property. If we see a setter, we know that // there is a getter, and we will visit it and return a property at // that time. if (!name && list->Method->param_size() != 0) continue; searchForDecl = property; } } if (auto VD = cast_or_null(Impl.importDeclReal(searchForDecl))) { if (isSubscript || !name) { // When searching for a subscript, we may have found a getter. If so, // use the subscript instead. if (auto func = dyn_cast(VD)) { auto known = Impl.Subscripts.find({func, nullptr}); if (known != Impl.Subscripts.end()) { consumer.foundDecl(known->second, DeclVisibilityKind::DynamicLookup); } } // If we were looking only for subscripts, don't report the getter. if (isSubscript) continue; } consumer.foundDecl(VD, DeclVisibilityKind::DynamicLookup); } } }; for (auto entry : S.MethodPool) { if (!acceptableSelector(entry.first)) continue; auto &methodListPair = entry.second; if (methodListPair.first.Method) importMethods(&methodListPair.first); if (methodListPair.second.Method) importMethods(&methodListPair.second); } } void ClangModuleUnit::lookupClassMember(Module::AccessPathTy accessPath, DeclName name, SmallVectorImpl &results) const { // FIXME: Not limited by module. VectorDeclConsumer consumer(results); lookupClassMembersImpl(owner.Impl, consumer, name); } void ClangModuleUnit::lookupClassMembers(Module::AccessPathTy accessPath, VisibleDeclConsumer &consumer) const { // FIXME: Not limited by module. lookupClassMembersImpl(owner.Impl, consumer); } void ClangModuleUnit::collectLinkLibraries( Module::LinkLibraryCallback callback) const { for (auto clangLinkLib : clangModule->LinkLibraries) { LibraryKind kind; if (clangLinkLib.IsFramework) kind = LibraryKind::Framework; else kind = LibraryKind::Library; callback(LinkLibrary(clangLinkLib.Library, kind)); } } StringRef ClangModuleUnit::getFilename() const { return clangModule->getASTFile()->getName(); } clang::TargetInfo &ClangImporter::getTargetInfo() const { return Impl.Instance->getTarget(); } clang::ASTContext &ClangImporter::getClangASTContext() const { return Impl.getClangASTContext(); } clang::Preprocessor &ClangImporter::getClangPreprocessor() const { return Impl.getClangPreprocessor(); } const clang::Module *ClangImporter::getClangOwningModule(ClangNode Node) const { return ::getClangOwningModule(Node, getClangASTContext()); } std::string ClangImporter::getClangModuleHash() const { return Impl.Invocation->getModuleHash(); } void ClangImporter::verifyAllModules() { #ifndef NDEBUG if (Impl.ImportCounter == Impl.VerifiedImportCounter) return; // Collect the Decls before verifying them; the act of verifying may cause // more decls to be imported and modify the map while we are iterating it. SmallVector Decls; for (auto &I : Impl.ImportedDecls) if (Decl *D = I.second) Decls.push_back(D); for (auto D : Decls) verify(D); Impl.VerifiedImportCounter = Impl.ImportCounter; #endif } //===----------------------------------------------------------------------===// // ClangModule Implementation //===----------------------------------------------------------------------===// ClangModuleUnit::ClangModuleUnit(Module &M, ClangImporter &owner, clang::Module *clangModule) : LoadedFile(FileUnitKind::ClangModule, M), owner(owner), clangModule(clangModule) { } bool ClangModuleUnit::hasClangModule(Module *M) { for (auto F : M->getFiles()) { if (isa(F)) return true; } return false; } bool ClangModuleUnit::isTopLevel() const { return !clangModule->isSubModule(); } bool ClangModuleUnit::isSystemModule() const { return clangModule->IsSystem; } clang::ASTContext &ClangModuleUnit::getClangASTContext() const { return owner.getClangASTContext(); } Module *ClangModuleUnit::getAdapterModule() const { if (!isTopLevel()) { // FIXME: Is this correct for submodules? auto topLevel = clangModule->getTopLevelModule(); auto wrapper = owner.Impl.getWrapperForModule(owner, topLevel); return wrapper->getAdapterModule(); } if (!adapterModule.getInt()) { // FIXME: Include proper source location. Module *M = getParentModule(); ASTContext &Ctx = M->Ctx; auto adapter = Ctx.getModule(Module::AccessPathTy({M->Name, SourceLoc()})); if (adapter == M) { adapter = nullptr; } else { auto &sharedModuleRef = Ctx.LoadedModules[M->Name.str()]; assert(!sharedModuleRef || sharedModuleRef == adapter || sharedModuleRef == M); sharedModuleRef = adapter; } auto mutableThis = const_cast(this); mutableThis->adapterModule.setPointerAndInt(adapter, true); } return adapterModule.getPointer(); }