blob: 5efa6aeaf760a3f2d7689186cceb79f1395e64fa [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"
Richard Smith9565c75b2017-06-19 23:09:36 +000012#include "clang/Basic/CharInfo.h"
NAKAMURA Takumi7f633df2017-07-18 08:55:03 +000013#include "clang/Config/config.h"
Daniel Dunbarc1b17292010-06-15 17:48:49 +000014#include "clang/Frontend/CompilerInstance.h"
Chandler Carruth3a022472012-12-04 09:13:33 +000015#include "clang/Frontend/FrontendActions.h"
Daniel Dunbarc1b17292010-06-15 17:48:49 +000016#include "clang/Frontend/FrontendDiagnostic.h"
17#include "clang/Frontend/Utils.h"
Chandler Carruth3a022472012-12-04 09:13:33 +000018#include "clang/Lex/Preprocessor.h"
Mehdi Amini9670f842016-07-18 19:02:11 +000019#include "clang/Lex/PreprocessorOptions.h"
Ted Kremenekcdf81492012-09-01 05:09:24 +000020#include "clang/Rewrite/Frontend/ASTConsumers.h"
21#include "clang/Rewrite/Frontend/FixItRewriter.h"
22#include "clang/Rewrite/Frontend/Rewriters.h"
Richard Smith86a3ef52017-06-09 21:24:02 +000023#include "clang/Serialization/ASTReader.h"
24#include "clang/Serialization/Module.h"
25#include "clang/Serialization/ModuleManager.h"
26#include "llvm/ADT/DenseSet.h"
27#include "llvm/Support/CrashRecoveryContext.h"
Argyrios Kyrtzidis24e9aff2012-01-26 02:40:48 +000028#include "llvm/Support/FileSystem.h"
Chandler Carruth3a022472012-12-04 09:13:33 +000029#include "llvm/Support/Path.h"
30#include "llvm/Support/raw_ostream.h"
Ahmed Charlesdfca6f92014-03-09 11:36:40 +000031#include <memory>
Benjamin Kramercfeacf52016-05-27 14:27:13 +000032#include <utility>
NAKAMURA Takumi69ee7d52012-01-26 03:47:18 +000033
Daniel Dunbarc1b17292010-06-15 17:48:49 +000034using namespace clang;
35
36//===----------------------------------------------------------------------===//
37// AST Consumer Actions
38//===----------------------------------------------------------------------===//
39
David Blaikie6beb6aa2014-08-10 19:56:51 +000040std::unique_ptr<ASTConsumer>
41HTMLPrintAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
Peter Collingbourne03f89072016-07-15 00:55:40 +000042 if (std::unique_ptr<raw_ostream> OS =
43 CI.createDefaultOutputFile(false, InFile))
44 return CreateHTMLPrinter(std::move(OS), CI.getPreprocessor());
Craig Topper8ae12032014-05-07 06:21:57 +000045 return nullptr;
Daniel Dunbarc1b17292010-06-15 17:48:49 +000046}
47
48FixItAction::FixItAction() {}
Angel Garcia Gomez637d1e62015-10-20 13:23:58 +000049FixItAction::~FixItAction() {}
Daniel Dunbarc1b17292010-06-15 17:48:49 +000050
David Blaikie6beb6aa2014-08-10 19:56:51 +000051std::unique_ptr<ASTConsumer>
52FixItAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
53 return llvm::make_unique<ASTConsumer>();
Daniel Dunbarc1b17292010-06-15 17:48:49 +000054}
55
Benjamin Kramerfb5e5842010-10-22 16:48:22 +000056namespace {
Nick Lewycky53f10422010-08-15 16:47:39 +000057class FixItRewriteInPlace : public FixItOptions {
58public:
Reid Kleckner3df5dd42015-06-17 17:47:30 +000059 FixItRewriteInPlace() { InPlace = true; }
60
Craig Topperfb6b25b2014-03-15 04:29:04 +000061 std::string RewriteFilename(const std::string &Filename, int &fd) override {
Reid Kleckner3df5dd42015-06-17 17:47:30 +000062 llvm_unreachable("don't call RewriteFilename for inplace rewrites");
Argyrios Kyrtzidis623e8772012-01-26 04:19:04 +000063 }
Nick Lewycky53f10422010-08-15 16:47:39 +000064};
65
Nick Lewycky078a5e22010-08-13 17:31:00 +000066class FixItActionSuffixInserter : public FixItOptions {
Daniel Dunbarc1b17292010-06-15 17:48:49 +000067 std::string NewSuffix;
68
69public:
Nick Lewycky078a5e22010-08-13 17:31:00 +000070 FixItActionSuffixInserter(std::string NewSuffix, bool FixWhatYouCan)
Benjamin Kramercfeacf52016-05-27 14:27:13 +000071 : NewSuffix(std::move(NewSuffix)) {
72 this->FixWhatYouCan = FixWhatYouCan;
Nick Lewycky078a5e22010-08-13 17:31:00 +000073 }
Daniel Dunbarc1b17292010-06-15 17:48:49 +000074
Craig Topperfb6b25b2014-03-15 04:29:04 +000075 std::string RewriteFilename(const std::string &Filename, int &fd) override {
Argyrios Kyrtzidis623e8772012-01-26 04:19:04 +000076 fd = -1;
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +000077 SmallString<128> Path(Filename);
Michael J. Spencere47230f2010-12-18 04:13:32 +000078 llvm::sys::path::replace_extension(Path,
79 NewSuffix + llvm::sys::path::extension(Path));
80 return Path.str();
Daniel Dunbarc1b17292010-06-15 17:48:49 +000081 }
82};
Argyrios Kyrtzidis24e9aff2012-01-26 02:40:48 +000083
84class FixItRewriteToTemp : public FixItOptions {
85public:
Craig Topperfb6b25b2014-03-15 04:29:04 +000086 std::string RewriteFilename(const std::string &Filename, int &fd) override {
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +000087 SmallString<128> Path;
Rafael Espindolaa36e78e2013-07-05 20:00:06 +000088 llvm::sys::fs::createTemporaryFile(llvm::sys::path::filename(Filename),
Argyrios Kyrtzidis203e9232015-09-09 16:48:47 +000089 llvm::sys::path::extension(Filename).drop_front(), fd,
Rafael Espindolaa36e78e2013-07-05 20:00:06 +000090 Path);
91 return Path.str();
Argyrios Kyrtzidis24e9aff2012-01-26 02:40:48 +000092 }
93};
Benjamin Kramerfb5e5842010-10-22 16:48:22 +000094} // end anonymous namespace
Daniel Dunbarc1b17292010-06-15 17:48:49 +000095
Richard Smithd9259c22017-06-09 01:36:10 +000096bool FixItAction::BeginSourceFileAction(CompilerInstance &CI) {
Daniel Dunbarc1b17292010-06-15 17:48:49 +000097 const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts();
98 if (!FEOpts.FixItSuffix.empty()) {
Nick Lewycky078a5e22010-08-13 17:31:00 +000099 FixItOpts.reset(new FixItActionSuffixInserter(FEOpts.FixItSuffix,
100 FEOpts.FixWhatYouCan));
Daniel Dunbarc1b17292010-06-15 17:48:49 +0000101 } else {
Nick Lewycky53f10422010-08-15 16:47:39 +0000102 FixItOpts.reset(new FixItRewriteInPlace);
103 FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan;
Daniel Dunbarc1b17292010-06-15 17:48:49 +0000104 }
105 Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(),
Nick Lewycky078a5e22010-08-13 17:31:00 +0000106 CI.getLangOpts(), FixItOpts.get()));
Daniel Dunbarc1b17292010-06-15 17:48:49 +0000107 return true;
108}
109
110void FixItAction::EndSourceFileAction() {
111 // Otherwise rewrite all files.
112 Rewriter->WriteFixedFiles();
113}
114
Argyrios Kyrtzidis24e9aff2012-01-26 02:40:48 +0000115bool FixItRecompile::BeginInvocation(CompilerInstance &CI) {
116
117 std::vector<std::pair<std::string, std::string> > RewrittenFiles;
118 bool err = false;
119 {
120 const FrontendOptions &FEOpts = CI.getFrontendOpts();
Ahmed Charlesb8984322014-03-07 20:03:18 +0000121 std::unique_ptr<FrontendAction> FixAction(new SyntaxOnlyAction());
Argyrios Kyrtzidisaf0bdfc2012-01-27 01:00:47 +0000122 if (FixAction->BeginSourceFile(CI, FEOpts.Inputs[0])) {
Ahmed Charlesb8984322014-03-07 20:03:18 +0000123 std::unique_ptr<FixItOptions> FixItOpts;
Argyrios Kyrtzidisaf0bdfc2012-01-27 01:00:47 +0000124 if (FEOpts.FixToTemporaries)
125 FixItOpts.reset(new FixItRewriteToTemp());
126 else
127 FixItOpts.reset(new FixItRewriteInPlace());
128 FixItOpts->Silent = true;
129 FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan;
130 FixItOpts->FixOnlyWarnings = FEOpts.FixOnlyWarnings;
131 FixItRewriter Rewriter(CI.getDiagnostics(), CI.getSourceManager(),
132 CI.getLangOpts(), FixItOpts.get());
133 FixAction->Execute();
Argyrios Kyrtzidis24e9aff2012-01-26 02:40:48 +0000134
Argyrios Kyrtzidisaf0bdfc2012-01-27 01:00:47 +0000135 err = Rewriter.WriteFixedFiles(&RewrittenFiles);
136
137 FixAction->EndSourceFile();
Craig Topper8ae12032014-05-07 06:21:57 +0000138 CI.setSourceManager(nullptr);
139 CI.setFileManager(nullptr);
Argyrios Kyrtzidisaf0bdfc2012-01-27 01:00:47 +0000140 } else {
141 err = true;
142 }
Argyrios Kyrtzidis24e9aff2012-01-26 02:40:48 +0000143 }
144 if (err)
145 return false;
146 CI.getDiagnosticClient().clear();
Argyrios Kyrtzidis0b5ec2d2012-01-27 06:15:37 +0000147 CI.getDiagnostics().Reset();
Argyrios Kyrtzidis24e9aff2012-01-26 02:40:48 +0000148
149 PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
150 PPOpts.RemappedFiles.insert(PPOpts.RemappedFiles.end(),
151 RewrittenFiles.begin(), RewrittenFiles.end());
152 PPOpts.RemappedFilesKeepOriginalName = false;
153
154 return true;
155}
156
Alp Toker0621cb22014-07-16 16:48:33 +0000157#ifdef CLANG_ENABLE_OBJC_REWRITER
Daniel Dunbarc1b17292010-06-15 17:48:49 +0000158
David Blaikie6beb6aa2014-08-10 19:56:51 +0000159std::unique_ptr<ASTConsumer>
160RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
Peter Collingbourne03f89072016-07-15 00:55:40 +0000161 if (std::unique_ptr<raw_ostream> OS =
162 CI.createDefaultOutputFile(false, InFile, "cpp")) {
John McCall5fb5df92012-06-20 06:18:46 +0000163 if (CI.getLangOpts().ObjCRuntime.isNonFragile())
Benjamin Kramer8c305922016-02-02 11:06:51 +0000164 return CreateModernObjCRewriter(
Peter Collingbourne03f89072016-07-15 00:55:40 +0000165 InFile, std::move(OS), CI.getDiagnostics(), CI.getLangOpts(),
Benjamin Kramer8c305922016-02-02 11:06:51 +0000166 CI.getDiagnosticOpts().NoRewriteMacros,
167 (CI.getCodeGenOpts().getDebugInfo() != codegenoptions::NoDebugInfo));
Peter Collingbourne03f89072016-07-15 00:55:40 +0000168 return CreateObjCRewriter(InFile, std::move(OS), CI.getDiagnostics(),
169 CI.getLangOpts(),
Daniel Dunbarc1b17292010-06-15 17:48:49 +0000170 CI.getDiagnosticOpts().NoRewriteMacros);
Fariborz Jahanian11671902012-02-07 17:11:38 +0000171 }
Craig Topper8ae12032014-05-07 06:21:57 +0000172 return nullptr;
Daniel Dunbarc1b17292010-06-15 17:48:49 +0000173}
174
Alp Toker0621cb22014-07-16 16:48:33 +0000175#endif
176
177//===----------------------------------------------------------------------===//
178// Preprocessor Actions
179//===----------------------------------------------------------------------===//
180
Daniel Dunbarc1b17292010-06-15 17:48:49 +0000181void RewriteMacrosAction::ExecuteAction() {
182 CompilerInstance &CI = getCompilerInstance();
Peter Collingbourne03f89072016-07-15 00:55:40 +0000183 std::unique_ptr<raw_ostream> OS =
184 CI.createDefaultOutputFile(true, getCurrentFile());
Daniel Dunbarc1b17292010-06-15 17:48:49 +0000185 if (!OS) return;
186
Peter Collingbourne03f89072016-07-15 00:55:40 +0000187 RewriteMacrosInInput(CI.getPreprocessor(), OS.get());
Daniel Dunbarc1b17292010-06-15 17:48:49 +0000188}
189
190void RewriteTestAction::ExecuteAction() {
191 CompilerInstance &CI = getCompilerInstance();
Peter Collingbourne03f89072016-07-15 00:55:40 +0000192 std::unique_ptr<raw_ostream> OS =
193 CI.createDefaultOutputFile(false, getCurrentFile());
Daniel Dunbarc1b17292010-06-15 17:48:49 +0000194 if (!OS) return;
195
Peter Collingbourne03f89072016-07-15 00:55:40 +0000196 DoRewriteTest(CI.getPreprocessor(), OS.get());
Daniel Dunbarc1b17292010-06-15 17:48:49 +0000197}
David Blaikied5321242012-06-06 18:52:13 +0000198
Richard Smith86a3ef52017-06-09 21:24:02 +0000199class RewriteIncludesAction::RewriteImportsListener : public ASTReaderListener {
200 CompilerInstance &CI;
201 std::weak_ptr<raw_ostream> Out;
202
203 llvm::DenseSet<const FileEntry*> Rewritten;
204
205public:
206 RewriteImportsListener(CompilerInstance &CI, std::shared_ptr<raw_ostream> Out)
207 : CI(CI), Out(Out) {}
208
209 void visitModuleFile(StringRef Filename,
210 serialization::ModuleKind Kind) override {
211 auto *File = CI.getFileManager().getFile(Filename);
212 assert(File && "missing file for loaded module?");
213
214 // Only rewrite each module file once.
215 if (!Rewritten.insert(File).second)
216 return;
217
218 serialization::ModuleFile *MF =
219 CI.getModuleManager()->getModuleManager().lookup(File);
220 assert(File && "missing module file for loaded module?");
221
222 // Not interested in PCH / preambles.
223 if (!MF->isModule())
224 return;
225
226 auto OS = Out.lock();
227 assert(OS && "loaded module file after finishing rewrite action?");
228
Richard Smith9565c75b2017-06-19 23:09:36 +0000229 (*OS) << "#pragma clang module build ";
230 if (isValidIdentifier(MF->ModuleName))
231 (*OS) << MF->ModuleName;
232 else {
233 (*OS) << '"';
234 OS->write_escaped(MF->ModuleName);
235 (*OS) << '"';
236 }
237 (*OS) << '\n';
Richard Smith86a3ef52017-06-09 21:24:02 +0000238
239 // Rewrite the contents of the module in a separate compiler instance.
240 CompilerInstance Instance(CI.getPCHContainerOperations(),
241 &CI.getPreprocessor().getPCMCache());
242 Instance.setInvocation(
243 std::make_shared<CompilerInvocation>(CI.getInvocation()));
244 Instance.createDiagnostics(
245 new ForwardingDiagnosticConsumer(CI.getDiagnosticClient()),
246 /*ShouldOwnClient=*/true);
Richard Smith4f05b362017-06-20 01:31:53 +0000247 Instance.getFrontendOpts().DisableFree = false;
Richard Smith86a3ef52017-06-09 21:24:02 +0000248 Instance.getFrontendOpts().Inputs.clear();
249 Instance.getFrontendOpts().Inputs.emplace_back(
250 Filename, InputKind(InputKind::Unknown, InputKind::Precompiled));
Richard Smitha21c8e12017-06-26 19:39:25 +0000251 Instance.getFrontendOpts().ModuleFiles.clear();
252 Instance.getFrontendOpts().ModuleMapFiles.clear();
Richard Smith86a3ef52017-06-09 21:24:02 +0000253 // Don't recursively rewrite imports. We handle them all at the top level.
254 Instance.getPreprocessorOutputOpts().RewriteImports = false;
255
256 llvm::CrashRecoveryContext().RunSafelyOnThread([&]() {
257 RewriteIncludesAction Action;
258 Action.OutputStream = OS;
259 Instance.ExecuteAction(Action);
260 });
261
262 (*OS) << "#pragma clang module endbuild /*" << MF->ModuleName << "*/\n";
263 }
264};
265
266bool RewriteIncludesAction::BeginSourceFileAction(CompilerInstance &CI) {
267 if (!OutputStream) {
268 OutputStream = CI.createDefaultOutputFile(true, getCurrentFile());
269 if (!OutputStream)
270 return false;
271 }
272
273 auto &OS = *OutputStream;
David Blaikied5321242012-06-06 18:52:13 +0000274
Richard Smith8128f332017-05-05 22:18:51 +0000275 // If we're preprocessing a module map, start by dumping the contents of the
276 // module itself before switching to the input buffer.
277 auto &Input = getCurrentInput();
278 if (Input.getKind().getFormat() == InputKind::ModuleMap) {
Richard Smithc784e962017-06-01 20:10:35 +0000279 if (Input.isFile()) {
Richard Smith86a3ef52017-06-09 21:24:02 +0000280 OS << "# 1 \"";
281 OS.write_escaped(Input.getFile());
282 OS << "\"\n";
Richard Smithc784e962017-06-01 20:10:35 +0000283 }
Richard Smith86a3ef52017-06-09 21:24:02 +0000284 getCurrentModule()->print(OS);
285 OS << "#pragma clang module contents\n";
Richard Smith8128f332017-05-05 22:18:51 +0000286 }
287
Richard Smith86a3ef52017-06-09 21:24:02 +0000288 // If we're rewriting imports, set up a listener to track when we import
289 // module files.
290 if (CI.getPreprocessorOutputOpts().RewriteImports) {
291 CI.createModuleManager();
292 CI.getModuleManager()->addListener(
293 llvm::make_unique<RewriteImportsListener>(CI, OutputStream));
294 }
295
296 return true;
297}
298
299void RewriteIncludesAction::ExecuteAction() {
300 CompilerInstance &CI = getCompilerInstance();
301
302 // If we're rewriting imports, emit the module build output first rather
303 // than switching back and forth (potentially in the middle of a line).
304 if (CI.getPreprocessorOutputOpts().RewriteImports) {
305 std::string Buffer;
306 llvm::raw_string_ostream OS(Buffer);
307
308 RewriteIncludesInInput(CI.getPreprocessor(), &OS,
309 CI.getPreprocessorOutputOpts());
310
311 (*OutputStream) << OS.str();
312 } else {
313 RewriteIncludesInInput(CI.getPreprocessor(), OutputStream.get(),
314 CI.getPreprocessorOutputOpts());
315 }
316
317 OutputStream.reset();
David Blaikied5321242012-06-06 18:52:13 +0000318}