xref: /freebsd/contrib/llvm-project/clang/lib/Frontend/Rewrite/FrontendActions.cpp (revision 7a6dacaca14b62ca4b74406814becb87a3fefac0)
10b57cec5SDimitry Andric //===--- FrontendActions.cpp ----------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "clang/Rewrite/Frontend/FrontendActions.h"
100b57cec5SDimitry Andric #include "clang/AST/ASTConsumer.h"
110b57cec5SDimitry Andric #include "clang/Basic/CharInfo.h"
12a7dea167SDimitry Andric #include "clang/Basic/LangStandard.h"
130b57cec5SDimitry Andric #include "clang/Config/config.h"
140b57cec5SDimitry Andric #include "clang/Frontend/CompilerInstance.h"
150b57cec5SDimitry Andric #include "clang/Frontend/FrontendActions.h"
160b57cec5SDimitry Andric #include "clang/Frontend/FrontendDiagnostic.h"
170b57cec5SDimitry Andric #include "clang/Frontend/Utils.h"
180b57cec5SDimitry Andric #include "clang/Lex/Preprocessor.h"
190b57cec5SDimitry Andric #include "clang/Lex/PreprocessorOptions.h"
200b57cec5SDimitry Andric #include "clang/Rewrite/Frontend/ASTConsumers.h"
210b57cec5SDimitry Andric #include "clang/Rewrite/Frontend/FixItRewriter.h"
220b57cec5SDimitry Andric #include "clang/Rewrite/Frontend/Rewriters.h"
230b57cec5SDimitry Andric #include "clang/Serialization/ASTReader.h"
24480093f4SDimitry Andric #include "clang/Serialization/ModuleFile.h"
250b57cec5SDimitry Andric #include "clang/Serialization/ModuleManager.h"
260b57cec5SDimitry Andric #include "llvm/ADT/DenseSet.h"
270b57cec5SDimitry Andric #include "llvm/Support/CrashRecoveryContext.h"
280b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h"
290b57cec5SDimitry Andric #include "llvm/Support/Path.h"
300b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
310b57cec5SDimitry Andric #include <memory>
320b57cec5SDimitry Andric #include <utility>
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric using namespace clang;
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
370b57cec5SDimitry Andric // AST Consumer Actions
380b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric std::unique_ptr<ASTConsumer>
410b57cec5SDimitry Andric HTMLPrintAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
420b57cec5SDimitry Andric   if (std::unique_ptr<raw_ostream> OS =
430b57cec5SDimitry Andric           CI.createDefaultOutputFile(false, InFile))
440b57cec5SDimitry Andric     return CreateHTMLPrinter(std::move(OS), CI.getPreprocessor());
450b57cec5SDimitry Andric   return nullptr;
460b57cec5SDimitry Andric }
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric FixItAction::FixItAction() {}
490b57cec5SDimitry Andric FixItAction::~FixItAction() {}
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric std::unique_ptr<ASTConsumer>
520b57cec5SDimitry Andric FixItAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
53a7dea167SDimitry Andric   return std::make_unique<ASTConsumer>();
540b57cec5SDimitry Andric }
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric namespace {
570b57cec5SDimitry Andric class FixItRewriteInPlace : public FixItOptions {
580b57cec5SDimitry Andric public:
590b57cec5SDimitry Andric   FixItRewriteInPlace() { InPlace = true; }
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric   std::string RewriteFilename(const std::string &Filename, int &fd) override {
620b57cec5SDimitry Andric     llvm_unreachable("don't call RewriteFilename for inplace rewrites");
630b57cec5SDimitry Andric   }
640b57cec5SDimitry Andric };
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric class FixItActionSuffixInserter : public FixItOptions {
670b57cec5SDimitry Andric   std::string NewSuffix;
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric public:
700b57cec5SDimitry Andric   FixItActionSuffixInserter(std::string NewSuffix, bool FixWhatYouCan)
710b57cec5SDimitry Andric       : NewSuffix(std::move(NewSuffix)) {
720b57cec5SDimitry Andric     this->FixWhatYouCan = FixWhatYouCan;
730b57cec5SDimitry Andric   }
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric   std::string RewriteFilename(const std::string &Filename, int &fd) override {
760b57cec5SDimitry Andric     fd = -1;
770b57cec5SDimitry Andric     SmallString<128> Path(Filename);
780b57cec5SDimitry Andric     llvm::sys::path::replace_extension(Path,
790b57cec5SDimitry Andric       NewSuffix + llvm::sys::path::extension(Path));
80*7a6dacacSDimitry Andric     return std::string(Path);
810b57cec5SDimitry Andric   }
820b57cec5SDimitry Andric };
830b57cec5SDimitry Andric 
840b57cec5SDimitry Andric class FixItRewriteToTemp : public FixItOptions {
850b57cec5SDimitry Andric public:
860b57cec5SDimitry Andric   std::string RewriteFilename(const std::string &Filename, int &fd) override {
870b57cec5SDimitry Andric     SmallString<128> Path;
880b57cec5SDimitry Andric     llvm::sys::fs::createTemporaryFile(llvm::sys::path::filename(Filename),
890b57cec5SDimitry Andric                                        llvm::sys::path::extension(Filename).drop_front(), fd,
900b57cec5SDimitry Andric                                        Path);
91*7a6dacacSDimitry Andric     return std::string(Path);
920b57cec5SDimitry Andric   }
930b57cec5SDimitry Andric };
940b57cec5SDimitry Andric } // end anonymous namespace
950b57cec5SDimitry Andric 
960b57cec5SDimitry Andric bool FixItAction::BeginSourceFileAction(CompilerInstance &CI) {
970b57cec5SDimitry Andric   const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts();
980b57cec5SDimitry Andric   if (!FEOpts.FixItSuffix.empty()) {
990b57cec5SDimitry Andric     FixItOpts.reset(new FixItActionSuffixInserter(FEOpts.FixItSuffix,
1000b57cec5SDimitry Andric                                                   FEOpts.FixWhatYouCan));
1010b57cec5SDimitry Andric   } else {
1020b57cec5SDimitry Andric     FixItOpts.reset(new FixItRewriteInPlace);
1030b57cec5SDimitry Andric     FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan;
1040b57cec5SDimitry Andric   }
1050b57cec5SDimitry Andric   Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(),
1060b57cec5SDimitry Andric                                    CI.getLangOpts(), FixItOpts.get()));
1070b57cec5SDimitry Andric   return true;
1080b57cec5SDimitry Andric }
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric void FixItAction::EndSourceFileAction() {
1110b57cec5SDimitry Andric   // Otherwise rewrite all files.
1120b57cec5SDimitry Andric   Rewriter->WriteFixedFiles();
1130b57cec5SDimitry Andric }
1140b57cec5SDimitry Andric 
1150b57cec5SDimitry Andric bool FixItRecompile::BeginInvocation(CompilerInstance &CI) {
1160b57cec5SDimitry Andric 
1170b57cec5SDimitry Andric   std::vector<std::pair<std::string, std::string> > RewrittenFiles;
1180b57cec5SDimitry Andric   bool err = false;
1190b57cec5SDimitry Andric   {
1200b57cec5SDimitry Andric     const FrontendOptions &FEOpts = CI.getFrontendOpts();
1210b57cec5SDimitry Andric     std::unique_ptr<FrontendAction> FixAction(new SyntaxOnlyAction());
1220b57cec5SDimitry Andric     if (FixAction->BeginSourceFile(CI, FEOpts.Inputs[0])) {
1230b57cec5SDimitry Andric       std::unique_ptr<FixItOptions> FixItOpts;
1240b57cec5SDimitry Andric       if (FEOpts.FixToTemporaries)
1250b57cec5SDimitry Andric         FixItOpts.reset(new FixItRewriteToTemp());
1260b57cec5SDimitry Andric       else
1270b57cec5SDimitry Andric         FixItOpts.reset(new FixItRewriteInPlace());
1280b57cec5SDimitry Andric       FixItOpts->Silent = true;
1290b57cec5SDimitry Andric       FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan;
1300b57cec5SDimitry Andric       FixItOpts->FixOnlyWarnings = FEOpts.FixOnlyWarnings;
1310b57cec5SDimitry Andric       FixItRewriter Rewriter(CI.getDiagnostics(), CI.getSourceManager(),
1320b57cec5SDimitry Andric                              CI.getLangOpts(), FixItOpts.get());
1330b57cec5SDimitry Andric       if (llvm::Error Err = FixAction->Execute()) {
1340b57cec5SDimitry Andric         // FIXME this drops the error on the floor.
1350b57cec5SDimitry Andric         consumeError(std::move(Err));
1360b57cec5SDimitry Andric         return false;
1370b57cec5SDimitry Andric       }
1380b57cec5SDimitry Andric 
1390b57cec5SDimitry Andric       err = Rewriter.WriteFixedFiles(&RewrittenFiles);
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric       FixAction->EndSourceFile();
1420b57cec5SDimitry Andric       CI.setSourceManager(nullptr);
1430b57cec5SDimitry Andric       CI.setFileManager(nullptr);
1440b57cec5SDimitry Andric     } else {
1450b57cec5SDimitry Andric       err = true;
1460b57cec5SDimitry Andric     }
1470b57cec5SDimitry Andric   }
1480b57cec5SDimitry Andric   if (err)
1490b57cec5SDimitry Andric     return false;
1500b57cec5SDimitry Andric   CI.getDiagnosticClient().clear();
1510b57cec5SDimitry Andric   CI.getDiagnostics().Reset();
1520b57cec5SDimitry Andric 
1530b57cec5SDimitry Andric   PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
1540b57cec5SDimitry Andric   PPOpts.RemappedFiles.insert(PPOpts.RemappedFiles.end(),
1550b57cec5SDimitry Andric                               RewrittenFiles.begin(), RewrittenFiles.end());
1560b57cec5SDimitry Andric   PPOpts.RemappedFilesKeepOriginalName = false;
1570b57cec5SDimitry Andric 
1580b57cec5SDimitry Andric   return true;
1590b57cec5SDimitry Andric }
1600b57cec5SDimitry Andric 
1610b57cec5SDimitry Andric #if CLANG_ENABLE_OBJC_REWRITER
1620b57cec5SDimitry Andric 
1630b57cec5SDimitry Andric std::unique_ptr<ASTConsumer>
1640b57cec5SDimitry Andric RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
1650b57cec5SDimitry Andric   if (std::unique_ptr<raw_ostream> OS =
1660b57cec5SDimitry Andric           CI.createDefaultOutputFile(false, InFile, "cpp")) {
1670b57cec5SDimitry Andric     if (CI.getLangOpts().ObjCRuntime.isNonFragile())
16806c3fb27SDimitry Andric       return CreateModernObjCRewriter(std::string(InFile), std::move(OS),
16906c3fb27SDimitry Andric                                       CI.getDiagnostics(), CI.getLangOpts(),
17006c3fb27SDimitry Andric                                       CI.getDiagnosticOpts().NoRewriteMacros,
17106c3fb27SDimitry Andric                                       (CI.getCodeGenOpts().getDebugInfo() !=
17206c3fb27SDimitry Andric                                        llvm::codegenoptions::NoDebugInfo));
1735ffd83dbSDimitry Andric     return CreateObjCRewriter(std::string(InFile), std::move(OS),
1745ffd83dbSDimitry Andric                               CI.getDiagnostics(), CI.getLangOpts(),
1750b57cec5SDimitry Andric                               CI.getDiagnosticOpts().NoRewriteMacros);
1760b57cec5SDimitry Andric   }
1770b57cec5SDimitry Andric   return nullptr;
1780b57cec5SDimitry Andric }
1790b57cec5SDimitry Andric 
1800b57cec5SDimitry Andric #endif
1810b57cec5SDimitry Andric 
1820b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
1830b57cec5SDimitry Andric // Preprocessor Actions
1840b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
1850b57cec5SDimitry Andric 
1860b57cec5SDimitry Andric void RewriteMacrosAction::ExecuteAction() {
1870b57cec5SDimitry Andric   CompilerInstance &CI = getCompilerInstance();
1880b57cec5SDimitry Andric   std::unique_ptr<raw_ostream> OS =
189fe6060f1SDimitry Andric       CI.createDefaultOutputFile(/*Binary=*/true, getCurrentFileOrBufferName());
1900b57cec5SDimitry Andric   if (!OS) return;
1910b57cec5SDimitry Andric 
1920b57cec5SDimitry Andric   RewriteMacrosInInput(CI.getPreprocessor(), OS.get());
1930b57cec5SDimitry Andric }
1940b57cec5SDimitry Andric 
1950b57cec5SDimitry Andric void RewriteTestAction::ExecuteAction() {
1960b57cec5SDimitry Andric   CompilerInstance &CI = getCompilerInstance();
1970b57cec5SDimitry Andric   std::unique_ptr<raw_ostream> OS =
198fe6060f1SDimitry Andric       CI.createDefaultOutputFile(/*Binary=*/false, getCurrentFileOrBufferName());
1990b57cec5SDimitry Andric   if (!OS) return;
2000b57cec5SDimitry Andric 
2010b57cec5SDimitry Andric   DoRewriteTest(CI.getPreprocessor(), OS.get());
2020b57cec5SDimitry Andric }
2030b57cec5SDimitry Andric 
2040b57cec5SDimitry Andric class RewriteIncludesAction::RewriteImportsListener : public ASTReaderListener {
2050b57cec5SDimitry Andric   CompilerInstance &CI;
2060b57cec5SDimitry Andric   std::weak_ptr<raw_ostream> Out;
2070b57cec5SDimitry Andric 
2080b57cec5SDimitry Andric   llvm::DenseSet<const FileEntry*> Rewritten;
2090b57cec5SDimitry Andric 
2100b57cec5SDimitry Andric public:
2110b57cec5SDimitry Andric   RewriteImportsListener(CompilerInstance &CI, std::shared_ptr<raw_ostream> Out)
2120b57cec5SDimitry Andric       : CI(CI), Out(Out) {}
2130b57cec5SDimitry Andric 
2140b57cec5SDimitry Andric   void visitModuleFile(StringRef Filename,
2150b57cec5SDimitry Andric                        serialization::ModuleKind Kind) override {
216a7dea167SDimitry Andric     auto File = CI.getFileManager().getFile(Filename);
2170b57cec5SDimitry Andric     assert(File && "missing file for loaded module?");
2180b57cec5SDimitry Andric 
2190b57cec5SDimitry Andric     // Only rewrite each module file once.
220a7dea167SDimitry Andric     if (!Rewritten.insert(*File).second)
2210b57cec5SDimitry Andric       return;
2220b57cec5SDimitry Andric 
2230b57cec5SDimitry Andric     serialization::ModuleFile *MF =
224480093f4SDimitry Andric         CI.getASTReader()->getModuleManager().lookup(*File);
225a7dea167SDimitry Andric     assert(MF && "missing module file for loaded module?");
2260b57cec5SDimitry Andric 
2270b57cec5SDimitry Andric     // Not interested in PCH / preambles.
2280b57cec5SDimitry Andric     if (!MF->isModule())
2290b57cec5SDimitry Andric       return;
2300b57cec5SDimitry Andric 
2310b57cec5SDimitry Andric     auto OS = Out.lock();
2320b57cec5SDimitry Andric     assert(OS && "loaded module file after finishing rewrite action?");
2330b57cec5SDimitry Andric 
2340b57cec5SDimitry Andric     (*OS) << "#pragma clang module build ";
235349cc55cSDimitry Andric     if (isValidAsciiIdentifier(MF->ModuleName))
2360b57cec5SDimitry Andric       (*OS) << MF->ModuleName;
2370b57cec5SDimitry Andric     else {
2380b57cec5SDimitry Andric       (*OS) << '"';
2390b57cec5SDimitry Andric       OS->write_escaped(MF->ModuleName);
2400b57cec5SDimitry Andric       (*OS) << '"';
2410b57cec5SDimitry Andric     }
2420b57cec5SDimitry Andric     (*OS) << '\n';
2430b57cec5SDimitry Andric 
2440b57cec5SDimitry Andric     // Rewrite the contents of the module in a separate compiler instance.
2450b57cec5SDimitry Andric     CompilerInstance Instance(CI.getPCHContainerOperations(),
2460b57cec5SDimitry Andric                               &CI.getModuleCache());
2470b57cec5SDimitry Andric     Instance.setInvocation(
2480b57cec5SDimitry Andric         std::make_shared<CompilerInvocation>(CI.getInvocation()));
2490b57cec5SDimitry Andric     Instance.createDiagnostics(
2500b57cec5SDimitry Andric         new ForwardingDiagnosticConsumer(CI.getDiagnosticClient()),
2510b57cec5SDimitry Andric         /*ShouldOwnClient=*/true);
2520b57cec5SDimitry Andric     Instance.getFrontendOpts().DisableFree = false;
2530b57cec5SDimitry Andric     Instance.getFrontendOpts().Inputs.clear();
2540b57cec5SDimitry Andric     Instance.getFrontendOpts().Inputs.emplace_back(
255a7dea167SDimitry Andric         Filename, InputKind(Language::Unknown, InputKind::Precompiled));
2560b57cec5SDimitry Andric     Instance.getFrontendOpts().ModuleFiles.clear();
2570b57cec5SDimitry Andric     Instance.getFrontendOpts().ModuleMapFiles.clear();
2580b57cec5SDimitry Andric     // Don't recursively rewrite imports. We handle them all at the top level.
2590b57cec5SDimitry Andric     Instance.getPreprocessorOutputOpts().RewriteImports = false;
2600b57cec5SDimitry Andric 
2610b57cec5SDimitry Andric     llvm::CrashRecoveryContext().RunSafelyOnThread([&]() {
2620b57cec5SDimitry Andric       RewriteIncludesAction Action;
2630b57cec5SDimitry Andric       Action.OutputStream = OS;
2640b57cec5SDimitry Andric       Instance.ExecuteAction(Action);
2650b57cec5SDimitry Andric     });
2660b57cec5SDimitry Andric 
2670b57cec5SDimitry Andric     (*OS) << "#pragma clang module endbuild /*" << MF->ModuleName << "*/\n";
2680b57cec5SDimitry Andric   }
2690b57cec5SDimitry Andric };
2700b57cec5SDimitry Andric 
2710b57cec5SDimitry Andric bool RewriteIncludesAction::BeginSourceFileAction(CompilerInstance &CI) {
2720b57cec5SDimitry Andric   if (!OutputStream) {
2730b57cec5SDimitry Andric     OutputStream =
274fe6060f1SDimitry Andric         CI.createDefaultOutputFile(/*Binary=*/true, getCurrentFileOrBufferName());
2750b57cec5SDimitry Andric     if (!OutputStream)
2760b57cec5SDimitry Andric       return false;
2770b57cec5SDimitry Andric   }
2780b57cec5SDimitry Andric 
2790b57cec5SDimitry Andric   auto &OS = *OutputStream;
2800b57cec5SDimitry Andric 
2810b57cec5SDimitry Andric   // If we're preprocessing a module map, start by dumping the contents of the
2820b57cec5SDimitry Andric   // module itself before switching to the input buffer.
2830b57cec5SDimitry Andric   auto &Input = getCurrentInput();
2840b57cec5SDimitry Andric   if (Input.getKind().getFormat() == InputKind::ModuleMap) {
2850b57cec5SDimitry Andric     if (Input.isFile()) {
2860b57cec5SDimitry Andric       OS << "# 1 \"";
2870b57cec5SDimitry Andric       OS.write_escaped(Input.getFile());
2880b57cec5SDimitry Andric       OS << "\"\n";
2890b57cec5SDimitry Andric     }
2900b57cec5SDimitry Andric     getCurrentModule()->print(OS);
2910b57cec5SDimitry Andric     OS << "#pragma clang module contents\n";
2920b57cec5SDimitry Andric   }
2930b57cec5SDimitry Andric 
2940b57cec5SDimitry Andric   // If we're rewriting imports, set up a listener to track when we import
2950b57cec5SDimitry Andric   // module files.
2960b57cec5SDimitry Andric   if (CI.getPreprocessorOutputOpts().RewriteImports) {
297480093f4SDimitry Andric     CI.createASTReader();
298480093f4SDimitry Andric     CI.getASTReader()->addListener(
299a7dea167SDimitry Andric         std::make_unique<RewriteImportsListener>(CI, OutputStream));
3000b57cec5SDimitry Andric   }
3010b57cec5SDimitry Andric 
3020b57cec5SDimitry Andric   return true;
3030b57cec5SDimitry Andric }
3040b57cec5SDimitry Andric 
3050b57cec5SDimitry Andric void RewriteIncludesAction::ExecuteAction() {
3060b57cec5SDimitry Andric   CompilerInstance &CI = getCompilerInstance();
3070b57cec5SDimitry Andric 
3080b57cec5SDimitry Andric   // If we're rewriting imports, emit the module build output first rather
3090b57cec5SDimitry Andric   // than switching back and forth (potentially in the middle of a line).
3100b57cec5SDimitry Andric   if (CI.getPreprocessorOutputOpts().RewriteImports) {
3110b57cec5SDimitry Andric     std::string Buffer;
3120b57cec5SDimitry Andric     llvm::raw_string_ostream OS(Buffer);
3130b57cec5SDimitry Andric 
3140b57cec5SDimitry Andric     RewriteIncludesInInput(CI.getPreprocessor(), &OS,
3150b57cec5SDimitry Andric                            CI.getPreprocessorOutputOpts());
3160b57cec5SDimitry Andric 
3170b57cec5SDimitry Andric     (*OutputStream) << OS.str();
3180b57cec5SDimitry Andric   } else {
3190b57cec5SDimitry Andric     RewriteIncludesInInput(CI.getPreprocessor(), OutputStream.get(),
3200b57cec5SDimitry Andric                            CI.getPreprocessorOutputOpts());
3210b57cec5SDimitry Andric   }
3220b57cec5SDimitry Andric 
3230b57cec5SDimitry Andric   OutputStream.reset();
3240b57cec5SDimitry Andric }
325