Home | History | Annotate | Download | only in Rewrite
      1 //===--- FrontendActions.cpp ----------------------------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #include "clang/Rewrite/Frontend/FrontendActions.h"
     11 #include "clang/AST/ASTConsumer.h"
     12 #include "clang/Basic/FileManager.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/Parse/Parser.h"
     19 #include "clang/Rewrite/Frontend/ASTConsumers.h"
     20 #include "clang/Rewrite/Frontend/FixItRewriter.h"
     21 #include "clang/Rewrite/Frontend/Rewriters.h"
     22 #include "llvm/Support/FileSystem.h"
     23 #include "llvm/Support/Path.h"
     24 #include "llvm/Support/raw_ostream.h"
     25 #include <memory>
     26 
     27 using namespace clang;
     28 
     29 //===----------------------------------------------------------------------===//
     30 // AST Consumer Actions
     31 //===----------------------------------------------------------------------===//
     32 
     33 std::unique_ptr<ASTConsumer>
     34 HTMLPrintAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
     35   if (raw_ostream *OS = CI.createDefaultOutputFile(false, InFile))
     36     return CreateHTMLPrinter(OS, CI.getPreprocessor());
     37   return nullptr;
     38 }
     39 
     40 FixItAction::FixItAction() {}
     41 FixItAction::~FixItAction() {}
     42 
     43 std::unique_ptr<ASTConsumer>
     44 FixItAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
     45   return llvm::make_unique<ASTConsumer>();
     46 }
     47 
     48 namespace {
     49 class FixItRewriteInPlace : public FixItOptions {
     50 public:
     51   FixItRewriteInPlace() { InPlace = true; }
     52 
     53   std::string RewriteFilename(const std::string &Filename, int &fd) override {
     54     llvm_unreachable("don't call RewriteFilename for inplace rewrites");
     55   }
     56 };
     57 
     58 class FixItActionSuffixInserter : public FixItOptions {
     59   std::string NewSuffix;
     60 
     61 public:
     62   FixItActionSuffixInserter(std::string NewSuffix, bool FixWhatYouCan)
     63     : NewSuffix(NewSuffix) {
     64       this->FixWhatYouCan = FixWhatYouCan;
     65   }
     66 
     67   std::string RewriteFilename(const std::string &Filename, int &fd) override {
     68     fd = -1;
     69     SmallString<128> Path(Filename);
     70     llvm::sys::path::replace_extension(Path,
     71       NewSuffix + llvm::sys::path::extension(Path));
     72     return Path.str();
     73   }
     74 };
     75 
     76 class FixItRewriteToTemp : public FixItOptions {
     77 public:
     78   std::string RewriteFilename(const std::string &Filename, int &fd) override {
     79     SmallString<128> Path;
     80     llvm::sys::fs::createTemporaryFile(llvm::sys::path::filename(Filename),
     81                                        llvm::sys::path::extension(Filename).drop_front(), fd,
     82                                        Path);
     83     return Path.str();
     84   }
     85 };
     86 } // end anonymous namespace
     87 
     88 bool FixItAction::BeginSourceFileAction(CompilerInstance &CI,
     89                                         StringRef Filename) {
     90   const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts();
     91   if (!FEOpts.FixItSuffix.empty()) {
     92     FixItOpts.reset(new FixItActionSuffixInserter(FEOpts.FixItSuffix,
     93                                                   FEOpts.FixWhatYouCan));
     94   } else {
     95     FixItOpts.reset(new FixItRewriteInPlace);
     96     FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan;
     97   }
     98   Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(),
     99                                    CI.getLangOpts(), FixItOpts.get()));
    100   return true;
    101 }
    102 
    103 void FixItAction::EndSourceFileAction() {
    104   // Otherwise rewrite all files.
    105   Rewriter->WriteFixedFiles();
    106 }
    107 
    108 bool FixItRecompile::BeginInvocation(CompilerInstance &CI) {
    109 
    110   std::vector<std::pair<std::string, std::string> > RewrittenFiles;
    111   bool err = false;
    112   {
    113     const FrontendOptions &FEOpts = CI.getFrontendOpts();
    114     std::unique_ptr<FrontendAction> FixAction(new SyntaxOnlyAction());
    115     if (FixAction->BeginSourceFile(CI, FEOpts.Inputs[0])) {
    116       std::unique_ptr<FixItOptions> FixItOpts;
    117       if (FEOpts.FixToTemporaries)
    118         FixItOpts.reset(new FixItRewriteToTemp());
    119       else
    120         FixItOpts.reset(new FixItRewriteInPlace());
    121       FixItOpts->Silent = true;
    122       FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan;
    123       FixItOpts->FixOnlyWarnings = FEOpts.FixOnlyWarnings;
    124       FixItRewriter Rewriter(CI.getDiagnostics(), CI.getSourceManager(),
    125                              CI.getLangOpts(), FixItOpts.get());
    126       FixAction->Execute();
    127 
    128       err = Rewriter.WriteFixedFiles(&RewrittenFiles);
    129 
    130       FixAction->EndSourceFile();
    131       CI.setSourceManager(nullptr);
    132       CI.setFileManager(nullptr);
    133     } else {
    134       err = true;
    135     }
    136   }
    137   if (err)
    138     return false;
    139   CI.getDiagnosticClient().clear();
    140   CI.getDiagnostics().Reset();
    141 
    142   PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
    143   PPOpts.RemappedFiles.insert(PPOpts.RemappedFiles.end(),
    144                               RewrittenFiles.begin(), RewrittenFiles.end());
    145   PPOpts.RemappedFilesKeepOriginalName = false;
    146 
    147   return true;
    148 }
    149 
    150 #ifdef CLANG_ENABLE_OBJC_REWRITER
    151 
    152 std::unique_ptr<ASTConsumer>
    153 RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
    154   if (raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, "cpp")) {
    155     if (CI.getLangOpts().ObjCRuntime.isNonFragile())
    156       return CreateModernObjCRewriter(InFile, OS,
    157                                 CI.getDiagnostics(), CI.getLangOpts(),
    158                                 CI.getDiagnosticOpts().NoRewriteMacros,
    159                                 (CI.getCodeGenOpts().getDebugInfo() !=
    160                                  CodeGenOptions::NoDebugInfo));
    161     return CreateObjCRewriter(InFile, OS,
    162                               CI.getDiagnostics(), CI.getLangOpts(),
    163                               CI.getDiagnosticOpts().NoRewriteMacros);
    164   }
    165   return nullptr;
    166 }
    167 
    168 #endif
    169 
    170 //===----------------------------------------------------------------------===//
    171 // Preprocessor Actions
    172 //===----------------------------------------------------------------------===//
    173 
    174 void RewriteMacrosAction::ExecuteAction() {
    175   CompilerInstance &CI = getCompilerInstance();
    176   raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile());
    177   if (!OS) return;
    178 
    179   RewriteMacrosInInput(CI.getPreprocessor(), OS);
    180 }
    181 
    182 void RewriteTestAction::ExecuteAction() {
    183   CompilerInstance &CI = getCompilerInstance();
    184   raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile());
    185   if (!OS) return;
    186 
    187   DoRewriteTest(CI.getPreprocessor(), OS);
    188 }
    189 
    190 void RewriteIncludesAction::ExecuteAction() {
    191   CompilerInstance &CI = getCompilerInstance();
    192   raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile());
    193   if (!OS) return;
    194 
    195   RewriteIncludesInInput(CI.getPreprocessor(), OS,
    196                          CI.getPreprocessorOutputOpts());
    197 }
    198