brintos

brintos / llvm-project-archived public Read only

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