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