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
116namespace 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
1612class 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