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/ADT/OwningPtr.h"
     23 #include "llvm/Support/FileSystem.h"
     24 #include "llvm/Support/Path.h"
     25 #include "llvm/Support/raw_ostream.h"
     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 0;
     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) {
     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) {
     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) {
     78     SmallString<128> Path;
     79     Path = llvm::sys::path::filename(Filename);
     80     Path += "-%%%%%%%%";
     81     Path += llvm::sys::path::extension(Filename);
     82     SmallString<128> NewPath;
     83     llvm::sys::fs::unique_file(Path.str(), fd, NewPath);
     84     return NewPath.str();
     85   }
     86 };
     87 } // end anonymous namespace
     88 
     89 bool FixItAction::BeginSourceFileAction(CompilerInstance &CI,
     90                                         StringRef Filename) {
     91   const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts();
     92   if (!FEOpts.FixItSuffix.empty()) {
     93     FixItOpts.reset(new FixItActionSuffixInserter(FEOpts.FixItSuffix,
     94                                                   FEOpts.FixWhatYouCan));
     95   } else {
     96     FixItOpts.reset(new FixItRewriteInPlace);
     97     FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan;
     98   }
     99   Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(),
    100                                    CI.getLangOpts(), FixItOpts.get()));
    101   return true;
    102 }
    103 
    104 void FixItAction::EndSourceFileAction() {
    105   // Otherwise rewrite all files.
    106   Rewriter->WriteFixedFiles();
    107 }
    108 
    109 bool FixItRecompile::BeginInvocation(CompilerInstance &CI) {
    110 
    111   std::vector<std::pair<std::string, std::string> > RewrittenFiles;
    112   bool err = false;
    113   {
    114     const FrontendOptions &FEOpts = CI.getFrontendOpts();
    115     OwningPtr<FrontendAction> FixAction(new SyntaxOnlyAction());
    116     if (FixAction->BeginSourceFile(CI, FEOpts.Inputs[0])) {
    117       OwningPtr<FixItOptions> FixItOpts;
    118       if (FEOpts.FixToTemporaries)
    119         FixItOpts.reset(new FixItRewriteToTemp());
    120       else
    121         FixItOpts.reset(new FixItRewriteInPlace());
    122       FixItOpts->Silent = true;
    123       FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan;
    124       FixItOpts->FixOnlyWarnings = FEOpts.FixOnlyWarnings;
    125       FixItRewriter Rewriter(CI.getDiagnostics(), CI.getSourceManager(),
    126                              CI.getLangOpts(), FixItOpts.get());
    127       FixAction->Execute();
    128 
    129       err = Rewriter.WriteFixedFiles(&RewrittenFiles);
    130 
    131       FixAction->EndSourceFile();
    132       CI.setSourceManager(0);
    133       CI.setFileManager(0);
    134     } else {
    135       err = true;
    136     }
    137   }
    138   if (err)
    139     return false;
    140   CI.getDiagnosticClient().clear();
    141   CI.getDiagnostics().Reset();
    142 
    143   PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
    144   PPOpts.RemappedFiles.insert(PPOpts.RemappedFiles.end(),
    145                               RewrittenFiles.begin(), RewrittenFiles.end());
    146   PPOpts.RemappedFilesKeepOriginalName = false;
    147 
    148   return true;
    149 }
    150 
    151 //===----------------------------------------------------------------------===//
    152 // Preprocessor Actions
    153 //===----------------------------------------------------------------------===//
    154 
    155 ASTConsumer *RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI,
    156                                                   StringRef InFile) {
    157   if (raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, "cpp")) {
    158     if (CI.getLangOpts().ObjCRuntime.isNonFragile())
    159       return CreateModernObjCRewriter(InFile, OS,
    160                                 CI.getDiagnostics(), CI.getLangOpts(),
    161                                 CI.getDiagnosticOpts().NoRewriteMacros,
    162                                 (CI.getCodeGenOpts().getDebugInfo() !=
    163                                  CodeGenOptions::NoDebugInfo));
    164     return CreateObjCRewriter(InFile, OS,
    165                               CI.getDiagnostics(), CI.getLangOpts(),
    166                               CI.getDiagnosticOpts().NoRewriteMacros);
    167   }
    168   return 0;
    169 }
    170 
    171 void RewriteMacrosAction::ExecuteAction() {
    172   CompilerInstance &CI = getCompilerInstance();
    173   raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile());
    174   if (!OS) return;
    175 
    176   RewriteMacrosInInput(CI.getPreprocessor(), OS);
    177 }
    178 
    179 void RewriteTestAction::ExecuteAction() {
    180   CompilerInstance &CI = getCompilerInstance();
    181   raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile());
    182   if (!OS) return;
    183 
    184   DoRewriteTest(CI.getPreprocessor(), OS);
    185 }
    186 
    187 void RewriteIncludesAction::ExecuteAction() {
    188   CompilerInstance &CI = getCompilerInstance();
    189   raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile());
    190   if (!OS) return;
    191 
    192   RewriteIncludesInInput(CI.getPreprocessor(), OS,
    193                          CI.getPreprocessorOutputOpts());
    194 }
    195