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