Files
swift-mirror/lib/ClangImporter/ClangImporter.cpp

1356 lines
47 KiB
C++

//===--- 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 <algorithm>
#include <memory>
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<clang::NAME##Attr, attr_fallback::NAME##Attr>::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<ClangImporter> 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<std::string> 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<const char *> invocationArgs;
for (auto &argStr : invocationArgStrs)
invocationArgs.push_back(argStr.c_str());
// Create a new Clang compiler invocation.
llvm::IntrusiveRefCntPtr<CompilerInvocation> 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<std::pair<Identifier, SourceLoc>> path) {
// Convert the Swift import path over to a Clang import path.
// FIXME: Map source locations over. Fun, fun!
SmallVector<std::pair<clang::IdentifierInfo *, clang::SourceLocation>, 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<clang::ObjCInterfaceDecl>(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<clang::TagDecl>(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<ClangImporter &>(*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<bool>(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<StringRef, StringRef>
splitSelectorPieceAt(StringRef selector, unsigned index,
SmallVectorImpl<char> &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<StringRef, StringRef>
splitFirstSelectorPiece(StringRef selector, SmallVectorImpl<char> &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<Identifier, 2> 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<ValueDecl>(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<TypeDecl>(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<ValueDecl>(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<ValueDecl>(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<ClangModuleUnit>(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<clang::NamedDecl *> 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<clang::NamedDecl *> 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<ValueDecl>(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<Decl *> &Results;
explicit VectorDeclPtrConsumer(SmallVectorImpl<Decl *> &Decls)
: Results(Decls) {}
virtual void foundDecl(ValueDecl *VD, DeclVisibilityKind Reason) override {
Results.push_back(VD);
}
};
} // unnamed namespace
void ClangModuleUnit::getTopLevelDecls(SmallVectorImpl<Decl*> &results) const {
VectorDeclPtrConsumer Consumer(results);
FilteringDeclaredDeclConsumer FilterConsumer(Consumer, this);
owner.lookupVisibleDecls(FilterConsumer);
}
static void getImportDecls(ClangModuleUnit *ClangUnit,
clang::Module *M,
SmallVectorImpl<Decl *> &Results) {
SmallVector<clang::Module *, 1> Exported;
M->getExportedModules(Exported);
ASTContext &Ctx = ClangUnit->getASTContext();
for (auto *ImportedMod : M->Imports) {
SmallVector<std::pair<swift::Identifier, swift::SourceLoc>, 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<Decl*> &results) const {
getImportDecls(const_cast<ClangModuleUnit *>(this), clangModule, results);
getTopLevelDecls(results);
}
void ClangModuleUnit::lookupValue(Module::AccessPathTy accessPath,
DeclName name, NLKind lookupKind,
SmallVectorImpl<ValueDecl*> &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<clang::ObjCInterfaceDecl>(
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<clang::ObjCInterfaceDecl>(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<Module::ImportedModule> &imports,
Module::ImportFilter filter) const {
auto topLevelAdapter = getAdapterModule();
SmallVector<clang::Module *, 8> 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<clang::Module *, 8> 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<ValueDecl>(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<FuncDecl>(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<ValueDecl*> &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<Decl *, 8> 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<ClangModuleUnit>(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<ClangModuleUnit *>(this);
mutableThis->adapterModule.setPointerAndInt(adapter, true);
}
return adapterModule.getPointer();
}