1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
#include "Core/Transform.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
namespace {
using namespace tooling;
using namespace ast_matchers;
/// \brief Custom FrontendActionFactory to produce FrontendActions that handle
/// overriding source file contents before parsing.
///
/// The nested class FactoryAdaptor overrides BeginSourceFileAction to override
/// source file contents before parsing happens. Both Begin and
/// EndSourceFileAction call corresponding callbacks provided by
/// SourceFileCallbacks.
class ActionFactory : public clang::tooling::FrontendActionFactory {
public:
ActionFactory(MatchFinder &Finder, const FileContentsByPath &Overrides,
SourceFileCallbacks &Callbacks)
: Finder(Finder), Overrides(Overrides), Callbacks(Callbacks) {}
virtual FrontendAction *create() LLVM_OVERRIDE {
return new FactoryAdaptor(Finder, Overrides, Callbacks);
}
private:
class FactoryAdaptor : public ASTFrontendAction {
public:
FactoryAdaptor(MatchFinder &Finder, const FileContentsByPath &Overrides,
SourceFileCallbacks &Callbacks)
: Finder(Finder), Overrides(Overrides), Callbacks(Callbacks) {}
ASTConsumer *CreateASTConsumer(CompilerInstance &, StringRef) {
return Finder.newASTConsumer();
}
virtual bool BeginSourceFileAction(CompilerInstance &CI,
StringRef Filename) LLVM_OVERRIDE {
if (!ASTFrontendAction::BeginSourceFileAction(CI, Filename))
return false;
FileContentsByPath::const_iterator I = Overrides.find(Filename.str());
if (I != Overrides.end())
// If an override exists, use it.
CI.getSourceManager()
.overrideFileContents(CI.getFileManager().getFile(I->first),
llvm::MemoryBuffer::getMemBuffer(I->second));
return Callbacks.handleBeginSource(CI, Filename);
}
virtual void EndSourceFileAction() LLVM_OVERRIDE {
Callbacks.handleEndSource();
return ASTFrontendAction::EndSourceFileAction();
}
private:
MatchFinder &Finder;
const FileContentsByPath &Overrides;
SourceFileCallbacks &Callbacks;
};
MatchFinder &Finder;
const FileContentsByPath &Overrides;
SourceFileCallbacks &Callbacks;
};
} // namespace
RewriterContainer::RewriterContainer(clang::FileManager &Files,
const FileContentsByPath &InputStates)
: DiagOpts(new clang::DiagnosticOptions()),
DiagnosticPrinter(llvm::errs(), DiagOpts.getPtr()),
Diagnostics(llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs>(
new clang::DiagnosticIDs()),
DiagOpts.getPtr(), &DiagnosticPrinter, false),
Sources(Diagnostics, Files), Rewrite(Sources, DefaultLangOptions) {
// Overwrite source manager's file contents with data from InputStates
for (FileContentsByPath::const_iterator I = InputStates.begin(),
E = InputStates.end();
I != E; ++I) {
Sources.overrideFileContents(Files.getFile(I->first),
llvm::MemoryBuffer::getMemBuffer(I->second));
}
}
void collectResults(clang::Rewriter &Rewrite,
const FileContentsByPath &InputStates,
FileContentsByPath &Results) {
// Copy the contents of InputStates to be modified.
Results = InputStates;
for (Rewriter::buffer_iterator I = Rewrite.buffer_begin(),
E = Rewrite.buffer_end();
I != E; ++I) {
const FileEntry *Entry = Rewrite.getSourceMgr().getFileEntryForID(I->first);
assert(Entry != 0 && "Expected a FileEntry");
assert(Entry->getName() != 0 &&
"Unexpected NULL return from FileEntry::getName()");
std::string ResultBuf;
// Get a copy of the rewritten buffer from the Rewriter.
llvm::raw_string_ostream StringStream(ResultBuf);
I->second.write(StringStream);
// Cause results to be written to ResultBuf.
StringStream.str();
// FIXME: Use move semantics to avoid copies of the buffer contents if
// benchmarking shows the copies are expensive, especially for large source
// files.
Results[Entry->getName()] = ResultBuf;
}
}
bool Transform::handleBeginSource(CompilerInstance &CI, StringRef Filename) {
if (!Options().EnableTiming)
return true;
Timings.push_back(std::make_pair(Filename.str(), llvm::TimeRecord()));
Timings.back().second -= llvm::TimeRecord::getCurrentTime(true);
return true;
}
void Transform::handleEndSource() {
if (!Options().EnableTiming)
return;
Timings.back().second += llvm::TimeRecord::getCurrentTime(false);
}
void Transform::addTiming(llvm::StringRef Label, llvm::TimeRecord Duration) {
Timings.push_back(std::make_pair(Label.str(), Duration));
}
FrontendActionFactory *
Transform::createActionFactory(MatchFinder &Finder,
const FileContentsByPath &InputStates) {
return new ActionFactory(Finder, InputStates, *this);
}
|