FrontendActions.cpp revision ba5f6eced29937e4e4851a2c0980744768413d66
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/Frontend/FrontendActions.h" 11#include "clang/AST/ASTConsumer.h" 12#include "clang/Lex/Preprocessor.h" 13#include "clang/Parse/Parser.h" 14#include "clang/Basic/FileManager.h" 15#include "clang/Frontend/AnalysisConsumer.h" 16#include "clang/Frontend/ASTConsumers.h" 17#include "clang/Frontend/ASTUnit.h" 18#include "clang/Frontend/CompilerInstance.h" 19#include "clang/Frontend/FixItRewriter.h" 20#include "clang/Frontend/FrontendDiagnostic.h" 21#include "clang/Frontend/Utils.h" 22#include "llvm/ADT/OwningPtr.h" 23#include "llvm/Support/raw_ostream.h" 24using namespace clang; 25 26//===----------------------------------------------------------------------===// 27// Custom Actions 28//===----------------------------------------------------------------------===// 29 30ASTConsumer *InitOnlyAction::CreateASTConsumer(CompilerInstance &CI, 31 llvm::StringRef InFile) { 32 return new ASTConsumer(); 33} 34 35void InitOnlyAction::ExecuteAction() { 36} 37 38//===----------------------------------------------------------------------===// 39// AST Consumer Actions 40//===----------------------------------------------------------------------===// 41 42ASTConsumer *AnalysisAction::CreateASTConsumer(CompilerInstance &CI, 43 llvm::StringRef InFile) { 44 return CreateAnalysisConsumer(CI.getPreprocessor(), 45 CI.getFrontendOpts().OutputFile, 46 CI.getAnalyzerOpts()); 47} 48 49ASTConsumer *ASTPrintAction::CreateASTConsumer(CompilerInstance &CI, 50 llvm::StringRef InFile) { 51 if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile)) 52 return CreateASTPrinter(OS); 53 return 0; 54} 55 56ASTConsumer *ASTPrintXMLAction::CreateASTConsumer(CompilerInstance &CI, 57 llvm::StringRef InFile) { 58 if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, "xml")) 59 return CreateASTPrinterXML(OS); 60 return 0; 61} 62 63ASTConsumer *ASTDumpAction::CreateASTConsumer(CompilerInstance &CI, 64 llvm::StringRef InFile) { 65 return CreateASTDumper(); 66} 67 68ASTConsumer *ASTViewAction::CreateASTConsumer(CompilerInstance &CI, 69 llvm::StringRef InFile) { 70 return CreateASTViewer(); 71} 72 73ASTConsumer *DeclContextPrintAction::CreateASTConsumer(CompilerInstance &CI, 74 llvm::StringRef InFile) { 75 return CreateDeclContextPrinter(); 76} 77 78ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI, 79 llvm::StringRef InFile) { 80 const std::string &Sysroot = CI.getHeaderSearchOpts().Sysroot; 81 if (CI.getFrontendOpts().RelocatablePCH && 82 Sysroot.empty()) { 83 CI.getDiagnostics().Report(diag::err_relocatable_without_without_isysroot); 84 return 0; 85 } 86 87 llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, InFile); 88 if (!OS) 89 return 0; 90 91 if (CI.getFrontendOpts().RelocatablePCH) 92 return CreatePCHGenerator(CI.getPreprocessor(), OS, Sysroot.c_str()); 93 94 return CreatePCHGenerator(CI.getPreprocessor(), OS); 95} 96 97ASTConsumer *HTMLPrintAction::CreateASTConsumer(CompilerInstance &CI, 98 llvm::StringRef InFile) { 99 if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile)) 100 return CreateHTMLPrinter(OS, CI.getPreprocessor()); 101 return 0; 102} 103 104ASTConsumer *InheritanceViewAction::CreateASTConsumer(CompilerInstance &CI, 105 llvm::StringRef InFile) { 106 return CreateInheritanceViewer(CI.getFrontendOpts().ViewClassInheritance); 107} 108 109FixItAction::FixItAction() {} 110FixItAction::~FixItAction() {} 111 112ASTConsumer *FixItAction::CreateASTConsumer(CompilerInstance &CI, 113 llvm::StringRef InFile) { 114 return new ASTConsumer(); 115} 116 117class FixItActionSuffixInserter : public FixItPathRewriter { 118 std::string NewSuffix; 119 120public: 121 explicit FixItActionSuffixInserter(std::string NewSuffix) 122 : NewSuffix(NewSuffix) {} 123 124 std::string RewriteFilename(const std::string &Filename) { 125 llvm::sys::Path Path(Filename); 126 std::string Suffix = Path.getSuffix(); 127 Path.eraseSuffix(); 128 Path.appendSuffix(NewSuffix + "." + Suffix); 129 return Path.c_str(); 130 } 131}; 132 133bool FixItAction::BeginSourceFileAction(CompilerInstance &CI, 134 llvm::StringRef Filename) { 135 const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts(); 136 if (!FEOpts.FixItSuffix.empty()) { 137 PathRewriter.reset(new FixItActionSuffixInserter(FEOpts.FixItSuffix)); 138 } else { 139 PathRewriter.reset(); 140 } 141 Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(), 142 CI.getLangOpts(), PathRewriter.get())); 143 return true; 144} 145 146void FixItAction::EndSourceFileAction() { 147 // Otherwise rewrite all files. 148 Rewriter->WriteFixedFiles(); 149} 150 151ASTConsumer *RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI, 152 llvm::StringRef InFile) { 153 if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, "cpp")) 154 return CreateObjCRewriter(InFile, OS, 155 CI.getDiagnostics(), CI.getLangOpts(), 156 CI.getDiagnosticOpts().NoRewriteMacros); 157 return 0; 158} 159 160ASTConsumer *SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI, 161 llvm::StringRef InFile) { 162 return new ASTConsumer(); 163} 164 165//===----------------------------------------------------------------------===// 166// Preprocessor Actions 167//===----------------------------------------------------------------------===// 168 169void DumpRawTokensAction::ExecuteAction() { 170 Preprocessor &PP = getCompilerInstance().getPreprocessor(); 171 SourceManager &SM = PP.getSourceManager(); 172 173 // Start lexing the specified input file. 174 const llvm::MemoryBuffer *FromFile = SM.getBuffer(SM.getMainFileID()); 175 Lexer RawLex(SM.getMainFileID(), FromFile, SM, PP.getLangOptions()); 176 RawLex.SetKeepWhitespaceMode(true); 177 178 Token RawTok; 179 RawLex.LexFromRawLexer(RawTok); 180 while (RawTok.isNot(tok::eof)) { 181 PP.DumpToken(RawTok, true); 182 llvm::errs() << "\n"; 183 RawLex.LexFromRawLexer(RawTok); 184 } 185} 186 187void DumpTokensAction::ExecuteAction() { 188 Preprocessor &PP = getCompilerInstance().getPreprocessor(); 189 // Start preprocessing the specified input file. 190 Token Tok; 191 PP.EnterMainSourceFile(); 192 do { 193 PP.Lex(Tok); 194 PP.DumpToken(Tok, true); 195 llvm::errs() << "\n"; 196 } while (Tok.isNot(tok::eof)); 197} 198 199void GeneratePTHAction::ExecuteAction() { 200 CompilerInstance &CI = getCompilerInstance(); 201 if (CI.getFrontendOpts().OutputFile.empty() || 202 CI.getFrontendOpts().OutputFile == "-") { 203 // FIXME: Don't fail this way. 204 // FIXME: Verify that we can actually seek in the given file. 205 llvm::report_fatal_error("PTH requires a seekable file for output!"); 206 } 207 llvm::raw_fd_ostream *OS = 208 CI.createDefaultOutputFile(true, getCurrentFile()); 209 if (!OS) return; 210 211 CacheTokens(CI.getPreprocessor(), OS); 212} 213 214void ParseOnlyAction::ExecuteAction() { 215 Preprocessor &PP = getCompilerInstance().getPreprocessor(); 216 llvm::OwningPtr<Action> PA(new MinimalAction(PP)); 217 218 Parser P(PP, *PA); 219 PP.EnterMainSourceFile(); 220 P.ParseTranslationUnit(); 221} 222 223void PreprocessOnlyAction::ExecuteAction() { 224 Preprocessor &PP = getCompilerInstance().getPreprocessor(); 225 226 Token Tok; 227 // Start parsing the specified input file. 228 PP.EnterMainSourceFile(); 229 do { 230 PP.Lex(Tok); 231 } while (Tok.isNot(tok::eof)); 232} 233 234void PrintParseAction::ExecuteAction() { 235 CompilerInstance &CI = getCompilerInstance(); 236 Preprocessor &PP = getCompilerInstance().getPreprocessor(); 237 llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile()); 238 if (!OS) return; 239 240 llvm::OwningPtr<Action> PA(CreatePrintParserActionsAction(PP, OS)); 241 242 Parser P(PP, *PA); 243 PP.EnterMainSourceFile(); 244 P.ParseTranslationUnit(); 245} 246 247void PrintPreprocessedAction::ExecuteAction() { 248 CompilerInstance &CI = getCompilerInstance(); 249 // Output file needs to be set to 'Binary', to avoid converting Unix style 250 // line feeds (<LF>) to Microsoft style line feeds (<CR><LF>). 251 llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile()); 252 if (!OS) return; 253 254 DoPrintPreprocessedInput(CI.getPreprocessor(), OS, 255 CI.getPreprocessorOutputOpts()); 256} 257 258void RewriteMacrosAction::ExecuteAction() { 259 CompilerInstance &CI = getCompilerInstance(); 260 llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile()); 261 if (!OS) return; 262 263 RewriteMacrosInInput(CI.getPreprocessor(), OS); 264} 265 266void RewriteTestAction::ExecuteAction() { 267 CompilerInstance &CI = getCompilerInstance(); 268 llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile()); 269 if (!OS) return; 270 271 DoRewriteTest(CI.getPreprocessor(), OS); 272} 273