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,90 @@ 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
416
+ SmallString<32 > newHeaderName =
417
+ *(++llvm::sys::path::rbegin (clangModule->PresumedModuleMapFile ));
418
+ llvm::sys::path::append (newHeaderName, header);
419
+ fullHeaderName = newHeaderName;
420
+ }
421
+ requiredTextualIncludes.insert (fullHeaderName);
422
+ };
423
+
424
+ for (clang::Module::HeaderKind headerKind :
425
+ {clang::Module::HK_Normal, clang::Module::HK_Private}) {
426
+ for (const clang::Module::Header &header :
427
+ clangModule->Headers [headerKind]) {
428
+ addHeader (clangModule, header.PathRelativeToRootModuleDirectory );
429
+ }
430
+ }
431
+
432
+ if (clang::Module::Header umbrellaHeader = clangModule->getUmbrellaHeader ()) {
433
+ addHeader (clangModule, umbrellaHeader.PathRelativeToRootModuleDirectory );
434
+ } else if (clang::Module::DirectoryName umbrellaDir =
435
+ clangModule->getUmbrellaDir ()) {
436
+ SmallString<128 > nativeUmbrellaDirPath;
437
+ std::error_code errorCode;
438
+ llvm::sys::path::native (umbrellaDir.Entry ->getName (),
439
+ nativeUmbrellaDirPath);
440
+ llvm::vfs::FileSystem &fileSystem = fileManager.getVirtualFileSystem ();
441
+ for (llvm::vfs::recursive_directory_iterator
442
+ dir (fileSystem, nativeUmbrellaDirPath, errorCode),
443
+ end;
444
+ dir != end && !errorCode; dir.increment (errorCode)) {
445
+
446
+ if (llvm::StringSwitch<bool >(llvm::sys::path::extension (dir->path ()))
447
+ .Cases (" .h" , " .H" , " .hh" , " .hpp" , true )
448
+ .Default (false )) {
449
+
450
+ // Computer path to the header relative to the root of the module
451
+ // (location of the module map) First compute the relative path from
452
+ // umbrella directory to header file
453
+ SmallVector<StringRef> pathComponents;
454
+ auto pathIt = llvm::sys::path::rbegin (dir->path ());
455
+
456
+ for (int i = 0 ; i != dir.level () + 1 ; ++i, ++pathIt)
457
+ pathComponents.push_back (*pathIt);
458
+ // Then append this to the path from module root to umbrella dir
459
+ SmallString<128 > relativeHeaderPath;
460
+ if (umbrellaDir.PathRelativeToRootModuleDirectory != " ." )
461
+ relativeHeaderPath += umbrellaDir.PathRelativeToRootModuleDirectory ;
462
+
463
+ for (auto it = pathComponents.rbegin (), end = pathComponents.rend ();
464
+ it != end; ++it) {
465
+ llvm::sys::path::append (relativeHeaderPath, *it);
466
+ }
467
+ addHeader (clangModule, relativeHeaderPath);
468
+ }
469
+ }
470
+ }
471
+
472
+ for (auto submodule : clangModule->submodules ()) {
473
+ collectClangModuleHeaderIncludes (submodule, fileManager,
474
+ requiredTextualIncludes);
475
+ }
476
+ }
477
+
396
478
static void writeImports (raw_ostream &out,
397
479
llvm::SmallPtrSetImpl<ImportModuleTy> &imports,
398
- ModuleDecl &M, StringRef bridgingHeader) {
480
+ ModuleDecl &M, StringRef bridgingHeader,
481
+ const FrontendOptions &frontendOpts) {
399
482
out << " #if __has_feature(modules)\n " ;
400
483
401
484
out << " #if __has_warning(\" -Watimport-in-framework-header\" )\n "
@@ -417,6 +500,11 @@ static void writeImports(raw_ostream &out,
417
500
return import == importer->getImportedHeaderModule ();
418
501
};
419
502
503
+ clang::FileSystemOptions fileSystemOptions;
504
+ clang::FileManager fileManager{fileSystemOptions};
505
+
506
+ llvm::SmallSet<llvm::SmallString<32 >, 10 > requiredTextualIncludes;
507
+
420
508
// Track printed names to handle overlay modules.
421
509
llvm::SmallPtrSet<Identifier, 8 > seenImports;
422
510
bool includeUnderlying = false ;
@@ -427,18 +515,39 @@ static void writeImports(raw_ostream &out,
427
515
includeUnderlying = true ;
428
516
continue ;
429
517
}
430
- if (seenImports.insert (Name).second )
518
+ if (seenImports.insert (Name).second ) {
431
519
out << " @import " << Name.str () << " ;\n " ;
520
+ if (frontendOpts.EmitObjCHeaderWithTextualImports ) {
521
+ if (const clang::Module *underlyingClangModule =
522
+ swiftModule->findUnderlyingClangModule ()) {
523
+ collectClangModuleHeaderIncludes (underlyingClangModule, fileManager,
524
+ requiredTextualIncludes);
525
+ }
526
+ }
527
+ }
432
528
} else {
433
529
const auto *clangModule = import.get <const clang::Module *>();
434
530
assert (clangModule->isSubModule () &&
435
531
" top-level modules should use a normal swift::ModuleDecl" );
436
532
out << " @import " ;
437
533
ModuleDecl::ReverseFullNameIterator (clangModule).printForward (out);
438
534
out << " ;\n " ;
535
+
536
+ if (frontendOpts.EmitObjCHeaderWithTextualImports ) {
537
+ collectClangModuleHeaderIncludes (clangModule, fileManager,
538
+ requiredTextualIncludes);
539
+ }
439
540
}
440
541
}
441
542
543
+ if (frontendOpts.EmitObjCHeaderWithTextualImports ) {
544
+ out << " #else\n " ;
545
+ for (auto header : requiredTextualIncludes) {
546
+ out << " #if __has_include(<" << header << " >)\n " ;
547
+ out << " #import <" << header << " >\n " ;
548
+ out << " #endif\n " ;
549
+ }
550
+ }
442
551
out << " #endif\n\n " ;
443
552
444
553
if (includeUnderlying) {
@@ -504,7 +613,8 @@ getModuleContentsCxxString(ModuleDecl &M,
504
613
bool swift::printAsClangHeader (raw_ostream &os, ModuleDecl *M,
505
614
StringRef bridgingHeader,
506
615
bool ExposePublicDeclsInClangHeader,
507
- const IRGenOptions &irGenOpts) {
616
+ const IRGenOptions &irGenOpts,
617
+ const FrontendOptions &frontendOpts) {
508
618
llvm::PrettyStackTraceString trace (" While generating Clang header" );
509
619
510
620
SwiftToClangInteropContext interopContext (*M, irGenOpts);
@@ -514,8 +624,8 @@ bool swift::printAsClangHeader(raw_ostream &os, ModuleDecl *M,
514
624
llvm::raw_string_ostream objcModuleContents{objcModuleContentsBuf};
515
625
printModuleContentsAsObjC (objcModuleContents, imports, *M, interopContext);
516
626
writePrologue (os, M->getASTContext (), computeMacroGuard (M));
517
- emitObjCConditional (os,
518
- [&] { writeImports (os, imports, *M, bridgingHeader); });
627
+ emitObjCConditional (
628
+ os, [&] { writeImports (os, imports, *M, bridgingHeader, frontendOpts ); });
519
629
writePostImportPrologue (os, *M);
520
630
emitObjCConditional (os, [&] { os << objcModuleContents.str (); });
521
631
emitCxxConditional (os, [&] {
0 commit comments