20
20
#include " swift/AST/PrettyStackTrace.h"
21
21
#include " swift/Basic/Version.h"
22
22
#include " swift/ClangImporter/ClangImporter.h"
23
+ #include " swift/Frontend/FrontendOptions.h"
23
24
25
+ #include " clang/Basic/FileManager.h"
24
26
#include " clang/Basic/Module.h"
25
27
26
28
#include " llvm/Support/raw_ostream.h"
@@ -393,9 +395,93 @@ static int compareImportModulesByName(const ImportModuleTy *left,
393
395
return 1 ;
394
396
}
395
397
398
+ // Collect the set of header includes needed to import the given Clang module
399
+ // into an ObjectiveC program. Modeled after collectModuleHeaderIncludes in the
400
+ // Clang frontend (FrontendAction.cpp)
401
+ // Augment requiredTextualIncludes with the set of headers required.
402
+ static void collectClangModuleHeaderIncludes (
403
+ const clang::Module *clangModule, clang::FileManager &fileManager,
404
+ llvm::SmallSet<llvm::SmallString<32 >, 10 > &requiredTextualIncludes) {
405
+
406
+ auto addHeader = [&](const clang::Module *module, StringRef header) {
407
+ llvm::SmallString<32 > fullHeaderName = header;
408
+ if (clangModule->IsFramework ) {
409
+ // Frameworks store their headers in an explicit header directory
410
+ // Transform "Headers/Foundation.h" -> "Foundation/Foundation.h"
411
+ llvm::sys::path::replace_path_prefix (fullHeaderName, " Headers" ,
412
+ clangModule->Name );
413
+ } else {
414
+ // Prepend the name of the directory containing the module to the header
415
+ // include, unless the directory seems to be on a typical include path
416
+ // (ends in include)
417
+ SmallString<32 > headerPrefix =
418
+ *(++llvm::sys::path::rbegin (clangModule->PresumedModuleMapFile ));
419
+ if (headerPrefix != " include" ) {
420
+ llvm::sys::path::append (headerPrefix, header);
421
+ fullHeaderName = headerPrefix;
422
+ }
423
+ }
424
+ requiredTextualIncludes.insert (fullHeaderName);
425
+ };
426
+
427
+ for (clang::Module::HeaderKind headerKind :
428
+ {clang::Module::HK_Normal, clang::Module::HK_Private}) {
429
+ for (const clang::Module::Header &header :
430
+ clangModule->Headers [headerKind]) {
431
+ addHeader (clangModule, header.PathRelativeToRootModuleDirectory );
432
+ }
433
+ }
434
+
435
+ if (clang::Module::Header umbrellaHeader = clangModule->getUmbrellaHeader ()) {
436
+ addHeader (clangModule, umbrellaHeader.PathRelativeToRootModuleDirectory );
437
+ } else if (clang::Module::DirectoryName umbrellaDir =
438
+ clangModule->getUmbrellaDir ()) {
439
+ SmallString<128 > nativeUmbrellaDirPath;
440
+ std::error_code errorCode;
441
+ llvm::sys::path::native (umbrellaDir.Entry ->getName (),
442
+ nativeUmbrellaDirPath);
443
+ llvm::vfs::FileSystem &fileSystem = fileManager.getVirtualFileSystem ();
444
+ for (llvm::vfs::recursive_directory_iterator
445
+ dir (fileSystem, nativeUmbrellaDirPath, errorCode),
446
+ end;
447
+ dir != end && !errorCode; dir.increment (errorCode)) {
448
+
449
+ if (llvm::StringSwitch<bool >(llvm::sys::path::extension (dir->path ()))
450
+ .Cases (" .h" , " .H" , " .hh" , " .hpp" , true )
451
+ .Default (false )) {
452
+
453
+ // Computer path to the header relative to the root of the module
454
+ // (location of the module map) First compute the relative path from
455
+ // umbrella directory to header file
456
+ SmallVector<StringRef> pathComponents;
457
+ auto pathIt = llvm::sys::path::rbegin (dir->path ());
458
+
459
+ for (int i = 0 ; i != dir.level () + 1 ; ++i, ++pathIt)
460
+ pathComponents.push_back (*pathIt);
461
+ // Then append this to the path from module root to umbrella dir
462
+ SmallString<128 > relativeHeaderPath;
463
+ if (umbrellaDir.PathRelativeToRootModuleDirectory != " ." )
464
+ relativeHeaderPath += umbrellaDir.PathRelativeToRootModuleDirectory ;
465
+
466
+ for (auto it = pathComponents.rbegin (), end = pathComponents.rend ();
467
+ it != end; ++it) {
468
+ llvm::sys::path::append (relativeHeaderPath, *it);
469
+ }
470
+ addHeader (clangModule, relativeHeaderPath);
471
+ }
472
+ }
473
+ }
474
+
475
+ for (auto submodule : clangModule->submodules ()) {
476
+ collectClangModuleHeaderIncludes (submodule, fileManager,
477
+ requiredTextualIncludes);
478
+ }
479
+ }
480
+
396
481
static void writeImports (raw_ostream &out,
397
482
llvm::SmallPtrSetImpl<ImportModuleTy> &imports,
398
- ModuleDecl &M, StringRef bridgingHeader) {
483
+ ModuleDecl &M, StringRef bridgingHeader,
484
+ const FrontendOptions &frontendOpts) {
399
485
out << " #if __has_feature(modules)\n " ;
400
486
401
487
out << " #if __has_warning(\" -Watimport-in-framework-header\" )\n "
@@ -417,6 +503,11 @@ static void writeImports(raw_ostream &out,
417
503
return import == importer->getImportedHeaderModule ();
418
504
};
419
505
506
+ clang::FileSystemOptions fileSystemOptions;
507
+ clang::FileManager fileManager{fileSystemOptions};
508
+
509
+ llvm::SmallSet<llvm::SmallString<32 >, 10 > requiredTextualIncludes;
510
+
420
511
// Track printed names to handle overlay modules.
421
512
llvm::SmallPtrSet<Identifier, 8 > seenImports;
422
513
bool includeUnderlying = false ;
@@ -427,18 +518,39 @@ static void writeImports(raw_ostream &out,
427
518
includeUnderlying = true ;
428
519
continue ;
429
520
}
430
- if (seenImports.insert (Name).second )
521
+ if (seenImports.insert (Name).second ) {
431
522
out << " @import " << Name.str () << " ;\n " ;
523
+ if (frontendOpts.EmitObjCHeaderWithTextualImports ) {
524
+ if (const clang::Module *underlyingClangModule =
525
+ swiftModule->findUnderlyingClangModule ()) {
526
+ collectClangModuleHeaderIncludes (underlyingClangModule, fileManager,
527
+ requiredTextualIncludes);
528
+ }
529
+ }
530
+ }
432
531
} else {
433
532
const auto *clangModule = import.get <const clang::Module *>();
434
533
assert (clangModule->isSubModule () &&
435
534
" top-level modules should use a normal swift::ModuleDecl" );
436
535
out << " @import " ;
437
536
ModuleDecl::ReverseFullNameIterator (clangModule).printForward (out);
438
537
out << " ;\n " ;
538
+
539
+ if (frontendOpts.EmitObjCHeaderWithTextualImports ) {
540
+ collectClangModuleHeaderIncludes (clangModule, fileManager,
541
+ requiredTextualIncludes);
542
+ }
439
543
}
440
544
}
441
545
546
+ if (frontendOpts.EmitObjCHeaderWithTextualImports ) {
547
+ out << " #else\n " ;
548
+ for (auto header : requiredTextualIncludes) {
549
+ out << " #if __has_include(<" << header << " >)\n " ;
550
+ out << " #import <" << header << " >\n " ;
551
+ out << " #endif\n " ;
552
+ }
553
+ }
442
554
out << " #endif\n\n " ;
443
555
444
556
if (includeUnderlying) {
@@ -504,7 +616,8 @@ getModuleContentsCxxString(ModuleDecl &M,
504
616
bool swift::printAsClangHeader (raw_ostream &os, ModuleDecl *M,
505
617
StringRef bridgingHeader,
506
618
bool ExposePublicDeclsInClangHeader,
507
- const IRGenOptions &irGenOpts) {
619
+ const IRGenOptions &irGenOpts,
620
+ const FrontendOptions &frontendOpts) {
508
621
llvm::PrettyStackTraceString trace (" While generating Clang header" );
509
622
510
623
SwiftToClangInteropContext interopContext (*M, irGenOpts);
@@ -514,8 +627,8 @@ bool swift::printAsClangHeader(raw_ostream &os, ModuleDecl *M,
514
627
llvm::raw_string_ostream objcModuleContents{objcModuleContentsBuf};
515
628
printModuleContentsAsObjC (objcModuleContents, imports, *M, interopContext);
516
629
writePrologue (os, M->getASTContext (), computeMacroGuard (M));
517
- emitObjCConditional (os,
518
- [&] { writeImports (os, imports, *M, bridgingHeader); });
630
+ emitObjCConditional (
631
+ os, [&] { writeImports (os, imports, *M, bridgingHeader, frontendOpts ); });
519
632
writePostImportPrologue (os, *M);
520
633
emitObjCConditional (os, [&] { os << objcModuleContents.str (); });
521
634
emitCxxConditional (os, [&] {
0 commit comments