1 //===--- CompilerInstance.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/CompilerInstance.h" 11 #include "clang/AST/ASTConsumer.h" 12 #include "clang/AST/ASTContext.h" 13 #include "clang/Basic/Diagnostic.h" 14 #include "clang/Basic/FileManager.h" 15 #include "clang/Basic/SourceManager.h" 16 #include "clang/Basic/TargetInfo.h" 17 #include "clang/Lex/HeaderSearch.h" 18 #include "clang/Lex/Preprocessor.h" 19 #include "clang/Lex/PTHManager.h" 20 #include "clang/Frontend/ChainedDiagnosticClient.h" 21 #include "clang/Frontend/PCHReader.h" 22 #include "clang/Frontend/FrontendDiagnostic.h" 23 #include "clang/Frontend/TextDiagnosticPrinter.h" 24 #include "clang/Frontend/VerifyDiagnosticsClient.h" 25 #include "clang/Frontend/Utils.h" 26 #include "clang/Sema/CodeCompleteConsumer.h" 27 #include "llvm/LLVMContext.h" 28 #include "llvm/Support/MemoryBuffer.h" 29 #include "llvm/Support/raw_ostream.h" 30 #include "llvm/Support/Timer.h" 31 #include "llvm/System/Path.h" 32 using namespace clang; 33 34 CompilerInstance::CompilerInstance(llvm::LLVMContext *_LLVMContext, 35 bool _OwnsLLVMContext) 36 : LLVMContext(_LLVMContext), 37 OwnsLLVMContext(_OwnsLLVMContext) { 38 } 39 40 CompilerInstance::~CompilerInstance() { 41 if (OwnsLLVMContext) 42 delete LLVMContext; 43 } 44 45 void CompilerInstance::setDiagnostics(Diagnostic *Value) { 46 Diagnostics.reset(Value); 47 } 48 49 void CompilerInstance::setDiagnosticClient(DiagnosticClient *Value) { 50 DiagClient.reset(Value); 51 } 52 53 void CompilerInstance::setTarget(TargetInfo *Value) { 54 Target.reset(Value); 55 } 56 57 void CompilerInstance::setFileManager(FileManager *Value) { 58 FileMgr.reset(Value); 59 } 60 61 void CompilerInstance::setSourceManager(SourceManager *Value) { 62 SourceMgr.reset(Value); 63 } 64 65 void CompilerInstance::setPreprocessor(Preprocessor *Value) { 66 PP.reset(Value); 67 } 68 69 void CompilerInstance::setASTContext(ASTContext *Value) { 70 Context.reset(Value); 71 } 72 73 void CompilerInstance::setASTConsumer(ASTConsumer *Value) { 74 Consumer.reset(Value); 75 } 76 77 void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) { 78 CompletionConsumer.reset(Value); 79 } 80 81 // Diagnostics 82 83 static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts, 84 unsigned argc, char **argv, 85 llvm::OwningPtr<DiagnosticClient> &DiagClient) { 86 std::string ErrorInfo; 87 llvm::raw_ostream *OS = 88 new llvm::raw_fd_ostream(DiagOpts.DumpBuildInformation.c_str(), ErrorInfo); 89 if (!ErrorInfo.empty()) { 90 // FIXME: Do not fail like this. 91 llvm::errs() << "error opening -dump-build-information file '" 92 << DiagOpts.DumpBuildInformation << "', option ignored!\n"; 93 delete OS; 94 return; 95 } 96 97 (*OS) << "clang-cc command line arguments: "; 98 for (unsigned i = 0; i != argc; ++i) 99 (*OS) << argv[i] << ' '; 100 (*OS) << '\n'; 101 102 // Chain in a diagnostic client which will log the diagnostics. 103 DiagnosticClient *Logger = 104 new TextDiagnosticPrinter(*OS, DiagOpts, /*OwnsOutputStream=*/true); 105 DiagClient.reset(new ChainedDiagnosticClient(DiagClient.take(), Logger)); 106 } 107 108 void CompilerInstance::createDiagnostics(int Argc, char **Argv) { 109 Diagnostics.reset(createDiagnostics(getDiagnosticOpts(), Argc, Argv)); 110 111 if (Diagnostics) 112 DiagClient.reset(Diagnostics->getClient()); 113 } 114 115 Diagnostic *CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts, 116 int Argc, char **Argv) { 117 llvm::OwningPtr<Diagnostic> Diags(new Diagnostic()); 118 119 // Create the diagnostic client for reporting errors or for 120 // implementing -verify. 121 llvm::OwningPtr<DiagnosticClient> DiagClient( 122 new TextDiagnosticPrinter(llvm::errs(), Opts)); 123 124 // Chain in -verify checker, if requested. 125 if (Opts.VerifyDiagnostics) 126 DiagClient.reset(new VerifyDiagnosticsClient(*Diags, DiagClient.take())); 127 128 if (!Opts.DumpBuildInformation.empty()) 129 SetUpBuildDumpLog(Opts, Argc, Argv, DiagClient); 130 131 // Configure our handling of diagnostics. 132 Diags->setClient(DiagClient.take()); 133 if (ProcessWarningOptions(*Diags, Opts)) 134 return 0; 135 136 return Diags.take(); 137 } 138 139 // File Manager 140 141 void CompilerInstance::createFileManager() { 142 FileMgr.reset(new FileManager()); 143 } 144 145 // Source Manager 146 147 void CompilerInstance::createSourceManager() { 148 SourceMgr.reset(new SourceManager()); 149 } 150 151 // Preprocessor 152 153 void CompilerInstance::createPreprocessor() { 154 PP.reset(createPreprocessor(getDiagnostics(), getLangOpts(), 155 getPreprocessorOpts(), getHeaderSearchOpts(), 156 getDependencyOutputOpts(), getTarget(), 157 getSourceManager(), getFileManager())); 158 } 159 160 Preprocessor * 161 CompilerInstance::createPreprocessor(Diagnostic &Diags, 162 const LangOptions &LangInfo, 163 const PreprocessorOptions &PPOpts, 164 const HeaderSearchOptions &HSOpts, 165 const DependencyOutputOptions &DepOpts, 166 const TargetInfo &Target, 167 SourceManager &SourceMgr, 168 FileManager &FileMgr) { 169 // Create a PTH manager if we are using some form of a token cache. 170 PTHManager *PTHMgr = 0; 171 if (!PPOpts.TokenCache.empty()) 172 PTHMgr = PTHManager::Create(PPOpts.TokenCache, Diags); 173 174 // FIXME: Don't fail like this. 175 if (Diags.hasErrorOccurred()) 176 exit(1); 177 178 // Create the Preprocessor. 179 HeaderSearch *HeaderInfo = new HeaderSearch(FileMgr); 180 Preprocessor *PP = new Preprocessor(Diags, LangInfo, Target, 181 SourceMgr, *HeaderInfo, PTHMgr, 182 /*OwnsHeaderSearch=*/true); 183 184 // Note that this is different then passing PTHMgr to Preprocessor's ctor. 185 // That argument is used as the IdentifierInfoLookup argument to 186 // IdentifierTable's ctor. 187 if (PTHMgr) { 188 PTHMgr->setPreprocessor(PP); 189 PP->setPTHManager(PTHMgr); 190 } 191 192 InitializePreprocessor(*PP, PPOpts, HSOpts); 193 194 // Handle generating dependencies, if requested. 195 if (!DepOpts.OutputFile.empty()) 196 AttachDependencyFileGen(*PP, DepOpts); 197 198 return PP; 199 } 200 201 // ASTContext 202 203 void CompilerInstance::createASTContext() { 204 Preprocessor &PP = getPreprocessor(); 205 Context.reset(new ASTContext(getLangOpts(), PP.getSourceManager(), 206 getTarget(), PP.getIdentifierTable(), 207 PP.getSelectorTable(), PP.getBuiltinInfo(), 208 /*FreeMemory=*/ !getFrontendOpts().DisableFree, 209 /*size_reserve=*/ 0)); 210 } 211 212 // ExternalASTSource 213 214 void CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path) { 215 llvm::OwningPtr<ExternalASTSource> Source; 216 Source.reset(createPCHExternalASTSource(Path, getHeaderSearchOpts().Sysroot, 217 getPreprocessor(), getASTContext())); 218 getASTContext().setExternalSource(Source); 219 } 220 221 ExternalASTSource * 222 CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path, 223 const std::string &Sysroot, 224 Preprocessor &PP, 225 ASTContext &Context) { 226 llvm::OwningPtr<PCHReader> Reader; 227 Reader.reset(new PCHReader(PP, &Context, 228 Sysroot.empty() ? 0 : Sysroot.c_str())); 229 230 switch (Reader->ReadPCH(Path)) { 231 case PCHReader::Success: 232 // Set the predefines buffer as suggested by the PCH reader. Typically, the 233 // predefines buffer will be empty. 234 PP.setPredefines(Reader->getSuggestedPredefines()); 235 return Reader.take(); 236 237 case PCHReader::Failure: 238 // Unrecoverable failure: don't even try to process the input file. 239 break; 240 241 case PCHReader::IgnorePCH: 242 // No suitable PCH file could be found. Return an error. 243 break; 244 } 245 246 return 0; 247 } 248 249 // Code Completion 250 251 void CompilerInstance::createCodeCompletionConsumer() { 252 const ParsedSourceLocation &Loc = getFrontendOpts().CodeCompletionAt; 253 CompletionConsumer.reset( 254 createCodeCompletionConsumer(getPreprocessor(), 255 Loc.FileName, Loc.Line, Loc.Column, 256 getFrontendOpts().DebugCodeCompletionPrinter, 257 getFrontendOpts().ShowMacrosInCodeCompletion, 258 llvm::outs())); 259 } 260 261 void CompilerInstance::createFrontendTimer() { 262 FrontendTimer.reset(new llvm::Timer("Clang front-end timer")); 263 } 264 265 CodeCompleteConsumer * 266 CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP, 267 const std::string &Filename, 268 unsigned Line, 269 unsigned Column, 270 bool UseDebugPrinter, 271 bool ShowMacros, 272 llvm::raw_ostream &OS) { 273 // Tell the source manager to chop off the given file at a specific 274 // line and column. 275 const FileEntry *Entry = PP.getFileManager().getFile(Filename); 276 if (!Entry) { 277 PP.getDiagnostics().Report(diag::err_fe_invalid_code_complete_file) 278 << Filename; 279 return 0; 280 } 281 282 // Truncate the named file at the given line/column. 283 PP.getSourceManager().truncateFileAt(Entry, Line, Column); 284 285 // Set up the creation routine for code-completion. 286 if (UseDebugPrinter) 287 return new PrintingCodeCompleteConsumer(ShowMacros, OS); 288 else 289 return new CIndexCodeCompleteConsumer(ShowMacros, OS); 290 } 291 292 // Output Files 293 294 void CompilerInstance::addOutputFile(llvm::StringRef Path, 295 llvm::raw_ostream *OS) { 296 assert(OS && "Attempt to add empty stream to output list!"); 297 OutputFiles.push_back(std::make_pair(Path, OS)); 298 } 299 300 void CompilerInstance::ClearOutputFiles(bool EraseFiles) { 301 for (std::list< std::pair<std::string, llvm::raw_ostream*> >::iterator 302 it = OutputFiles.begin(), ie = OutputFiles.end(); it != ie; ++it) { 303 delete it->second; 304 if (EraseFiles && !it->first.empty()) 305 llvm::sys::Path(it->first).eraseFromDisk(); 306 } 307 OutputFiles.clear(); 308 } 309 310 llvm::raw_fd_ostream * 311 CompilerInstance::createDefaultOutputFile(bool Binary, 312 llvm::StringRef InFile, 313 llvm::StringRef Extension) { 314 return createOutputFile(getFrontendOpts().OutputFile, Binary, 315 InFile, Extension); 316 } 317 318 llvm::raw_fd_ostream * 319 CompilerInstance::createOutputFile(llvm::StringRef OutputPath, 320 bool Binary, 321 llvm::StringRef InFile, 322 llvm::StringRef Extension) { 323 std::string Error, OutputPathName; 324 llvm::raw_fd_ostream *OS = createOutputFile(OutputPath, Error, Binary, 325 InFile, Extension, 326 &OutputPathName); 327 if (!OS) { 328 // FIXME: Don't fail this way. 329 llvm::errs() << "error: " << Error << "\n"; 330 ::exit(1); 331 } 332 333 // Add the output file -- but don't try to remove "-", since this means we are 334 // using stdin. 335 addOutputFile((OutputPathName != "-") ? OutputPathName : "", OS); 336 337 return OS; 338 } 339 340 llvm::raw_fd_ostream * 341 CompilerInstance::createOutputFile(llvm::StringRef OutputPath, 342 std::string &Error, 343 bool Binary, 344 llvm::StringRef InFile, 345 llvm::StringRef Extension, 346 std::string *ResultPathName) { 347 std::string OutFile; 348 if (!OutputPath.empty()) { 349 OutFile = OutputPath; 350 } else if (InFile == "-") { 351 OutFile = "-"; 352 } else if (!Extension.empty()) { 353 llvm::sys::Path Path(InFile); 354 Path.eraseSuffix(); 355 Path.appendSuffix(Extension); 356 OutFile = Path.str(); 357 } else { 358 OutFile = "-"; 359 } 360 361 llvm::OwningPtr<llvm::raw_fd_ostream> OS( 362 new llvm::raw_fd_ostream(OutFile.c_str(), Error, 363 (Binary ? llvm::raw_fd_ostream::F_Binary : 0))); 364 if (!Error.empty()) 365 return 0; 366 367 if (ResultPathName) 368 *ResultPathName = OutFile; 369 370 return OS.take(); 371 } 372 373 // Initialization Utilities 374 375 bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile) { 376 return InitializeSourceManager(InputFile, getDiagnostics(), getFileManager(), 377 getSourceManager(), getFrontendOpts()); 378 } 379 380 bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile, 381 Diagnostic &Diags, 382 FileManager &FileMgr, 383 SourceManager &SourceMgr, 384 const FrontendOptions &Opts) { 385 // Figure out where to get and map in the main file. 386 if (Opts.EmptyInputOnly) { 387 const char *EmptyStr = ""; 388 llvm::MemoryBuffer *SB = 389 llvm::MemoryBuffer::getMemBuffer(EmptyStr, EmptyStr, "<empty input>"); 390 SourceMgr.createMainFileIDForMemBuffer(SB); 391 } else if (InputFile != "-") { 392 const FileEntry *File = FileMgr.getFile(InputFile); 393 if (File) SourceMgr.createMainFileID(File, SourceLocation()); 394 if (SourceMgr.getMainFileID().isInvalid()) { 395 Diags.Report(diag::err_fe_error_reading) << InputFile; 396 return false; 397 } 398 } else { 399 llvm::MemoryBuffer *SB = llvm::MemoryBuffer::getSTDIN(); 400 SourceMgr.createMainFileIDForMemBuffer(SB); 401 if (SourceMgr.getMainFileID().isInvalid()) { 402 Diags.Report(diag::err_fe_error_reading_stdin); 403 return false; 404 } 405 } 406 407 return true; 408 } 409