Skip to content

Commit f1413f2

Browse files
committed
Swift: move back file opening code
1 parent a46582d commit f1413f2

File tree

2 files changed

+48
-81
lines changed

2 files changed

+48
-81
lines changed

swift/extractor/SwiftExtractor.cpp

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,16 +48,53 @@ static void extractFile(const SwiftExtractorConfiguration& config, swift::Source
4848
return;
4949
}
5050

51-
if (TrapOutput trap{config, file.getFilename().str()}) {
52-
TrapArena arena{};
51+
// The extractor can be called several times from different processes with
52+
// the same input file(s)
53+
// We are using PID to avoid concurrent access
54+
// TODO: find a more robust approach to avoid collisions?
55+
std::string tempTrapName = file.getFilename().str() + '.' + std::to_string(getpid()) + ".trap";
56+
llvm::SmallString<PATH_MAX> tempTrapPath(config.trapDir);
57+
llvm::sys::path::append(tempTrapPath, tempTrapName);
5358

54-
auto label = arena.allocateLabel<File::Tag>();
55-
trap.assignStar(label);
59+
llvm::StringRef trapParent = llvm::sys::path::parent_path(tempTrapPath);
60+
if (std::error_code ec = llvm::sys::fs::create_directories(trapParent)) {
61+
std::cerr << "Cannot create trap directory '" << trapParent.str() << "': " << ec.message()
62+
<< "\n";
63+
return;
64+
}
65+
66+
std::ofstream trapStream(tempTrapPath.str().str());
67+
if (!trapStream) {
68+
std::error_code ec;
69+
ec.assign(errno, std::generic_category());
70+
std::cerr << "Cannot create temp trap file '" << tempTrapPath.str().str()
71+
<< "': " << ec.message() << "\n";
72+
return;
73+
}
74+
trapStream << "// extractor-args: ";
75+
for (auto opt : config.frontendOptions) {
76+
trapStream << std::quoted(opt) << " ";
77+
}
78+
trapStream << "\n\n";
79+
80+
TrapOutput trap{trapStream};
81+
TrapArena arena{};
82+
auto label = arena.allocateLabel<File::Tag>();
83+
trap.assignStar(label);
84+
File f{};
85+
f.id = label;
86+
f.name = srcFilePath.str().str();
87+
trap.emit(f);
88+
89+
// TODO: Pick a better name to avoid collisions
90+
std::string trapName = file.getFilename().str() + ".trap";
91+
llvm::SmallString<PATH_MAX> trapPath(config.trapDir);
92+
llvm::sys::path::append(trapPath, trapName);
5693

57-
File f{};
58-
f.id = label;
59-
f.name = srcFilePath.str().str();
60-
trap.emit(f);
94+
// TODO: The last process wins. Should we do better than that?
95+
if (std::error_code ec = llvm::sys::fs::rename(tempTrapPath, trapPath)) {
96+
std::cerr << "Cannot rename temp trap file '" << tempTrapPath.str().str() << "' -> '"
97+
<< trapPath.str().str() << "': " << ec.message() << "\n";
6198
}
6299
}
63100

swift/extractor/trap/TrapOutput.h

Lines changed: 3 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,19 @@
11
#pragma once
22

33
#include <memory>
4-
#include <llvm/ADT/SmallString.h>
5-
#include <llvm/Support/FileSystem.h>
6-
#include <llvm/Support/Path.h>
7-
8-
#include "swift/extractor/SwiftExtractorConfiguration.h"
94
#include "swift/extractor/trap/TrapLabel.h"
105

116
namespace codeql {
127

138
// Sink for trap emissions and label assignments. This abstracts away `ofstream` operations
149
// like `ofstream`, an explicit bool operator is provided, that return false if something
1510
// went wrong
11+
// TODO better error handling
1612
class TrapOutput {
17-
std::ofstream out_{};
18-
std::string target_;
13+
std::ostream& out_;
1914

2015
public:
21-
// open a output stream. Internally a temporary file is created which is then moved into place
22-
// on `close()` or destruction
23-
TrapOutput(const SwiftExtractorConfiguration& config, const std::string& target) {
24-
// TODO: Pick a better name to avoid collisions
25-
llvm::SmallString<PATH_MAX> trapPath(config.trapDir);
26-
llvm::sys::path::append(trapPath, target);
27-
target_ = trapPath.str().str();
28-
29-
auto trapDir = llvm::sys::path::parent_path(trapPath);
30-
if (std::error_code ec = llvm::sys::fs::create_directories(trapDir)) {
31-
std::cerr << "Cannot create trap directory '" << trapDir.str() << "': " << ec.message()
32-
<< "\n";
33-
return;
34-
}
35-
36-
auto tempFile = getTempFile();
37-
out_ = std::ofstream{tempFile};
38-
if (!out_) {
39-
std::error_code ec;
40-
ec.assign(errno, std::generic_category());
41-
std::cerr << "Cannot create temp trap file '" << tempFile << "': " << ec.message() << "\n";
42-
return;
43-
}
44-
out_ << "// extractor-args: ";
45-
for (auto opt : config.frontendOptions) {
46-
out_ << std::quoted(opt) << " ";
47-
}
48-
out_ << "\n\n";
49-
}
50-
51-
~TrapOutput() { close(); }
52-
53-
TrapOutput(const TrapOutput& other) = delete;
54-
TrapOutput& operator=(const TrapOutput& other) = delete;
55-
56-
TrapOutput(TrapOutput&& other) : out_{std::move(other.out_)}, target_{std::move(other.target_)} {
57-
assert(!other.out_.is_open());
58-
}
59-
60-
TrapOutput& operator=(TrapOutput&& other) {
61-
close();
62-
out_ = std::move(other.out_);
63-
target_ = std::move(other.target_);
64-
return *this;
65-
}
66-
67-
explicit operator bool() const { return bool{out_}; }
68-
69-
void close() {
70-
// TODO: The last process wins. Should we do better than that?
71-
if (out_.is_open()) {
72-
out_.close();
73-
auto tempFile = getTempFile();
74-
auto targetFile = getTargetFile();
75-
if (std::error_code ec = llvm::sys::fs::rename(tempFile, targetFile)) {
76-
std::cerr << "Cannot rename temp trap file '" << tempFile << "' -> '" << targetFile
77-
<< "': " << ec.message() << "\n";
78-
}
79-
}
80-
}
16+
explicit TrapOutput(std::ostream& out) : out_{out} {}
8117

8218
template <typename Tag>
8319
void assignStar(TrapLabel<Tag> label) {
@@ -104,12 +40,6 @@ class TrapOutput {
10440
}
10541

10642
private:
107-
std::string getTargetFile() { return target_ + ".trap"; }
108-
std::string getTempFile() {
109-
// TODO: find a more robust approach to avoid collisions?
110-
return target_ + '.' + std::to_string(getpid()) + ".trap";
111-
}
112-
11343
template <typename... Args>
11444
void print(const Args&... args) {
11545
(out_ << ... << args) << '\n';

0 commit comments

Comments
 (0)