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>
CreateASTConsumer(CompilerInstance & CI,StringRef InFile)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
FixItAction()480b57cec5SDimitry Andric FixItAction::FixItAction() {}
~FixItAction()490b57cec5SDimitry Andric FixItAction::~FixItAction() {}
500b57cec5SDimitry Andric
510b57cec5SDimitry Andric std::unique_ptr<ASTConsumer>
CreateASTConsumer(CompilerInstance & CI,StringRef InFile)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:
FixItRewriteInPlace()590b57cec5SDimitry Andric FixItRewriteInPlace() { InPlace = true; }
600b57cec5SDimitry Andric
RewriteFilename(const std::string & Filename,int & fd)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:
FixItActionSuffixInserter(std::string NewSuffix,bool FixWhatYouCan)700b57cec5SDimitry Andric FixItActionSuffixInserter(std::string NewSuffix, bool FixWhatYouCan)
710b57cec5SDimitry Andric : NewSuffix(std::move(NewSuffix)) {
720b57cec5SDimitry Andric this->FixWhatYouCan = FixWhatYouCan;
730b57cec5SDimitry Andric }
740b57cec5SDimitry Andric
RewriteFilename(const std::string & Filename,int & fd)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:
RewriteFilename(const std::string & Filename,int & fd)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
BeginSourceFileAction(CompilerInstance & CI)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
EndSourceFileAction()1100b57cec5SDimitry Andric void FixItAction::EndSourceFileAction() {
1110b57cec5SDimitry Andric // Otherwise rewrite all files.
1120b57cec5SDimitry Andric Rewriter->WriteFixedFiles();
1130b57cec5SDimitry Andric }
1140b57cec5SDimitry Andric
BeginInvocation(CompilerInstance & CI)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>
CreateASTConsumer(CompilerInstance & CI,StringRef InFile)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
ExecuteAction()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
ExecuteAction()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:
RewriteImportsListener(CompilerInstance & CI,std::shared_ptr<raw_ostream> Out)2110b57cec5SDimitry Andric RewriteImportsListener(CompilerInstance &CI, std::shared_ptr<raw_ostream> Out)
2120b57cec5SDimitry Andric : CI(CI), Out(Out) {}
2130b57cec5SDimitry Andric
visitModuleFile(StringRef Filename,serialization::ModuleKind Kind)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
BeginSourceFileAction(CompilerInstance & CI)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
ExecuteAction()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