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