//===--- ImporterImpl.h - Import Clang Modules: Implementation --*- 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 // //===----------------------------------------------------------------------===// // // This file provides the implementation class definitions for the Clang // module loader. // //===----------------------------------------------------------------------===// #ifndef SWIFT_CLANG_IMPORTER_IMPL_H #define SWIFT_CLANG_IMPORTER_IMPL_H #include "ClangAdapter.h" #include "ClangSourceBufferImporter.h" #include "ImportEnumInfo.h" #include "ImportName.h" #include "SwiftLookupTable.h" #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" #include "swift/AST/ForeignErrorConvention.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/Module.h" #include "swift/AST/RequirementSignature.h" #include "swift/AST/Type.h" #include "swift/Basic/FileTypes.h" #include "swift/Basic/SourceLoc.h" #include "swift/Basic/StringExtras.h" #include "swift/ClangImporter/ClangImporter.h" #include "swift/ClangImporter/ClangModule.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/Specifiers.h" #include "clang/Basic/TargetInfo.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Serialization/ModuleFileExtension.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/TinyPtrVector.h" #include "llvm/Support/Path.h" #include #include #include #include #include namespace llvm { class SmallBitVector; } namespace clang { class APValue; class DeclarationName; class MangleContext; class ObjCInterfaceDecl; class ObjCMethodDecl; class ObjCPropertyDecl; class ParmVarDecl; class Parser; class QualType; class TypedefNameDecl; } namespace swift { class ASTContext; class ClassDecl; class ConstructorDecl; class Decl; class DeclContext; class Expr; class ExtensionDecl; class FuncDecl; class Identifier; class Pattern; class SubscriptDecl; class ValueDecl; /// Describes the kind of conversion to apply to a constant value. enum class ConstantConvertKind { /// No conversion required. None, /// Construct the given type from the constant value by calling /// init(rawValue:). Construction, /// Construct the given type from the constant value by force /// unwrapping the result of init(rawValue:). ConstructionWithUnwrap }; /// Describes the kind of type import we're performing. enum class ImportTypeKind { /// Import a type in its most abstract form, without any adjustment. Abstract, /// Import the underlying type of a typedef. Typedef, /// Import the type of a literal value. Value, /// Import the type of an Objective-C generic argument. ObjCCollectionElement, /// Import the declared type of a variable. Variable, /// Import the declared type of an audited variable. /// /// This is exactly like ImportTypeKind::Variable, except it /// disables wrapping CF class types in Unmanaged. AuditedVariable, /// Import the declared type of a struct or union field. RecordField, /// Import the result type of a function. /// /// This provides special treatment for 'void', among other things, and /// enables the conversion of bridged types. Result, /// Import the result type of an audited function. /// /// This is exactly like ImportTypeKind::Result, except it /// disables wrapping CF class types in Unmanaged. AuditedResult, /// Import the type of a function parameter. /// /// Special handling: /// * C and C++ pointers become `UnsafePointer?` or `UnsafeMutablePointer?` /// * C++ references become `UnsafePointer` or `UnsafeMutablePointer` /// * Bridging that requires type conversions is allowed. /// Parameters are always considered CF-audited. Parameter, /// Import the type of a special "completion handler" function parameter. CompletionHandlerParameter, /// Import the type of a parameter to a completion handler that can indicate /// a thrown error. /// /// Special handling: /// * _Nullable_result is treated as _Nonnull rather than _Nullable_result. CompletionHandlerResultParameter, /// Import the type of an ObjC property. /// /// This enables the conversion of bridged types. Properties are always /// considered CF-audited. Property, /// Import the type of an ObjC property accessor marked 'weak', /// 'assign', or 'unsafe_unretained'. /// /// Like Property, but doesn't allow bridging to a value type, since that /// would discard the ownership. PropertyWithReferenceSemantics, /// Import the underlying type of an enum. /// /// This provides special treatment for 'NSUInteger'. Enum }; /// Flags which are extracted from an imported declaration to influence how its /// type is imported. Typically used via \c ImportTypeAttrs to form an option /// set. /// /// \warning Do not use this as a random grab bag of flags to \c importType() . /// This information is intended to be extracted and applied all at once. enum class ImportTypeAttr : uint8_t { /// Type should be imported as though declaration was marked with /// \c __attribute__((noescape)) . NoEscape = 1 << 0, /// Type should be imported as though declaration was marked with /// \c __attribute__((swift_attr("@MainActor"))) . MainActor = 1 << 1, /// Type should be imported as though declaration was marked with /// \c __attribute__((swift_attr("@Sendable"))) . Sendable = 1 << 2, /// Type is in a declaration where it would be imported as Sendable by /// default. This comes directly from the parameters to /// \c getImportTypeAttrs() and merely affects diagnostics. DefaultsToSendable = 1 << 3, /// Import the type of a parameter declared with /// \c CF_RETURNS_RETAINED. /// /// This ensures that the parameter is not marked as Unmanaged. CFRetainedOutParameter = 1 << 4, /// Import the type of a parameter declared with /// \c CF_RETURNS_NON_RETAINED. /// /// This ensures that the parameter is not marked as Unmanaged. CFUnretainedOutParameter = 1 << 5, }; /// Find and iterate over swift attributes embedded in the type /// without looking through typealiases. void findSwiftAttributes( clang::QualType type, llvm::function_ref callback); /// Attributes which were set on the declaration and affect how its type is /// imported. /// /// \seeAlso ImportTypeAttr using ImportTypeAttrs = OptionSet; /// Extracts the \c ImportTypeAttrs from a declaration. /// /// \param D The declaration to extract attributes from. /// \param isParam Is the declaration a function parameter? If so, additional /// attributes will be imported. ImportTypeAttrs getImportTypeAttrs(const clang::Decl *D, bool isParam = false); /// Extract concurrency related attributes from a type. /// /// \param SwiftContext The context. /// \param importKind The kind of import being performed. /// \param attrs The list to add the new attributes to. /// \param type The type to extract attributes from. void getConcurrencyAttrs(ASTContext &SwiftContext, ImportTypeKind importKind, ImportTypeAttrs &attrs, clang::QualType type); struct ImportDiagnostic { ImportDiagnosticTarget target; Diagnostic diag; clang::SourceLocation loc; ImportDiagnostic(ImportDiagnosticTarget target, const Diagnostic &diag, clang::SourceLocation loc) : target(target), diag(diag), loc(loc) {} bool operator==(const ImportDiagnostic &other) const { return target == other.target && loc == other.loc && diag.getID() == other.diag.getID(); } }; /// Controls whether \p decl, when imported, should name the fully-bridged /// Swift type or the original Clang type. /// /// In either case we end up losing sugar at some uses sites, so this is more /// about what the right default is. static inline Bridgeability getTypedefBridgeability(const clang::TypedefNameDecl *decl) { if (decl->hasAttr() || decl->getUnderlyingType()->isBlockPointerType()) { return Bridgeability::Full; } return Bridgeability::None; } /// Describes the kind of the C type that can be mapped to a stdlib /// swift type. enum class MappedCTypeKind { UnsignedInt, SignedInt, UnsignedWord, SignedWord, FloatIEEEsingle, FloatIEEEdouble, FloatX87DoubleExtended, VaList, ObjCBool, ObjCSel, ObjCId, ObjCClass, CGFloat, Block, }; /// Describes what to do with the C name of a type that can be mapped to /// a Swift standard library type. enum class MappedTypeNameKind { DoNothing, DefineOnly, DefineAndUse }; /// Describes certain kinds of methods that need to be specially /// handled by the importer. enum class SpecialMethodKind { Regular, Constructor, NSDictionarySubscriptGetter }; #define SWIFT_PROTOCOL_SUFFIX "Protocol" #define SWIFT_CFTYPE_SUFFIX "Ref" /// Describes whether to classify a factory method as an initializer. enum class FactoryAsInitKind { /// Infer based on name and type (the default). Infer, /// Treat as a class method. AsClassMethod, /// Treat as an initializer. AsInitializer }; namespace importer { struct PlatformAvailability { private: PlatformKind platformKind; public: /// Returns true when the given platform should be considered for /// availabilityon imported declarations. bool isPlatformRelevant(StringRef platform) const; /// Returns true when the given declaration with the given deprecation /// should be included in the cutoff of imported deprecated APIs marked /// unavailable. bool treatDeprecatedAsUnavailable(const clang::Decl *clangDecl, const llvm::VersionTuple &version, bool isAsync) const; /// The message to embed for implicitly unavailability if a deprecated /// API is now unavailable. std::string deprecatedAsUnavailableMessage; /// The message to embed for implicit async unavailability based on /// deprecation. std::string asyncDeprecatedAsUnavailableMessage; PlatformAvailability(const LangOptions &opts); private: PlatformAvailability(const PlatformAvailability&) = delete; PlatformAvailability &operator=(const PlatformAvailability &) = delete; }; } using LookupTableMap = llvm::DenseMap>; /// The result of importing a clang type. It holds both the Swift Type /// as well as a bool in which 'true' indicates either: /// This is an Optional type. /// This is a function type where the result type is an Optional. /// It is otherwise 'false'. class ImportedType { Type type; bool isIUO; public: ImportedType() { type = Type(); isIUO = false; } ImportedType(Type ty, bool implicitlyUnwrap) : type(ty), isIUO(implicitlyUnwrap) { #if !defined(NDEBUG) if (implicitlyUnwrap) { assert(ty->getOptionalObjectType() || ty->getAs()); if (!ty->getOptionalObjectType()) { auto fnTy = ty->castTo(); assert(fnTy->getResult()->getOptionalObjectType()); } } #endif } Type getType() const { return type; } bool isImplicitlyUnwrapped() const { return isIUO; } // Allow a direct test in boolean contexts. It makes sense to base // this entirely on the type as the isIUO is meaningless for a null // type. explicit operator bool() const { return type.getPointer() != nullptr; } }; /// Wraps a Clang source location with additional optional information used to /// resolve it for diagnostics. struct HeaderLoc { clang::SourceLocation clangLoc; SourceLoc fallbackLoc; const clang::SourceManager *sourceMgr; explicit HeaderLoc(clang::SourceLocation clangLoc, SourceLoc fallbackLoc = SourceLoc(), const clang::SourceManager *sourceMgr = nullptr) : clangLoc(clangLoc), fallbackLoc(fallbackLoc), sourceMgr(sourceMgr) {} }; struct ImportDiagnosticTargetHasher { std::size_t operator()(const ImportDiagnosticTarget &target) const { return std::hash()(target.getOpaqueValue()); } }; struct ImportDiagnosticHasher { std::size_t operator()(const ImportDiagnostic &diag) const { return llvm::hash_combine(diag.target.getOpaqueValue(), diag.diag.getID(), diag.loc.getHashValue()); } }; /// Implementation of the Clang importer. class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation : public LazyMemberLoader, public LazyConformanceLoader { friend class ClangImporter; using Version = importer::ImportNameVersion; public: Implementation(ASTContext &ctx, DependencyTracker *dependencyTracker, DWARFImporterDelegate *dwarfImporterDelegate); ~Implementation(); class DiagnosticWalker : public clang::RecursiveASTVisitor { public: DiagnosticWalker(ClangImporter::Implementation &Impl); bool TraverseDecl(clang::Decl *D); bool TraverseParmVarDecl(clang::ParmVarDecl *D); bool VisitDecl(clang::Decl *D); bool VisitMacro(const clang::MacroInfo *MI); bool VisitObjCObjectPointerType(clang::ObjCObjectPointerType *T); bool VisitType(clang::Type *T); private: Implementation &Impl; clang::SourceLocation TypeReferenceSourceLocation; }; /// Swift AST context. ASTContext &SwiftContext; // Associates a vector of import diagnostics with a ClangNode std::unordered_map, ImportDiagnosticTargetHasher> ImportDiagnostics; // Tracks the set of import diagnostics already produced for deduplication // purposes. std::unordered_set CollectedDiagnostics; // Keeps track of `clang::RecordDecl`s where diagnostics have already been // emitted due to failed SWIFT_SHARED_REFERENCE inference. std::unordered_set DiagnosedCxxRefDecls; const bool ImportForwardDeclarations; const bool DisableSwiftBridgeAttr; const bool BridgingHeaderExplicitlyRequested; const bool DisableOverlayModules; const bool EnableClangSPI; const bool UseClangIncludeTree; bool IsReadingBridgingPCH; llvm::SmallVector PCHImportedSubmodules; const Version CurrentVersion; constexpr static const char * const moduleImportBufferName = ""; constexpr static const char * const bridgingHeaderBufferName = ""; private: DiagnosticWalker Walker; /// The Swift lookup tables, per module. /// /// Annoyingly, we list this table early so that it gets torn down after /// the underlying Clang instances that reference it /// (through the Swift name lookup module file extension). LookupTableMap LookupTables; /// A helper class used to bring Clang buffers into Swift's SourceManager /// for the purpose of emitting diagnostics. /// /// Listed early so that it gets torn down after the underlying Clang /// instances that also use these buffers. importer::ClangSourceBufferImporter BuffersForDiagnostics; /// The fake buffer used to import modules. /// /// \see getNextIncludeLoc clang::FileID DummyIncludeBuffer; /// A count of the number of load module operations. /// /// \see getNextIncludeLoc unsigned IncludeCounter = 0; /// Generate a dummy Clang source location for header includes and module /// imports. /// /// These have to be unique and valid or Clang gets very confused. clang::SourceLocation getNextIncludeLoc(); /// Used to avoid running the AST verifier over the same declarations. size_t VerifiedDeclsCounter = 0; /// Clang compiler invocation. std::shared_ptr Invocation; /// Clang compiler instance, which is used to actually load Clang /// modules. std::unique_ptr Instance; /// Clang compiler action, which is used to actually run the /// parser. std::unique_ptr Action; /// Clang parser, which is used to load textual headers. std::unique_ptr Parser; /// Clang parser, which is used to load textual headers. std::unique_ptr Mangler; /// Clang arguments used to create the Clang invocation. std::vector ClangArgs; /// Mapping from Clang swift_attr attribute text to the Swift source file(s) /// that contain that attribute text. /// /// These are re-used when parsing the Swift attributes on import. llvm::StringMap> ClangSwiftAttrSourceFiles; public: /// The Swift lookup table for the bridging header. std::unique_ptr BridgingHeaderLookupTable; /// Mapping of already-imported declarations. llvm::DenseMap, Decl *> ImportedDecls; /// The set of "special" typedef-name declarations, which are /// mapped to specific Swift types. /// /// Normal typedef-name declarations imported into Swift will maintain /// equality between the imported declaration's underlying type and the /// import of the underlying type. A typedef-name declaration is special /// when this is not the case, e.g., Objective-C's "BOOL" has an underlying /// type of "signed char", but is mapped to a special Swift struct type /// ObjCBool. llvm::SmallDenseMap SpecialTypedefNames; /// Provide a single extension point for any given type per clang /// submodule llvm::DenseMap, ExtensionDecl *> extensionPoints; /// Typedefs that we should not be importing. We should be importing /// underlying decls instead. llvm::DenseSet SuperfluousTypedefs; /// Tag decls whose typedefs were imported instead. /// /// \sa SuperfluousTypedefs llvm::DenseSet DeclsWithSuperfluousTypedefs; /// Mapping of already-imported declarations from protocols, which /// can (and do) get replicated into classes. llvm::DenseMap, Decl *> ImportedProtocolDecls; /// Mapping from identifiers to the set of macros that have that name along /// with their corresponding Swift declaration. /// /// Multiple macro definitions can map to the same declaration if the /// macros are identically defined. llvm::DenseMap, 2>> ImportedMacros; // Mapping from macro to value for macros that expand to constant values. llvm::DenseMap> ImportedMacroConstants; // Mapping from imported types to their raw value types. llvm::DenseMap RawTypes; // Caches used by ObjCInterfaceAndImplementationRequest. llvm::DenseMap ImplementationsByInterface; llvm::DenseMap> InterfacesByImplementation; clang::CompilerInstance *getClangInstance() { return Instance.get(); } /// Writes the mangled name of \p clangDecl to \p os. void getMangledName(clang::MangleContext *mangler, const clang::NamedDecl *clangDecl, raw_ostream &os); /// Whether the C++ interoperability compatibility version is at least /// 'major'. /// /// Use the /// `isCxxInteropCompatVersionAtLeast(version::getUpcomingCxxInteropCompatVersion())` /// check when making a source breaking C++ interop change. bool isCxxInteropCompatVersionAtLeast(unsigned major, unsigned minor = 0) const { return SwiftContext.LangOpts.isCxxInteropCompatVersionAtLeast(major, minor); } private: /// The Importer may be configured to load modules of a different OS Version /// than the underlying Swift compilation. This is the `TargetOptions` /// corresponding to the instantiating Swift compilation's triple. These are /// to be used by all IRGen/CodeGen clients of `ClangImporter`. std::unique_ptr CodeGenTargetInfo; std::unique_ptr CodeGenOpts; public: void setSwiftTargetInfo(clang::TargetInfo *SwiftTargetInfo) { CodeGenTargetInfo.reset(SwiftTargetInfo); } clang::TargetInfo *getSwiftTargetInfo() const { return CodeGenTargetInfo.get(); } void setSwiftCodeGenOptions(clang::CodeGenOptions *SwiftCodeGenOpts) { CodeGenOpts.reset(SwiftCodeGenOpts); } clang::CodeGenOptions *getSwiftCodeGenOptions() const { return CodeGenOpts.get(); } private: /// Generation number that is used for crude versioning. /// /// This value is incremented every time a new module is imported. unsigned Generation = 1; void bumpGeneration() { ++Generation; SwiftContext.bumpGeneration(); } public: /// Keep track of subscript declarations based on getter/setter /// pairs. llvm::DenseMap, SubscriptDecl *> Subscripts; llvm::DenseMap< NominalTypeDecl *, llvm::DenseMap>> GetterSetterMap; /// Keep track of getter/setter pairs for functions imported from C++ /// subscript operators based on the type in which they are declared and /// the type of their parameter. /// /// `.first` corresponds to a getter /// `.second` corresponds to a setter llvm::MapVector, std::pair> cxxSubscripts; llvm::MapVector> cxxDereferenceOperators; llvm::SmallPtrSet synthesizedAndAlwaysVisibleDecls; private: // Keep track of the decls that were already cloned for this specific class. llvm::DenseMap, ValueDecl *> clonedBaseMembers; public: llvm::DenseMap defaultArgGenerators; bool isDefaultArgSafeToImport(const clang::ParmVarDecl *param); ValueDecl *importBaseMemberDecl(ValueDecl *decl, DeclContext *newContext, ClangInheritanceInfo inheritance); static size_t getImportedBaseMemberDeclArity(const ValueDecl *valueDecl); // Cache for already-specialized function templates and any thunks they may // have. llvm::DenseMap specializedFunctionTemplates; /// Keeps track of the Clang functions that have been turned into /// properties. llvm::DenseMap FunctionsAsProperties; importer::EnumInfo getEnumInfo(const clang::EnumDecl *decl) { return getNameImporter().getEnumInfo(decl); } importer::EnumKind getEnumKind(const clang::EnumDecl *decl) { return getNameImporter().getEnumKind(decl); } private: /// A mapping from imported declarations to their "alternate" declarations, /// for cases where a single Clang declaration is imported to two /// different Swift declarations. llvm::DenseMap> AlternateDecls; public: /// Keep track of initializer declarations that correspond to /// imported methods. llvm::DenseMap< std::tuple, ConstructorDecl *> Constructors; /// Keep track of all initializers that have been imported into a /// nominal type. llvm::DenseMap> ConstructorsForNominal; /// Keep track of all member declarations that have been imported into /// a nominal type. llvm::DenseMap>> MembersForNominal; /// Keep track of the nested 'Code' enum for imported error wrapper /// structs. llvm::DenseMap ErrorCodeEnums; /// Retrieve the alternative declaration for the given imported /// Swift declaration. ArrayRef getAlternateDecls(Decl *decl) { auto known = AlternateDecls.find(decl); if (known == AlternateDecls.end()) return {}; return known->second; } /// Add an alternative decl void addAlternateDecl(Decl *forDecl, ValueDecl *altDecl) { auto &vec = AlternateDecls[forDecl]; for (auto alt : vec) if (alt == altDecl) return; vec.push_back(altDecl); } private: /// NSObject, imported into Swift. Type NSObjectTy; /// A pair containing a ClangModuleUnit, /// and whether the overlays of its re-exported modules have all been forced /// to load already. using ModuleInitPair = llvm::PointerIntPair; public: /// A map from Clang modules to their Swift wrapper modules. llvm::SmallDenseMap ModuleWrappers; /// The module unit that contains declarations from imported headers. ClangModuleUnit *ImportedHeaderUnit = nullptr; /// The modules re-exported by imported headers. llvm::SmallVector ImportedHeaderExports; /// The modules that requested imported headers. /// /// These are used to look up Swift classes forward-declared with \@class. TinyPtrVector ImportedHeaderOwners; /// Clang's objectAtIndexedSubscript: selector. clang::Selector objectAtIndexedSubscript; /// Clang's setObjectAt:indexedSubscript: selector. clang::Selector setObjectAtIndexedSubscript; /// Clang's objectForKeyedSubscript: selector. clang::Selector objectForKeyedSubscript; /// Clang's setObject:forKeyedSubscript: selector. clang::Selector setObjectForKeyedSubscript; private: /// Records those modules that we have looked up. llvm::DenseMap checkedModules; /// The set of imported protocols for a declaration, used only to /// load all members of the declaration. llvm::DenseMap> ImportedProtocols; void startedImportingEntity(); public: importer::PlatformAvailability platformAvailability; private: /// For importing names. This is initialized by the ClangImporter::create() /// after having set up a suitable Clang instance. std::unique_ptr nameImporter = nullptr; /// If there is a single .PCH file imported into the __ObjC module, this /// is the filename of that PCH. When other files are imported, this should /// be std::nullopt. std::optional SinglePCHImport = std::nullopt; public: importer::NameImporter &getNameImporter() { assert(nameImporter && "haven't finished initialization"); return *nameImporter; } /// Tracks top level decls from the bridging header. std::vector BridgeHeaderTopLevelDecls; std::vector> BridgeHeaderTopLevelImports; /// Tracks macro definitions from the bridging header. std::vector BridgeHeaderMacros; /// Tracks included headers from the bridging header. llvm::DenseSet BridgeHeaderFiles; void addBridgeHeaderTopLevelDecls(clang::Decl *D); bool shouldIgnoreBridgeHeaderTopLevelDecl(clang::Decl *D); private: /// When set, ClangImporter is disabled, and all requests go to the /// DWARFImporter delegate. bool DisableSourceImport; /// File dependency tracker, if installed. DependencyTracker *SwiftDependencyTracker = nullptr; /// The DWARF importer delegate, if installed. DWARFImporterDelegate *DWARFImporter = nullptr; public: /// Only used for testing. void setDWARFImporterDelegate(DWARFImporterDelegate &delegate); private: /// The list of Clang modules found in the debug info. llvm::DenseMap DWARFModuleUnits; /// Load a module using the clang::CompilerInstance. ModuleDecl *loadModuleClang(SourceLoc importLoc, ImportPath::Module path); /// "Load" a module from debug info. Because debug info types are read on /// demand, this doesn't really do any work. ModuleDecl *loadModuleDWARF(SourceLoc importLoc, ImportPath::Module path); /// Lookup a clang module. clang::Module *lookupModule(StringRef moduleName); public: /// Load a module using either method. ModuleDecl *loadModule(SourceLoc importLoc, ImportPath::Module path); void recordImplicitUnwrapForDecl(ValueDecl *decl, bool isIUO) { if (!isIUO) return; #if !defined(NDEBUG) Type ty; if (auto *FD = dyn_cast(decl)) { ty = FD->getResultInterfaceType(); } else if (auto *CD = dyn_cast(decl)) { ty = CD->getResultInterfaceType(); } else { ty = cast(decl)->getValueInterfaceType(); } assert(ty->getOptionalObjectType()); #endif decl->setImplicitlyUnwrappedOptional(true); } /// Retrieve the Clang AST context. clang::ASTContext &getClangASTContext() const { return Instance->getASTContext(); } /// Retrieve the Clang Sema object. clang::Sema &getClangSema() const { return Instance->getSema(); } /// Retrieve the Clang AST context. clang::Preprocessor &getClangPreprocessor() const { return Instance->getPreprocessor(); } clang::CodeGenOptions &getCodeGenOpts() const { return Instance->getCodeGenOpts(); } importer::ClangSourceBufferImporter &getBufferImporterForDiagnostics() { return BuffersForDiagnostics; } /// Imports the given header contents into the Clang context. bool importHeader(ModuleDecl *adapter, StringRef headerName, SourceLoc diagLoc, bool trackParsedSymbols, std::unique_ptr contents, bool implicitImport); /// Retrieve the imported module that should contain the given /// Clang decl. ClangModuleUnit *getClangModuleForDecl(const clang::Decl *D, bool allowForwardDeclaration = false); /// Returns the module \p MI comes from, or \c None if \p MI does not have /// a valid associated module. /// /// The returned module may be null (but not \c None) if \p MI comes from /// an imported header. const clang::Module *getClangOwningModule(ClangNode Node) const; /// Whether NSUInteger can be imported as Int in certain contexts. If false, /// should always be imported as UInt. static bool shouldAllowNSUIntegerAsInt(bool isFromSystemModule, const clang::NamedDecl *decl); /// Converts the given Swift identifier for Clang. clang::DeclarationName exportName(Identifier name); /// Imports the full name of the given Clang declaration into Swift. /// /// Note that this may result in a name very different from the Clang name, /// so it should not be used when referencing Clang symbols. /// /// \param D The Clang declaration whose name should be imported. importer::ImportedName importFullName(const clang::NamedDecl *D, Version version, clang::DeclarationName givenName = clang::DeclarationName()) { return getNameImporter().importName(D, version, givenName); } /// Print an imported name as a string suitable for the swift_name attribute, /// or the 'Rename' field of AvailableAttr. void printSwiftName(importer::ImportedName name, importer::ImportNameVersion version, bool fullyQualified, llvm::raw_ostream &os); /// Emit a diagnostic, taking care not to interrupt a diagnostic that's /// already in flight. template void diagnose(Args &&...args) { // If we're in the middle of pretty-printing, suppress diagnostics. if (SwiftContext.Diags.isPrettyPrintingDecl()) { return; } SwiftContext.Diags.diagnose(std::forward(args)...); } /// Emit a diagnostic, taking care not to interrupt a diagnostic that's /// already in flight. template void diagnose(SourceLoc loc, Args &&...args) { // If we're in the middle of pretty-printing, suppress diagnostics. if (SwiftContext.Diags.isPrettyPrintingDecl()) { return; } SwiftContext.Diags.diagnose(loc, std::forward(args)...); } /// Emit a diagnostic at a clang source location, falling back to a Swift /// location if the clang one is invalid. /// /// The diagnostic will appear in the header file rather than in a generated /// interface. Use this to diagnose issues with declarations that are not /// imported or that are not reflected in a generated interface. template InFlightDiagnostic diagnose(HeaderLoc loc, Args &&...args) { // If we're in the middle of pretty-printing, suppress diagnostics. if (SwiftContext.Diags.isPrettyPrintingDecl()) { return InFlightDiagnostic(); } auto swiftLoc = loc.fallbackLoc; if (loc.clangLoc.isValid()) { auto &clangSrcMgr = loc.sourceMgr ? *loc.sourceMgr : getClangASTContext().getSourceManager(); auto &bufferImporter = getBufferImporterForDiagnostics(); swiftLoc = bufferImporter.resolveSourceLocation(clangSrcMgr, loc.clangLoc); } return SwiftContext.Diags.diagnose(swiftLoc, std::forward(args)...); } void addImportDiagnostic( ImportDiagnosticTarget target, Diagnostic &&diag, clang::SourceLocation loc); /// Import the given Clang identifier into Swift. /// /// \param identifier The Clang identifier to map into Swift. /// /// \param removePrefix The prefix to remove from the Clang name to produce /// the Swift name. If the Clang name does not start with this prefix, /// nothing is removed. Identifier importIdentifier(const clang::IdentifierInfo *identifier, StringRef removePrefix = ""); /// Import an Objective-C selector. ObjCSelector importSelector(clang::Selector selector); /// Import a Swift name as a Clang selector. clang::Selector exportSelector(DeclName name, bool allowSimpleName = true); /// Export a Swift Objective-C selector as a Clang Objective-C selector. clang::Selector exportSelector(ObjCSelector selector); /// Import the given Swift source location into Clang. clang::SourceLocation exportSourceLoc(SourceLoc loc); /// Import the given Clang source location into Swift. SourceLoc importSourceLoc(clang::SourceLocation loc); /// Import the given Clang source range into Swift. SourceRange importSourceRange(clang::SourceRange loc); /// Import the given Clang preprocessor macro as a Swift value decl. /// /// \p macroNode must be a MacroInfo or a ModuleMacro. /// /// \returns The imported declaration, or null if the macro could not be /// translated into Swift. ValueDecl *importMacro(Identifier name, ClangNode macroNode); /// Map a Clang identifier name to its imported Swift equivalent. StringRef getSwiftNameFromClangName(StringRef name); /// Retrieve the placeholder source file for use in parsing Swift attributes /// in the given module. SourceFile &getClangSwiftAttrSourceFile( ModuleDecl &module, StringRef attributeText, bool cached); /// Create attribute with given text and attach it to decl, creating or /// retrieving a chached source file as needed. void importNontrivialAttribute(Decl *MappedDecl, StringRef attributeText); /// Utility function to import Clang attributes from a source Swift decl to /// synthesized Swift decl. /// /// \param SourceDecl The Swift decl to copy the atteribute from. /// \param SynthesizedDecl The synthesized Swift decl to attach attributes to. void importAttributesFromClangDeclToSynthesizedSwiftDecl(Decl *SourceDecl, Decl *SynthesizedDecl); /// Import attributes from the given Clang declaration to its Swift /// equivalent. /// /// \param ClangDecl The decl being imported. /// \param MappedDecl The decl to attach attributes to. /// \param NewContext If present, the Clang node for the context the decl is /// being imported into, which may affect info from API notes. void importAttributes(const clang::NamedDecl *ClangDecl, Decl *MappedDecl, const clang::ObjCContainerDecl *NewContext = nullptr); Type applyImportTypeAttrs(ImportTypeAttrs attrs, Type type, llvm::function_ref addImportDiagnosticFn); /// If we already imported a given decl, return the corresponding Swift decl. /// Otherwise, return nullptr. std::optional importDeclCached(const clang::NamedDecl *ClangDecl, Version version, bool UseCanonicalDecl = true); Decl *importDeclImpl(const clang::NamedDecl *ClangDecl, Version version, bool &TypedefIsSuperfluous, bool &HadForwardDeclaration); Decl *importDeclAndCacheImpl(const clang::NamedDecl *ClangDecl, Version version, bool SuperfluousTypedefsAreTransparent, bool UseCanonicalDecl); /// Same as \c importDeclReal, but for use inside importer /// implementation. /// /// Unlike \c importDeclReal, this function for convenience transparently /// looks through superfluous typedefs and returns the imported underlying /// decl in that case. Decl *importDecl(const clang::NamedDecl *ClangDecl, Version version, bool UseCanonicalDecl = true) { return importDeclAndCacheImpl(ClangDecl, version, /*SuperfluousTypedefsAreTransparent=*/true, /*UseCanonicalDecl*/ UseCanonicalDecl); } /// Import the given Clang declaration into Swift. Use this function /// outside of the importer implementation, when importing a decl requested by /// Swift code. /// /// \returns The imported declaration, or null if this declaration could /// not be represented in Swift. Decl *importDeclReal(const clang::NamedDecl *ClangDecl, Version version, bool useCanonicalDecl = true) { return importDeclAndCacheImpl(ClangDecl, version, /*SuperfluousTypedefsAreTransparent=*/false, /*UseCanonicalDecl*/ useCanonicalDecl); } /// Import a cloned version of the given declaration, which is part of /// an Objective-C protocol and currently must be a method or property, into /// the given declaration context. /// /// \returns The imported declaration, or null if this declaration could not /// be represented in Swift. Decl *importMirroredDecl(const clang::NamedDecl *decl, DeclContext *dc, Version version, ProtocolDecl *proto); void importInheritedConstructors(const clang::ObjCInterfaceDecl *curObjCClass, const ClassDecl *classDecl, SmallVectorImpl &newMembers); void importMirroredProtocolMembers(const clang::ObjCContainerDecl *decl, DeclContext *dc, std::optional name, SmallVectorImpl &members); /// Utility function for building simple generic signatures. GenericSignature buildGenericSignature(GenericParamList *genericParams, DeclContext *dc); /// Import the given Clang declaration context into Swift. /// /// Usually one will use \c importDeclContextOf instead. /// /// \returns The imported declaration context, or null if it could not /// be converted. DeclContext *importDeclContextImpl(const clang::Decl *ImportingDecl, const clang::DeclContext *dc); private: /// Declarations currently being imported by \c importDeclForDeclContext(). /// Used to break cycles when a swift_name attribute is circular in a way that /// can't be resolved, or there is some other cycle through /// \c importDeclContextOf(). llvm::SmallVector, 8> contextDeclsBeingImported; /// Records which contexts \c importDeclForDeclContext() has already warned /// were unimportable. llvm::SmallPtrSet contextDeclsWarnedAbout; /// Exactly equivalent to \c importDecl(), except with additional /// cycle-breaking code. /// /// \param writtenName The name that should be used for the declaration /// in cycle diagnostics. Decl *importDeclForDeclContext(const clang::Decl *ImportingDecl, StringRef writtenName, const clang::NamedDecl *ClangDecl, Version version, bool UseCanonicalDecl = true); public: /// Import the declaration context of a given Clang declaration into /// Swift. /// /// \param context The effective context as determined by importFullName. /// /// \returns The imported declaration context, or null if it could not /// be converted. DeclContext *importDeclContextOf(const clang::Decl *D, EffectiveClangContext context); /// Determine whether the given declaration is considered /// 'unavailable' in Swift. bool isUnavailableInSwift(const clang::Decl *decl) { return importer::isUnavailableInSwift( decl, &platformAvailability, SwiftContext.LangOpts.EnableObjCInterop); } /// Add "Unavailable" annotation to the swift declaration. void markUnavailable(ValueDecl *decl, StringRef unavailabilityMsg); /// Create a decl with error type and an "unavailable" attribute on it /// with the specified message. ValueDecl *createUnavailableDecl(Identifier name, DeclContext *dc, Type type, StringRef UnavailableMessage, bool isStatic, ClangNode ClangN, AccessLevel access); /// Add a synthesized typealias to the given nominal type. void addSynthesizedTypealias(NominalTypeDecl *nominal, Identifier name, Type underlyingType); void addSynthesizedProtocolAttrs( NominalTypeDecl *nominal, ArrayRef synthesizedProtocolAttrs, bool isUnchecked = false); void makeComputed(AbstractStorageDecl *storage, AccessorDecl *getter, AccessorDecl *setter); /// Retrieve the standard library module. ModuleDecl *getStdlibModule(); /// Retrieve the named module. /// /// \param name The name of the module. /// /// \returns The named module, or null if the module has not been imported. ModuleDecl *getNamedModule(StringRef name); /// Returns the "Foundation" module, if it can be loaded. /// /// After this has been called, the Foundation module will or won't be loaded /// into the ASTContext. ModuleDecl *tryLoadFoundationModule(); /// Returns whether or not the "Foundation" module can be imported, without loading it. bool canImportFoundationModule(); /// Retrieves the Swift wrapper for the given Clang module, creating /// it if necessary. ClangModuleUnit *getWrapperForModule(const clang::Module *underlying, SourceLoc importLoc = SourceLoc()); /// Constructs a Swift module for the given Clang module. ModuleDecl *finishLoadingClangModule(const clang::Module *clangModule, SourceLoc importLoc); /// Call finishLoadingClangModule on each deferred import collected /// while scanning a bridging header or PCH. void handleDeferredImports(SourceLoc diagLoc); /// Retrieve the named Swift type, e.g., Int32. /// /// \param moduleName The name of the module in which the type should occur. /// /// \param name The name of the type to find. /// /// \returns The named type, or null if the type could not be found. Type getNamedSwiftType(StringRef moduleName, StringRef name); /// Retrieve the named Swift type, e.g., Int32. /// /// \param module The module in which the type should occur. /// /// \param name The name of the type to find. /// /// \returns The named type, or null if the type could not be found. Type getNamedSwiftType(ModuleDecl *module, StringRef name); /// Retrieve the NSObject type. Type getNSObjectType(); /// Retrieve the NSObject protocol type. Type getNSObjectProtocolType(); /// Determines whether the given type matches an implicit type /// bound of "Hashable", which is used to validate NSDictionary/NSSet. bool matchesHashableBound(Type type); /// Determines whether the type declared by the given declaration /// is over-aligned. bool isOverAligned(const clang::TypeDecl *typeDecl); bool isOverAligned(clang::QualType type); /// Determines whether the given Clang type is serializable in a /// Swift AST. This should only be called after successfully importing /// the type, because it will look for a stable serialization path for any /// referenced declarations, which may depend on whether there's a known /// import of it. (It will not try to import the declaration to avoid /// circularity problems.) /// /// Note that this will only check the requested sugaring of the given /// type (depending on \c checkCanonical); the canonical type may be /// serializable even if the non-canonical type is not, or vice-versa. bool isSerializable(clang::QualType type, bool checkCanonical); /// Try to find a stable Swift serialization path for the given Clang /// declaration. StableSerializationPath findStableSerializationPath(const clang::Decl *decl); /// Look up and attempt to import a Clang declaration with /// the given name. Decl *importDeclByName(StringRef name); /// Import the given Clang type into Swift. /// /// \param type The Clang type to import. /// /// \param kind A classification of the immediate context in which this type /// will be used. Different contexts result in the type being imported /// differently; for example, CF types are normally considered Unmanaged, /// but in parameter position they are known to always be passed at +0. /// See also the \p topLevelBridgeability parameter. /// /// \param addImportDiagnosticFn A function that can be called to add import /// diagnostics to the declaration being imported. This can be any lambda or /// callable object, but it's designed to be compatible with /// \c ImportDiagnosticAdder . /// /// \param allowNSUIntegerAsInt If true, NSUInteger will be imported as Int /// in certain contexts. If false, it will always be imported as UInt. /// /// \param topLevelBridgeability A classification of the top-level context in /// which this type will be used. This and \p kind are used together to /// determine whether a type can be imported in a more Swifty way than /// a naive translation of its C type. Full bridgeability requires that SIL /// can get back to the original Clang type if it needs to, which implies /// that this type is part of a top-level declaration where we do bridging. /// Without full bridgeability, we can still do some Swifty importing (e.g. /// mapping NSString to String) if we're in an immediate context \p kind /// that allows bridging, but only in cases where Swift's default mapping /// "back" to C is the correct one. If the original type has something /// funny going on, we either have to use a less lossy version of the type /// (ObjCBool rather than Bool) or refuse to import it at all (a block with /// the \c ns_returns_retained attribute). /// /// \param attrs Attributes extracted from the declaration containing the type /// that should be applied to it. This should usually generated by applying /// \c getImportTypeAttrs() to the declaration. /// /// \param optional If the imported type was a pointer-like type in C, this /// optionality is applied to the resulting Swift type. /// /// \param resugarNSErrorPointer If true, Objective-C's `NSError **` is /// imported as Foundation.NSErrorPointer rather than /// AutoreleasingUnsafeMutablePointer<...>. This is usually desirable /// behavior, but isn't necessary when we use Swift's \c throws anyway. /// Strictly speaking, though, this is a hack used to break cyclic /// dependencies. /// /// \returns An ImportedType value which holds the imported type. If /// this type is an Optional, it also has a flag which /// indicates if the Optional is implicitly unwrapped. If /// the type cannot be represented in Swift, then the type /// field will be null. ImportedType importType( clang::QualType type, ImportTypeKind kind, llvm::function_ref addImportDiagnosticFn, bool allowNSUIntegerAsInt, Bridgeability topLevelBridgeability, ImportTypeAttrs attrs, OptionalTypeKind optional = OTK_ImplicitlyUnwrappedOptional, bool resugarNSErrorPointer = true, std::optional completionHandlerErrorParamIndex = std::nullopt); /// Import the given Clang type into Swift. /// /// For a description of parameters, see importType(). This differs /// only in that it returns a Type rather than ImportedType, which /// means that we do not retain the information of whether the type /// returned might be an implicitly unwrapped optional. /// /// \returns The imported type, or null if this type could not be /// represented in Swift. Type importTypeIgnoreIUO( clang::QualType type, ImportTypeKind kind, llvm::function_ref addImportDiagnosticFn, bool allowNSUIntegerAsInt, Bridgeability topLevelBridgeability, ImportTypeAttrs attrs, OptionalTypeKind optional = OTK_ImplicitlyUnwrappedOptional, bool resugarNSErrorPointer = true); /// Import the given Clang type into Swift, returning the /// Swift parameters and result type and whether we should treat it /// as an optional that is implicitly unwrapped. /// /// The parameters are returned via \c parameterList, and the result type is /// the return type of this method. /// /// \returns A pair of the imported result type and whether we should treat /// it as an optional that is implicitly unwrapped. The returned /// type is null if it cannot be represented in Swift. /// Import the given function type. /// /// This routine should be preferred when importing function types for /// which we have actual function parameters, e.g., when dealing with a /// function declaration, because it produces a function type whose input /// tuple has argument names. /// /// \param dc The context the function is being imported into. /// \param clangDecl The underlying declaration, if any; should only be /// considered for any attributes it might carry. /// \param params The parameter types to the function. /// \param isVariadic Whether the function is variadic. /// \param isFromSystemModule Whether to apply special rules that only apply /// to system APIs. /// \param name The name of the function. /// \param[out] parameterList The parameters visible inside the function body. ImportedType importFunctionParamsAndReturnType( DeclContext *dc, const clang::FunctionDecl *clangDecl, ArrayRef params, bool isVariadic, bool isFromSystemModule, DeclName name, ParameterList *¶meterList, ArrayRef genericParams); /// Import the given function return type. /// /// \param dc The context the function is being imported into. /// \param clangDecl The underlying declaration, if any; should only be /// considered for any attributes it might carry. /// \param allowNSUIntegerAsInt If true, NSUInteger will be imported as Int /// in certain contexts. If false, it will always be imported as UInt. /// /// \returns the imported function return type, or null if the type cannot be /// imported. ImportedType importFunctionReturnType(DeclContext *dc, const clang::FunctionDecl *clangDecl, bool allowNSUIntegerAsInt); /// Import the parameter list for a function /// /// \param clangDecl The underlying declaration, if any; should only be /// considered for any attributes it might carry. /// \param params The parameter types to the function. /// \param isVariadic Whether the function is variadic. /// \param allowNSUIntegerAsInt If true, NSUInteger will be imported as Int /// in certain contexts. If false, it will always be imported as UInt. /// \param argNames The argument names /// /// \returns The imported parameter list on success, or null on failure ParameterList *importFunctionParameterList( DeclContext *dc, const clang::FunctionDecl *clangDecl, ArrayRef params, bool isVariadic, bool allowNSUIntegerAsInt, ArrayRef argNames, ArrayRef genericParams, Type resultType); struct ImportParameterTypeResult { /// The imported parameter Swift type. swift::Type swiftTy; /// If the parameter is or not inout. bool isInOut; /// If the parameter should be imported as consuming. bool isConsuming; /// If the parameter is implicitly unwrapped or not. bool isParamTypeImplicitlyUnwrapped; }; /// Import a parameter type /// /// \param param The underlaying parameter declaraction. /// \param optionalityOfParam The kind of optionality for the parameter /// being imported. /// \param allowNSUIntegerAsInt If true, NSUInteger will be import as Int /// in certain contexts. If false, it will always be import as UInt. /// \param isNSDictionarySubscriptGetter If true, the parameter is being /// imported as part of an NSDictionary subscript getter. If false, /// the parameter belongs to some other kind of method/function. /// \param paramIsError If true, the parameter being imported is an NSError /// parameter. If false, the parameter is not an error parameter. /// \param paramIsCompletionHandler If true, the parameter being imported is /// a completion handler. If false, the parameter is not a completion /// handler. /// \param completionHandlerErrorParamIndex If it contains a value, the value /// indicates the index of the completion handler whose error /// parameter is used to indicate throwing. If None, the function does /// not have such parameter. /// \param genericParams For C++ functions, an array of the generic type /// parameters of the function. For the rest of cases, an empty array /// can be provided. /// \param addImportDiagnosticFn A function that can be called to add import /// diagnostics to the declaration being imported. This can be any /// lambda or callable object, but it's designed to be compatible /// with \c ImportDiagnosticAdder . /// /// \returns The imported parameter result on success, or None on failure. std::optional importParameterType( const clang::ParmVarDecl *param, OptionalTypeKind optionalityOfParam, bool allowNSUIntegerAsInt, bool isNSDictionarySubscriptGetter, bool paramIsError, bool paramIsCompletionHandler, std::optional completionHandlerErrorParamIndex, ArrayRef genericParams, llvm::function_ref addImportDiagnosticFn); ImportedType importPropertyType(const clang::ObjCPropertyDecl *clangDecl, bool isFromSystemModule); /// Determines what the type of an effectful, computed read-only property /// would be, if the given method were imported as such a property. ImportedType importEffectfulPropertyType(const clang::ObjCMethodDecl *decl, DeclContext *dc, importer::ImportedName name, bool isFromSystemModule); /// Attempt to infer a default argument for a parameter with the /// given Clang \c type, \c baseName, and optionality. static ArgumentAttrs inferDefaultArgument(clang::QualType type, OptionalTypeKind clangOptionality, DeclBaseName baseName, StringRef argumentLabel, bool isFirstParameter, bool isLastParameter, importer::NameImporter &nameImporter); /// Import the parameter and return types of an Objective-C method. /// /// The parameters are returned via \c bodyParams, and the result type is /// the return type of this method. /// /// Note that this is not appropriate to use for property accessor methods. /// Use #importAccessorParamsAndReturnType instead. /// /// \param dc The context the method is being imported into. /// \param clangDecl The underlying declaration. /// \param params The parameter types to the function. Note that this may not /// include all parameters defined on the ObjCMethodDecl. /// \param isVariadic Whether the function is variadic. /// \param isFromSystemModule Whether to apply special rules that only apply /// to system APIs. /// \param[out] bodyParams The patterns visible inside the function body. /// \param importedName How to import the name of the method. /// \param[out] errorConv Whether and how the method throws NSErrors. /// \param kind Controls whether we're building a type for a method that /// needs special handling. /// /// \returns the imported result type, or null if the type cannot be /// imported. ImportedType importMethodParamsAndReturnType( const DeclContext *dc, const clang::ObjCMethodDecl *clangDecl, ArrayRef params, bool isVariadic, bool isFromSystemModule, ParameterList **bodyParams, importer::ImportedName importedName, std::optional &asyncConv, std::optional &errorConv, SpecialMethodKind kind); /// Import the type of an Objective-C method that will be imported as an /// accessor for \p property. /// /// The parameters are returned via \c bodyParams, and the result type is /// the return type of this method. /// /// \param dc The context the method is being imported into. /// \param property The property the method will be an accessor for. /// \param clangDecl The underlying declaration. /// \param isFromSystemModule Whether to apply special rules that only apply /// to system APIs. /// \param importedName How to import the name of the method. This is still /// important to satisfy the AST verifier, even though the method is an /// accessor. /// \param[out] params The patterns visible inside the function body. /// /// \returns the imported result type, or null if the type cannot be /// imported. ImportedType importAccessorParamsAndReturnType(const DeclContext *dc, const clang::ObjCPropertyDecl *property, const clang::ObjCMethodDecl *clangDecl, bool isFromSystemModule, importer::ImportedName importedName, ParameterList **params); /// Determine whether the given typedef-name is "special", meaning /// that it has performed some non-trivial mapping of its underlying type /// based on the name of the typedef. std::optional getSpecialTypedefKind(clang::TypedefNameDecl *decl); /// Look up a name, accepting only typedef results. const clang::TypedefNameDecl *lookupTypedef(clang::DeclarationName); /// Return whether a global of the given type should be imported as a /// 'let' declaration as opposed to 'var'. bool shouldImportGlobalAsLet(clang::QualType type); /// Record the set of imported protocols for the given declaration, /// to be used by member loading. /// /// FIXME: This is all a hack; we should have lazier deserialization /// of protocols separate from their conformances. void recordImportedProtocols(Decl *decl, ArrayRef protocols) { // Nothing to do for protocols. if (isa(decl)) return; if (protocols.empty()) return; ImportedProtocols[decl] = SwiftContext.AllocateCopy(protocols); if (auto nominal = dyn_cast(decl)) { nominal->setConformanceLoader(this, 0); } else { auto ext = cast(decl); ext->setConformanceLoader(this, 0); } } /// Retrieve the imported protocols for the given declaration. ArrayRef getImportedProtocols(const Decl *decl) { auto known = ImportedProtocols.find(decl); if (known != ImportedProtocols.end()) return known->second; return ArrayRef(); } EnumDecl *lookupErrorCodeEnum(const StructDecl *errorWrapper) { auto found = ErrorCodeEnums.find(errorWrapper); if (found == ErrorCodeEnums.end()) return nullptr; return found->second; } virtual void loadAllMembers(Decl *D, uint64_t unused) override; virtual TinyPtrVector loadNamedMembers(const IterableDeclContext *IDC, DeclBaseName N, uint64_t contextData) override; private: void loadAllMembersOfObjcContainer(Decl *D, const clang::ObjCContainerDecl *objcContainer); void loadAllMembersOfRecordDecl(NominalTypeDecl *swiftDecl, const clang::RecordDecl *clangRecord, ClangInheritanceInfo inheritance); void collectMembersToAdd(const clang::ObjCContainerDecl *objcContainer, Decl *D, DeclContext *DC, SmallVectorImpl &members); void insertMembersAndAlternates(const clang::NamedDecl *nd, SmallVectorImpl &members, DeclContext *expectedDC = nullptr); void loadAllMembersIntoExtension(Decl *D, uint64_t extra); /// Imports \p decl under \p nameVersion with the name \p newName, and adds /// it and its alternates to \p ext. /// /// \returns true if \p decl was successfully imported, whether or not it was /// ultimately added to \p ext. This matches the behavior of /// forEachDistinctName's callback. bool addMemberAndAlternatesToExtension( clang::NamedDecl *decl, importer::ImportedName newName, importer::ImportNameVersion nameVersion, ExtensionDecl *ext); public: void loadAllConformances( const Decl *D, uint64_t contextData, SmallVectorImpl &Conformances) override; void finishNormalConformance(NormalProtocolConformance *conformance, uint64_t unused) override; /// Returns the default definition type for \p ATD. Type loadAssociatedTypeDefault(const AssociatedTypeDecl *ATD, uint64_t contextData) override { llvm_unreachable("unimplemented for ClangImporter"); } ValueDecl * loadDynamicallyReplacedFunctionDecl(const DynamicReplacementAttr *DRA, uint64_t contextData) override { llvm_unreachable("unimplemented for ClangImporter"); } AbstractFunctionDecl * loadReferencedFunctionDecl(const DerivativeAttr *DA, uint64_t contextData) override { llvm_unreachable("unimplemented for ClangImporter"); } Type loadTypeEraserType(const TypeEraserAttr *TRA, uint64_t contextData) override { llvm_unreachable("unimplemented for ClangImporter"); } ValueDecl *loadTargetFunctionDecl(const SpecializeAttr *attr, uint64_t contextData) override { llvm_unreachable("unimplemented for ClangImporter"); } void loadRequirementSignature(const ProtocolDecl *decl, uint64_t contextData, SmallVectorImpl &reqs, SmallVectorImpl &typeAliases) override { llvm_unreachable("unimplemented for ClangImporter"); } void loadAssociatedTypes( const ProtocolDecl *decl, uint64_t contextData, SmallVectorImpl &assocTypes) override { llvm_unreachable("unimplemented for ClangImporter"); } void loadPrimaryAssociatedTypes( const ProtocolDecl *decl, uint64_t contextData, SmallVectorImpl &assocTypes) override { llvm_unreachable("unimplemented for ClangImporter"); } template DeclTy *createDeclWithClangNode(ClangNode ClangN, AccessLevel access, Targs &&... Args) { assert(ClangN); void *DeclPtr = allocateMemoryForDecl(SwiftContext, sizeof(DeclTy), true); auto D = ::new (DeclPtr) DeclTy(std::forward(Args)...); D->setClangNode(ClangN); D->setAccess(access); if (auto ASD = dyn_cast(D)) ASD->setSetterAccess(access); if constexpr (std::is_base_of_v) { // Estimate brace locations. clang::SourceLocation begin; clang::SourceLocation end; if (auto *td = dyn_cast_or_null(ClangN.getAsDecl())) { begin = td->getBraceRange().getBegin(); end = td->getBraceRange().getEnd(); } else { begin = ClangN.getAsDecl()->getBeginLoc(); end = ClangN.getAsDecl()->getEndLoc(); } SourceRange range; if (begin.isValid() && end.isValid() && D->getNameLoc().isValid()) range = SourceRange(importSourceLoc(begin), importSourceLoc(end)); else { range = SourceRange(D->getNameLoc(), D->getNameLoc()); } assert(range.isValid() == D->getNameLoc().isValid()); D->setBraces(range); #ifndef NDEBUG auto declRange = D->getSourceRange(); CharSourceRange checkValidRange(SwiftContext.SourceMgr, declRange.Start, declRange.End); #endif } // SwiftAttrs on ParamDecls are interpreted by applyParamAttributes(). if (!isa(D)) importSwiftAttrAttributes(D); return D; } void importSwiftAttrAttributes(Decl *decl); void swiftify(FuncDecl *MappedDecl); /// 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. SwiftLookupTable *findLookupTable(const clang::Module *clangModule); /// Find the lookup table that should contain the given Clang declaration. SwiftLookupTable *findLookupTable(const clang::Decl *decl); /// Visit each of the lookup tables in some deterministic order. /// /// \param fn Invoke the given visitor for each table. If the /// visitor returns true, stop early. /// /// \returns \c true if the \c visitor ever returns \c true, \c /// false otherwise. bool forEachLookupTable(llvm::function_ref fn); /// Determine whether the given Clang entry is visible. /// /// FIXME: this is an elaborate hack to badly reflect Clang's /// submodule visibility into Swift. bool isVisibleClangEntry(const clang::NamedDecl *clangDecl); bool isVisibleClangEntry(SwiftLookupTable::SingleEntry entry); /// Look for namespace-scope values with the given name in the given /// Swift lookup table. bool lookupValue(SwiftLookupTable &table, DeclName name, VisibleDeclConsumer &consumer); /// Look for namespace-scope values with the given name using the /// DWARFImporterDelegate. /// \param inModule only return results from this module. void lookupValueDWARF(DeclName name, NLKind lookupKind, Identifier inModule, SmallVectorImpl &results); /// Look for top-level scope types with a name and kind using the /// DWARFImporterDelegate. void lookupTypeDeclDWARF(StringRef rawName, ClangTypeKind kind, llvm::function_ref receiver); /// Look for namespace-scope values in the given Swift lookup table. void lookupVisibleDecls(SwiftLookupTable &table, VisibleDeclConsumer &consumer); /// Look for Objective-C members with the given name in the given /// Swift lookup table. void lookupObjCMembers(SwiftLookupTable &table, DeclName name, VisibleDeclConsumer &consumer); /// Look for all Objective-C members in the given Swift lookup table. void lookupAllObjCMembers(SwiftLookupTable &table, VisibleDeclConsumer &consumer); /// Emits diagnostics for any declarations named name /// whose direct declaration context is a TU. void diagnoseTopLevelValue(const DeclName &name); /// Emit diagnostics for declarations named name that are members /// of the provided container. void diagnoseMemberValue(const DeclName &name, const clang::DeclContext *container); /// Emit any import diagnostics associated with the given Clang node. void diagnoseTargetDirectly(ImportDiagnosticTarget target); private: ImportDiagnosticTarget importDiagnosticTargetFromLookupTableEntry( SwiftLookupTable::SingleEntry entry); bool emitDiagnosticsForTarget( ImportDiagnosticTarget target, clang::SourceLocation fallbackLoc = clang::SourceLocation()); public: /// Determine the effective Clang context for the given Swift nominal type. EffectiveClangContext getEffectiveClangContext(const NominalTypeDecl *nominal); /// Attempts to import the name of \p decl with each possible /// ImportNameVersion. \p action will be called with each unique name. /// /// In this case, "unique" means either the full name is distinct or the /// effective context is distinct. This method does not attempt to handle /// "unresolved" contexts in any special way---if one name references a /// particular Clang declaration and the other has an unresolved context that /// will eventually reference that declaration, the contexts will still be /// considered distinct. /// /// If \p action returns false, the current name will \e not be added to the /// set of seen names. /// /// The active name is always first, followed by the other names in the order /// of ImportNameVersion::forEachOtherImportNameVersion. void forEachDistinctName( const clang::NamedDecl *decl, llvm::function_ref action) { getNameImporter().forEachDistinctImportName(decl, CurrentVersion, action); } /// Dump the Swift-specific name lookup tables we generate. void dumpSwiftLookupTables(); void setSinglePCHImport(std::optional PCHFilename) { if (PCHFilename.has_value()) { assert(llvm::sys::path::extension(PCHFilename.value()) .ends_with(file_types::getExtension(file_types::TY_PCH)) && "Single PCH imported filename doesn't have .pch extension!"); } SinglePCHImport = PCHFilename; } /// If there was is a single .pch bridging header without other imported /// files, we can provide the PCH filename for declaration caching, /// especially in code completion. StringRef getSinglePCHImport() const { if (SinglePCHImport.has_value()) return *SinglePCHImport; return StringRef(); } }; class ImportDiagnosticAdder { ClangImporter::Implementation &impl; ImportDiagnosticTarget target; const clang::SourceLocation loc; public: ImportDiagnosticAdder( ClangImporter::Implementation &impl, ImportDiagnosticTarget target, clang::SourceLocation loc) : impl(impl), target(target), loc(loc) {} void operator () (Diagnostic &&diag) { impl.addImportDiagnostic(target, std::move(diag), loc); } }; namespace importer { /// Returns true if the given C/C++ record should be imported as a reference /// type into Swift. bool recordHasReferenceSemantics(const clang::RecordDecl *decl, ClangImporter::Implementation *importerImpl); /// Returns true if the given C/C++ reference type uses "immortal" /// retain/release functions. bool hasImmortalAttrs(const clang::RecordDecl *decl); /// Whether this is a forward declaration of a type. We ignore forward /// declarations in certain cases, and instead process the real declarations. bool isForwardDeclOfType(const clang::Decl *decl); /// Whether we should suppress the import of the given Clang declaration. bool shouldSuppressDeclImport(const clang::Decl *decl); /// Identifies certain UIKit constants that used to have overlay equivalents, /// but are now renamed using the swift_name attribute. bool isSpecialUIKitStructZeroProperty(const clang::NamedDecl *decl); /// \returns true if \p a has the same underlying type as \p b after removing /// any pointer/reference specifiers. Note that this does not currently look through /// nested types other than pointers or references. bool hasSameUnderlyingType(const clang::Type *a, const clang::TemplateTypeParmDecl *b); /// Add command-line arguments for a normal import of Clang code. void getNormalInvocationArguments(std::vector &invocationArgStrs, ASTContext &ctx, bool ignoreClangTarget); /// Add command-line arguments common to all imports of Clang code. void addCommonInvocationArguments(std::vector &invocationArgStrs, ASTContext &ctx, bool requiresBuiltinHeadersInSystemModules, bool ignoreClangTarget); /// Finds a particular kind of nominal by looking through typealiases. template static T *dynCastIgnoringCompatibilityAlias(Decl *D) { static_assert(std::is_base_of::value, "only meant for use with NominalTypeDecl and subclasses"); if (auto *alias = dyn_cast_or_null(D)) { if (!alias->isCompatibilityAlias()) return nullptr; D = alias->getDeclaredInterfaceType()->getAnyNominal(); } return dyn_cast_or_null(D); } /// Finds a particular kind of nominal by looking through typealiases. template static T *castIgnoringCompatibilityAlias(Decl *D) { static_assert(std::is_base_of::value, "only meant for use with NominalTypeDecl and subclasses"); if (auto *alias = dyn_cast_or_null(D)) { assert(alias->isCompatibilityAlias() && "non-compatible typealias found where nominal was expected"); D = alias->getDeclaredInterfaceType()->getAnyNominal(); } return cast_or_null(D); } class SwiftNameLookupExtension : public clang::ModuleFileExtension { std::unique_ptr &pchLookupTable; LookupTableMap &lookupTables; ASTContext &swiftCtx; ClangSourceBufferImporter &buffersForDiagnostics; const PlatformAvailability &availability; ClangImporter::Implementation *importerImpl; public: SwiftNameLookupExtension(std::unique_ptr &pchLookupTable, LookupTableMap &tables, ASTContext &ctx, ClangSourceBufferImporter &buffersForDiagnostics, const PlatformAvailability &avail, ClangImporter::Implementation *importerImpl) : // Update in response to D97702 landing. clang::ModuleFileExtension(), pchLookupTable(pchLookupTable), lookupTables(tables), swiftCtx(ctx), buffersForDiagnostics(buffersForDiagnostics), availability(avail), importerImpl(importerImpl) {} clang::ModuleFileExtensionMetadata getExtensionMetadata() const override; void hashExtension(ExtensionHashBuilder &HBuilder) const override; std::unique_ptr createExtensionWriter(clang::ASTWriter &writer) override; std::unique_ptr createExtensionReader(const clang::ModuleFileExtensionMetadata &metadata, clang::ASTReader &reader, clang::serialization::ModuleFile &mod, const llvm::BitstreamCursor &stream) override; }; /// Determines whether the given swift_attr attribute describes the main /// actor. bool isMainActorAttr(const clang::SwiftAttrAttr *swiftAttr); /// Determines whether the given swift_attr controls mutability bool isMutabilityAttr(const clang::SwiftAttrAttr *swiftAttr); /// Apply an attribute to a function type. static inline Type applyToFunctionType( Type type, llvm::function_ref transform) { // Recurse into optional types. if (Type objectType = type->getOptionalObjectType()) { return OptionalType::get(applyToFunctionType(objectType, transform)); } // Apply transform to function types. if (auto funcType = type->getAs()) { auto newExtInfo = transform(funcType->getExtInfo()); if (!newExtInfo.isEqualTo(funcType->getExtInfo(), /*useClangTypes=*/true)) return FunctionType::get(funcType->getParams(), funcType->getResult(), newExtInfo); } return type; } inline std::optional findAnonymousEnumForTypedef(const ASTContext &ctx, const clang::TypedefType *typedefType) { auto *typedefDecl = typedefType->getDecl(); auto *lookupTable = ctx.getClangModuleLoader()->findLookupTable(typedefDecl->getOwningModule()); auto foundDecls = lookupTable->lookup( SerializedSwiftName(typedefDecl->getName()), EffectiveClangContext()); auto found = llvm::find_if(foundDecls, [](SwiftLookupTable::SingleEntry decl) { return decl.is() && isa(decl.get()); }); if (found != foundDecls.end()) return cast(found->get()); // If a swift_private attribute has been attached to the enum, its name will // be prefixed with two underscores llvm::SmallString<32> swiftPrivateName; swiftPrivateName += "__"; swiftPrivateName += typedefDecl->getName(); foundDecls = lookupTable->lookup( SerializedSwiftName(ctx.getIdentifier(swiftPrivateName)), EffectiveClangContext()); auto swiftPrivateFound = llvm::find_if(foundDecls, [](SwiftLookupTable::SingleEntry decl) { return decl.is() && isa(decl.get()) && decl.get() ->hasAttr(); }); if (swiftPrivateFound != foundDecls.end()) return cast(swiftPrivateFound->get()); return std::nullopt; } /// Construct the imported Swift name for an imported Clang operator kind, /// e.g., \c "__operatorPlus" for Clang::OO_Plus. /// /// Returns an empty identifier (internally, a nullptr) when \a op does not /// represent an actual operator, i.e., OO_None or NUM_OVERLOADED_OPERATORS. Identifier getOperatorName(ASTContext &ctx, clang::OverloadedOperatorKind op); /// Construct the imported Swift name corresponding to an operator identifier, /// e.g., \c "__operatorPlus" for \c "+". /// /// Returns an empty identifier (internally, a nullptr) when \a op does not /// correspond to an overloaded C++ operator. Identifier getOperatorName(ASTContext &ctx, Identifier op); bool hasOwnedValueAttr(const clang::RecordDecl *decl); bool hasUnsafeAPIAttr(const clang::Decl *decl); bool hasIteratorAPIAttr(const clang::Decl *decl); bool hasNonEscapableAttr(const clang::RecordDecl *decl); bool hasEscapableAttr(const clang::RecordDecl *decl); bool isViewType(const clang::CXXRecordDecl *decl); } // end namespace importer } // end namespace swift #endif