Clang Project

clang_source_code/lib/Frontend/Rewrite/FrontendActions.cpp
1//===--- FrontendActions.cpp ----------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "clang/Rewrite/Frontend/FrontendActions.h"
10#include "clang/AST/ASTConsumer.h"
11#include "clang/Basic/CharInfo.h"
12#include "clang/Config/config.h"
13#include "clang/Frontend/CompilerInstance.h"
14#include "clang/Frontend/FrontendActions.h"
15#include "clang/Frontend/FrontendDiagnostic.h"
16#include "clang/Frontend/Utils.h"
17#include "clang/Lex/Preprocessor.h"
18#include "clang/Lex/PreprocessorOptions.h"
19#include "clang/Rewrite/Frontend/ASTConsumers.h"
20#include "clang/Rewrite/Frontend/FixItRewriter.h"
21#include "clang/Rewrite/Frontend/Rewriters.h"
22#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"
27#include "llvm/Support/FileSystem.h"
28#include "llvm/Support/Path.h"
29#include "llvm/Support/raw_ostream.h"
30#include <memory>
31#include <utility>
32
33using namespace clang;
34
35//===----------------------------------------------------------------------===//
36// AST Consumer Actions
37//===----------------------------------------------------------------------===//
38
39std::unique_ptr<ASTConsumer>
40HTMLPrintAction::CreateASTConsumer(CompilerInstance &CIStringRef InFile) {
41  if (std::unique_ptr<raw_ostreamOS =
42          CI.createDefaultOutputFile(false, InFile))
43    return CreateHTMLPrinter(std::move(OS), CI.getPreprocessor());
44  return nullptr;
45}
46
47FixItAction::FixItAction() {}
48FixItAction::~FixItAction() {}
49
50std::unique_ptr<ASTConsumer>
51FixItAction::CreateASTConsumer(CompilerInstance &CIStringRef InFile) {
52  return llvm::make_unique<ASTConsumer>();
53}
54
55namespace {
56class FixItRewriteInPlace : public FixItOptions {
57public:
58  FixItRewriteInPlace() { InPlace = true; }
59
60  std::string RewriteFilename(const std::string &Filenameint &fd) override {
61    llvm_unreachable("don't call RewriteFilename for inplace rewrites");
62  }
63};
64
65class FixItActionSuffixInserter : public FixItOptions {
66  std::string NewSuffix;
67
68public:
69  FixItActionSuffixInserter(std::string NewSuffixbool FixWhatYouCan)
70      : NewSuffix(std::move(NewSuffix)) {
71    this->FixWhatYouCan = FixWhatYouCan;
72  }
73
74  std::string RewriteFilename(const std::string &Filenameint &fd) override {
75    fd = -1;
76    SmallString<128Path(Filename);
77    llvm::sys::path::replace_extension(Path,
78      NewSuffix + llvm::sys::path::extension(Path));
79    return Path.str();
80  }
81};
82
83class FixItRewriteToTemp : public FixItOptions {
84public:
85  std::string RewriteFilename(const std::string &Filenameint &fd) override {
86    SmallString<128Path;
87    llvm::sys::fs::createTemporaryFile(llvm::sys::path::filename(Filename),
88                                       llvm::sys::path::extension(Filename).drop_front(), fd,
89                                       Path);
90    return Path.str();
91  }
92};
93// end anonymous namespace
94
95bool FixItAction::BeginSourceFileAction(CompilerInstance &CI) {
96  const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts();
97  if (!FEOpts.FixItSuffix.empty()) {
98    FixItOpts.reset(new FixItActionSuffixInserter(FEOpts.FixItSuffix,
99                                                  FEOpts.FixWhatYouCan));
100  } else {
101    FixItOpts.reset(new FixItRewriteInPlace);
102    FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan;
103  }
104  Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(),
105                                   CI.getLangOpts(), FixItOpts.get()));
106  return true;
107}
108
109void FixItAction::EndSourceFileAction() {
110  // Otherwise rewrite all files.
111  Rewriter->WriteFixedFiles();
112}
113
114bool FixItRecompile::BeginInvocation(CompilerInstance &CI) {
115
116  std::vector<std::pair<std::stringstd::string> > RewrittenFiles;
117  bool err = false;
118  {
119    const FrontendOptions &FEOpts = CI.getFrontendOpts();
120    std::unique_ptr<FrontendActionFixAction(new SyntaxOnlyAction());
121    if (FixAction->BeginSourceFile(CIFEOpts.Inputs[0])) {
122      std::unique_ptr<FixItOptionsFixItOpts;
123      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();
133
134      err = Rewriter.WriteFixedFiles(&RewrittenFiles);
135
136      FixAction->EndSourceFile();
137      CI.setSourceManager(nullptr);
138      CI.setFileManager(nullptr);
139    } else {
140      err = true;
141    }
142  }
143  if (err)
144    return false;
145  CI.getDiagnosticClient().clear();
146  CI.getDiagnostics().Reset();
147
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
156#if CLANG_ENABLE_OBJC_REWRITER
157
158std::unique_ptr<ASTConsumer>
159RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
160  if (std::unique_ptr<raw_ostream> OS =
161          CI.createDefaultOutputFile(false, InFile, "cpp")) {
162    if (CI.getLangOpts().ObjCRuntime.isNonFragile())
163      return CreateModernObjCRewriter(
164          InFile, std::move(OS), CI.getDiagnostics(), CI.getLangOpts(),
165          CI.getDiagnosticOpts().NoRewriteMacros,
166          (CI.getCodeGenOpts().getDebugInfo() != codegenoptions::NoDebugInfo));
167    return CreateObjCRewriter(InFile, std::move(OS), CI.getDiagnostics(),
168                              CI.getLangOpts(),
169                              CI.getDiagnosticOpts().NoRewriteMacros);
170  }
171  return nullptr;
172}
173
174#endif
175
176//===----------------------------------------------------------------------===//
177// Preprocessor Actions
178//===----------------------------------------------------------------------===//
179
180void RewriteMacrosAction::ExecuteAction() {
181  CompilerInstance &CI = getCompilerInstance();
182  std::unique_ptr<raw_ostreamOS =
183      CI.createDefaultOutputFile(true, getCurrentFileOrBufferName());
184  if (!OSreturn;
185
186  RewriteMacrosInInput(CI.getPreprocessor()OS.get());
187}
188
189void RewriteTestAction::ExecuteAction() {
190  CompilerInstance &CI = getCompilerInstance();
191  std::unique_ptr<raw_ostreamOS =
192      CI.createDefaultOutputFile(false, getCurrentFileOrBufferName());
193  if (!OSreturn;
194
195  DoRewriteTest(CI.getPreprocessor()OS.get());
196}
197
198class RewriteIncludesAction::RewriteImportsListener : public ASTReaderListener {
199  CompilerInstance &CI;
200  std::weak_ptr<raw_ostreamOut;
201
202  llvm::DenseSet<const FileEntry*> Rewritten;
203
204public:
205  RewriteImportsListener(CompilerInstance &CIstd::shared_ptr<raw_ostreamOut)
206      : CI(CI), Out(Out) {}
207
208  void visitModuleFile(StringRef Filename,
209                       serialization::ModuleKind Kind) override {
210    auto *File = CI.getFileManager().getFile(Filename);
211     (0) . __assert_fail ("File && \"missing file for loaded module?\"", "/home/seafit/code_projects/clang_source/clang/lib/Frontend/Rewrite/FrontendActions.cpp", 211, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">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     (0) . __assert_fail ("File && \"missing module file for loaded module?\"", "/home/seafit/code_projects/clang_source/clang/lib/Frontend/Rewrite/FrontendActions.cpp", 219, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">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     (0) . __assert_fail ("OS && \"loaded module file after finishing rewrite action?\"", "/home/seafit/code_projects/clang_source/clang/lib/Frontend/Rewrite/FrontendActions.cpp", 226, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(OS && "loaded module file after finishing rewrite action?");
227
228    (*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';
237
238    // Rewrite the contents of the module in a separate compiler instance.
239    CompilerInstance Instance(CI.getPCHContainerOperations(),
240                              &CI.getModuleCache());
241    Instance.setInvocation(
242        std::make_shared<CompilerInvocation>(CI.getInvocation()));
243    Instance.createDiagnostics(
244        new ForwardingDiagnosticConsumer(CI.getDiagnosticClient()),
245        /*ShouldOwnClient=*/true);
246    Instance.getFrontendOpts().DisableFree = false;
247    Instance.getFrontendOpts().Inputs.clear();
248    Instance.getFrontendOpts().Inputs.emplace_back(
249        Filename, InputKind(InputKind::Unknown, InputKind::Precompiled));
250    Instance.getFrontendOpts().ModuleFiles.clear();
251    Instance.getFrontendOpts().ModuleMapFiles.clear();
252    // Don't recursively rewrite imports. We handle them all at the top level.
253    Instance.getPreprocessorOutputOpts().RewriteImports = false;
254
255    llvm::CrashRecoveryContext().RunSafelyOnThread([&]() {
256      RewriteIncludesAction Action;
257      Action.OutputStream = OS;
258      Instance.ExecuteAction(Action);
259    });
260
261    (*OS) << "#pragma clang module endbuild /*" << MF->ModuleName << "*/\n";
262  }
263};
264
265bool RewriteIncludesAction::BeginSourceFileAction(CompilerInstance &CI) {
266  if (!OutputStream) {
267    OutputStream =
268        CI.createDefaultOutputFile(true, getCurrentFileOrBufferName());
269    if (!OutputStream)
270      return false;
271  }
272
273  auto &OS = *OutputStream;
274
275  // 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) {
279    if (Input.isFile()) {
280      OS << "# 1 \"";
281      OS.write_escaped(Input.getFile());
282      OS << "\"\n";
283    }
284    getCurrentModule()->print(OS);
285    OS << "#pragma clang module contents\n";
286  }
287
288  // 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();
318}
319
clang::HTMLPrintAction::CreateASTConsumer
clang::FixItAction::CreateASTConsumer
clang::FixItAction::BeginSourceFileAction
clang::FixItAction::EndSourceFileAction
clang::FixItRecompile::BeginInvocation
clang::RewriteMacrosAction::ExecuteAction
clang::RewriteTestAction::ExecuteAction
clang::RewriteIncludesAction::RewriteImportsListener
clang::RewriteIncludesAction::RewriteImportsListener::CI
clang::RewriteIncludesAction::RewriteImportsListener::Out
clang::RewriteIncludesAction::RewriteImportsListener::Rewritten
clang::RewriteIncludesAction::RewriteImportsListener::visitModuleFile
clang::RewriteIncludesAction::BeginSourceFileAction
clang::RewriteIncludesAction::ExecuteAction