| //===--- PrintAsObjC.cpp - Emit a header file for a Swift AST -------------===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "swift/PrintAsObjC/PrintAsObjC.h" |
| |
| #include "ModuleContentsWriter.h" |
| |
| #include "swift/AST/ASTContext.h" |
| #include "swift/AST/Module.h" |
| #include "swift/AST/PrettyStackTrace.h" |
| #include "swift/Basic/Version.h" |
| #include "swift/ClangImporter/ClangImporter.h" |
| |
| #include "clang/Basic/Module.h" |
| |
| #include "llvm/Support/raw_ostream.h" |
| |
| using namespace swift; |
| |
| static void writePrologue(raw_ostream &out, ASTContext &ctx) { |
| out << "// Generated by " << version::getSwiftFullVersion( |
| ctx.LangOpts.EffectiveLanguageVersion) << "\n" |
| "#pragma clang diagnostic push\n" |
| "#pragma clang diagnostic ignored \"-Wgcc-compat\"\n" |
| "\n" |
| "#if !defined(__has_include)\n" |
| "# define __has_include(x) 0\n" |
| "#endif\n" |
| "#if !defined(__has_attribute)\n" |
| "# define __has_attribute(x) 0\n" |
| "#endif\n" |
| "#if !defined(__has_feature)\n" |
| "# define __has_feature(x) 0\n" |
| "#endif\n" |
| "#if !defined(__has_warning)\n" |
| "# define __has_warning(x) 0\n" |
| "#endif\n" |
| "\n" |
| "#if __has_include(<swift/objc-prologue.h>)\n" |
| "# include <swift/objc-prologue.h>\n" |
| "#endif\n" |
| "\n" |
| "#pragma clang diagnostic ignored \"-Wauto-import\"\n" |
| "#include <Foundation/Foundation.h>\n" |
| "#include <stdint.h>\n" |
| "#include <stddef.h>\n" |
| "#include <stdbool.h>\n" |
| "\n" |
| "#if !defined(SWIFT_TYPEDEFS)\n" |
| "# define SWIFT_TYPEDEFS 1\n" |
| "# if __has_include(<uchar.h>)\n" |
| "# include <uchar.h>\n" |
| "# elif !defined(__cplusplus)\n" |
| "typedef uint_least16_t char16_t;\n" |
| "typedef uint_least32_t char32_t;\n" |
| "# endif\n" |
| #define MAP_SIMD_TYPE(C_TYPE, SCALAR_TYPE, _) \ |
| "typedef " #SCALAR_TYPE " swift_" #C_TYPE "2" \ |
| " __attribute__((__ext_vector_type__(2)));\n" \ |
| "typedef " #SCALAR_TYPE " swift_" #C_TYPE "3" \ |
| " __attribute__((__ext_vector_type__(3)));\n" \ |
| "typedef " #SCALAR_TYPE " swift_" #C_TYPE "4" \ |
| " __attribute__((__ext_vector_type__(4)));\n" |
| #include "swift/ClangImporter/SIMDMappedTypes.def" |
| "#endif\n" |
| "\n" |
| "#if !defined(SWIFT_PASTE)\n" |
| "# define SWIFT_PASTE_HELPER(x, y) x##y\n" |
| "# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y)\n" |
| "#endif" |
| "\n" |
| "#if !defined(SWIFT_METATYPE)\n" |
| "# define SWIFT_METATYPE(X) Class\n" |
| "#endif\n" |
| "#if !defined(SWIFT_CLASS_PROPERTY)\n" |
| "# if __has_feature(objc_class_property)\n" |
| "# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__\n" |
| "# else\n" |
| "# define SWIFT_CLASS_PROPERTY(...)\n" |
| "# endif\n" |
| "#endif\n" |
| "\n" |
| "#if __has_attribute(objc_runtime_name)\n" |
| "# define SWIFT_RUNTIME_NAME(X) " |
| "__attribute__((objc_runtime_name(X)))\n" |
| "#else\n" |
| "# define SWIFT_RUNTIME_NAME(X)\n" |
| "#endif\n" |
| "#if __has_attribute(swift_name)\n" |
| "# define SWIFT_COMPILE_NAME(X) " |
| "__attribute__((swift_name(X)))\n" |
| "#else\n" |
| "# define SWIFT_COMPILE_NAME(X)\n" |
| "#endif\n" |
| "#if __has_attribute(objc_method_family)\n" |
| "# define SWIFT_METHOD_FAMILY(X) " |
| "__attribute__((objc_method_family(X)))\n" |
| "#else\n" |
| "# define SWIFT_METHOD_FAMILY(X)\n" |
| "#endif\n" |
| "#if __has_attribute(noescape)\n" |
| "# define SWIFT_NOESCAPE __attribute__((noescape))\n" |
| "#else\n" |
| "# define SWIFT_NOESCAPE\n" |
| "#endif\n" |
| "#if __has_attribute(warn_unused_result)\n" |
| "# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result))\n" |
| "#else\n" |
| "# define SWIFT_WARN_UNUSED_RESULT\n" |
| "#endif\n" |
| "#if __has_attribute(noreturn)\n" |
| "# define SWIFT_NORETURN __attribute__((noreturn))\n" |
| "#else\n" |
| "# define SWIFT_NORETURN\n" |
| "#endif\n" |
| "#if !defined(SWIFT_CLASS_EXTRA)\n" |
| "# define SWIFT_CLASS_EXTRA\n" |
| "#endif\n" |
| "#if !defined(SWIFT_PROTOCOL_EXTRA)\n" |
| "# define SWIFT_PROTOCOL_EXTRA\n" |
| "#endif\n" |
| "#if !defined(SWIFT_ENUM_EXTRA)\n" |
| "# define SWIFT_ENUM_EXTRA\n" |
| "#endif\n" |
| "#if !defined(SWIFT_CLASS)\n" |
| "# if __has_attribute(objc_subclassing_restricted)\n" |
| "# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) " |
| "__attribute__((objc_subclassing_restricted)) " |
| "SWIFT_CLASS_EXTRA\n" |
| "# define SWIFT_CLASS_NAMED(SWIFT_NAME) " |
| "__attribute__((objc_subclassing_restricted)) " |
| "SWIFT_COMPILE_NAME(SWIFT_NAME) " |
| "SWIFT_CLASS_EXTRA\n" |
| "# else\n" |
| "# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) " |
| "SWIFT_CLASS_EXTRA\n" |
| "# define SWIFT_CLASS_NAMED(SWIFT_NAME) " |
| "SWIFT_COMPILE_NAME(SWIFT_NAME) " |
| "SWIFT_CLASS_EXTRA\n" |
| "# endif\n" |
| "#endif\n" |
| "#if !defined(SWIFT_RESILIENT_CLASS)\n" |
| "# if __has_attribute(objc_class_stub)\n" |
| "# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) " |
| "__attribute__((objc_class_stub))\n" |
| "# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) " |
| "__attribute__((objc_class_stub)) " |
| "SWIFT_CLASS_NAMED(SWIFT_NAME)\n" |
| "# else\n" |
| "# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) " |
| "SWIFT_CLASS(SWIFT_NAME)\n" |
| "# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) " |
| "SWIFT_CLASS_NAMED(SWIFT_NAME)\n" |
| "# endif\n" |
| "#endif\n" |
| "\n" |
| "#if !defined(SWIFT_PROTOCOL)\n" |
| "# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) " |
| "SWIFT_PROTOCOL_EXTRA\n" |
| "# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) " |
| "SWIFT_COMPILE_NAME(SWIFT_NAME) " |
| "SWIFT_PROTOCOL_EXTRA\n" |
| "#endif\n" |
| "\n" |
| "#if !defined(SWIFT_EXTENSION)\n" |
| "# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__)\n" |
| "#endif\n" |
| "\n" |
| "#if !defined(OBJC_DESIGNATED_INITIALIZER)\n" |
| "# if __has_attribute(objc_designated_initializer)\n" |
| "# define OBJC_DESIGNATED_INITIALIZER " |
| "__attribute__((objc_designated_initializer))\n" |
| "# else\n" |
| "# define OBJC_DESIGNATED_INITIALIZER\n" |
| "# endif\n" |
| "#endif\n" |
| "#if !defined(SWIFT_ENUM_ATTR)\n" |
| "# if defined(__has_attribute) && " |
| "__has_attribute(enum_extensibility)\n" |
| "# define SWIFT_ENUM_ATTR(_extensibility) " |
| "__attribute__((enum_extensibility(_extensibility)))\n" |
| "# else\n" |
| "# define SWIFT_ENUM_ATTR(_extensibility)\n" |
| "# endif\n" |
| "#endif\n" |
| "#if !defined(SWIFT_ENUM)\n" |
| "# define SWIFT_ENUM(_type, _name, _extensibility) " |
| "enum _name : _type _name; " |
| "enum SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA " |
| "_name : _type\n" |
| "# if __has_feature(generalized_swift_name)\n" |
| "# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, " |
| "_extensibility) " |
| "enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); " |
| "enum SWIFT_COMPILE_NAME(SWIFT_NAME) " |
| "SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type\n" |
| "# else\n" |
| "# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, " |
| "_extensibility) SWIFT_ENUM(_type, _name, _extensibility)\n" |
| "# endif\n" |
| "#endif\n" |
| "#if !defined(SWIFT_UNAVAILABLE)\n" |
| "# define SWIFT_UNAVAILABLE __attribute__((unavailable))\n" |
| "#endif\n" |
| "#if !defined(SWIFT_UNAVAILABLE_MSG)\n" |
| "# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg)))\n" |
| "#endif\n" |
| "#if !defined(SWIFT_AVAILABILITY)\n" |
| "# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__)))\n" |
| "#endif\n" |
| "#if !defined(SWIFT_WEAK_IMPORT)\n" |
| "# define SWIFT_WEAK_IMPORT __attribute__((weak_import))\n" |
| "#endif\n" |
| "#if !defined(SWIFT_DEPRECATED)\n" |
| "# define SWIFT_DEPRECATED __attribute__((deprecated))\n" |
| "#endif\n" |
| "#if !defined(SWIFT_DEPRECATED_MSG)\n" |
| "# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__)))\n" |
| "#endif\n" |
| "#if __has_feature(attribute_diagnose_if_objc)\n" |
| "# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, \"warning\")))\n" |
| "#else\n" |
| "# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg)\n" |
| "#endif\n" |
| "#if !defined(IBSegueAction)\n" |
| "# define IBSegueAction\n" |
| "#endif\n" |
| ; |
| static_assert(SWIFT_MAX_IMPORTED_SIMD_ELEMENTS == 4, |
| "need to add SIMD typedefs here if max elements is increased"); |
| } |
| |
| static int compareImportModulesByName(const ImportModuleTy *left, |
| const ImportModuleTy *right) { |
| auto *leftSwiftModule = left->dyn_cast<ModuleDecl *>(); |
| auto *rightSwiftModule = right->dyn_cast<ModuleDecl *>(); |
| |
| if (leftSwiftModule && !rightSwiftModule) |
| return -compareImportModulesByName(right, left); |
| |
| if (leftSwiftModule && rightSwiftModule) |
| return leftSwiftModule->getName().compare(rightSwiftModule->getName()); |
| |
| auto *leftClangModule = left->get<const clang::Module *>(); |
| assert(leftClangModule->isSubModule() && |
| "top-level modules should use a normal swift::ModuleDecl"); |
| if (rightSwiftModule) { |
| // Because the Clang module is a submodule, its full name will never be |
| // equal to a Swift module's name, even if the top-level name is the same; |
| // it will always come before or after. |
| if (leftClangModule->getTopLevelModuleName() < |
| rightSwiftModule->getName().str()) { |
| return -1; |
| } |
| return 1; |
| } |
| |
| auto *rightClangModule = right->get<const clang::Module *>(); |
| assert(rightClangModule->isSubModule() && |
| "top-level modules should use a normal swift::ModuleDecl"); |
| |
| SmallVector<StringRef, 8> leftReversePath( |
| ModuleDecl::ReverseFullNameIterator(leftClangModule), {}); |
| SmallVector<StringRef, 8> rightReversePath( |
| ModuleDecl::ReverseFullNameIterator(rightClangModule), {}); |
| |
| assert(leftReversePath != rightReversePath && |
| "distinct Clang modules should not have the same full name"); |
| if (std::lexicographical_compare(leftReversePath.rbegin(), |
| leftReversePath.rend(), |
| rightReversePath.rbegin(), |
| rightReversePath.rend())) { |
| return -1; |
| } |
| return 1; |
| } |
| |
| static void writeImports(raw_ostream &out, |
| llvm::SmallPtrSetImpl<ImportModuleTy> &imports, |
| ModuleDecl &M, StringRef bridgingHeader) { |
| out << "#if __has_feature(modules)\n"; |
| |
| out << "#if __has_warning(\"-Watimport-in-framework-header\")\n" |
| << "#pragma clang diagnostic ignored \"-Watimport-in-framework-header\"\n" |
| << "#endif\n"; |
| |
| // Sort alphabetically for determinism and consistency. |
| SmallVector<ImportModuleTy, 8> sortedImports{imports.begin(), |
| imports.end()}; |
| llvm::array_pod_sort(sortedImports.begin(), sortedImports.end(), |
| &compareImportModulesByName); |
| |
| auto isUnderlyingModule = [&M, bridgingHeader](ModuleDecl *import) -> bool { |
| if (bridgingHeader.empty()) |
| return import != &M && import->getName() == M.getName(); |
| |
| auto importer = static_cast<ClangImporter *>( |
| import->getASTContext().getClangModuleLoader()); |
| return import == importer->getImportedHeaderModule(); |
| }; |
| |
| // Track printed names to handle overlay modules. |
| llvm::SmallPtrSet<Identifier, 8> seenImports; |
| bool includeUnderlying = false; |
| for (auto import : sortedImports) { |
| if (auto *swiftModule = import.dyn_cast<ModuleDecl *>()) { |
| auto Name = swiftModule->getName(); |
| if (isUnderlyingModule(swiftModule)) { |
| includeUnderlying = true; |
| continue; |
| } |
| if (seenImports.insert(Name).second) |
| out << "@import " << Name.str() << ";\n"; |
| } else { |
| const auto *clangModule = import.get<const clang::Module *>(); |
| assert(clangModule->isSubModule() && |
| "top-level modules should use a normal swift::ModuleDecl"); |
| out << "@import "; |
| ModuleDecl::ReverseFullNameIterator(clangModule).printForward(out); |
| out << ";\n"; |
| } |
| } |
| |
| out << "#endif\n\n"; |
| |
| if (includeUnderlying) { |
| if (bridgingHeader.empty()) |
| out << "#import <" << M.getName().str() << '/' << M.getName().str() |
| << ".h>\n\n"; |
| else |
| out << "#import \"" << bridgingHeader << "\"\n\n"; |
| } |
| } |
| |
| static void writePostImportPrologue(raw_ostream &os, ModuleDecl &M) { |
| os << |
| "#pragma clang diagnostic ignored \"-Wproperty-attribute-mismatch\"\n" |
| "#pragma clang diagnostic ignored \"-Wduplicate-method-arg\"\n" |
| "#if __has_warning(\"-Wpragma-clang-attribute\")\n" |
| "# pragma clang diagnostic ignored \"-Wpragma-clang-attribute\"\n" |
| "#endif\n" |
| "#pragma clang diagnostic ignored \"-Wunknown-pragmas\"\n" |
| "#pragma clang diagnostic ignored \"-Wnullability\"\n" |
| "\n" |
| "#if __has_attribute(external_source_symbol)\n" |
| "# pragma push_macro(\"any\")\n" |
| "# undef any\n" |
| "# pragma clang attribute push(" |
| "__attribute__((external_source_symbol(language=\"Swift\", " |
| "defined_in=\"" << M.getNameStr() << "\",generated_declaration))), " |
| "apply_to=any(function,enum,objc_interface,objc_category," |
| "objc_protocol))\n" |
| "# pragma pop_macro(\"any\")\n" |
| "#endif\n\n"; |
| } |
| |
| static void writeEpilogue(raw_ostream &os) { |
| os << |
| "#if __has_attribute(external_source_symbol)\n" |
| "# pragma clang attribute pop\n" |
| "#endif\n" |
| "#pragma clang diagnostic pop\n"; |
| } |
| |
| bool swift::printAsObjC(raw_ostream &os, ModuleDecl *M, |
| StringRef bridgingHeader, |
| AccessLevel minRequiredAccess) { |
| llvm::PrettyStackTraceString trace("While generating Objective-C header"); |
| |
| SmallPtrSet<ImportModuleTy, 8> imports; |
| std::string moduleContentsBuf; |
| llvm::raw_string_ostream moduleContents{moduleContentsBuf}; |
| printModuleContentsAsObjC(moduleContents, imports, *M, minRequiredAccess); |
| |
| writePrologue(os, M->getASTContext()); |
| writeImports(os, imports, *M, bridgingHeader); |
| writePostImportPrologue(os, *M); |
| os << moduleContents.str(); |
| writeEpilogue(os); |
| |
| return false; |
| } |