blob: f64fbdafd597f77601ea3022e8c450ff49072c94 [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"
Daniel Dunbarc1b17292010-06-15 17:48:49 +000013#include "clang/Frontend/CompilerInstance.h"
Chandler Carruth3a022472012-12-04 09:13:33 +000014#include "clang/Frontend/FrontendActions.h"
Daniel Dunbarc1b17292010-06-15 17:48:49 +000015#include "clang/Frontend/FrontendDiagnostic.h"
16#include "clang/Frontend/Utils.h"
Chandler Carruth3a022472012-12-04 09:13:33 +000017#include "clang/Lex/Preprocessor.h"
Mehdi Amini9670f842016-07-18 19:02:11 +000018#include "clang/Lex/PreprocessorOptions.h"
Ted Kremenekcdf81492012-09-01 05:09:24 +000019#include "clang/Rewrite/Frontend/ASTConsumers.h"
20#include "clang/Rewrite/Frontend/FixItRewriter.h"
21#include "clang/Rewrite/Frontend/Rewriters.h"
Richard Smith86a3ef52017-06-09 21:24:02 +000022#include "clang/Serialization/ASTReader.h"
23#include "clang/Serialization/Module.h"
24#include "clang/Serialization/ModuleManager.h"
25#include "llvm/ADT/DenseSet.h"
26#include "llvm/Support/CrashRecoveryContext.h"
Argyrios Kyrtzidis24e9aff2012-01-26 02:40:48 +000027#include "llvm/Support/FileSystem.h"
Chandler Carruth3a022472012-12-04 09:13:33 +000028#include "llvm/Support/Path.h"
29#include "llvm/Support/raw_ostream.h"
Ahmed Charlesdfca6f92014-03-09 11:36:40 +000030#include <memory>
Benjamin Kramercfeacf52016-05-27 14:27:13 +000031#include <utility>
NAKAMURA Takumi69ee7d52012-01-26 03:47:18 +000032
Daniel Dunbarc1b17292010-06-15 17:48:49 +000033using namespace clang;
34
35//===----------------------------------------------------------------------===//
36// AST Consumer Actions
37//===----------------------------------------------------------------------===//
38
David Blaikie6beb6aa2014-08-10 19:56:51 +000039std::unique_ptr<ASTConsumer>
40HTMLPrintAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
Peter Collingbourne03f89072016-07-15 00:55:40 +000041 if (std::unique_ptr<raw_ostream> OS =
42 CI.createDefaultOutputFile(false, InFile))
43 return CreateHTMLPrinter(std::move(OS), CI.getPreprocessor());
Craig Topper8ae12032014-05-07 06:21:57 +000044 return nullptr;
Daniel Dunbarc1b17292010-06-15 17:48:49 +000045}
46
47FixItAction::FixItAction() {}
Angel Garcia Gomez637d1e62015-10-20 13:23:58 +000048FixItAction::~FixItAction() {}
Daniel Dunbarc1b17292010-06-15 17:48:49 +000049
David Blaikie6beb6aa2014-08-10 19:56:51 +000050std::unique_ptr<ASTConsumer>
51FixItAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
52 return llvm::make_unique<ASTConsumer>();
Daniel Dunbarc1b17292010-06-15 17:48:49 +000053}
54
Benjamin Kramerfb5e5842010-10-22 16:48:22 +000055namespace {
Nick Lewycky53f10422010-08-15 16:47:39 +000056class FixItRewriteInPlace : public FixItOptions {
57public:
Reid Kleckner3df5dd42015-06-17 17:47:30 +000058 FixItRewriteInPlace() { InPlace = true; }
59
Craig Topperfb6b25b2014-03-15 04:29:04 +000060 std::string RewriteFilename(const std::string &Filename, int &fd) override {
Reid Kleckner3df5dd42015-06-17 17:47:30 +000061 llvm_unreachable("don't call RewriteFilename for inplace rewrites");
Argyrios Kyrtzidis623e8772012-01-26 04:19:04 +000062 }
Nick Lewycky53f10422010-08-15 16:47:39 +000063};
64
Nick Lewycky078a5e22010-08-13 17:31:00 +000065class FixItActionSuffixInserter : public FixItOptions {
Daniel Dunbarc1b17292010-06-15 17:48:49 +000066 std::string NewSuffix;
67
68public:
Nick Lewycky078a5e22010-08-13 17:31:00 +000069 FixItActionSuffixInserter(std::string NewSuffix, bool FixWhatYouCan)
Benjamin Kramercfeacf52016-05-27 14:27:13 +000070 : NewSuffix(std::move(NewSuffix)) {
71 this->FixWhatYouCan = FixWhatYouCan;
Nick Lewycky078a5e22010-08-13 17:31:00 +000072 }
Daniel Dunbarc1b17292010-06-15 17:48:49 +000073
Craig Topperfb6b25b2014-03-15 04:29:04 +000074 std::string RewriteFilename(const std::string &Filename, int &fd) override {
Argyrios Kyrtzidis623e8772012-01-26 04:19:04 +000075 fd = -1;
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +000076 SmallString<128> Path(Filename);
Michael J. Spencere47230f2010-12-18 04:13:32 +000077 llvm::sys::path::replace_extension(Path,
78 NewSuffix + llvm::sys::path::extension(Path));
79 return Path.str();
Daniel Dunbarc1b17292010-06-15 17:48:49 +000080 }
81};
Argyrios Kyrtzidis24e9aff2012-01-26 02:40:48 +000082
83class FixItRewriteToTemp : public FixItOptions {
84public:
Craig Topperfb6b25b2014-03-15 04:29:04 +000085 std::string RewriteFilename(const std::string &Filename, int &fd) override {
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +000086 SmallString<128> Path;
Rafael Espindolaa36e78e2013-07-05 20:00:06 +000087 llvm::sys::fs::createTemporaryFile(llvm::sys::path::filename(Filename),
Argyrios Kyrtzidis203e9232015-09-09 16:48:47 +000088 llvm::sys::path::extension(Filename).drop_front(), fd,
Rafael Espindolaa36e78e2013-07-05 20:00:06 +000089 Path);
90 return Path.str();
Argyrios Kyrtzidis24e9aff2012-01-26 02:40:48 +000091 }
92};
Benjamin Kramerfb5e5842010-10-22 16:48:22 +000093} // end anonymous namespace
Daniel Dunbarc1b17292010-06-15 17:48:49 +000094
Richard Smithd9259c22017-06-09 01:36:10 +000095bool FixItAction::BeginSourceFileAction(CompilerInstance &CI) {
Daniel Dunbarc1b17292010-06-15 17:48:49 +000096 const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts();
97 if (!FEOpts.FixItSuffix.empty()) {
Nick Lewycky078a5e22010-08-13 17:31:00 +000098 FixItOpts.reset(new FixItActionSuffixInserter(FEOpts.FixItSuffix,
99 FEOpts.FixWhatYouCan));
Daniel Dunbarc1b17292010-06-15 17:48:49 +0000100 } else {
Nick Lewycky53f10422010-08-15 16:47:39 +0000101 FixItOpts.reset(new FixItRewriteInPlace);
102 FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan;
Daniel Dunbarc1b17292010-06-15 17:48:49 +0000103 }
104 Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(),
Nick Lewycky078a5e22010-08-13 17:31:00 +0000105 CI.getLangOpts(), FixItOpts.get()));
Daniel Dunbarc1b17292010-06-15 17:48:49 +0000106 return true;
107}
108
109void FixItAction::EndSourceFileAction() {
110 // Otherwise rewrite all files.
111 Rewriter->WriteFixedFiles();
112}
113
Argyrios Kyrtzidis24e9aff2012-01-26 02:40:48 +0000114bool FixItRecompile::BeginInvocation(CompilerInstance &CI) {
115
116 std::vector<std::pair<std::string, std::string> > RewrittenFiles;
117 bool err = false;
118 {
119 const FrontendOptions &FEOpts = CI.getFrontendOpts();
Ahmed Charlesb8984322014-03-07 20:03:18 +0000120 std::unique_ptr<FrontendAction> FixAction(new SyntaxOnlyAction());
Argyrios Kyrtzidisaf0bdfc2012-01-27 01:00:47 +0000121 if (FixAction->BeginSourceFile(CI, FEOpts.Inputs[0])) {
Ahmed Charlesb8984322014-03-07 20:03:18 +0000122 std::unique_ptr<FixItOptions> FixItOpts;
Argyrios Kyrtzidisaf0bdfc2012-01-27 01:00:47 +0000123 if (FEOpts.FixToTemporaries)
124 FixItOpts.reset(new FixItRewriteToTemp());
125 else
126 FixItOpts.reset(new FixItRewriteInPlace());
127 FixItOpts->Silent = true;
128 FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan;
129 FixItOpts->FixOnlyWarnings = FEOpts.FixOnlyWarnings;
130 FixItRewriter Rewriter(CI.getDiagnostics(), CI.getSourceManager(),
131 CI.getLangOpts(), FixItOpts.get());
132 FixAction->Execute();
Argyrios Kyrtzidis24e9aff2012-01-26 02:40:48 +0000133
Argyrios Kyrtzidisaf0bdfc2012-01-27 01:00:47 +0000134 err = Rewriter.WriteFixedFiles(&RewrittenFiles);
135
136 FixAction->EndSourceFile();
Craig Topper8ae12032014-05-07 06:21:57 +0000137 CI.setSourceManager(nullptr);
138 CI.setFileManager(nullptr);
Argyrios Kyrtzidisaf0bdfc2012-01-27 01:00:47 +0000139 } else {
140 err = true;
141 }
Argyrios Kyrtzidis24e9aff2012-01-26 02:40:48 +0000142 }
143 if (err)
144 return false;
145 CI.getDiagnosticClient().clear();
Argyrios Kyrtzidis0b5ec2d2012-01-27 06:15:37 +0000146 CI.getDiagnostics().Reset();
Argyrios Kyrtzidis24e9aff2012-01-26 02:40:48 +0000147
148 PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
149 PPOpts.RemappedFiles.insert(PPOpts.RemappedFiles.end(),
150 RewrittenFiles.begin(), RewrittenFiles.end());
151 PPOpts.RemappedFilesKeepOriginalName = false;
152
153 return true;
154}
155
Alp Toker0621cb22014-07-16 16:48:33 +0000156#ifdef CLANG_ENABLE_OBJC_REWRITER
Daniel Dunbarc1b17292010-06-15 17:48:49 +0000157
David Blaikie6beb6aa2014-08-10 19:56:51 +0000158std::unique_ptr<ASTConsumer>
159RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
Peter Collingbourne03f89072016-07-15 00:55:40 +0000160 if (std::unique_ptr<raw_ostream> OS =
161 CI.createDefaultOutputFile(false, InFile, "cpp")) {
John McCall5fb5df92012-06-20 06:18:46 +0000162 if (CI.getLangOpts().ObjCRuntime.isNonFragile())
Benjamin Kramer8c305922016-02-02 11:06:51 +0000163 return CreateModernObjCRewriter(
Peter Collingbourne03f89072016-07-15 00:55:40 +0000164 InFile, std::move(OS), CI.getDiagnostics(), CI.getLangOpts(),
Benjamin Kramer8c305922016-02-02 11:06:51 +0000165 CI.getDiagnosticOpts().NoRewriteMacros,
166 (CI.getCodeGenOpts().getDebugInfo() != codegenoptions::NoDebugInfo));
Peter Collingbourne03f89072016-07-15 00:55:40 +0000167 return CreateObjCRewriter(InFile, std::move(OS), CI.getDiagnostics(),
168 CI.getLangOpts(),
Daniel Dunbarc1b17292010-06-15 17:48:49 +0000169 CI.getDiagnosticOpts().NoRewriteMacros);
Fariborz Jahanian11671902012-02-07 17:11:38 +0000170 }
Craig Topper8ae12032014-05-07 06:21:57 +0000171 return nullptr;
Daniel Dunbarc1b17292010-06-15 17:48:49 +0000172}
173
Alp Toker0621cb22014-07-16 16:48:33 +0000174#endif
175
176//===----------------------------------------------------------------------===//
177// Preprocessor Actions
178//===----------------------------------------------------------------------===//
179
Daniel Dunbarc1b17292010-06-15 17:48:49 +0000180void RewriteMacrosAction::ExecuteAction() {
181 CompilerInstance &CI = getCompilerInstance();
Peter Collingbourne03f89072016-07-15 00:55:40 +0000182 std::unique_ptr<raw_ostream> OS =
183 CI.createDefaultOutputFile(true, getCurrentFile());
Daniel Dunbarc1b17292010-06-15 17:48:49 +0000184 if (!OS) return;
185
Peter Collingbourne03f89072016-07-15 00:55:40 +0000186 RewriteMacrosInInput(CI.getPreprocessor(), OS.get());
Daniel Dunbarc1b17292010-06-15 17:48:49 +0000187}
188
189void RewriteTestAction::ExecuteAction() {
190 CompilerInstance &CI = getCompilerInstance();
Peter Collingbourne03f89072016-07-15 00:55:40 +0000191 std::unique_ptr<raw_ostream> OS =
192 CI.createDefaultOutputFile(false, getCurrentFile());
Daniel Dunbarc1b17292010-06-15 17:48:49 +0000193 if (!OS) return;
194
Peter Collingbourne03f89072016-07-15 00:55:40 +0000195 DoRewriteTest(CI.getPreprocessor(), OS.get());
Daniel Dunbarc1b17292010-06-15 17:48:49 +0000196}
David Blaikied5321242012-06-06 18:52:13 +0000197
Richard Smith86a3ef52017-06-09 21:24:02 +0000198class RewriteIncludesAction::RewriteImportsListener : public ASTReaderListener {
199 CompilerInstance &CI;
200 std::weak_ptr<raw_ostream> Out;
201
202 llvm::DenseSet<const FileEntry*> Rewritten;
203
204public:
205 RewriteImportsListener(CompilerInstance &CI, std::shared_ptr<raw_ostream> Out)
206 : CI(CI), Out(Out) {}
207
208 void visitModuleFile(StringRef Filename,
209 serialization::ModuleKind Kind) override {
210 auto *File = CI.getFileManager().getFile(Filename);
211 assert(File && "missing file for loaded module?");
212
213 // Only rewrite each module file once.
214 if (!Rewritten.insert(File).second)
215 return;
216
217 serialization::ModuleFile *MF =
218 CI.getModuleManager()->getModuleManager().lookup(File);
219 assert(File && "missing module file for loaded module?");
220
221 // Not interested in PCH / preambles.
222 if (!MF->isModule())
223 return;
224
225 auto OS = Out.lock();
226 assert(OS && "loaded module file after finishing rewrite action?");
227
Richard Smith9565c75b2017-06-19 23:09:36 +0000228 (*OS) << "#pragma clang module build ";
229 if (isValidIdentifier(MF->ModuleName))
230 (*OS) << MF->ModuleName;
231 else {
232 (*OS) << '"';
233 OS->write_escaped(MF->ModuleName);
234 (*OS) << '"';
235 }
236 (*OS) << '\n';
Richard Smith86a3ef52017-06-09 21:24:02 +0000237
238 // Rewrite the contents of the module in a separate compiler instance.
239 CompilerInstance Instance(CI.getPCHContainerOperations(),
240 &CI.getPreprocessor().getPCMCache());
241 Instance.setInvocation(
242 std::make_shared<CompilerInvocation>(CI.getInvocation()));
243 Instance.createDiagnostics(
244 new ForwardingDiagnosticConsumer(CI.getDiagnosticClient()),
245 /*ShouldOwnClient=*/true);
Richard Smith4f05b362017-06-20 01:31:53 +0000246 Instance.getFrontendOpts().DisableFree = false;
Richard Smith86a3ef52017-06-09 21:24:02 +0000247 Instance.getFrontendOpts().Inputs.clear();
248 Instance.getFrontendOpts().Inputs.emplace_back(
249 Filename, InputKind(InputKind::Unknown, InputKind::Precompiled));
250 // Don't recursively rewrite imports. We handle them all at the top level.
251 Instance.getPreprocessorOutputOpts().RewriteImports = false;
252
253 llvm::CrashRecoveryContext().RunSafelyOnThread([&]() {
254 RewriteIncludesAction Action;
255 Action.OutputStream = OS;
256 Instance.ExecuteAction(Action);
257 });
258
259 (*OS) << "#pragma clang module endbuild /*" << MF->ModuleName << "*/\n";
260 }
261};
262
263bool RewriteIncludesAction::BeginSourceFileAction(CompilerInstance &CI) {
264 if (!OutputStream) {
265 OutputStream = CI.createDefaultOutputFile(true, getCurrentFile());
266 if (!OutputStream)
267 return false;
268 }
269
270 auto &OS = *OutputStream;
David Blaikied5321242012-06-06 18:52:13 +0000271
Richard Smith8128f332017-05-05 22:18:51 +0000272 // If we're preprocessing a module map, start by dumping the contents of the
273 // module itself before switching to the input buffer.
274 auto &Input = getCurrentInput();
275 if (Input.getKind().getFormat() == InputKind::ModuleMap) {
Richard Smithc784e962017-06-01 20:10:35 +0000276 if (Input.isFile()) {
Richard Smith86a3ef52017-06-09 21:24:02 +0000277 OS << "# 1 \"";
278 OS.write_escaped(Input.getFile());
279 OS << "\"\n";
Richard Smithc784e962017-06-01 20:10:35 +0000280 }
Richard Smith86a3ef52017-06-09 21:24:02 +0000281 getCurrentModule()->print(OS);
282 OS << "#pragma clang module contents\n";
Richard Smith8128f332017-05-05 22:18:51 +0000283 }
284
Richard Smith86a3ef52017-06-09 21:24:02 +0000285 // If we're rewriting imports, set up a listener to track when we import
286 // module files.
287 if (CI.getPreprocessorOutputOpts().RewriteImports) {
288 CI.createModuleManager();
289 CI.getModuleManager()->addListener(
290 llvm::make_unique<RewriteImportsListener>(CI, OutputStream));
291 }
292
293 return true;
294}
295
296void RewriteIncludesAction::ExecuteAction() {
297 CompilerInstance &CI = getCompilerInstance();
298
299 // If we're rewriting imports, emit the module build output first rather
300 // than switching back and forth (potentially in the middle of a line).
301 if (CI.getPreprocessorOutputOpts().RewriteImports) {
302 std::string Buffer;
303 llvm::raw_string_ostream OS(Buffer);
304
305 RewriteIncludesInInput(CI.getPreprocessor(), &OS,
306 CI.getPreprocessorOutputOpts());
307
308 (*OutputStream) << OS.str();
309 } else {
310 RewriteIncludesInInput(CI.getPreprocessor(), OutputStream.get(),
311 CI.getPreprocessorOutputOpts());
312 }
313
314 OutputStream.reset();
David Blaikied5321242012-06-06 18:52:13 +0000315}