| Daniel Dunbar | 4ee2409 | 2009-11-14 10:42:35 +0000 | [diff] [blame] | 1 | //===--- FrontendAction.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/FrontendAction.h" | 
|  | 11 | #include "clang/AST/ASTContext.h" | 
|  | 12 | #include "clang/Lex/HeaderSearch.h" | 
|  | 13 | #include "clang/Lex/Preprocessor.h" | 
|  | 14 | #include "clang/Frontend/ASTUnit.h" | 
|  | 15 | #include "clang/Frontend/CompilerInstance.h" | 
|  | 16 | #include "clang/Frontend/FrontendDiagnostic.h" | 
|  | 17 | #include "clang/Sema/ParseAST.h" | 
|  | 18 | #include "llvm/Support/MemoryBuffer.h" | 
|  | 19 | #include "llvm/Support/Timer.h" | 
|  | 20 | #include "llvm/Support/ErrorHandling.h" | 
|  | 21 | #include "llvm/Support/raw_ostream.h" | 
|  | 22 | using namespace clang; | 
|  | 23 |  | 
| Kovarththanan Rajaratnam | f79bafa | 2009-11-29 09:57:35 +0000 | [diff] [blame] | 24 | FrontendAction::FrontendAction() : Instance(0) {} | 
| Daniel Dunbar | 4ee2409 | 2009-11-14 10:42:35 +0000 | [diff] [blame] | 25 |  | 
|  | 26 | FrontendAction::~FrontendAction() {} | 
|  | 27 |  | 
|  | 28 | void FrontendAction::setCurrentFile(llvm::StringRef Value, ASTUnit *AST) { | 
|  | 29 | CurrentFile = Value; | 
|  | 30 | CurrentASTUnit.reset(AST); | 
|  | 31 | } | 
|  | 32 |  | 
|  | 33 | bool FrontendAction::BeginSourceFile(CompilerInstance &CI, | 
|  | 34 | llvm::StringRef Filename, | 
|  | 35 | bool IsAST) { | 
|  | 36 | assert(!Instance && "Already processing a source file!"); | 
|  | 37 | assert(!Filename.empty() && "Unexpected empty filename!"); | 
|  | 38 | setCurrentFile(Filename); | 
|  | 39 | setCompilerInstance(&CI); | 
|  | 40 |  | 
|  | 41 | // AST files follow a very different path, since they share objects via the | 
|  | 42 | // AST unit. | 
|  | 43 | if (IsAST) { | 
|  | 44 | assert(!usesPreprocessorOnly() && | 
|  | 45 | "Attempt to pass AST file to preprocessor only action!"); | 
|  | 46 | assert(hasASTSupport() && "This action does not have AST support!"); | 
|  | 47 |  | 
|  | 48 | std::string Error; | 
| Daniel Dunbar | 5262fda | 2009-12-03 01:45:44 +0000 | [diff] [blame] | 49 | ASTUnit *AST = ASTUnit::LoadFromPCHFile(Filename, CI.getDiagnostics()); | 
|  | 50 | if (!AST) | 
| Daniel Dunbar | 4ee2409 | 2009-11-14 10:42:35 +0000 | [diff] [blame] | 51 | goto failure; | 
| Daniel Dunbar | 4ee2409 | 2009-11-14 10:42:35 +0000 | [diff] [blame] | 52 |  | 
|  | 53 | setCurrentFile(Filename, AST); | 
|  | 54 |  | 
|  | 55 | // Set the shared objects, these are reset when we finish processing the | 
|  | 56 | // file, otherwise the CompilerInstance will happily destroy them. | 
|  | 57 | CI.setFileManager(&AST->getFileManager()); | 
|  | 58 | CI.setSourceManager(&AST->getSourceManager()); | 
|  | 59 | CI.setPreprocessor(&AST->getPreprocessor()); | 
|  | 60 | CI.setASTContext(&AST->getASTContext()); | 
|  | 61 |  | 
|  | 62 | // Initialize the action. | 
|  | 63 | if (!BeginSourceFileAction(CI, Filename)) | 
|  | 64 | goto failure; | 
|  | 65 |  | 
|  | 66 | /// Create the AST consumer. | 
|  | 67 | CI.setASTConsumer(CreateASTConsumer(CI, Filename)); | 
|  | 68 | if (!CI.hasASTConsumer()) | 
|  | 69 | goto failure; | 
|  | 70 |  | 
|  | 71 | return true; | 
|  | 72 | } | 
|  | 73 |  | 
|  | 74 | // Inform the diagnostic client we are processing a source file. | 
|  | 75 | CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(), | 
|  | 76 | &CI.getPreprocessor()); | 
|  | 77 |  | 
|  | 78 | // Initialize the action. | 
|  | 79 | if (!BeginSourceFileAction(CI, Filename)) | 
|  | 80 | goto failure; | 
|  | 81 |  | 
|  | 82 | /// Create the AST context and consumer unless this is a preprocessor only | 
|  | 83 | /// action. | 
|  | 84 | if (!usesPreprocessorOnly()) { | 
|  | 85 | CI.createASTContext(); | 
|  | 86 | CI.setASTConsumer(CreateASTConsumer(CI, Filename)); | 
|  | 87 | if (!CI.hasASTConsumer()) | 
|  | 88 | goto failure; | 
|  | 89 |  | 
|  | 90 | /// Use PCH? | 
| Daniel Dunbar | 049d3a0 | 2009-11-17 05:52:41 +0000 | [diff] [blame] | 91 | if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) { | 
| Daniel Dunbar | 4ee2409 | 2009-11-14 10:42:35 +0000 | [diff] [blame] | 92 | assert(hasPCHSupport() && "This action does not have PCH support!"); | 
|  | 93 | CI.createPCHExternalASTSource( | 
| Daniel Dunbar | 049d3a0 | 2009-11-17 05:52:41 +0000 | [diff] [blame] | 94 | CI.getPreprocessorOpts().ImplicitPCHInclude); | 
| Daniel Dunbar | 4ee2409 | 2009-11-14 10:42:35 +0000 | [diff] [blame] | 95 | if (!CI.getASTContext().getExternalSource()) | 
|  | 96 | goto failure; | 
|  | 97 | } | 
|  | 98 | } | 
|  | 99 |  | 
|  | 100 | // Initialize builtin info as long as we aren't using an external AST | 
|  | 101 | // source. | 
|  | 102 | if (!CI.hasASTContext() || !CI.getASTContext().getExternalSource()) { | 
|  | 103 | Preprocessor &PP = CI.getPreprocessor(); | 
|  | 104 | PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(), | 
|  | 105 | PP.getLangOptions().NoBuiltin); | 
|  | 106 | } | 
|  | 107 |  | 
|  | 108 | return true; | 
|  | 109 |  | 
|  | 110 | // If we failed, reset state since the client will not end up calling the | 
|  | 111 | // matching EndSourceFile(). | 
|  | 112 | failure: | 
|  | 113 | if (isCurrentFileAST()) { | 
|  | 114 | CI.takeASTContext(); | 
|  | 115 | CI.takePreprocessor(); | 
|  | 116 | CI.takeSourceManager(); | 
|  | 117 | CI.takeFileManager(); | 
|  | 118 | } | 
|  | 119 |  | 
|  | 120 | CI.getDiagnosticClient().EndSourceFile(); | 
|  | 121 | setCurrentFile(""); | 
|  | 122 | setCompilerInstance(0); | 
|  | 123 | return false; | 
|  | 124 | } | 
|  | 125 |  | 
|  | 126 | void FrontendAction::Execute() { | 
|  | 127 | CompilerInstance &CI = getCompilerInstance(); | 
|  | 128 |  | 
|  | 129 | // Initialize the main file entry. This needs to be delayed until after PCH | 
|  | 130 | // has loaded. | 
|  | 131 | if (isCurrentFileAST()) { | 
|  | 132 | // Set the main file ID to an empty file. | 
|  | 133 | // | 
|  | 134 | // FIXME: We probably shouldn't need this, but for now this is the | 
|  | 135 | // simplest way to reuse the logic in ParseAST. | 
|  | 136 | const char *EmptyStr = ""; | 
|  | 137 | llvm::MemoryBuffer *SB = | 
|  | 138 | llvm::MemoryBuffer::getMemBuffer(EmptyStr, EmptyStr, "<dummy input>"); | 
|  | 139 | CI.getSourceManager().createMainFileIDForMemBuffer(SB); | 
|  | 140 | } else { | 
|  | 141 | if (!CI.InitializeSourceManager(getCurrentFile())) | 
|  | 142 | return; | 
|  | 143 | } | 
|  | 144 |  | 
| Kovarththanan Rajaratnam | f79bafa | 2009-11-29 09:57:35 +0000 | [diff] [blame] | 145 | if (CI.hasFrontendTimer()) { | 
|  | 146 | llvm::TimeRegion Timer(CI.getFrontendTimer()); | 
|  | 147 | ExecuteAction(); | 
|  | 148 | } | 
|  | 149 | else ExecuteAction(); | 
| Daniel Dunbar | 4ee2409 | 2009-11-14 10:42:35 +0000 | [diff] [blame] | 150 | } | 
|  | 151 |  | 
|  | 152 | void FrontendAction::EndSourceFile() { | 
|  | 153 | CompilerInstance &CI = getCompilerInstance(); | 
|  | 154 |  | 
|  | 155 | // Finalize the action. | 
|  | 156 | EndSourceFileAction(); | 
|  | 157 |  | 
|  | 158 | // Release the consumer and the AST, in that order since the consumer may | 
|  | 159 | // perform actions in its destructor which require the context. | 
|  | 160 | // | 
|  | 161 | // FIXME: There is more per-file stuff we could just drop here? | 
|  | 162 | if (CI.getFrontendOpts().DisableFree) { | 
|  | 163 | CI.takeASTConsumer(); | 
|  | 164 | if (!isCurrentFileAST()) | 
|  | 165 | CI.takeASTContext(); | 
|  | 166 | } else { | 
|  | 167 | CI.setASTConsumer(0); | 
|  | 168 | if (!isCurrentFileAST()) | 
|  | 169 | CI.setASTContext(0); | 
|  | 170 | } | 
|  | 171 |  | 
| Daniel Dunbar | dbd8209 | 2010-03-23 05:09:10 +0000 | [diff] [blame] | 172 | // Inform the preprocessor we are done. | 
|  | 173 | if (CI.hasPreprocessor()) | 
|  | 174 | CI.getPreprocessor().EndSourceFile(); | 
|  | 175 |  | 
| Daniel Dunbar | 4ee2409 | 2009-11-14 10:42:35 +0000 | [diff] [blame] | 176 | if (CI.getFrontendOpts().ShowStats) { | 
|  | 177 | llvm::errs() << "\nSTATISTICS FOR '" << getCurrentFile() << "':\n"; | 
|  | 178 | CI.getPreprocessor().PrintStats(); | 
|  | 179 | CI.getPreprocessor().getIdentifierTable().PrintStats(); | 
|  | 180 | CI.getPreprocessor().getHeaderSearchInfo().PrintStats(); | 
|  | 181 | CI.getSourceManager().PrintStats(); | 
|  | 182 | llvm::errs() << "\n"; | 
|  | 183 | } | 
|  | 184 |  | 
|  | 185 | // Cleanup the output streams, and erase the output files if we encountered | 
|  | 186 | // an error. | 
| Kovarththanan Rajaratnam | e51dd7b | 2010-03-06 12:07:48 +0000 | [diff] [blame] | 187 | CI.clearOutputFiles(/*EraseFiles=*/CI.getDiagnostics().getNumErrors()); | 
| Daniel Dunbar | 4ee2409 | 2009-11-14 10:42:35 +0000 | [diff] [blame] | 188 |  | 
|  | 189 | // Inform the diagnostic client we are done with this source file. | 
|  | 190 | CI.getDiagnosticClient().EndSourceFile(); | 
|  | 191 |  | 
|  | 192 | if (isCurrentFileAST()) { | 
|  | 193 | CI.takeASTContext(); | 
|  | 194 | CI.takePreprocessor(); | 
|  | 195 | CI.takeSourceManager(); | 
|  | 196 | CI.takeFileManager(); | 
|  | 197 | } | 
|  | 198 |  | 
|  | 199 | setCompilerInstance(0); | 
|  | 200 | setCurrentFile(""); | 
|  | 201 | } | 
|  | 202 |  | 
|  | 203 | //===----------------------------------------------------------------------===// | 
|  | 204 | // Utility Actions | 
|  | 205 | //===----------------------------------------------------------------------===// | 
|  | 206 |  | 
|  | 207 | void ASTFrontendAction::ExecuteAction() { | 
|  | 208 | CompilerInstance &CI = getCompilerInstance(); | 
|  | 209 |  | 
|  | 210 | // FIXME: Move the truncation aspect of this into Sema, we delayed this till | 
|  | 211 | // here so the source manager would be initialized. | 
|  | 212 | if (hasCodeCompletionSupport() && | 
|  | 213 | !CI.getFrontendOpts().CodeCompletionAt.FileName.empty()) | 
|  | 214 | CI.createCodeCompletionConsumer(); | 
|  | 215 |  | 
|  | 216 | // Use a code completion consumer? | 
|  | 217 | CodeCompleteConsumer *CompletionConsumer = 0; | 
|  | 218 | if (CI.hasCodeCompletionConsumer()) | 
|  | 219 | CompletionConsumer = &CI.getCodeCompletionConsumer(); | 
|  | 220 |  | 
|  | 221 | ParseAST(CI.getPreprocessor(), &CI.getASTConsumer(), CI.getASTContext(), | 
|  | 222 | CI.getFrontendOpts().ShowStats, | 
|  | 223 | usesCompleteTranslationUnit(), CompletionConsumer); | 
|  | 224 | } | 
|  | 225 |  | 
|  | 226 | ASTConsumer * | 
|  | 227 | PreprocessorFrontendAction::CreateASTConsumer(CompilerInstance &CI, | 
|  | 228 | llvm::StringRef InFile) { | 
| Jeffrey Yasskin | 9f61aa9 | 2009-12-12 05:05:38 +0000 | [diff] [blame] | 229 | llvm_unreachable("Invalid CreateASTConsumer on preprocessor action!"); | 
| Daniel Dunbar | 4ee2409 | 2009-11-14 10:42:35 +0000 | [diff] [blame] | 230 | } |