Home | History | Annotate | Download | only in Frontend
      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 ASTConsumer *HTMLPrintAction::CreateASTConsumer(CompilerInstance &CI,
     34                                                 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 ASTConsumer *FixItAction::CreateASTConsumer(CompilerInstance &CI,
     44                                             StringRef InFile) {
     45   return new ASTConsumer();
     46 }
     47 
     48 namespace {
     49 class FixItRewriteInPlace : public FixItOptions {
     50 public:
     51   std::string RewriteFilename(const std::string &Filename, int &fd) override {
     52     fd = -1;
     53     return Filename;
     54   }
     55 };
     56 
     57 class FixItActionSuffixInserter : public FixItOptions {
     58   std::string NewSuffix;
     59 
     60 public:
     61   FixItActionSuffixInserter(std::string NewSuffix, bool FixWhatYouCan)
     62     : NewSuffix(NewSuffix) {
     63       this->FixWhatYouCan = FixWhatYouCan;
     64   }
     65 
     66   std::string RewriteFilename(const std::string &Filename, int &fd) override {
     67     fd = -1;
     68     SmallString<128> Path(Filename);
     69     llvm::sys::path::replace_extension(Path,
     70       NewSuffix + llvm::sys::path::extension(Path));
     71     return Path.str();
     72   }
     73 };
     74 
     75 class FixItRewriteToTemp : public FixItOptions {
     76 public:
     77   std::string RewriteFilename(const std::string &Filename, int &fd) override {
     78     SmallString<128> Path;
     79     llvm::sys::fs::createTemporaryFile(llvm::sys::path::filename(Filename),
     80                                        llvm::sys::path::extension(Filename), fd,
     81                                        Path);
     82     return Path.str();
     83   }
     84 };
     85 } // end anonymous namespace
     86 
     87 bool FixItAction::BeginSourceFileAction(CompilerInstance &CI,
     88                                         StringRef Filename) {
     89   const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts();
     90   if (!FEOpts.FixItSuffix.empty()) {
     91     FixItOpts.reset(new FixItActionSuffixInserter(FEOpts.FixItSuffix,
     92                                                   FEOpts.FixWhatYouCan));
     93   } else {
     94     FixItOpts.reset(new FixItRewriteInPlace);
     95     FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan;
     96   }
     97   Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(),
     98                                    CI.getLangOpts(), FixItOpts.get()));
     99   return true;
    100 }
    101 
    102 void FixItAction::EndSourceFileAction() {
    103   // Otherwise rewrite all files.
    104   Rewriter->WriteFixedFiles();
    105 }
    106 
    107 bool FixItRecompile::BeginInvocation(CompilerInstance &CI) {
    108 
    109   std::vector<std::pair<std::string, std::string> > RewrittenFiles;
    110   bool err = false;
    111   {
    112     const FrontendOptions &FEOpts = CI.getFrontendOpts();
    113     std::unique_ptr<FrontendAction> FixAction(new SyntaxOnlyAction());
    114     if (FixAction->BeginSourceFile(CI, FEOpts.Inputs[0])) {
    115       std::unique_ptr<FixItOptions> FixItOpts;
    116       if (FEOpts.FixToTemporaries)
    117         FixItOpts.reset(new FixItRewriteToTemp());
    118       else
    119         FixItOpts.reset(new FixItRewriteInPlace());
    120       FixItOpts->Silent = true;
    121       FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan;
    122       FixItOpts->FixOnlyWarnings = FEOpts.FixOnlyWarnings;
    123       FixItRewriter Rewriter(CI.getDiagnostics(), CI.getSourceManager(),
    124                              CI.getLangOpts(), FixItOpts.get());
    125       FixAction->Execute();
    126 
    127       err = Rewriter.WriteFixedFiles(&RewrittenFiles);
    128 
    129       FixAction->EndSourceFile();
    130       CI.setSourceManager(nullptr);
    131       CI.setFileManager(nullptr);
    132     } else {
    133       err = true;
    134     }
    135   }
    136   if (err)
    137     return false;
    138   CI.getDiagnosticClient().clear();
    139   CI.getDiagnostics().Reset();
    140 
    141   PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
    142   PPOpts.RemappedFiles.insert(PPOpts.RemappedFiles.end(),
    143                               RewrittenFiles.begin(), RewrittenFiles.end());
    144   PPOpts.RemappedFilesKeepOriginalName = false;
    145 
    146   return true;
    147 }
    148 
    149 //===----------------------------------------------------------------------===//
    150 // Preprocessor Actions
    151 //===----------------------------------------------------------------------===//
    152 
    153 ASTConsumer *RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI,
    154                                                   StringRef InFile) {
    155   if (raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, "cpp")) {
    156     if (CI.getLangOpts().ObjCRuntime.isNonFragile())
    157       return CreateModernObjCRewriter(InFile, OS,
    158                                 CI.getDiagnostics(), CI.getLangOpts(),
    159                                 CI.getDiagnosticOpts().NoRewriteMacros,
    160                                 (CI.getCodeGenOpts().getDebugInfo() !=
    161                                  CodeGenOptions::NoDebugInfo));
    162     return CreateObjCRewriter(InFile, OS,
    163                               CI.getDiagnostics(), CI.getLangOpts(),
    164                               CI.getDiagnosticOpts().NoRewriteMacros);
    165   }
    166   return nullptr;
    167 }
    168 
    169 void RewriteMacrosAction::ExecuteAction() {
    170   CompilerInstance &CI = getCompilerInstance();
    171   raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile());
    172   if (!OS) return;
    173 
    174   RewriteMacrosInInput(CI.getPreprocessor(), OS);
    175 }
    176 
    177 void RewriteTestAction::ExecuteAction() {
    178   CompilerInstance &CI = getCompilerInstance();
    179   raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile());
    180   if (!OS) return;
    181 
    182   DoRewriteTest(CI.getPreprocessor(), OS);
    183 }
    184 
    185 void RewriteIncludesAction::ExecuteAction() {
    186   CompilerInstance &CI = getCompilerInstance();
    187   raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile());
    188   if (!OS) return;
    189 
    190   RewriteIncludesInInput(CI.getPreprocessor(), OS,
    191                          CI.getPreprocessorOutputOpts());
    192 }
    193