mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
When MemberImportVisibility is enabled we failed to find certain base methods from the extensions when said base methods are imported from C++. rdar://154887575
344 lines
13 KiB
C++
344 lines
13 KiB
C++
//===--- ClangModuleLoader.h - Clang Module Loader Interface ----*- C++ -*-===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_AST_CLANG_MODULE_LOADER_H
|
|
#define SWIFT_AST_CLANG_MODULE_LOADER_H
|
|
|
|
#include "swift/AST/ModuleLoader.h"
|
|
#include "swift/AST/SubstitutionMap.h"
|
|
#include "swift/Basic/TaggedUnion.h"
|
|
#include "clang/AST/DeclTemplate.h"
|
|
|
|
namespace clang {
|
|
class ASTContext;
|
|
class CompilerInstance;
|
|
class Decl;
|
|
class Module;
|
|
class Preprocessor;
|
|
class Sema;
|
|
class TargetInfo;
|
|
class Type;
|
|
class SourceLocation;
|
|
} // namespace clang
|
|
|
|
namespace swift {
|
|
|
|
class ClangInheritanceInfo;
|
|
class ClangNode;
|
|
class ConcreteDeclRef;
|
|
class Decl;
|
|
class FuncDecl;
|
|
class VarDecl;
|
|
class DeclContext;
|
|
class EffectiveClangContext;
|
|
class SwiftLookupTable;
|
|
class ValueDecl;
|
|
class VisibleDeclConsumer;
|
|
|
|
/// Represents the different namespaces for types in C.
|
|
///
|
|
/// A simplified version of clang::Sema::LookupKind.
|
|
enum class ClangTypeKind {
|
|
Typedef,
|
|
ObjCClass = Typedef,
|
|
/// Structs, enums, and unions.
|
|
Tag,
|
|
ObjCProtocol,
|
|
};
|
|
|
|
/// A path for serializing a declaration.
|
|
class StableSerializationPath {
|
|
public:
|
|
struct ExternalPath {
|
|
enum ComponentKind {
|
|
/// A named record type (but not a template specialization)
|
|
Record,
|
|
|
|
/// A named enum type
|
|
Enum,
|
|
|
|
/// A C++ namespace
|
|
Namespace,
|
|
|
|
/// A typedef
|
|
Typedef,
|
|
|
|
/// A typedef's anonymous tag declaration. Identifier is empty.
|
|
TypedefAnonDecl,
|
|
|
|
/// An Objective-C interface.
|
|
ObjCInterface,
|
|
|
|
/// An Objective-C protocol.
|
|
ObjCProtocol,
|
|
};
|
|
|
|
static bool requiresIdentifier(ComponentKind kind) {
|
|
return kind != TypedefAnonDecl;
|
|
}
|
|
|
|
SmallVector<std::pair<ComponentKind, Identifier>, 2> Path;
|
|
|
|
void add(ComponentKind kind, Identifier name) {
|
|
Path.push_back({kind, name});
|
|
}
|
|
};
|
|
private:
|
|
TaggedUnion<void, const Decl *, ExternalPath> Union;
|
|
|
|
public:
|
|
StableSerializationPath() {}
|
|
StableSerializationPath(const Decl *d) : Union(d) {}
|
|
StableSerializationPath(ExternalPath ext) : Union(ext) {}
|
|
|
|
explicit operator bool() const { return !Union.empty(); }
|
|
|
|
bool isSwiftDecl() const { return Union.isa<const Decl*>(); }
|
|
const Decl *getSwiftDecl() const {
|
|
assert(isSwiftDecl());
|
|
return Union.get<const Decl*>();
|
|
}
|
|
|
|
bool isExternalPath() const { return Union.isa<ExternalPath>(); }
|
|
const ExternalPath &getExternalPath() const {
|
|
assert(isExternalPath());
|
|
return Union.get<ExternalPath>();
|
|
}
|
|
|
|
SWIFT_DEBUG_DUMP;
|
|
void dump(raw_ostream &os) const;
|
|
};
|
|
|
|
class ClangModuleLoader : public ModuleLoader {
|
|
private:
|
|
virtual void anchor() override;
|
|
|
|
protected:
|
|
using ModuleLoader::ModuleLoader;
|
|
|
|
public:
|
|
/// This module loader's Clang instance may be configured with a different
|
|
/// (higher) OS version than the compilation target itself in order to be able
|
|
/// to load pre-compiled Clang modules that are aligned with the broader SDK,
|
|
/// and match the SDK deployment target against which Swift modules are also
|
|
/// built.
|
|
///
|
|
/// In this case, we must use the Swift compiler's OS version triple when
|
|
/// performing codegen, and the importer's Clang instance OS version triple
|
|
/// during module loading. `getModuleAvailabilityTarget` is for module-loading
|
|
/// clients only, and uses the latter.
|
|
///
|
|
/// (The implementing `ClangImporter` class maintains separate Target info
|
|
/// for use by IRGen/CodeGen clients)
|
|
virtual clang::TargetInfo &getModuleAvailabilityTarget() const = 0;
|
|
|
|
virtual clang::ASTContext &getClangASTContext() const = 0;
|
|
virtual clang::Preprocessor &getClangPreprocessor() const = 0;
|
|
virtual clang::Sema &getClangSema() const = 0;
|
|
virtual const clang::CompilerInstance &getClangInstance() const = 0;
|
|
virtual void printStatistics() const = 0;
|
|
virtual void dumpSwiftLookupTables() const = 0;
|
|
|
|
/// Returns the module that contains imports and declarations from all loaded
|
|
/// header files.
|
|
virtual ModuleDecl *getImportedHeaderModule() const = 0;
|
|
|
|
/// Retrieves the Swift wrapper for the given Clang module, creating
|
|
/// it if necessary.
|
|
virtual ModuleDecl *
|
|
getWrapperForModule(const clang::Module *mod,
|
|
bool returnOverlayIfPossible = false) const = 0;
|
|
|
|
/// Adds a new search path to the Clang CompilerInstance, as if specified with
|
|
/// -I or -F.
|
|
///
|
|
/// \returns true if there was an error adding the search path.
|
|
virtual bool addSearchPath(StringRef newSearchPath, bool isFramework,
|
|
bool isSystem) = 0;
|
|
|
|
/// Determine whether \c overlayDC is within an overlay module for the
|
|
/// imported context enclosing \c importedDC.
|
|
///
|
|
/// This routine is used for various hacks that are only permitted within
|
|
/// overlays of imported modules, e.g., Objective-C bridging conformances.
|
|
virtual bool
|
|
isInOverlayModuleForImportedModule(const DeclContext *overlayDC,
|
|
const DeclContext *importedDC) = 0;
|
|
|
|
/// Look for declarations associated with the given name.
|
|
///
|
|
/// \param name The name we're searching for.
|
|
virtual void lookupValue(DeclName name, VisibleDeclConsumer &consumer) = 0;
|
|
|
|
/// Look up a type declaration by its Clang name.
|
|
///
|
|
/// Note that this method does no filtering. If it finds the type in a loaded
|
|
/// module, it returns it. This is intended for use in reflection / debugging
|
|
/// contexts where access is not a problem.
|
|
virtual void
|
|
lookupTypeDecl(StringRef clangName, ClangTypeKind kind,
|
|
llvm::function_ref<void(TypeDecl *)> receiver) = 0;
|
|
|
|
/// Look up type a declaration synthesized by the Clang importer itself, using
|
|
/// a "related entity kind" to determine which type it should be. For example,
|
|
/// this can be used to find the synthesized error struct for an
|
|
/// NS_ERROR_ENUM.
|
|
///
|
|
/// Note that this method does no filtering. If it finds the type in a loaded
|
|
/// module, it returns it. This is intended for use in reflection / debugging
|
|
/// contexts where access is not a problem.
|
|
virtual void
|
|
lookupRelatedEntity(StringRef clangName, ClangTypeKind kind,
|
|
StringRef relatedEntityKind,
|
|
llvm::function_ref<void(TypeDecl *)> receiver) = 0;
|
|
|
|
/// Imports a clang decl directly, rather than looking up its name.
|
|
virtual Decl *importDeclDirectly(const clang::NamedDecl *decl) = 0;
|
|
|
|
/// Clones an imported \param decl from its base class to its derived class
|
|
/// \param newContext where it is inherited. Its access level is determined
|
|
/// with respect to \param inheritance, which signifies whether \param decl
|
|
/// was inherited via C++ public/protected/private inheritance.
|
|
///
|
|
/// This function uses a cache so that it is idempotent; successive
|
|
/// invocations will only generate one cloned ValueDecl (and all return
|
|
/// a pointer to it). Returns a NULL pointer upon failure.
|
|
virtual ValueDecl *importBaseMemberDecl(ValueDecl *decl,
|
|
DeclContext *newContext,
|
|
ClangInheritanceInfo inheritance) = 0;
|
|
|
|
/// Returnes the original method if \param decl is a clone from a base class
|
|
virtual ValueDecl *getOriginalForClonedMember(const ValueDecl *decl) = 0;
|
|
|
|
/// Emits diagnostics for any declarations named name
|
|
/// whose direct declaration context is a TU.
|
|
virtual void diagnoseTopLevelValue(const DeclName &name) = 0;
|
|
|
|
/// Emit diagnostics for declarations named name that are members
|
|
/// of the provided baseType.
|
|
virtual void diagnoseMemberValue(const DeclName &name,
|
|
const Type &baseType) = 0;
|
|
|
|
/// Instantiate and import class template using given arguments.
|
|
///
|
|
/// This method will find the clang::ClassTemplateSpecialization decl if
|
|
/// it already exists, or it will create one. Then it will import this
|
|
/// decl the same way as we import typedeffed class templates - using
|
|
/// the hidden struct prefixed with `__CxxTemplateInst`.
|
|
virtual StructDecl *
|
|
instantiateCXXClassTemplate(clang::ClassTemplateDecl *decl,
|
|
ArrayRef<clang::TemplateArgument> arguments) = 0;
|
|
|
|
virtual ConcreteDeclRef
|
|
getCXXFunctionTemplateSpecialization(SubstitutionMap subst,
|
|
ValueDecl *decl) = 0;
|
|
|
|
/// Try to parse the string as a Clang function type.
|
|
///
|
|
/// Returns null if there was a parsing failure.
|
|
virtual const clang::Type *parseClangFunctionType(StringRef type,
|
|
SourceLoc loc) const = 0;
|
|
|
|
/// Print the Clang type.
|
|
virtual void printClangType(const clang::Type *type,
|
|
llvm::raw_ostream &os) const = 0;
|
|
|
|
/// Try to find a stable serialization path for the given declaration,
|
|
/// if there is one.
|
|
virtual StableSerializationPath
|
|
findStableSerializationPath(const clang::Decl *decl) const = 0;
|
|
|
|
/// Try to resolve a stable serialization path down to the original
|
|
/// declaration.
|
|
virtual const clang::Decl *
|
|
resolveStableSerializationPath(const StableSerializationPath &path) const = 0;
|
|
|
|
/// Determine whether the given type is serializable.
|
|
///
|
|
/// If \c checkCanonical is true, checks the canonical type,
|
|
/// not the given possibly-sugared type. In general:
|
|
/// - non-canonical representations should be preserving the
|
|
/// sugared type even if it isn't serializable, since that
|
|
/// maintains greater source fidelity;
|
|
/// - semantic checks need to be checking the serializability
|
|
/// of the canonical type, since it's always potentially
|
|
/// necessary to serialize that (e.g. in SIL); and
|
|
/// - serializers can try to serialize the sugared type to
|
|
/// maintain source fidelity and just fall back on the canonical
|
|
/// type if that's not possible.
|
|
///
|
|
/// The expectation here is that this predicate is meaningful
|
|
/// independent of the actual form of serialization: the types
|
|
/// that we can't reliably binary-serialize without an absolute
|
|
/// Clang AST cross-reference are the same types that won't
|
|
/// reliably round-trip through a textual format. At the very
|
|
/// least, it's probably best to use conservative predicates
|
|
/// that work both ways so that language behavior doesn't differ
|
|
/// based on subtleties like the target module interface format.
|
|
virtual bool isSerializable(const clang::Type *type,
|
|
bool checkCanonical) const = 0;
|
|
|
|
virtual clang::FunctionDecl *
|
|
instantiateCXXFunctionTemplate(ASTContext &ctx,
|
|
clang::FunctionTemplateDecl *func,
|
|
SubstitutionMap subst) = 0;
|
|
|
|
virtual bool isCXXMethodMutating(const clang::CXXMethodDecl *method) = 0;
|
|
|
|
virtual bool isUnsafeCXXMethod(const FuncDecl *func) = 0;
|
|
|
|
virtual FuncDecl *getDefaultArgGenerator(const clang::ParmVarDecl *param) = 0;
|
|
|
|
virtual std::optional<Type>
|
|
importFunctionReturnType(const clang::FunctionDecl *clangDecl,
|
|
DeclContext *dc) = 0;
|
|
|
|
virtual Type importVarDeclType(const clang::VarDecl *clangDecl,
|
|
VarDecl *swiftDecl,
|
|
DeclContext *dc) = 0;
|
|
|
|
/// Find the lookup table that corresponds to the given Clang module.
|
|
///
|
|
/// \param clangModule The module, or null to indicate that we're talking
|
|
/// about the directly-parsed headers.
|
|
virtual SwiftLookupTable *
|
|
findLookupTable(const clang::Module *clangModule) = 0;
|
|
|
|
virtual DeclName
|
|
importName(const clang::NamedDecl *D,
|
|
clang::DeclarationName givenName = clang::DeclarationName()) = 0;
|
|
|
|
/// Determine the effective Clang context for the given Swift nominal type.
|
|
virtual EffectiveClangContext getEffectiveClangContext(
|
|
const NominalTypeDecl *nominal) = 0;
|
|
|
|
virtual const clang::TypedefType *
|
|
getTypeDefForCXXCFOptionsDefinition(const clang::Decl *candidateDecl) = 0;
|
|
|
|
virtual SourceLoc importSourceLocation(clang::SourceLocation loc) = 0;
|
|
|
|
/// Just like Decl::getClangNode() except we look through to the 'Code'
|
|
/// enum of an error wrapper struct.
|
|
virtual ClangNode getEffectiveClangNode(const Decl *decl) const = 0;
|
|
};
|
|
|
|
/// Describes a C++ template instantiation error.
|
|
struct TemplateInstantiationError {
|
|
/// Generic types that could not be converted to QualTypes using the
|
|
/// ClangTypeConverter.
|
|
SmallVector<Type, 4> failedTypes;
|
|
};
|
|
|
|
} // namespace swift
|
|
|
|
#endif // LLVM_SWIFT_AST_CLANG_MODULE_LOADER_H
|