blob: 45feffbcb5b543b4f374a6d63d7a60c71b9c13ec [file] [log] [blame]
Daniel Dunbarc1b17292010-06-15 17:48:49 +00001//===--- FrontendActions.cpp ----------------------------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Ted Kremenekcdf81492012-09-01 05:09:24 +000010#include "clang/Rewrite/Frontend/FrontendActions.h"
Daniel Dunbarc1b17292010-06-15 17:48:49 +000011#include "clang/AST/ASTConsumer.h"
Daniel Dunbarc1b17292010-06-15 17:48:49 +000012#include "clang/Frontend/CompilerInstance.h"
Chandler Carruth3a022472012-12-04 09:13:33 +000013#include "clang/Frontend/FrontendActions.h"
Daniel Dunbarc1b17292010-06-15 17:48:49 +000014#include "clang/Frontend/FrontendDiagnostic.h"
15#include "clang/Frontend/Utils.h"
Chandler Carruth3a022472012-12-04 09:13:33 +000016#include "clang/Lex/Preprocessor.h"
Mehdi Amini9670f842016-07-18 19:02:11 +000017#include "clang/Lex/PreprocessorOptions.h"
Ted Kremenekcdf81492012-09-01 05:09:24 +000018#include "clang/Rewrite/Frontend/ASTConsumers.h"
19#include "clang/Rewrite/Frontend/FixItRewriter.h"
20#include "clang/Rewrite/Frontend/Rewriters.h"
Richard Smith86a3ef52017-06-09 21:24:02 +000021#include "clang/Serialization/ASTReader.h"
22#include "clang/Serialization/Module.h"
23#include "clang/Serialization/ModuleManager.h"
24#include "llvm/ADT/DenseSet.h"
25#include "llvm/Support/CrashRecoveryContext.h"
Argyrios Kyrtzidis24e9aff2012-01-26 02:40:48 +000026#include "llvm/Support/FileSystem.h"
Chandler Carruth3a022472012-12-04 09:13:33 +000027#include "llvm/Support/Path.h"
28#include "llvm/Support/raw_ostream.h"
Ahmed Charlesdfca6f92014-03-09 11:36:40 +000029#include <memory>
Benjamin Kramercfeacf52016-05-27 14:27:13 +000030#include <utility>
NAKAMURA Takumi69ee7d52012-01-26 03:47:18 +000031
Daniel Dunbarc1b17292010-06-15 17:48:49 +000032using namespace clang;
33
34//===----------------------------------------------------------------------===//
35// AST Consumer Actions
36//===----------------------------------------------------------------------===//
37
David Blaikie6beb6aa2014-08-10 19:56:51 +000038std::unique_ptr<ASTConsumer>
39HTMLPrintAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
Peter Collingbourne03f89072016-07-15 00:55:40 +000040 if (std::unique_ptr<raw_ostream> OS =
41 CI.createDefaultOutputFile(false, InFile))
42 return CreateHTMLPrinter(std::move(OS), CI.getPreprocessor());
Craig Topper8ae12032014-05-07 06:21:57 +000043 return nullptr;
Daniel Dunbarc1b17292010-06-15 17:48:49 +000044}
45
46FixItAction::FixItAction() {}
Angel Garcia Gomez637d1e62015-10-20 13:23:58 +000047FixItAction::~FixItAction() {}
Daniel Dunbarc1b17292010-06-15 17:48:49 +000048
David Blaikie6beb6aa2014-08-10 19:56:51 +000049std::unique_ptr<ASTConsumer>
50FixItAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
51 return llvm::make_unique<ASTConsumer>();
Daniel Dunbarc1b17292010-06-15 17:48:49 +000052}
53
Benjamin Kramerfb5e5842010-10-22 16:48:22 +000054namespace {
Nick Lewycky53f10422010-08-15 16:47:39 +000055class FixItRewriteInPlace : public FixItOptions {
56public:
Reid Kleckner3df5dd42015-06-17 17:47:30 +000057 FixItRewriteInPlace() { InPlace = true; }
58
Craig Topperfb6b25b2014-03-15 04:29:04 +000059 std::string RewriteFilename(const std::string &Filename, int &fd) override {
Reid Kleckner3df5dd42015-06-17 17:47:30 +000060 llvm_unreachable("don't call RewriteFilename for inplace rewrites");
Argyrios Kyrtzidis623e8772012-01-26 04:19:04 +000061 }
Nick Lewycky53f10422010-08-15 16:47:39 +000062};
63
Nick Lewycky078a5e22010-08-13 17:31:00 +000064class FixItActionSuffixInserter : public FixItOptions {
Daniel Dunbarc1b17292010-06-15 17:48:49 +000065 std::string NewSuffix;
66
67public:
Nick Lewycky078a5e22010-08-13 17:31:00 +000068 FixItActionSuffixInserter(std::string NewSuffix, bool FixWhatYouCan)
Benjamin Kramercfeacf52016-05-27 14:27:13 +000069 : NewSuffix(std::move(NewSuffix)) {
70 this->FixWhatYouCan = FixWhatYouCan;
Nick Lewycky078a5e22010-08-13 17:31:00 +000071 }
Daniel Dunbarc1b17292010-06-15 17:48:49 +000072
Craig Topperfb6b25b2014-03-15 04:29:04 +000073 std::string RewriteFilename(const std::string &Filename, int &fd) override {
Argyrios Kyrtzidis623e8772012-01-26 04:19:04 +000074 fd = -1;
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +000075 SmallString<128> Path(Filename);
Michael J. Spencere47230f2010-12-18 04:13:32 +000076 llvm::sys::path::replace_extension(Path,
77 NewSuffix + llvm::sys::path::extension(Path));
78 return Path.str();
Daniel Dunbarc1b17292010-06-15 17:48:49 +000079 }
80};
Argyrios Kyrtzidis24e9aff2012-01-26 02:40:48 +000081
82class FixItRewriteToTemp : public FixItOptions {
83public:
Craig Topperfb6b25b2014-03-15 04:29:04 +000084 std::string RewriteFilename(const std::string &Filename, int &fd) override {
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +000085 SmallString<128> Path;
Rafael Espindolaa36e78e2013-07-05 20:00:06 +000086 llvm::sys::fs::createTemporaryFile(llvm::sys::path::filename(Filename),
Argyrios Kyrtzidis203e9232015-09-09 16:48:47 +000087 llvm::sys::path::extension(Filename).drop_front(), fd,
Rafael Espindolaa36e78e2013-07-05 20:00:06 +000088 Path);
89 return Path.str();
Argyrios Kyrtzidis24e9aff2012-01-26 02:40:48 +000090 }
91};
Benjamin Kramerfb5e5842010-10-22 16:48:22 +000092} // end anonymous namespace
Daniel Dunbarc1b17292010-06-15 17:48:49 +000093
Richard Smithd9259c22017-06-09 01:36:10 +000094bool FixItAction::BeginSourceFileAction(CompilerInstance &CI) {
Daniel Dunbarc1b17292010-06-15 17:48:49 +000095 const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts();
96 if (!FEOpts.FixItSuffix.empty()) {
Nick Lewycky078a5e22010-08-13 17:31:00 +000097 FixItOpts.reset(new FixItActionSuffixInserter(FEOpts.FixItSuffix,
98 FEOpts.FixWhatYouCan));
Daniel Dunbarc1b17292010-06-15 17:48:49 +000099 } else {
Nick Lewycky53f10422010-08-15 16:47:39 +0000100 FixItOpts.reset(new FixItRewriteInPlace);
101 FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan;
Daniel Dunbarc1b17292010-06-15 17:48:49 +0000102 }
103 Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(),
Nick Lewycky078a5e22010-08-13 17:31:00 +0000104 CI.getLangOpts(), FixItOpts.get()));
Daniel Dunbarc1b17292010-06-15 17:48:49 +0000105 return true;
106}
107
108void FixItAction::EndSourceFileAction() {
109 // Otherwise rewrite all files.
110 Rewriter->WriteFixedFiles();
111}
112
Argyrios Kyrtzidis24e9aff2012-01-26 02:40:48 +0000113bool FixItRecompile::BeginInvocation(CompilerInstance &CI) {
114
115 std::vector<std::pair<std::string, std::string> > RewrittenFiles;
116 bool err = false;
117 {
118 const FrontendOptions &FEOpts = CI.getFrontendOpts();
Ahmed Charlesb8984322014-03-07 20:03:18 +0000119 std::unique_ptr<FrontendAction> FixAction(new SyntaxOnlyAction());
Argyrios Kyrtzidisaf0bdfc2012-01-27 01:00:47 +0000120 if (FixAction->BeginSourceFile(CI, FEOpts.Inputs[0])) {
Ahmed Charlesb8984322014-03-07 20:03:18 +0000121 std::unique_ptr<FixItOptions> FixItOpts;
Argyrios Kyrtzidisaf0bdfc2012-01-27 01:00:47 +0000122 if (FEOpts.FixToTemporaries)
123 FixItOpts.reset(new FixItRewriteToTemp());
124 else
125 FixItOpts.reset(new FixItRewriteInPlace());
126 FixItOpts->Silent = true;
127 FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan;
128 FixItOpts->FixOnlyWarnings = FEOpts.FixOnlyWarnings;
129 FixItRewriter Rewriter(CI.getDiagnostics(), CI.getSourceManager(),
130 CI.getLangOpts(), FixItOpts.get());
131 FixAction->Execute();
Argyrios Kyrtzidis24e9aff2012-01-26 02:40:48 +0000132
Argyrios Kyrtzidisaf0bdfc2012-01-27 01:00:47 +0000133 err = Rewriter.WriteFixedFiles(&RewrittenFiles);
134
135 FixAction->EndSourceFile();
Craig Topper8ae12032014-05-07 06:21:57 +0000136 CI.setSourceManager(nullptr);
137 CI.setFileManager(nullptr);
Argyrios Kyrtzidisaf0bdfc2012-01-27 01:00:47 +0000138 } else {
139 err = true;
140 }
Argyrios Kyrtzidis24e9aff2012-01-26 02:40:48 +0000141 }
142 if (err)
143 return false;
144 CI.getDiagnosticClient().clear();
Argyrios Kyrtzidis0b5ec2d2012-01-27 06:15:37 +0000145 CI.getDiagnostics().Reset();
Argyrios Kyrtzidis24e9aff2012-01-26 02:40:48 +0000146
147 PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
148 PPOpts.RemappedFiles.insert(PPOpts.RemappedFiles.end(),
149 RewrittenFiles.begin(), RewrittenFiles.end());
150 PPOpts.RemappedFilesKeepOriginalName = false;
151
152 return true;
153}
154
Alp Toker0621cb22014-07-16 16:48:33 +0000155#ifdef CLANG_ENABLE_OBJC_REWRITER
Daniel Dunbarc1b17292010-06-15 17:48:49 +0000156
David Blaikie6beb6aa2014-08-10 19:56:51 +0000157std::unique_ptr<ASTConsumer>
158RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
Peter Collingbourne03f89072016-07-15 00:55:40 +0000159 if (std::unique_ptr<raw_ostream> OS =
160 CI.createDefaultOutputFile(false, InFile, "cpp")) {
John McCall5fb5df92012-06-20 06:18:46 +0000161 if (CI.getLangOpts().ObjCRuntime.isNonFragile())
Benjamin Kramer8c305922016-02-02 11:06:51 +0000162 return CreateModernObjCRewriter(
Peter Collingbourne03f89072016-07-15 00:55:40 +0000163 InFile, std::move(OS), CI.getDiagnostics(), CI.getLangOpts(),
Benjamin Kramer8c305922016-02-02 11:06:51 +0000164 CI.getDiagnosticOpts().NoRewriteMacros,
165 (CI.getCodeGenOpts().getDebugInfo() != codegenoptions::NoDebugInfo));
Peter Collingbourne03f89072016-07-15 00:55:40 +0000166 return CreateObjCRewriter(InFile, std::move(OS), CI.getDiagnostics(),
167 CI.getLangOpts(),
Daniel Dunbarc1b17292010-06-15 17:48:49 +0000168 CI.getDiagnosticOpts().NoRewriteMacros);
Fariborz Jahanian11671902012-02-07 17:11:38 +0000169 }
Craig Topper8ae12032014-05-07 06:21:57 +0000170 return nullptr;
Daniel Dunbarc1b17292010-06-15 17:48:49 +0000171}
172
Alp Toker0621cb22014-07-16 16:48:33 +0000173#endif
174
175//===----------------------------------------------------------------------===//
176// Preprocessor Actions
177//===----------------------------------------------------------------------===//
178
Daniel Dunbarc1b17292010-06-15 17:48:49 +0000179void RewriteMacrosAction::ExecuteAction() {
180 CompilerInstance &CI = getCompilerInstance();
Peter Collingbourne03f89072016-07-15 00:55:40 +0000181 std::unique_ptr<raw_ostream> OS =
182 CI.createDefaultOutputFile(true, getCurrentFile());
Daniel Dunbarc1b17292010-06-15 17:48:49 +0000183 if (!OS) return;
184
Peter Collingbourne03f89072016-07-15 00:55:40 +0000185 RewriteMacrosInInput(CI.getPreprocessor(), OS.get());
Daniel Dunbarc1b17292010-06-15 17:48:49 +0000186}
187
188void RewriteTestAction::ExecuteAction() {
189 CompilerInstance &CI = getCompilerInstance();
Peter Collingbourne03f89072016-07-15 00:55:40 +0000190 std::unique_ptr<raw_ostream> OS =
191 CI.createDefaultOutputFile(false, getCurrentFile());
Daniel Dunbarc1b17292010-06-15 17:48:49 +0000192 if (!OS) return;
193
Peter Collingbourne03f89072016-07-15 00:55:40 +0000194 DoRewriteTest(CI.getPreprocessor(), OS.get());
Daniel Dunbarc1b17292010-06-15 17:48:49 +0000195}
David Blaikied5321242012-06-06 18:52:13 +0000196
Richard Smith86a3ef52017-06-09 21:24:02 +0000197class RewriteIncludesAction::RewriteImportsListener : public ASTReaderListener {
198 CompilerInstance &CI;
199 std::weak_ptr<raw_ostream> Out;
200
201 llvm::DenseSet<const FileEntry*> Rewritten;
202
203public:
204 RewriteImportsListener(CompilerInstance &CI, std::shared_ptr<raw_ostream> Out)
205 : CI(CI), Out(Out) {}
206
207 void visitModuleFile(StringRef Filename,
208 serialization::ModuleKind Kind) override {
209 auto *File = CI.getFileManager().getFile(Filename);
210 assert(File && "missing file for loaded module?");
211
212 // Only rewrite each module file once.
213 if (!Rewritten.insert(File).second)
214 return;
215
216 serialization::ModuleFile *MF =
217 CI.getModuleManager()->getModuleManager().lookup(File);
218 assert(File && "missing module file for loaded module?");
219
220 // Not interested in PCH / preambles.
221 if (!MF->isModule())
222 return;
223
224 auto OS = Out.lock();
225 assert(OS && "loaded module file after finishing rewrite action?");
226
227 (*OS) << "#pragma clang module build " << MF->ModuleName << "\n";
228
229 // Rewrite the contents of the module in a separate compiler instance.
230 CompilerInstance Instance(CI.getPCHContainerOperations(),
231 &CI.getPreprocessor().getPCMCache());
232 Instance.setInvocation(
233 std::make_shared<CompilerInvocation>(CI.getInvocation()));
234 Instance.createDiagnostics(
235 new ForwardingDiagnosticConsumer(CI.getDiagnosticClient()),
236 /*ShouldOwnClient=*/true);
237 Instance.getFrontendOpts().Inputs.clear();
238 Instance.getFrontendOpts().Inputs.emplace_back(
239 Filename, InputKind(InputKind::Unknown, InputKind::Precompiled));
240 // Don't recursively rewrite imports. We handle them all at the top level.
241 Instance.getPreprocessorOutputOpts().RewriteImports = false;
242
243 llvm::CrashRecoveryContext().RunSafelyOnThread([&]() {
244 RewriteIncludesAction Action;
245 Action.OutputStream = OS;
246 Instance.ExecuteAction(Action);
247 });
248
249 (*OS) << "#pragma clang module endbuild /*" << MF->ModuleName << "*/\n";
250 }
251};
252
253bool RewriteIncludesAction::BeginSourceFileAction(CompilerInstance &CI) {
254 if (!OutputStream) {
255 OutputStream = CI.createDefaultOutputFile(true, getCurrentFile());
256 if (!OutputStream)
257 return false;
258 }
259
260 auto &OS = *OutputStream;
David Blaikied5321242012-06-06 18:52:13 +0000261
Richard Smith8128f332017-05-05 22:18:51 +0000262 // If we're preprocessing a module map, start by dumping the contents of the
263 // module itself before switching to the input buffer.
264 auto &Input = getCurrentInput();
265 if (Input.getKind().getFormat() == InputKind::ModuleMap) {
Richard Smithc784e962017-06-01 20:10:35 +0000266 if (Input.isFile()) {
Richard Smith86a3ef52017-06-09 21:24:02 +0000267 OS << "# 1 \"";
268 OS.write_escaped(Input.getFile());
269 OS << "\"\n";
Richard Smithc784e962017-06-01 20:10:35 +0000270 }
Richard Smith86a3ef52017-06-09 21:24:02 +0000271 getCurrentModule()->print(OS);
272 OS << "#pragma clang module contents\n";
Richard Smith8128f332017-05-05 22:18:51 +0000273 }
274
Richard Smith86a3ef52017-06-09 21:24:02 +0000275 // If we're rewriting imports, set up a listener to track when we import
276 // module files.
277 if (CI.getPreprocessorOutputOpts().RewriteImports) {
278 CI.createModuleManager();
279 CI.getModuleManager()->addListener(
280 llvm::make_unique<RewriteImportsListener>(CI, OutputStream));
281 }
282
283 return true;
284}
285
286void RewriteIncludesAction::ExecuteAction() {
287 CompilerInstance &CI = getCompilerInstance();
288
289 // If we're rewriting imports, emit the module build output first rather
290 // than switching back and forth (potentially in the middle of a line).
291 if (CI.getPreprocessorOutputOpts().RewriteImports) {
292 std::string Buffer;
293 llvm::raw_string_ostream OS(Buffer);
294
295 RewriteIncludesInInput(CI.getPreprocessor(), &OS,
296 CI.getPreprocessorOutputOpts());
297
298 (*OutputStream) << OS.str();
299 } else {
300 RewriteIncludesInInput(CI.getPreprocessor(), OutputStream.get(),
301 CI.getPreprocessorOutputOpts());
302 }
303
304 OutputStream.reset();
David Blaikied5321242012-06-06 18:52:13 +0000305}