FrontendActions.cpp revision e127a0d80155b45dafe77f2b4380e5fa111a3345
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 *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI, 78 llvm::StringRef InFile) { 79 const std::string &Sysroot = CI.getHeaderSearchOpts().Sysroot; 80 if (CI.getFrontendOpts().RelocatablePCH && 81 Sysroot.empty()) { 82 CI.getDiagnostics().Report(diag::err_relocatable_without_without_isysroot); 83 return 0; 84 } 85 86 llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, InFile); 87 if (!OS) 88 return 0; 89 90 if (CI.getFrontendOpts().RelocatablePCH) 91 return CreatePCHGenerator(CI.getPreprocessor(), OS, Sysroot.c_str()); 92 93 return CreatePCHGenerator(CI.getPreprocessor(), OS); 94} 95 96ASTConsumer *HTMLPrintAction::CreateASTConsumer(CompilerInstance &CI, 97 llvm::StringRef InFile) { 98 if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile)) 99 return CreateHTMLPrinter(OS, CI.getPreprocessor()); 100 return 0; 101} 102 103ASTConsumer *InheritanceViewAction::CreateASTConsumer(CompilerInstance &CI, 104 llvm::StringRef InFile) { 105 return CreateInheritanceViewer(CI.getFrontendOpts().ViewClassInheritance); 106} 107 108FixItAction::FixItAction() {} 109FixItAction::~FixItAction() {} 110 111ASTConsumer *FixItAction::CreateASTConsumer(CompilerInstance &CI, 112 llvm::StringRef InFile) { 113 return new ASTConsumer(); 114} 115 116/// AddFixItLocations - Add any individual user specified "fix-it" locations, 117/// and return true on success. 118static bool AddFixItLocations(CompilerInstance &CI, 119 FixItRewriter &FixItRewrite) { 120 const std::vector<ParsedSourceLocation> &Locs = 121 CI.getFrontendOpts().FixItLocations; 122 for (unsigned i = 0, e = Locs.size(); i != e; ++i) { 123 const FileEntry *File = CI.getFileManager().getFile(Locs[i].FileName); 124 if (!File) { 125 CI.getDiagnostics().Report(diag::err_fe_unable_to_find_fixit_file) 126 << Locs[i].FileName; 127 return false; 128 } 129 130 RequestedSourceLocation Requested; 131 Requested.File = File; 132 Requested.Line = Locs[i].Line; 133 Requested.Column = Locs[i].Column; 134 FixItRewrite.addFixItLocation(Requested); 135 } 136 137 const std::string &OutputFile = CI.getFrontendOpts().OutputFile; 138 if (Locs.empty() && !OutputFile.empty()) { 139 // FIXME: we will issue "FIX-IT applied suggested code changes" for every 140 // input, but only the main file will actually be rewritten. 141 const std::vector<std::pair<FrontendOptions::InputKind, std::string> > &Inputs = 142 CI.getFrontendOpts().Inputs; 143 for (unsigned i = 0, e = Inputs.size(); i != e; ++i) { 144 const FileEntry *File = CI.getFileManager().getFile(Inputs[i].second); 145 assert(File && "Input file not found in FileManager"); 146 RequestedSourceLocation Requested; 147 Requested.File = File; 148 Requested.Line = 0; 149 Requested.Column = 0; 150 FixItRewrite.addFixItLocation(Requested); 151 } 152 } 153 154 return true; 155} 156 157bool FixItAction::BeginSourceFileAction(CompilerInstance &CI, 158 llvm::StringRef Filename) { 159 Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(), 160 CI.getLangOpts())); 161 if (!AddFixItLocations(CI, *Rewriter)) 162 return false; 163 164 return true; 165} 166 167void FixItAction::EndSourceFileAction() { 168 const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts(); 169 if (!FEOpts.OutputFile.empty()) { 170 // When called with 'clang -fixit -o filename' output only the main file. 171 172 const SourceManager &SM = getCompilerInstance().getSourceManager(); 173 FileID MainFileID = SM.getMainFileID(); 174 if (!Rewriter->IsModified(MainFileID)) { 175 getCompilerInstance().getDiagnostics().Report( 176 diag::note_fixit_main_file_unchanged); 177 return; 178 } 179 180 llvm::OwningPtr<llvm::raw_ostream> OwnedStream; 181 llvm::raw_ostream *OutFile; 182 if (FEOpts.OutputFile == "-") { 183 OutFile = &llvm::outs(); 184 } else { 185 std::string Err; 186 OutFile = new llvm::raw_fd_ostream(FEOpts.OutputFile.c_str(), Err, 187 llvm::raw_fd_ostream::F_Binary); 188 OwnedStream.reset(OutFile); 189 } 190 191 Rewriter->WriteFixedFile(MainFileID, *OutFile); 192 return; 193 } 194 195 // Otherwise rewrite all files. 196 Rewriter->WriteFixedFiles(); 197} 198 199ASTConsumer *RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI, 200 llvm::StringRef InFile) { 201 if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, "cpp")) 202 return CreateObjCRewriter(InFile, OS, 203 CI.getDiagnostics(), CI.getLangOpts(), 204 CI.getDiagnosticOpts().NoRewriteMacros); 205 return 0; 206} 207 208ASTConsumer *SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI, 209 llvm::StringRef InFile) { 210 return new ASTConsumer(); 211} 212 213//===----------------------------------------------------------------------===// 214// Preprocessor Actions 215//===----------------------------------------------------------------------===// 216 217void DumpRawTokensAction::ExecuteAction() { 218 Preprocessor &PP = getCompilerInstance().getPreprocessor(); 219 SourceManager &SM = PP.getSourceManager(); 220 221 // Start lexing the specified input file. 222 const llvm::MemoryBuffer *FromFile = SM.getBuffer(SM.getMainFileID()); 223 Lexer RawLex(SM.getMainFileID(), FromFile, SM, PP.getLangOptions()); 224 RawLex.SetKeepWhitespaceMode(true); 225 226 Token RawTok; 227 RawLex.LexFromRawLexer(RawTok); 228 while (RawTok.isNot(tok::eof)) { 229 PP.DumpToken(RawTok, true); 230 llvm::errs() << "\n"; 231 RawLex.LexFromRawLexer(RawTok); 232 } 233} 234 235void DumpTokensAction::ExecuteAction() { 236 Preprocessor &PP = getCompilerInstance().getPreprocessor(); 237 // Start preprocessing the specified input file. 238 Token Tok; 239 PP.EnterMainSourceFile(); 240 do { 241 PP.Lex(Tok); 242 PP.DumpToken(Tok, true); 243 llvm::errs() << "\n"; 244 } while (Tok.isNot(tok::eof)); 245} 246 247void GeneratePTHAction::ExecuteAction() { 248 CompilerInstance &CI = getCompilerInstance(); 249 if (CI.getFrontendOpts().OutputFile.empty() || 250 CI.getFrontendOpts().OutputFile == "-") { 251 // FIXME: Don't fail this way. 252 // FIXME: Verify that we can actually seek in the given file. 253 llvm::report_fatal_error("PTH requires a seekable file for output!"); 254 } 255 llvm::raw_fd_ostream *OS = 256 CI.createDefaultOutputFile(true, getCurrentFile()); 257 if (!OS) return; 258 259 CacheTokens(CI.getPreprocessor(), OS); 260} 261 262void ParseOnlyAction::ExecuteAction() { 263 Preprocessor &PP = getCompilerInstance().getPreprocessor(); 264 llvm::OwningPtr<Action> PA(new MinimalAction(PP)); 265 266 Parser P(PP, *PA); 267 PP.EnterMainSourceFile(); 268 P.ParseTranslationUnit(); 269} 270 271void PreprocessOnlyAction::ExecuteAction() { 272 Preprocessor &PP = getCompilerInstance().getPreprocessor(); 273 274 Token Tok; 275 // Start parsing the specified input file. 276 PP.EnterMainSourceFile(); 277 do { 278 PP.Lex(Tok); 279 } while (Tok.isNot(tok::eof)); 280} 281 282void PrintParseAction::ExecuteAction() { 283 CompilerInstance &CI = getCompilerInstance(); 284 Preprocessor &PP = getCompilerInstance().getPreprocessor(); 285 llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile()); 286 if (!OS) return; 287 288 llvm::OwningPtr<Action> PA(CreatePrintParserActionsAction(PP, OS)); 289 290 Parser P(PP, *PA); 291 PP.EnterMainSourceFile(); 292 P.ParseTranslationUnit(); 293} 294 295void PrintPreprocessedAction::ExecuteAction() { 296 CompilerInstance &CI = getCompilerInstance(); 297 // Output file needs to be set to 'Binary', to avoid converting Unix style 298 // line feeds (<LF>) to Microsoft style line feeds (<CR><LF>). 299 llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile()); 300 if (!OS) return; 301 302 DoPrintPreprocessedInput(CI.getPreprocessor(), OS, 303 CI.getPreprocessorOutputOpts()); 304} 305 306void RewriteMacrosAction::ExecuteAction() { 307 CompilerInstance &CI = getCompilerInstance(); 308 llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile()); 309 if (!OS) return; 310 311 RewriteMacrosInInput(CI.getPreprocessor(), OS); 312} 313 314void RewriteTestAction::ExecuteAction() { 315 CompilerInstance &CI = getCompilerInstance(); 316 llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile()); 317 if (!OS) return; 318 319 DoRewriteTest(CI.getPreprocessor(), OS); 320} 321