32
32
#include " llvm/ADT/StringRef.h"
33
33
#include " llvm/ADT/StringSet.h"
34
34
#include " llvm/Support/FileSystem.h"
35
+ #include " llvm/Support/StringSaver.h"
36
+ #include " llvm/Support/YAMLTraits.h"
37
+ #include " llvm/Support/YAMLParser.h"
35
38
#include < set>
36
39
37
40
using namespace swift ;
41
+ using namespace llvm ::yaml;
38
42
39
43
namespace {
44
+ struct BatchScanInput {
45
+ StringRef moduleName;
46
+ StringRef arguments;
47
+ StringRef outputPath;
48
+ bool isSwift;
49
+ };
50
+
51
+ static std::string getScalaNodeText (Node *N) {
52
+ SmallString<32 > Buffer;
53
+ return cast<ScalarNode>(N)->getValue (Buffer).str ();
54
+ }
55
+
56
+ // / Parse an entry like this, where the "platforms" key-value pair is optional:
57
+ // / {
58
+ // / "swiftModuleName": "Foo",
59
+ // / "arguments": "-target 10.15",
60
+ // / "output": "../Foo.json"
61
+ // / },
62
+ static bool parseBatchInputEntries (ASTContext &Ctx, llvm::StringSaver &saver,
63
+ Node *Node, std::vector<BatchScanInput> &result) {
64
+ auto *SN = cast<SequenceNode>(Node);
65
+ if (!SN)
66
+ return true ;
67
+ for (auto It = SN->begin (); It != SN->end (); ++It) {
68
+ auto *MN = cast<MappingNode>(&*It);
69
+ BatchScanInput entry;
70
+ Optional<std::set<int8_t >> Platforms;
71
+ for (auto &Pair: *MN) {
72
+ auto Key = getScalaNodeText (Pair.getKey ());
73
+ auto * Value = Pair.getValue ();
74
+ if (Key == " clangModuleName" ) {
75
+ entry.moduleName = saver.save (getScalaNodeText (Value));
76
+ entry.isSwift = false ;
77
+ } else if (Key == " swiftModuleName" ) {
78
+ entry.moduleName = saver.save (getScalaNodeText (Value));
79
+ entry.isSwift = true ;
80
+ } else if (Key == " arguments" ) {
81
+ entry.arguments = saver.save (getScalaNodeText (Value));
82
+ } else if (Key == " output" ) {
83
+ entry.outputPath = saver.save (getScalaNodeText (Value));
84
+ } else {
85
+ // Future proof.
86
+ continue ;
87
+ }
88
+ }
89
+ if (entry.moduleName .empty ())
90
+ return true ;
91
+ if (entry.outputPath .empty ())
92
+ return true ;
93
+ result.emplace_back (std::move (entry));
94
+ }
95
+ return false ;
96
+ }
40
97
98
+ static Optional<std::vector<BatchScanInput>>
99
+ parseBatchScanInputFile (ASTContext &ctx, StringRef batchInputPath,
100
+ llvm::StringSaver &saver) {
101
+ assert (!batchInputPath.empty ());
102
+ namespace yaml = llvm::yaml;
103
+ std::vector<BatchScanInput> result;
104
+
105
+ // Load the input file.
106
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileBufOrErr =
107
+ llvm::MemoryBuffer::getFile (batchInputPath);
108
+ if (!FileBufOrErr) {
109
+ ctx.Diags .diagnose (SourceLoc (), diag::batch_scan_input_file_missing,
110
+ batchInputPath);
111
+ return None;
112
+ }
113
+ StringRef Buffer = FileBufOrErr->get ()->getBuffer ();
114
+
115
+ // Use a new source manager instead of the one from ASTContext because we
116
+ // don't want the Json file to be persistent.
117
+ SourceManager SM;
118
+ yaml::Stream Stream (llvm::MemoryBufferRef (Buffer, batchInputPath),
119
+ SM.getLLVMSourceMgr ());
120
+ for (auto DI = Stream.begin (); DI != Stream.end (); ++ DI) {
121
+ assert (DI != Stream.end () && " Failed to read a document" );
122
+ yaml::Node *N = DI->getRoot ();
123
+ assert (N && " Failed to find a root" );
124
+ if (parseBatchInputEntries (ctx, saver, N, result)) {
125
+ ctx.Diags .diagnose (SourceLoc (), diag::batch_scan_input_file_corrupted,
126
+ batchInputPath);
127
+ return None;
128
+ }
129
+ }
130
+ return result;
131
+ }
41
132
}
42
133
43
134
// / Find all of the imported Clang modules starting with the given module name.
@@ -533,15 +624,17 @@ static bool diagnoseCycle(CompilerInstance &instance,
533
624
return false ;
534
625
}
535
626
536
- bool swift::scanClangDependencies (CompilerInstance &instance) {
627
+ static bool scanModuleDependencies (CompilerInstance &instance,
628
+ StringRef moduleName,
629
+ StringRef arguments,
630
+ bool isClang,
631
+ StringRef outputPath) {
537
632
ASTContext &ctx = instance.getASTContext ();
538
- ModuleDecl *mainModule = instance.getMainModule ();
539
633
auto &FEOpts = instance.getInvocation ().getFrontendOptions ();
540
634
ModuleInterfaceLoaderOptions LoaderOpts (FEOpts);
541
635
auto ModuleCachePath = getModuleCachePathFromClang (ctx
542
636
.getClangModuleLoader ()->getClangInstance ());
543
637
544
- StringRef mainModuleName = mainModule->getNameStr ();
545
638
llvm::SetVector<ModuleDependencyID, std::vector<ModuleDependencyID>,
546
639
std::set<ModuleDependencyID>> allModules;
547
640
// Create the module dependency cache.
@@ -555,16 +648,23 @@ bool swift::scanClangDependencies(CompilerInstance &instance) {
555
648
FEOpts.PrebuiltModuleCachePath ,
556
649
FEOpts.SerializeModuleInterfaceDependencyHashes ,
557
650
FEOpts.shouldTrackSystemDependencies ());
558
- // Loading the clang module using Clang importer.
559
- // This action will populate the cache with the main module's dependencies.
560
- auto rootDeps = static_cast <ClangImporter*>(ctx.getClangModuleLoader ())
561
- ->getModuleDependencies (mainModuleName, cache, ASTDelegate);
651
+ Optional<ModuleDependencies> rootDeps;
652
+ if (isClang) {
653
+ // Loading the clang module using Clang importer.
654
+ // This action will populate the cache with the main module's dependencies.
655
+ rootDeps = ctx.getModuleDependencies (moduleName, /* IsClang*/ true , cache,
656
+ ASTDelegate);
657
+ } else {
658
+ // Loading the swift module's dependencies.
659
+ rootDeps = ctx.getSwiftModuleDependencies (moduleName, cache, ASTDelegate);
660
+ }
562
661
if (!rootDeps.hasValue ()) {
563
662
// We cannot find the clang module, abort.
564
663
return true ;
565
664
}
566
665
// Add the main module.
567
- allModules.insert ({mainModuleName.str (), ModuleDependenciesKind::Clang});
666
+ allModules.insert ({moduleName.str (), isClang ? ModuleDependenciesKind::Clang:
667
+ ModuleDependenciesKind::Swift});
568
668
569
669
// Explore the dependencies of every module.
570
670
for (unsigned currentModuleIdx = 0 ;
@@ -576,13 +676,38 @@ bool swift::scanClangDependencies(CompilerInstance &instance) {
576
676
allModules.insert (discoveredModules.begin (), discoveredModules.end ());
577
677
}
578
678
// Write out the JSON description.
579
- std::string path = FEOpts.InputsAndOutputs .getSingleOutputFilename ();
580
679
std::error_code EC;
581
- llvm::raw_fd_ostream out (path , EC, llvm::sys::fs::F_None);
680
+ llvm::raw_fd_ostream out (outputPath , EC, llvm::sys::fs::F_None);
582
681
writeJSON (out, instance, cache, ASTDelegate, allModules.getArrayRef ());
583
682
return false ;
584
683
}
585
684
685
+ bool swift::scanClangDependencies (CompilerInstance &instance) {
686
+ return scanModuleDependencies (instance,
687
+ instance.getMainModule ()->getNameStr (),
688
+ StringRef (),
689
+ /* isClang*/ true ,
690
+ instance.getInvocation ().getFrontendOptions ()
691
+ .InputsAndOutputs .getSingleOutputFilename ());
692
+ }
693
+
694
+ bool swift::batchScanModuleDependencies (CompilerInstance &instance,
695
+ llvm::StringRef batchInputFile) {
696
+ (void )instance.getMainModule ();
697
+ llvm::BumpPtrAllocator alloc;
698
+ llvm::StringSaver saver (alloc);
699
+ auto results = parseBatchScanInputFile (instance.getASTContext (),
700
+ batchInputFile, saver);
701
+ if (!results.hasValue ())
702
+ return true ;
703
+ for (auto &entry: *results) {
704
+ if (scanModuleDependencies (instance, entry.moduleName , entry.arguments ,
705
+ !entry.isSwift , entry.outputPath ))
706
+ return true ;
707
+ }
708
+ return false ;
709
+ }
710
+
586
711
bool swift::scanDependencies (CompilerInstance &instance) {
587
712
ASTContext &Context = instance.getASTContext ();
588
713
ModuleDecl *mainModule = instance.getMainModule ();
0 commit comments