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 27using namespace clang; 28 29//===----------------------------------------------------------------------===// 30// AST Consumer Actions 31//===----------------------------------------------------------------------===// 32 33std::unique_ptr<ASTConsumer> 34HTMLPrintAction::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 40FixItAction::FixItAction() {} 41FixItAction::~FixItAction() {} 42 43std::unique_ptr<ASTConsumer> 44FixItAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { 45 return llvm::make_unique<ASTConsumer>(); 46} 47 48namespace { 49class FixItRewriteInPlace : public FixItOptions { 50public: 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 58class FixItActionSuffixInserter : public FixItOptions { 59 std::string NewSuffix; 60 61public: 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 76class FixItRewriteToTemp : public FixItOptions { 77public: 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 88bool 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 103void FixItAction::EndSourceFileAction() { 104 // Otherwise rewrite all files. 105 Rewriter->WriteFixedFiles(); 106} 107 108bool 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 152std::unique_ptr<ASTConsumer> 153RewriteObjCAction::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 174void 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 182void 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 190void 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