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 (raw_ostream *OS = CI.createDefaultOutputFile(false, InFile)) 37 return CreateHTMLPrinter(OS, CI.getPreprocessor()); 38 return nullptr; 39 } 40 41 FixItAction::FixItAction() {} 42 FixItAction::~FixItAction() {} 43 44 std::unique_ptr<ASTConsumer> 45 FixItAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { 46 return llvm::make_unique<ASTConsumer>(); 47 } 48 49 namespace { 50 class FixItRewriteInPlace : public FixItOptions { 51 public: 52 FixItRewriteInPlace() { InPlace = true; } 53 54 std::string RewriteFilename(const std::string &Filename, int &fd) override { 55 llvm_unreachable("don't call RewriteFilename for inplace rewrites"); 56 } 57 }; 58 59 class FixItActionSuffixInserter : public FixItOptions { 60 std::string NewSuffix; 61 62 public: 63 FixItActionSuffixInserter(std::string NewSuffix, bool FixWhatYouCan) 64 : NewSuffix(std::move(NewSuffix)) { 65 this->FixWhatYouCan = FixWhatYouCan; 66 } 67 68 std::string RewriteFilename(const std::string &Filename, int &fd) override { 69 fd = -1; 70 SmallString<128> Path(Filename); 71 llvm::sys::path::replace_extension(Path, 72 NewSuffix + llvm::sys::path::extension(Path)); 73 return Path.str(); 74 } 75 }; 76 77 class FixItRewriteToTemp : public FixItOptions { 78 public: 79 std::string RewriteFilename(const std::string &Filename, int &fd) override { 80 SmallString<128> Path; 81 llvm::sys::fs::createTemporaryFile(llvm::sys::path::filename(Filename), 82 llvm::sys::path::extension(Filename).drop_front(), fd, 83 Path); 84 return Path.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 std::unique_ptr<FrontendAction> FixAction(new SyntaxOnlyAction()); 116 if (FixAction->BeginSourceFile(CI, FEOpts.Inputs[0])) { 117 std::unique_ptr<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(nullptr); 133 CI.setFileManager(nullptr); 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 #ifdef CLANG_ENABLE_OBJC_REWRITER 152 153 std::unique_ptr<ASTConsumer> 154 RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { 155 if (raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, "cpp")) { 156 if (CI.getLangOpts().ObjCRuntime.isNonFragile()) 157 return CreateModernObjCRewriter( 158 InFile, OS, CI.getDiagnostics(), CI.getLangOpts(), 159 CI.getDiagnosticOpts().NoRewriteMacros, 160 (CI.getCodeGenOpts().getDebugInfo() != 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