1
1
#pragma once
2
2
3
3
#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"
9
4
#include " swift/extractor/trap/TrapLabel.h"
10
5
11
6
namespace codeql {
12
7
13
8
// Sink for trap emissions and label assignments. This abstracts away `ofstream` operations
14
9
// like `ofstream`, an explicit bool operator is provided, that return false if something
15
10
// went wrong
11
+ // TODO better error handling
16
12
class TrapOutput {
17
- std::ofstream out_{};
18
- std::string target_;
13
+ std::ostream& out_;
19
14
20
15
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} {}
81
17
82
18
template <typename Tag>
83
19
void assignStar (TrapLabel<Tag> label) {
@@ -104,12 +40,6 @@ class TrapOutput {
104
40
}
105
41
106
42
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
-
113
43
template <typename ... Args>
114
44
void print (const Args&... args) {
115
45
(out_ << ... << args) << ' \n ' ;
0 commit comments