11#include " SwiftExtractor.h"
22
3- #include < filesystem>
4- #include < fstream>
53#include < iostream>
6- #include < sstream>
74#include < memory>
8- #include < unistd.h>
95#include < unordered_set>
106#include < queue>
117
1612#include < llvm/Support/Path.h>
1713
1814#include " swift/extractor/trap/generated/TrapClasses.h"
19- #include " swift/extractor/trap/TrapOutput .h"
15+ #include " swift/extractor/trap/TrapDomain .h"
2016#include " swift/extractor/visitors/SwiftVisitor.h"
17+ #include " swift/extractor/infra/TargetFile.h"
2118
2219using namespace codeql ;
2320
@@ -52,7 +49,7 @@ static void archiveFile(const SwiftExtractorConfiguration& config, swift::Source
5249 }
5350}
5451
55- static std::string getTrapFilename (swift::ModuleDecl& module , swift::SourceFile* primaryFile) {
52+ static std::string getFilename (swift::ModuleDecl& module , swift::SourceFile* primaryFile) {
5653 if (primaryFile) {
5754 return primaryFile->getFilename ().str ();
5855 }
@@ -76,60 +73,45 @@ static llvm::SmallVector<swift::Decl*> getTopLevelDecls(swift::ModuleDecl& modul
7673 return ret;
7774}
7875
76+ static void dumpArgs (TargetFile& out, const SwiftExtractorConfiguration& config) {
77+ out << " /* extractor-args:\n " ;
78+ for (const auto & opt : config.frontendOptions ) {
79+ out << " " << std::quoted (opt) << " \\\n " ;
80+ }
81+ out << " \n */\n " ;
82+
83+ out << " /* swift-frontend-args:\n " ;
84+ for (const auto & opt : config.patchedFrontendOptions ) {
85+ out << " " << std::quoted (opt) << " \\\n " ;
86+ }
87+ out << " \n */\n " ;
88+ }
89+
7990static void extractDeclarations (const SwiftExtractorConfiguration& config,
8091 swift::CompilerInstance& compiler,
8192 swift::ModuleDecl& module ,
8293 swift::SourceFile* primaryFile = nullptr ) {
94+ auto filename = getFilename (module , primaryFile);
95+
8396 // The extractor can be called several times from different processes with
84- // the same input file(s)
85- // We are using PID to avoid concurrent access
86- // TODO: find a more robust approach to avoid collisions?
87- auto name = getTrapFilename (module , primaryFile);
88- llvm::StringRef filename (name);
89- std::string tempTrapName = filename.str () + ' .' + std::to_string (getpid ()) + " .trap" ;
90- llvm::SmallString<PATH_MAX> tempTrapPath (config.getTempTrapDir ());
91- llvm::sys::path::append (tempTrapPath, tempTrapName);
92-
93- llvm::StringRef tempTrapParent = llvm::sys::path::parent_path (tempTrapPath);
94- if (std::error_code ec = llvm::sys::fs::create_directories (tempTrapParent)) {
95- std::cerr << " Cannot create temp trap directory '" << tempTrapParent.str ()
96- << " ': " << ec.message () << " \n " ;
97+ // the same input file(s). Using `TargetFile` the first process will win, and the following
98+ // will just skip the work
99+ auto trapTarget = TargetFile::create (filename + " .trap" , config.trapDir , config.getTempTrapDir ());
100+ if (!trapTarget) {
101+ // another process arrived first, nothing to do for us
97102 return ;
98103 }
99-
100- std::ofstream trapStream (tempTrapPath.str ().str ());
101- if (!trapStream) {
102- std::error_code ec;
103- ec.assign (errno, std::generic_category ());
104- std::cerr << " Cannot create temp trap file '" << tempTrapPath.str ().str ()
105- << " ': " << ec.message () << " \n " ;
106- return ;
107- }
108- trapStream << " /* extractor-args:\n " ;
109- for (auto opt : config.frontendOptions ) {
110- trapStream << " " << std::quoted (opt) << " \\\n " ;
111- }
112- trapStream << " \n */\n " ;
113-
114- trapStream << " /* swift-frontend-args:\n " ;
115- for (auto opt : config.patchedFrontendOptions ) {
116- trapStream << " " << std::quoted (opt) << " \\\n " ;
117- }
118- trapStream << " \n */\n " ;
119-
120- TrapOutput trap{trapStream};
121- TrapArena arena{};
104+ dumpArgs (*trapTarget, config);
105+ TrapDomain trap{*trapTarget};
122106
123107 // TODO: move default location emission elsewhere, possibly in a separate global trap file
124- auto unknownFileLabel = arena.allocateLabel <FileTag>();
125108 // the following cannot conflict with actual files as those have an absolute path starting with /
126- trap.assignKey (unknownFileLabel, " unknown" );
109+ auto unknownFileLabel = trap.createLabel <FileTag>(" unknown" );
110+ auto unknownLocationLabel = trap.createLabel <LocationTag>(" unknown" );
127111 trap.emit (FilesTrap{unknownFileLabel});
128- auto unknownLocationLabel = arena.allocateLabel <LocationTag>();
129- trap.assignKey (unknownLocationLabel, " unknown" );
130112 trap.emit (LocationsTrap{unknownLocationLabel, unknownFileLabel});
131113
132- SwiftVisitor visitor (compiler.getSourceMgr (), arena, trap, module , primaryFile);
114+ SwiftVisitor visitor (compiler.getSourceMgr (), trap, module , primaryFile);
133115 auto topLevelDecls = getTopLevelDecls (module , primaryFile);
134116 for (auto decl : topLevelDecls) {
135117 visitor.extract (decl);
@@ -142,28 +124,9 @@ static void extractDeclarations(const SwiftExtractorConfiguration& config,
142124 // fact that the file was extracted
143125 llvm::SmallString<PATH_MAX> name (filename);
144126 llvm::sys::fs::make_absolute (name);
145- auto fileLabel = arena.allocateLabel <FileTag>();
146- trap.assignKey (fileLabel, name.str ().str ());
127+ auto fileLabel = trap.createLabel <FileTag>(name.str ().str ());
147128 trap.emit (FilesTrap{fileLabel, name.str ().str ()});
148129 }
149-
150- // TODO: Pick a better name to avoid collisions
151- std::string trapName = filename.str () + " .trap" ;
152- llvm::SmallString<PATH_MAX> trapPath (config.trapDir );
153- llvm::sys::path::append (trapPath, trapName);
154-
155- llvm::StringRef trapParent = llvm::sys::path::parent_path (trapPath);
156- if (std::error_code ec = llvm::sys::fs::create_directories (trapParent)) {
157- std::cerr << " Cannot create trap directory '" << trapParent.str () << " ': " << ec.message ()
158- << " \n " ;
159- return ;
160- }
161-
162- // TODO: The last process wins. Should we do better than that?
163- if (std::error_code ec = llvm::sys::fs::rename (tempTrapPath, trapPath)) {
164- std::cerr << " Cannot rename temp trap file '" << tempTrapPath.str ().str () << " ' -> '"
165- << trapPath.str ().str () << " ': " << ec.message () << " \n " ;
166- }
167130}
168131
169132static std::unordered_set<std::string> collectInputFilenames (swift::CompilerInstance& compiler) {
0 commit comments