Path: blob/main/contrib/llvm-project/clang/lib/Frontend/Rewrite/FrontendActions.cpp
35266 views
//===--- FrontendActions.cpp ----------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#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>3233using namespace clang;3435//===----------------------------------------------------------------------===//36// AST Consumer Actions37//===----------------------------------------------------------------------===//3839std::unique_ptr<ASTConsumer>40HTMLPrintAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {41if (std::unique_ptr<raw_ostream> OS =42CI.createDefaultOutputFile(false, InFile))43return CreateHTMLPrinter(std::move(OS), CI.getPreprocessor());44return nullptr;45}4647FixItAction::FixItAction() {}48FixItAction::~FixItAction() {}4950std::unique_ptr<ASTConsumer>51FixItAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {52return std::make_unique<ASTConsumer>();53}5455namespace {56class FixItRewriteInPlace : public FixItOptions {57public:58FixItRewriteInPlace() { InPlace = true; }5960std::string RewriteFilename(const std::string &Filename, int &fd) override {61llvm_unreachable("don't call RewriteFilename for inplace rewrites");62}63};6465class FixItActionSuffixInserter : public FixItOptions {66std::string NewSuffix;6768public:69FixItActionSuffixInserter(std::string NewSuffix, bool FixWhatYouCan)70: NewSuffix(std::move(NewSuffix)) {71this->FixWhatYouCan = FixWhatYouCan;72}7374std::string RewriteFilename(const std::string &Filename, int &fd) override {75fd = -1;76SmallString<128> Path(Filename);77llvm::sys::path::replace_extension(Path,78NewSuffix + llvm::sys::path::extension(Path));79return std::string(Path);80}81};8283class FixItRewriteToTemp : public FixItOptions {84public:85std::string RewriteFilename(const std::string &Filename, int &fd) override {86SmallString<128> Path;87llvm::sys::fs::createTemporaryFile(llvm::sys::path::filename(Filename),88llvm::sys::path::extension(Filename).drop_front(), fd,89Path);90return std::string(Path);91}92};93} // end anonymous namespace9495bool FixItAction::BeginSourceFileAction(CompilerInstance &CI) {96const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts();97if (!FEOpts.FixItSuffix.empty()) {98FixItOpts.reset(new FixItActionSuffixInserter(FEOpts.FixItSuffix,99FEOpts.FixWhatYouCan));100} else {101FixItOpts.reset(new FixItRewriteInPlace);102FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan;103}104Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(),105CI.getLangOpts(), FixItOpts.get()));106return true;107}108109void FixItAction::EndSourceFileAction() {110// Otherwise rewrite all files.111Rewriter->WriteFixedFiles();112}113114bool FixItRecompile::BeginInvocation(CompilerInstance &CI) {115116std::vector<std::pair<std::string, std::string> > RewrittenFiles;117bool err = false;118{119const FrontendOptions &FEOpts = CI.getFrontendOpts();120std::unique_ptr<FrontendAction> FixAction(new SyntaxOnlyAction());121if (FixAction->BeginSourceFile(CI, FEOpts.Inputs[0])) {122std::unique_ptr<FixItOptions> FixItOpts;123if (FEOpts.FixToTemporaries)124FixItOpts.reset(new FixItRewriteToTemp());125else126FixItOpts.reset(new FixItRewriteInPlace());127FixItOpts->Silent = true;128FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan;129FixItOpts->FixOnlyWarnings = FEOpts.FixOnlyWarnings;130FixItRewriter Rewriter(CI.getDiagnostics(), CI.getSourceManager(),131CI.getLangOpts(), FixItOpts.get());132if (llvm::Error Err = FixAction->Execute()) {133// FIXME this drops the error on the floor.134consumeError(std::move(Err));135return false;136}137138err = Rewriter.WriteFixedFiles(&RewrittenFiles);139140FixAction->EndSourceFile();141CI.setSourceManager(nullptr);142CI.setFileManager(nullptr);143} else {144err = true;145}146}147if (err)148return false;149CI.getDiagnosticClient().clear();150CI.getDiagnostics().Reset();151152PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();153PPOpts.RemappedFiles.insert(PPOpts.RemappedFiles.end(),154RewrittenFiles.begin(), RewrittenFiles.end());155PPOpts.RemappedFilesKeepOriginalName = false;156157return true;158}159160#if CLANG_ENABLE_OBJC_REWRITER161162std::unique_ptr<ASTConsumer>163RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {164if (std::unique_ptr<raw_ostream> OS =165CI.createDefaultOutputFile(false, InFile, "cpp")) {166if (CI.getLangOpts().ObjCRuntime.isNonFragile())167return CreateModernObjCRewriter(std::string(InFile), std::move(OS),168CI.getDiagnostics(), CI.getLangOpts(),169CI.getDiagnosticOpts().NoRewriteMacros,170(CI.getCodeGenOpts().getDebugInfo() !=171llvm::codegenoptions::NoDebugInfo));172return CreateObjCRewriter(std::string(InFile), std::move(OS),173CI.getDiagnostics(), CI.getLangOpts(),174CI.getDiagnosticOpts().NoRewriteMacros);175}176return nullptr;177}178179#endif180181//===----------------------------------------------------------------------===//182// Preprocessor Actions183//===----------------------------------------------------------------------===//184185void RewriteMacrosAction::ExecuteAction() {186CompilerInstance &CI = getCompilerInstance();187std::unique_ptr<raw_ostream> OS =188CI.createDefaultOutputFile(/*Binary=*/true, getCurrentFileOrBufferName());189if (!OS) return;190191RewriteMacrosInInput(CI.getPreprocessor(), OS.get());192}193194void RewriteTestAction::ExecuteAction() {195CompilerInstance &CI = getCompilerInstance();196std::unique_ptr<raw_ostream> OS =197CI.createDefaultOutputFile(/*Binary=*/false, getCurrentFileOrBufferName());198if (!OS) return;199200DoRewriteTest(CI.getPreprocessor(), OS.get());201}202203class RewriteIncludesAction::RewriteImportsListener : public ASTReaderListener {204CompilerInstance &CI;205std::weak_ptr<raw_ostream> Out;206207llvm::DenseSet<const FileEntry*> Rewritten;208209public:210RewriteImportsListener(CompilerInstance &CI, std::shared_ptr<raw_ostream> Out)211: CI(CI), Out(Out) {}212213void visitModuleFile(StringRef Filename,214serialization::ModuleKind Kind) override {215auto File = CI.getFileManager().getFile(Filename);216assert(File && "missing file for loaded module?");217218// Only rewrite each module file once.219if (!Rewritten.insert(*File).second)220return;221222serialization::ModuleFile *MF =223CI.getASTReader()->getModuleManager().lookup(*File);224assert(MF && "missing module file for loaded module?");225226// Not interested in PCH / preambles.227if (!MF->isModule())228return;229230auto OS = Out.lock();231assert(OS && "loaded module file after finishing rewrite action?");232233(*OS) << "#pragma clang module build ";234if (isValidAsciiIdentifier(MF->ModuleName))235(*OS) << MF->ModuleName;236else {237(*OS) << '"';238OS->write_escaped(MF->ModuleName);239(*OS) << '"';240}241(*OS) << '\n';242243// Rewrite the contents of the module in a separate compiler instance.244CompilerInstance Instance(CI.getPCHContainerOperations(),245&CI.getModuleCache());246Instance.setInvocation(247std::make_shared<CompilerInvocation>(CI.getInvocation()));248Instance.createDiagnostics(249new ForwardingDiagnosticConsumer(CI.getDiagnosticClient()),250/*ShouldOwnClient=*/true);251Instance.getFrontendOpts().DisableFree = false;252Instance.getFrontendOpts().Inputs.clear();253Instance.getFrontendOpts().Inputs.emplace_back(254Filename, InputKind(Language::Unknown, InputKind::Precompiled));255Instance.getFrontendOpts().ModuleFiles.clear();256Instance.getFrontendOpts().ModuleMapFiles.clear();257// Don't recursively rewrite imports. We handle them all at the top level.258Instance.getPreprocessorOutputOpts().RewriteImports = false;259260llvm::CrashRecoveryContext().RunSafelyOnThread([&]() {261RewriteIncludesAction Action;262Action.OutputStream = OS;263Instance.ExecuteAction(Action);264});265266(*OS) << "#pragma clang module endbuild /*" << MF->ModuleName << "*/\n";267}268};269270bool RewriteIncludesAction::BeginSourceFileAction(CompilerInstance &CI) {271if (!OutputStream) {272OutputStream =273CI.createDefaultOutputFile(/*Binary=*/true, getCurrentFileOrBufferName());274if (!OutputStream)275return false;276}277278auto &OS = *OutputStream;279280// If we're preprocessing a module map, start by dumping the contents of the281// module itself before switching to the input buffer.282auto &Input = getCurrentInput();283if (Input.getKind().getFormat() == InputKind::ModuleMap) {284if (Input.isFile()) {285OS << "# 1 \"";286OS.write_escaped(Input.getFile());287OS << "\"\n";288}289getCurrentModule()->print(OS);290OS << "#pragma clang module contents\n";291}292293// If we're rewriting imports, set up a listener to track when we import294// module files.295if (CI.getPreprocessorOutputOpts().RewriteImports) {296CI.createASTReader();297CI.getASTReader()->addListener(298std::make_unique<RewriteImportsListener>(CI, OutputStream));299}300301return true;302}303304void RewriteIncludesAction::ExecuteAction() {305CompilerInstance &CI = getCompilerInstance();306307// If we're rewriting imports, emit the module build output first rather308// than switching back and forth (potentially in the middle of a line).309if (CI.getPreprocessorOutputOpts().RewriteImports) {310std::string Buffer;311llvm::raw_string_ostream OS(Buffer);312313RewriteIncludesInInput(CI.getPreprocessor(), &OS,314CI.getPreprocessorOutputOpts());315316(*OutputStream) << OS.str();317} else {318RewriteIncludesInInput(CI.getPreprocessor(), OutputStream.get(),319CI.getPreprocessorOutputOpts());320}321322OutputStream.reset();323}324325326