FrontendActions.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  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. #include "clang/Rewrite/Frontend/FrontendActions.h"
  9. #include "clang/AST/ASTConsumer.h"
  10. #include "clang/Basic/CharInfo.h"
  11. #include "clang/Basic/LangStandard.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/ModuleFile.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. using namespace clang;
  33. //===----------------------------------------------------------------------===//
  34. // AST Consumer Actions
  35. //===----------------------------------------------------------------------===//
  36. std::unique_ptr<ASTConsumer>
  37. HTMLPrintAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
  38. if (std::unique_ptr<raw_ostream> OS =
  39. CI.createDefaultOutputFile(false, InFile))
  40. return CreateHTMLPrinter(std::move(OS), CI.getPreprocessor());
  41. return nullptr;
  42. }
  43. FixItAction::FixItAction() {}
  44. FixItAction::~FixItAction() {}
  45. std::unique_ptr<ASTConsumer>
  46. FixItAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
  47. return std::make_unique<ASTConsumer>();
  48. }
  49. namespace {
  50. class FixItRewriteInPlace : public FixItOptions {
  51. public:
  52. FixItRewriteInPlace() { InPlace = true; }
  53. std::string RewriteFilename(const std::string &Filename, int &fd) override {
  54. llvm_unreachable("don't call RewriteFilename for inplace rewrites");
  55. }
  56. };
  57. class FixItActionSuffixInserter : public FixItOptions {
  58. std::string NewSuffix;
  59. public:
  60. FixItActionSuffixInserter(std::string NewSuffix, bool FixWhatYouCan)
  61. : NewSuffix(std::move(NewSuffix)) {
  62. this->FixWhatYouCan = FixWhatYouCan;
  63. }
  64. std::string RewriteFilename(const std::string &Filename, int &fd) override {
  65. fd = -1;
  66. SmallString<128> Path(Filename);
  67. llvm::sys::path::replace_extension(Path,
  68. NewSuffix + llvm::sys::path::extension(Path));
  69. return std::string(Path.str());
  70. }
  71. };
  72. class FixItRewriteToTemp : public FixItOptions {
  73. public:
  74. std::string RewriteFilename(const std::string &Filename, int &fd) override {
  75. SmallString<128> Path;
  76. llvm::sys::fs::createTemporaryFile(llvm::sys::path::filename(Filename),
  77. llvm::sys::path::extension(Filename).drop_front(), fd,
  78. Path);
  79. return std::string(Path.str());
  80. }
  81. };
  82. } // end anonymous namespace
  83. bool FixItAction::BeginSourceFileAction(CompilerInstance &CI) {
  84. const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts();
  85. if (!FEOpts.FixItSuffix.empty()) {
  86. FixItOpts.reset(new FixItActionSuffixInserter(FEOpts.FixItSuffix,
  87. FEOpts.FixWhatYouCan));
  88. } else {
  89. FixItOpts.reset(new FixItRewriteInPlace);
  90. FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan;
  91. }
  92. Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(),
  93. CI.getLangOpts(), FixItOpts.get()));
  94. return true;
  95. }
  96. void FixItAction::EndSourceFileAction() {
  97. // Otherwise rewrite all files.
  98. Rewriter->WriteFixedFiles();
  99. }
  100. bool FixItRecompile::BeginInvocation(CompilerInstance &CI) {
  101. std::vector<std::pair<std::string, std::string> > RewrittenFiles;
  102. bool err = false;
  103. {
  104. const FrontendOptions &FEOpts = CI.getFrontendOpts();
  105. std::unique_ptr<FrontendAction> FixAction(new SyntaxOnlyAction());
  106. if (FixAction->BeginSourceFile(CI, FEOpts.Inputs[0])) {
  107. std::unique_ptr<FixItOptions> FixItOpts;
  108. if (FEOpts.FixToTemporaries)
  109. FixItOpts.reset(new FixItRewriteToTemp());
  110. else
  111. FixItOpts.reset(new FixItRewriteInPlace());
  112. FixItOpts->Silent = true;
  113. FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan;
  114. FixItOpts->FixOnlyWarnings = FEOpts.FixOnlyWarnings;
  115. FixItRewriter Rewriter(CI.getDiagnostics(), CI.getSourceManager(),
  116. CI.getLangOpts(), FixItOpts.get());
  117. if (llvm::Error Err = FixAction->Execute()) {
  118. // FIXME this drops the error on the floor.
  119. consumeError(std::move(Err));
  120. return false;
  121. }
  122. err = Rewriter.WriteFixedFiles(&RewrittenFiles);
  123. FixAction->EndSourceFile();
  124. CI.setSourceManager(nullptr);
  125. CI.setFileManager(nullptr);
  126. } else {
  127. err = true;
  128. }
  129. }
  130. if (err)
  131. return false;
  132. CI.getDiagnosticClient().clear();
  133. CI.getDiagnostics().Reset();
  134. PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
  135. PPOpts.RemappedFiles.insert(PPOpts.RemappedFiles.end(),
  136. RewrittenFiles.begin(), RewrittenFiles.end());
  137. PPOpts.RemappedFilesKeepOriginalName = false;
  138. return true;
  139. }
  140. #if CLANG_ENABLE_OBJC_REWRITER
  141. std::unique_ptr<ASTConsumer>
  142. RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
  143. if (std::unique_ptr<raw_ostream> OS =
  144. CI.createDefaultOutputFile(false, InFile, "cpp")) {
  145. if (CI.getLangOpts().ObjCRuntime.isNonFragile())
  146. return CreateModernObjCRewriter(
  147. std::string(InFile), std::move(OS), CI.getDiagnostics(),
  148. CI.getLangOpts(), CI.getDiagnosticOpts().NoRewriteMacros,
  149. (CI.getCodeGenOpts().getDebugInfo() != codegenoptions::NoDebugInfo));
  150. return CreateObjCRewriter(std::string(InFile), std::move(OS),
  151. CI.getDiagnostics(), CI.getLangOpts(),
  152. CI.getDiagnosticOpts().NoRewriteMacros);
  153. }
  154. return nullptr;
  155. }
  156. #endif
  157. //===----------------------------------------------------------------------===//
  158. // Preprocessor Actions
  159. //===----------------------------------------------------------------------===//
  160. void RewriteMacrosAction::ExecuteAction() {
  161. CompilerInstance &CI = getCompilerInstance();
  162. std::unique_ptr<raw_ostream> OS =
  163. CI.createDefaultOutputFile(/*Binary=*/true, getCurrentFileOrBufferName());
  164. if (!OS) return;
  165. RewriteMacrosInInput(CI.getPreprocessor(), OS.get());
  166. }
  167. void RewriteTestAction::ExecuteAction() {
  168. CompilerInstance &CI = getCompilerInstance();
  169. std::unique_ptr<raw_ostream> OS =
  170. CI.createDefaultOutputFile(/*Binary=*/false, getCurrentFileOrBufferName());
  171. if (!OS) return;
  172. DoRewriteTest(CI.getPreprocessor(), OS.get());
  173. }
  174. class RewriteIncludesAction::RewriteImportsListener : public ASTReaderListener {
  175. CompilerInstance &CI;
  176. std::weak_ptr<raw_ostream> Out;
  177. llvm::DenseSet<const FileEntry*> Rewritten;
  178. public:
  179. RewriteImportsListener(CompilerInstance &CI, std::shared_ptr<raw_ostream> Out)
  180. : CI(CI), Out(Out) {}
  181. void visitModuleFile(StringRef Filename,
  182. serialization::ModuleKind Kind) override {
  183. auto File = CI.getFileManager().getFile(Filename);
  184. assert(File && "missing file for loaded module?");
  185. // Only rewrite each module file once.
  186. if (!Rewritten.insert(*File).second)
  187. return;
  188. serialization::ModuleFile *MF =
  189. CI.getASTReader()->getModuleManager().lookup(*File);
  190. assert(MF && "missing module file for loaded module?");
  191. // Not interested in PCH / preambles.
  192. if (!MF->isModule())
  193. return;
  194. auto OS = Out.lock();
  195. assert(OS && "loaded module file after finishing rewrite action?");
  196. (*OS) << "#pragma clang module build ";
  197. if (isValidAsciiIdentifier(MF->ModuleName))
  198. (*OS) << MF->ModuleName;
  199. else {
  200. (*OS) << '"';
  201. OS->write_escaped(MF->ModuleName);
  202. (*OS) << '"';
  203. }
  204. (*OS) << '\n';
  205. // Rewrite the contents of the module in a separate compiler instance.
  206. CompilerInstance Instance(CI.getPCHContainerOperations(),
  207. &CI.getModuleCache());
  208. Instance.setInvocation(
  209. std::make_shared<CompilerInvocation>(CI.getInvocation()));
  210. Instance.createDiagnostics(
  211. new ForwardingDiagnosticConsumer(CI.getDiagnosticClient()),
  212. /*ShouldOwnClient=*/true);
  213. Instance.getFrontendOpts().DisableFree = false;
  214. Instance.getFrontendOpts().Inputs.clear();
  215. Instance.getFrontendOpts().Inputs.emplace_back(
  216. Filename, InputKind(Language::Unknown, InputKind::Precompiled));
  217. Instance.getFrontendOpts().ModuleFiles.clear();
  218. Instance.getFrontendOpts().ModuleMapFiles.clear();
  219. // Don't recursively rewrite imports. We handle them all at the top level.
  220. Instance.getPreprocessorOutputOpts().RewriteImports = false;
  221. llvm::CrashRecoveryContext().RunSafelyOnThread([&]() {
  222. RewriteIncludesAction Action;
  223. Action.OutputStream = OS;
  224. Instance.ExecuteAction(Action);
  225. });
  226. (*OS) << "#pragma clang module endbuild /*" << MF->ModuleName << "*/\n";
  227. }
  228. };
  229. bool RewriteIncludesAction::BeginSourceFileAction(CompilerInstance &CI) {
  230. if (!OutputStream) {
  231. OutputStream =
  232. CI.createDefaultOutputFile(/*Binary=*/true, getCurrentFileOrBufferName());
  233. if (!OutputStream)
  234. return false;
  235. }
  236. auto &OS = *OutputStream;
  237. // If we're preprocessing a module map, start by dumping the contents of the
  238. // module itself before switching to the input buffer.
  239. auto &Input = getCurrentInput();
  240. if (Input.getKind().getFormat() == InputKind::ModuleMap) {
  241. if (Input.isFile()) {
  242. OS << "# 1 \"";
  243. OS.write_escaped(Input.getFile());
  244. OS << "\"\n";
  245. }
  246. getCurrentModule()->print(OS);
  247. OS << "#pragma clang module contents\n";
  248. }
  249. // If we're rewriting imports, set up a listener to track when we import
  250. // module files.
  251. if (CI.getPreprocessorOutputOpts().RewriteImports) {
  252. CI.createASTReader();
  253. CI.getASTReader()->addListener(
  254. std::make_unique<RewriteImportsListener>(CI, OutputStream));
  255. }
  256. return true;
  257. }
  258. void RewriteIncludesAction::ExecuteAction() {
  259. CompilerInstance &CI = getCompilerInstance();
  260. // If we're rewriting imports, emit the module build output first rather
  261. // than switching back and forth (potentially in the middle of a line).
  262. if (CI.getPreprocessorOutputOpts().RewriteImports) {
  263. std::string Buffer;
  264. llvm::raw_string_ostream OS(Buffer);
  265. RewriteIncludesInInput(CI.getPreprocessor(), &OS,
  266. CI.getPreprocessorOutputOpts());
  267. (*OutputStream) << OS.str();
  268. } else {
  269. RewriteIncludesInInput(CI.getPreprocessor(), OutputStream.get(),
  270. CI.getPreprocessorOutputOpts());
  271. }
  272. OutputStream.reset();
  273. }